select(['logistic_number', 'order_id', 'id']) ->with(['order' => function ($query) { return $query->select(['id', 'logistic_id'])->with('logistic:id,name,code'); }]); if ($is_to_init) {//当前时间小于等于初始化时间 $initDate = Carbon::parse(config('api_logistic.init_date')); //初始化查询一个月的数据,exception为否 $query = $query->where('created_at', '>=', $initDate) ->whereNull('received_at'); } else {//查询20天以内的数据 $query = $query->where('created_at', '>=', now()->subDays(config('api_logistic.querying_days'))->startOfDay()) ->whereNull('received_at'); } } else { $query = OrderPackage::query() ->select(['logistic_number', 'order_id', 'id']) ->with(['order' => function ($query) { return $query->select(['id', 'logistic_id'])->with('logistic:id,name,code'); }]) ->whereIn('logistic_number', $logistic_numbers); } $query->chunkById(1000, function ($orderPackages) { // LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法", json_encode(data_get($orderPackages,'*.logistic_number'))); $logisticNumbers = $this->buildData($orderPackages); //sf if (array_key_exists('SF', $logisticNumbers)) { $SFLogisticNumbers = $logisticNumbers['SF']; // LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-SF", json_encode($SFLogisticNumbers)); foreach ($SFLogisticNumbers as $logisticNumber) { // LogService::log(OrderPackageReceivedSyncService::class, "同步SF快递单号", $logisticNumber); LogisticSFSync::dispatch($logisticNumber); } } //更新中通 if (array_key_exists('ZTO', $logisticNumbers)) { $ZTOLogisticNumbers = $logisticNumbers['ZTO']; // LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-ZTO", json_encode($ZTOLogisticNumbers)); foreach ($ZTOLogisticNumbers as $logisticNumber) { // LogService::log(OrderPackageReceivedSyncService::class, "同步ZTO快递单号", $logisticNumber); LogisticZopSync::dispatch($logisticNumber); } } //更新韵达 if (array_key_exists('YUNDA', $logisticNumbers)) { $YDLogisticNumbers = $logisticNumbers['YUNDA']; // LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-YUNDA", json_encode($YDLogisticNumbers)); foreach ($YDLogisticNumbers as $logistic_number) { // LogService::log(OrderPackageReceivedSyncService::class, "同步YUNDA快递单号", $logisticNumber); LogisticYDSync::dispatch($logistic_number); } } //更新圆通 if (array_key_exists('YTO', $logisticNumbers)) { $YTOLogisticNumbers = $logisticNumbers['YTO']; // LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-YTO", json_encode($YTOLogisticNumbers)); foreach ($YTOLogisticNumbers as $logistic_number) { if ($logistic_number) LogisticYTOSync::dispatch($logistic_number); } } }); } public function syncLogisticRouteByAliJiSu($logistic_numbers = []) { if (empty($logistic_numbers)) { ini_set('max_execution_time', 2 * 60 * 60); $query = OrderPackage::query() ->select(['logistic_number', 'order_id', 'id']) ->whereIn('order_id', function ($query) { $query->from('orders')->selectRaw('id')->whereIn('logistic_id', function ($builder) { $builder->from('logistics')->selectRaw('id')->where('type', '=', '快递')->whereNotIn('belong_company', ['顺丰', '中通', '韵达', '圆通', '京东']); }); }); $query = $query->where('created_at', '>=', now()->subDays(config('api_logistic.querying_days'))) ->whereNull('received_at'); } else { $query = OrderPackage::query() ->select(['logistic_number', 'order_id', 'id']) ->whereIn('logistic_number', $logistic_numbers); } $query->chunkById(200, function ($orderPackages) { // LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-阿里公用接口", json_encode($orderPackages)); foreach ($orderPackages as $orderPackage) { if ($orderPackage && $orderPackage->logistic_number) LogisticAliJiSuSync::dispatch($orderPackage->logistic_number); } }); //TODO 暂时不同步京东 // $this->syncLogisticRouteJD(); } public function syncLogisticRouteJD() { ini_set('max_execution_time', 60); $query = OrderPackage::query() ->select(['logistic_number', 'order_id', 'id']) ->whereIn('order_id', function ($query) { $query->from('orders')->selectRaw('id')->whereIn('logistic_id', function ($builder) { $builder->from('logistics')->selectRaw('id')->where('type', '!=', '物流')->where('belong_company', '京东'); }); }); $query = $query->where('created_at', '>=', now()->subDays(config('api_logistic.querying_days'))) ->whereNull('received_at')->where('logistic_number', 'like', 'JD%'); $query->chunkById(200, function ($orderPackages) { // LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-JD", json_encode($orderPackages)); foreach ($orderPackages as $orderPackage) { if ($orderPackage && $orderPackage->logistic_number) LogisticAliJiSuSync::dispatch($orderPackage->logistic_number); } }); } /** * 根据传递的承运商与快递单号更新快递信息 * @param array $logisticNumbers 快递单号 * example: ['SF' => ['SF1038651915891', 'SF1038651413847', 'SF1038611050071'],'ZT'=>['75424148714142','548464120822', '75424147834290']....] * @throws Exception 快递接口调用或者返回的信息有误,无法更新指定的快递路由信息 */ public function syncLogisticRouteApi(array $logisticNumbers) { $this->update($this->getLogisticRoutes($logisticNumbers)); } /** * 获取快件揽收信息 * @param array $request [ * 'SF' => ['SF1038651915891', 'SF1038651413847', 'SF1038611050071'], * 'ZT'=>['75424148714142','548464120822', '75424147834290'] * ] * @return array * @throws Exception */ public function getLogisticRoutes(array $request): array { $this->logisticSFService = new LogisticSFService(); $resultSF = []; $resultYD = []; $resultYT = []; $resultOther = []; foreach ($request as $key => $logisticNums) { switch ($key) { case "SF": $resultSF = $this->logisticSFService->get($logisticNums); break; case "YD": $resultYD = []; break; case "YT": $resultYT = []; break; default: $resultOther = []; break; } } return array_merge($resultSF, $resultYD, $resultYT, $resultOther); } /** * 根据快递单号更新状态 * @param array $logisticResponses */ public function update(array $logisticResponses) { foreach ($logisticResponses as $logisticResponse) { if (empty($logisticResponse)) continue; $orderPackage = OrderPackage::query()->where('logistic_number', $logisticResponse['logistic_number'])->first(); //如果已经收货,状态改为已签收 if ($logisticResponse['received_at'] ?? false) { $logisticResponse['status'] = '已签收'; } //标记为手动更新的 status不更新 if ($orderPackage->is_manual_update) { if (OrderPackage::switchStatus($orderPackage->status) > OrderPackage::switchStatus($logisticResponse['status'] ?? '生成订单')) { unset($logisticResponse['status']); } } $logisticResponse = $this->setExceptionStatus($logisticResponse); if (Str::contains($orderPackage->logistic_number, ['SO', '#', '-'])) { $logisticResponse['exception_status'] = '单号异常'; } if (((!isset($logisticResponse['status'])) || ($logisticResponse['status'] === '')) && $orderPackage->status === '') { $logisticResponse['status'] = '生成订单'; if (!empty($orderPackage->sent_at)) { $logisticResponse['status'] = '已复核'; } if (!empty($orderPackage->weighed_at)) { $logisticResponse['status'] = '已称重'; } } if (isset($logisticResponse['exception_status'])) $logisticResponse['exception_status'] = OrderPackage::switchExceptionStatus($logisticResponse['exception_status']); if (isset($logisticResponse['status'])) $logisticResponse['status'] = OrderPackage::switchStatus($logisticResponse['status']); if (isset($logisticResponse['routes_length'])) unset($logisticResponse['routes_length']); if(empty($logisticResponse['transfer_status'])) unset($logisticResponse['transfer_status']); OrderPackage::query()->where('logistic_number', $logisticResponse['logistic_number']) ->update($logisticResponse); } } /** * 将orderPackage集合分类并摘取指定数据 * @param Collection $orderPackages * @return array */ private function buildData(Collection $orderPackages): array { $data = []; foreach ($orderPackages as $orderPackage) { try { $logisticCode = $orderPackage->order->logistic->code; } catch (Exception $e) { // LogService::log(OrderPackageReceivedSyncService::class, "快递同步按照承运商分组异常", json_encode($orderPackage??[])); continue; } $key = config('api_logistic.logistic.' . $logisticCode); if (!isset($data[$key])) { $data[$key] = []; } $data[$key][] = $orderPackage->logistic_number; } return $data; } }