Explorar o código

1. app-hd(花掌柜)补取消跑腿、获取取消原因接口
2. 处理各平台跑腿订单状态回调--实现跑腿状态与商城订单状态的映射函数,方便转换

shizhongqi hai 8 meses
pai
achega
6521d209f8

+ 99 - 0
app-hd/controllers/DeliveryController.php

@@ -6,6 +6,7 @@ use bizGhs\custom\classes\CustomClass;
 use bizGhs\express\classes\DeliveryAuthTokenClass;
 use bizHd\order\classes\OrderClass;
 use bizHd\express\classes\HdDeliveryOrderClass;
+use hd\models\delivery\CancelOrderForm;
 use hd\models\delivery\CreateOrderForm;
 use Yii;
 use biz\shop\classes\ShopClass;
@@ -200,6 +201,104 @@ class DeliveryController extends BaseController
         }
     }
 
+    // 取消订单
+    public function actionCancelOrder()
+    {
+        $form = new CancelOrderForm();
+        $form->loadAndValidate();
+        $post = $form->getAttributes();
+        $orderId = $post['orderId'] ?? 0; // 平台的orderId,
+        $platform = $post['platform'] ?? '';
+        $hdOrderId = $post['hdOrderId'];
+
+        // 先获取配送订单,确保 $gdo 始终可用
+        $hdo = HdDeliveryOrderClass::getByCondition(['mainId'=>$this->mainId, 'hdOrderId'=>$hdOrderId, 'orderStatus!='=> -1], true);
+        if(empty($hdo)) {
+            util::fail('未找到对应订单: ' . $hdOrderId);
+        }
+
+        // 如果没有提供平台和订单ID,从配送订单中获取
+        if($platform == '' || $orderId == 0) {
+            $orderId = $hdo->orderId;
+            $platform = $hdo->deliveryId;
+        }
+
+        $ds = new DispatchService($this->mainId, $platform);
+
+        $cancelCostCent = 0;
+        if($platform == 'fengniao') {
+            //请求订单预取消接口,获取是否可取消。如果运单状态不允许取消,则直接返回
+            $cancelParams = ['order_id'=>$orderId, 'order_cancel_code'=>$post['order_cancel_code']];
+            $res = $ds->getAdapter()->preCancelOrder($cancelParams);
+            if($res['code'] != 0){
+                util::fail('运单状态不允许取消');
+            }
+            $cancelCostCent = $res['data']['actual_cancel_cost_cent']; //取消实际需金额(单位:分)
+        }
+        if($platform == 'shunfeng') {
+            //请求订单预取消接口,获取是否可取消。如果运单状态不允许取消,则直接返回
+            $cancelParams = ['order_id'=>$orderId, 'order_cancel_code'=>$post['order_cancel_code']];
+            $res = $ds->getAdapter()->preCancelOrder($cancelParams);
+            if($res['code'] != 0){
+                util::fail('运单状态不允许取消');
+            }
+            $post['order_type'] = 1; //查询订单ID类型	 1、顺丰订单号 2、商家订单号
+        }
+
+        $post['order_cancel_role'] = 1; //1:商户取消, 2:用户取消
+        $ret = $ds->cancelOrder($orderId, $post);
+        if($ret['code'] == 0) {
+            // 更新跑腿订单与批发订单状态
+            $hdo->orderStatus = -1;
+            $hdo->cancelCost = $ret['platform'] !== 'fengniao' ? $ret['data']['deductionFee'] : $cancelCostCent; // 由于蜂鸟平台返回的扣费不一样造成
+            if(!$hdo->save()) {
+                Yii::error('保存配送订单失败: ' . json_encode($hdo->errors));
+                util::fail('保存配送订单失败');
+            }
+
+            $Order = OrderClass::getById($hdOrderId, true, 'id, sendDistance, sendStatus, deliveryId');
+            $Order->sendDistance = 0;
+            $Order->sendStatus = -1;
+            $Order->status = 5;
+            $Order->deliveryId = '';
+            if(!$Order->save()) {
+                Yii::error('保存批发订单失败: ' . json_encode($Order->errors));
+                util::fail('保存批发订单失败');
+            }
+
+            util::success($ret['data'], "success");
+        }
+
+        util::fail('取消失败');
+    }
+
+    /**
+     * 获取订单取消原因
+     */
+    public function actionCancelReason()
+    {
+        $post = Yii::$app->request->post();
+        $hdOrderId = $post['hdOrderId'];
+        $platform = $post['platform'];
+
+        $hdo = HdDeliveryOrderClass::getByCondition(['mainId'=>$this->mainId, 'ghsOrderId'=>$hdOrderId, 'orderStatus!='=>-1], true);
+        if(!empty($hdo)) {
+            $orderId = $hdo->orderId;
+            //$platform = $gdo->deliveryId;
+        } else {
+            util::fail('未找到对应订单: ' . $hdOrderId);
+        }
+
+        $ds = new DispatchService($this->mainId, $platform);
+        $ret = $ds->getCancelReasonList($orderId);
+        if($ret['code'] == 0){
+            util::success($ret['data']);
+        }else{
+            Yii::error('获取订单取消原因:'.json_encode($ret));
+            util::fail($ret['msg']);
+        }
+    }
+
     public function actionAddress()
     {
         $post = Yii::$app->request->post();

+ 65 - 0
app-hd/models/delivery/CancelOrderForm.php

@@ -0,0 +1,65 @@
+<?php
+namespace hd\models\delivery;
+
+use bizHd\express\classes\HdDeliveryOrderClass;
+use hd\models\BaseForm;
+use Yii;
+
+/**
+ * 取消配送订单表单模型
+ * 用于 actionCancelOrder 的参数验证
+ */
+class CancelOrderForm extends BaseForm
+{
+    public $hdOrderId;        // 零售订单ID (必需)
+    public $orderId;           // 第三方平台订单ID (可选)
+    public $platform;          // 配送平台 (可选)
+    public $order_cancel_code; // 订单取消原因代码 (用于蜂鸟平台)
+    public $order_cancel_reason; // 订单取消原因(20字以内)
+
+    public function rules()
+    {
+        return [
+            ['hdOrderId', 'required'],
+            ['hdOrderId', 'integer'],
+            ['hdOrderId', 'validateHdOrderId'],
+            ['orderId', 'string'],
+            ['platform', 'string'],
+            ['order_cancel_code', 'string'],
+            ['order_cancel_reason', 'required'],
+            ['order_cancel_reason', 'string', 'max' => 20],
+        ];
+    }
+
+    public function attributeLabels()
+    {
+        return [
+            'hdOrderId' => '零售订单ID',
+            'orderId' => '平台订单ID',
+            'platform' => '配送平台',
+            'order_cancel_code' => '取消原因代码',
+            'order_cancel_reason' => '取消原因',
+        ];
+    }
+
+    /**
+     * 验证批发订单ID
+     * @param $attribute
+     */
+    public function validateHdOrderId($attribute)
+    {
+        if (!$this->hasErrors()) {
+            // 检查配送订单是否存在
+            $gdo = HdDeliveryOrderClass::getByCondition(
+                ['mainId' => Yii::$app->controller->mainId, 'hdOrderId' => $this->hdOrderId, 'orderStatus!=' => -1],
+                false,
+                'orderId, deliveryId'
+            );
+            
+            if (empty($gdo)) {
+                $this->addError($attribute, '未找到对应的配送订单');
+            }
+        }
+    }
+}
+

+ 4 - 1
common/components/delivery/platform/fengniao/CallBackNotify.php

@@ -51,13 +51,15 @@ class CallBackNotify
     {
         $deliveryOrder = $this->getDeliveryOrder($data['order_id']);
         // 将蜂鸟平台的订单状态转换为系统内的 orderStatus
-        $sendStatus = OrderStatusUtil::convertOrderStatus($data['order_status']);
+        $sendStatus = SendStatusUtil::convertOrderStatus($data['order_status']);
         $deliveryOrder->orderStatus = $sendStatus;
         $deliveryOrder->save();
+        $orderStatus = OrderStatusUtil::convertStatus($data['order_status']);
 
         if(property_exists($deliveryOrder, 'ghsOrderId')){ // 批发
             $order = OrderClass::getById($deliveryOrder->ghsOrderId, true, 'id,sendType,sendStatus,deliveryId,purchaseId,customId,status');
             $order->sendStatus = $sendStatus;
+            $order->status = $orderStatus;
             $order->save();
 
             // 确认送达或取消订单,更新主订单状态
@@ -70,6 +72,7 @@ class CallBackNotify
         }elseif(property_exists($deliveryOrder, 'hdOrderId')){ // 零售
             $order = HdOrderClass::getById($deliveryOrder->hdOrderId, true, 'id,sendType,sendStatus,deliveryId,customId,status');
             $order->sendStatus = $sendStatus;
+            $order->status = $orderStatus;
             $order->save();
         }
 

+ 40 - 57
common/components/delivery/platform/fengniao/OrderStatusUtil.php

@@ -2,15 +2,15 @@
 namespace common\components\delivery\platform\fengniao;
 
 /**
- * Class FengniaoStatusUtil
- * 蜂鸟配送平台状态转换工具类
- * @package common\components\delivery\helpers
+ * Class OrderStatusUtil
+ * 蜂鸟配送平台状态转换工具类 (转换为主订单 status)
+ * @package common\components\delivery\platform\fengniao
  */
 class OrderStatusUtil
 {
     /**
-     * 蜂鸟平台订单状态到系统 orderStatus 的转换映射
-     * 
+     * 蜂鸟平台订单状态到订单 status 的转换映射
+     *
      * 蜂鸟平台状态码说明:
      *  0 - 订单生成
      *  1 - 运单生成成功
@@ -20,54 +20,46 @@ class OrderStatusUtil
      *  3 - 已完成
      *  4 - 已取消
      *  5 - 配送异常
-     * 
-     * 系统内 orderStatus 状态码说明:
-     *  0 - 订单生成
-     *  1 - 系统已接单
-     *  2 - 派单中
-     *  3 - 待取货
-     *  4 - 配送中
-     *  5 - 已送达
-     * -1 - 已取消
-     * -2 - 异常
-     * 10 - 改派中
-     * 20 - 已分配骑手
-     * 30 - 骑手已到店
-     * 40 - 申请取消中
-     * 50 - 客服介入处理中
+     *
+     * 订单 status 状态码说明
+     *  1 - 待付款
+     *  2 - 待配送
+     *  3 - 配送中
+     *  4 - 已完成
+     *  5 - 已取消 (订单最终状态,配送取消不应直接使用此状态)
      */
     const STATUS_MAPPING = [
-        0  => 0,   // 订单生成 -> 订单生成
-        1  => 1,   // 运单生成成功 -> 系统已接单
-        20 => 20,  // 骑手接单 -> 已分配骑手
-        80 => 30,  // 骑手到店 -> 骑手已到店
-        2  => 4,   // 配送中 -> 配送中
-        3  => 5,   // 已完成 -> 已送达
-        4  => -1,  // 已取消 -> 已取消
-        5  => -2,  // 配送异常 -> 异常
+        0  => 2,   // 订单生成 -> 待配送
+        1  => 2,   // 运单生成成功 -> 待配送
+        20 => 2,   // 骑手接单 -> 待配送
+        80 => 2,   // 骑手到店 -> 待配送
+        2  => 3,   // 配送中 -> 配送中
+        3  => 4,   // 已完成 -> 已完成
+        4  => 2,   // 已取消 -> 待配送 (配送取消,可重新派单)
+        5  => 2,   // 配送异常 -> 待配送 (可重新派单)
     ];
 
     /**
-     * 将蜂鸟平台的订单状态转换为系统内的 orderStatus
-     * 
+     * 将蜂鸟平台的订单状态转换为系统内的 status
+     *
      * @param int $fengniaoStatus 蜂鸟平台的订单状态码
-     * @return int 转换后的系统 orderStatus 状态码
+     * @return int 转换后的系统 status 状态码
      * @throws \Exception 当状态码无法转换时抛出异常
      */
-    public static function convertOrderStatus($fengniaoStatus)
+    public static function convertStatus($fengniaoStatus)
     {
         $fengniaoStatus = (int)$fengniaoStatus;
-        
+
         if (!isset(self::STATUS_MAPPING[$fengniaoStatus])) {
             throw new \Exception("无效的蜂鸟订单状态码:{$fengniaoStatus}");
         }
-        
+
         return self::STATUS_MAPPING[$fengniaoStatus];
     }
 
     /**
      * 获取蜂鸟平台的状态描述
-     * 
+     *
      * @param int $fengniaoStatus 蜂鸟平台的订单状态码
      * @return string 状态描述
      */
@@ -83,35 +75,26 @@ class OrderStatusUtil
             4  => '已取消',
             5  => '配送异常',
         ];
-        
+
         return $statusDescMap[$fengniaoStatus] ?? '未知状态';
     }
 
     /**
-     * 获取系统 orderStatus 的状态描述
-     * 
-     * @param int $orderStatus 系统的 orderStatus 状态码
+     * 获取系统 status 的状态描述
+     *
+     * @param int $status 系统的 status 状态码
      * @return string 状态描述
      */
-    public static function getOrderStatusDesc($orderStatus)
+    public static function getSystemStatusDesc($status)
     {
         $statusDescMap = [
-            0   => '订单生成',
-            1   => '系统已接单',
-            2   => '派单中',
-            3   => '待取货',
-            4   => '配送中',
-            5   => '已送达',
-            -1  => '已取消',
-            -2  => '异常',
-            10  => '改派中',
-            20  => '已分配骑手',
-            30  => '骑手已到店',
-            40  => '申请取消中',
-            50  => '客服介入处理中',
+            1 => '待付款',
+            2 => '待配送',
+            3 => '配送中',
+            4 => '已完成',
+            5 => '已取消',
         ];
-        
-        return $statusDescMap[$orderStatus] ?? '未知状态';
-    }
-}
 
+        return $statusDescMap[$status] ?? '未知状态';
+    }
+}

+ 117 - 0
common/components/delivery/platform/fengniao/SendStatusUtil.php

@@ -0,0 +1,117 @@
+<?php
+namespace common\components\delivery\platform\fengniao;
+
+/**
+ * Class FengniaoStatusUtil
+ * 蜂鸟配送平台状态转换工具类
+ * @package common\components\delivery\helpers
+ */
+class SendStatusUtil
+{
+    /**
+     * 蜂鸟平台订单状态到系统 sendStatus 的转换映射
+     * 
+     * 蜂鸟平台状态码说明:
+     *  0 - 订单生成
+     *  1 - 运单生成成功
+     * 20 - 骑手接单
+     * 80 - 骑手到店
+     *  2 - 配送中
+     *  3 - 已完成
+     *  4 - 已取消
+     *  5 - 配送异常
+     * 
+     * 系统内 sendStatus 状态码说明:
+     *  0 - 订单生成
+     *  1 - 系统已接单
+     *  2 - 派单中
+     *  3 - 待取货
+     *  4 - 配送中
+     *  5 - 已送达
+     * -1 - 已取消
+     * -2 - 异常
+     * 10 - 改派中
+     * 20 - 已分配骑手
+     * 30 - 骑手已到店
+     * 40 - 申请取消中
+     * 50 - 客服介入处理中
+     */
+    const STATUS_MAPPING = [
+        0  => 0,   // 订单生成 -> 订单生成
+        1  => 1,   // 运单生成成功 -> 系统已接单
+        20 => 20,  // 骑手接单 -> 已分配骑手
+        80 => 30,  // 骑手到店 -> 骑手已到店
+        2  => 4,   // 配送中 -> 配送中
+        3  => 5,   // 已完成 -> 已送达
+        4  => -1,  // 已取消 -> 已取消
+        5  => -2,  // 配送异常 -> 异常
+    ];
+
+    /**
+     * 将蜂鸟平台的订单状态转换为系统内的 sendStatus
+     * 
+     * @param int $fengniaoStatus 蜂鸟平台的订单状态码
+     * @return int 转换后的系统 orderStatus 状态码
+     * @throws \Exception 当状态码无法转换时抛出异常
+     */
+    public static function convertOrderStatus($fengniaoStatus)
+    {
+        $fengniaoStatus = (int)$fengniaoStatus;
+        
+        if (!isset(self::STATUS_MAPPING[$fengniaoStatus])) {
+            throw new \Exception("无效的蜂鸟订单状态码:{$fengniaoStatus}");
+        }
+        
+        return self::STATUS_MAPPING[$fengniaoStatus];
+    }
+
+    /**
+     * 获取蜂鸟平台的状态描述
+     * 
+     * @param int $fengniaoStatus 蜂鸟平台的订单状态码
+     * @return string 状态描述
+     */
+    public static function getStatusDesc($fengniaoStatus)
+    {
+        $statusDescMap = [
+            0  => '订单生成',
+            1  => '运单生成成功',
+            20 => '骑手接单',
+            80 => '骑手到店',
+            2  => '配送中',
+            3  => '已完成',
+            4  => '已取消',
+            5  => '配送异常',
+        ];
+        
+        return $statusDescMap[$fengniaoStatus] ?? '未知状态';
+    }
+
+    /**
+     * 获取系统 orderStatus 的状态描述
+     * 
+     * @param int $orderStatus 系统的 orderStatus 状态码
+     * @return string 状态描述
+     */
+    public static function getOrderStatusDesc($orderStatus)
+    {
+        $statusDescMap = [
+            0   => '订单生成',
+            1   => '系统已接单',
+            2   => '派单中',
+            3   => '待取货',
+            4   => '配送中',
+            5   => '已送达',
+            -1  => '已取消',
+            -2  => '异常',
+            10  => '改派中',
+            20  => '已分配骑手',
+            30  => '骑手已到店',
+            40  => '申请取消中',
+            50  => '客服介入处理中',
+        ];
+        
+        return $statusDescMap[$orderStatus] ?? '未知状态';
+    }
+}
+

+ 52 - 7
common/components/delivery/platform/huolala/CallBackHandler.php

@@ -34,6 +34,11 @@ class CallBackHandler
                 return false;
             }
 
+            $sendStatus = $this->mapEventTypeToOrderSendStatus($eventType);
+            if ($sendStatus === null) {
+                Yii::warning(sprintf('货拉拉事件未配置状态映射: event_type=%s, order_display_id=%s', $eventType, $orderDisplayId), 'huolala-callback');
+                return true;
+            }
             $orderStatus = $this->mapEventTypeToOrderStatus($eventType);
             if ($orderStatus === null) {
                 Yii::warning(sprintf('货拉拉事件未配置状态映射: event_type=%s, order_display_id=%s', $eventType, $orderDisplayId), 'huolala-callback');
@@ -46,7 +51,7 @@ class CallBackHandler
                 return false;
             }
 
-            $deliveryOrder->orderStatus = $orderStatus;
+            $deliveryOrder->orderStatus = $sendStatus;
             if (!$deliveryOrder->save()) {
                 Yii::error('更新配送订单状态失败: ' . json_encode($deliveryOrder->getErrors(), JSON_UNESCAPED_UNICODE), 'huolala-callback');
                 return false;
@@ -56,16 +61,17 @@ class CallBackHandler
             if(property_exists($deliveryOrder, 'ghsOrderId')){ // 批发
                 $order = OrderClass::getById($deliveryOrder->ghsOrderId, true, 'id,sendStatus,deliveryId,purchaseId,customId,status');
                 if ($order) {
-                    $order->sendStatus = $orderStatus;
+                    $order->sendStatus = $sendStatus;
+                    $order->status = $orderStatus;
                     if (!$order->save()) {
                         Yii::warning('更新主订单配送状态失败: ' . json_encode($order->getErrors(), JSON_UNESCAPED_UNICODE), 'huolala-callback');
                     }
 
                     // 确认送达或取消订单,更新主订单状态
-                    if ($orderStatus == 5) {
+                    if ($sendStatus == 5) {
                         OrderClass::confirmReach($order, ['staffId' => 0, 'staffName' => '']);
                     }
-                    if ($orderStatus == -1 || $orderStatus == -2) {
+                    if ($sendStatus == -1 || $sendStatus == -2) {
                         OrderClass::cancelOrderSend($order, ['staffId' => 0, 'staffName' => '']);
                     }
                 } else {
@@ -74,7 +80,8 @@ class CallBackHandler
             }elseif(property_exists($deliveryOrder, 'hdOrderId')){ // 零售
                 $order = HdOrderClass::getById($deliveryOrder->hdOrderId, true, 'id,sendType,sendStatus,deliveryId,customId,status');
                 if ($order) {
-                    $order->sendStatus = $orderStatus;
+                    $order->sendStatus = $sendStatus;
+                    $order->status = $orderStatus;
                     if (!$order->save()) {
                         Yii::warning('更新主订单配送状态失败: ' . json_encode($order->getErrors(), JSON_UNESCAPED_UNICODE), 'huolala-callback');
                     }
@@ -83,7 +90,7 @@ class CallBackHandler
                 }
             }
 
-            Yii::info(sprintf('货拉拉配送状态更新成功: order_display_id=%s, event_type=%s, orderStatus=%s', $orderDisplayId, $eventType, $orderStatus), 'huolala-callback');
+            Yii::info(sprintf('货拉拉配送状态更新成功: order_display_id=%s, event_type=%s, orderStatus=%s', $orderDisplayId, $eventType, $sendStatus), 'huolala-callback');
             return true;
         } catch (\Throwable $e) {
             Yii::error('货拉拉回调处理异常: ' . $e->getMessage() . ' | Trace: ' . $e->getTraceAsString(), 'huolala-callback');
@@ -97,7 +104,7 @@ class CallBackHandler
      * @param string $eventType
      * @return int|null
      */
-    protected function mapEventTypeToOrderStatus($eventType)
+    protected function mapEventTypeToOrderSendStatus($eventType)
     {
         $map = [
             'order_cancel' => -1,
@@ -122,6 +129,44 @@ class CallBackHandler
         return $map[$eventType] ?? null;
     }
 
+    /**
+     * 事件到系统订单状态的映射
+     *
+     * @param string $eventType
+     * @return int|null
+     */
+    protected function mapEventTypeToOrderStatus($eventType)
+    {
+        // 系统订单状态: 1待付款 2待配送 3配送中 4已完成 5已取消
+        $map = [
+            // 取消状态 (订单终态)
+            'order_cancel' => 2,        // 订单取消 -> 已取消 改为 待配送(配送的取消不等于订单的取消,由于 status 带有配送状态,所以改为:待配送)
+
+            // 回到待配送状态 (可重新派单)
+            'no_load_cancel' => 2,      // 未装货取消 -> 待配送
+            'no_complete_cancel' => 2,  // 未完成取消 -> 待配送
+            'order_timeout' => 2,       // 订单超时 -> 待配送
+            'driver_reject' => 2,       // 司机拒单 -> 待配送
+            'set_order_abnormal' => 2,  // 订单异常 -> 待配送
+            'prepay_ok' => 2,           // 预付成功 -> 待配送
+
+            // 配送中状态
+            'pickup' => 3,              // 已取货 -> 配送中
+            'loading' => 3,             // 装货中 -> 配送中
+            'loaded' => 3,              // 已装货 -> 配送中
+            'unloading' => 3,           // 卸货中 -> 配送中
+            'unload_finish' => 3,       // 卸货完成 -> 配送中
+
+            // 完成状态
+            'order_complete' => 4,          // 订单完成 -> 已完成
+            'order_auto_complete' => 4,     // 订单自动完成 -> 已完成
+            'auto_confirm_bill_pay' => 4,   // 自动确认支付 -> 已完成
+            'rear_pay_ok' => 4,             // 尾款支付成功 -> 已完成
+            'cash_received' => 4,           // 收到现金 -> 已完成
+        ];
+        return $map[$eventType] ?? null;
+    }
+
      /**
      * 根据订单号查找配送订单
      *

+ 5 - 4
common/components/delivery/platform/shansong/OrderStatusCallBack.php

@@ -41,8 +41,8 @@ class OrderStatusCallBack
             
             // 将闪送平台的订单状态转换为系统内的 orderStatus
             $subStatus = isset($data['subStatus']) ? $data['subStatus'] : null;
-            $sendStatus = OrderStatusUtil::convertOrderStatus($data['status'], $subStatus);
-            
+            $sendStatus = SendStatusUtil::convertOrderStatus($data['status'], $subStatus);
+            $orderStatus = OrderStatusUtil::convertStatus($data['status'], $subStatus);
             
             // 处理骑手信息
             $this->handleCourierInfo($data, $deliveryOrder);
@@ -62,6 +62,7 @@ class OrderStatusCallBack
                 $order = OrderClass::getById($deliveryOrder->ghsOrderId, true, 'id,sendType,sendStatus,deliveryId,purchaseId,customId,status');
             }elseif(property_exists($deliveryOrder, 'hdOrderId')){ // 零售
                 $order = HdOrderClass::getById($deliveryOrder->hdOrderId, true, 'id,sendType,sendStatus,deliveryId,customId,status');
+                $order->status = $orderStatus;
             }
             if ($order) {
                 $order->sendStatus = $sendStatus;
@@ -144,9 +145,9 @@ class OrderStatusCallBack
             
             Yii::info($data['issOrderNo'] . '-闪送取消信息: ' . json_encode([
                 'abortType' => $abortType,
-                'abortTypeDesc' => $abortType ? OrderStatusUtil::getAbortTypeDesc($abortType) : '',
+                'abortTypeDesc' => $abortType ? SendStatusUtil::getAbortTypeDesc($abortType) : '',
                 'punishType' => $punishType,
-                'punishTypeDesc' => $punishType ? OrderStatusUtil::getPunishTypeDesc($punishType) : '',
+                'punishTypeDesc' => $punishType ? SendStatusUtil::getPunishTypeDesc($punishType) : '',
                 'abortReason' => $abortReason,
             ], JSON_UNESCAPED_UNICODE), 'shansong-callback');
             

+ 30 - 117
common/components/delivery/platform/shansong/OrderStatusUtil.php

@@ -2,95 +2,53 @@
 namespace common\components\delivery\platform\shansong;
 
 /**
- * Class OrderStatusUtil
- * 闪送配送平台状态转换工具类
- * @package common\components\delivery\platform\shanSong
+ * Class SystemStatusUtil
+ * 闪送配送平台状态转换工具类 (转换为主订单 status)
+ * @package common\components\delivery\platform\shansong
  */
 class OrderStatusUtil
 {
     /**
-     * 闪送平台订单状态到系统 orderStatus 的转换映射
+     * 闪送平台订单状态到系统 status 的转换映射
      * 
      * 闪送平台状态码说明:
      * 20 - 派单中(转单改派中)
-     *      subStatus: 1-派单中, 2-转单改派中
      * 30 - 待取货(已就位)
-     *      subStatus: 1-待取货, 2-已就位
      * 40 - 闪送中(申请取消中、物品送回中、取消单客服介入中)
-     *      subStatus: 1-闪送中, 2-申请取消中, 3-物品送回中, 4-取消单客服介入中
      * 50 - 已完成(已退款)
-     *      subStatus: 1-已完成, 2-已退款
      * 60 - 已取消
      * 
-     * 系统内 orderStatus 状态码说明:
-     *  0 - 订单生成
-     *  1 - 系统已接单
-     *  2 - 派单中
-     *  3 - 待取货
-     *  4 - 配送中
-     *  5 - 已送达
-     * -1 - 已取消
-     * -2 - 异常
-     * 10 - 改派中
-     * 20 - 已分配骑手
-     * 30 - 骑手已到店
-     * 40 - 申请取消中
-     * 50 - 客服介入处理中
+     * 系统内 status 状态码说明:
+     * 1 - 待付款
+     * 2 - 待配送
+     * 3 - 配送中
+     * 4 - 已完成
+     * 5 - 已取消
      */
     const STATUS_MAPPING = [
-        20 => 2,   // 派单中 -> 派单中
-        30 => 3,   // 待取货 -> 待取货
-        40 => 4,   // 闪送中 -> 配送中
-        50 => 5,   // 已完成 -> 已送达
-        60 => -1,  // 已取消 -> 已取消
+        20 => 2,   // 派单中 -> 待配送
+        30 => 2,   // 待取货 -> 待配送
+        40 => 3,   // 闪送中 -> 配送中
+        50 => 4,   // 已完成 -> 已完成
+        60 => 2,   // 已取消 -> 待配送(配送的取消不等于订单的取消,由于 status 带有配送状态,所以改为:待配送)
     ];
 
     /**
-     * 子状态到系统状态的特殊映射
-     * 格式:[主状态 => [子状态 => 系统状态]]
-     */
-    const SUB_STATUS_MAPPING = [
-        20 => [
-            1 => 2,   // 派单中 -> 派单中
-            2 => 10,  // 转单改派中 -> 改派中
-        ],
-        30 => [
-            1 => 3,   // 待取货 -> 待取货
-            2 => 30,  // 已就位 -> 骑手已到店
-        ],
-        40 => [
-            1 => 4,   // 闪送中 -> 配送中
-            2 => 40,  // 申请取消中 -> 申请取消中
-            3 => 4,   // 物品送回中 -> 配送中
-            4 => 50,  // 取消单客服介入中 -> 客服介入处理中
-        ],
-        50 => [
-            1 => 5,   // 已完成 -> 已送达
-            2 => 5,   // 已退款 -> 已送达
-        ],
-    ];
-
-    /**
-     * 将闪送平台的订单状态转换为系统内的 orderStatus
+     * 将闪送平台的订单状态转换为系统内的 status
      * 
      * @param int $shansongStatus 闪送平台的订单状态码
      * @param int|null $subStatus 闪送平台的订单子状态码(可选)
-     * @return int 转换后的系统 orderStatus 状态码
+     * @return int 转换后的系统 status 状态码
      * @throws \Exception 当状态码无法转换时抛出异常
      */
-    public static function convertOrderStatus($shansongStatus, $subStatus = null)
+    public static function convertStatus($shansongStatus, $subStatus = null)
     {
         $shansongStatus = (int)$shansongStatus;
         
-        // 如果提供了子状态,优先使用子状态映射
-        if ($subStatus !== null) {
-            $subStatus = (int)$subStatus;
-            if (isset(self::SUB_STATUS_MAPPING[$shansongStatus][$subStatus])) {
-                return self::SUB_STATUS_MAPPING[$shansongStatus][$subStatus];
-            }
-        }
+        // 此处不需要子状态映射,因为系统 status 状态较粗粒度
+        // 20(派单中), 30(待取货) 都对应 2(待配送)
+        // 40(闪送中) 对应 3(配送中)
         
-        // 使用主状态映射
         if (!isset(self::STATUS_MAPPING[$shansongStatus])) {
             throw new \Exception("无效的闪送订单状态码:{$shansongStatus}");
         }
@@ -132,66 +90,21 @@ class OrderStatusUtil
     }
 
     /**
-     * 获取系统 orderStatus 的状态描述
+     * 获取系统 status 的状态描述
      * 
-     * @param int $orderStatus 系统的 orderStatus 状态码
+     * @param int $status 系统的 status 状态码
      * @return string 状态描述
      */
-    public static function getOrderStatusDesc($orderStatus)
+    public static function getSystemStatusDesc($status)
     {
         $statusDescMap = [
-            0   => '订单生成',
-            1   => '系统已接单',
-            2   => '派单中',
-            3   => '待取货',
-            4   => '配送中',
-            5   => '已送达',
-            -1  => '已取消',
-            -2  => '异常',
-            10  => '改派中',
-            20  => '已分配骑手',
-            30  => '骑手已到店',
-            40  => '申请取消中',
-            50  => '客服介入处理中',
-        ];
-        
-        return $statusDescMap[$orderStatus] ?? '未知状态';
-    }
-
-    /**
-     * 获取取消发起人描述
-     * 
-     * @param int $abortType 取消发起人类型
-     * @return string 描述
-     */
-    public static function getAbortTypeDesc($abortType)
-    {
-        $descMap = [
-            1  => '客户发起取消',
-            3  => '闪送员发起取消',
-            10 => '系统自动发起取消',
+            1 => '待付款',
+            2 => '待配送',
+            3 => '配送中',
+            4 => '已完成',
+            5 => '已取消',
         ];
         
-        return $descMap[$abortType] ?? '未知';
-    }
-
-    /**
-     * 获取取消责任人描述
-     * 
-     * @param int $punishType 取消责任人类型
-     * @return string 描述
-     */
-    public static function getPunishTypeDesc($punishType)
-    {
-        $descMap = [
-            1  => '因客户',
-            2  => '因服务',
-            3  => '因闪送员',
-            10 => '因系统自动取消',
-            99 => '因其它',
-        ];
-        
-        return $descMap[$punishType] ?? '未知';
+        return $statusDescMap[$status] ?? '未知状态';
     }
 }
-

+ 197 - 0
common/components/delivery/platform/shansong/SendStatusUtil.php

@@ -0,0 +1,197 @@
+<?php
+namespace common\components\delivery\platform\shansong;
+
+/**
+ * Class OrderStatusUtil
+ * 闪送配送平台状态转换工具类
+ * @package common\components\delivery\platform\shanSong
+ */
+class SendStatusUtil
+{
+    /**
+     * 闪送平台订单状态到系统 orderStatus 的转换映射
+     * 
+     * 闪送平台状态码说明:
+     * 20 - 派单中(转单改派中)
+     *      subStatus: 1-派单中, 2-转单改派中
+     * 30 - 待取货(已就位)
+     *      subStatus: 1-待取货, 2-已就位
+     * 40 - 闪送中(申请取消中、物品送回中、取消单客服介入中)
+     *      subStatus: 1-闪送中, 2-申请取消中, 3-物品送回中, 4-取消单客服介入中
+     * 50 - 已完成(已退款)
+     *      subStatus: 1-已完成, 2-已退款
+     * 60 - 已取消
+     * 
+     * 系统内 orderStatus 状态码说明:
+     *  0 - 订单生成
+     *  1 - 系统已接单
+     *  2 - 派单中
+     *  3 - 待取货
+     *  4 - 配送中
+     *  5 - 已送达
+     * -1 - 已取消
+     * -2 - 异常
+     * 10 - 改派中
+     * 20 - 已分配骑手
+     * 30 - 骑手已到店
+     * 40 - 申请取消中
+     * 50 - 客服介入处理中
+     */
+    const STATUS_MAPPING = [
+        20 => 2,   // 派单中 -> 派单中
+        30 => 3,   // 待取货 -> 待取货
+        40 => 4,   // 闪送中 -> 配送中
+        50 => 5,   // 已完成 -> 已送达
+        60 => -1,  // 已取消 -> 已取消
+    ];
+
+    /**
+     * 子状态到系统状态的特殊映射
+     * 格式:[主状态 => [子状态 => 系统状态]]
+     */
+    const SUB_STATUS_MAPPING = [
+        20 => [
+            1 => 2,   // 派单中 -> 派单中
+            2 => 10,  // 转单改派中 -> 改派中
+        ],
+        30 => [
+            1 => 3,   // 待取货 -> 待取货
+            2 => 30,  // 已就位 -> 骑手已到店
+        ],
+        40 => [
+            1 => 4,   // 闪送中 -> 配送中
+            2 => 40,  // 申请取消中 -> 申请取消中
+            3 => 4,   // 物品送回中 -> 配送中
+            4 => 50,  // 取消单客服介入中 -> 客服介入处理中
+        ],
+        50 => [
+            1 => 5,   // 已完成 -> 已送达
+            2 => 5,   // 已退款 -> 已送达
+        ],
+    ];
+
+    /**
+     * 将闪送平台的订单状态转换为系统内的 orderStatus
+     * 
+     * @param int $shansongStatus 闪送平台的订单状态码
+     * @param int|null $subStatus 闪送平台的订单子状态码(可选)
+     * @return int 转换后的系统 orderStatus 状态码
+     * @throws \Exception 当状态码无法转换时抛出异常
+     */
+    public static function convertOrderStatus($shansongStatus, $subStatus = null)
+    {
+        $shansongStatus = (int)$shansongStatus;
+        
+        // 如果提供了子状态,优先使用子状态映射
+        if ($subStatus !== null) {
+            $subStatus = (int)$subStatus;
+            if (isset(self::SUB_STATUS_MAPPING[$shansongStatus][$subStatus])) {
+                return self::SUB_STATUS_MAPPING[$shansongStatus][$subStatus];
+            }
+        }
+        
+        // 使用主状态映射
+        if (!isset(self::STATUS_MAPPING[$shansongStatus])) {
+            throw new \Exception("无效的闪送订单状态码:{$shansongStatus}");
+        }
+        
+        return self::STATUS_MAPPING[$shansongStatus];
+    }
+
+    /**
+     * 获取闪送平台的状态描述
+     * 
+     * @param int $shansongStatus 闪送平台的订单状态码
+     * @param int|null $subStatus 闪送平台的订单子状态码(可选)
+     * @return string 状态描述
+     */
+    public static function getStatusDesc($shansongStatus, $subStatus = null)
+    {
+        $mainStatusDescMap = [
+            20 => '派单中',
+            30 => '待取货',
+            40 => '闪送中',
+            50 => '已完成',
+            60 => '已取消',
+        ];
+        
+        $subStatusDescMap = [
+            20 => [1 => '派单中', 2 => '转单改派中'],
+            30 => [1 => '待取货', 2 => '已就位'],
+            40 => [1 => '闪送中', 2 => '申请取消中', 3 => '物品送回中', 4 => '取消单客服介入中'],
+            50 => [1 => '已完成', 2 => '已退款'],
+        ];
+        
+        $mainDesc = $mainStatusDescMap[$shansongStatus] ?? '未知状态';
+        
+        if ($subStatus !== null && isset($subStatusDescMap[$shansongStatus][$subStatus])) {
+            return $subStatusDescMap[$shansongStatus][$subStatus];
+        }
+        
+        return $mainDesc;
+    }
+
+    /**
+     * 获取系统 orderStatus 的状态描述
+     * 
+     * @param int $orderStatus 系统的 orderStatus 状态码
+     * @return string 状态描述
+     */
+    public static function getOrderStatusDesc($orderStatus)
+    {
+        $statusDescMap = [
+            0   => '订单生成',
+            1   => '系统已接单',
+            2   => '派单中',
+            3   => '待取货',
+            4   => '配送中',
+            5   => '已送达',
+            -1  => '已取消',
+            -2  => '异常',
+            10  => '改派中',
+            20  => '已分配骑手',
+            30  => '骑手已到店',
+            40  => '申请取消中',
+            50  => '客服介入处理中',
+        ];
+        
+        return $statusDescMap[$orderStatus] ?? '未知状态';
+    }
+
+    /**
+     * 获取取消发起人描述
+     * 
+     * @param int $abortType 取消发起人类型
+     * @return string 描述
+     */
+    public static function getAbortTypeDesc($abortType)
+    {
+        $descMap = [
+            1  => '客户发起取消',
+            3  => '闪送员发起取消',
+            10 => '系统自动发起取消',
+        ];
+        
+        return $descMap[$abortType] ?? '未知';
+    }
+
+    /**
+     * 获取取消责任人描述
+     * 
+     * @param int $punishType 取消责任人类型
+     * @return string 描述
+     */
+    public static function getPunishTypeDesc($punishType)
+    {
+        $descMap = [
+            1  => '因客户',
+            2  => '因服务',
+            3  => '因闪送员',
+            10 => '因系统自动取消',
+            99 => '因其它',
+        ];
+        
+        return $descMap[$punishType] ?? '未知';
+    }
+}
+

+ 33 - 6
common/components/delivery/platform/shunfeng/CallBackHandler.php

@@ -117,7 +117,9 @@ class CallBackHandler
 
         $orderStatus = $data['order_status'];
         // 转换顺丰订单状态到系统状态
-        $sendStatus = $this->convertOrderStatus($orderStatus);
+        $sendStatus = $this->convertOrderSendStatus($orderStatus);
+        $orderStatus = $this->convertOrderStatus($orderStatus);
+
         if ($sendStatus !== null) {
             // 更新配送订单
             $deliveryOrder->orderStatus = $sendStatus;
@@ -128,12 +130,14 @@ class CallBackHandler
                 $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
                 if ($order) {
                     $order->sendStatus = $sendStatus;
+                    $order->status = $orderStatus;
                     $order->save();
                 }
             }elseif(property_exists($deliveryOrder, 'hdOrderId')){ // 零售
                 $order = HdOrderClass::getById($deliveryOrder->hdOrderId, true);
                 if ($order) {
                     $order->sendStatus = $sendStatus;
+                    $order->status = $orderStatus;
                     $order->save();
                 }
             }
@@ -169,7 +173,7 @@ class CallBackHandler
             return false;
         }
         
-        $sendStatus = $this->convertOrderStatus($data['order_status']);
+        $sendStatus = $this->convertOrderSendStatus($data['order_status']);
         if ($sendStatus === null) {
             Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
             return false;
@@ -226,7 +230,7 @@ class CallBackHandler
             return false;
         }
         
-        $sendStatus = $this->convertOrderStatus($data['order_status']);
+        $sendStatus = $this->convertOrderSendStatus($data['order_status']);
         if ($sendStatus === null) {
             Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
             return false;
@@ -283,7 +287,7 @@ class CallBackHandler
             return false;
         }
         
-        $sendStatus = $this->convertOrderStatus($data['order_status']);
+        $sendStatus = $this->convertOrderSendStatus($data['order_status']);
         if ($sendStatus === null) {
             Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
             return false;
@@ -340,7 +344,7 @@ class CallBackHandler
             return false;
         }
         
-        $sendStatus = $this->convertOrderStatus($data['order_status']);
+        $sendStatus = $this->convertOrderSendStatus($data['order_status']);
         if ($sendStatus === null) {
             Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
             return false;
@@ -485,7 +489,7 @@ class CallBackHandler
      * @param int $sfOrderStatus 顺丰订单状态
      * @return int|null 系统配送状态,null表示不需要更新主订单状态
      */
-    private function convertOrderStatus($sfOrderStatus)
+    private function convertOrderSendStatus($sfOrderStatus)
     {
         // 顺丰状态映射到系统配送状态
         $statusMap = [
@@ -501,6 +505,29 @@ class CallBackHandler
         return $statusMap[$sfOrderStatus] ?? null;
     }
 
+    /**
+     * 转换顺丰订单状态到系统订单状态
+     * 
+     * @param int $sfOrderStatus 顺丰订单状态
+     * @return int|null 系统订单状态,null表示不需要更新主订单状态
+     */
+    private function convertOrderStatus($sfOrderStatus)
+    {
+        // 顺丰状态映射到系统订单状态
+        // 系统订单状态: 1待付款 2待配送 3配送中 4已完成 5已取消
+        $statusMap = [
+            10 => 2,  // 配送员接单/改派 -> 待配送
+            12 => 2,  // 配送员到店 -> 待配送
+            15 => 3,  // 配送员配送中 -> 配送中
+            17 => 4,  // 配送完成 -> 已完成
+            2  => 2,  // 订单取消 -> 待配送(配送的取消不等于订单的取消,由于 status 带有配送状态,所以改为:待配送)
+            22 => 2,  // 配送员撤单 -> 待配送 (重新派单)
+            91 => 2,  // 骑士上报异常 -> 异常 (不更新主状态)
+        ];
+        
+        return $statusMap[$sfOrderStatus] ?? null;
+    }
+
     /**
      * 根据顺丰订单号查找配送订单
      *