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

View File

@@ -36,7 +36,17 @@ class wms_delivery_check{
$delivery_id = $deliveryBill ? $deliveryBill['delivery_id'] : 0;
$delivery = $dlyModel->getList('branch_id,delivery_id,status,deli_cfg,process_status,delivery_bn,print_status,logi_number',array('delivery_id'=>$delivery_id),0,1);
// [提货物流] delivery_model='pickup' 运单号后取,扫描的是发货单号
if (empty($delivery)) {
$pickupDly = $dlyModel->getList('branch_id,delivery_id,status,deli_cfg,process_status,delivery_bn,print_status,logi_number', array('delivery_bn' => $logi_no, 'delivery_model' => 'pickup'), 0, 1);
if ($pickupDly) {
$delivery = $pickupDly;
$delivery_id = $pickupDly[0]['delivery_id'];
$deliveryBill = $dlyBillMdl->db_dump(array('delivery_id' => $delivery_id, 'type' => 1));
}
}
//[同城配]商家配送支持配送员手机号搜索
if(empty($delivery) && strlen($logi_no) == 11){
$delivery = $dlyModel->getList('*', array('deliveryman_mobile'=>$logi_no, 'process_status'=>array(0,1)), 0, 1);
@@ -310,7 +320,17 @@ class wms_delivery_check{
}
}
}
// [提货物流] delivery_model='pickup' 运单号后取,扫描的是发货单号
if (empty($dly)) {
$pickupDly = $dlyObj->dump(array('delivery_bn' => $logi_no, 'delivery_model' => 'pickup'), 'delivery_id');
if ($pickupDly) {
$primary = true;
$delivery_id = $pickupDly['delivery_id'];
$dly = $dlyObj->dump(array('delivery_id' => $delivery_id), '*', array('delivery_items' => array('*')));
}
}
//[同城配]商家配送支持配送员手机号搜索
if(empty($dly) && strlen($logi_no) == 11){
$dly = $dlyObj->dump(array('deliveryman_mobile'=>$logi_no, 'process_status'=>array(2,3)), '*', array('delivery_items'=>array('*')));

View File

@@ -245,6 +245,7 @@ class wms_delivery_process{
*/
function consignDelivery($dly_id, $type='') {
$deliveryObj = app::get('wms')->model('delivery');
$opinfo = array();
$delivery_time = time();
$filter['delivery_id'] = $dly_id;
@@ -256,7 +257,7 @@ class wms_delivery_process{
if(!is_numeric($affect_row) || $affect_row <= 0){
return false;
}else{
$deliveryInfo = $deliveryObj->dump($dly_id,'delivery_bn,outer_delivery_bn,branch_id,weight,delivery_cost_actual');
$deliveryInfo = $deliveryObj->dump($dly_id, '*');
//如果发货成功,处理保质期批次的变化:冻结释放,实际数量扣减,单据转正
$storageLifeReceiptLib = kernel::single('material_receipt_storagelife');
@@ -304,6 +305,9 @@ class wms_delivery_process{
$deliveryBillItemMdl = app::get('wms')->model('delivery_bill_items');
$bill_list = $billObj->getList('*',array('delivery_id'=>$dly_id, 'status'=>'1'));
// 获取主单运单号
$primary_bill = $billObj->dump(array('delivery_id'=>$dly_id, 'type'=>'1', 'status'=>'1'), '*');
$other_list_0 = array(); $packages = [];
foreach ($bill_list as $bill) {
@@ -322,6 +326,16 @@ class wms_delivery_process{
);
}
// logi_id
if ($deliveryInfo['logi_id']) {
$data['logistics'] = $deliveryInfo['logi_id'];
}
// logi_no
if (isset($primary_bill['logi_no']) && $primary_bill['logi_no']) {
$data['logi_no'] = $primary_bill['logi_no'];
}
$data['other_list_0'] = json_encode($other_list_0);
$data['packages'] = json_encode($packages);
@@ -361,6 +375,12 @@ class wms_delivery_process{
}
$res = kernel::single('wms_event_trigger_delivery')->consign($wms_id, $data, true);
if ($res === false || (is_array($res) && $res['rsp'] == 'fail')) {
$msg = is_array($res) && $res['msg'] ? '通知OMS发货失败' . $res['msg'] : '通知OMS发货失败';
$opObj->write_log('delivery_process@wms', $dly_id, $msg,'',$opinfo);
return false;
}
return true;
}

View File

@@ -87,6 +87,7 @@ class wms_event_trigger_logistics_data_electron_wxshipin extends wms_event_trigg
}
$dlyCorp = app::get('ome')->model('dly_corp')->dump(array('corp_id' => $delivery['logi_id']));
app::get('ome')->model('dly_corp_channel')->getChannel($dlyCorp, array($delivery));
$prt_tmpl_id = $dlyCorp['prt_tmpl_id'];

View File

@@ -164,6 +164,7 @@ class wms_event_trigger_logistics_data_electron_xhs extends wms_event_trigger_lo
}
$dlyCorp = app::get('ome')->model('dly_corp')->dump(array('corp_id' => $delivery['logi_id']));
app::get('ome')->model('dly_corp_channel')->getChannel($dlyCorp, array($delivery));
$sdf = parent::getDirectSdf($arrDelivery, $arrBill, $shop);
$sdf['primary_bn'] = $delivery['delivery_bn'];

View File

@@ -17,7 +17,7 @@
class wms_finder_delivery{
var $detail_basic = "发货单详情";
var $detail_item = "货品详情";
var $detail_item = "基础物料详情";
var $detail_delivery = "物流单列表";
var $detail_serial = "唯一码详情";
var $detail_storagelife = "保质期批次详情";
@@ -170,7 +170,7 @@ class wms_finder_delivery{
$content = $row[$this->col_prefix . 'bnsContent'];
$cnts = unserialize($content);
$cnt = sprintf("共有 %d 种商品,总共数量为 %d 件, 具体 SKU 为: %s", $skuNum, $itemNum, @implode(', ', $cnts));
$cnt = sprintf("共有 %d 种基础物料,总共数量为 %d 件, 具体 SKU 为: %s", $skuNum, $itemNum, @implode(', ', $cnts));
@reset($cnts);
$content = $cnts[@key($cnts)];
@@ -181,7 +181,7 @@ class wms_finder_delivery{
}
var $column_product_name = "货品名称";
var $column_product_name = "基础物料名称";
var $column_product_name_width = "160";
function column_product_name($row,$list) {
@@ -196,7 +196,7 @@ class wms_finder_delivery{
foreach ($product_id as $pid) {
$names[] = $productName[$pid];
}
$cnt = sprintf("共有 %d 种商品,总共数量为 %d 件, 具体 名称 为: %s", $skuNum, $itemNum, @implode(', ', $names));
$cnt = sprintf("共有 %d 种基础物料,总共数量为 %d 件, 具体 名称 为: %s", $skuNum, $itemNum, @implode(', ', $names));
@reset($names);
$content = $names[@key($names)];

View File

@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class wms_finder_extend_filter_branch_product{
function get_extend_colums(){
$db['branch_product']=array (
@@ -22,7 +21,7 @@ class wms_finder_extend_filter_branch_product{
'bn'=> array (
'type' => 'varchar(40)',
'editable' => false,
'label' => '货号',
'label' => '基础物料编码',
'width' => 110,
'filtertype' => 'normal',
'filterdefault' => true,
@@ -59,4 +58,4 @@ class wms_finder_extend_filter_branch_product{
}
}
?>
?>

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]
);
}
}

View File

@@ -88,6 +88,13 @@ class wms_operation_log{
'fukubukuro_combine_add' => array('name'=>'福袋组合添加', 'type'=>'fukubukuro_combine@material'),
'fukubukuro_combine_edit' => array('name'=>'福袋组合编辑', 'type'=>'fukubukuro_combine@material'),
'fukubukuro_combine_modify' => array('name'=>'编辑关联销售物料', 'type'=>'fukubukuro_combine@material'),
// 赠品审批实例
'order_workflow_case' => array('name'=>'赠品审批', 'type'=>'workflow_case@ticket'),
// SET商品
'set_materialprice_create' => array('name'=>'创建加价购', 'type'=>'basic_material_price@miele'),
'set_materialprice_edit' => array('name'=>'编辑加价购', 'type'=>'basic_material_price@miele'),
);
return array('wms'=>$operations);