array( 'skucategory' => '按商品品类拆', 'skuweight' => '按商品重量拆', 'skuvolume' => '按商品体积拆', )]; } #拆单规则保存前处理 /** * preSaveSdf * @param mixed $sdf sdf * @return mixed 返回值 */ public function preSaveSdf(&$sdf) { if($sdf['split_type'] != 'storemax') { return [true]; } if($sdf['split_config']['split_type_2']) { list($rs, $msg) = kernel::single('omeauto_split_router', $sdf['split_config']['split_type_2'])->preSaveSdf($sdf); if(!$rs) { return [false, $msg]; } if($sdf['split_config']['split_type_2'] == $sdf['split_config']['split_type_3']) { return [false, '第二层与第三层拆分不能一致']; } } if($sdf['split_config']['split_type_3']) { list($rs, $msg) = kernel::single('omeauto_split_router', $sdf['split_config']['split_type_3'])->preSaveSdf($sdf); if(!$rs) { return [false, $msg]; } } return array(true, '保存成功'); } #拆分订单 /** * splitOrder * @param mixed $group group * @param mixed $splitConfig 配置 * @return mixed 返回值 */ public function splitOrder(&$group, $splitConfig) { $arrOrder = $group->getOrders(); $arrOrderId = array(); $splitOrder = array(); foreach ($arrOrder as $ok => $order) { $arrOrderId[] = $order['order_id']; } list($rs, $msg) = $this->_splitOrderByStore($arrOrder, $group, $splitConfig); if (!$rs) { return array(false, $msg); } if($splitConfig['split_type_2']) { list($rs, $msg) = kernel::single('omeauto_split_router', $splitConfig['split_type_2'])->splitOrderFromSplit($arrOrder, $group, $splitConfig); if(!$rs) { return [false, $msg]; } } if($splitConfig['split_type_3']) { list($rs, $msg) = kernel::single('omeauto_split_router', $splitConfig['split_type_3'])->splitOrderFromSplit($arrOrder, $group, $splitConfig); if(!$rs) { return [false, $msg]; } } $splitOrder = $arrOrder; if ($arrOrderId) { $group->setSplitOrderId($arrOrderId); } $group->updateOrderInfo($splitOrder); if (empty($splitOrder)) { return array(false, '无法拆单'); } return array(true); } /** * splitOrderFromSplit * @param mixed $arrOrder arrOrder * @param mixed $group group * @param mixed $splitConfig 配置 * @return mixed 返回值 */ public function splitOrderFromSplit(&$arrOrder, &$group, $splitConfig) { return $this->_splitOrderByStore($arrOrder, $group, $splitConfig); } protected function _splitOrderByStore(&$arrOrder, &$group, $splitConfig) { $group->setConfirmBranch(true); $bmIdNum = array(); foreach ($arrOrder as $k => $order) { foreach ($order['objects'] as $ok => $object) { foreach ($object['items'] as $ik => $item) { if($splitConfig['from'] == 'split') { $bmIdNum[$item['product_id']] += $item['nums']; continue; } if ($item['nums'] > $item['split_num']) { $arrOrder[$k]['objects'][$ok]['items'][$ik]['original_num'] = $item['nums']; $arrOrder[$k]['objects'][$ok]['items'][$ik]['nums'] = $nums = $item['nums'] - $item['split_num']; if ($bmIdNum[$item['product_id']]) { $bmIdNum[$item['product_id']] += $nums; } else { $bmIdNum[$item['product_id']] = $nums; } } else { unset($arrOrder[$k]['objects'][$ok]['items'][$ik]); } } if (empty($arrOrder[$k]['objects'][$ok]['items'])) { unset($arrOrder[$k]['objects'][$ok]); } } if (empty($arrOrder[$k]['objects'])) { unset($arrOrder[$k]); } } if (empty($arrOrder)) { return array(false, '可拆单明细为空,无需拆分'); } $arrBranchId = $group->getBranchId(); $bmIds = array_keys($bmIdNum); if (!is_array($arrBranchId)) { //手工批量审单 固定仓库 $bi = app::get('ome')->model('branch')->db_dump($arrBranchId, 'b_type,b_status'); $arrBranchId = array($arrBranchId); if ($bi['b_type'] == '2') { return array(false, '批量审单不支持门店'); } else { $storeRows = $this->getBranchStoreRows($arrBranchId, $bmIds); } } else { $tidBranchId = array(); foreach ($arrBranchId as $k => $v) { //选择第一个仓库规则 if(strpos($k, '-')) { list($tmpTid) = explode('-', $k); } else { $tmpTid = 0; } if (!isset($tid)) { $tid = $tmpTid; $branchConfig = $group->getAutoBranch(); $group->setAutoBranch((array) $branchConfig[$tid]); } if ($tid == $tmpTid) { $tidBranchId[] = $v; } } $storeRows = $this->getStoreRows($tidBranchId, $bmIds, $splitConfig, $arrOrder); } if (empty($storeRows)) { $group->setOrderStatus('*', omeauto_auto_const::__STORE_CODE); return array(false, '有库存的仓库不存在'); } //选取sku最全的仓库 $maxBranch = array(); $branchInfo = array(); foreach ($storeRows as $val) { $validNum = $val['store'] > $val['store_freeze'] ? $val['store'] - $val['store_freeze'] : 0; if ($validNum) { $maxBranch[$val['branch_id']] += 1; $branchInfo[$val['branch_id']]['branch_id'] = $val['branch_id']; $branchInfo[$val['branch_id']]['store'][$val['product_id']] = $validNum; } } if (empty($maxBranch)) { $group->setOrderStatus('*', omeauto_auto_const::__STORE_CODE); return array(false, '有可用库存的仓库不存在'); } $rs = $this->dealStoreOrder($arrOrder, $branchInfo, $splitConfig); if(empty($rs['branchInfo'])) { $group->setOrderStatus('*', omeauto_auto_const::__STORE_CODE); return [false, '库存不足无法拆单']; } $canBranchId = []; foreach ($rs['is_split'] as $branchId => $value) { if(!$value) { $canBranchId[] = $branchId; } } if(!$canBranchId) { arsort($rs['sku_num']); $max = current($rs['sku_num']); foreach ($rs['sku_num'] as $branchId => $num) { if($max == $num) { $canBranchId[] = $branchId; } } } if(count($canBranchId) == 1) { $branchId = current($canBranchId); } else { $group->updateOrderInfo($arrOrder); $group->setBranchId($canBranchId); $branchId = kernel::single('omeauto_branch_choose')->getSelectBid($tid, $group, $rs['branchInfo']); } $resultBranch = app::get('ome')->model('branch')->db_dump($branchId, 'b_type,b_status'); if ($resultBranch['b_type'] == '2') { $group->setStoreBranch(); $group->setStoreDlyType('o2o_ship'); } $logResult = [ '初始值' => $branchInfo, '拆分情况' => $rs, '初选仓' => $canBranchId, '终选仓' => $branchId ]; $this->writeSuccessLog($logResult, $arrOrder); if(isset($tid)) {#有仓库规则需要重置仓库 $group->setBranchId(array($branchId)); } $arrOrder = $rs['order'][$branchId]; return [true]; } #根据库存订单处理拆分 protected function dealStoreOrder($arrOrder, $branchInfo, $splitConfig) { $return = ['branchInfo'=>[], 'order'=>[], 'sku_num'=>[], 'is_split'=>[]]; if ($splitConfig['dimension'] == '1') { return $this->dealStoreOrderObject($arrOrder, $branchInfo); } foreach ($branchInfo as $branch_id => $value) { $tmpBI = ['branch_id'=>$branch_id, 'store'=>[]]; $tmpSN = 0; $is_split = false; $tmpOrder = $arrOrder; foreach ($tmpOrder as $k => $order) { foreach ($order['objects'] as $ok => $object) { foreach ($object['items'] as $ik => $item) { if($value['store'][$item['product_id']] < $item['nums']) { $num = $value['store'][$item['product_id']]; $is_split = true; } else { $num = $item['nums']; } if($num < 1) { unset($tmpOrder[$k]['objects'][$ok]['items'][$ik]); continue; } $tmpOrder[$k]['objects'][$ok]['items'][$ik]['nums'] = $num; $value['store'][$item['product_id']] -= $num; $tmpBI['store'][$item['product_id']] += $num; $tmpSN += $num; } if(empty($tmpOrder[$k]['objects'][$ok]['items'])) { unset($tmpOrder[$k]['objects'][$ok]); } } if(empty($tmpOrder[$k]['objects'])) { unset($tmpOrder[$k]); } } if($tmpOrder) { $return['branchInfo'][$branch_id] = $tmpBI; $return['order'][$branch_id] = $tmpOrder; $return['sku_num'][$branch_id] = $tmpSN; $return['is_split'][$branch_id] = $is_split; } } return $return; } #根据订单库存拆分销售物料 protected function dealStoreOrderObject($arrOrder, $branchInfo) { $return = ['branchInfo'=>[], 'order'=>[], 'sku_num'=>[], 'is_split'=>[]]; foreach ($arrOrder as $order) { foreach ($order['objects'] as $object) { $smIds[$object['goods_id']] = $object['goods_id']; } } $smBc = app::get('material')->model('sales_basic_material')->getList('sm_id, bm_id, number', array('sm_id'=>$smIds)); $smBmNumber = array(); foreach ($smBc as $v) { $smBmNumber[$v['sm_id']][$v['bm_id']] = $v['number']; } foreach ($branchInfo as $branch_id => $value) { $tmpBI = ['branch_id'=>$branch_id, 'store'=>[]]; $tmpSN = 0; $is_split = false; $tmpOrder = $arrOrder; foreach ($tmpOrder as $k => $order) { foreach ($order['objects'] as $ok => $object) { $objNumber = null; foreach ($object['items'] as $ik => $item) { $unitNumber = $smBmNumber[$object['goods_id']][$item['product_id']] ? : 1; if($value['store'][$item['product_id']] < $item['nums']) { $num = $value['store'][$item['product_id']]; } else { $num = $item['nums']; } $objTmpNum = floor($num / $unitNumber); if($objTmpNum < 1) { $objNumber = 0; break; } if(!isset($objNumber) || $objNumber > $objTmpNum) { $objNumber = $objTmpNum; } } if($objNumber) { foreach ($object['items'] as $ik => $item) { $unitNumber = $smBmNumber[$object['goods_id']][$item['product_id']] ? : 1; $num = intval($objNumber * $unitNumber); if($num < $item['nums']) { $is_split = true; } $tmpOrder[$k]['objects'][$ok]['items'][$ik]['nums'] = $num; $value['store'][$item['product_id']] -= $num; $tmpBI['store'][$item['product_id']] += $num; $tmpSN += $num; } } else { unset($tmpOrder[$k]['objects'][$ok]); $is_split = true; } } if(empty($tmpOrder[$k]['objects'])) { unset($tmpOrder[$k]); } } if($tmpOrder) { $return['branchInfo'][$branch_id] = $tmpBI; $return['order'][$branch_id] = $tmpOrder; $return['sku_num'][$branch_id] = $tmpSN; $return['is_split'][$branch_id] = $is_split; } } return $return; } protected function getStoreRows($arrBranchId, $bmIds, $splitConfig, $arrOrder) { switch ($splitConfig['s_type']) { case '1': #先电商仓再门店仓 $storeRows = $this->getBranchStoreRows($arrBranchId, $bmIds); if (empty($storeRows)) { $storeRows = $this->getO2oStoreRows($bmIds, $arrOrder); } break; case '2': #先门店仓再电商仓 $storeRows = $this->getO2oStoreRows($bmIds, $arrOrder); if (empty($storeRows)) { $storeRows = $this->getBranchStoreRows($arrBranchId, $bmIds); } break; case '3': #同时门店仓电商仓,优先门店仓 $branchStoreRows = $this->getBranchStoreRows($arrBranchId, $bmIds); $o2oStoreRows = $this->getO2oStoreRows($bmIds, $arrOrder); $storeRows = $o2oStoreRows; foreach ($branchStoreRows as $v) { $storeRows[] = $v; } break; case '4': #同时电商仓门店仓,优先电商仓 $branchStoreRows = $this->getBranchStoreRows($arrBranchId, $bmIds); $o2oStoreRows = $this->getO2oStoreRows($bmIds, $arrOrder); $storeRows = $branchStoreRows; foreach ($o2oStoreRows as $v) { $storeRows[] = $v; } break; case '5': #仅门店仓 $storeRows = $this->getO2oStoreRows($bmIds, $arrOrder); break; default: #仅电商仓 $storeRows = $this->getBranchStoreRows($arrBranchId, $bmIds); break; } return $storeRows; } protected function getBranchStoreRows($arrBranchId, $bmIds) { /* $modelBp = app::get('ome')->model('branch_product'); $bpFilter = array( 'product_id' => $bmIds, 'branch_id' => $arrBranchId, 'filter_sql' => 'store>store_freeze', ); $storeRows = $modelBp->getList('branch_id, product_id, store, store_freeze', $bpFilter); */ $arrBranchId = $this->filterBranchesByStoreControl($arrBranchId); $storeRows = $this->batchStoreFromRedis($bmIds, $arrBranchId); return $this->sortBranchById($storeRows, $arrBranchId); } protected function batchStoreFromRedis($bmIds, $arrBranchId) { $storeRows = []; foreach ($bmIds as $product_id) { foreach ($arrBranchId as $branch_id) { $rs = ome_branch_product::storeFromRedis(['branch_id' => $branch_id, 'product_id' => $product_id]); if(!$rs[0]) { continue; } if($rs[2]['store'] <= $rs[2]['store_freeze']) { continue; } $storeRows[] = [ 'branch_id' => $branch_id, 'product_id' => $product_id, 'store' => $rs[2]['store'], 'store_freeze' => $rs[2]['store_freeze'], ]; } } return $storeRows; } #storeRows 根据 arrBranchId 排序 protected function sortBranchById($storeRows, $arrBranchId) { if (empty($storeRows)) { return array(); } $tmpStore = array(); foreach ($storeRows as $v) { $index = array_search($v['branch_id'], $arrBranchId); if ($index !== false) { $tmpStore[$index][] = $v; } } ksort($tmpStore); $ttmpStore = array(); foreach ($tmpStore as $v) { foreach ($v as $vv) { $ttmpStore[] = $vv; } } return $ttmpStore; } protected function getO2oStoreRows($bmIds, $arrOrder) { //如果全局不管控供货关系即门店不管控库存 $supply_relation = app::get('o2o')->getConf('o2o.ctrl.supply.relation'); if ($supply_relation != 'true') { //return array(); } #启用的门店 $branchLib = kernel::single('ome_interface_branch'); $branchRows = $branchLib->getList('branch_id,branch_bn', array('b_type' => 2, 'b_status' => 1, 'is_ctrl_store' => '1'), 0, -1); if (empty($branchRows)) { return array(); } $refuse_stores = app::get('o2o')->model('store_refuse_analysis')->get_refuse_stores(array_column($arrOrder, 'order_id')); $branchIds = array(); foreach ($branchRows as $v) { // 排除掉拒绝的门店 if (in_array($v['branch_bn'], $refuse_stores)) { continue; } $branchIds[] = $v['branch_id']; } #商品库存 $productStoreObj = app::get('ome')->model('branch_product'); $psFilter = array( 'product_id' => $bmIds, 'branch_id' => $branchIds, 'filter_sql' => 'store>store_freeze', ); // $psRows = $productStoreObj->getList('branch_id,product_id,store,store_freeze', $psFilter); $storeRows = $this->batchStoreFromRedis($bmIds, $branchIds); if (empty($storeRows)) { return array(); } #门店权重排序 $o2oStoreId = app::get('o2o')->model('store')->getList('branch_id', array('branch_id' => $psFilter['branch_id']), 0, -1, 'priority desc'); $arrO2oBranchId = array_map('current', $o2oStoreId); return $this->sortBranchById($storeRows, $arrO2oBranchId); } protected function writeSuccessLog($logResult, $arrOrder) { $bmIdBn = array(); $arrOrderBn = array(); foreach ($arrOrder as $order) { foreach ($order['objects'] as $ok => $object) { foreach ($object['items'] as $ik => $item) { $bmIdBn[$item['product_id']] = $item['bn']; } } $arrOrderBn[] = $order['order_bn']; } $branchId = array(); foreach ($logResult['初始值'] as $v) { $branchId[] = $v['branch_id']; } $branchLib = kernel::single('ome_interface_branch'); $branchRows = $branchLib->getList('branch_id, branch_bn', array('branch_id' => $branchId)); $branchIdBn = array(); foreach ($branchRows as $v) { $branchIdBn[$v['branch_id']] = $v['branch_bn']; } $logResult['id对应编码'] = [ '基础物料'=>$bmIdBn, '仓库'=>$branchIdBn, ]; $apilogModel = app::get('ome')->model('api_log'); $log_id = $apilogModel->gen_id(); $logsdf = array( 'log_id' => $log_id, 'task_name' => '按库存就全拆结果', 'status' => 'success', 'worker' => '', 'params' => json_encode(array('store.split', $logResult), JSON_UNESCAPED_UNICODE), #longtext 'msg' => '', #text json字符串 'log_type' => '', 'api_type' => 'response', 'memo' => '', 'original_bn' => $arrOrderBn[0], 'createtime' => time(), 'last_modified' => time(), 'msg_id' => '', ); $apilogModel->insert($logsdf); } /** * 过滤出管控库存的仓库 * @param array $branchIds 仓库ID数组 * @return array 管控库存的仓库ID数组 */ protected function filterBranchesByStoreControl($branchIds) { if (empty($branchIds)) { return []; } $branchLib = kernel::single('ome_interface_branch'); $branchList = $branchLib->getList('branch_id', ['branch_id' => $branchIds, 'is_ctrl_store' => '1'], 0, -1); if (empty($branchList)) { return []; } // 获取满足条件的分支ID集合 $branchList = array_column($branchList, null,'branch_id'); // 循环遍历原始数组,删除不满足条件的分支ID foreach ($branchIds as $bkey => $branch_id) { if (!isset($branchList[$branch_id])) { unset($branchIds[$bkey]); } } return $branchIds; } }