|
|
@@ -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;
|
|
|
+ }
|
|
|
+}
|