CallBackHandler.php 11 KB

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