CallBackHandler.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <?php
  2. namespace common\components\delivery\platform\huolala;
  3. use biz\common\classes\GhsNotifyClass;
  4. use biz\common\classes\HdNotifyClass;
  5. use bizGhs\express\classes\GhsDeliveryOrderClass;
  6. use bizGhs\order\classes\OrderClass;
  7. use bizHd\express\classes\HdDeliveryOrderClass;
  8. use bizHd\order\classes\OrderClass as HdOrderClass;
  9. use bizHd\purchase\classes\PurchaseClass;
  10. use common\components\util;
  11. use Yii;
  12. class CallBackHandler
  13. {
  14. /**
  15. * 货拉拉状态回调入口
  16. *
  17. * @param array $data
  18. * @return bool
  19. */
  20. public function handler($data)
  21. {
  22. try {
  23. Yii::info('货拉拉回调 - 原始数据: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'huolala-callback');
  24. if (empty($data) || empty($data['data']) || !is_array($data['data'])) {
  25. Yii::error('货拉拉回调参数异常: ' . json_encode($data, JSON_UNESCAPED_UNICODE), 'huolala-callback');
  26. return false;
  27. }
  28. $bizData = $data['data'];
  29. $eventType = $bizData['event_type'] ?? '';
  30. $orderDisplayId = $bizData['order_display_id'] ?? '';
  31. if ($eventType === '' || $orderDisplayId === '') {
  32. Yii::error('货拉拉回调缺少必要字段: ' . json_encode($bizData, JSON_UNESCAPED_UNICODE), 'huolala-callback');
  33. return false;
  34. }
  35. $sendStatus = $this->mapEventTypeToOrderSendStatus($eventType);
  36. if ($sendStatus === null) {
  37. Yii::warning(sprintf('货拉拉事件未配置状态映射: event_type=%s, order_display_id=%s', $eventType, $orderDisplayId), 'huolala-callback');
  38. return true;
  39. }
  40. $orderStatus = $this->mapEventTypeToOrderStatus($eventType);
  41. if ($orderStatus === null) {
  42. Yii::warning(sprintf('货拉拉事件未配置状态映射: event_type=%s, order_display_id=%s', $eventType, $orderDisplayId), 'huolala-callback');
  43. return true;
  44. }
  45. $deliveryOrder = $this->getDeliveryOrder($orderDisplayId);
  46. if (!$deliveryOrder) {
  47. Yii::error('货拉拉配送订单不存在: order_display_id=' . $orderDisplayId, 'huolala-callback');
  48. return false;
  49. }
  50. $deliveryOrder->orderStatus = $sendStatus;
  51. if (!$deliveryOrder->save()) {
  52. Yii::error('更新配送订单状态失败: ' . json_encode($deliveryOrder->getErrors(), JSON_UNESCAPED_UNICODE), 'huolala-callback');
  53. return false;
  54. }
  55. if(isset($deliveryOrder->ghsOrderId)){ // 批发
  56. util::checkRepeatCommit('ghs_pt_'.$deliveryOrder->ghsOrderId.'_'.$sendStatus, 2); // 防止重复回调
  57. $order = OrderClass::getById($deliveryOrder->ghsOrderId, true, 'id,sendStatus,deliveryId,purchaseId,customId,status');
  58. if ($order) {
  59. // 确认送达或取消订单,更新主订单状态
  60. if ($sendStatus == 5) {
  61. OrderClass::confirmReach($order, ['staffId' => 0, 'staffName' => '']);
  62. }
  63. if (!in_array($order->sendStatus, [-2, -1]) && ($sendStatus == -1 || $sendStatus == -2)) {
  64. OrderClass::cancelOrderSend($order, ['staffId' => 0, 'staffName' => '']);
  65. $event = $this->cancelFrom($sendStatus, $eventType);
  66. GhsNotifyClass::ptErrorNotify($order->id, $event);
  67. }
  68. $cg = PurchaseClass::getById($order->purchaseId, true, 'id,sendStatus');
  69. $cg->sendStatus = $sendStatus;
  70. $cg->save();
  71. $order->sendStatus = $sendStatus;
  72. $order->status = $orderStatus;
  73. if (!$order->save()) {
  74. Yii::warning('更新主订单配送状态失败: ' . json_encode($order->getErrors(), JSON_UNESCAPED_UNICODE), 'huolala-callback');
  75. }
  76. } else {
  77. Yii::warning('未找到主订单: ghsOrderId=' . $deliveryOrder->ghsOrderId, 'huolala-callback');
  78. }
  79. }elseif(isset($deliveryOrder->hdOrderId)){ // 零售
  80. util::checkRepeatCommit('hd_pt_'.$deliveryOrder->hdOrderId.'_'.$sendStatus, 2); // 防止重复回调
  81. $order = HdOrderClass::getById($deliveryOrder->hdOrderId, true, 'id,sendType,sendStatus,deliveryId,customId,status');
  82. if ($order) {
  83. if (!in_array($order->sendStatus, [-1, -2]) && ($sendStatus == -1 || $sendStatus == -2)) {
  84. $event = $this->cancelFrom($sendStatus, $eventType);
  85. HdNotifyClass::ptErrorNotify($order->id, $event);
  86. }
  87. $order->sendStatus = $sendStatus;
  88. $order->status = $orderStatus;
  89. if (!$order->save()) {
  90. Yii::warning('更新主订单配送状态失败: ' . json_encode($order->getErrors(), JSON_UNESCAPED_UNICODE), 'huolala-callback');
  91. }
  92. } else {
  93. Yii::warning('未找到主订单: hdOrderId=' . $deliveryOrder->hdOrderId, 'huolala-callback');
  94. }
  95. }
  96. Yii::info(sprintf('货拉拉配送状态更新成功: order_display_id=%s, event_type=%s, orderStatus=%s', $orderDisplayId, $eventType, $sendStatus), 'huolala-callback');
  97. return true;
  98. } catch (\Throwable $e) {
  99. Yii::error('货拉拉回调处理异常: ' . $e->getMessage() . ' | Trace: ' . $e->getTraceAsString(), 'huolala-callback');
  100. return false;
  101. }
  102. }
  103. /**
  104. * 事件到系统配送状态的映射
  105. *
  106. * @param string $eventType
  107. * @return int|null
  108. */
  109. protected function mapEventTypeToOrderSendStatus($eventType)
  110. {
  111. $eventType = strtolower($eventType);
  112. $map = [
  113. 'order_cancelled' => -1, // 官方接口文档未更新,做下返回数据兼容
  114. 'order_cancel' => -1,
  115. 'pickup' => 20,
  116. 'driver_reject' => 2,
  117. 'order_complete' => 5,
  118. 'set_order_abnormal' => -2,
  119. 'loaded' => 4,
  120. 'auto_confirm_bill_pay' => 5,
  121. 'no_load_cancel' => -1,
  122. 'no_complete_cancel' => -1,
  123. 'loading' => 3,
  124. 'unloading' => 4,
  125. 'unload_finish' => 4,
  126. 'order_auto_complete' => 5,
  127. 'order_timeout' => -1,
  128. 'prepay_ok' => 2,
  129. 'rear_pay_ok' => 5,
  130. 'cash_received' => 5,
  131. ];
  132. return $map[$eventType] ?? null;
  133. }
  134. /**
  135. * 事件到系统订单状态的映射
  136. *
  137. * @param string $eventType
  138. * @return int|null
  139. */
  140. protected function mapEventTypeToOrderStatus($eventType)
  141. {
  142. // 系统订单状态: 1待付款 2待配送 3配送中 4已完成 5已取消
  143. $map = [
  144. // 取消状态 (订单终态)
  145. 'order_cancel' => 2, // 订单取消 -> 已取消 改为 待配送(配送的取消不等于订单的取消,由于 status 带有配送状态,所以改为:待配送)
  146. 'order_cancelled' => 2, // 官方接口文档未更新,做下返回数据兼容
  147. // 回到待配送状态 (可重新派单)
  148. 'no_load_cancel' => 2, // 未装货取消 -> 待配送
  149. 'no_complete_cancel' => 2, // 未完成取消 -> 待配送
  150. 'order_timeout' => 2, // 订单超时 -> 待配送
  151. 'driver_reject' => 2, // 司机拒单 -> 待配送
  152. 'set_order_abnormal' => 2, // 订单异常 -> 待配送
  153. // 配送中状态
  154. 'prepay_ok' => 3, // 预付成功 -> 配送中
  155. 'pickup' => 3, // 已取货 -> 配送中
  156. 'loading' => 3, // 装货中 -> 配送中
  157. 'loaded' => 3, // 已装货 -> 配送中
  158. 'unloading' => 3, // 卸货中 -> 配送中
  159. 'unload_finish' => 3, // 卸货完成 -> 配送中
  160. // 完成状态
  161. 'order_complete' => 4, // 订单完成 -> 已完成
  162. 'order_auto_complete' => 4, // 订单自动完成 -> 已完成
  163. 'auto_confirm_bill_pay' => 4, // 自动确认支付 -> 已完成
  164. 'rear_pay_ok' => 4, // 尾款支付成功 -> 已完成
  165. 'cash_received' => 4, // 收到现金 -> 已完成
  166. ];
  167. return $map[$eventType] ?? null;
  168. }
  169. /**
  170. * 根据订单号查找配送订单
  171. *
  172. * @param string $orderId
  173. * @return object|null
  174. */
  175. private function getDeliveryOrder($orderId)
  176. {
  177. // 查找批发配送订单
  178. $deliveryOrder = GhsDeliveryOrderClass::getByCondition([
  179. 'deliveryId' => 'huolala',
  180. 'orderId' => $orderId
  181. ], true);
  182. if ($deliveryOrder) {
  183. return $deliveryOrder;
  184. }
  185. // 查找零售配送订单
  186. return HdDeliveryOrderClass::getByCondition([
  187. 'deliveryId' => 'huolala',
  188. 'orderId' => $orderId
  189. ], true);
  190. }
  191. private function cancelFrom($sendStatus, $eventType)
  192. {
  193. if($sendStatus == -1){
  194. $reasons = [
  195. 'order_cancel' => '用户已取消订单',
  196. 'driver_reject' => '司机接单后拒绝,订单自动取消',
  197. 'no_load_cancel' => '5天内司机未操作“开始装货”,订单自动取消(测试环境40分钟)',
  198. 'no_complete_cancel' => '10天内未操作卸货,订单自动取消',
  199. 'order_timeout' => '订单无司机响应,已自动取消',
  200. ];
  201. return $reasons[$eventType] ?? '未知';
  202. }
  203. if($sendStatus == -2){
  204. $reasons = [
  205. 'set_order_abnormal' => '异常完成(1、客服点击虚报订单,状态为11;2、用户或者司机申诉账单,客服修改账单为0,状态为2)',
  206. ];
  207. return $reasons[$eventType] ?? '未知';
  208. }
  209. return '未知';
  210. }
  211. }