This is what is included with the UPS XML contribution (which works great for the most part). What i need to do is put some constraints on it. I ship odd size packages, and it is putting some "Oversized" products into smaller boxes because it is based on volume. Can anyone let me know how to add a variable of "max_width". ex. a product that is 108x1x2 is being placed into a box 12x12x12
Any help would be great.
-Shawn
// A very simple box packing algorithm. Given a list of packages, returns
// an array of boxes.
function packProducts($productsArray) {
// This algorithm is trivial. It works on the premise that you have selected
// boxes that fit your products, and that their volumes are resonable multiples
// of the products they store. For example, if you sell CDs and these CDs are
// 5x5x0.5", your boxes should be 5x5x0.5 (1 CD mailer), 5x5x2.5 (5 CD mailer)
// and 5x5x5 (10 CD mailer). No matter how many CDs a customer buys, this
// routine will always find the optimal packing.
//
// Your milage may differ, depending on what variety of products you sell, and
// how they're boxed. I just made up this algorithm in a hurry to fill a small
// niche. You are encouraged to find better algorithms. Better algorithms mean
// better packaging, resulting in higher quoting accuracy and less loss due to
// inaccurate quoting.
//
// The algorithm proceeds as follows:
// Get the first, smallest box, and try to put everything into it. If not all
// of it fits, try fitting it all into the next largest box. Keep increasing
// the size of the box until no larger box can be obtained, then spill over
// into a second, smallest box. Once again, increase the box size until
// everything fits, or spill over again. Repeat until everything is boxed.
//
// The cost of a box determines the order in which it is tried. There will definitely
// be cases where it is cheaper to send two small packages rather than one larger one.
// In that case, you'll need a better algorithm.
// Get the available packages and "prepare" empty boxes with weight and remaining volume
// counters. (Take existing box and add 'remaining_volume' and 'current_weight';
$definedPackages = $this->getPackages();
$emptyBoxesArray = array();
for ($i = 0; $i < count($definedPackages); $i++) {
$definedBox = $definedPackages[$i];
$definedBox['remaining_volume'] = $definedBox['length'] * $definedBox['width'] * $definedBox['height'];
$definedBox['max_width'] = $definedBox['width'];
$definedBox['current_weight'] = $definedBox['empty_weight'];
$emptyBoxesArray[] = $definedBox;
}
$packedBoxesArray = array();
$currentBox = NULL;
// Get the product array and expand multiple qty items.
$productsRemaining = array();
for ($i = 0; $i < count($productsArray); $i++) {
$product = $productsArray[$i];
for ($j = 0; $j < $productsArray[$i]['quantity']; $j++) {
$productsRemaining[] = $product;
}
}
// Worst case, you'll need as many boxes as products ordered.
while (count($productsRemaining)) {
// Immediately set aside products that are already packed and ready.
if ($productsRemaining[0]['ready_to_ship'] == '1') {
$packedBoxesArray[] = array (
'length' => $productsRemaining[0]['length'],
'width' => $productsRemaining[0]['width'],
'height' => $productsRemaining[0]['height'],
'current_weight' => $productsRemaining[0]['weight']
);
$productsRemaining = array_slice($productsRemaining, 1);
continue;
}
//Cylcle through boxes, increasing box size if all doesn't fit.
if (count($emptyBoxesArray) == 0) {
print_r("ERROR: No boxes to ship unpackaged product<br>");
break;
}
for ($b = 0; $b < count($emptyBoxesArray); $b++) {
$currentBox = $emptyBoxesArray[$b];
//Try to fit each product in box
for ($p = 0; $p < count($productsRemaining); $p++) {
if ($this->fitsInBox($productsRemaining[$p], $currentBox)) {
//It fits. Put it in the box.
$currentBox = $this->putProductInBox($productsRemaining[$p], $currentBox);
if ($p == count($productsRemaining) - 1) {
$packedBoxesArray[] = $currentBox;
$productsRemaining = array_slice($productsRemaining, $p + 1);
break 2;
}
} else {
if ($b == count($emptyBoxesArray) - 1) {
//We're at the largest box already, and it's full.
//Keep what we've packed so far and get another box.
$packedBoxesArray[] = $currentBox;
$productsRemaining = array_slice($productsRemaining, $p + 1);
break 2;
}
// Not all of them fit. Stop packing remaining products and try
// next box.
break;
}
}
}
}
return $packedBoxesArray;
}
function fitsInBox($product, $box) {
$productVolume = $product['length'] * $product['width'] * $product['height'];
if ($productVolume <= $box['remaining_volume']) {
if ($productWidth <= $box['max_width']) {
if ($box['max_weight'] == 0 || ($box['current_weight'] + $product['weight'] <= $box['max_weight'])) {
return true;
}
}
return false;
}
function putProductInBox($product, $box) {
$productVolume = $product['length'] * $product['width'] * $product['height'];
$box['max_width'] <= $product['width']
$box['remaining_volume'] -= $productVolume;
$box['products'][] = $product;
$box['current_weight'] += $product['weight'];
return $box;
}