OrderPackageReceivedSyncService.php 9.3 KB

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