按20kg/箱拆分产品数组并计算对应总容积的PHP实现问题
PHP 产品装箱逻辑修正:按20kg阈值装箱并计算总容积
看起来你的现有代码在处理装箱逻辑时出现了不少问题,比如重复添加产品、容积计算混乱、剩余产品处理逻辑错误,导致无法得到你预期的装箱结果。我帮你重新梳理了逻辑,写出了符合需求的修正代码,同时会解释关键的实现点。
需求回顾
我们需要把产品按每箱最大20kg的规则装箱,同时计算每个箱子的总容积,核心逻辑是:
- 优先整组装入产品,若整组装入后超过阈值,则拆分该组,取部分产品填满当前箱子,剩余部分放入下一箱
- 示例(第一箱):装入第一组(6.5kg)、第二组(9kg),再从第三组取3个(4.5kg),总重刚好20kg,总容积按实际装入的产品数量对应计算
现有代码的问题
- 重复将同一产品添加到箱子中(
$boxes[$box_number][] = $product;执行了两次) - 容积计算逻辑混乱,变量
ttal_cub、the_cubic的处理没有对应实际装箱的产品数量 - 剩余产品的处理逻辑错误,没有正确延续到下一个箱子继续填充
- 箱子的重量累加逻辑不符合“先整组装,装不下拆组”的需求
修正后的代码
<?php // 定义每箱最大重量阈值 $BOX_WEIGHT_LIMIT = 20; $itemArray = []; foreach ($main as $key => $products) { $boxes = []; $currentBoxIndex = 0; // 初始化第一个箱子,包含总重、总容积、箱内产品明细 $boxes[$currentBoxIndex] = [ 'total_weight' => 0, 'total_cubic' => 0, 'items' => [] ]; foreach ($products as $product) { // 复制产品数据,避免修改原数组的原始值 $remainingProduct = $product; // 循环处理当前产品的剩余数量,直到全部装箱完成 while ($remainingProduct['quantity'] > 0) { $currentBox = &$boxes[$currentBoxIndex]; // 计算当前箱子还能容纳的重量 $remainingWeight = $BOX_WEIGHT_LIMIT - $currentBox['total_weight']; if ($remainingWeight <= 0) { // 当前箱子已满,创建新箱子并切换过去 $currentBoxIndex++; $boxes[$currentBoxIndex] = [ 'total_weight' => 0, 'total_cubic' => 0, 'items' => [] ]; continue; } // 计算当前箱子最多能装该产品的数量 $maxPossibleQty = floor($remainingWeight / $remainingProduct['weight']); if ($maxPossibleQty <= 0) { // 单个产品重量超过箱子剩余容量,这里假设业务中不会出现这种情况,如需处理可在此添加逻辑 break; } // 实际取的数量:不超过产品剩余数量,也不超过箱子可装数量 $takeQty = min($maxPossibleQty, $remainingProduct['quantity']); $takeWeight = $takeQty * $remainingProduct['weight']; // 计算对应容积:两种方式可选,根据你的实际数据结构调整 // 方式1:按单个产品容积计算(适合cubic是单个产品的容积) $takeCubic = $takeQty * $remainingProduct['cubic']; // 方式2:按总容积比例计算(适合total_cubic是该组产品的总容积) // $takeCubic = $remainingProduct['total_cubic'] * ($takeQty / $remainingProduct['quantity']); // 将取出的产品部分加入当前箱子 $currentBox['items'][] = [ 'product_id' => $remainingProduct['product_id'], 'quantity' => $takeQty, 'weight' => $remainingProduct['weight'], 'cubic' => $remainingProduct['cubic'], 'total_weight' => $takeWeight, 'total_cubic' => $takeCubic ]; // 更新当前箱子的总重量和总容积 $currentBox['total_weight'] += $takeWeight; $currentBox['total_cubic'] += $takeCubic; // 更新剩余产品的数量和总重量 $remainingProduct['quantity'] -= $takeQty; $remainingProduct['total_weight'] -= $takeWeight; if ($remainingProduct['quantity'] == 0) { // 当前产品已全部装箱,跳出循环处理下一个产品 break; } else { // 当前箱子已满,创建新箱子继续装剩余产品 $currentBoxIndex++; $boxes[$currentBoxIndex] = [ 'total_weight' => 0, 'total_cubic' => 0, 'items' => [] ]; } } } // 整理输出格式,匹配你原代码的输出结构(可根据实际需求调整) $formattedBoxes = []; foreach ($boxes as $boxIdx => $box) { $formattedBoxes[] = [ 'item_reference' => $products[0]['order_id'], 'cubic_volume' => number_format($box['total_cubic'], 5), 'weight' => number_format($box['total_weight'], 2), 'packaging_type' => 'CTN', 'product_id' => 'EXP', 'authority_to_leave' => false, // 原代码中$orders未定义,这里默认false,可根据实际情况修改 'tracking_details' => [ 'article_id' => 'test', 'consignment_id' => 'test', 'barcode_id' => 'test' ], 'items' => $box['items'] // 可选:保留箱内产品明细,方便核对 ]; } $itemArray[] = $formattedBoxes; } echo "<pre>"; print_r($itemArray); echo "</pre>"; ?>
关键逻辑说明
- 箱子生命周期管理:每个订单开始时初始化第一个箱子,当当前箱子剩余容量不足时自动创建新箱子,确保装箱流程连续。
- 逐产品循环处理:对每个产品,循环处理其剩余数量,直到该产品全部装入箱子,避免遗漏。
- 精准计算可装数量:根据箱子剩余重量和产品单重,计算最多能装的产品数量,确保不超过重量阈值。
- 容积计算适配:提供两种容积计算方式,你可以根据实际数据结构(
cubic是单个产品容积还是组总容积)切换使用。 - 剩余产品延续处理:如果产品未全部装完,自动切换到新箱子继续处理,保证产品不会被丢弃。
验证示例
针对你给出的第一箱需求:
- 第一组产品(5个,6.5kg)全部装入,容积按方式1计算为
5*0.00267=0.01335(如果用方式2则是原total_cubic0.00267) - 第二组产品(6个,9kg)全部装入,容积为
6*0.00348=0.02088(方式2则是0.00348) - 第三组产品取3个(4.5kg),容积为
3*0.00267=0.00801(方式2则是0.00267*(3/7)=0.00114) - 总重
6.5+9+4.5=20kg,符合阈值要求
你可以根据自己的实际数据结构调整容积计算方式,确保得到你预期的结果。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

