1. 【新增】售后单售后原因类型支持搜索

2. 【新增】手工创建订单折扣可输入正数

3. 【优化】盘点申请单确认

4. 【修复】采购退货单模拟出库失败问题

5. 【新增】订单金额客户实付与结算金额

6. 【优化】仓库发货统计报表物料名称显示

7. 【优化】自有仓储虚拟发货逻辑

8. 【修复】基础物料分类管理问题
This commit is contained in:
chenping
2026-04-01 11:59:17 +08:00
parent 9341122827
commit 61783b7d01
754 changed files with 46179 additions and 5700 deletions

204
app/wms/lib/logistics.php Normal file
View File

@@ -0,0 +1,204 @@
<?php
/**
* WMS 物流相关封装
* 统一通过 erpapi shop request 调用各平台物流接口
*/
class wms_logistics
{
/**
* 官方提货(提货物流)
* 入参为 wms delivery_id通过 outer_delivery_bn 对应 ome_delivery.delivery_bn 取 ome 发货单,
* 用 ome_event_trigger_shop_data_delivery_alibaba->get_sdf 取 sdf再调 erpapi 对应平台 officialPickup
* @param int|array $delivery_id wms 发货单主键;或数组且含 key delivery_id
* @return array 统一返回 ['rsp' => 'succ'|'fail', 'msg' => '', 'data' => ...],便于后续根据成功/失败处理
*/
public function officialPickup($delivery_id)
{
$fail = function ($msg, $data = null) {
return ['rsp' => 'fail', 'msg' => $msg, 'data' => $data];
};
$ok = function ($result) {
if (is_array($result) && isset($result['rsp'])) {
return $result;
}
return ['rsp' => 'succ', 'msg' => '', 'data' => $result];
};
$wms_delivery_id = is_array($delivery_id) ? (isset($delivery_id['delivery_id']) ? (int)$delivery_id['delivery_id'] : 0) : (int)$delivery_id;
if ($wms_delivery_id <= 0) {
return $fail('无效的发货单ID');
}
$wmsDeliveryMdl = app::get('wms')->model('delivery');
$wmsDelivery = $wmsDeliveryMdl->dump($wms_delivery_id, 'delivery_id,outer_delivery_bn,shop_id');
if (empty($wmsDelivery) || empty($wmsDelivery['outer_delivery_bn']) || empty($wmsDelivery['shop_id'])) {
return $fail('未找到WMS发货单或缺少 outer_delivery_bn/shop_id');
}
$omeDeliveryMdl = app::get('ome')->model('delivery');
$omeDelivery = $omeDeliveryMdl->dump(['delivery_bn' => $wmsDelivery['outer_delivery_bn']]);
if (empty($omeDelivery) || empty($omeDelivery['delivery_id'])) {
return $fail('未找到对应的OMS发货单');
}
$ome_delivery_id = $omeDelivery['delivery_id'];
$deliveryList = $omeDeliveryMdl->getList('*', ['delivery_id' => $ome_delivery_id]);
if (empty($deliveryList)) {
return $fail('OMS发货单列表为空');
}
$deliveryOrderMdl = app::get('ome')->model('delivery_order');
$deliveryOrderList = $deliveryOrderMdl->getList('delivery_id,order_id', ['delivery_id' => $ome_delivery_id]);
$order_ids = [];
$delivery_orders = [];
$orderList = [];
foreach ($deliveryOrderList as $row) {
$order_ids[] = $row['order_id'];
$delivery_orders[$row['delivery_id']] = &$orderList[$row['order_id']];
}
$orderModel = app::get('ome')->model('orders');
$orders = $orderModel->getList('*', ['order_id' => $order_ids]);
foreach ($orders as $o) {
$orderList[$o['order_id']] = $o;
}
$delivery = $deliveryList[0];
$order = isset($delivery_orders[$ome_delivery_id]) ? $delivery_orders[$ome_delivery_id] : null;
$sdf = $this->_buildOfficialPickupSdf($ome_delivery_id, $delivery, $order);
if (empty($sdf)) {
return $fail('获取平台发货数据(sdf)为空');
}
$result = kernel::single('erpapi_router_request')->set('shop', $wmsDelivery['shop_id'])->logistics_officialPickup($sdf);
$ret = $ok($result);
// 仅成功时:从平台返回结果中提取运单号,回写 OMS / WMS原 erpapi_shop_matrix_alibaba_request_delivery confirm_callback 逻辑)
if ($ret['rsp'] === 'succ' || $ret['rsp'] === 'success') {
$this->_officialPickupSyncLogiNo($ret, $sdf['delivery_bn'], $wmsDelivery['delivery_id']);
}
return $ret;
}
/**
* 在本类内直接组装 officialPickup 所需 sdf与 erpapi alibaba request logistics 入参一致,避免 router 取数不全
* 结构orderinfo.order_bn、delivery_items(oid/nums/number/weight)、memo、delivery_time、delivery_bn
* @param int $ome_delivery_id OMS 发货单 id
* @param array $delivery OMS 发货单行(含 delivery_bn, delivery_time, memo 等)
* @param array|null $order OMS 订单行(含 order_bn/platform_order_bn
* @return array 空表示组装失败,否则为 alibaba officialPickup 所需 sdf
*/
protected function _buildOfficialPickupSdf($ome_delivery_id, $delivery, $order)
{
if (empty($delivery) || empty($order)) {
return [];
}
$order_bn = isset($order['platform_order_bn']) && $order['platform_order_bn'] !== ''
? $order['platform_order_bn']
: (isset($order['order_bn']) ? $order['order_bn'] : '');
if ($order_bn === '') {
return [];
}
$detailMdl = app::get('ome')->model('delivery_items_detail');
$details = $detailMdl->getList('*', ['delivery_id' => $ome_delivery_id]);
if (empty($details)) {
return [];
}
$objIds = array_unique(array_column($details, 'order_obj_id'));
$objMdl = app::get('ome')->model('order_objects');
$objRows = $objMdl->getList('obj_id,oid', ['obj_id' => $objIds]);
$objId2Oid = [];
foreach ($objRows as $r) {
$objId2Oid[$r['obj_id']] = isset($r['oid']) ? trim((string)$r['oid']) : '';
}
$delivery_items = [];
foreach ($details as $d) {
$oid = isset($objId2Oid[$d['order_obj_id']]) ? $objId2Oid[$d['order_obj_id']] : '';
if ($oid === '') {
continue;
}
$num = isset($d['number']) ? (int)$d['number'] : 0;
if ($num < 1) {
continue;
}
$delivery_items[] = [
'oid' => $oid,
'nums' => $num,
'number' => $num,
'weight' => isset($d['weight']) ? (float)$d['weight'] : 0,
];
}
if (empty($delivery_items)) {
return [];
}
return [
'orderinfo' => ['order_bn' => $order_bn],
'delivery_items'=> $delivery_items,
'memo' => isset($delivery['memo']) ? $delivery['memo'] : '',
'delivery_time' => isset($delivery['delivery_time']) ? $delivery['delivery_time'] : time(),
'delivery_bn' => isset($delivery['delivery_bn']) ? $delivery['delivery_bn'] : '',
];
}
/**
* 从 officialPickup 返回的 result 中解析出 result.pickUpInfo与 yunqi saveOfficialPickupResult 一致data 可能为 JSON 字符串,且含 msg 内嵌 JSON
* @param array $result ['rsp'=>'succ','data'=>'...'] 其中 data 可能为 '{"msg":"{\"result\":{\"pickUpInfo\":{...}}}","success":true}'
* @return array|null pickUpInfo 或 null
*/
protected function _parseOfficialPickupResult($result)
{
$data = isset($result['data']) ? $result['data'] : $result;
if (is_string($data)) {
$data = json_decode($data, true);
if (is_array($data) && isset($data['msg']) && is_string($data['msg'])) {
$inner = json_decode($data['msg'], true);
if (is_array($inner)) {
$data = array_merge($data, $inner);
}
}
}
if (!is_array($data)) {
$data = array();
}
if (!empty($data['result']['pickUpInfo'])) {
return $data['result']['pickUpInfo'];
}
if (!empty($result['result']['pickUpInfo'])) {
return $result['result']['pickUpInfo'];
}
return null;
}
/**
* 官方提货成功:从接口返回中解析 pickUpInfo.mailNo回写 OMS 与 WMS 运单号
* @param array $result officialPickup 返回的 ['rsp'=>'succ','data'=>...]
* @param string $delivery_bn OMS 发货单号delivery_bn
* @param int $wms_delivery_id WMS 发货单主键
*/
protected function _officialPickupSyncLogiNo($result, $delivery_bn, $wms_delivery_id)
{
$pickUpInfo = $this->_parseOfficialPickupResult($result);
if (empty($pickUpInfo) || empty($pickUpInfo['mailNo'])) {
return;
}
$mailNo = trim($pickUpInfo['mailNo']);
// OMS: 通过 addLogiNo 统一链路更新 ome_delivery.logi_no
kernel::single('ome_event_receive_delivery')->update([
'delivery_bn' => $delivery_bn,
'logi_no' => $mailNo,
'action' => 'addLogiNo',
'status' => 'update',
]);
// WMS: 同步更新 wms_delivery_bill.logi_notype=1 主单)
app::get('wms')->model('delivery_bill')->update(
['logi_no' => $mailNo],
['delivery_id' => $wms_delivery_id, 'type' => 1]
);
}
}