Files
OMS/app/console/lib/delivery.php
2025-12-28 23:13:25 +08:00

1505 lines
56 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 © ShopeX http://www.shopex.cn. All rights reserved.
* See LICENSE file for license details.
*/
class console_delivery
{
/**
* 更新发货单推送WMS返回状态
*
* @param int $dly_id
* @param string $status
* @param string $msg WMS错误原因
* @param string $error_code WMS错误码
* @return boolean
*/
public function update_sync_status($dly_id, $status, $msg='', $error_code=null)
{
if(!$dly_id || !$status){
return false;
}
$updateArr = array(
'sync_status'=>&$status_int
);
$old = app::get('ome')->model('delivery')->db_dump(['delivery_id'=>$dly_id],'sync_send_succ_times,sync,delivery_bn');
//根据仓库识别是否门店仓还是电商仓
$store_id = kernel::single('ome_branch')->isStoreBranch($old['branch_id']);
if($store_id){
$channel_type = 'store';
}else{
$channel_type = 'wms';
}
switch($status){
case 'send':
$status_int = '1';
$updateArr['sync'] = $old['sync'] | console_delivery_bool_sync::__SEND_CODE;
break;
case 'send_fail':
$status_int = '2';
$updateArr['sync'] = $old['sync'] | console_delivery_bool_sync::__SEND_FAIL;
break;
case 'send_succ':
$status_int = '3';
$updateArr['sync'] = $old['sync'] | console_delivery_bool_sync::__SEND_SUCC;
$updateArr['sync_send_succ_times'] = $old['sync_send_succ_times'] + 1;
// 监控到发货单取消请求早于创建请求,故推送成功后重新发起取消
if ($old['sync'] & console_delivery_bool_sync::__CANCEL_FAIL) {
$deliveryObj = app::get('ome')->model('delivery');
// $deliveryObj->rebackDelivery($dly_id, '推送成功后重新取消发货单', false, false);
}
break;
case 'cancel_fail':
$status_int = '4';
$updateArr['sync'] = $old['sync'] | console_delivery_bool_sync::__CANCEL_FAIL;
break;
case 'cancel_succ':
$updateArr['sync'] = $old['sync'] | console_delivery_bool_sync::__CANCEL_SUCC;
$status_int = '5';
break;
case 'search_fail':
$updateArr['sync'] = $old['sync'] | console_delivery_bool_sync::__SEARCH_FAIL;
$status_int = '9';
break;
case 'search_succ':
$updateArr['sync'] = $old['sync'] | console_delivery_bool_sync::__SEARCH_SUCC;
$status_int = '10';
break;
default:
return false;
break;
}
if($msg){
//过滤html标签
$msg = strip_tags($msg);
$msg = str_replace(array("\r\n", "\r", "\n"), "", $msg);
$updateArr['sync_msg'] = $msg;
}elseif($status == 'send_succ'){
$updateArr['sync_msg'] = ''; //清空同步失败原因
}
//WMS错误码
if($status == 'send_succ'){
$updateArr['sync_code'] = '';
}elseif($error_code){
$error_code = str_replace(array('"', "'"), '', $error_code);
$updateArr['sync_code'] = $error_code;
}
$dlyObj = app::get('console')->model('delivery');
return $dlyObj->update($updateArr, array('delivery_id'=>$dly_id));
}
/**
* [京东一件代发]获取发货单对应所有包裹信息
*
* @param int $order_id
* @param array $skus
* @param string $error_msg
* @param string $status
* @return array
*/
public function getDeliveryPackage($delivery_id, &$error_msg=null, $status='delivery')
{
$packageObj = app::get('ome')->model('delivery_package');
//filter
$filter = array('delivery_id'=>$delivery_id);
if($status){
$filter['status'] = $status;
}
//获取已发货的京东包裹单
$dataList = $packageObj->getList('*', $filter);
if(empty($dataList)){
$error_msg = '没有找到关联的京东包裹';
return false;
}
$packageList = array();
foreach ($dataList as $key => $val)
{
$delivery_id = $val['delivery_id'];
$product_id = $val['product_id']; //赠品会有0的场景
$package_bn = $val['package_bn'];
if(empty($packageList[$package_bn])){
$packageList[$package_bn] = array(
'package_id' => $val['package_id'],
'package_bn' => $val['package_bn'],
'delivery_id' => $val['delivery_id'],
'logi_bn' => $val['logi_bn'], //物流编码
'logi_no' => $val['logi_no'], //物流单号
'status' => $val['status'], //状态
'shipping_status' => $val['shipping_status'], //配送状态
);
//item
$packageList[$package_bn]['items'][] = array(
'product_id' => $val['product_id'],
'bn' => $val['bn'],
'outer_sku' => $val['outer_sku'],
'number' => $val['number'],
'product_name' => $val['product_name'],
'create_time' => $val['create_time'],
'is_wms_gift' => $val['is_wms_gift'],
);
}else{
//item
$packageList[$package_bn]['items'][] = array(
'product_id' => $val['product_id'],
'bn' => $val['bn'],
'outer_sku' => $val['outer_sku'],
'number' => $val['number'],
'product_name' => $val['product_name'],
'create_time' => $val['create_time'],
'is_wms_gift' => $val['is_wms_gift'],
);
}
}
return $packageList;
}
/**
* 京东配送方式
*
* @param string $shipping_type
* @return string
*/
public function getShippingType($shipping_type=null)
{
$shipping_types = array(
'0' => '默认',
'1' => '京东配送',
'2' => '京配转三方配送',
'3' => '第三方配送',
'4' => '普通快递配送',
'9' => '不支持配送',
);
if($shipping_type || $shipping_type === '0'){
return $shipping_types[$shipping_type];
}
return $shipping_types;
}
/**
* 京东包裹发货状态
*
* @param string $status
* @return string
*/
public function getShippingStatus($status=null)
{
$status_list = array(
'-100' => '已取消',
'0' => '提单成功',
'1' => '等待付款',
'4' => '已支付',
'6' => '等待打印',
'7' => '拣货完成',
'8' => '出库完成',
'15' => '待用户确认收货',
'16' => '用户拒收',
'18' => '用户签收',
'21' => '订单锁定',
'9' => '等待发货',
);
if($status || $status === '0'){
return $status_list[$status];
}
return $status_list;
}
/**
* 京东包裹状态
*
* @param string $status
* @return string
*/
public function getPackageStatus($status=null)
{
$status_list = array(
'accept' => '未发货',
'delivery' => '已发货',
'return_back' => '拦截追回',
'cancel' => '已取消', //现在没有此状态
);
if($status){
return $status_list[$status];
}
return $status_list;
}
/**
* 更新发货单上京东云交易采购价格
*/
public function updatePurchasePrice($params, &$error_msg=null)
{
$dlyObj = app::get('ome')->model('delivery');
//发货单号
$delivery_bn = ($params['wms_order_code'] ? $params['wms_order_code'] : $params['out_order_code']);
//发货明细
$items = $params['items'];
if(empty($delivery_bn) || empty($items)){
$error_msg = '无效的数据!';
return false;
}
$items = json_decode($items, true);
if(empty($items)){
$error_msg = '无效的数据。';
return false;
}
//发货单信息
$dlyInfo = $dlyObj->dump(array('delivery_bn'=>$delivery_bn), 'delivery_id');
if(empty($dlyInfo)){
$error_msg = '没有找到发货单信息';
return false;
}
$delivery_id = $dlyInfo['delivery_id'];
//items
foreach ($items['item'] as $key => $val)
{
$item_code = $val['item_code'];
$item_price = $val['item_price'];
if(empty($item_code)){
continue;
}
//更新仓储采购价
$update_sql = "UPDATE sdb_ome_delivery_items SET purchase_price='%s' WHERE delivery_id=%d AND bn='%s'";
$update_sql = sprintf($update_sql, $item_price, $delivery_id, $item_code);
$dlyObj->db->exec($update_sql);
}
return true;
}
/**
* 获取已发货完成的发货单关联包裹列表
*/
public function getShipDlyPackages($delivery_id, &$error_msg=null)
{
$packageObj = app::get('ome')->model('delivery_package');
//获取已发货的京东包裹单
$filter = array('delivery_id'=>$delivery_id, 'status'=>array('delivery', 'return_back'));
$dataList = $packageObj->getList('package_id,package_bn,status,logi_bn,logi_no,bn,outer_sku,number', $filter);
if(empty($dataList)){
$error_msg = '没有找到关联的京东包裹';
return false;
}
$packageList = array();
foreach ($dataList as $key => $val)
{
$product_id = $val['product_id']; //赠品会有0的场景
$package_bn = $val['package_bn'];
//包裹状态
$val['package_status'] = $this->getPackageStatus($val['status']);
$packageList[] = $val;
}
return $packageList;
}
/**
* [包裹发货完成]添加WMS仓库赠送的赠品到OMS发货单明细上,并且扣减库存
* @todo插入赠品到订单object层明细、订单items层明细、发货单items层明细、发货单item_detail层明细
*
* @param array $dlyParams
* @param string $error_msg
* @return bool
*/
public function addWmsGifts($dlyParams, &$error_msg=null)
{
$operLogObj = app::get('ome')->model('operation_log');
$dlyObj = app::get('console')->model('delivery');
$dlyItemObj = app::get('ome')->model('delivery_items');
$dlyItemDetailObj = app::get('ome')->model('delivery_items_detail');
$foreignObj = app::get('console')->model('foreign_sku');
$saleMaterialObj = app::get('material')->model('sales_material');
$objectObj = app::get('ome')->model('order_objects');
$itemObj = app::get('ome')->model('order_items');
$salesBasicMaterialLib = kernel::single('material_sales_material');
$basicMStockFreezeLib = kernel::single('material_basic_material_stock_freeze');
$deliveryId = $dlyParams['delivery_id'];
$wms_id = $dlyParams['wms_id'];
$oid = $dlyParams['oid'];
$shop_id = $dlyParams['shop_id'];
$branch_id = $dlyParams['branch_id'];
$gift_list = $dlyParams['gift_list'];
//关联订单
$sql = "SELECT * FROM sdb_ome_delivery_order WHERE delivery_id=". $deliveryId;
$dlyOrderList = $dlyItemObj->db->select($sql);
if(empty($dlyOrderList)){
$error_msg = '没有找到关联订单';
return false;
}
//现在只取第一个订单
$order_id = $dlyOrderList[0]['order_id'];
//赠送的货品
$outer_skus = array();
foreach ($gift_list as $key => $val)
{
$outer_skus[] = $val['product_bn'];
}
//WMS货品信息
$filter = array(
'wms_id' => $wms_id,
'outer_sku' => $outer_skus,
);
$tempList = $foreignObj->getList('inner_sku,outer_sku,price', $filter);
if(empty($tempList)){
//[兼容]读取基础物料
$basicMaterialObj = app::get('material')->model('basic_material');
$tempList = $basicMaterialObj->dump(array('material_bn'=>$outer_skus), 'bm_id,material_bn');
if(empty($tempList)){
$error_msg = 'WMS赠送的货品,在OMS商品关系中不存在';
return false;
}
$product_bns = array();
foreach ($tempList as $key => $val)
{
$material_bn = $val['material_bn'];
$product_bns[$material_bn] = $material_bn;
}
}else{
$product_bns = array();
foreach ($tempList as $key => $val)
{
$inner_sku = $val['inner_sku']; //oms基础物料编码
$outer_sku = $val['outer_sku']; //WMS货号
$product_bns[$inner_sku] = $inner_sku;
}
}
//检查赠品是否已经存在
$isCheck = $dlyItemObj->dump(array('delivery_id'=>$deliveryId, 'bn'=>$product_bns, 'is_wms_gift'=>'true'), 'delivery_id');
if($isCheck){
$error_msg = '赠品已经存在,不能重复添加';
return false;
}
//获取销售物料信息
$tempList = $saleMaterialObj->getList('sm_id,sales_material_bn,sales_material_name,shop_id,sales_material_type', array('sales_material_bn'=>$product_bns));
if(empty($tempList)){
$error_msg = 'WMS赠送的货品,在OMS销售物料里不存在';
return false;
}
$smList = array();
foreach ($tempList as $key => $val)
{
$sm_id = $val['sm_id'];
$sales_material_bn = $val['sales_material_bn'];
//绑定的基础物料
$bindInfo = $salesBasicMaterialLib->getBasicMBySalesMIds($sm_id);
$bindInfo = $bindInfo[$sm_id];
$bindInfo = $bindInfo ? array_column($bindInfo, null, 'bm_id') : null;
if(empty($bindInfo)){
continue;
}
$val['basicMaterial'] = $bindInfo;
$smList[$sales_material_bn] = $val;
}
//组织新加的赠品
$new_order_object = array();
$obj_i = 0;
foreach ($gift_list as $key => $val)
{
$product_bn = $val['product_bn'];
$val['price'] = ($val['price'] ? $val['price'] : 0);
//销售物料
$smInfo = $smList[$product_bn];
//销售物料绑定的基础物料
$salesBasicMaterial = $smInfo['basicMaterial'];
//check
if(empty($smInfo) || empty($salesBasicMaterial)){
continue;
}
//object
$new_order_object[$obj_i] = array(
'order_id' => $order_id,
'obj_type' => 'gift',
'obj_alias' => 'gift',
'bn' => $smInfo['sales_material_bn'],
'name' => $smInfo['sales_material_name'],
'goods_id' => $smInfo['sm_id'],
'quantity' => $val['num'],
'price' => 0,
'amount' => 0,
'pmt_price' => 0,
'sale_price' => 0,
'divide_order_fee' => 0,
'part_mjz_discount' => 0,
'is_wms_gift' => 'true', //是否WMS赠品
);
//订单item层明细
$new_order_item = array();
foreach ($salesBasicMaterial as $bmItem)
{
$item_type = 'gift';
$new_order_item[] = array(
'order_id' => $order_id,
'bn' => $bmItem['material_bn'],
'name' => $bmItem['material_name'],
'product_id' => $bmItem['bm_id'],
'item_type' => 'gift',
'nums' => $val['num'],
'price' => 0,
'amount' => 0,
'pmt_price' => 0,
'sale_price' => 0,
'divide_order_fee' => 0,
'part_mjz_discount' => 0,
'is_wms_gift' => 'true', //是否WMS赠品
);
}
$new_order_object[$obj_i]['order_items'] = $new_order_item;
$obj_i++;
}
if(empty($new_order_object)){
$error_msg = '没有需要添加的赠品明细';
return false;
}
//开启事务
kernel::database()->beginTransaction();
$obj_type = material_basic_material_stock_freeze::__BRANCH;
$bill_type = material_basic_material_stock_freeze::__DELIVERY;
$bmsq_id = material_basic_material_stock_freeze::__SHARE_STORE;
//插入赠品
$freeze_product_list = array();
foreach ($new_order_object as $objKey => $objVal)
{
//新增obj
$isSave = $objectObj->insert($objVal);
if(!$isSave){
//事务回滚
kernel::database()->rollBack();
$err_msg = sprintf('添加obj层销售物料[%s]失败', $objVal['bn']);
return false;
}
foreach ($objVal['order_items'] as $itemKey => $itemVal)
{
$itemVal['obj_id'] = $objVal['obj_id'];
$product_id = $itemVal['product_id'];
//insert
$isSave = $itemObj->insert($itemVal);
if(!$isSave){
//事务回滚
kernel::database()->rollBack();
$err_msg = sprintf('添加item层基础物料[%s]失败', $itemVal['bn']);
return false;
}
//插入发货单items层明细
$saveData = array(
'delivery_id' => $deliveryId,
'product_id' => $product_id,
'bn' => $itemVal['bn'],
'product_name' => $itemVal['name'],
'number' => $itemVal['nums'],
'purchase_price' => 0, //仓储采购价格:$wmsProcutInfo['price']
'is_wms_gift' => 'true', //是否WMS赠品
'oid' => $oid, //WMS包裹号
);
$isSave = $dlyItemObj->insert($saveData);
if(!$isSave){
//事务回滚
kernel::database()->rollBack();
$err_msg = sprintf('添加发货单items层明细[%s]失败', $itemVal['bn']);
return false;
}else{
if($freeze_product_list[$product_id]){
$freeze_product_list[$product_id]['nums'] += $itemVal['nums'];
}else{
$freeze_product_list[$product_id] = array(
'product_id' => $itemVal['product_id'],
'goods_id' => $objVal['goods_id'],
'obj_type' => $obj_type,
'bill_type' => $bill_type,
'delivery_id' => $deliveryId,
'shop_id' => $shop_id,
'branch_id' => $branch_id,
'bmsq_id' => $bmsq_id,
'nums' => $itemVal['nums'],
);
}
}
//插入发货单item_detail层明细
$saveData = array(
'delivery_id' => $deliveryId,
'delivery_item_id' => $saveData['item_id'],
'order_id' => $order_id,
'order_obj_id' => $objVal['obj_id'],
'order_item_id' => $itemVal['item_id'],
'item_type' => 'gift',
'product_id' => $itemVal['product_id'],
'bn' => $itemVal['bn'],
'product_name' => $itemVal['name'],
'number' => $itemVal['nums'],
'is_wms_gift' => 'true', //是否WMS赠品
);
$isSave = $dlyItemDetailObj->insert($saveData);
if(!$isSave){
//事务回滚
kernel::database()->rollBack();
$err_msg = sprintf('添加发货单item_detail层明细[%s]失败', $itemVal['bn']);
return false;
}
}
}
//添加仓库预占流水
if($freeze_product_list){
$batchList = [];
//排序防止死锁
ksort($freeze_product_list);
foreach ($freeze_product_list as $key => $val)
{
$freezeData = [];
$freezeData['bm_id'] = $val['product_id'];
$freezeData['sm_id'] = $val['goods_id'];
$freezeData['obj_type'] = $val['obj_type'];
$freezeData['bill_type'] = $val['bill_type'];
$freezeData['obj_id'] = $val['delivery_id'];
$freezeData['shop_id'] = $val['shop_id'];
$freezeData['branch_id'] = $val['branch_id'];
$freezeData['bmsq_id'] = $val['bmsq_id'];
$freezeData['num'] = $val['nums'];
$freezeData['obj_bn'] = $dlyParams['delivery_bn'];
$freezeData['sub_bill_type'] = 'wms赠品';
$freezeData['sync_sku'] = false;
$batchList[] = $freezeData;
}
//添加仓库预占流水
$rs = $basicMStockFreezeLib->freezeBatch($batchList, __CLASS__.'::'.__FUNCTION__, $error_msg);
if ($rs == false) {
//$err_msg .= '仓库货品冻结预占失败!';
//return false;
}
}
//打标发货单有WMS赠品
$update_sql = "UPDATE sdb_ome_delivery SET is_wms_gift='true' WHERE delivery_id=". $deliveryId;
$dlyObj->db->exec($update_sql);
//提交事务
kernel::database()->commit();
//log
$operLogObj->write_log('order_modify@ome', $order_id, 'WMS仓库赠送赠品添加成功。');
$operLogObj->write_log('delivery_modify@ome', $deliveryId, 'WMS仓库赠送赠品添加成功。');
return true;
}
/**
* 删除WMS仓库赠送的赠品
*
* @param array $params
* @param string $error_msg
* @return bool
*/
public function deleteWmsGifts($params, &$error_msg=null)
{
$operLogObj = app::get('ome')->model('operation_log');
$deliveryObj = app::get('ome')->model('delivery');
$dlyItemObj = app::get('ome')->model('delivery_items');
$dlyItemDetailObj = app::get('ome')->model('delivery_items_detail');
$foreignObj = app::get('console')->model('foreign_sku');
$objectObj = app::get('ome')->model('order_objects');
$itemObj = app::get('ome')->model('order_items');
//params
$delivery_bn = $params['delivery_bn'];
$gift_list = $params['gift_list'];
if(empty($delivery_bn) || empty($gift_list)){
$error_msg = '没有发货单号或者赠品';
return false;
}
//发货单信息
$deliveryInfo = $deliveryObj->dump(array('delivery_bn'=>$delivery_bn), 'delivery_id,status');
if(empty($deliveryInfo)){
$error_msg = '发货单不存在';
return false;
}
if(in_array($deliveryInfo['status'], array('succ', 'return_back'))){
$error_msg = '发货单已经发货,不允许删除赠品';
return false;
}
$deliveryId = $deliveryInfo['delivery_id'];
//关联订单
$sql = "SELECT * FROM sdb_ome_delivery_order WHERE delivery_id=". $deliveryId;
$dlyOrderList = $dlyItemObj->db->select($sql);
if(empty($dlyOrderList)){
$error_msg = '没有找到关联订单';
return false;
}
//现在只取第一个订单
$order_id = $dlyOrderList[0]['order_id'];
/****
//赠送的货品
$outer_skus = array();
foreach ($gift_list as $key => $val)
{
$outer_skus[] = $val['product_bn'];
}
//WMS货品信息
$filter = array(
'wms_id' => $wms_id,
'outer_sku' => $outer_skus,
);
$tempList = $foreignObj->getList('inner_sku,outer_sku,price', $filter);
if(empty($tempList)){
$error_msg = 'WMS赠送的货品,在OMS商品关系中不存在';
return false;
}
$product_bns = array();
foreach ($tempList as $key => $val)
{
$inner_sku = $val['inner_sku']; //oms基础物料编码
$product_bns[$inner_sku] = $inner_sku;
}
***/
//删除订单object层赠品
$objectObj->delete(array('order_id'=>$order_id, 'is_wms_gift'=>'true')); //'bn'=>$product_bns
//删除订单items层赠品
$itemObj->delete(array('order_id'=>$order_id, 'is_wms_gift'=>'true')); //'bn'=>$product_bns
//删除订单delivery_items层赠品
$dlyItemObj->delete(array('delivery_id'=>$deliveryId, 'is_wms_gift'=>'true')); //'bn'=>$product_bns
//删除订单delivery_items_detail层赠品
$dlyItemDetailObj->delete(array('delivery_id'=>$deliveryId, 'is_wms_gift'=>'true')); //'bn'=>$product_bns
//删除标识(WMS有拆单可能)
//$update_sql = "UPDATE sdb_ome_delivery SET is_wms_gift='false' WHERE delivery_id=". $deliveryId;
//$dlyObj->db->exec($update_sql);
//log
$operLogObj->write_log('order_modify@ome', $order_id, '发货失败,撤消添加的WMS仓库赠品。');
$operLogObj->write_log('delivery_modify@ome', $deliveryId, '发货失败,撤消添加的WMS仓库赠品。');
return true;
}
/**
* 自动批量取消订单对应所有(已发货)发货单
*/
public function autoCancelDelivery(&$cursor_id, $params, &$error_msg=null)
{
$deliveryObj = app::get('ome')->model('delivery');
$operLogObj = app::get('ome')->model('operation_log');
//data
$sdfdata = $params['sdfdata'];
$order_id = intval($sdfdata['order_id']);
//关联发货单(获取已发货、已追回的发货单)
$sql = "SELECT b.delivery_id,b.delivery_bn,b.is_wms_gift,b.wms_channel_id,b.branch_id FROM sdb_ome_delivery_order AS a LEFT JOIN sdb_ome_delivery AS b ON a.delivery_id=b.delivery_id ";
$sql .= " WHERE a.order_id=". $order_id ." AND b.status='succ'";
$dataList = $deliveryObj->db->select($sql);
if(empty($dataList)){
//$error_msg = '没有退货单';
return false;
}
foreach ($dataList as $key => $delivery)
{
$delivery_id = $delivery['delivery_id'];
$res = ome_delivery_notice::cancel($delivery, true);
if($res['rsp'] == 'succ'){
$operLogObj->write_log('delivery_modify@ome', $delivery_id, '请求撤消发货单,发送命令成功。');
}else{
$log_error_msg = ($res['error_msg'] ? $res['error_msg'] : $res['msg']);
$operLogObj->write_log('delivery_modify@ome', $delivery_id, '请求撤消发货单,发送命令失败:'.$log_error_msg);
}
}
return false;
}
/**
* 按发货单ID进行取消京东订单包裹
*
* @param int $cursor_id
* @param array $params
* @param string $error_msg
* @return boolean
*/
public function autoCancelPackage(&$cursor_id, $params, &$error_msg=null)
{
$deliveryObj = app::get('ome')->model('delivery');
$packageObj = app::get('ome')->model('delivery_package');
$operLogObj = app::get('ome')->model('operation_log');
//data
$sdfdata = $params['sdfdata'];
$delivery_id = intval($sdfdata['delivery_id']);
$delivery_bn = $sdfdata['delivery_bn'];
$filter = array();
if($delivery_id){
$filter['delivery_id'] = $delivery_id;
}else{
$filter['delivery_bn'] = $delivery_bn;
}
//发货单信息
$deliveryInfo = $deliveryObj->dump($filter, '*');
if(empty($deliveryInfo)){
$error_msg = '没有找到发货单';
return false;
}
//京东订单号
$packageRows = $packageObj->getList('package_id,package_bn,status', array('delivery_id'=>$deliveryInfo['delivery_id'], 'status|noequal'=>'cancel'));
if(empty($packageRows)){
$error_msg = '发货单没有对应京东订单号';
return false;
}
//cancel
$res = ome_delivery_notice::cancel($deliveryInfo, true);
if($res['rsp'] == 'succ'){
$operLogObj->write_log('delivery_modify@ome', $deliveryInfo['delivery_id'], '自动请求取消京东订单包裹,请求成功.');
}else{
$error_msg = ($res['error_msg'] ? $res['error_msg'] : $res['msg']);
$operLogObj->write_log('delivery_modify@ome', $delivery_id, '自动取消京东订单包裹,请求失败:'.$error_msg);
}
return false;
}
/**
* 物流包裹单状态
*
* @param string $status
* @return bool
*/
public function getDeliveryBillStatus($status=null)
{
$status_list = array(
'normal' => '0',
'delivery' => '1',
'cancel' => '2',
'accept' => '3',
'sign' => '4',
'payed' => '5',
);
if($status){
return ($status_list[$status] ? $status_list[$status] : '0');
}
return $status_list;
}
/**
* 保存物流包裹单
*
* @param int $cursor_id
* @param array $params
* @param string $error_msg
* @return boolean
*/
public function saveDeliveryBill(&$cursor_id, $params, &$error_msg=null)
{
$dlyBillObj = app::get('ome')->model('delivery_bill');
//data
$sdfdata = $params['sdfdata'];
$delivery_id = $sdfdata['delivery_id'];
$delivery_bn = $sdfdata['delivery_bn'];
$package_bn = $sdfdata['package_bn'];
$wms_id = $sdfdata['wms_id'];
//京东订单发货明细
$items = $sdfdata['items'];
//check
if(empty($delivery_id) || empty($delivery_bn) || empty($package_bn)){
$error_msg = '无效的发货单数据';
return false;
}
//包裹状态
$status = $this->getDeliveryBillStatus($sdfdata['status']);
$weight = ($sdfdata['weight'] ? $sdfdata['weight'] : 0);
//物流包裹单信息
$billInfo = $dlyBillObj->dump(array('delivery_bn'=>$delivery_bn, 'package_bn'=>$package_bn), 'log_id,logi_code,status');
//接收状态与存在的物流单状态相同,直接返回
if($billInfo && $billInfo['status'] === $status){
if($billInfo['status'] == 'delivery' && $billInfo['logi_code']){
return true;
}else{
return true;
}
}
//获取订单
$sql = 'SELECT a.order_id,a.order_bn FROM sdb_ome_orders AS a LEFT JOIN sdb_ome_delivery_order AS b ON a.order_id=b.order_id
WHERE b.delivery_id='. $delivery_id;
$orderInfo = $dlyBillObj->db->selectrow($sql);
if(empty($orderInfo)){
$error_msg = '没有找到订单信息';
return false;
}
//save
$saveData = array(
'delivery_id' => $delivery_id,
'delivery_bn' => $delivery_bn,
'logi_code' => $sdfdata['logi_id'],
'logi_no' => $sdfdata['logi_no'],
'status' => $status,
'weight' => floatval($weight),
'order_id' => $orderInfo['order_id'],
'order_bn' => $orderInfo['order_bn'],
'package_bn' => $package_bn,
'last_modified' => time(),
);
//已发货逻辑
if($sdfdata['status'] == 'delivery'){
//发货时间
$saveData['delivery_time'] = time();
//[兼容]获取物流信息(京东订单SKU发货明细中有物流信息)
if(empty($saveData['logi_code'])){
foreach ($items as $itemKey => $itemVal)
{
$itemVal['logistics'] = trim($itemVal['logistics']);
$saveData['logi_code'] = $this->getLogiCode($itemVal['logistics'], $wms_id);
$saveData['logi_no'] = ($saveData['logi_no'] ? $saveData['logi_no'] : $itemVal['logi_no']);
}
}
}
//[特殊处理]指定转换物流公司
if($sdfdata['status']=='delivery' && strtoupper($saveData['logi_code'])=='JD' && $sdfdata['wms_channel_id']){
$change_logi = $sdfdata['crop_config']['change_logi_off']; //转换物流公司开关
$change_channel_id = trim($sdfdata['crop_config']['change_channel_id']); //指定渠道ID
$change_logi_code = $sdfdata['crop_config']['change_logi_code']; //指定物流公司
//转换物流开启&&指定渠道ID&&设置了转换物流公司
if($change_logi=='1' && $change_channel_id==$sdfdata['wms_channel_id'] && $change_logi_code){
$saveData['logi_code'] = $change_logi_code;
}
}
//保存物流包裹单
if($billInfo){
unset($saveData['delivery_id'], $saveData['delivery_bn'], $saveData['order_id'], $saveData['order_bn'], $saveData['package_bn']);
//更新
$dlyBillObj->update($saveData, array('log_id'=>$billInfo['log_id']));
}else{
$saveData['create_time'] = time();
//新建
$dlyBillObj->insert($saveData);
}
//检查发货单只有一个京东订单,则不用单独回传平台
$is_flag = true;
$sql = "SELECT count(distinct package_bn) AS nums FROM sdb_ome_delivery_package WHERE delivery_id=". $delivery_id ." AND status!='cancel'";
$count = $dlyBillObj->db->selectrow($sql);
if($count['nums'] < 2){
return true;
}
//发货回写方式
$is_send_delivery = false;
$delivery_mode = $sdfdata['crop_config']['delivery_mode'];
if($delivery_mode == 'package'){
$is_send_delivery = true; //按京东订单号回写
}
//[已发货or签收]推送给平台发货状态
if(in_array($sdfdata['status'], array('delivery','sign')) && $is_send_delivery){
$sync_error_msg = '';
$params = array(
'delivery_bn' => $delivery_bn,
'package_bn' => $package_bn,
);
$result = $this->pushDeliveryConfirm($params, $sync_error_msg);
if(!$result){
$error_msg = $sync_error_msg;
}
}
return true;
}
/**
* 按京东订单纬度,推送给平台发货状态
*
* @param string $status
* @return bool
*/
public function pushDeliveryConfirm($params, &$error_msg=null)
{
$deliveryObj = app::get('ome')->model('delivery');
$dlyBillObj = app::get('ome')->model('delivery_bill');
$packageObj = app::get('ome')->model('delivery_package');
$deliveryOrderObj = app::get('ome')->model('delivery_order');
$routeLib = kernel::single('ome_event_trigger_shop_data_delivery_router');
$delivery_bn = $params['delivery_bn'];
$package_bn = $params['package_bn'];
//物流包裹单信息
$billInfo = $dlyBillObj->dump(array('delivery_bn'=>$delivery_bn, 'package_bn'=>$package_bn), '*');
if(empty($billInfo)){
$error_msg = '没有获取到物流包裹单信息';
return false;
}
//已经推送平台成功
if($billInfo['sync_status'] == 'succ'){
return true;
}
if(!in_array($billInfo['status'], array('1', '4'))){
$error_msg = '物流包裹单不是发货状态';
return false;
}
//获取物流单号
if(empty($billInfo['logi_code']) || empty($billInfo['logi_no'])){
$sql = "SELECT * FROM sdb_ome_delivery_package WHERE package_bn='". $package_bn ."' AND status IN('delivery', 'sign')";
$packageRow = $deliveryObj->db->selectrow($sql);
if($packageRow){
$billInfo['logi_code'] = $packageRow['logi_bn'];
$billInfo['logi_no'] = $packageRow['logi_no'];
}
}
//check
if(empty($billInfo['logi_code']) || empty($billInfo['logi_no'])){
$error_msg = '没有物流信息';
return false;
}
$delivery_id = $billInfo['delivery_id'];
//物流公司名称
$sql = "SELECT corp_id,type,name FROM sdb_ome_dly_corp WHERE type='". $billInfo['logi_code'] ."'";
$corpInfo = $dlyBillObj->db->selectrow($sql);
$billInfo['logi_name'] = $corpInfo['name'];
//获取已发货的京东包裹单
$filter = array('delivery_id'=>$delivery_id, 'package_bn'=>$package_bn, 'status'=>array('delivery','sign'));
$dataList = $packageObj->getList('*', $filter);
if(empty($dataList)){
$error_msg = '没有找到关联的京东包裹明细';
return false;
}
//按sku组织发货明细
$dlyBns = array();
foreach ($dataList as $key => $val)
{
$product_bn = $val['bn'];
$number = $val['number'];
//过滤京东赠品
if($val['is_wms_gift'] == 'true'){
continue;
}
if($dlyBns[$product_bn]){
$dlyBns[$product_bn] += $number;
}else{
$dlyBns[$product_bn] = $number;
}
}
//发货单信息
$deliveryInfo = $deliveryObj->dump(array('delivery_id'=>$delivery_id), '*');
//合并发货单类型
if($deliveryInfo['is_bind'] == 'true'){
//所有子发货单
$childrenDlyIds = array();
$childrednDeliveryList = $deliveryObj->getList('*', array('parent_id'=>$deliveryInfo['delivery_id']));
foreach ($childrednDeliveryList as $c_key => $c_delivery)
{
//使用父发货单上物流信息
$childrednDeliveryList[$c_key]['status'] = $deliveryInfo['status'];
$childrednDeliveryList[$c_key]['logi_id'] = $deliveryInfo['logi_id'];
$childrednDeliveryList[$c_key]['logi_name'] = $deliveryInfo['logi_name'];
$childrednDeliveryList[$c_key]['logi_no'] = $deliveryInfo['logi_no'];
$childrednDeliveryList[$c_key]['delivery_cost_actual'] = $deliveryInfo['delivery_cost_actual'];
$childrenDlyIds[] = $c_delivery['delivery_id'];
}
//获取发货单对应的订单
$delivery_orders = array();
$sql = "SELECT a.*, b.delivery_id FROM sdb_ome_orders AS a LEFT JOIN sdb_ome_delivery_order AS b ON a.order_id=b.order_id
WHERE b.delivery_id IN(". implode(',', $childrenDlyIds) .")";
$orderList = $dlyBillObj->db->select($sql);
foreach ($orderList as $key => $val)
{
$c_delivery_id = $val['delivery_id'];
$delivery_orders[$c_delivery_id] = $val;
}
foreach ($childrednDeliveryList as $c_delivery)
{
//组织回传参数
$dlySdf = $routeLib->set_shop_id($deliveryInfo['shop_id'])->init($c_delivery, $delivery_orders)->get_sdf($deliveryInfo['delivery_id']);
//[兼容]发货物流信息
$dlySdf['logi_type'] = ($billInfo['logi_code'] ? $billInfo['logi_code'] : $dlySdf['logi_type']);
$dlySdf['logi_no'] = ($billInfo['logi_no'] ? $billInfo['logi_no'] : $dlySdf['logi_no']);
$dlySdf['logi_name'] = ($billInfo['logi_name'] ? $billInfo['logi_name'] : $dlySdf['logi_name']);
//格式化请求参数
$sdf = $this->formatDeliveryParmas($dlySdf, $dlyBns, $error_msg);
if(!$sdf){
return false;
}
//request
$result = kernel::single('erpapi_router_request')->set('shop', $deliveryInfo['shop_id'])->delivery_confirm($sdf);
if($result['rsp'] == 'fail'){
$error_msg = $result['err_msg'];
$dlyBillObj->update(array('sync_status'=>'fail'), array('log_id'=>$billInfo['log_id']));
return false;
}elseif($result['rsp'] == 'succ'){
$dlyBillObj->update(array('sync_status'=>'succ'), array('log_id'=>$billInfo['log_id']));
}
}
}else{
//获取订单信息
$sql = "SELECT a.* FROM sdb_ome_orders AS a LEFT JOIN sdb_ome_delivery_order AS b ON a.order_id=b.order_id
WHERE b.delivery_id=". $delivery_id;
$orderInfo = $dlyBillObj->db->selectrow($sql);
//组织回传参数
$deliveryList = array($deliveryInfo);
$delivery_orders[$delivery_id] = $orderInfo;
$dlySdf = $routeLib->set_shop_id($deliveryInfo['shop_id'])->init($deliveryList, $delivery_orders)->get_sdf($deliveryInfo['delivery_id']);
//[兼容]发货物流信息
$dlySdf['logi_type'] = ($billInfo['logi_code'] ? $billInfo['logi_code'] : $dlySdf['logi_type']);
$dlySdf['logi_no'] = ($billInfo['logi_no'] ? $billInfo['logi_no'] : $dlySdf['logi_no']);
$dlySdf['logi_name'] = ($billInfo['logi_name'] ? $billInfo['logi_name'] : $dlySdf['logi_name']);
//格式化请求参数
$sdf = $this->formatDeliveryParmas($dlySdf, $dlyBns, $error_msg);
if(!$sdf){
return false;
}
//request
$result =kernel::single('erpapi_router_request')->set('shop', $deliveryInfo['shop_id'])->delivery_confirm($sdf);
if($result['rsp'] == 'fail'){
$error_msg = $result['err_msg'];
$dlyBillObj->update(array('sync_status'=>'fail'), array('log_id'=>$billInfo['log_id']));
return false;
}elseif($result['rsp'] == 'succ'){
$dlyBillObj->update(array('sync_status'=>'succ'), array('log_id'=>$billInfo['log_id']));
}
}
unset($billInfo, $filter, $dataList, $deliveryInfo);
return true;
}
/**
* 按京东订单纬度,推送给平台发货状态
*
* @param string $status
* @return bool
*/
public function formatDeliveryParmas($dlySdf, $dlyBns, &$error_msg=null)
{
$delivery_items = $dlySdf['delivery_items'];
if(empty($delivery_items)){
$error_msg = '没有获取到发货商品明细';
return false;
}
//加入拆单标识
$dlySdf['is_split'] = 1;
//重置发货状态
$dlySdf['status'] = 'succ';
//items
$dlyItems = array();
foreach ($delivery_items as $key => $val)
{
$product_bn = ($val['bn'] ? $val['bn'] : $val['product_bn']);
$number = $val['number'];
//过滤不是京东订单上的商品
if(empty($dlyBns[$product_bn])){
continue;
}
//[兼容]发货物流信息
$val['logi_type'] = ($dlySdf['logi_type'] ? $dlySdf['logi_type'] : $val['logi_type']);
$val['logi_no'] = ($dlySdf['logi_no'] ? $dlySdf['logi_no'] : $val['logi_no']);
$dlyItems[$key] = $val;
}
$dlySdf['delivery_items'] = $dlyItems;
//删除收货人信息
unset($dlySdf['consignee']);
//销毁
unset($delivery_items, $dlyItems);
return $dlySdf;
}
/**
* 映射WMS仓储物流编码
* @todo兼容京东传的物流单号是ID
*
* @param string $logi_code
* @return string
*/
public function getLogiCode($logi_code, $wms_id)
{
$dlyCorpObj = app::get('ome')->model('dly_corp');
$relationObj = app::get('wmsmgr')->model('express_relation');
//获取物流公司对照关系
$logiMapInfo = $relationObj->dump(array('wms_id'=>$wms_id, 'wms_express_bn'=>$logi_code), 'sys_express_bn');
$logi_code = ($logiMapInfo['sys_express_bn'] ? $logiMapInfo['sys_express_bn'] : $logi_code);
//获取物流公司信息
$dlyInfo = $dlyCorpObj->dump(array('type'=>$logi_code), 'corp_id,type,name');
//[兼容]指定物流公司
if(empty($dlyInfo)){
//QT其它物流公司
$logi_type = 'QT';
$dlyInfo = $dlyCorpObj->dump(array('type'=>$logi_type), 'corp_id,type,name');
//JD京东物流公司
if(empty($dlyInfo)){
$logi_type = 'JD';
$dlyInfo = $dlyCorpObj->dump(array('type'=>$logi_type), 'corp_id,type,name');
}
}
$logi_code = ($dlyInfo['type'] ? $dlyInfo['type'] : $logi_code);
return $logi_code;
}
/**
* 处理京东云交易赠品
*/
public function disposeKeplerGift($delivery, $params)
{
$packageObj = app::get('ome')->model('delivery_package');
$deliveryId = $delivery['delivery_id'];
$status = strtolower($params['status']);
//父单号
$rootOrderId = trim($params['rootOrderId']);
$rootOrderId = ($rootOrderId && $rootOrderId != '0') ? $rootOrderId : '';
//子单号
$jd_order_id = $params['oid'];
//check
if(empty($delivery) || empty($jd_order_id) || empty($params['item']) || $status != 'delivery'){
return false;
}
//获取京东包裹里赠品
$tempList = $packageObj->getList('*', array('delivery_id'=>$deliveryId, 'is_wms_gift'=>'true'));
if(empty($tempList)){
return false;
}
$packageList = array();
foreach ($tempList as $key => $val)
{
$package_bn = $val['package_bn'];
$outer_sku = ($val['outer_sku'] ? $val['outer_sku'] : $val['bn']);
//过滤已取消记录
if($val['status'] == 'cancel'){
continue;
}
$packageList[$package_bn][$outer_sku] = $val;
}
if(empty($packageList)){
return false;
}
//items
$itemsList = json_decode($params['item'], true);
foreach ($itemsList as $key => $val)
{
$isRootFlag = false;
$outer_sku = $val['product_bn'];
//包裹信息
if($packageList[$rootOrderId][$outer_sku]){
$isRootFlag = true;
$packageInfo = $packageList[$rootOrderId][$outer_sku];
}else{
$packageInfo = $packageList[$jd_order_id][$outer_sku];
}
$package_id = $packageInfo['package_id'];
if(empty($package_id)){
continue;
}
//获取物流信息
$logi_code = '';
$val['logistics'] = trim($val['logistics']);
$val['logistics'] = str_replace(array('"', "'"), '', $val['logistics']);
if($val['logistics'] && $val['logi_no']){
$logi_code = $this->getLogiCode($val['logistics'], $delivery['wms_id']);
}
//如果有子单取消父单
if ($isRootFlag && $rootOrderId) {
//取消父单
$packageObj->update(array('status'=>'cancel'), array('package_bn'=>$rootOrderId));
//创建子单
$saveData = array(
'delivery_id' => $packageInfo['delivery_id'],
'order_id' => $packageInfo['order_id'],
'package_bn' => $jd_order_id,
'logi_bn' => $logi_code,
'logi_no' => $val['logi_no'],
'product_id' => $val['product_id'],
'bn' => $packageInfo['bn'],
'outer_sku' => $packageInfo['outer_sku'],
'status' => $status,
'number' => $val['num'],
'create_time' => time(),
'delivery_time' => time(),
'is_wms_gift' => 'true', //赠品类型
'main_sku_id' => $packageInfo['main_sku_id'], //关联主sku
);
$packageObj->insert($saveData);
}elseif($logi_code){
//更新物流信息
$saveData = array(
'status' => $status,
'logi_bn' => $logi_code,
'logi_no' => $val['logi_no'],
);
$packageObj->update($saveData, array('package_id'=>$package_id));
}
}
return true;
}
/**
* 重试推送失败的发货单
* @todo每3个小时自动推送失败的发货单检索"商品无货"关键字;
*
* @return bool
*/
public function auto_retry_wms_delivery()
{
$apiFailModel = app::get('erpapi')->model('api_fail');
$deliveryMdl = app::get('ome')->model('delivery');
//config
$retryConfig = app::get('ome')->getConf('ome.delivery.retry_push');
if($retryConfig != 'on'){
return false; //未开启重新推送配置
}
//filter
$objType = 'delivery';
$retryError = array(
// '商品无货', //商品无货
'timeout', //超时
'e00090', //请求超时
'timed out', //请求超时
);
//每3小时自动推送
$endTime = time() - (10 * 60);
//查询近3天内的失败(只查前500条数据)
$filter = array(
'last_modify|sthan' => $endTime, //小于等于10分钟
'last_modify|than' => strtotime('-1 days'), //大于3天之前
'obj_type' => $objType,
'fail_times|lthan' => '15', //失败次数
'status' => 'fail',
'filter_sql' => ' err_msg REGEXP "' . implode('|', $retryError) . '"',
);
$dataList = $apiFailModel->getList('*', $filter, 0, 500, 'last_modify DESC,fail_times ASC');
if(empty($dataList)){
return false;
}
//发货单列表
$deliveryBns = array_column($dataList, 'obj_bn');
$deliveryList = $deliveryMdl->getList('delivery_id,delivery_bn,status,pause,process,sync_status', array('delivery_bn'=>$deliveryBns));
$deliveryList = array_column($deliveryList, null, 'delivery_bn');
//查订单list 判断订单状态 已支付 未发货
$orderIdList = app::get('ome')->model('delivery_order')->getList('order_id,delivery_id',['delivery_id'=>array_column($deliveryList,'delivery_id')]);
$orderIds = array_column($orderIdList,'order_id');
$deliveryOrderIds = [];
foreach($orderIdList as $val){
$deliveryOrderIds[$val['delivery_id']][] = $val['order_id'];
}
$orderList = app::get('ome')->model('orders')->getList('order_id,pay_status,ship_status',['order_id'=>$orderIds]);
$orderList = array_column($orderList,null,'order_id');
//list
foreach ($dataList as $key => $value)
{
//推送发货单无法使用$apiFailModel->retry()方法
//@todoome_delivery_notice::create($delivery_id)是静态方法;
//$apiFailModel->retry($value);
$id = $value['id'];
$obj_bn = $value['obj_bn'];
//发货单信息
$deliveryInfo = $deliveryList[$obj_bn];
//execute
if(in_array($deliveryInfo['status'], array('succ','cancel','back','return_back'))){
//删除此记录
$apiFailModel->delete(array('id'=>$id));
continue;
}elseif(in_array($deliveryInfo['status'], array('progress','ready')) && $deliveryInfo['pause'] == 'false' && $deliveryInfo['process'] == 'false' && in_array($deliveryInfo['sync_status'],['2'])){
$orderIdList = $deliveryOrderIds[$deliveryInfo['delivery_id']] ?? [];
if ($orderIdList) {
$is_push = true;
foreach ($orderIdList as $order_id) {
$order = $orderList[$order_id];
//已支付 未发货
if (!$order || $order['pay_status'] != 1 || $order['ship_status'] != 0) {
$is_push = false;
}
}
if ($is_push) {
//发货单通知单推送仓库
ome_delivery_notice::create($deliveryInfo['delivery_id']);
}
}
}
}
return true;
}
}