[TBID:SCRUM-7446] v8.5.0

1、支持拼多多消费者付费送货上门服务信息
2、修复唯品会库存回写多规格问题
3、优化天猫加急发货逻辑
4、增加库存回写触发依据配置
5、京东余额支付包含进订单支付金额中
This commit is contained in:
chenping
2026-07-27 17:02:14 +08:00
parent b40887c9c3
commit 2367b18a64
46 changed files with 1604 additions and 423 deletions

View File

@@ -15,8 +15,6 @@
* limitations under the License.
*/
class console_ctl_admin_delivery extends desktop_controller {
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
var $name = "发货单列表";
var $workground = "console_center";
@@ -164,7 +162,7 @@ class console_ctl_admin_delivery extends desktop_controller {
'label'=>app::get('base')->_('加急发货'),
'filter'=>array(
'status' => array('ready','progress','succ'),
'order_label_code' => self::URGENT_LABEL_CODE,
'order_label_code' => 'SOMS_URGENT_SHIP',
),
'optional'=>false
),
@@ -536,6 +534,39 @@ class console_ctl_admin_delivery extends desktop_controller {
$this->display("admin/delivery_showmemo.html");
}
/**
* 过滤批量提交的发货单ID
*
* delivery_id来自后台批量操作的POST参数后续会拼接到SQL的IN条件中。
* 这里只保留正整数ID并去重避免恶意参数未经处理进入SQL造成注入风险。
*
* @param mixed $deliveryIds
* @return array
*/
private function _filterDeliveryIds($deliveryIds)
{
$deliveryIds = (array) $deliveryIds;
$result = array();
foreach ($deliveryIds as $deliveryId) {
if (!is_scalar($deliveryId)) {
continue;
}
$deliveryId = trim($deliveryId);
if (!preg_match('/^\d+$/', $deliveryId)) {
continue;
}
$deliveryId = intval($deliveryId);
if ($deliveryId > 0) {
$result[$deliveryId] = $deliveryId;
}
}
return array_values($result);
}
/**
* 强制撤销第三方仓储发货单
*
@@ -548,7 +579,7 @@ class console_ctl_admin_delivery extends desktop_controller {
$operLogObj = app::get('ome')->model('operation_log');
$limit = 500;
$deliveryIds = $_POST['delivery_id'];
$deliveryIds = $this->_filterDeliveryIds($_POST['delivery_id']);
//check
if($_POST['isSelectedAll'] == '_ALL_'){

View File

@@ -18,7 +18,14 @@
class desktop_finder_builder_filter_render
{
function __contruct($finder_aliasname){
/**
* 保存当前Finder别名供高级筛选扩展区分同一模型下的不同业务页面。
*
* 部分调用场景不会传入别名,因此参数必须保持可选,兼容原有无参实例化。
*
* @param string|null $finder_aliasname
*/
function __construct($finder_aliasname=null){
$this->finder_aliasname = $finder_aliasname;
}
function main($object_name,$app,$filter=null,$controller=null,$cusrender=null){
@@ -138,4 +145,3 @@ class desktop_finder_builder_filter_render
$render->display('finder/finder_filter.html');
}
}

View File

@@ -312,7 +312,7 @@ class erpapi_shop_matrix_360buy_response_order extends erpapi_shop_response_orde
}
}
}
if($value['type'] == 110) {
/* if($value['type'] == 110) {
$balanceAmount = 0;
// 定义控制变量:初始值为不加
$shouldAddAmount = false;
@@ -339,7 +339,7 @@ class erpapi_shop_matrix_360buy_response_order extends erpapi_shop_response_orde
"paymethod" => '余额'
];
}
}
} */
// bearer = 5 国补立减,也需要算在订单总额里
//@todo官方文档https://open.jd.com/v2/#/doc/scene?listId=2168

View File

@@ -264,6 +264,11 @@ class erpapi_shop_matrix_luban_response_aftersalev2 extends erpapi_shop_response
if($params['refund_type']=='return' && empty($params['return_type'])){
$sdf['return_type'] = $params['refund_type'];
}
//平台优惠退回金额(平台下发单位为分,转为元)
if (isset($params['platform_discount_return_amount']) && $params['platform_discount_return_amount'] !== '') {
$sdf['platform_discount_return_amount'] = sprintf('%.2f', $params['platform_discount_return_amount'] / 100);
}
return $sdf;
}

View File

@@ -40,6 +40,14 @@ class erpapi_shop_matrix_pinduoduo_response_order extends erpapi_shop_response_o
{
parent::_analysis();
// 矩阵回调原始数据不保证携带 shop_type付费送货上门插件需据此限定拼多多订单
// 直接使用已通过路由校验的店铺配置,避免依赖可选的预处理服务补齐该字段。
$this->_ordersdf['shop_type'] = $this->__channelObj->channel['shop_type'];
// 消费者付费送货上门依赖平台服务费明细。先统一格式化服务信息,
// 后续订单标签和物流白名单插件只读取标准结构,避免各处重复兼容矩阵嵌套数据。
$this->_formatChargeHomeDeliveryDoor();
if($this->_ordersdf['consignee']['area_city'] == '县') {
$this->_ordersdf['consignee']['area_city'] = $this->_ordersdf['consignee']['area_state'];
}
@@ -184,14 +192,113 @@ class erpapi_shop_matrix_pinduoduo_response_order extends erpapi_shop_response_o
$plugins[] = 'confirmreceipt';
}
if($this->_ordersdf['is_delivery']=='Y'){
// 本服务的标签和白名单需要在服务取消时主动清理,不能完全依赖 is_delivery。
// 风险单等场景会先变为 N若历史已打标仍需运行插件恢复其他业务白名单。
if ($this->_ordersdf['is_delivery'] == 'Y' || $this->_needSyncChargeHomeDeliveryDoor()) {
$plugins[] = 'orderextend';
$plugins[] = 'orderlabels';
}
return $plugins;
}
/**
* 判断不可配送订单是否仍需同步或清理消费者付费送货上门服务
*/
private function _needSyncChargeHomeDeliveryDoor()
{
if (!empty($this->_ordersdf['charge_home_delivery_door']['active'])) {
return true;
}
$orderId = $this->_tgOrder['order_id'] ?? 0;
if (!$orderId) {
return false;
}
$oldExtend = app::get('ome')->model('order_extend')->db_dump(
['order_id' => $orderId],
'extend_field'
);
$oldExtendField = $oldExtend['extend_field']
? json_decode($oldExtend['extend_field'], true)
: [];
if (!empty($oldExtendField['charge_home_delivery_door_oms'])) {
return true;
}
// 兼容历史执行中扩展信息保存失败、但标签已经写入的半完成状态。
$labelInfo = kernel::single('ome_bill_label')->getBillLabelInfo(
$orderId,
'order',
'SOMS_ZFSHSM'
);
return !empty($labelInfo);
}
/**
* 格式化拼多多消费者付费送货上门服务信息
*
* 矩阵的 service_fee_detail 可能是数组、嵌套数组或 JSON 字符串。
* 这里只识别 charge_home_delivery_door并将有效服务费汇总成 OMS 标准结构,
* 供订单标签打标、费用保存和审单物流白名单处理共同使用。
*/
private function _formatChargeHomeDeliveryDoor()
{
$serviceFee = 0;
$serviceDetail = $this->_ordersdf['extend_field']['service_fee_detail'] ?? [];
$this->_collectChargeHomeDeliveryDoorFee($serviceDetail, $serviceFee);
$serviceFee = round($serviceFee, 2);
$serviceInfo = [
'active' => $serviceFee > 0,
'service_name' => 'charge_home_delivery_door',
'service_fee' => number_format($serviceFee, 2, '.', ''),
'white_delivery_cps' => ['ZTO', 'YTO', 'STO', 'jitu', 'YUNDA'],
];
$this->_ordersdf['charge_home_delivery_door'] = $serviceInfo;
if ($serviceInfo['active']) {
$this->_ordersdf['extend_field']['charge_home_delivery_door_oms'] = $serviceInfo;
} else {
unset($this->_ordersdf['extend_field']['charge_home_delivery_door_oms']);
}
}
/**
* 递归汇总消费者付费送货上门服务费
*
* @param mixed $serviceDetail
* @param float $serviceFee
*/
private function _collectChargeHomeDeliveryDoorFee($serviceDetail, &$serviceFee)
{
if (is_string($serviceDetail)) {
$decoded = json_decode($serviceDetail, true);
if (!is_array($decoded)) {
return;
}
$serviceDetail = $decoded;
}
if (!is_array($serviceDetail)) {
return;
}
if (isset($serviceDetail['service_name'])) {
if ($serviceDetail['service_name'] == 'charge_home_delivery_door'
&& is_numeric($serviceDetail['service_fee'])
&& $serviceDetail['service_fee'] > 0) {
$serviceFee += (float)$serviceDetail['service_fee'];
}
return;
}
foreach ($serviceDetail as $detail) {
$this->_collectChargeHomeDeliveryDoorFee($detail, $serviceFee);
}
}
protected function get_update_components()
{
$components = array('markmemo','marktype','custommemo');

View File

@@ -39,7 +39,7 @@ class erpapi_shop_matrix_vop_request_product extends erpapi_shop_request_product
$bns = array();
foreach ($stocks as $key => $val)
{
$product_bn = trim($val['barcode']); // 用条码barcode去匹配
$barcode = trim($val['barcode']); // 用条码barcode去匹配
//指定常态合作编码cooperation_no回写库存
if($cooperation_no){
@@ -47,21 +47,24 @@ class erpapi_shop_matrix_vop_request_product extends erpapi_shop_request_product
}
//sku_id
$val['sku_id'] = $product_bn;
$val['sku_id'] = $barcode;
$bns[$product_bn] = $val;
$bns[$barcode] = $val;
}
//按店铺+货号查询
$tempList = $skuObj->getList('shop_iid,shop_product_bn', array('shop_id' => $shop_id, 'shop_product_bn' => array_keys($bns)));
$tempList = $skuObj->getList('id,shop_iid,shop_product_bn,shop_sku_id', array('shop_id'=>$shop_id, 'shop_sku_id'=>array_keys($bns)));
if (empty($tempList)) {
return false;
}
$itemStocks = [];
foreach ($tempList as $k => $v) {
if ($bns[$v['shop_product_bn']]) {
$itemStocks[] = $bns[$v['shop_product_bn']];
foreach ($tempList as $k => $v)
{
$barcode = $v['shop_sku_id'];
if ($bns[$barcode]) {
$itemStocks[] = $bns[$barcode];
}
}
unset($tempList, $stocks);

View File

@@ -16,19 +16,17 @@
*/
/**
* 订单催发货(店小蜜)
*
*
* @author wangbiao<wangbiao@shopex.cn>
* @version 0.1
*/
class erpapi_shop_response_delivergoods extends erpapi_shop_response_abstract
{
const URGENT_SERVICE_TAG = '加急发货';
const URGENT_ORDER_FIELDS = 'order_id, order_bn, process_status, status, ship_status, order_bool_type, shop_id, shop_type, source, createway, sync, sync_fail_type, abnormal, pause, timing_confirm, pay_status, is_cod, order_type, logi_no,last_modified';
/**
* 接收参数
*/
public $_sdf = array();
/**
@@ -40,7 +38,7 @@ class erpapi_shop_response_delivergoods extends erpapi_shop_response_abstract
public function urgent($params){
$tid = $params['tid'];
$serviceTags = $this->normalizeServiceTags($params['service_tags']);
$isUrgentShip = in_array(self::URGENT_SERVICE_TAG, $serviceTags, true);
$isUrgentShip = in_array('加急发货', $serviceTags, true);
$this->__apilog['title'] = sprintf('%s[%s]', $isUrgentShip ? '淘宝加急发货' : '催发货', $tid);
$this->__apilog['original_bn'] = $tid;
@@ -249,7 +247,7 @@ class erpapi_shop_response_delivergoods extends erpapi_shop_response_abstract
/**
* 格式化参数
*
*
* @param array $params
* @return array:
*/

View File

@@ -107,6 +107,13 @@ class erpapi_shop_response_plugins_order_orderextend extends erpapi_shop_respons
if($platform->_ordersdf['biz_delivery_code']){
$extend['biz_delivery_code'] = $platform->_ordersdf['biz_delivery_code'];
}
// 控制字段只在插件保存阶段使用,不写入 order_extend 表。
// 由保存阶段结合旧白名单计算有效交集,防止直接覆盖其他物流服务的限制。
if ($platform->_ordersdf['shop_type'] == 'pinduoduo'
&& isset($platform->_ordersdf['charge_home_delivery_door'])) {
$extend['_charge_home_delivery_door'] = $platform->_ordersdf['charge_home_delivery_door'];
}
//保价订单SKU商品
if ($platform->_ordersdf['extend_field']['special_refund_type_info'] && is_array($platform->_ordersdf['extend_field']['special_refund_type_info'])) {
foreach ($platform->_ordersdf['extend_field']['special_refund_type_info'] as $skuOid => $skuVal)
@@ -226,6 +233,8 @@ class erpapi_shop_response_plugins_order_orderextend extends erpapi_shop_respons
public function postCreate($order_id,$extendinfo)
{
$orderExtendObj = app::get('ome')->model('order_extend');
$extendinfo = $this->_prepareChargeHomeDeliveryDoorExtend($order_id, $extendinfo);
if ($extendinfo['contents']) {
// 判断contents是否有值
@@ -266,6 +275,8 @@ class erpapi_shop_response_plugins_order_orderextend extends erpapi_shop_respons
public function postUpdate($order_id,$extendinfo)
{
$orderExtendObj = app::get('ome')->model('order_extend');
$extendinfo = $this->_prepareChargeHomeDeliveryDoorExtend($order_id, $extendinfo);
if ($extendinfo['contents']) {
// 判断contents是否有值
@@ -287,6 +298,66 @@ class erpapi_shop_response_plugins_order_orderextend extends erpapi_shop_respons
$orderExtendObj->save($extendinfo);
}
}
/**
* 合并拼多多消费者付费送货上门物流白名单
*
* white_delivery_cps 可能已经承载其他平台物流服务限制。首次命中服务时取交集,
* 并在 OMS 专用扩展节点保存合并前白名单;服务取消时再恢复,避免直接清空或覆盖
* 其他业务写入的承运商限制。
*
* @param int $order_id
* @param array $extendinfo
* @return array
*/
private function _prepareChargeHomeDeliveryDoorExtend($order_id, $extendinfo)
{
if (!array_key_exists('_charge_home_delivery_door', $extendinfo)) {
return $extendinfo;
}
$serviceInfo = $extendinfo['_charge_home_delivery_door'];
unset($extendinfo['_charge_home_delivery_door']);
$orderExtendObj = app::get('ome')->model('order_extend');
$oldExtend = $orderExtendObj->db_dump(['order_id' => $order_id], 'white_delivery_cps,extend_field');
$oldExtendField = $oldExtend['extend_field'] ? json_decode($oldExtend['extend_field'], true) : [];
$newExtendField = $extendinfo['extend_field'] ? json_decode($extendinfo['extend_field'], true) : [];
$oldServiceInfo = $oldExtendField['charge_home_delivery_door_oms'] ?? [];
if ($serviceInfo['active']) {
if (array_key_exists('white_delivery_cps', $extendinfo)) {
$originalWhiteDeliveryCps = json_decode($extendinfo['white_delivery_cps'], true);
} elseif (array_key_exists('original_white_delivery_cps', $oldServiceInfo)) {
$originalWhiteDeliveryCps = $oldServiceInfo['original_white_delivery_cps'];
} else {
$originalWhiteDeliveryCps = $oldExtend['white_delivery_cps'] ? json_decode($oldExtend['white_delivery_cps'], true) : [];
}
$originalWhiteDeliveryCps = array_values(array_unique(array_filter((array)$originalWhiteDeliveryCps)));
$serviceWhiteDeliveryCps = array_values(array_unique((array)$serviceInfo['white_delivery_cps']));
$effectiveWhiteDeliveryCps = $originalWhiteDeliveryCps
? array_values(array_intersect($originalWhiteDeliveryCps, $serviceWhiteDeliveryCps))
: $serviceWhiteDeliveryCps;
$serviceInfo['original_white_delivery_cps'] = $originalWhiteDeliveryCps;
$serviceInfo['effective_white_delivery_cps'] = $effectiveWhiteDeliveryCps;
$newExtendField['charge_home_delivery_door_oms'] = $serviceInfo;
$extendinfo['white_delivery_cps'] = json_encode($effectiveWhiteDeliveryCps);
$extendinfo['extend_field'] = json_encode($newExtendField, JSON_UNESCAPED_UNICODE);
} elseif ($oldServiceInfo) {
// 当前白名单仍是本功能上次写入的值时才恢复,避免覆盖期间由其他业务更新的白名单。
$currentWhiteDeliveryCps = $oldExtend['white_delivery_cps'] ? json_decode($oldExtend['white_delivery_cps'], true) : [];
$effectiveWhiteDeliveryCps = (array)$oldServiceInfo['effective_white_delivery_cps'];
if ($currentWhiteDeliveryCps == $effectiveWhiteDeliveryCps) {
$extendinfo['white_delivery_cps'] = json_encode((array)$oldServiceInfo['original_white_delivery_cps']);
}
unset($newExtendField['charge_home_delivery_door_oms']);
$extendinfo['extend_field'] = json_encode($newExtendField, JSON_UNESCAPED_UNICODE);
}
return $extendinfo;
}
/**
* 翱象数据格式化

View File

@@ -123,6 +123,29 @@ class erpapi_shop_response_plugins_order_orderlabels extends erpapi_shop_respons
}
}
// 拼多多消费者付费送货上门使用独立标签,不能复用 SOMS_SHSM。
// 服务费随标签保存在 extend_info供订单和发货单展示同一份消费者付费金额。
if ($platform->_ordersdf['shop_type'] == 'pinduoduo'
&& isset($platform->_ordersdf['charge_home_delivery_door'])) {
$serviceInfo = $platform->_ordersdf['charge_home_delivery_door'];
if ($serviceInfo['active']) {
$labels[] = [
'label_code' => 'SOMS_ZFSHSM',
'extend_info' => json_encode([
'service_name' => $serviceInfo['service_name'],
'service_fee' => $serviceInfo['service_fee'],
'service_white_delivery_cps' => $serviceInfo['white_delivery_cps'],
], JSON_UNESCAPED_UNICODE),
];
} else {
// 创建订单时 postCreate 会忽略删除动作;更新订单时用于清理已取消的服务标签。
$labels[] = [
'label_code' => 'SOMS_ZFSHSM',
'label_action' => 'del',
];
}
}
// 集运信息打标签
if ($platform->_ordersdf['extend_field']['consolidate_info']) {
$consolidate_type = $platform->_ordersdf['extend_field']['consolidate_info']['consolidate_type'];

View File

@@ -77,6 +77,9 @@ class erpapi_shop_response_process_aftersalev2 {
if($sdf['refund_version_change']) {
$upData['memo'] = $sdf['reason'];
$upData['money'] = $sdf['refund_fee'];
if (isset($sdf['platform_discount_return_amount'])) {
$upData['platform_discount_return_amount'] = $sdf['platform_discount_return_amount'];
}
}
$memo = '更新成功,状态:' . $sdf['status'];
break;
@@ -212,6 +215,7 @@ class erpapi_shop_response_process_aftersalev2 {
'tag_type' => ($sdf['tag_type'] ? $sdf['tag_type'] : '0'), //退款类型
'jsrefund_flag' => ($sdf['jsrefund_flag'] ? $sdf['jsrefund_flag'] : '0'), //极速退款标识
'cs_status' => $sdf['cs_status'],
'platform_discount_return_amount' => isset($sdf['platform_discount_return_amount']) ? $sdf['platform_discount_return_amount'] : 0,
);
// 经销店铺的单据delivery_mode冗余到退款单申请表

View File

@@ -22,12 +22,6 @@
*/
class erpapi_shop_response_process_delivergoods extends erpapi_shop_response_abstract
{
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
const URGENT_SERVICE_TAG = '加急发货';
const URGENT_REPORT_TASK_NOTIFY = 'urgent_logistics_notify';
const URGENT_REPORT_TASK_DELIVERY = 'urgent_logistics_dly';
const URGENT_REPORT_TASK_CONSIGN = 'urgent_logistics_csg';
/**
* 根据 service_tags 分流普通催发货与淘宝加急发货处理。
*
@@ -135,19 +129,18 @@ class erpapi_shop_response_process_delivergoods extends erpapi_shop_response_abs
$labelLib = kernel::single('ome_bill_label');
$deliveryMdl = app::get('ome')->model('delivery');
$deliveryIds = $deliveryMdl->getDeliverIdByOrderId($order['order_id']);
$alreadyMarked = $labelLib->existLabel($order['order_id'], self::URGENT_LABEL_CODE);
$alreadyMarked = $labelLib->existLabel($order['order_id'], 'SOMS_URGENT_SHIP');
if (!$alreadyMarked) {
$err = '';
$markResult = $labelLib->markBillLabel($order['order_id'], '', self::URGENT_LABEL_CODE, 'order', $err);
$markResult = $labelLib->markBillLabel($order['order_id'], '', 'SOMS_URGENT_SHIP', 'order', $err);
if (!$markResult) {
return $this->fail('SYSTEM_ERROR', $err ?: '订单加急标签写入失败', true, $order['order_bn']);
}
}
if ($deliveryIds) {
foreach ((array)$deliveryIds as $deliveryId) {
$err = '';
$labelLib->markBillLabel($deliveryId, '', self::URGENT_LABEL_CODE, 'delivery', $err);
$labelLib->orderToDeliveryLabel($order['order_id'], $deliveryId, 'ome_delivery');
}
}
@@ -200,10 +193,10 @@ class erpapi_shop_response_process_delivergoods extends erpapi_shop_response_abs
{
if (!is_array($order['service_tags'])) {
$serviceTags = trim((string)$order['service_tags']);
return $serviceTags !== '' && $serviceTags === self::URGENT_SERVICE_TAG;
return $serviceTags !== '' && $serviceTags === '加急发货';
}
return in_array(self::URGENT_SERVICE_TAG, $order['service_tags'], true);
return in_array('加急发货', $order['service_tags'], true);
}
/**
@@ -274,13 +267,13 @@ class erpapi_shop_response_process_delivergoods extends erpapi_shop_response_abs
return false;
}
$taskTypeMap = [
'notify' => self::URGENT_REPORT_TASK_NOTIFY,
'delivery_status' => self::URGENT_REPORT_TASK_DELIVERY,
'consign_sync' => self::URGENT_REPORT_TASK_CONSIGN,
'notify' => 'urgent_logistics_notify',
'delivery_status' => 'urgent_logistics_dly',
'consign_sync' => 'urgent_logistics_csg',
];
return app::get('ome')->model('misc_task')->saveMiscTask([
'obj_id' => intval($orderId),
'obj_type' => $taskTypeMap[$scene] ?: self::URGENT_REPORT_TASK_NOTIFY,
'obj_type' => $taskTypeMap[$scene] ?: 'urgent_logistics_notify',
'exec_time' => time(),
'addon' => json_encode(['scene' => $scene], JSON_UNESCAPED_UNICODE),
]);

View File

@@ -24,7 +24,6 @@
*/
class erpapi_wms_matrix_qimen_request_delivery extends erpapi_wms_request_delivery
{
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
private $_shop_type_mapping = array(
'taobao' => 'TB',
'paipai' => 'PP',
@@ -594,15 +593,15 @@ class erpapi_wms_matrix_qimen_request_delivery extends erpapi_wms_request_delive
protected function isUrgentDelivery($sdf)
{
$labelLib = kernel::single('ome_bill_label');
if (!empty($sdf['delivery_id']) && $labelLib->existLabel($sdf['delivery_id'], self::URGENT_LABEL_CODE, 'delivery')) {
if (!empty($sdf['delivery_id']) && $labelLib->existLabel($sdf['delivery_id'], 'SOMS_URGENT_SHIP', 'ome_delivery')) {
return true;
}
if (!empty($sdf['order_id']) && $labelLib->existLabel($sdf['order_id'], self::URGENT_LABEL_CODE)) {
if (!empty($sdf['order_id']) && $labelLib->existLabel($sdf['order_id'], 'SOMS_URGENT_SHIP')) {
return true;
}
if (!empty($sdf['order_bn'])) {
$order = app::get('ome')->model('orders')->dump(['order_bn' => $sdf['order_bn']], 'order_id');
if (!empty($order['order_id']) && $labelLib->existLabel($order['order_id'], self::URGENT_LABEL_CODE)) {
if (!empty($order['order_id']) && $labelLib->existLabel($order['order_id'], 'SOMS_URGENT_SHIP')) {
return true;
}
}

View File

@@ -365,6 +365,27 @@ class inventorydepth_ctl_shop_adjustment extends desktop_controller {
// 获取商品条码
// $barcode = kernel::single('material_codebase')->getBarcodeBySmbn($sku['shop_product_bn'], $sku['shop_id'], 1);
// 唯品会单个商品发布库存,需要走队列的方式
//@todo唯品会按照区域仓的方式进行回写库存;
if(in_array($sku['shop_type'], ['vop'])){
$res = [];
// shop_id
$shop_id = $sku['shop_id'];
$shopIds = [$shop_id];
// 获取销售物料
$field = 'sm_id,sales_material_name,sales_material_bn,sales_material_type,shop_id,class_id';
$filter = array('sales_material_bn'=>$sku['shop_product_bn']);
$products = app::get('material')->model('sales_material')->getList($field, $filter, 0, -1);
// request
kernel::single('inventorydepth_logic_stock')->do_sync_products_stock($products, $shopIds);
$this->end(true,$this->app->_('单个商品发布中'), null, $res);
}
// stock
$memo = array('last_modified'=>time());
$stocks[$sku['id']] = array(
'bn' => $sku['shop_product_bn'],
@@ -526,6 +547,9 @@ class inventorydepth_ctl_shop_adjustment extends desktop_controller {
for ($i=$total; $i>=0 ; $i--) {
$params['offset'] = $i*$limit;
# 插入队列
kernel::single('inventorydepth_queue')->insert_stock_update_queue($title,$params);
}

View File

@@ -47,10 +47,11 @@ class inventorydepth_ctl_sync_set extends desktop_controller {
$setData = array();
$setData['stock_sync_set'] = app::get('inventorydepth')->getConf('stock.sync.set');
$setData['stock_sync_mode'] = app::get('inventorydepth')->getConf('stock.sync.mode');
$setData['stock_sync_trigger_basis'] = kernel::single('inventorydepth_sync_set')->getStockTriggerBasis();
$this->pagedata['setData'] = $setData;
$this->pagedata['support_name'] = kernel::single('inventorydepth_sync_set')->getSupportName();
$this->pagedata['mode_support_name'] = kernel::single('inventorydepth_sync_set')->getModeSupportName();
$this->page("sync/setting.html");
}
}
}

View File

@@ -1016,11 +1016,28 @@ class inventorydepth_logic_stock extends inventorydepth_logic_abstract
// 判断是否为唯品会省仓,如果是省仓,找到省仓对应关系
// $shop = [shop_id,shop_bn,node_type,business_type]
// bn
$bnList = array_column($stocks, 'bn');
// 查询销售物料类型
$salesMaterialObj = app::get('material')->model('sales_material');
$smList = $salesMaterialObj->getList('sm_id,sales_material_bn,sales_material_type', array('sales_material_bn'=>$bnList));
$smList = array_column($smList, null, 'sales_material_bn');
// 获取商品条码
$materialCodeLib = kernel::single('material_codebase');
foreach ($stocks as $_k => $_v) {
$barcode = $materialCodeLib->getBarcodeBySmbn($_v['bn'], $shop['shop_id']);
foreach ($stocks as $_k => $_v)
{
$temp_bn = $_v['bn'];
// 销售物料类型是组合barcode条形码直接使用销售物料编码
if(isset($smList[$temp_bn]) && $smList[$temp_bn]['sales_material_type'] == '2'){
$barcode = $temp_bn;
}else{
$barcode = $materialCodeLib->getBarcodeBySmbn($_v['bn'], $shop['shop_id']);
}
$stocks[$_k]['barcode']= $barcode; // 回传匹配店铺资源的商品用barcode去匹配
}
@@ -1082,6 +1099,8 @@ class inventorydepth_logic_stock extends inventorydepth_logic_abstract
public function eliminateSameNumber($stocks, $shop, $sales_bn_list) {
$stockApi = [];
$stockApiModel = app::get('ome')->model('api_stock_log');
$triggerBasis = kernel::single('inventorydepth_sync_set')->getStockTriggerBasis();
$currentStockField = ($triggerBasis == 'store') ? 'quantity' : 'actual_stock';
foreach ($stockApiModel->getList('shop_id,product_bn,store,actual_stock,msg,last_modified,status,shop_sku_id',array('product_bn'=>$sales_bn_list, 'shop_id'=>$shop['shop_id'])) as $value) {
// $index = $value['shop_id'] . "-" .$value['product_bn'] . "-" . $value['shop_sku_id'];
$index = $value['shop_id'] . "-" .$value['product_bn'];
@@ -1093,8 +1112,11 @@ class inventorydepth_logic_stock extends inventorydepth_logic_abstract
continue;
}
$stockapi_code = $shop['shop_id'] . "-" . $st['bn'];
if(isset($stockApi[$stockapi_code]['actual_stock'])
&& $stockApi[$stockapi_code]['actual_stock'] == $st['actual_stock']
// 默认沿用历史逻辑比较可售库存;选择“回写库存”时,使用本次规则计算结果
// quantity 对比 api_stock_log.store。其余成功状态、常量规则和强制回写条件保持不变。
if(isset($stockApi[$stockapi_code][$triggerBasis])
&& isset($st[$currentStockField])
&& $stockApi[$stockapi_code][$triggerBasis] == $st[$currentStockField]
&& $stockApi[$stockapi_code]['status'] == 'success'
&& (
#如果规则为常量,则没有规则说明,需发起请求

View File

@@ -20,7 +20,6 @@
*/
class inventorydepth_service_shop_vop extends inventorydepth_service_shop_common
{
//定义每页拉取数据(平台限制每页最多200条)
public $customLimit = 50;
@@ -86,29 +85,36 @@ class inventorydepth_service_shop_vop extends inventorydepth_service_shop_common
'approve_status' => $v['selling_status'] == '1' ? 'onsale' : 'instock', //上下架
];
}
// 获取sku信息
$spuList[$v['sn']]['skus'][$v['barcode']] = [
'sku_id' => $v['barcode'],
'outer_id' => $v['oms_sm_bn']?$v['oms_sm_bn']:$v['sn'], //sku货号
'outer_id' => $v['barcode'], //sku货号使用平台barcode条形码作为销售物料编码
'sku_wid' => $v['barcode'],
'title' => $v['product_name'], //货品名称
];
}
foreach ($spuList as $spuBn => $spuInfo) {
$iid = $spuBn;
$skuList = [];
foreach ($spuInfo['skus'] as $key => $val) {
$skuList['sku'][] = $val;
}
// data
$data[] = array(
'outer_id' => $spuBn, //spu商品编号
'iid' => $spuBn,
'iid' => $iid,
'title' => $spuInfo['title'],
'approve_status' => $spuInfo['approve_status'],
'simple' => 'false',
'skus' => $skuList,
);
}
//销毁
unset($result, $skuList);
@@ -144,14 +150,20 @@ class inventorydepth_service_shop_vop extends inventorydepth_service_shop_common
return false;
}
// 根据barcode获取普通商品的sm_bn
/**
* 根据barcode获取普通商品的sm_bn
*
* @param $barcodeList
* @return array
*/
public function barcodeToSmbn($barcodeList)
{
$codeList = $bmIds = $smIds = $smList = [];
$basicMaterialBarcode = kernel::single('material_basic_material_barcode');
$bmIds = $basicMaterialBarcode->getBmidListByFilter(['code|in'=>$barcodeList], $codeList);
// 获取销售物料ID
if ($bmIds) {
$smIds = app::get('material')->model('sales_basic_material')->getList("bm_id,sm_id",array("bm_id|in"=>$bmIds), 0, -1);
}
@@ -188,6 +200,7 @@ class inventorydepth_service_shop_vop extends inventorydepth_service_shop_common
}
}
}
return $barcodeVsSmbn;
}
}

View File

@@ -240,8 +240,11 @@ class inventorydepth_shop_vop
}else{
$skuStocks[$barcode]['leaving_stock'] += $val['leaving_stock']; //剩余库存
$skuStocks[$barcode]['current_hold'] += $val['current_hold']; //库存占用
$skuStocks[$barcode]['circuit_break_value'] += $val['circuit_break_value']; //熔断值
//$skuStocks[$barcode]['circuit_break_value'] += $val['circuit_break_value']; //熔断值
$skuStocks[$barcode]['unpaid_hold'] += $val['unpaid_hold']; //未支付占用数
// 熔断值(现在多个条形码时,不进行累加熔断值)
$skuStocks[$barcode]['circuit_break_value'] = $val['circuit_break_value']; //熔断值
}
}

View File

@@ -43,6 +43,25 @@ class inventorydepth_sync_set {
return implode(',', $this->mode_support);
}
/**
* 获取库存回写触发依据。
*
* 历史版本固定使用可售库存判断是否需要回写。为保证未初始化配置的站点
* 升级后行为不变,仅当配置明确选择 store 时才改用回写库存比较。
*
* @return string actual_stock可售库存store回写库存
*/
public function getStockTriggerBasis()
{
$triggerBasis = app::get('inventorydepth')->getConf('stock.sync.trigger_basis');
if ($triggerBasis === 'store') {
return 'store';
}
return 'actual_stock';
}
// 是否开启并支持增量库存回写
public function isModeSupportInc($shop_type = '')
{
@@ -86,4 +105,4 @@ class inventorydepth_sync_set {
return (app::get('inventorydepth')->getConf('stock.sync.set') == 'skuid'
&& in_array($shop['node_type'], array_keys($this->support)));
}
}
}

View File

@@ -35,6 +35,14 @@
&nbsp;&nbsp;<span style="color:red;">* 选择增量库存的时候,会对比上一次库存进行加减。(增量仅支持<{$mode_support_name}></span>
</td>
</tr>
<tr>
<th>库存回写触发依据</th>
<td>
<input type="radio" name="set[stock.sync.trigger_basis]" value="actual_stock" <{if $setData.stock_sync_trigger_basis != 'store'}> checked<{/if}>>可售库存
<input type="radio" name="set[stock.sync.trigger_basis]" value="store" <{if $setData.stock_sync_trigger_basis == 'store'}> checked<{/if}>>回写库存
&nbsp;&nbsp;<span style="color:red;">* 可售库存为系统计算出的可售数量;回写库存为上一次成功同步给平台的库存数量。选择后将以对应库存发生变化才会触发回写。</span>
</td>
</tr>
</tbody>
</table>
</div>
@@ -43,4 +51,4 @@
<{button label="提交" type="submit" name="submit" id="btn-setting"}>
</div>
</div>
</form>
</form>

View File

@@ -14,22 +14,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class logisticsmanager_waybill_douyin
{
/**
* 打印组件三个接口
* 获取打印数据 /logistics/waybillApply
* 获取标准模板 /logistics/templateList
* 获取自定义模板 /logistics/customTemplateList
* @return array [description]
*/
/**
* 打印组件三个接口
* 获取打印数据 /logistics/waybillApply
* 获取标准模板 /logistics/templateList
* 获取自定义模板 /logistics/customTemplateList
* @return array [description]
*/
public function template_cfg() {
$arr = array(
'template_name' => '抖音',
'shop_name' => '抖音',
'print_url' => 'https://logistics.douyinec.com/davinci/CloudPrintClient',
'template_url' => 'https://cloudprint.douyinec.com/login',
'template_url' => 'https://cloudprint.douyinec.com/?param1=CgYIASAHKAESTgpMI2MYBqPNBgyE%2FiGN2D8SFv6YL%2BnGgX%2BgkMVpzFY%2FXKIyqYpdJv4161%2BRJw%2BI%2FipYYPDDwi83BRzqrZYxg3PmKXyGIOR20DRRi%2BJatBoA&param2=CgYIASAHKAESLgosG5aEgKc%2B8xwujPWKNjwnV1glTC0a36jI493ehdRA6iw%2BmlatQUKcD9cqyvoaAA%3D%3D',
'shop_type' => 'luban',
'control_type' => 'douyin',
'request_again' => true
@@ -92,11 +91,6 @@ class logisticsmanager_waybill_douyin
return $logistics;
}
/**
* service_code
* @param mixed $param param
* @return mixed 返回值
*/
public function service_code($param)
{
$cpCode = $param['logistics'];

View File

@@ -15,7 +15,6 @@
* limitations under the License.
*/
class ome_ctl_admin_delivery extends desktop_controller{
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
var $name = "发货单";
var $workground = "console_center";
@@ -30,7 +29,7 @@ class ome_ctl_admin_delivery extends desktop_controller{
);
$sub_menu = array(
0 => array('label' => app::get('base')->_('全部'), 'filter' => $baseFilter, 'optional' => false),
1 => array('label' => app::get('base')->_('加急发货'), 'filter' => array_merge($baseFilter, array('delivery_label_code' => self::URGENT_LABEL_CODE)), 'optional' => false),
1 => array('label' => app::get('base')->_('加急发货'), 'filter' => array_merge($baseFilter, array('delivery_label_code' => 'SOMS_URGENT_SHIP')), 'optional' => false),
);
foreach ($sub_menu as $k => $v) {
$sub_menu[$k]['filter'] = $v['filter'];

View File

@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ome_ctl_admin_goods_editor extends desktop_controller{
//var $workground = 'goods_manager';
var $simpleGoodsId = 1;
@@ -141,7 +140,10 @@ class ome_ctl_admin_goods_editor extends desktop_controller{
);
}
if( $goods['spec'] ){
$goods['spec'] = unserialize($goods['spec']);
$goods['spec'] = $this->_parse_serialized_array($goods['spec'], null);
if( !is_array($goods['spec']) ){
$goods['spec'] = null;
}
}else{
$goods['spec'] = null;
}
@@ -532,8 +534,19 @@ class ome_ctl_admin_goods_editor extends desktop_controller{
$this->pagedata['goods_spec'] = $spec;
}
private function _parse_serialized_array($data, $default = array()){
if( is_array($data) ){
return $data;
}
if( !is_string($data) || $data === '' ){
return $default;
}
$parsed = @unserialize($data, array('allowed_classes' => false));
return is_array($parsed) ? $parsed : $default;
}
function set_spec($typeId=0){
$_POST['spec'] = unserialize($_POST['spec']);
$_POST['spec'] = $this->_parse_serialized_array(isset($_POST['spec']) ? $_POST['spec'] : '');
if( $_POST['spec'] ){
$this->_set_spec($_POST['spec']);
}else{
@@ -674,7 +687,7 @@ class ome_ctl_admin_goods_editor extends desktop_controller{
$oType = app::get('ome')->model('goods_type');
$oBrand = app::get('ome')->model('brand');
$goodslog = $logObj->dump($log_id,'memo');
$memo = unserialize($goodslog['memo']);
$memo = $this->_parse_serialized_array($goodslog['memo']);
$cat = $oCat->dump($memo['category']['cat_id'],'cat_name');
$memo['cat_name'] = $cat['cat_name'];
$type = $oType->dump($memo['type']['type_id'],'name');

View File

@@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ome_ctl_admin_order extends desktop_controller{
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
var $name = "订单中心";
var $workground = "order_center";
var $order_type = 'all';
@@ -119,7 +116,7 @@ class ome_ctl_admin_order extends desktop_controller{
7 => array('label'=>app::get('base')->_('已发货'),'filter'=>array('ship_status' =>'1','status' => 'active'),'optional'=>false),
8 => array('label'=>app::get('base')->_('取消'),'filter'=>array('process_status' => 'cancel'),'optional'=>false),
9 => array('label'=>app::get('base')->_('暂停'),'filter'=>array('pause' => 'true'),'optional'=>false),
10 => array('label'=>app::get('base')->_('加急发货'),'filter'=>array('order_label_code' => self::URGENT_LABEL_CODE),'optional'=>false),
10 => array('label'=>app::get('base')->_('加急发货'),'filter'=>array('order_label_code' => 'SOMS_URGENT_SHIP'),'optional'=>false),
);
$i=0;
foreach($sub_menu as $k=>$v){
@@ -2700,6 +2697,18 @@ class ome_ctl_admin_order extends desktop_controller{
$orderListTmp[$orderId]['oldOrder'] = $oldOrder;
$orderListTmp[$orderId]['orderExt'] = $orderExt;
// 拼多多消费者付费送货上门订单限制五家承运商;
// 自有仓还必须使用对应承运商的拼多多电子面单。
$homeDeliveryError = '';
if (!kernel::single('ome_order_platform_pinduoduo_chargehomedelivery')->validate(
$oldOrder,
$temp_branch,
$corpInfo,
$homeDeliveryError
)) {
$this->end(false, $homeDeliveryError);
}
if ($oldOrder['shop_type'] == 'dewu' && kernel::single('ome_order_bool_type')->isDWBrand($oldOrder['order_bool_type'])) {
// 由于没有实际单据测试,所以审单的时候拦截,暂不支持多仓
if ($orderExt['extend_field']['performance_type'] == '3'){
@@ -3184,6 +3193,30 @@ class ome_ctl_admin_order extends desktop_controller{
}
}
}
// 兼容旧版单笔拆单入口:底层 addDelivery 仍会兜底校验,
// 此处提前返回明确错误,避免旧代码忽略 addDelivery 失败结果后仍提示操作完成。
$homeDeliveryOrder = $oOrder->dump($_POST['order_id'], 'order_id,order_bn,shop_type');
foreach ((array)$new_delivery as $homeDelivery) {
$homeDeliveryBranch = $this->app->model('branch')->db_dump(
['branch_id' => $homeDelivery['branch_id'], 'check_permission' => false],
'branch_id,wms_id'
);
$homeDeliveryCorp = $this->app->model('dly_corp')->db_dump(
['corp_id' => $homeDelivery['logi_id']],
'corp_id,name,type,tmpl_type,channel_id'
);
$homeDeliveryError = '';
if (!kernel::single('ome_order_platform_pinduoduo_chargehomedelivery')->validate(
$homeDeliveryOrder,
$homeDeliveryBranch,
$homeDeliveryCorp,
$homeDeliveryError
)) {
$this->end(false, $homeDeliveryError);
}
}
//订单拆分,产生发货单
$oOrder->mkDelivery($_POST['order_id'],$new_delivery);
$item_list = $oOrder->getItemBranchStore($_POST['order_id']);
@@ -6254,7 +6287,7 @@ class ome_ctl_admin_order extends desktop_controller{
}
//统计批量支付订单数量
$this->pagedata['order_ids'] = serialize($order_info['order_id']);
$this->pagedata['order_ids'] = json_encode($order_info['order_id']);
$this->display('admin/order/batch_update_declare.html');
}
@@ -6268,7 +6301,14 @@ class ome_ctl_admin_order extends desktop_controller{
$order_ids = array();
if(!empty($_POST['order_ids']))
{
$order_ids = unserialize($_POST['order_ids']);
if (is_array($_POST['order_ids'])) {
$order_ids = $_POST['order_ids'];
} elseif (is_string($_POST['order_ids'])) {
$order_ids = json_decode($_POST['order_ids'], true);
if (!is_array($order_ids)) {
$order_ids = array();
}
}
}
if(empty($order_ids))
{

View File

@@ -14,8 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
+----------------------------------------------------------
* 订单复审&财审
+----------------------------------------------------------
*
* Time: 2014-04-30 $
* [Ecos!] (C)2003-2014 Shopex Inc.
+----------------------------------------------------------
*/
class ome_ctl_admin_order_retrial extends desktop_controller
{
var $order_type = 'index';
@@ -25,13 +32,14 @@ class ome_ctl_admin_order_retrial extends desktop_controller
/*------------------------------------------------------ */
function index()
{
$op_id = kernel::single('desktop_user')->get_id();
$this->title = '商品变化订单';
$base_filter['retrial_type'] = 'normal';
//check shop permission
$organization_permissions = kernel::single('desktop_user')->get_organization_permission();
if($organization_permissions){
$base_filter['org_id'] = $organization_permissions;
$base_filter['permission_org_id'] = $organization_permissions;
}
$params =
@@ -44,6 +52,7 @@ class ome_ctl_admin_order_retrial extends desktop_controller
'allow_detail_popup'=>true,
'use_buildin_recycle'=>false,
'use_view_tab'=>true,
'finder_aliasname' => 'order_retrial_normal'.$op_id,
'base_filter' => $base_filter,
);
@@ -62,7 +71,7 @@ class ome_ctl_admin_order_retrial extends desktop_controller
//check shop permission
$organization_permissions = kernel::single('desktop_user')->get_organization_permission();
if($organization_permissions){
$base_filter['org_id'] = $organization_permissions;
$base_filter['permission_org_id'] = $organization_permissions;
}
$params =
@@ -85,18 +94,19 @@ class ome_ctl_admin_order_retrial extends desktop_controller
/*------------------------------------------------------ */
function success()
{
$op_id = kernel::single('desktop_user')->get_id();
$this->title = '已复审订单';
$this->order_type = 'success';
if(empty($_GET['view']))
{
$base_filter['status'] = array('1', '2', '3');
$base_filter['status'] = array('1', '2', '3', '4');
}
//check shop permission
$organization_permissions = kernel::single('desktop_user')->get_organization_permission();
if($organization_permissions){
$base_filter['org_id'] = $organization_permissions;
$base_filter['permission_org_id'] = $organization_permissions;
}
$this->finder('ome_mdl_order_retrial',
@@ -109,6 +119,7 @@ class ome_ctl_admin_order_retrial extends desktop_controller
'allow_detail_popup'=>true,
'use_buildin_recycle'=>false,
'use_view_tab'=>true,
'finder_aliasname' => 'order_retrial_success'.$op_id,
'base_filter' => $base_filter,
));
}
@@ -143,7 +154,7 @@ class ome_ctl_admin_order_retrial extends desktop_controller
foreach($sub_menu as $k => $v)
{
if($organization_permissions){
$v['filter']['org_id'] = $organization_permissions;
$v['filter']['permission_org_id'] = $organization_permissions;
}
$sub_menu[$k]['filter'] = $v['filter']?$v['filter']:null;
@@ -176,9 +187,10 @@ class ome_ctl_admin_order_retrial extends desktop_controller
function _views_success()
{
$sub_menu = array(
0 => array('label'=>app::get('base')->_('全部'), 'filter'=>array('status'=>array('1', '2')), 'optional'=>false),
0 => array('label'=>app::get('base')->_('全部'), 'filter'=>array('status'=>array('1', '2', '3', '4')), 'optional'=>false),
1 => array('label'=>app::get('base')->_('复审通过'), 'filter'=>array('status'=>'1'), 'optional'=>false),
2 => array('label'=>app::get('base')->_('复审未通过'), 'filter'=>array('status'=>array('2', '3')), 'optional'=>false),
3 => array('label'=>app::get('base')->_('订单已取消'), 'filter'=>array('status'=>'4'), 'optional'=>false),
);
return $sub_menu;
}
@@ -498,4 +510,4 @@ class ome_ctl_admin_order_retrial extends desktop_controller
$this->pagedata['operation_detail'] = $detail;
$this->singlepage('admin/order/retrial_show_operation.html');
}
}
}

View File

@@ -15,13 +15,12 @@
* limitations under the License.
*/
/*
* 单据打印
*/
class ome_ctl_admin_receipts_print extends desktop_controller {
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
var $name = "发货中心";
var $workground = "delivery_center";
var $dlyCorp_tab = 'show';
@@ -100,7 +99,7 @@ class ome_ctl_admin_receipts_print extends desktop_controller {
);
$sub_menu[$c++] = array(
'label' => app::get('base')->_('加急发货'),
'filter' => array_merge($tmp_filter, array('delivery_label_code' => self::URGENT_LABEL_CODE)),
'filter' => array_merge($tmp_filter, array('delivery_label_code' => 'SOMS_URGENT_SHIP')),
'optional' => false
);
#第三方发货时,显示已发货、未发货

View File

@@ -1686,6 +1686,12 @@ class ome_ctl_admin_return_rchange extends desktop_controller
}
}
// 切换换货仓库时页面会一次提交全部已选销售物料并直接读取JSON
// 复用新增销售物料的库存计算逻辑,确保普通、组合、福袋和多选一口径一致。
if($_GET['response_type'] == 'json'){
echo json_encode($rows);exit;
}
echo "window.autocompleter_json=".json_encode($rows);exit;
}
//获取展示销售物料信息

View File

@@ -225,7 +225,7 @@ $db['api_stock_log']=array (
),
'store' =>
array (
'label' => '库存',
'label' => '回写库存',
'type' => 'number',
'width' => 80,
'editable' => false,
@@ -238,7 +238,7 @@ $db['api_stock_log']=array (
),
'actual_stock' =>
array (
'label' => '可售库存',
'label' => '可售库存',
'type' => 'number',
'width' => 80,
'editable' => false,

View File

@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
$db['order_retrial']=array (
'columns' =>
array (
@@ -78,6 +77,7 @@ $db['order_retrial']=array (
1=>'复审通过',
2=>'复审未通过',
3=>'恢复原订单',
4=>'订单已取消',
),
'default' => '0',
'required' => true,
@@ -151,4 +151,4 @@ $db['order_retrial']=array (
'comment' => '复审订单表',
'engine' => 'innodb',
'version' => '$Rev: 44513 $',
);
);

View File

@@ -358,6 +358,13 @@ $db['refund_apply'] = array(
'in_list' => true,
),
'platform_discount_return_amount' => array(
'type' => 'money',
'default' => '0',
'label' => '平台优惠退回金额',
'comment' => '平台优惠退回金额(元)',
'editable' => false,
),
'order_source' => array (
'type' => 'varchar(50)',
'label' => '来源渠道',

View File

@@ -229,6 +229,20 @@ class ome_batch_order{
$isMkDly = false; continue;
}
// 与单笔和自动审单共用同一套拼多多消费者付费送货上门物流校验。
// corp_id=auto 时在自动物流插件选出实际物流后再次校验。
$homeDeliveryError = '';
if (!kernel::single('ome_order_platform_pinduoduo_chargehomedelivery')->validate(
$order,
$branch,
$corp,
$homeDeliveryError
)) {
$retArr['err_msg'][] = '['.$order['order_bn'].']'.$homeDeliveryError;
$is_combine || $retArr['ifail']++;
$isMkDly = false; continue;
}
// 如果是得物品牌直发,判断是否合规
if ($order['shop_type'] == 'dewu' && kernel::single('ome_order_bool_type')->isDWBrand($order['order_bool_type'])) {

View File

@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 单据标签管理Lib类
*
@@ -50,6 +49,7 @@ class ome_bill_label
// 系统内部的请用SOMS_为开头
'SOMS_WFP' => ['label_name' => '晚发赔', 'label_color' => 'Green'],
'SOMS_SHSM' => ['label_name' => '送货上门', 'label_color' => 'Chocolate', 'label_thumb'=>'送'],
'SOMS_ZFSHSM' => ['label_name' => '自费送货上门', 'label_color' => 'Chocolate', 'label_thumb'=>'自费送', 'label_to_delivery' => true, 'extend_info_to_delivery' => true],
'SOMS_IMEI' => ['label_name' => '发货必传IMEI码', 'label_color' => 'Gold', 'label_to_delivery' => true],
'SOMS_SERIALNUMBER' => ['label_name' => '发货必传SN码', 'label_color' => 'Gold', 'label_to_delivery' => true],
'SOMS_EXPRESS_MUST' => ['label_name' => '自选快递', 'label_color' => 'CornflowerBlue'],
@@ -312,10 +312,10 @@ class ome_bill_label
'label_desc' => $labelInfo['label_desc'],
);
$billLabelMdl = app::get('ome')->model('bill_label');
$isCheck = $billLabelMdl->db_dump(['bill_type' => $bill_type, 'bill_id' => $bill_id, 'label_id' => $labelInfo['label_id']], 'id,label_value');
$isCheck = $billLabelMdl->db_dump(['bill_type' => $bill_type, 'bill_id' => $bill_id, 'label_id' => $labelInfo['label_id']], 'id,label_value,extend_info');
if (!$isCheck) {
$billLabelMdl->insert($saveData);
} elseif ($isCheck['label_value'] != $label_value) {
} elseif ($isCheck['label_value'] != $label_value || (string)$isCheck['extend_info'] !== (string)$extend_info) {
$billLabelMdl->update($saveData, ['id' => $isCheck['id']]);
}
@@ -346,9 +346,21 @@ class ome_bill_label
$labelMdl = app::get('omeauto')->model('order_labels');
$res = $labelMdl->db_dump($filter);
if ($res) {
/***
$labelInfo['label_id'] = $res['label_id'];
unset($labelInfo['create_time']);
$labelMdl->update($labelInfo, $filter);
***/
// unset
unset($labelInfo['create_time']);
// 按主键更新,且不把 label_id 放入 SET避免同 label_code 多行时 UPDATE 主键冲突
// Duplicate entry 'N' for key 'PRIMARY'
$labelMdl->update($labelInfo, ['label_id' => $res['label_id']]);
// label_id
$labelInfo['label_id'] = $res['label_id'];
} else {
$labelMdl->insert($labelInfo);
}
@@ -523,7 +535,12 @@ class ome_bill_label
$labelOrder = $this->getLabelFromOrder($orderId, 'order');
foreach ($labelOrder as $k => $label) {
if($this->orderLabelsPreset[$label['label_code']]['label_to_delivery']) {
$this->markBillLabel($deliveryId, '', $label['label_code'], $bill_type, $err, $label['label_value'], $extend_info);
$labelExtendInfo = $extend_info;
if ($this->orderLabelsPreset[$label['label_code']]['extend_info_to_delivery']) {
$orderLabelInfo = $this->getBillLabelInfo($orderId, 'order', $label['label_code']);
$labelExtendInfo = $orderLabelInfo['extend_info'] ?? '';
}
$this->markBillLabel($deliveryId, '', $label['label_code'], $bill_type, $err, $label['label_value'], $labelExtendInfo);
}
}
}

View File

@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 订单请求
*
@@ -25,8 +24,6 @@
*/
class ome_event_trigger_shop_order
{
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
/**
* 淘宝全链路
*
@@ -123,7 +120,7 @@ class ome_event_trigger_shop_order
if (!in_array($order['shop_type'], ['taobao', 'tmall'])) {
continue;
}
if (!$labelLib->existLabel($order['order_id'], self::URGENT_LABEL_CODE)) {
if (!$labelLib->existLabel($order['order_id'], 'SOMS_URGENT_SHIP')) {
continue;
}
@@ -131,9 +128,6 @@ class ome_event_trigger_shop_order
if (empty($statusPayload['orderStatus'])) {
continue;
}
if (in_array($statusPayload['orderStatus'], ['SHIPPED', 'CANCELLED']) && $this->isUrgentTerminalReported($order['order_id'], $statusPayload['orderStatus'])) {
continue;
}
$sdf = [
'tid' => $order['order_bn'],
@@ -154,21 +148,6 @@ class ome_event_trigger_shop_order
}
}
/**
* 通过操作日志判断终态回告是否已经成功落库,避免重复回告。
*
* @param int $orderId
* @param string $status
* @return bool
*/
protected function isUrgentTerminalReported($orderId, $status)
{
$pattern = '淘宝加急发货状态回告终态:' . $status;
$sql = "SELECT log_id FROM sdb_ome_operation_log WHERE obj_id=" . intval($orderId) . " AND obj_type='order_modify@ome' AND memo LIKE '%" . addslashes($pattern) . "%' LIMIT 1";
$rows = kernel::database()->select($sql);
return !empty($rows);
}
public function received($orderId) {
$order = app::get('ome')->model('orders')->db_dump($orderId, 'shop_id, order_bn');
if(empty($order)) {

View File

@@ -0,0 +1,149 @@
<?php
/**
* 复审订单高级筛选扩展
*
* 商品变化订单和已复审订单沿用历史订单列表的筛选控件样式,方便用户保持
* 一致的操作习惯。店铺和运营组织选项同时按当前账号的组织权限裁剪,避免
* 筛选选项暴露权限范围外的数据。
*/
class ome_finder_extend_filter_order_retrial
{
public function get_extend_colums($finder_aliasname=null)
{
$finder_aliasname = (string) $finder_aliasname;
if(strpos($finder_aliasname, 'order_retrial_normal') !== 0
&& strpos($finder_aliasname, 'order_retrial_success') !== 0)
{
return array();
}
$organization_permissions = kernel::single('desktop_user')->get_organization_permission();
$shop_filter = array();
if($organization_permissions)
{
$shop_filter['user_org_id'] = $organization_permissions;
}
$shop_list = app::get('ome')->model('shop')->getList('shop_id,name', $shop_filter, 0, -1, 'name ASC');
$shop_options = array_column((array) $shop_list, 'name', 'shop_id');
$org_filter = array();
if($organization_permissions)
{
$org_filter['org_id'] = $organization_permissions;
}
$org_list = app::get('ome')->model('operation_organization')->getList('org_id,name', $org_filter, 0, -1, 'name ASC');
$org_options = array_column((array) $org_list, 'name', 'org_id');
$db['order_retrial']['columns'] = array(
'shop_id' => array(
'type' => $shop_options,
'label' => '来源店铺',
'width' => 100,
'filtertype' => 'fuzzy_search_multiple',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
'org_id' => array(
'type' => $org_options,
'label' => '运营组织',
'width' => 60,
'filtertype' => 'normal',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
'product_bn' => array(
'type' => 'varchar(30)',
'label' => '基础物料编码',
'width' => 85,
'filtertype' => 'textarea',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
'sales_material_bn' => array(
'type' => 'varchar(30)',
'label' => '销售物料编码',
'width' => 85,
'filtertype' => 'textarea',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
'sales_material_name' => array(
'type' => 'varchar(200)',
'label' => '销售物料名称',
'width' => 120,
'filtertype' => 'textarea',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
'createtime' => array(
'type' => 'time',
'label' => '下单时间',
'width' => 160,
'filtertype' => 'time',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
'pay_status' => array(
'type' => array(
0 => '未支付',
1 => '已支付',
2 => '处理中',
3 => '部分付款',
4 => '部分退款',
5 => '全额退款',
6 => '退款申请中',
7 => '退款中',
8 => '支付中',
),
'label' => '付款状态',
'width' => 75,
'filtertype' => 'yes',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
'ship_status' => array(
'type' => array(
0 => '未发货',
1 => '已发货',
2 => '部分发货',
3 => '部分退货',
4 => '已退货',
),
'label' => '发货状态',
'width' => 75,
'filtertype' => 'yes',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
'process_status' => array(
'type' => array(
'unconfirmed' => '未确认',
'confirmed' => '已确认',
'splitting' => '部分拆分',
'splited' => '已拆分完',
'cancel' => '取消',
'remain_cancel' => '余单撤销',
'is_retrial' => '复审订单',
'is_declare' => '跨境申报订单',
),
'label' => '确认状态',
'width' => 70,
'filtertype' => 'yes',
'filterdefault' => true,
'editable' => false,
'in_list' => false,
),
);
return $db;
}
}

View File

@@ -14,8 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
+----------------------------------------------------------
* 复审订单列表
+----------------------------------------------------------
*
* Time: 2014-04-22 $
* [Ecos!] (C)2003-2014 Shopex Inc.
+----------------------------------------------------------
*/
class ome_finder_order_retrial
{
/*------------------------------------------------------ */
@@ -29,7 +36,11 @@ class ome_finder_order_retrial
$str = '<a href="index.php?app=ome&ctl=admin_order_retrial&act=normal&id='.$row['id'].'&p[0]='.$row['id'].'&finder_id='.$_GET['_finder']['finder_id'].'"
target="_blank">复审</a>';
if($row['status'] == '1' || $row['status'] == '2' || $row['status'] == '3')
if($row['status'] == '4')
{
$str = '已取消';
}
elseif($row['status'] == '1' || $row['status'] == '2' || $row['status'] == '3')
{
$str = '已审核';
}
@@ -352,4 +363,4 @@ class ome_finder_order_retrial
return $this->__shopList[$shop_id] ?: [];
}
}
}

View File

@@ -0,0 +1,188 @@
<?php
/**
* 拼多多消费者付费送货上门审单物流校验
*
* 仅处理带 SOMS_ZFSHSM 标签的拼多多订单。所有仓库校验承运商白名单,
* OMS 自有仓额外校验物流公司使用启用中的拼多多电子面单;第三方 WMS
* 不校验电子面单来源,避免依赖第三方在 OMS 中不存在的面单配置。
*/
class ome_order_platform_pinduoduo_chargehomedelivery
{
const LABEL_CODE = 'SOMS_ZFSHSM';
private $allowedCorpTypes = ['ZTO', 'YTO', 'STO', 'jitu', 'YUNDA'];
private $pddLogisticsCodeMap = [
'ZTO' => 'ZTO',
'YTO' => 'YTO',
'STO' => 'STO',
'jitu' => 'JTSD',
'YUNDA' => 'YUNDA',
];
/**
* 校验审单所选物流公司
*
* @param array $order
* @param array|int $branch
* @param array $corp
* @param string $errorMsg
* @return bool
*/
public function validate($order, $branch, $corp, &$errorMsg = '')
{
if (strtolower($order['shop_type']) != 'pinduoduo' || empty($order['order_id'])) {
return true;
}
$labelInfo = kernel::single('ome_bill_label')->getBillLabelInfo(
$order['order_id'],
'order',
self::LABEL_CODE
);
if (!$labelInfo) {
return true;
}
// “自动匹配物流”需要等自动审单插件选出实际物流后再校验。
if (isset($corp['corp_id']) && $corp['corp_id'] === 'auto') {
return true;
}
$corp = $this->completeCorpInfo($corp);
if (empty($corp['corp_id']) || empty($corp['type'])) {
$errorMsg = '拼多多消费者付费送货上门订单未选择有效物流公司';
return false;
}
$whiteDeliveryCps = $this->getWhiteDeliveryCps($order['order_id']);
if (!$whiteDeliveryCps) {
$errorMsg = '订单物流服务要求存在冲突,没有同时满足条件的物流公司,请人工处理';
return false;
}
if (!in_array($corp['type'], $whiteDeliveryCps, true)
|| !in_array($corp['type'], $this->allowedCorpTypes, true)) {
$errorMsg = '拼多多消费者付费送货上门订单只能使用中通、圆通、申通、极兔或韵达发货';
return false;
}
if (!$this->isSelfWms($branch)) {
return true;
}
if ($corp['tmpl_type'] != 'electron' || empty($corp['channel_id'])) {
$errorMsg = '拼多多消费者付费送货上门订单,自有仓发货必须使用拼多多电子面单';
return false;
}
$channel = app::get('logisticsmanager')->model('channel')->db_dump([
'channel_id' => $corp['channel_id'],
'status' => 'true',
], 'channel_id,channel_type,logistics_code,status');
$expectedLogisticsCode = $this->pddLogisticsCodeMap[$corp['type']] ?? '';
if (!$channel
|| $channel['channel_type'] != 'pdd'
|| strtoupper($channel['logistics_code']) != strtoupper($expectedLogisticsCode)) {
$errorMsg = '拼多多消费者付费送货上门订单,自有仓发货必须使用拼多多电子面单';
return false;
}
return true;
}
/**
* 从仓库可用物流中选择第一个满足整个订单组要求的物流公司
*
* 仓库物流列表已经按 weight 倒序排列。自动审单原先选中的物流不合规时,
* 仅在同一仓库的可达物流中寻找替代项,避免有合规物流却直接挂起订单。
*
* @param array $orders
* @param array|int $branch
* @param string $shipArea
* @return array
*/
public function findAvailableCorp($orders, $branch, $shipArea = '')
{
$branchId = is_array($branch) ? $branch['branch_id'] : $branch;
if (empty($branchId)) {
return [];
}
$corpList = app::get('ome')->model('branch')->get_corp($branchId, $shipArea);
foreach ((array)$corpList as $corp) {
$isAvailable = true;
foreach ((array)$orders as $order) {
$errorMsg = '';
if (!$this->validate($order, $branch, $corp, $errorMsg)) {
$isAvailable = false;
break;
}
}
if ($isAvailable) {
return $corp;
}
}
return [];
}
/**
* 补齐审单入口可能未查询的电子面单字段
*/
private function completeCorpInfo($corp)
{
if (empty($corp['corp_id']) || (!empty($corp['type']) && isset($corp['tmpl_type']) && isset($corp['channel_id']))) {
return $corp;
}
$corpInfo = app::get('ome')->model('dly_corp')->db_dump(
['corp_id' => $corp['corp_id']],
'corp_id,name,type,tmpl_type,channel_id,disabled'
);
return $corpInfo ? array_merge($corp, $corpInfo) : $corp;
}
/**
* 获取订单当前生效的承运商白名单
*/
private function getWhiteDeliveryCps($orderId)
{
$orderExtend = app::get('ome')->model('order_extend')->db_dump(
['order_id' => $orderId],
'white_delivery_cps'
);
$whiteDeliveryCps = $orderExtend['white_delivery_cps']
? json_decode($orderExtend['white_delivery_cps'], true)
: [];
return array_values(array_unique(array_filter((array)$whiteDeliveryCps)));
}
/**
* 判断审单仓库是否由 OMS 自有仓履约
*/
private function isSelfWms($branch)
{
if (!is_array($branch)) {
$branch = app::get('ome')->model('branch')->db_dump(
['branch_id' => $branch, 'check_permission' => false],
'branch_id,wms_id'
);
} elseif (empty($branch['wms_id']) && $branch['branch_id']) {
$branch = app::get('ome')->model('branch')->db_dump(
['branch_id' => $branch['branch_id'], 'check_permission' => false],
'branch_id,wms_id'
);
}
if (empty($branch['wms_id'])) {
return false;
}
$adapter = app::get('channel')->model('adapter')->db_dump(
['channel_id' => $branch['wms_id']],
'adapter'
);
return $adapter['adapter'] == 'selfwms';
}
}

View File

@@ -2,7 +2,6 @@
class ome_mdl_delivery extends dbeav_model
{
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
//public $filter_use_like = true;
public $has_many = array(
'delivery_items' => 'delivery_items',
@@ -217,7 +216,7 @@ class ome_mdl_delivery extends dbeav_model
$where .= ' AND EXISTS (
SELECT 1 FROM sdb_ome_bill_label bl
WHERE bl.bill_id = '.$tPre.'delivery_id
AND bl.bill_type = "delivery"
AND bl.bill_type = "ome_delivery"
AND bl.label_code = "'.addslashes($filter['delivery_label_code']).'"
)';
unset($filter['delivery_label_code']);
@@ -227,15 +226,15 @@ class ome_mdl_delivery extends dbeav_model
$where .= ' AND EXISTS (
SELECT 1 FROM sdb_ome_bill_label bl
WHERE bl.bill_id = '.$tPre.'delivery_id
AND bl.bill_type = "delivery"
AND bl.label_code = "'.self::URGENT_LABEL_CODE.'"
AND bl.bill_type = "ome_delivery"
AND bl.label_code = "SOMS_URGENT_SHIP"
)';
} else {
$where .= ' AND NOT EXISTS (
SELECT 1 FROM sdb_ome_bill_label bl
WHERE bl.bill_id = '.$tPre.'delivery_id
AND bl.bill_type = "delivery"
AND bl.label_code = "'.self::URGENT_LABEL_CODE.'"
AND bl.bill_type = "ome_delivery"
AND bl.label_code = "SOMS_URGENT_SHIP"
)';
}
unset($filter['urgent_delivery']);
@@ -2132,6 +2131,22 @@ class ome_mdl_delivery extends dbeav_model
}
$order = $oOrder->dump($order_id);
// 所有审单入口最终都会进入发货单创建。这里作为事务内兜底,防止旧版单笔审单
// 或其他生成发货单入口绕过上层的拼多多消费者付费送货上门物流校验。
if (!$is_diff_order) {
$homeDeliveryCorp = $delivery['logi_id'] ? $oDly_corp->dump($delivery['logi_id']) : [];
$homeDeliveryError = '';
if (!kernel::single('ome_order_platform_pinduoduo_chargehomedelivery')->validate(
$order,
$delivery['branch_id'],
$homeDeliveryCorp,
$homeDeliveryError
)) {
$this->db->rollBack();
return array('rsp' => 'fail', 'msg' => $homeDeliveryError);
}
}
if (kernel::single('ome_order_bool_type')->isJITX($order['order_bool_type'])) {
kernel::single('purchase_branch_freeze')->deleteFromOrder($order['order_bn'], $order['shop_id']);
}
@@ -3688,7 +3703,6 @@ class ome_mdl_delivery extends dbeav_model
if ($data['delivery_id'] > 0) {
$this->updateOrderLogi($data['delivery_id'], $data);
$this->inheritUrgentLabelFromOrders($data['delivery_id']);
}
return $result;
@@ -3710,8 +3724,8 @@ class ome_mdl_delivery extends dbeav_model
$prefix = "CASE WHEN EXISTS (
SELECT 1 FROM sdb_ome_bill_label bl
WHERE bl.bill_id = ".$this->table_name(true).".delivery_id
AND bl.bill_type = 'delivery'
AND bl.label_code = '".self::URGENT_LABEL_CODE."'
AND bl.bill_type = 'ome_delivery'
AND bl.label_code = 'SOMS_URGENT_SHIP'
) THEN 0 ELSE 1 END ASC";
return $prefix . ($orderSql ? ',' . $orderSql : '');
}
@@ -3747,34 +3761,6 @@ class ome_mdl_delivery extends dbeav_model
return $globalConf === null || $globalConf === '' || $globalConf === 'on';
}
/**
* 在发货单保存后,把关联订单上的加急标签补写到发货单标签表。
*
* @param int $deliveryId
* @return bool
*/
public function inheritUrgentLabelFromOrders($deliveryId)
{
if (!$deliveryId) {
return false;
}
$labelLib = kernel::single('ome_bill_label');
if ($labelLib->existLabel($deliveryId, self::URGENT_LABEL_CODE, 'delivery')) {
return true;
}
$orderRows = app::get('ome')->model('delivery_order')->getList('order_id', ['delivery_id' => $deliveryId]);
if (!$orderRows) {
return false;
}
foreach ($orderRows as $row) {
if ($labelLib->existLabel($row['order_id'], self::URGENT_LABEL_CODE)) {
$err = '';
return $labelLib->markBillLabel($deliveryId, '', self::URGENT_LABEL_CODE, 'delivery', $err);
}
}
return false;
}
/**
* 更新发货单对应的订单发货物流信息
*
@@ -4654,7 +4640,7 @@ class ome_mdl_delivery extends dbeav_model
if (!$deliveryIds) {
return array();
}
$labelRows = app::get('ome')->model('bill_label')->getBIllLabelList($deliveryIds, 'delivery');
$labelRows = app::get('ome')->model('bill_label')->getBIllLabelList($deliveryIds, 'ome_delivery');
$result = array();
foreach ((array)$labelRows as $label) {
$result[$label['bill_id']] .= sprintf(

View File

@@ -16,16 +16,6 @@
*/
class ome_mdl_delivery_order extends dbeav_model{
public function save(&$data, $mustUpdate = null)
{
$result = parent::save($data, $mustUpdate);
if ($result && !empty($data['delivery_id'])) {
app::get('ome')->model('delivery')->inheritUrgentLabelFromOrders($data['delivery_id']);
}
return $result;
}
function insertParentOrderByItems($parent_id, $items){
if (!is_array($items)) return false;
@@ -44,12 +34,6 @@ class ome_mdl_delivery_order extends dbeav_model{
return false;
}
#根据物流单号,获取会员备注与订单备注
/**
* 获取MarkInfo
* @param mixed $dly_id ID
* @param mixed $_column _column
* @return mixed 返回结果
*/
public function getMarkInfo($dly_id,$_column=null){
if(!empty($_column)){

View File

@@ -37,6 +37,85 @@ class ome_mdl_order_retrial extends dbeav_model
return $rows;
}
/**
* 规范化高级筛选中的单值或多行文本值
*
* 历史订单的物料筛选使用多行文本框Finder会将多个值以换行符提交。
* 这里统一兼容字符串和数组,去除空值并去重,供店铺和物料筛选复用。
*
* @param mixed $value
* @return array
*/
private function _normalize_filter_values($value)
{
if(is_string($value))
{
$value = preg_split('/\r\n|\r|\n/', $value);
}
$result = array();
foreach((array) $value as $item)
{
if(!is_scalar($item))
{
continue;
}
$item = trim((string) $item);
if($item !== '')
{
$result[$item] = $item;
}
}
return array_values($result);
}
/**
* 生成日期时间高级筛选条件
*
* 参数结构与Finder现有time控件保持一致支持等于、大于、小于和时间范围。
*
* @param array $filter
* @param string $field
* @param string $column
* @return string
*/
private function _build_time_filter($filter, $field, $column)
{
$search_key = '_'.$field.'_search';
$search = isset($filter[$search_key]) ? $filter[$search_key] : '';
if($search == 'between' && !empty($filter[$field.'_from']) && !empty($filter[$field.'_to']))
{
$from_hour = isset($filter['_DTIME_']['H'][$field.'_from']) ? intval($filter['_DTIME_']['H'][$field.'_from']) : 0;
$from_minute = isset($filter['_DTIME_']['M'][$field.'_from']) ? intval($filter['_DTIME_']['M'][$field.'_from']) : 0;
$to_hour = isset($filter['_DTIME_']['H'][$field.'_to']) ? intval($filter['_DTIME_']['H'][$field.'_to']) : 0;
$to_minute = isset($filter['_DTIME_']['M'][$field.'_to']) ? intval($filter['_DTIME_']['M'][$field.'_to']) : 0;
$from = strtotime($filter[$field.'_from'].' '.$from_hour.':'.$from_minute.':00');
$to = strtotime($filter[$field.'_to'].' '.$to_hour.':'.$to_minute.':00');
return "(".$column.">='".$from."' AND ".$column."<='".$to."')";
}
if(empty($filter[$field]))
{
return '';
}
$hour = isset($filter['_DTIME_']['H'][$field]) ? intval($filter['_DTIME_']['H'][$field]) : 0;
$minute = isset($filter['_DTIME_']['M'][$field]) ? intval($filter['_DTIME_']['M'][$field]) : 0;
$time = strtotime($filter[$field].' '.$hour.':'.$minute.':00');
if($search == 'than')
{
return $column.">'".$time."'";
}
elseif($search == 'lthan')
{
return $column."<'".$time."'";
}
return $column."='".$time."'";
}
/*------------------------------------------------------ */
//-- 过滤条件[自定义]
/*------------------------------------------------------ */
@@ -55,6 +134,138 @@ class ome_mdl_order_retrial extends dbeav_model
{
$where[] = "a.order_bn = '".$filter['order_bn']."'";
}
//控制器传入不可修改的组织权限范围,必须独立于用户选择的组织筛选条件。
//两个条件同时存在时会自然取交集恶意提交权限外的org_id也无法越权。
if(!empty($filter['permission_org_id']))
{
$org_ids = array();
foreach((array) $filter['permission_org_id'] as $org_id)
{
$org_id = intval($org_id);
if($org_id > 0)
{
$org_ids[$org_id] = $org_id;
}
}
$where[] = $org_ids ? "b.org_id IN (".implode(',', $org_ids).")" : '1=0';
}
//运营组织高级筛选选项由Finder按当前账号权限裁剪。
if(!empty($filter['org_id']))
{
$org_ids = array();
foreach((array) $filter['org_id'] as $org_id)
{
$org_id = intval($org_id);
if($org_id > 0)
{
$org_ids[$org_id] = $org_id;
}
}
$where[] = $org_ids ? "b.org_id IN (".implode(',', $org_ids).")" : '1=0';
}
//来源店铺沿用历史订单的可搜索多选控件。
if(!empty($filter['shop_id']))
{
$shop_ids = $this->_normalize_filter_values($filter['shop_id']);
$quoted_shop_ids = array();
foreach($shop_ids as $shop_id)
{
$quoted_shop_ids[] = $this->db->quote($shop_id);
}
$where[] = $quoted_shop_ids ? "b.shop_id IN (".implode(',', $quoted_shop_ids).")" : '1=0';
}
//基础物料和销售物料使用EXISTS过滤避免直接JOIN明细导致复审列表重复。
if(!empty($filter['product_bn']))
{
$product_bns = $this->_normalize_filter_values($filter['product_bn']);
$quoted_product_bns = array();
foreach($product_bns as $product_bn)
{
$quoted_product_bns[] = $this->db->quote($product_bn);
}
$where[] = $quoted_product_bns
? "EXISTS (SELECT 1 FROM ". DB_PREFIX ."ome_order_items AS oi WHERE oi.order_id=a.order_id AND oi.`delete`='false' AND oi.bn IN (".implode(',', $quoted_product_bns)."))"
: '1=0';
}
if(!empty($filter['sales_material_bn']))
{
$sales_material_bns = $this->_normalize_filter_values($filter['sales_material_bn']);
$quoted_sales_material_bns = array();
foreach($sales_material_bns as $sales_material_bn)
{
$quoted_sales_material_bns[] = $this->db->quote($sales_material_bn);
}
$where[] = $quoted_sales_material_bns
? "EXISTS (SELECT 1 FROM ". DB_PREFIX ."ome_order_objects AS oo WHERE oo.order_id=a.order_id AND oo.`delete`='false' AND oo.bn IN (".implode(',', $quoted_sales_material_bns)."))"
: '1=0';
}
if(!empty($filter['sales_material_name']))
{
$sales_material_names = $this->_normalize_filter_values($filter['sales_material_name']);
$quoted_sales_material_names = array();
foreach($sales_material_names as $sales_material_name)
{
$quoted_sales_material_names[] = $this->db->quote($sales_material_name);
}
$where[] = $quoted_sales_material_names
? "EXISTS (SELECT 1 FROM ". DB_PREFIX ."ome_order_objects AS oo WHERE oo.order_id=a.order_id AND oo.`delete`='false' AND oo.name IN (".implode(',', $quoted_sales_material_names)."))"
: '1=0';
}
$createtime_where = $this->_build_time_filter($filter, 'createtime', 'b.createtime');
if($createtime_where)
{
$where[] = $createtime_where;
}
if(isset($filter['pay_status']) && $filter['pay_status'] !== '')
{
$pay_status = array();
foreach((array) $filter['pay_status'] as $status)
{
$status = intval($status);
if($status >= 0 && $status <= 8)
{
$pay_status[$status] = $status;
}
}
$where[] = $pay_status ? "b.pay_status IN (".implode(',', $pay_status).")" : '1=0';
}
if(isset($filter['ship_status']) && $filter['ship_status'] !== '')
{
$ship_status = array();
foreach((array) $filter['ship_status'] as $status)
{
$status = intval($status);
if($status >= 0 && $status <= 4)
{
$ship_status[$status] = $status;
}
}
$where[] = $ship_status ? "b.ship_status IN (".implode(',', $ship_status).")" : '1=0';
}
if(!empty($filter['process_status']))
{
$allowed_process_status = array(
'unconfirmed' => true,
'confirmed' => true,
'splitting' => true,
'splited' => true,
'cancel' => true,
'remain_cancel' => true,
'is_retrial' => true,
'is_declare' => true,
);
$process_status = array();
foreach($this->_normalize_filter_values($filter['process_status']) as $status)
{
if(isset($allowed_process_status[$status]))
{
$process_status[] = $this->db->quote($status);
}
}
$where[] = $process_status ? "b.process_status IN (".implode(',', $process_status).")" : '1=0';
}
if(!empty($filter['status']) || $filter['status'] == '0')
{
if(is_array($filter['status']))
@@ -1488,6 +1699,80 @@ class ome_mdl_order_retrial extends dbeav_model
return true;
}
/**
* 订单取消后自动结束待复审流程
*
* 全额退款、平台取消和后台人工取消最终都会进入订单统一取消流程。
* 订单取消成功后,待复审记录不能继续保留为可操作状态,否则订单仍会出现在
* 待复审列表中。这里只维护复审终态、异常状态和复审库存跟踪记录;订单取消
* 主流程已经按当前订单明细释放实际冻结库存,因此不能再调用复审通过或回滚
* 的库存处理方法,避免重复释放库存。
*
* @param int $order_id 订单ID
* @return bool
*/
public function finish_by_order_cancel($order_id)
{
$order_id = intval($order_id);
if($order_id <= 0)
{
return false;
}
// 只有订单已经成功取消时才结束复审,避免取消失败时提前关闭复审流程。
$order = $this->db->selectrow("SELECT order_id FROM ". DB_PREFIX ."ome_orders WHERE order_id='".$order_id."' AND (process_status='cancel' OR status='dead')");
if(empty($order))
{
return false;
}
$retrial_list = $this->db->select("SELECT id, remarks FROM ". DB_PREFIX ."ome_order_retrial WHERE order_id='".$order_id."' AND status='0'");
if(empty($retrial_list))
{
return true;
}
$lastdate = time();
$system_remarks = '订单已取消,系统自动退出复审流程。';
$retrial_ids = array();
foreach($retrial_list as $retrial)
{
$retrial_id = intval($retrial['id']);
$remarks = trim((string) $retrial['remarks']);
if(strpos($remarks, $system_remarks) === false)
{
$remarks = $remarks ? $remarks.' '.$system_remarks : $system_remarks;
}
$sql = "UPDATE ". DB_PREFIX ."ome_order_retrial SET status='4', remarks=".$this->db->quote($remarks).", lastdate='".$lastdate."' WHERE id='".$retrial_id."' AND status='0'";
$this->db->exec($sql);
if($this->db->affect_row() > 0)
{
$retrial_ids[] = $retrial_id;
}
}
// 并发情况下记录可能已被人工复审处理,不再重复执行取消收口。
if(empty($retrial_ids))
{
return true;
}
// 订单已经是取消终态,同时清除复审产生的异常、暂停标记。
$this->db->exec("UPDATE ". DB_PREFIX ."ome_orders SET abnormal='false', pause='false' WHERE order_id='".$order_id."' AND (process_status='cancel' OR status='dead')");
$this->update_abnormal($order_id);
// 这里只删除复审库存计算记录,不再调整实际库存冻结,避免与订单取消重复释放。
if($retrial_ids)
{
$this->db->exec("DELETE FROM ". DB_PREFIX ."ome_order_retrial_store_freeze WHERE retrial_id IN (".implode(',', $retrial_ids).")");
}
$oOperation_log = app::get('ome')->model('operation_log');
$oOperation_log->write_log('order_retrial@ome', $order_id, $system_remarks);
return true;
}
/**
+----------------------------------------------------------
* 更新订单异常表[ome_abnormal]状态

View File

@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ome_mdl_orders extends dbeav_model{
//是否有导出配置
@@ -2748,6 +2747,26 @@ class ome_mdl_orders extends dbeav_model{
return true;
}
/**
* 订单取消后结束待复审流程
*
* 复审收口属于订单取消后的附加处理,异常不能反向阻断订单取消、库存释放
* 以及其他取消扩展,因此统一捕获异常并记录系统日志。
*
* @param int $order_id 订单ID
* @return bool
*/
private function _finish_order_retrial_by_cancel($order_id)
{
try {
return app::get('ome')->model('order_retrial')->finish_by_order_cancel($order_id);
} catch (Exception $e) {
kernel::log('订单取消后退出复审失败order_id='.intval($order_id).'error='.$e->getMessage());
}
return false;
}
/**
* 取消订单
* @access public
@@ -2795,6 +2814,8 @@ class ome_mdl_orders extends dbeav_model{
//logs
$memo = '订单已经是取消状态!';
$operLogMdl->write_log('order_modify@ome', $order_id, $memo);
$this->_finish_order_retrial_by_cancel($order_id);
return $rs;
}else{
@@ -2824,6 +2845,9 @@ class ome_mdl_orders extends dbeav_model{
//logs
$operLogMdl->write_log('order_modify@ome',$order_id,$memo);
//订单取消主流程完成后,自动结束仍处于待处理状态的复审流程。
$this->_finish_order_retrial_by_cancel($order_id);
// 订单取消成功,触发订单取消事件
$instance = kernel::service('ome.service.order.cancel.after');
if($instance && method_exists($instance, 'cancel_order_after')){

View File

@@ -1,18 +1,3 @@
<!--
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.
-->
<services>
<service id="desktop_finder.ome_mdl_orders">
<class>ome_finder_orders</class>
@@ -312,6 +297,9 @@
<service id="extend_filter_ome_mdl_orders">
<class>ome_finder_extend_filter_orders</class>
</service>
<service id="extend_filter_ome_mdl_order_retrial">
<class>ome_finder_extend_filter_order_retrial</class>
</service>
<service id="extend_filter_ome_mdl_payments">
<class>ome_finder_extend_filter_payments</class>
</service>

View File

@@ -756,6 +756,7 @@ $ES('.hidden_money').addEvent('click',function(){
var store_change = [];
var change_store_request = null;
<{if $not_edit}>
var tpl_change = '<tr key="{product_id}" id="product_{product_id}">';
@@ -1286,9 +1287,126 @@ function rchange_bn_number(obj, sm_id)
});
}
//切换换货仓库 保证所有销售物料重新选择
// 切换换货仓库后,一次提交当前全部销售物料重新计算库存。
// 只更新销售物料和基础物料库存,保留用户已填写的申请数量、售价等未保存数据。
function refresh_change_store(){
if(!$('changebranch') || !store_change.length){
return;
}
var changebranch = $('changebranch').get('value');
if(!changebranch){
return;
}
var product_ids = [];
var post_data = [];
store_change.each(function(item){
// PageData不会自动同步输入框值刷新前先保存用户尚未提交的数量和售价。
var product_row = $('product_'+item.product_id);
if(product_row){
var num_input = product_row.getElement('input[key=num]');
var price_input = product_row.getElement('input[key=price]');
if(num_input){
item.num = num_input.get('value');
}
if(price_input){
item.price = price_input.get('value');
}
}
if(item.items){
item.items.each(function(basic_item){
basic_item.change_num = parseInt(item.num) * parseInt(basic_item.number);
});
}
product_ids.push(item.product_id);
post_data.push('product_id[]='+encodeURIComponent(item.product_id));
var sale_store = $('sale_store_'+item.bn);
var sale_store_input = $('product_sale_store_'+item.bn);
if(sale_store){
sale_store.set('html', '加载中...');
}
if(sale_store_input){
sale_store_input.set('value', '');
}
});
if(!product_ids.length){
return;
}
if(change_store_request){
change_store_request.cancel();
}
var request_branch = changebranch;
var order_id = $('order_id').get('value');
change_store_request = new Request.JSON({
url:'index.php?app=ome&ctl=admin_return_rchange&act=getProducts&type=change&source=<{$source}>&response_type=json&changebranch_id='+request_branch+'&order_id='+order_id,
method:'post',
data:post_data.join('&'),
onSuccess:function(response){
// 快速连续切仓时,旧仓请求即使返回也不能覆盖当前仓库库存。
if(!$('changebranch') || $('changebranch').get('value') != request_branch){
return;
}
response = response || [];
response.each(function(new_item){
store_change.each(function(old_item){
if(old_item.product_id != new_item.product_id){
return;
}
old_item.sale_store = new_item.sale_store;
if(old_item.items && new_item.items){
old_item.items.each(function(old_basic_item){
new_item.items.each(function(new_basic_item){
if(old_basic_item.bm_id == new_basic_item.bm_id){
old_basic_item.store = new_basic_item.store;
}
});
});
}
});
});
createProduct(store_change);
change_store_request = null;
},
onFailure:function(){
if($('changebranch') && $('changebranch').get('value') == request_branch){
store_change.each(function(item){
var sale_store = $('sale_store_'+item.bn);
if(sale_store){
sale_store.set('html', '--');
}
});
MessageBox.error('切换仓库后刷新库存失败,请重新选择仓库重试');
}
change_store_request = null;
},
onError:function(){
if($('changebranch') && $('changebranch').get('value') == request_branch){
store_change.each(function(item){
var sale_store = $('sale_store_'+item.bn);
if(sale_store){
sale_store.set('html', '--');
}
});
MessageBox.error('库存数据解析失败,请重新选择仓库重试');
}
change_store_request = null;
}
}).send();
}
// 当切换了换货仓库,清空销售物料选择过滤并刷新已选物料库存。
function clean_change_filter(){
$ES('input[name=total_change_filter]').set("value","");
refresh_change_store();
}
if($('selectLogisticsName'))

View File

@@ -78,6 +78,25 @@ class omeauto_auto_plugin_logi extends omeauto_auto_plugin_abstract implements o
return;
}
foreach($orders as $val) {
// 强制指定、店铺绑定等路径不能静默替换物流,只在最终校验不合规时挂起。
$homeDeliveryError = '';
$homeDeliveryLib = kernel::single('ome_order_platform_pinduoduo_chargehomedelivery');
if (!$homeDeliveryLib->validate(
$val,
$group->getBranchId(),
$corp,
$homeDeliveryError
)) {
$group->setDlyCorp([]);
$group->setOrderStatus('*', $this->getMsgFlag());
$group->setStatus(
omeauto_auto_group_item::__OPT_HOLD,
$this->_getPlugName(),
$val['order_bn'].' '.$homeDeliveryError
);
return;
}
if($val['shop_type'] == '360buy') {
if(kernel::single('ome_bill_label_shsm')->isTinyPieces($val['order_id']) && $corp['channel_id']) {
$extendObj = app::get('logisticsmanager')->model('channel_extend');
@@ -784,4 +803,4 @@ class omeauto_auto_plugin_logi extends omeauto_auto_plugin_abstract implements o
}
return $jdcorpList;
}
}
}

View File

@@ -14,14 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class sales_aftersale_type_refund
{
/**
* generate_aftersale
* @param mixed $refund_id ID
* @return mixed 返回值
*/
public function generate_aftersale($refund_id = null)
{
if (empty($refund_id)) {
@@ -128,7 +122,7 @@ class sales_aftersale_type_refund
$saleInfo = app::get('ome')->model('sales')->db_dump(['order_id' => $apply_detail[0]['order_id']], 'sale_id,ship_time');
$data['ship_time'] = $saleInfo['ship_time'];
$sale_id = $saleInfo['sale_id'];
$saleItems = app::get('ome')->model('sales_items')->getList('product_id,nums,platform_amount,settlement_amount,platform_pay_amount,actually_amount', ['sale_id'=>$sale_id]);
$saleItems = app::get('ome')->model('sales_items')->getList('product_id,nums,platform_pay_amount,actually_amount', ['sale_id'=>$sale_id]);
$orderItems = $Oorder_items->getList('product_id,bn,item_id,obj_id,shop_goods_id,shop_product_id', array('order_id' => $apply_detail[0]['order_id']));
$orderItems = array_column($orderItems,null,'product_id');
@@ -137,8 +131,6 @@ class sales_aftersale_type_refund
$productSendnum = [];
foreach($saleItems as $v) {
$productSendnum[$v['product_id']] += $v['nums'];
$productSaleAmount[$v['product_id']]['platform_amount'] += $v['platform_amount'];
$productSaleAmount[$v['product_id']]['settlement_amount'] += $v['settlement_amount'];
$productSaleAmount[$v['product_id']]['actually_amount'] += $v['actually_amount'];
$productSaleAmount[$v['product_id']]['platform_pay_amount'] += $v['platform_pay_amount'];
}
@@ -152,22 +144,20 @@ class sales_aftersale_type_refund
foreach ($product_data as $k => $v)
{
$product_id = $v['product_id'];
$saleprice = bcmul((float)$v['price'], (float)$v['num'], 2);
//关联的销售物料
$returnItemInfo = $returnItems['products'][$product_id];
$orderItemInfo = $orderItems[$product_id];
$platform_amount = 0;
$settlement_amount = $saleprice;
if($productSendnum[$product_id]) {
$platform_amount = sprintf("%.2f", $productSaleAmount[$product_id]['platform_amount'] * $v['num'] / $productSendnum[$product_id]);
$settlement_amount = sprintf("%.2f", $productSaleAmount[$product_id]['settlement_amount'] * $v['num'] / $productSendnum[$product_id]);
$platform_pay_amount = sprintf("%.2f", $productSaleAmount[$product_id]['platform_pay_amount'] * $v['num'] / $productSendnum[$product_id]);
$actually_amount = sprintf("%.2f", $productSaleAmount[$product_id]['actually_amount'] * $v['num'] / $productSendnum[$product_id]);
} else {
$platform_amount = 0;
$settlement_amount = 0;
$platform_pay_amount = 0;
$actually_amount = 0;
}
$data['platform_amount'] += $platform_amount;
$data['settlement_amount'] += $settlement_amount;
$data['platform_pay_amount'] += $platform_pay_amount;
$data['actually_amount'] += $actually_amount;
@@ -178,10 +168,10 @@ class sales_aftersale_type_refund
'product_id' => $v['product_id'],
'num' => $v['num'],
'price' => $v['price'],
'saleprice' => bcmul((float)$v['price'], (float)$v['num'], 2),
'saleprice' => $saleprice,
'return_type' => 'refunded',
'money' => bcmul((float)$v['price'], (float)$v['num'], 2),
'refunded' => bcmul((float)$v['price'], (float)$v['num'], 2),
'money' => $saleprice,
'refunded' => $saleprice,
'create_time' => time(),
'last_modified' => time(),
'item_type' => $returnItemInfo['item_type'], //物料类型
@@ -193,6 +183,22 @@ class sales_aftersale_type_refund
'actually_amount' => $actually_amount
);
}
//累加平台优惠退回金额到结算金额
$platform_discount_return_amount = $apply_detail[0]['platform_discount_return_amount'] ? $apply_detail[0]['platform_discount_return_amount'] : 0;
if (bccomp($platform_discount_return_amount, 0, 2) > 0 && !empty($aftersale_items)) {
$aftersale_items = kernel::single('ome_order')->calculate_part_porth($aftersale_items, array(
'part_total' => $platform_discount_return_amount,
'part_field' => 'discount_return_share',
'porth_field' => 'saleprice',
));
foreach ($aftersale_items as $k => $item) {
$share = isset($item['discount_return_share']) ? $item['discount_return_share'] : 0;
$aftersale_items[$k]['settlement_amount'] = bcadd($item['settlement_amount'], $share, 2);
unset($aftersale_items[$k]['discount_return_share']);
$data['settlement_amount'] = bcadd($data['settlement_amount'], $share, 2);
}
}
$data['aftersale_items'] = $aftersale_items;

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,6 @@
* limitations under the License.
*/
class wms_mdl_delivery extends dbeav_model{
const URGENT_LABEL_CODE = 'SOMS_URGENT_SHIP';
public $filter_use_like = true;
var $has_many = array(
'delivery_items' => 'delivery_items',
@@ -206,7 +205,7 @@ class wms_mdl_delivery extends dbeav_model{
$where .= ' AND EXISTS (
SELECT 1 FROM sdb_ome_bill_label bl
WHERE bl.bill_id = '.$tPre.'delivery_id
AND bl.bill_type = "delivery"
AND bl.bill_type = "wms_delivery"
AND bl.label_code = "'.addslashes($filter['delivery_label_code']).'"
)';
unset($filter['delivery_label_code']);
@@ -216,15 +215,15 @@ class wms_mdl_delivery extends dbeav_model{
$where .= ' AND EXISTS (
SELECT 1 FROM sdb_ome_bill_label bl
WHERE bl.bill_id = '.$tPre.'delivery_id
AND bl.bill_type = "delivery"
AND bl.label_code = "'.self::URGENT_LABEL_CODE.'"
AND bl.bill_type = "wms_delivery"
AND bl.label_code = "SOMS_URGENT_SHIP"
)';
} else {
$where .= ' AND NOT EXISTS (
SELECT 1 FROM sdb_ome_bill_label bl
WHERE bl.bill_id = '.$tPre.'delivery_id
AND bl.bill_type = "delivery"
AND bl.label_code = "'.self::URGENT_LABEL_CODE.'"
AND bl.bill_type = "wms_delivery"
AND bl.label_code = "SOMS_URGENT_SHIP"
)';
}
unset($filter['urgent_delivery']);
@@ -1503,7 +1502,7 @@ class wms_mdl_delivery extends dbeav_model{
if (!$deliveryIds) {
return array();
}
$labelRows = app::get('ome')->model('bill_label')->getBIllLabelList($deliveryIds, 'delivery');
$labelRows = app::get('ome')->model('bill_label')->getBIllLabelList($deliveryIds, 'wms_delivery');
$result = array();
foreach ((array)$labelRows as $label) {
$result[$label['bill_id']] .= sprintf(

View File

@@ -1,5 +1,5 @@
<deploy>
<ver>8.4.0.20260707</ver>
<ver>8.5.0.20260723</ver>
<licence file="LICENSE" />
<product_name>ONEX OMS</product_name>
<product_id>taog</product_id>