OrderPackageReceivedSyncService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <?php
  2. namespace App\Services;
  3. use App\Jobs\LogisticAliJiSuSync;
  4. use App\Jobs\LogisticSFSync;
  5. use App\Jobs\LogisticYDSync;
  6. use App\Jobs\LogisticYTOSync;
  7. use App\Jobs\LogisticZopSync;
  8. use App\OrderPackage;
  9. use App\OrderPackageExpressRoute;
  10. use Carbon\Carbon;
  11. use Exception;
  12. use Illuminate\Database\Eloquent\Collection;
  13. use Illuminate\Support\Str;
  14. class OrderPackageReceivedSyncService
  15. {
  16. protected $logisticSFService;
  17. protected $logisticZopService;
  18. use \App\Traits\LogisticSyncTrait;
  19. /**
  20. * 同步快递信息
  21. * @param bool $is_to_init 是否为初始化数据状态 初始化同步一个月的 正常执行为15天
  22. * @param array $logistic_numbers 指定更新的单号
  23. */
  24. public function syncLogisticRoute($is_to_init = false, $logistic_numbers = [])
  25. {
  26. ini_set('max_execution_time', 2 * 60 * 60);
  27. ini_set('memory_limit', '1024M');
  28. //没有指定单号
  29. if (empty($logistic_numbers)) {
  30. $query = OrderPackage::query()
  31. ->select(['logistic_number', 'order_id', 'id'])
  32. ->whereIn('status', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null])
  33. ->whereIn('exception_status', [0, 1, 2, 3, 4, 5, 6, 7, null])
  34. ->with(['order' => function ($query) {
  35. return $query->select(['id', 'logistic_id'])->with('logistic:id,name,code');
  36. }]);
  37. if ($is_to_init) {//当前时间小于等于初始化时间
  38. $initDate = Carbon::parse(config('api_logistic.init_date'));
  39. //初始化查询一个月的数据
  40. $query = $query->where('created_at', '>=', $initDate)
  41. ->whereNull('received_at');
  42. } else {//查询20天以内的数据
  43. $query = $query->where('created_at', '>=', now()->subDays(config('api_logistic.querying_days'))->startOfDay())
  44. ->whereNull('received_at');
  45. }
  46. } else {//指定了单号
  47. $query = OrderPackage::query()
  48. ->select(['logistic_number', 'order_id', 'id'])
  49. ->with(['order' => function ($query) {
  50. return $query->select(['id', 'logistic_id'])->with('logistic:id,name,code');
  51. }])
  52. ->whereIn('logistic_number', $logistic_numbers);
  53. }
  54. //分块执行
  55. $query->chunkById(1000, function ($orderPackages) {
  56. //按照承运商分组
  57. $logisticNumbers = $this->buildData($orderPackages);
  58. //更新顺丰系列
  59. if (array_key_exists('SF', $logisticNumbers)) {
  60. $SFLogisticNumbers = $logisticNumbers['SF'];
  61. foreach ($SFLogisticNumbers as $logisticNumber) {
  62. LogisticSFSync::dispatch($logisticNumber);
  63. }
  64. }
  65. //更新中通
  66. if (array_key_exists('ZTO', $logisticNumbers)) {
  67. $ZTOLogisticNumbers = $logisticNumbers['ZTO'];
  68. foreach ($ZTOLogisticNumbers as $logisticNumber) {
  69. LogisticZopSync::dispatch($logisticNumber);
  70. }
  71. }
  72. //更新韵达
  73. if (array_key_exists('YUNDA', $logisticNumbers)) {
  74. $YDLogisticNumbers = $logisticNumbers['YUNDA'];
  75. foreach ($YDLogisticNumbers as $logistic_number) {
  76. LogisticYDSync::dispatch($logistic_number);
  77. }
  78. }
  79. //更新圆通
  80. if (array_key_exists('YTO', $logisticNumbers)) {
  81. $YTOLogisticNumbers = $logisticNumbers['YTO'];
  82. foreach ($YTOLogisticNumbers as $logistic_number) {
  83. if ($logistic_number) LogisticYTOSync::dispatch($logistic_number);
  84. }
  85. }
  86. });
  87. }
  88. /**
  89. * 阿里云同步快递信息
  90. * @param array $logistic_numbers 指定单号同步
  91. */
  92. public function syncLogisticRouteByAliJiSu(array $logistic_numbers = [])
  93. {
  94. //没有指定单号
  95. if (empty($logistic_numbers)) {
  96. ini_set('max_execution_time', 2 * 60 * 60);
  97. $query = OrderPackage::query()
  98. ->select(['logistic_number', 'order_id', 'id'])
  99. ->whereIn('status', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null])
  100. ->whereIn('exception_status', [0, 1, 2, 3, 4, 5, 6, 7, null])
  101. ->whereIn('order_id', function ($query) {
  102. $query->from('orders')->selectRaw('id')->whereIn('logistic_id', function ($builder) {
  103. $builder->from('logistics')->selectRaw('id')->where('type', '=', '快递')->whereNotIn('belong_company', ['顺丰', '中通', '韵达', '圆通', '京东']);
  104. });
  105. });
  106. $query = $query->where('created_at', '>=', now()->subDays(config('api_logistic.querying_days')))
  107. ->whereNull('received_at');
  108. } else {//指定了单号
  109. $query = OrderPackage::query()
  110. ->select(['logistic_number', 'order_id', 'id'])
  111. ->whereIn('logistic_number', $logistic_numbers);
  112. }
  113. $query->chunkById(200, function ($orderPackages) {
  114. foreach ($orderPackages as $orderPackage) {
  115. if ($orderPackage && $orderPackage->logistic_number) LogisticAliJiSuSync::dispatch($orderPackage->logistic_number);
  116. }
  117. });
  118. }
  119. public function syncLogisticRouteJD()
  120. {
  121. ini_set('max_execution_time', 60);
  122. $query = OrderPackage::query()
  123. ->select(['logistic_number', 'order_id', 'id'])
  124. ->whereIn('order_id', function ($query) {
  125. $query->from('orders')->selectRaw('id')->whereIn('logistic_id', function ($builder) {
  126. $builder->from('logistics')->selectRaw('id')->where('type', '!=', '物流')->where('belong_company', '京东');
  127. });
  128. });
  129. $query = $query->where('created_at', '>=', now()->subDays(config('api_logistic.querying_days')))
  130. ->whereNull('received_at')->where('logistic_number', 'like', 'JD%');
  131. $query->chunkById(200, function ($orderPackages) {
  132. foreach ($orderPackages as $orderPackage) {
  133. if ($orderPackage && $orderPackage->logistic_number) LogisticAliJiSuSync::dispatch($orderPackage->logistic_number);
  134. }
  135. });
  136. }
  137. /**
  138. * 根据快递单号更新状态
  139. * @param array $logisticResponses
  140. */
  141. public function update(array $logisticResponses)
  142. {
  143. foreach ($logisticResponses as $logisticResponse) {
  144. if (empty($logisticResponse)) continue;
  145. $orderPackage = OrderPackage::query()->where('logistic_number', $logisticResponse['logistic_number'])->first();
  146. if (empty($orderPackage)) continue;
  147. //如果已经收货,状态改为已签收
  148. if ($logisticResponse['received_at'] ?? false) {
  149. $logisticResponse['status'] = '已签收';
  150. }
  151. //设置异常信息
  152. $logisticResponse = $this->setExceptionStatus($logisticResponse);
  153. //标记为手动更新的 status不更新
  154. if ($orderPackage->is_manual_update) {
  155. //异常状态不更新
  156. if (isset($logisticResponse['exception_status'])) unset($logisticResponse['exception_status']);
  157. //状态允许向后更新
  158. if (OrderPackage::switchStatus($orderPackage->status) > OrderPackage::switchStatus($logisticResponse['status'] ?? '生成订单')) {
  159. unset($logisticResponse['status']);
  160. }
  161. }
  162. //标记为单号异常
  163. if (Str::contains($orderPackage->logistic_number, ['SO', '#', '-'])) {
  164. $logisticResponse['exception_status'] = '单号异常';
  165. }
  166. //没有状态的数据赋予初始状态
  167. if (((!isset($logisticResponse['status'])) || ($logisticResponse['status'] === '')) &&
  168. $orderPackage->status === '') {
  169. $logisticResponse['status'] = '生成订单';
  170. if (!empty($orderPackage->sent_at)) {
  171. $logisticResponse['status'] = '已复核';
  172. }
  173. if (!empty($orderPackage->weighed_at)) {
  174. $logisticResponse['status'] = '已称重';
  175. }
  176. }
  177. if (isset($logisticResponse['exception_status'])) $logisticResponse['exception_status'] = OrderPackage::switchExceptionStatus($logisticResponse['exception_status']);
  178. if (isset($logisticResponse['status'])) $logisticResponse['status'] = OrderPackage::switchStatus($logisticResponse['status']);
  179. if (isset($logisticResponse['routes_length'])) unset($logisticResponse['routes_length']);
  180. if (empty($logisticResponse['transfer_status'])) unset($logisticResponse['transfer_status']);
  181. if (isset($logisticResponse['transfer_status'])) {
  182. $logisticResponse['route_length'] = count($logisticResponse['transfer_status']);
  183. } else {
  184. $logisticResponse['route_length'] = 0;
  185. }
  186. /** @var OrderPackage $orderPackage */
  187. $orderPackage = OrderPackage::query()->where('logistic_number', $logisticResponse['logistic_number'])->first();
  188. if (isset($logisticResponse['transfer_status']) && isset($logisticResponse['logistic_number'])) {
  189. $orderPackageExpressRoute = OrderPackageExpressRoute::query()->updateOrCreate(
  190. [
  191. 'logistics_number' => $logisticResponse['logistic_number'],
  192. ],
  193. [
  194. 'order_package_express_routes' => $logisticResponse['transfer_status'],
  195. 'logistics_number' => $logisticResponse['logistic_number'],
  196. ]);
  197. $orderPackage->order_package_express_route_id = $orderPackageExpressRoute->id;
  198. $orderPackage->save();
  199. }
  200. unset($logisticResponse['transfer_status']);
  201. OrderPackage::query()->where('logistic_number', $logisticResponse['logistic_number'])->update($logisticResponse);
  202. }
  203. }
  204. /**
  205. * 将orderPackage集合分类并摘取指定数据
  206. * @param Collection $orderPackages
  207. * @return array
  208. */
  209. private function buildData(Collection $orderPackages): array
  210. {
  211. $data = [];
  212. foreach ($orderPackages as $orderPackage) {
  213. try {
  214. $logisticCode = $orderPackage->order->logistic->code;
  215. } catch (Exception $e) {
  216. continue;
  217. }
  218. $key = config('api_logistic.logistic.' . $logisticCode);
  219. if (!isset($data[$key])) {
  220. $data[$key] = [];
  221. }
  222. $data[$key][] = $orderPackage->logistic_number;
  223. }
  224. return $data;
  225. }
  226. }