Skip to content

Instantly share code, notes, and snippets.

@vensires
Created December 19, 2016 18:29
Show Gist options
  • Save vensires/f06ca627800b9c6808e9b47b31bec772 to your computer and use it in GitHub Desktop.
Save vensires/f06ca627800b9c6808e9b47b31bec772 to your computer and use it in GitHub Desktop.
Divides an array of different products weights to packages containing at most $package_max_weight weight and $package_max_items items. You could use this function to calculate shipping based on package weight instead of product weight.
<?php
/**
* Divides product weights into packages.
*
* @param array $weights
* An array of product weights.
* @param int $package_max_weight
* The maximum weight of a package. Set to 0 to not allow limit per weight.
* @param int $package_max_items
* The maximum number of items per package. Set to 0 to not allow limit per items.
*
* @return array
* An array of package weights.
*/
function commerce_shipping_packages_product_weights_to_packages($weights, $package_max_weight = 0, $package_max_items = 0) {
// Sort weights from maximum to minimum.
rsort($weights);
// An array to hold the packages.
$packages = array();
// An array to hold the parsed weights.
$parsed = array();
// A variable to hold the package's weight.
$package_weight = 0;
// A variable to hold the package's total items.
$package_items = 0;
// Get the latest (equivalent) key.
end($weights);
$eqweight_index = key($weights);
// Latest PHP versions don't need this since foreach automatically resets.
reset($weights);
foreach ($weights as $index => $weight) {
if (in_array($index, $parsed)) {
// Reached an already parsed value. Assume all values were parsed.
if ($package_weight > 0 && $package_items > 0) {
// There are still items without a package.
$packages[] = $package_weight;
}
break;
}
if ($package_max_items) {
// Check number of items in package including this item.
if ($package_items + 1 > $package_max_items) {
$packages[] = $package_weight;
$package_weight = 0;
$package_items = 0;
}
}
// Check package weight including this weight.
if ($package_max_weight) {
if ($weight > $package_max_weight) {
// This item is already heavy enough. Create a new package for any
// previous items. Create a new package for this item too.
$parsed[] = $index;
if ($package_weight) {
$packages[] = $package_weight;
}
$packages[] = $weight;
$package_items = 0;
$package_weight = 0;
continue;
}
elseif ($package_weight + $weight > $package_max_weight) {
// This package already contains heavy enough items. Create a new
// package for them. Then add this weight as a package base weight.
$packages[] = $package_weight;
$parsed[] = $index;
$package_items = 1;
$package_weight = $weight;
}
else {
// This item can be stored in the current package.
$package_weight += $weight;
$package_items++;
$parsed[] = $index;
}
if (isset($weights[$eqweight_index]) && !in_array($eqweight_index, $parsed)) {
// There is a non-parsed equivalent weight.
if (!$package_max_items || $package_max_items && $package_max_items > $package_items) {
// No package max items configured or didn't yet reach max items.
if ($package_weight + $weights[$eqweight_index] <= $package_max_weight) {
// Haven't yet reached maximum weight.
$package_weight += $weights[$eqweight_index];
$package_items++;
$parsed[] = $eqweight_index;
// Decrease the equivalent weight index key by 1.
$eqweight_index--;
}
}
}
}
}
return $packages;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment