CallBackHandler.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <?php
  2. namespace common\components\delivery\platform\shunfeng;
  3. use bizGhs\express\classes\GhsDeliveryOrderClass;
  4. use bizGhs\order\classes\OrderClass;
  5. use Yii;
  6. /**
  7. * 顺丰同城回调处理类
  8. * 处理顺丰平台的各种回调通知
  9. *
  10. * Class CallBackHandler
  11. * @package common\components\delivery\platform\shunfeng
  12. */
  13. class CallBackHandler
  14. {
  15. /**
  16. * 处理顺丰回调
  17. * 根据 url_index 参数判断回调类型并分发到对应的处理方法
  18. *
  19. * @param array $data 回调数据
  20. * @return bool 处理结果
  21. */
  22. public function handle($data)
  23. {
  24. try {
  25. // 记录回调原始数据
  26. Yii::info('顺丰同城回调 - 原始数据: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  27. // 验证必要参数
  28. if (empty($data['url_index'])) {
  29. Yii::error('顺丰回调缺少 url_index 参数: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  30. return false;
  31. }
  32. $urlIndex = $data['url_index'];
  33. // 根据回调类型分发处理
  34. switch ($urlIndex) {
  35. case 'rider_status':
  36. // 配送状态更改回调
  37. return $this->handleRiderStatus($data);
  38. case 'order_complete':
  39. // 订单完成回调
  40. return $this->handleOrderComplete($data);
  41. case 'sf_cancel':
  42. // 顺丰原因取消回调
  43. return $this->handleSfCancel($data);
  44. case 'rider_exception':
  45. // 订单异常回调
  46. return $this->handleRiderException($data);
  47. case 'rider_recall':
  48. // 骑士撤单回调
  49. return $this->handleRiderRecall($data);
  50. default:
  51. Yii::warning('未知的顺丰回调类型: ' . $urlIndex, 'shunfeng-callback');
  52. return false;
  53. }
  54. } catch (\Exception $e) {
  55. Yii::error('顺丰回调处理异常: ' . $e->getMessage() . ' | ' . $e->getTraceAsString(), 'shunfeng-callback');
  56. return false;
  57. }
  58. }
  59. /**
  60. * 处理配送状态更改回调
  61. * 状态包括:10-配送员接单/改派;12-配送员到店;15-配送员配送中
  62. *
  63. * @param array $data 回调数据
  64. * @return bool 处理结果
  65. */
  66. private function handleRiderStatus($data)
  67. {
  68. Yii::info('顺丰配送状态更改回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  69. // 验证必要参数
  70. if (empty($data['sf_order_id']) || !isset($data['order_status'])) {
  71. Yii::error('顺丰配送状态回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  72. return false;
  73. }
  74. $orderId = $data['sf_order_id'];
  75. // 查找配送订单
  76. $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
  77. 'deliveryId' => 'shunfeng',
  78. 'orderId' => $orderId
  79. ], true);
  80. if (!$deliveryOrder) {
  81. Yii::error('顺丰配送订单不存在: sf_order_id=' . $orderId, 'shunfeng-callback');
  82. return false;
  83. }
  84. // 更新配送订单信息
  85. $updateData = [];
  86. // 更新配送员信息
  87. $updateData['riderName'] = $data['operator_name'];
  88. $updateData['riderPhone'] = $data['operator_phone'];
  89. $updateData['riderLng'] = $data['rider_lng'];
  90. $updateData['riderLat'] = $data['rider_lat'];
  91. $updateData['statusDesc'] = $data['status_desc'];
  92. $updateData['pushTime'] = date('Y-m-d H:i:s', $data['push_time']);
  93. $orderStatus = $data['order_status'];
  94. // 转换顺丰订单状态到系统状态
  95. $sendStatus = $this->convertOrderStatus($orderStatus);
  96. if ($sendStatus !== null) {
  97. // 更新配送订单
  98. $deliveryOrder->orderStatus = $sendStatus;
  99. $deliveryOrder->save();
  100. // 更新主订单的配送状态
  101. $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
  102. if ($order) {
  103. $order->sendStatus = $sendStatus;
  104. $order->save();
  105. }
  106. } else {
  107. return false;
  108. }
  109. return true;
  110. }
  111. /**
  112. * 处理订单完成回调
  113. * 订单状态:17-配送员点击完成
  114. *
  115. * @param array $data 回调数据
  116. * @return bool 处理结果
  117. */
  118. private function handleOrderComplete($data)
  119. {
  120. Yii::info('顺丰订单完成回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  121. // 验证必要参数
  122. if (empty($data['sf_order_id'])) {
  123. Yii::error('顺丰订单完成回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  124. return false;
  125. }
  126. $orderId = $data['sf_order_id'];
  127. // 查找配送订单
  128. $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
  129. 'deliveryId' => 'shunfeng',
  130. 'orderId' => $orderId
  131. ], true);
  132. if (!$deliveryOrder) {
  133. Yii::error('顺丰配送订单不存在: sf_order_id=' . $orderId, 'shunfeng-callback');
  134. return false;
  135. }
  136. $sendStatus = $this->convertOrderStatus($data['order_status']);
  137. if ($sendStatus === null) {
  138. Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
  139. return false;
  140. }
  141. $deliveryOrder->orderStatus = $sendStatus;
  142. $deliveryOrder->save();
  143. // 更新主订单状态为已送达
  144. $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
  145. if ($order) {
  146. $order->sendStatus = $sendStatus;
  147. $order->save();
  148. }
  149. return true;
  150. }
  151. /**
  152. * 处理顺丰原因取消回调
  153. * 订单状态:2-订单取消
  154. *
  155. * @param array $data 回调数据
  156. * @return bool 处理结果
  157. */
  158. private function handleSfCancel($data)
  159. {
  160. Yii::info('顺丰取消订单回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  161. // 验证必要参数
  162. if (empty($data['sf_order_id'])) {
  163. Yii::error('顺丰取消回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  164. return false;
  165. }
  166. $orderId = $data['sf_order_id'];
  167. // 查找配送订单
  168. $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
  169. 'deliveryId' => 'shunfeng',
  170. 'orderId' => $orderId
  171. ], true);
  172. if (!$deliveryOrder) {
  173. Yii::error('顺丰配送订单不存在: sf_order_id=' . $orderId, 'shunfeng-callback');
  174. return false;
  175. }
  176. $sendStatus = $this->convertOrderStatus($data['order_status']);
  177. if ($sendStatus === null) {
  178. Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
  179. return false;
  180. }
  181. $deliveryOrder->orderStatus = $sendStatus;
  182. $deliveryOrder->save();
  183. // 更新主订单状态为取消
  184. $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
  185. if ($order) {
  186. $order->sendStatus = $sendStatus;
  187. $order->save();
  188. }
  189. return true;
  190. }
  191. /**
  192. * 处理订单异常回调
  193. * 订单状态:91-骑士上报异常
  194. *
  195. * @param array $data 回调数据
  196. * @return bool 处理结果
  197. */
  198. private function handleRiderException($data)
  199. {
  200. Yii::info('顺丰订单异常回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  201. // 验证必要参数
  202. if (empty($data['sf_order_id'])) {
  203. Yii::error('顺丰异常回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  204. return false;
  205. }
  206. $orderId = $data['sf_order_id'];
  207. // 查找配送订单
  208. $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
  209. 'deliveryId' => 'shunfeng',
  210. 'orderId' => $orderId
  211. ], true);
  212. if (!$deliveryOrder) {
  213. Yii::error('顺丰配送订单不存在: sf_order_id=' . $orderId, 'shunfeng-callback');
  214. return false;
  215. }
  216. $sendStatus = $this->convertOrderStatus($data['order_status']);
  217. if ($sendStatus === null) {
  218. Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
  219. return false;
  220. }
  221. $deliveryOrder->orderStatus = $sendStatus;
  222. $deliveryOrder->save();
  223. // 更新主订单状态为异常
  224. $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
  225. if ($order) {
  226. $order->sendStatus = $sendStatus;
  227. $order->save();
  228. }
  229. return true;
  230. }
  231. /**
  232. * 处理骑士撤单回调
  233. * 订单状态:22-配送员撤单
  234. *
  235. * @param array $data 回调数据
  236. * @return bool 处理结果
  237. */
  238. private function handleRiderRecall($data)
  239. {
  240. Yii::info('顺丰骑士撤单回调: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  241. // 验证必要参数
  242. if (empty($data['shop_order_id'])) {
  243. Yii::error('顺丰撤单回调参数不完整: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'shunfeng-callback');
  244. return false;
  245. }
  246. $shopOrderId = $data['shop_order_id'];
  247. // 查找配送订单
  248. $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
  249. 'deliveryId' => 'shunfeng',
  250. 'orderId' => $shopOrderId
  251. ], true);
  252. if (!$deliveryOrder) {
  253. Yii::error('顺丰配送订单不存在: shop_order_id=' . $shopOrderId, 'shunfeng-callback');
  254. return false;
  255. }
  256. $sendStatus = $this->convertOrderStatus($data['order_status']);
  257. if ($sendStatus === null) {
  258. Yii::error('顺丰订单状态转换失败: ' . $data['order_status'], 'shunfeng-callback');
  259. return false;
  260. }
  261. $deliveryOrder->orderStatus = $sendStatus;
  262. $deliveryOrder->save();
  263. // 更新主订单状态为派单中
  264. $order = OrderClass::getById($deliveryOrder->ghsOrderId, true);
  265. if ($order) {
  266. $order->sendStatus = $sendStatus;
  267. $order->save();
  268. }
  269. return true;
  270. }
  271. /**
  272. * 转换顺丰订单状态到系统配送状态
  273. *
  274. * 顺丰状态说明:
  275. * - 10: 配送员接单/配送员改派
  276. * - 12: 配送员到店
  277. * - 15: 配送员配送中
  278. * - 17: 配送员点击完成
  279. * - 2: 订单取消
  280. * - 22: 配送员撤单
  281. * - 91: 骑士上报异常
  282. *
  283. * 系统状态说明:
  284. * - 0: 订单生成
  285. * - 1: 系统已接单
  286. * - 2: 派单中
  287. * - 3: 待取货
  288. * - 4: 配送中
  289. * - 5: 已送达
  290. * - -1: 已取消
  291. * - -2: 异常
  292. * - 10: 改派中
  293. * - 20: 已分配骑手
  294. * - 30: 骑手已到店
  295. * - 40: 申请取消中
  296. * - 50: 客服介入处理中
  297. *
  298. * @param int $sfOrderStatus 顺丰订单状态
  299. * @return int|null 系统配送状态,null表示不需要更新主订单状态
  300. */
  301. private function convertOrderStatus($sfOrderStatus)
  302. {
  303. // 顺丰状态映射到系统配送状态
  304. $statusMap = [
  305. 10 => 20, // 配送员接单/改派 -> 已分配骑手
  306. 12 => 30, // 配送员到店 -> 骑手已到店
  307. 15 => 4, // 配送员配送中 -> 配送中
  308. 17 => 5, // 配送完成 -> 已送达
  309. 2 => -1, // 订单取消 -> 已取消
  310. 22 => 2, // 配送员撤单 -> 派单中(重新派单)
  311. 91 => -2, // 骑士上报异常 -> 异常
  312. ];
  313. return $statusMap[$sfOrderStatus] ?? null;
  314. }
  315. }