app_key = config('api_logistic.YD.prod.app-key', '999999'); $this->app_secret = config('api_logistic.YD.prod.app-secret', '04d4ad40eeec11e9bad2d962f53dda9d'); $this->url = config('api_logistic.YD.prod.register.url'); $sender = [ "address" => "上海市松江区泗泾镇泗砖公路351号", "city" => "上海市", "county" => "松江区", "name" => "施尧", "phone" => '13761413262', "province" => "上海市" ]; $body = [ "orders" => [], ]; $order_packages = OrderPackage::query() ->with('order') ->whereIn('logistic_number', $logistic_numbers)->get(); foreach ($order_packages as $order_package) { $order = $order_package->order; $body['orders'][] = [ 'orderid' => $order->client_code, "mailno" => $order_package->logistic_number, "receiver" => [ "address" => $order->address, "city" => $order->city, "county" => $order->district, "name" => $order->consignee_name, "phone" => $order->consignee_phone, "province" => $order->province ], "sender" => $sender ]; } $json_body = json_encode($body, JSON_UNESCAPED_UNICODE); $sign = md5($json_body . '_' . $this->app_secret); $headers = [ 'app-key' => $this->app_key, 'sign' => $sign, 'req-time' => now()->timestamp, "Content-Type" => "application/json" ]; $response = Http::withHeaders($headers)->withBody($json_body, 'application/json')->post($this->url); return json_decode($response); } public function query($logistic_number) { $this->app_key = config('api_logistic.YD.prod.app-key', '999999'); $this->app_secret = config('api_logistic.YD.prod.app-secret', '04d4ad40eeec11e9bad2d962f53dda9d'); $this->url = config('api_logistic.YD.prod.search.url'); $body = [ "mailno" => $logistic_number ]; $sign = md5(json_encode($body, JSON_UNESCAPED_UNICODE) . '_' . $this->app_secret); $headers = [ 'app-key' => $this->app_key, 'sign' => $sign, 'req-time' => now()->timestamp, "Content-Type" => "application/json" ]; $response = Http::withHeaders($headers)->withBody(json_encode($body, JSON_UNESCAPED_UNICODE), 'application/json')->post($this->url); return json_decode($response->body()); } public function format($nativeResponse) { $result = []; if ($nativeResponse->code != '0000') { return []; } else { $nativeData = $nativeResponse->data; $result['logistic_number'] = $nativeData->mailno; $nativeRoutes = $nativeData->steps; if (!empty($nativeRoutes)) { $lastNativeRoute = $nativeRoutes[count($nativeRoutes) - 1]; $result['status'] = $this->getStatus($nativeData); if ($result['status'] == '已收件') { $result['received_at'] = $lastNativeRoute->time; } $result['transfer_status'] = $this->getTransferStatus($nativeRoutes); $exceptionData = $this->setExceptionType($result, $lastNativeRoute ? $lastNativeRoute->time : null); $result['exception_type'] = $exceptionData['exception_type']; $result['exception'] = $exceptionData['exception']; } else { $result['status'] = null; $result['transfer_status'] = []; } if (!array_key_exists('status', $result)) { $result['status'] = null; $result['transfer_status'] = []; } //如果没有发现额外的异常,且查询到物流轨迹,将异常置为无 if (!array_key_exists('exception', $result) && !array_key_exists('exception_type', $result) && array_key_exists('transfer_status', $result) ) { $result['exception_type'] = '无'; $result['exception'] = '否'; } return $result; } } /** * @param array $data * @param $lastRouteDate * @return array */ private function setExceptionType(array $data, $lastRouteDate): array { $logistic_number = $data['logistic_number']; /** @var OrderPackage $orderPackage */ $orderPackage = OrderPackage::query()->with('order')->where('logistic_number', $logistic_number)->first(); $delivered_duration = now()->diffInHours(Carbon::parse($orderPackage['sent_at'])); $last_routed_duration = now()->diffInHours(Carbon::parse($lastRouteDate)); $VALID_HOURS = 4; $SHORT_RESPONSE_HOURS = (function ($province) { switch ($province) { case '浙江省': case '江苏省': case '上海': case '安徽省': return 24; case '北京': case '天津': case '江西省': case '湖北省': case '湖南省': case '广东省': case '福建省': case '山东省': case '河北省': case '河南省': case '山西省': case '四川省': case '陕西省': case '重庆': case '广西壮族自治区': case '贵州省': case '云南省': case '海南省': case '吉林省': case '黑龙江省': case '辽宁省': return 72; case '青海省': case '宁夏回族自治区': case '甘肃省': case '内蒙古自治区': case '新疆维吾尔自治区': case '西藏自治区': return 120; default: return 24; } })($orderPackage->order->province); $LONG_RESPONSE_HOURS = (function ($province) { switch ($province) { case '浙江省': case '江苏省': case '上海': case '安徽省': return 72; case '北京': case '天津': case '江西省': case '湖北省': case '湖南省': case '广东省': case '福建省': case '山东省': case '河北省': case '河南省': case '山西省': case '四川省': case '陕西省': case '重庆': case '广西壮族自治区': case '贵州省': case '云南省': case '海南省': case '吉林省': case '黑龙江省': case '辽宁省': return 120; case '青海省': case '宁夏回族自治区': case '甘肃省': case '内蒙古自治区': case '新疆维吾尔自治区': case '西藏自治区': return 168; default: return 72; } })($orderPackage->order->province); $SENDING_RESPONSE_HOURS = 48; $IS_ROUTED = 1; //0000 0001 有路由信息 $IS_IN_VALID_TIME = 2; //0000 0010 大于4小时 $IS_WEIGHED = 4; //0000 0100 称重过 $IS_RECEIVED = 8; //0000 1000 已经收货 $IS_SENDING = 16; //0001 0000 正在派送 $IS_SHORT_NO_RESPONSE = 32; //0010 0000 中转异常 $IS_LONG_NO_RESPONSE = 64; //0010 0000 疑似丢件 $IS_SENDING_NO_RESPONSE = 128; //0010 0000 派送异常 $conclusion = (function () use ( $data, $delivered_duration, $last_routed_duration, $VALID_HOURS, $IS_ROUTED, $IS_IN_VALID_TIME, $IS_WEIGHED, $IS_RECEIVED, $IS_SENDING, $IS_SHORT_NO_RESPONSE, $IS_LONG_NO_RESPONSE, $IS_SENDING_NO_RESPONSE, $SHORT_RESPONSE_HOURS, $LONG_RESPONSE_HOURS, $SENDING_RESPONSE_HOURS, $orderPackage ) { $conclusion = 0; $conclusion |= !empty($data['transfer_status']) ? $IS_ROUTED : 0; $conclusion |= ($delivered_duration > $VALID_HOURS) ? $IS_IN_VALID_TIME : 0; $conclusion |= ($orderPackage->weighed_at) ? $IS_WEIGHED : 0; $conclusion |= ($data['status'] == '已收件') ? $IS_RECEIVED : 0; $conclusion |= ($data['status'] == '派送中') ? $IS_SENDING : 0;// $conclusion |= ($last_routed_duration > $SHORT_RESPONSE_HOURS && $last_routed_duration < $LONG_RESPONSE_HOURS) ? $IS_SHORT_NO_RESPONSE : 0; $conclusion |= ($last_routed_duration > $LONG_RESPONSE_HOURS) ? $IS_LONG_NO_RESPONSE : 0; $conclusion |= ($last_routed_duration > $SENDING_RESPONSE_HOURS && $data['status'] == '派送中') ? $IS_SENDING_NO_RESPONSE : 0; return $conclusion; })(); switch ($conclusion) { case $IS_IN_VALID_TIME: $data['exception_type'] = '疑似库内丢件'; break; case $IS_IN_VALID_TIME | $IS_WEIGHED: $data['exception_type'] = '揽件异常'; break; case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE: case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE | $IS_WEIGHED: $data['exception_type'] = '中转异常'; break; case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE: case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE | $IS_WEIGHED: $data['exception_type'] = '疑似丢件'; break; default: break; } if ($conclusion == ($conclusion | $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SENDING | $IS_SENDING_NO_RESPONSE)) { $data['exception_type'] = '派件异常'; } switch ($conclusion) { case $IS_IN_VALID_TIME: case $IS_IN_VALID_TIME | $IS_WEIGHED: case $IS_ROUTED | $IS_SHORT_NO_RESPONSE: case $IS_LONG_NO_RESPONSE: $data['exception'] = '是'; break; default: break; } return [ 'exception_type' => array_key_exists('exception_type', $data) ? $data['exception_type'] : null, 'exception' => array_key_exists('exception', $data) ? $data['exception'] : null, ]; } /** * @param $nativeData * @return string */ private function getStatus($nativeData): string { $status = null; switch ($nativeData->status) { case 'GOT': $status = '已揽收'; break; case 'TRANSIT': $status = '在途'; break; case 'SIGNED': $status = '已收件'; break; case 'RETURN': $status = '返回中'; break; case 'SIGNFAIL': $status = '无'; break; default: $status = '无'; } return $status; } /** * @param $nativeRoutes * @return array */ private function getTransferStatus($nativeRoutes): array { $transferStatus = []; foreach ($nativeRoutes as $nativeRoute) { $item = []; $item['accept_time'] = $nativeRoute->time; $item['accept_address'] = $nativeRoute->description; $item['remark'] = ""; $transferStatus[] = $item; } return $transferStatus; } }