select(['logistic_number', 'order_id', 'id']) ->whereIn('status', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null]) ->whereIn('exception_status', [0, 1, 2, 3, 4, 5, 6, 7, null]) ->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')); //初始化查询一个月的数据 $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) { //按照承运商分组 $logisticNumbers = $this->buildData($orderPackages); //更新顺丰系列 if (array_key_exists('SF', $logisticNumbers)) { $SFLogisticNumbers = $logisticNumbers['SF']; foreach ($SFLogisticNumbers as $logisticNumber) { LogisticSFSync::dispatch($logisticNumber); } } //更新中通 if (array_key_exists('ZTO', $logisticNumbers)) { $ZTOLogisticNumbers = $logisticNumbers['ZTO']; foreach ($ZTOLogisticNumbers as $logisticNumber) { LogisticZopSync::dispatch($logisticNumber); } } //更新韵达 if (array_key_exists('YUNDA', $logisticNumbers)) { $YDLogisticNumbers = $logisticNumbers['YUNDA']; foreach ($YDLogisticNumbers as $logistic_number) { LogisticYDSync::dispatch($logistic_number); } } //更新圆通 if (array_key_exists('YTO', $logisticNumbers)) { $YTOLogisticNumbers = $logisticNumbers['YTO']; foreach ($YTOLogisticNumbers as $logistic_number) { if ($logistic_number) LogisticYTOSync::dispatch($logistic_number); } } }); } /** * 阿里云同步快递信息 * @param array $logistic_numbers 指定单号同步 */ public function syncLogisticRouteByAliJiSu(array $logistic_numbers = []) { //没有指定单号 if (empty($logistic_numbers)) { ini_set('max_execution_time', 2 * 60 * 60); $query = OrderPackage::query() ->select(['logistic_number', 'order_id', 'id']) ->whereIn('status', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null]) ->whereIn('exception_status', [0, 1, 2, 3, 4, 5, 6, 7, null]) ->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) { foreach ($orderPackages as $orderPackage) { if ($orderPackage && $orderPackage->logistic_number) LogisticAliJiSuSync::dispatch($orderPackage->logistic_number); } }); } 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) { foreach ($orderPackages as $orderPackage) { if ($orderPackage && $orderPackage->logistic_number) LogisticAliJiSuSync::dispatch($orderPackage->logistic_number); } }); } /** * 根据快递单号更新状态 * @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 (empty($orderPackage)) continue; //如果已经收货,状态改为已签收 if ($logisticResponse['received_at'] ?? false) { $logisticResponse['status'] = '已签收'; } //设置异常信息 $logisticResponse = $this->setExceptionStatus($logisticResponse); //标记为手动更新的 status不更新 if ($orderPackage->is_manual_update) { //异常状态不更新 if (isset($logisticResponse['exception_status'])) unset($logisticResponse['exception_status']); //状态允许向后更新 if (OrderPackage::switchStatus($orderPackage->status) > OrderPackage::switchStatus($logisticResponse['status'] ?? '生成订单')) { unset($logisticResponse['status']); } } //标记为单号异常 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']); if (isset($logisticResponse['transfer_status'])) { $logisticResponse['route_length'] = count($logisticResponse['transfer_status']); } else { $logisticResponse['route_length'] = 0; } /** @var OrderPackage $orderPackage */ $orderPackage = OrderPackage::query()->where('logistic_number', $logisticResponse['logistic_number'])->first(); if (isset($logisticResponse['transfer_status']) && isset($logisticResponse['logistic_number'])) { $orderPackageExpressRouteArr = [ 'order_package_express_routes' => $logisticResponse['transfer_status'], 'logistics_number' => $logisticResponse['logistic_number'], ]; try { $issue_time = $orderPackage->order->created_at ?? null; $check_time = $orderPackage->sent_at ?? null; $pickup_time = $orderPackageExpressRouteArr['order_package_express_routes'][0]['accept_time'] ?? null; $array_filter = array_filter($orderPackageExpressRouteArr['order_package_express_routes'], function ($item) { return ( str_contains($item['remark'], '已发出')//中通 || str_contains($item['accept_address'], '已发出')//中通 || str_contains($item['remark'], '转运')//中通 || str_contains($item['remark'], '完成分拣')//顺丰 || str_contains($item['accept_address'], '转运')//圆通 || str_contains($item['remark'], '已发往')//中通 || str_contains($item['accept_address'], '已发往')//中通 || str_contains($item['remark'], '中心') || str_contains($item['accept_address'], '中心')); }) ?? null; $transfer_time = null; if ($array_filter != null) { $transfer_time = $array_filter[array_key_first($array_filter)]['accept_time'] ?? null; } $receive_time = $logisticResponse['received_at'] ?? null; $orderPackageExpressRouteArr['issue_time'] = $issue_time; $orderPackageExpressRouteArr['check_time'] = $check_time; $orderPackageExpressRouteArr['pickup_time'] = $pickup_time; $orderPackageExpressRouteArr['transfer_time'] = $transfer_time; $orderPackageExpressRouteArr['receive_time'] = $receive_time; } catch (Exception $e) { Log::error("快递同步异常", ["msg" => $e->getMessage(), "json" => $orderPackageExpressRouteArr]); } $orderPackageExpressRoute = OrderPackageExpressRoute::query()->updateOrCreate( [ 'logistics_number' => $logisticResponse['logistic_number'], ], $orderPackageExpressRouteArr); $orderPackage->order_package_express_route_id = $orderPackageExpressRoute->id; $orderPackage->save(); } 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) { continue; } $key = config('api_logistic.logistic.' . $logisticCode); if (!isset($data[$key])) { $data[$key] = []; } $data[$key][] = $orderPackage->logistic_number; } return $data; } }