Files
OMS/app/omeauto/lib/branch/router.php
2026-01-04 19:08:31 +08:00

336 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Copyright 2012-2026 ShopeX (https://www.shopex.cn)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* ============================
* @Author: yaokangming
* @Version: 1.0
* @DateTime: 2020/9/8 17:20:23
* @describe: 就近原则获取仓库
* ============================
*/
class omeauto_branch_router extends omeauto_branch_abstract {
private $orderBn;
private $location;
/**
* 处理
* @param mixed $branchIds ID
* @param mixed $group group
* @param mixed $branchInfo branchInfo
* @return mixed 返回值
*/
public function process($branchIds, &$group, $branchInfo) {
$orders = $group->getOrders();
$order = current($orders);
$this->orderBn = $order['order_bn'];
$shipArea = $order['ship_area'];
list(,,$areaId) = explode(':', $shipArea);
if(empty($areaId)) {
return $branchIds;
}
$bgData = $group->getBranchGroup();
if($bgData) {
$branchIds = array();
foreach ($bgData as $k => $v) {
$branchIds = array_merge($branchIds, $v['branch_id']);
}
$branchIds = array_unique($branchIds);
}
$branchMdl = app::get('ome')->model('branch');
$field = 'branch_id,branch_bn,name,area,location,b_type';
$branchInfo = $branchMdl->getList($field, array('branch_id'=>$branchIds,'check_permission' => 'false'), 0, -1, 'weight desc');
list($rs, $this->location) = kernel::single('console_map_order')->getLocation($order['order_id'], false);
if($rs) {
$branchInfo = $this->_getLocationBranch($branchInfo);
} else {
$branchInfo = $this->_getGroupBranch($areaId, $branchInfo);
}
$branchIds = array();
foreach ($branchInfo as $v) {
$branchIds[] = $v['branch_id'];
}
if($bgData) {
foreach ($bgData as $k => $v) {
if(!array_intersect($branchIds, $v['branch_id'])) {
unset($bgData[$k]);
continue;
}
}
$group->setBranchGroup($bgData);
}
return $branchIds;
}
protected function _getGroupBranch($areaId, $branchInfo){
if(!$this->_groupAreaId[$areaId]) {
$this->_groupAreaId[$areaId] = $this->_getGroupAreaId($areaId);
}
$groupBranch = array(
'distinct' => array(),
'city' => array(),
'province' => array(),
'logistics' => array(),
'province_router' => array(),
'country' => array(),
);
$logisticsBranchId = array();
// 预取门店仓覆盖区域,避免在循环中重复查询
$storeBranchIds = array();
foreach ((array)$branchInfo as $bi) {
if (isset($bi['b_type']) && intval($bi['b_type']) == 2) {
$storeBranchIds[] = intval($bi['branch_id']);
}
}
// bid => [lastRegionId, ...]
$bid2LastRegionIds = array();
// 收集所有末级覆盖region_id用于一次性查询其region_grade
$allLastRegionIds = array();
if (!empty($storeBranchIds)) {
$warehouseObj = app::get('logisticsmanager')->model('warehouse');
$warehouseList = $warehouseObj->getList('branch_id,region_ids', array('branch_id' => $storeBranchIds));
foreach ((array)$warehouseList as $wh) {
$bid = intval($wh['branch_id']);
if (empty($wh['region_ids'])) {
continue;
}
// 多组覆盖以分号分隔每组为逗号分隔的路径取每组最后一个ID
$groups = array_filter(array_map('trim', explode(';', $wh['region_ids'])));
foreach ($groups as $grp) {
$pathIds = array_filter(array_map('intval', explode(',', $grp)));
if (empty($pathIds)) {
continue;
}
$lastId = end($pathIds);
$bid2LastRegionIds[$bid][] = $lastId;
$allLastRegionIds[$lastId] = true;
}
}
}
// 查询这些末级region的等级grade构建映射
$regionId2Grade = array();
if (!empty($allLastRegionIds)) {
$regionModel = app::get('eccommon')->model('regions');
$regionRows = $regionModel->getList('region_id,region_grade', array('region_id' => array_keys($allLastRegionIds)));
foreach ((array)$regionRows as $row) {
$regionId2Grade[intval($row['region_id'])] = intval($row['region_grade']);
}
}
// 订单地区路径index为级数value为该级的region_id在_getGroupAreaId中已提供
$areaIdRegionPath = (array)$this->_groupAreaId[$areaId]['areaIdregionPath'];
foreach ($branchInfo as $val) {
if($val['b_type'] == 2) {
// 门店仓:先判断是否配置覆盖区域;未配置直接归入 country 并跳过
$bid = intval($val['branch_id']);
if (empty($bid2LastRegionIds[$bid])) {
$groupBranch['country'][] = $val;
continue;
}
// 覆盖区域存在按覆盖路径级数与订单路径同级ID一致判定可配送
$covered = false;
foreach ($bid2LastRegionIds[$bid] as $lastId) {
$grade = isset($regionId2Grade[$lastId]) ? $regionId2Grade[$lastId] : 0;
if ($grade > 0 && isset($areaIdRegionPath[$grade]) && intval($areaIdRegionPath[$grade]) === intval($lastId)) {
$covered = true;
break;
}
}
if (!$covered) {
// 覆盖不支持:归入 country 并跳过
$groupBranch['country'][] = $val;
continue;
}
// 覆盖支持:不中断,继续按常规分级逻辑处理
}
list(,$areaTxt,$areaBranchId) = explode(':', $val['area']);
if(in_array($areaBranchId, $this->_groupAreaId[$areaId]['distinctAreaId'])) {
$groupBranch['distinct'][] = $val;
continue;
}
if(in_array($areaBranchId, $this->_groupAreaId[$areaId]['cityAreaId'])) {
$groupBranch['city'][] = $val;
continue;
}
if(in_array($areaBranchId, $this->_groupAreaId[$areaId]['provinceAreaId'])) {
$groupBranch['province'][] = $val;
continue;
}
if($this->_groupAreaId[$areaId]['routerLogisticsArea']) {
list($province, $city, $distinct) = explode('/', $areaTxt);
$index = array_search($province, $this->_groupAreaId[$areaId]['routerLogisticsArea']);
if($index !== false) {
$logisticsBranchId[$index][] = $val;
continue;
}
} else {
if (in_array($areaBranchId, $this->_groupAreaId[$areaId]['logisticsAreaId'])) {
$groupBranch['logistics'][] = $val;
continue;
}
}
$groupBranch['country'][] = $val;
}
ksort($logisticsBranchId);
$groupBranch['province_router'] = $logisticsBranchId;
foreach ($groupBranch as $key => $value) {
if($key == 'province_router') {
if($logisticsBranchId) {
$return = current($logisticsBranchId);
break;
}
continue;
}
if(count($value)) {
$return = $value;
break;
}
}
$this->writeSuccessLog($groupBranch, $return);
return $return;
}
protected function _getGroupAreaId($areaId) {
$modelRegion = app::get('eccommon')->model('regions');
$row = $modelRegion->db_dump(array('region_id'=>$areaId), 'region_path');
$arrPath = explode(',', $row['region_path']);
$province = $arrPath[1];
$city = $arrPath[2];
$distinct = $arrPath[3];
$routerProvinceId = app::get('logistics')->model('area_router')->db_dump(array('area_id'=>$province), 'first_dc,router_area');
$logisticsAreaId = array();
$routerLogisticsArea = array();
if($routerProvinceId) {
$routerArea = unserialize($routerProvinceId['router_area']);
$firstPId = '';
foreach ($routerArea as $k => $val) {
if(!$firstPId) {
$firstPId = $k;
}
if($val['weight'] < 0) {
continue;
}
$routerLogisticsArea[] = $val['name'];
}
$distinctAreaId = $cityAreaId = $provinceAreaId = array();
if($firstPId == $province) {
$distinctAreaId = $this->_getAreaId($distinct);
$cityAreaId = $this->_getAreaId($city, $distinct);
$provinceAreaId = $this->_getAreaId($province, $city);
}
} else {
$distinctAreaId = $this->_getAreaId($distinct);
$cityAreaId = $this->_getAreaId($city, $distinct);
$provinceAreaId = $this->_getAreaId($province, $city);
$logistics = app::get('logistics')->model('area')->db_dump(
array('filter_sql' => 'find_in_set(' . $province . ', region_id)'), 'region_id'
);
if ($logistics) {
$arrLogistics = explode(',', $logistics['region_id']);
foreach ($arrLogistics as $val) {
if ($val != $province) {
$tmp = $this->_getAreaId($val);
$logisticsAreaId = array_merge($logisticsAreaId, $tmp);
}
}
}
}
return array(
'distinctAreaId' => $distinctAreaId,
'cityAreaId' => $cityAreaId,
'provinceAreaId' => $provinceAreaId,
'logisticsAreaId' => $logisticsAreaId,
'first_dc' => $firstDc,
'routerLogisticsArea' => $routerLogisticsArea,
'areaIdregionPath' => $arrPath, // 县区id对应的完整路径数组
);
}
protected function _getAreaId($find, $notFind = 0) {
$filterSql = 'find_in_set(' . $find . ', region_path)';
if($notFind) {
$filterSql .= ' and !find_in_set(' . $notFind . ', region_path)';
}
$filter = array(
'haschild' => '0',
'filter_sql' => $filterSql
);
$modelRegion = app::get('eccommon')->model('regions');
$rows = $modelRegion->getList('region_id', $filter);
$return = array();
foreach ($rows as $val) {
$return[] = $val['region_id'];
}
return $return;
}
protected function _getLocationBranch($branchInfo) {
$gBranch = [];
$msg = [];
$orderLocation = $this->location;
$orderLocation = explode(',', $orderLocation);
foreach ($branchInfo as $v) {
if(!$v['location']) {
list($rs, $v['location']) = kernel::single('console_map_branch')->getLocation($v['branch_id'], false);
if(!$rs) {
$msg['get location fail'][] = $v;
continue;
}
}
$branchLocation = explode(',', $v['location']);
$length = bcadd(
bcmul(($branchLocation[0] - $orderLocation[0]), ($branchLocation[0] - $orderLocation[0]), 12),
bcmul(($branchLocation[1] - $orderLocation[1]), ($branchLocation[1] - $orderLocation[1]), 12),
12
);
$length = (string) $length;
$gBranch[$length][] = $v;
}
ksort($gBranch);
$msg['result'] = current($gBranch);
$this->writeSuccessLog($gBranch, $msg);
return $msg['result'];
}
protected function writeSuccessLog($result, $msg) {
foreach ($result as $k => $v) {
$result[$k] = json_encode($v, JSON_UNESCAPED_UNICODE);
}
foreach ($msg as $k => $v) {
$msg[$k] = json_encode($v, JSON_UNESCAPED_UNICODE);
}
$msg['订单定位'] = $this->location;
$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('branch.router', $result), JSON_UNESCAPED_UNICODE), #longtext
'msg' => json_encode($msg, JSON_UNESCAPED_UNICODE), #text json字符串
'log_type' => '',
'api_type' => 'response',
'memo' => '',
'original_bn' => $this->orderBn,
'createtime' => time(),
'last_modified' => time(),
'msg_id' => '',
);
$apilogModel->insert($logsdf);
}
}