package com.salesmanager.core.business.modules.integration.shipping.impl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import com.salesmanager.core.business.exception.ServiceException;
import com.salesmanager.core.business.services.shipping.ShippingService;
import com.salesmanager.core.business.services.system.MerchantLogService;
import com.salesmanager.core.model.catalog.product.Product;
import com.salesmanager.core.model.catalog.product.attribute.ProductAttribute;
import com.salesmanager.core.model.merchant.MerchantStore;
import com.salesmanager.core.model.shipping.PackageDetails;
import com.salesmanager.core.model.shipping.ShippingConfiguration;
import com.salesmanager.core.model.shipping.ShippingProduct;
import com.salesmanager.core.model.system.MerchantLog;
import com.salesmanager.core.modules.integration.shipping.model.Packaging;
public class DefaultPackagingImpl implements Packaging {
@Inject
private ShippingService shippingService;
@Inject
private MerchantLogService merchantLogService;
/** default dimensions **/
private final static Double defaultWeight = 1D;
private final static Double defaultHeight = 4D;
private final static Double defaultLength = 4D;
private final static Double defaultWidth = 4D;
@Override
public List<PackageDetails> getBoxPackagesDetails(
List<ShippingProduct> products, MerchantStore store)
throws ServiceException {
if (products == null) {
throw new ServiceException("Product list cannot be null !!");
}
double width = 0;
double length = 0;
double height = 0;
double weight = 0;
double maxweight = 0;
//int treshold = 0;
ShippingConfiguration shippingConfiguration = shippingService.getShippingConfiguration(store);
if(shippingConfiguration==null) {
throw new ServiceException("ShippingConfiguration not found for merchant " + store.getCode());
}
width = new Double(shippingConfiguration.getBoxWidth()).doubleValue();
length = new Double(shippingConfiguration.getBoxLength()).doubleValue();
height = new Double(shippingConfiguration.getBoxHeight()).doubleValue();
weight = new Double(shippingConfiguration.getBoxWeight()).doubleValue();
maxweight = new Double(shippingConfiguration.getMaxWeight()).doubleValue();
List<PackageDetails> boxes = new ArrayList<PackageDetails>();
// maximum number of boxes
int maxBox = 100;
int iterCount = 0;
List<Product> individualProducts = new ArrayList<Product>();
// need to put items individually
for(ShippingProduct shippingProduct : products){
Product product = shippingProduct.getProduct();
if (product.isProductVirtual()) {
continue;
}
int qty = shippingProduct.getQuantity();
Set<ProductAttribute> attrs = shippingProduct.getProduct().getAttributes();
// set attributes values
BigDecimal w = product.getProductWeight();
BigDecimal h = product.getProductHeight();
BigDecimal l = product.getProductLength();
BigDecimal wd = product.getProductWidth();
if(w==null) {
w = new BigDecimal(defaultWeight);
}
if(h==null) {
h = new BigDecimal(defaultHeight);
}
if(l==null) {
l = new BigDecimal(defaultLength);
}
if(wd==null) {
wd = new BigDecimal(defaultWidth);
}
if (attrs != null && attrs.size() > 0) {
for(ProductAttribute attribute : attrs) {
if(attribute.getProductAttributeWeight()!=null) {
w = w.add(attribute.getProductAttributeWeight());
}
}
}
if (qty > 1) {
for (int i = 1; i <= qty; i++) {
Product temp = new Product();
temp.setProductHeight(h);
temp.setProductLength(l);
temp.setProductWidth(wd);
temp.setProductWeight(w);
temp.setAttributes(product.getAttributes());
temp.setDescriptions(product.getDescriptions());
individualProducts.add(temp);
}
} else {
Product temp = new Product();
temp.setProductHeight(h);
temp.setProductLength(l);
temp.setProductWidth(wd);
temp.setProductWeight(w);
temp.setAttributes(product.getAttributes());
temp.setDescriptions(product.getDescriptions());
individualProducts.add(temp);
}
iterCount++;
}
if (iterCount == 0) {
return null;
}
int productCount = individualProducts.size();
List<PackingBox> boxesList = new ArrayList<PackingBox>();
//start the creation of boxes
PackingBox box = new PackingBox();
// set box max volume
double maxVolume = width * length * height;
if (maxVolume == 0 || maxweight == 0) {
merchantLogService.save(new MerchantLog(store,"shipping","Check shipping box configuration, it has a volume of "
+ maxVolume + " and a maximum weight of "
+ maxweight
+ ". Those values must be greater than 0."));
throw new ServiceException("Product configuration exceeds box configuraton");
}
box.setVolumeLeft(maxVolume);
box.setWeightLeft(maxweight);
boxesList.add(box);//assign first box
//int boxCount = 1;
List<Product> assignedProducts = new ArrayList<Product>();
// calculate the volume for the next object
if (assignedProducts.size() > 0) {
individualProducts.removeAll(assignedProducts);
assignedProducts = new ArrayList<Product>();
}
boolean productAssigned = false;
for(Product p : individualProducts) {
//Set<ProductAttribute> attributes = p.getAttributes();
productAssigned = false;
double productWeight = p.getProductWeight().doubleValue();
// validate if product fits in the box
if (p.getProductWidth().doubleValue() > width
|| p.getProductHeight().doubleValue() > height
|| p.getProductLength().doubleValue() > length) {
// log message to customer
merchantLogService.save(new MerchantLog(store,"shipping","Product "
+ p.getSku()
+ " has a demension larger than the box size specified. Will use per item calculation."));
throw new ServiceException("Product configuration exceeds box configuraton");
}
if (productWeight > maxweight) {
merchantLogService.save(new MerchantLog(store,"shipping","Product "
+ p.getSku()
+ " has a weight larger than the box maximum weight specified. Will use per item calculation."));
throw new ServiceException("Product configuration exceeds box configuraton");
}
double productVolume = (p.getProductWidth().doubleValue()
* p.getProductHeight().doubleValue() * p
.getProductLength().doubleValue());
if (productVolume == 0) {
merchantLogService.save(new MerchantLog(store,"shipping","Product "
+ p.getSku()
+ " has one of the dimension set to 0 and therefore cannot calculate the volume"));
throw new ServiceException("Product configuration exceeds box configuraton");
}
if (productVolume > maxVolume) {
throw new ServiceException("Product configuration exceeds box configuraton");
}
//List boxesList = boxesList;
// try each box
//Iterator boxIter = boxesList.iterator();
for (PackingBox pbox : boxesList) {
double volumeLeft = pbox.getVolumeLeft();
double weightLeft = pbox.getWeightLeft();
if ((volumeLeft * .75) >= productVolume
&& pbox.getWeightLeft() >= productWeight) {// fit the item
// in this
// box
// fit in the current box
volumeLeft = volumeLeft - productVolume;
pbox.setVolumeLeft(volumeLeft);
weightLeft = weightLeft - productWeight;
pbox.setWeightLeft(weightLeft);
assignedProducts.add(p);
productCount--;
double w = pbox.getWeight();
w = w + productWeight;
pbox.setWeight(w);
productAssigned = true;
maxBox--;
break;
}
}
if (!productAssigned) {// create a new box
box = new PackingBox();
// set box max volume
box.setVolumeLeft(maxVolume);
box.setWeightLeft(maxweight);
boxesList.add(box);
double volumeLeft = box.getVolumeLeft() - productVolume;
box.setVolumeLeft(volumeLeft);
double weightLeft = box.getWeightLeft() - productWeight;
box.setWeightLeft(weightLeft);
assignedProducts.add(p);
productCount--;
double w = box.getWeight();
w = w + productWeight;
box.setWeight(w);
maxBox--;
}
}
// now prepare the shipping info
// number of boxes
//Iterator ubIt = usedBoxesList.iterator();
System.out.println("###################################");
System.out.println("Number of boxes " + boxesList.size());
System.out.println("###################################");
for(PackingBox pb : boxesList) {
PackageDetails details = new PackageDetails();
details.setShippingHeight(height);
details.setShippingLength(length);
details.setShippingWeight(weight + box.getWeight());
details.setShippingWidth(width);
details.setItemName(store.getCode());
boxes.add(details);
}
return boxes;
}
@Override
public List<PackageDetails> getItemPackagesDetails(
List<ShippingProduct> products, MerchantStore store)
throws ServiceException {
List<PackageDetails> packages = new ArrayList<PackageDetails>();
for(ShippingProduct shippingProduct : products) {
Product product = shippingProduct.getProduct();
if (product.isProductVirtual()) {
continue;
}
//BigDecimal weight = product.getProductWeight();
Set<ProductAttribute> attributes = product.getAttributes();
// set attributes values
BigDecimal w = product.getProductWeight();
BigDecimal h = product.getProductHeight();
BigDecimal l = product.getProductLength();
BigDecimal wd = product.getProductWidth();
if(w==null) {
w = new BigDecimal(defaultWeight);
}
if(h==null) {
h = new BigDecimal(defaultHeight);
}
if(l==null) {
l = new BigDecimal(defaultLength);
}
if(wd==null) {
wd = new BigDecimal(defaultWidth);
}
if (attributes != null && attributes.size() > 0) {
for(ProductAttribute attribute : attributes) {
if(attribute.getAttributeAdditionalWeight()!=null) {
w = w.add(attribute.getProductAttributeWeight());
}
}
}
if (shippingProduct.getQuantity() == 1) {
PackageDetails detail = new PackageDetails();
detail.setShippingHeight(h
.doubleValue());
detail.setShippingLength(l
.doubleValue());
detail.setShippingWeight(w.doubleValue());
detail.setShippingWidth(wd.doubleValue());
detail.setShippingQuantity(shippingProduct.getQuantity());
String description = "item";
if(product.getDescriptions().size()>0) {
description = product.getDescriptions().iterator().next().getName();
}
detail.setItemName(description);
packages.add(detail);
} else if (shippingProduct.getQuantity() > 1) {
for (int i = 0; i < shippingProduct.getQuantity(); i++) {
PackageDetails detail = new PackageDetails();
detail.setShippingHeight(h
.doubleValue());
detail.setShippingLength(l
.doubleValue());
detail.setShippingWeight(w.doubleValue());
detail.setShippingWidth(wd
.doubleValue());
detail.setShippingQuantity(shippingProduct.getQuantity());
String description = "item";
if(product.getDescriptions().size()>0) {
description = product.getDescriptions().iterator().next().getName();
}
detail.setItemName(description);
packages.add(detail);
}
}
}
return packages;
}
}
class PackingBox {
private double volumeLeft;
private double weightLeft;
private double weight;
public double getVolumeLeft() {
return volumeLeft;
}
public void setVolumeLeft(double volumeLeft) {
this.volumeLeft = volumeLeft;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getWeightLeft() {
return weightLeft;
}
public void setWeightLeft(double weightLeft) {
this.weightLeft = weightLeft;
}
}