Parcourir la source

顺丰回调处理类完成

shizhongqi il y a 8 mois
Parent
commit
3cd2cb2f39

+ 36 - 19
app-ghs/controllers/DeliveryController.php

@@ -21,7 +21,7 @@ use Yii;
 class DeliveryController extends BaseController
 {
     public $guestAccess = ['callback', 'shansong-auth-callback', 'huolala-auth-callback',
-        'fengniao-callback', 'shansong-callback', 'huolala-callback'];
+        'fengniao-callback', 'shansong-callback', 'huolala-callback', 'shunfeng-callback'];
 
     public function actionList()
     {
@@ -261,7 +261,8 @@ class DeliveryController extends BaseController
                         'en_name' => 'shunfeng',
                         'price' => $item['real_pay_money'],
                         'distance' => $item['distance'],
-                        'type' => ''
+                        'type' => '',
+                        'isAble' => true
                     ];
                     break;
                 case 'shansong':
@@ -271,7 +272,8 @@ class DeliveryController extends BaseController
                         'price' => $item['total_amount'],
                         'distance' => $item['total_distance'],
                         'type' => '',
-                        'issOrderNo' => $item['order_number'] //
+                        'issOrderNo' => $item['order_number'],
+                        'isAble' => true
                     ];
                     break;
                 case 'fengniao':
@@ -284,17 +286,29 @@ class DeliveryController extends BaseController
                                     'actual_delivery_amount_cent' => $good['actual_delivery_amount_cent'] ?? 0,
                                     'service_goods_id' => $good['service_goods_id'] ?? ''
                                 ];
+
+                                $deliveryList[] = [
+                                    'name' => '蜂鸟'. ' (' .$good['base_goods_id'] . ')',
+                                    'en_name' => 'fengniao',
+                                    'price' => $good['actual_delivery_amount_cent'],
+                                    'distance' => $item['distance'],
+                                    'valid_goods' => $validGoods,
+                                    'type' => '',
+                                    'isAble' => true
+                                ];
+                            } else {
+                                $deliveryList[] = [
+                                    'name' => '蜂鸟'. ' (' .$good['base_goods_id'] . ')',
+                                    'en_name' => 'fengniao',
+                                    'price' => 0,
+                                    'distance' => $item['distance'],
+                                    'valid_goods' => $good,
+                                    'type' => $good['disable_reason'],
+                                    'isAble' => false
+                                ];
                             }
                         }
                     }
-                    $deliveryList[] = [
-                        'name' => '蜂鸟',
-                        'en_name' => 'fengniao',
-                        'price' => !empty($validGoods) ? $validGoods[0]['actual_delivery_amount_cent'] : 0,
-                        'distance' => $item['distance'],
-                        'valid_goods' => $validGoods,  // 返回所有有效的商品信息
-                        'type' => ''
-                    ];
                     break;
                 case 'huolala':
                     $deliveryList = [];
@@ -307,6 +321,8 @@ class DeliveryController extends BaseController
                             'price' => $priceInfo['price_conditions'][0]['price_info']['total_price'],
                             'distance' => $priceInfo['distance_info']['distance_total'],
                             'type' => $vehicleType['_meta']['vehicle_type'],
+                            'isAble' => true,
+                            // ---------------------------------------------
                             'order_vehicle_id' => $vehicleType['order_vehicle_id'],
                             'city_id' => $item['city_id'],
                             'city_info_revision' => $vehicleType['city_info_revision'],
@@ -551,12 +567,6 @@ class DeliveryController extends BaseController
     public function actionFengniaoCallback()
     {
         $callbackData = Yii::$app->request->post();
-        if (empty($callbackData)) {
-            $postStr = file_get_contents('php://input');
-            $callbackData = json_decode($postStr, true);
-        }
-        Yii::info('fengniao 回调 -- post: ' . json_encode($callbackData));
-
         // 逆向回调接口结果的加签
         $param = [
             'app_id' => $callbackData['app_id'],
@@ -599,8 +609,15 @@ class DeliveryController extends BaseController
      */
     public function actionShunfengCallback()
     {
-        // 1.配送状态更改  2.订单完成  3.顺丰原因取消  4.订单配送异常  5.骑士撤单  6.自动建店回调
-
+        $post = Yii::$app->request->post();
+        $cbh = new \common\components\delivery\platform\shunfeng\CallBackHandler();
+        $ret = $cbh->handle($post);// 1.配送状态更改  2.订单完成  3.顺丰原因取消  4.订单配送异常  5.骑士撤单  6.自动建店回调
+        if($ret) {
+            return $this->asJson(['error_code' => 0, 'error_msg' => 'success']);
+        } else {
+            Yii::error('顺丰回调失败: ' . json_encode($post, JSON_UNESCAPED_UNICODE));
+            return $this->asJson(['error_code' => -1, 'error_msg' => 'failed']);
+        }
     }
 
 

+ 369 - 0
common/components/delivery/platform/shunfeng/CallBackHandler.php

@@ -0,0 +1,369 @@
+<?php
+namespace common\components\delivery\platform\shunfeng;
+
+use bizGhs\express\classes\GhsDeliveryOrderClass;
+use bizGhs\order\classes\OrderClass;
+use Yii;
+
+/**
+ * 顺丰同城回调处理类
+ * 处理顺丰平台的各种回调通知
+ * 
+ * Class CallBackHandler
+ * @package common\components\delivery\platform\shunfeng
+ */
+class CallBackHandler
+{
+    /**
+     * 处理顺丰回调
+     * 根据 url_index 参数判断回调类型并分发到对应的处理方法
+     * 
+     * @param array $data 回调数据
+     * @return bool 处理结果
+     */
+    public function handle($data)
+    {
+        try {
+            // 记录回调原始数据
+            Yii::info('顺丰同城回调 - 原始数据: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+            
+            // 验证必要参数
+            if (empty($data['url_index'])) {
+                Yii::error('顺丰回调缺少 url_index 参数: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+                return false;
+            }
+            
+            $urlIndex = $data['url_index'];
+            
+            // 根据回调类型分发处理
+            switch ($urlIndex) {
+                case 'rider_status':
+                    // 配送状态更改回调
+                    return $this->handleRiderStatus($data);
+                    
+                case 'order_complete':
+                    // 订单完成回调
+                    return $this->handleOrderComplete($data);
+                    
+                case 'sf_cancel':
+                    // 顺丰原因取消回调
+                    return $this->handleSfCancel($data);
+                    
+                case 'rider_exception':
+                    // 订单异常回调
+                    return $this->handleRiderException($data);
+                    
+                case 'rider_recall':
+                    // 骑士撤单回调
+                    return $this->handleRiderRecall($data);
+                    
+                default:
+                    Yii::warning('未知的顺丰回调类型: ' . $urlIndex, 'shunfeng-callback');
+                    return false;
+            }
+            
+        } catch (\Exception $e) {
+            Yii::error('顺丰回调处理异常: ' . $e->getMessage() . ' | ' . $e->getTraceAsString(), 'shunfeng-callback');
+            return false;
+        }
+    }
+    
+    /**
+     * 处理配送状态更改回调
+     * 状态包括:10-配送员接单/改派;12-配送员到店;15-配送员配送中
+     * 
+     * @param array $data 回调数据
+     * @return bool 处理结果
+     */
+    private function handleRiderStatus($data)
+    {
+        Yii::info('顺丰配送状态更改回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+        
+        // 验证必要参数
+        if (empty($data['sf_order_id']) || !isset($data['order_status'])) {
+            Yii::error('顺丰配送状态回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+            return false;
+        }
+        
+        $orderId = $data['sf_order_id'];
+        
+        // 查找配送订单
+        $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
+            'deliveryId' => 'shunfeng',
+            'orderId' => $orderId
+        ], true);
+        
+        if (!$deliveryOrder) {
+            Yii::error('顺丰配送订单不存在: sf_order_id=' . $orderId, 'shunfeng-callback');
+            return false;
+        }
+        
+        // 更新配送订单信息
+        $updateData = [];
+        // 更新配送员信息
+        $updateData['riderName'] = $data['operator_name'];
+        $updateData['riderPhone'] = $data['operator_phone'];
+        $updateData['riderLng'] = $data['rider_lng'];
+        $updateData['riderLat'] = $data['rider_lat'];
+        $updateData['statusDesc'] = $data['status_desc'];
+        $updateData['pushTime'] = date('Y-m-d H:i:s', $data['push_time']);
+
+        $orderStatus = $data['order_status'];
+        // 转换顺丰订单状态到系统状态
+        $sendStatus = $this->convertOrderStatus($orderStatus);
+        if ($sendStatus !== null) {
+            // 更新配送订单
+            $deliveryOrder->orderStatus = $sendStatus;
+            $deliveryOrder->save();
+            
+            // 更新主订单的配送状态
+            $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
+            if ($order) {
+                $order->sendStatus = $sendStatus;
+                $order->save();
+            }
+        } else {
+            return false;
+        }
+        
+        return true;
+    }
+    
+    /**
+     * 处理订单完成回调
+     * 订单状态:17-配送员点击完成
+     * 
+     * @param array $data 回调数据
+     * @return bool 处理结果
+     */
+    private function handleOrderComplete($data)
+    {
+        Yii::info('顺丰订单完成回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+        
+        // 验证必要参数
+        if (empty($data['sf_order_id'])) {
+            Yii::error('顺丰订单完成回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+            return false;
+        }
+        
+        $orderId = $data['sf_order_id'];
+        
+        // 查找配送订单
+        $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
+            'deliveryId' => 'shunfeng',
+            'orderId' => $orderId
+        ], true);
+        
+        if (!$deliveryOrder) {
+            Yii::error('顺丰配送订单不存在: sf_order_id=' . $orderId, 'shunfeng-callback');
+            return false;
+        }
+        
+        $sendStatus = $this->convertOrderStatus($data['order_status']);
+        if ($sendStatus === null) {
+            Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
+            return false;
+        }
+        $deliveryOrder->orderStatus = $sendStatus;
+        $deliveryOrder->save();
+        
+        // 更新主订单状态为已送达
+        $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
+        if ($order) {
+            $order->sendStatus = $sendStatus;
+            $order->save();
+        }
+        
+        return true;
+    }
+    
+    /**
+     * 处理顺丰原因取消回调
+     * 订单状态:2-订单取消
+     * 
+     * @param array $data 回调数据
+     * @return bool 处理结果
+     */
+    private function handleSfCancel($data)
+    {
+        Yii::info('顺丰取消订单回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+        
+        // 验证必要参数
+        if (empty($data['sf_order_id'])) {
+            Yii::error('顺丰取消回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+            return false;
+        }
+        
+        $orderId = $data['sf_order_id'];
+        
+        // 查找配送订单
+        $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
+            'deliveryId' => 'shunfeng',
+            'orderId' => $orderId
+        ], true);
+        
+        if (!$deliveryOrder) {
+            Yii::error('顺丰配送订单不存在: sf_order_id=' . $orderId, 'shunfeng-callback');
+            return false;
+        }
+        
+        $sendStatus = $this->convertOrderStatus($data['order_status']);
+        if ($sendStatus === null) {
+            Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
+            return false;
+        }
+        $deliveryOrder->orderStatus = $sendStatus;
+        $deliveryOrder->save();
+        
+        // 更新主订单状态为取消
+        $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
+        if ($order) {
+            $order->sendStatus = OrderClass::SEND_STATUS_CANCEL;
+            $order->save();
+        }
+        
+        return true;
+    }
+    
+    /**
+     * 处理订单异常回调
+     * 订单状态:91-骑士上报异常
+     * 
+     * @param array $data 回调数据
+     * @return bool 处理结果
+     */
+    private function handleRiderException($data)
+    {
+        Yii::info('顺丰订单异常回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+        
+        // 验证必要参数
+        if (empty($data['sf_order_id'])) {
+            Yii::error('顺丰异常回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+            return false;
+        }
+        
+        $orderId = $data['sf_order_id'];
+        
+        // 查找配送订单
+        $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
+            'deliveryId' => 'shunfeng',
+            'orderId' => $orderId
+        ], true);
+        
+        if (!$deliveryOrder) {
+            Yii::error('顺丰配送订单不存在: sf_order_id=' . $orderId, 'shunfeng-callback');
+            return false;
+        }
+        
+        $sendStatus = $this->convertOrderStatus($data['order_status']);
+        if ($sendStatus === null) {
+            Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
+            return false;
+        }
+        $deliveryOrder->orderStatus = $sendStatus;
+        $deliveryOrder->save();
+
+        // 更新主订单状态为异常
+        $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
+        if ($order) {
+            $order->sendStatus = $sendStatus;
+            $order->save();
+        }
+        
+        return true;
+    }
+    
+    /**
+     * 处理骑士撤单回调
+     * 订单状态:22-配送员撤单
+     * 
+     * @param array $data 回调数据
+     * @return bool 处理结果
+     */
+    private function handleRiderRecall($data)
+    {
+        Yii::info('顺丰骑士撤单回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+        
+        // 验证必要参数
+        if (empty($data['shop_order_id'])) {
+            Yii::error('顺丰撤单回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
+            return false;
+        }
+        
+        $shopOrderId = $data['shop_order_id'];
+        
+        // 查找配送订单
+        $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
+            'deliveryId' => 'shunfeng',
+            'orderId' => $shopOrderId
+        ], true);
+        
+        if (!$deliveryOrder) {
+            Yii::error('顺丰配送订单不存在: shop_order_id=' . $shopOrderId, 'shunfeng-callback');
+            return false;
+        }
+        
+        $sendStatus = $this->convertOrderStatus($data['order_status']);
+        if ($sendStatus === null) {
+            Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
+            return false;
+        }
+        $deliveryOrder->orderStatus = $sendStatus;
+        $deliveryOrder->save();
+
+        // 更新主订单状态为派单中
+        $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
+        if ($order) {
+            $order->sendStatus = $sendStatus;
+            $order->save();
+        }
+        
+        return true;
+    }
+    
+    /**
+     * 转换顺丰订单状态到系统配送状态
+     * 
+     * 顺丰状态说明:
+     * - 10: 配送员接单/配送员改派
+     * - 12: 配送员到店
+     * - 15: 配送员配送中
+     * - 17: 配送员点击完成
+     * - 2:  订单取消
+     * - 22: 配送员撤单
+     * - 91: 骑士上报异常
+     * 
+     * 系统状态说明:
+     * - 0:  订单生成
+     * - 1:  系统已接单
+     * - 2:  派单中
+     * - 3:  待取货
+     * - 4:  配送中
+     * - 5:  已送达
+     * - -1: 已取消
+     * - -2: 异常
+     * - 10: 改派中
+     * - 20: 已分配骑手
+     * - 30: 骑手已到店
+     * - 40: 申请取消中
+     * - 50: 客服介入处理中
+     * 
+     * @param int $sfOrderStatus 顺丰订单状态
+     * @return int|null 系统配送状态,null表示不需要更新主订单状态
+     */
+    private function convertOrderStatus($sfOrderStatus)
+    {
+        // 顺丰状态映射到系统配送状态
+        $statusMap = [
+            10 => 20,  // 配送员接单/改派 -> 已分配骑手
+            12 => 30,  // 配送员到店 -> 骑手已到店
+            15 => 4,   // 配送员配送中 -> 配送中
+            17 => 5,   // 配送完成 -> 已送达
+            2  => -1,  // 订单取消 -> 已取消
+            22 => 2,   // 配送员撤单 -> 派单中(重新派单)
+            91 => -2,  // 骑士上报异常 -> 异常
+        ];
+        
+        return $statusMap[$sfOrderStatus] ?? null;
+    }
+}

+ 1 - 9
common/components/delivery/services/DispatchService.php

@@ -63,14 +63,6 @@ class DispatchService
             }
             $this->platformName = $platform;
         }
-
-        //$this->adapters = [
-            //'meituan'  => new MeituanAdapter(),
-            //'dada'     => new DadaAdapter(),
-            //'sf'       => new SFAdapter(),
-            //'uu'       => new UUAdapter(),
-            //'fengniao' => new FengniaoAdapter(),
-        //];
     }
 
     /**
@@ -459,7 +451,7 @@ class DispatchService
                 // 根据平台类型调用相应的 buildPriceRequest(s) 方法
                 if ($platform === 'huolala') {
                     // 货拉拉返回多个请求(一个请求对应一个车型)
-                    $priceRequests = $adapter->buildPriceRequests($data, $orderTime);
+                    $priceRequests = $adapter->buildPriceRequest($data, $orderTime);
                     foreach ($priceRequests as $requestKey => $requestInfo) {
                         $allRequests[$requestKey] = $requestInfo;
                         $platformMapping[$requestKey] = ['platform' => 'huolala', 'data' => $data];

+ 1 - 1
common/components/delivery/services/adapter/Adapter.php

@@ -8,5 +8,5 @@ interface Adapter
 {
     public function cityList();
     public function createOrder($order);
-    public function getPrice($orderData, $orderTime);
+    public function buildPriceRequest($data, $orderTime);
 }

+ 3 - 3
common/components/delivery/services/adapter/FengniaoAdapter.php

@@ -628,9 +628,9 @@ class FengniaoAdapter implements Adapter
      */
     public function getPrice($data, $orderTime)
     {
-        $request = $this->buildPriceRequest($data, $orderTime);
-        $resp = HttpClient::post($request['url'], $request['data'], $request['headers']);
-        return $this->processPriceResponse($resp);
+//        $request = $this->buildPriceRequest($data, $orderTime);
+//        $resp = HttpClient::post($request['url'], $request['data'], $request['headers']);
+//        return $this->processPriceResponse($resp);
     }
 
     /**

+ 1 - 1
common/components/delivery/services/adapter/HuolalaAdapter.php

@@ -530,7 +530,7 @@ class HuolalaAdapter implements Adapter
      * @param string $orderTime 配送时间
      * @return array 请求信息列表,以车型ID为键
      */
-    public function buildPriceRequests($data, $orderTime)
+    public function buildPriceRequest($data, $orderTime)
     {
         //用车时间 -- 用车时间(unix时间戳:秒)。 取值范围:(当前时间+10分钟)<=用车时间<=(当前时间+5天)
         $orderTime = strtotime($orderTime);

+ 14 - 19
common/components/delivery/services/adapter/ShunfengAdapter.php

@@ -157,6 +157,10 @@ class ShunfengAdapter
         return $data;
     }
 
+    /**
+     * @param $data
+     * @return array
+     */
     public function createOrder($data)
     {
         $resp = $this->httpRequest('createorder', $data);
@@ -188,17 +192,16 @@ class ShunfengAdapter
 
     public function getPrice($data)
     {
-        $requestData = [
-            "user_lng" => "116.339392",
-            "user_lat" => "40.002349",
-            "user_address" => "北京市海淀区国泰大厦",
-            "weight" => 1000,
-            "product_type" => 4,
-            "push_time" => 1639558442
-        ];
-        $method = 'precreateorder';
-        $ret = $this->httpRequest($method, $requestData);
-
+//        $requestData = [
+//            "user_lng" => "116.339392",
+//            "user_lat" => "40.002349",
+//            "user_address" => "北京市海淀区国泰大厦",
+//            "weight" => 1000,
+//            "product_type" => 4,
+//            "push_time" => 1639558442
+//        ];
+//        $method = 'precreateorder';
+//        $ret = $this->httpRequest($method, $requestData);
     }
 
     /**
@@ -210,14 +213,6 @@ class ShunfengAdapter
     public function processPriceResponse($resp)
     {
         if (isset($resp['error_code']) && $resp['error_code'] == 0 && isset($resp['result'])) {
-            //return $resp['result'];
-//            return [
-//                'platform' => 'fengniao',
-//                'distance' => (int)($respData['distance'] ?? 0),
-//                'time' => (int)($respData['time'] ?? 0),
-//                'goods_infos' => $goodsInfos,
-//            ];
-
             $result = $resp['result'];
             return [
                 'platform' => 'shunfeng',