[branch_bn, ...] */ public function setApplySupplyBranches($applySupplyBranches) { $this->applySupplyBranches = $applySupplyBranches; } /** * 获取供货仓列表 * 优先使用应用专用供货仓,如果不存在则使用店铺默认供货仓 * @param string $shop_bn 店铺编码 * @param string $shop_id 店铺ID * @return array 供货仓编码数组 */ protected function getSupplyBranches($shop_bn, $shop_id) { // 先判断是否存在应用专供仓 if (!empty($this->applySupplyBranches) && is_array($this->applySupplyBranches)) { return $this->applySupplyBranches; } // 如果不存在,使用店铺默认供货仓 return kernel::single('inventorydepth_shop')->getBranchByshop($shop_bn); } protected function initMaterial($salesmaterial) {//初始化物料 //shop_id $shopIds = array_unique(array_column($salesmaterial, 'shop_id')); if(array_search('_ALL_', $shopIds) !== false) { $this->shop_delivery_mode = 'self'; $shopIds[] = 0; //避免只有_ALL_的时候, 被dbeav_filter过滤掉 } if($shopIds){ $shopRows = app::get('ome')->model('shop')->getList('delivery_mode', ['shop_id'=>$shopIds]); if($shopRows) { $delivery_mode = array_unique(array_column($shopRows, 'delivery_mode')); if(count($delivery_mode) > 1) { $this->throwException('店铺的发货方式不能混用:'.json_encode($shopIds)); return; } if($this->shop_delivery_mode) { if($this->shop_delivery_mode != $delivery_mode[0]) { $this->throwException('店铺的发货方式不能混用:'.json_encode($shopIds)); return; } } else { $this->shop_delivery_mode = $delivery_mode[0]; } } } //shopyjdf if($this->shop_delivery_mode == 'shopyjdf') { $this->initYjdfMaterial($salesmaterial); } else { $this->initSelfMaterial($salesmaterial); } } protected function initYjdfMaterial($salesmaterial) { //yjdf店铺物料 $smId = $sp = []; foreach ($salesmaterial as $key => $value) { $this->salesmaterialBnId[$value['sales_material_bn']][$value['shop_id']] = $value['sm_id']; $this->salesmaterial[$value['sm_id']] = $value; $smId[] = $value['sm_id']; $this->salesmaterial[$value['sm_id']]['products'] = &$sp[$value['sm_id']]; } $salesMLib = kernel::single('material_sales_material'); if($smId) { $smbc = app::get('dealer')->model('sales_basic_material'); $smProduct = $salesMLib->getBasicMBySalesMIds($smId, $smbc); foreach ((array)$smProduct as $key=>$value) { foreach ($value as $bm) { $this->basicmaterial[$bm['bm_id']] = $bm; } $sp[$key] = $value; } } } protected function initSelfMaterial($salesmaterial) { //自发店铺物料 $pkoSmId = $smId = $pkop = $sp = $luckySmids = $luckyList = []; foreach ($salesmaterial as $key => $value) { $this->salesmaterialBnId[$value['sales_material_bn']][$value['shop_id']] = $value['sm_id']; $this->salesmaterial[$value['sm_id']] = $value; //按销售物料类型 if($value['sales_material_type'] == 5){ //多选一 $pkoSmId[] = $value['sm_id']; $this->salesmaterial[$value['sm_id']]['products'] = &$pkop[$value['sm_id']]; }elseif($value['sales_material_type'] == 7){ //福袋组合 $luckySmids[] = $value['sm_id']; $this->salesmaterial[$value['sm_id']]['products'] = &$luckyList[$value['sm_id']]; }else{ $smId[] = $value['sm_id']; $this->salesmaterial[$value['sm_id']]['products'] = &$sp[$value['sm_id']]; } } $salesMLib = kernel::single('material_sales_material'); if($pkoSmId) { //获取多选一销售物料对应的基础物料明细 $pkoProduct = $salesMLib->get_pickone_sm_bm($pkoSmId); foreach((array)$pkoProduct as $key => $value){ //key是sm_id foreach ($value as $bm) { $this->basicmaterial[$bm['bm_id']] = $bm; } $pkop[$key] = $value; } } if($smId) { $smProduct = $salesMLib->getBasicMBySalesMIds($smId); foreach ((array)$smProduct as $key=>$value) { foreach ($value as $bm) { $this->basicmaterial[$bm['bm_id']] = $bm; } $sp[$key] = $value; } } //福袋组合 if($luckySmids){ //福袋组合 //@todo:最终返回的是三层结构(销售物料-->福袋组合-->基础物料) $combineLib = kernel::single('material_fukubukuro_combine'); $error_msg = ''; //福袋组合包含的基础物料列表 $luckyBagList = $combineLib->getLuckyMaterialBySmid($luckySmids, $error_msg); if(empty($luckyBagList)){ $luckyBagList = array(); } foreach ($luckyBagList as $sm_id => $luckyInfo) { //销售物料关联的福袋列表 $luckyList[$sm_id] = $luckyInfo; //按福袋纬度 foreach ((array)$luckyInfo as $combine_id => $combineInfo) { //check if(empty($combineInfo['items'])){ continue; } //关联的基础物料列表 foreach ($combineInfo['items'] as $bm_id => $bmInfo) { $this->basicmaterial[$bm_id] = $bmInfo; } } } //unset unset($luckyBagList); } } protected function initBranchProduct() { $bmIds = array_keys($this->basicmaterial); if(empty($bmIds)) { return; } $branches = app::get('ome')->model('branch')->getList('branch_id,branch_bn,b_type', ['check_permission'=>'false']); foreach ($branches as $key=>$branch) { $this->branch[$branch['branch_bn']] = $branch; } $bpModel = app::get('ome')->model('branch_product'); $branch_product = $bpModel->getList('branch_id,product_id,store,store_freeze,last_modified,arrive_store,safe_store', ['product_id'=>$bmIds]); foreach ($branch_product as $key=>$bp) { $bp = $this->resetBranchProductStore($bp); $this->branch_product[$bp['product_id']][$bp['branch_id']] = $bp; } } protected function resetBranchProductStore($bp) { $branchLib = kernel::single('ome_branch'); $channelLib = kernel::single('channel_func'); $basicMStorageLifeLib = kernel::single('material_storagelife'); $branch_id = $bp['branch_id']; $product_id = $bp['product_id']; if(empty($branch_id) || empty($product_id)) { return $bp; } //是否自有仓储 if(isset($this->tmp_is_selfwms[$branch_id])){ $is_selfWms = $this->tmp_is_selfwms[$branch_id]; }else{ $wms_id = $branchLib->getWmsIdById($branch_id); if($wms_id){ $is_selfWms = $channelLib->isSelfWms($wms_id); }else{ $is_selfWms = false; } $this->tmp_is_selfwms[$branch_id] = $is_selfWms; } //是否保质期物料 if(isset($this->tmp_is_use_expire[$product_id])){ $is_use_expire = $this->tmp_is_use_expire[$product_id]; }else{ $is_use_expire = $basicMStorageLifeLib->checkStorageLifeById($product_id); $this->tmp_is_use_expire[$product_id] = $is_use_expire; } //扣减失效的保质期库存 if($is_selfWms && $is_use_expire){ //仓库货品下失效的保质期库存数 if(isset($this->tmp_expire_store[$product_id][$branch_id])){ $expire_store = $this->tmp_expire_store[$product_id][$branch_id]; }else{ $expire_store = $basicMStorageLifeLib->getExpireStorageLifeStore($branch_id, $product_id); $this->tmp_expire_store[$product_id][$branch_id] = $expire_store; } if($expire_store){ $bp['store'] = $bp['store'] - $expire_store; } } return $bp; } public function initOrderFreeze() { $bmIds = array_keys($this->basicmaterial); if(empty($bmIds)) { return; } $shop = app::get('ome')->model('shop')->getList('shop_id', ['delivery_mode'=>'jingxiao']); $notInShop = ''; if($shop) { $notInShop = "and shop_id not in ('".implode("','", array_column($shop, 'shop_id'))."')"; } $bmIdStr = "('".implode("','", $bmIds)."')"; $sql = "SELECT sum(num) as total,shop_id,bm_id FROM sdb_material_basic_material_stock_freeze WHERE bm_id in {$bmIdStr} AND obj_type=1 AND branch_id=0 {$notInShop} GROUP BY bm_id, shop_id"; $list = kernel::database()->select($sql); foreach ($list as $key => $value) { $sha1Str = sha1($value['shop_id'].'-'.$value['bm_id']); $this->shopFreeze[$sha1Str] = (int) $value['total']; } $you = material_basic_material_stock_freeze::__ORDER_YOU; $sql = "SELECT sum(num) as total,branch_id,bm_id FROM sdb_material_basic_material_stock_freeze WHERE bm_id in {$bmIdStr} AND obj_type=1 AND branch_id<>0 AND bill_type<>{$you} {$notInShop} GROUP BY bm_id, branch_id"; $list = kernel::database()->select($sql); foreach ($list as $key => $value) { $sha1Str = sha1($value['branch_id'].'-'.$value['bm_id']); $this->appointBranchFreeze[$sha1Str] = (int) $value['total']; } } public function init($salesmaterial) { //自动回写库存初始化数据 $this->isInit = true; $this->salesmaterialBnId = []; $this->salesmaterial = []; $this->basicmaterial = []; $this->shop_delivery_mode = ''; $this->initMaterial($salesmaterial); $this->branch = []; $this->branch_product = []; $this->tmp_is_selfwms = []; $this->tmp_is_use_expire = []; $this->tmp_expire_store = []; $this->initBranchProduct(); $this->shopFreeze = []; $this->appointBranchFreeze = []; $this->initOrderFreeze(); } public function initBasicMaterial($bmIds) { $list = kernel::single('material_basic_material')->getBasicMaterialByBmids($bmIds); foreach ($list as $bm) { $this->basicmaterial[$bm['bm_id']] = $bm; } } public function initFromBasic($bmIds) { //基础物料可售库存初始化数据 $this->isInit = true; $this->salesmaterialBnId = []; $this->salesmaterial = []; $this->basicmaterial = []; $this->shop_delivery_mode = ''; $this->initBasicMaterial($bmIds); $this->branch = []; $this->branch_product = []; $this->tmp_is_selfwms = []; $this->tmp_is_use_expire = []; $this->tmp_expire_store = []; $this->initBranchProduct(); $this->shopFreeze = []; $this->appointBranchFreeze = []; $this->initOrderFreeze(); } public function getSalesMaterialType($salesMaterialBn, $shopId) { $salesmaterial = $this->getSalesMaterial($salesMaterialBn, $shopId); if($salesmaterial['sales_material_type'] == 2){ //促销 return 'pkg'; }elseif($salesmaterial['sales_material_type'] == 7){ //福袋类型 return 'fukubukuro'; } if($salesmaterial['sales_material_type'] == 5){ //多选一 return 'pko'; } if ($salesmaterial['sales_material_type'] == 3) { //多选一 return 'gift'; } return 'product'; } public function getSalesMaterial($salesMaterialBn, $shopId) { if($this->salesmaterialBnId[$salesMaterialBn] && $this->salesmaterialBnId[$salesMaterialBn][$shopId]) { return $this->salesmaterial[$this->salesmaterialBnId[$salesMaterialBn][$shopId]]; } if($this->shop_delivery_mode == 'self') { if($this->salesmaterialBnId[$salesMaterialBn] && $this->salesmaterialBnId[$salesMaterialBn]['_ALL_']) { return $this->salesmaterial[$this->salesmaterialBnId[$salesMaterialBn]['_ALL_']]; } } if($this->isInit) { return []; } $salesMaterialObj = app::get('material')->model('sales_material'); $goods = $salesMaterialObj->db_dump(array('sales_material_bn'=>$salesMaterialBn), 'sm_id,sales_material_name,sales_material_bn,sales_material_type,shop_id'); if(empty($goods)){ return []; } //sm_id $sm_id = $goods['sm_id']; //根据类型组合销售物料数据 if($goods['sales_material_type'] == 7) { //福袋组合 //@todo:最终返回的是三层结构(销售物料-->福袋组合-->基础物料) $combineLib = kernel::single('material_fukubukuro_combine'); $error_msg = ''; //福袋组合包含的基础物料列表 $luckyBagList = $combineLib->getLuckyMaterialBySmid(array($sm_id), $error_msg); if(!$luckyBagList){ $luckyBagList = array(); } $goods['products'] = $luckyBagList[$sm_id]; //销售物料关联的福袋列表 foreach((array)$goods['products'] as $luckyKey => $luckyVal) { //check if(empty($luckyVal['items'])){ continue; } //福袋关联的基础物料列表 foreach ($luckyVal['items'] as $bmKey => $bmVal) { $bm_id = $bmVal['bm_id']; $this->basicmaterial[$bm_id] = $bmVal; } } }else{ $salesMLib = kernel::single('material_sales_material'); if($goods['sales_material_type'] == 5) { //多选一 $pkoProduct = $salesMLib->get_pickone_sm_bm(array($goods['sm_id'])); $goods['products'] = $pkoProduct[$goods['sm_id']]; } else { $products = $salesMLib->getBasicMBySalesMId($goods['sm_id']); $goods['products'] = $products; } foreach((array)$goods['products'] as $key => $value){ $this->basicmaterial[$value['bm_id']] = $value; } } $this->salesmaterialBnId[$salesMaterialBn] = $goods['sm_id']; $this->salesmaterial[$goods['sm_id']] = $goods; return $this->salesmaterial[$goods['sm_id']] ; } protected function throwException($msg) { throw new exception($msg); } public function getBranch($branch_bn) { if($this->branch[$branch_bn]) { return $this->branch[$branch_bn]; } if($this->isInit) { return []; } $this->throwException('未进行初始化'); return []; } public function getBranchProduct($bm_id, $branch_id) { if($this->branch_product[$bm_id][$branch_id]) { return $this->branch_product[$bm_id][$branch_id]; } if($this->isInit) { return []; } $this->throwException('未进行初始化'); return []; } //获取可售库存 public function get_actual_stock($bm_id, $shop_bn, $shop_id) { return $this->getActualStock($bm_id, $shop_bn, $shop_id); } //获取仓库可售库存 public function get_branch_actual_stock($bm_id, $shop_bn, $shop_id) { return $this->getActualStock($bm_id, $shop_bn, $shop_id, 'branch'); } //获取门店可售库存 public function get_md_actual_stock($bm_id, $shop_bn, $shop_id) { return $this->getActualStock($bm_id, $shop_bn, $shop_id, 'md'); } //获取可售安全库存 public function get_actual_safe_stock($bm_id, $shop_bn, $shop_id) { return $this->getActualStock($bm_id, $shop_bn, $shop_id, 'all', true); } //获取仓库可售安全库存 public function get_branch_actual_safe_stock($bm_id, $shop_bn, $shop_id) { return $this->getActualStock($bm_id, $shop_bn, $shop_id, 'branch', true); } //获取门店可售安全库存 public function get_md_actual_safe_stock($bm_id, $shop_bn, $shop_id) { return $this->getActualStock($bm_id, $shop_bn, $shop_id, 'md', true); } protected function getActualStock($bm_id, $shop_bn, $shop_id, $type = 'all', $safe = false) { $branches = $this->getSupplyBranches($shop_bn, $shop_id); if (!$branches) { return [false, ['error'=>'店铺'.$shop_bn.'缺少供货仓']]; } $sha1Str = $bm_id.'-'.$shop_id.'-'.$type.($safe ? '-safe' : '').implode('|', $branches); $sha1 = sha1($sha1Str); if(isset($this->actualStock[$sha1])) return [$this->actualStock[$sha1], $this->actualStockMake[$sha1]]; $store_sum = $store_freeze_sum = $appoint_freeze = $safeActual = 0; $detail = []; foreach ($branches as $branch_bn) { $branch = $this->getBranch($branch_bn); if($type == 'branch' && $branch['b_type'] == 2) { continue; } if($type == 'md' && $branch['b_type'] != 2) { continue; } $branch_product = $this->getBranchProduct($bm_id, $branch['branch_id']); if ($branch_product) { $store_sum += $branch_product['store']; $store_freeze_sum += $branch_product['store_freeze']; } list($tmpAF,) = $this->get_appoint_branch_freeze($bm_id, $branch['branch_id']); $appoint_freeze += $tmpAF; $tmpSA = $branch_product['store'] - $branch_product['store_freeze'] - $tmpAF - $branch_product['safe_store']; $tmpSA = $tmpSA > 0 ? $tmpSA : 0; $safeActual += $tmpSA; $detail[$branch_bn]['库存'] = $branch_product['store']; $detail[$branch_bn]['仓库预占'] = $branch_product['store_freeze']; $detail[$branch_bn]['安全库存'] = $branch_product['safe_store']; $detail[$branch_bn]['指定仓预占'] = $tmpAF; $detail[$branch_bn]['安全可售'] = [ 'quantity' => $tmpSA, 'info' => '库存-仓库预占-指定仓预占-安全库存=安全可售(小于0时为0)' ]; } if($type == 'md') { if($safe) { $actual_stock = $safeActual; $this->actualStockMake[$sha1]['公式'] = '安全可售'; } else { $actual_stock = $store_sum - $store_freeze_sum - $appoint_freeze; $this->actualStockMake[$sha1]['公式'] = '库存-仓库预占-指定仓预占'; } } else { list($globals_freeze, ) = $this->get_globals_freeze($bm_id, $shop_bn, $shop_id); $globals_freeze = (int) $globals_freeze; if($safe) { $actual_stock = $safeActual - $globals_freeze; $this->actualStockMake[$sha1]['公式'] = '安全可售-全局预占'; } else { $actual_stock = $store_sum - $globals_freeze - $store_freeze_sum - $appoint_freeze; $this->actualStockMake[$sha1]['公式'] = '库存-全局预占-仓库预占-指定仓预占'; } $this->actualStockMake[$sha1]['全局预占'] = $globals_freeze; } $this->actualStockMake[$sha1]['库存'] = $store_sum; $this->actualStockMake[$sha1]['仓库预占'] = $store_freeze_sum; $this->actualStockMake[$sha1]['指定仓预占'] = $appoint_freeze; $this->actualStockMake[$sha1]['安全可售'] = $safeActual; $this->actualStockMake[$sha1]['detail'] = $detail; $this->actualStock[$sha1] = (int)$actual_stock > 0 ? (int)$actual_stock : 0; return [$this->actualStock[$sha1], $this->actualStockMake[$sha1]]; } //获取全局预占 public function get_globals_freeze($bm_id,$shop_bn,$shop_id) { $shop_branches = kernel::single('inventorydepth_shop')->getBranchByshop(); $branches = $this->getSupplyBranches($shop_bn, $shop_id); if (empty($branches) || empty($shop_branches)) { return [false, ['error'=>'仓库未绑定店铺']]; } $sha1Str = $shop_bn.'-'.$bm_id; $sha1 = sha1($sha1Str); if(isset($this->globalsFreeze[$sha1])) return [$this->globalsFreeze[$sha1], []]; # 获取这些仓所对应的所有店铺 $shopListKey = sha1($shop_bn . '-' . json_encode($branches)); if (!isset($this->shopList[$shopListKey])) { $shopes = array(); foreach ($branches as $branch_bn) { foreach ($shop_branches as $shop => $branch) { if (in_array($branch_bn, $branch)) { $shopes[] = $shop; } } } $s = app::get('ome')->model('shop')->getList('shop_id,shop_bn',array('shop_bn'=>$shopes)); $this->shopList[$shopListKey] = $s; } # 根据订单计算店铺预占(未发货订单) 该店铺下的商品ID $globals_freeze = 0; foreach ($this->shopList[$shopListKey] as $key=>$value) { list($tmpNum, )= $this->get_shop_freeze($bm_id, $value['shop_bn'], $value['shop_id']); $globals_freeze += $tmpNum; } $this->globalsFreeze[$sha1] = $globals_freeze > 0 ? (int)$globals_freeze : 0; return [$this->globalsFreeze[$sha1], []]; } //获取订单店铺预占 public function get_shop_freeze($bm_id, $shop_bn, $shop_id) { $sha1Str = sha1($shop_id.'-'.$bm_id); if(isset($this->shopFreeze[$sha1Str])) { return [$this->shopFreeze[$sha1Str], []]; } if($this->isInit) { return [0, []]; } $this->throwException('未进行初始化'); return []; } //获取订单指定仓预占 public function get_appoint_branch_freeze($product_id, $branch_id) { $sha1Str = sha1($branch_id.'-'.$product_id); if(isset($this->appointBranchFreeze[$sha1Str])) { return [$this->appointBranchFreeze[$sha1Str], []]; } if($this->isInit) { return [0, []]; } $this->throwException('未进行初始化'); return []; } }