diff --git a/server/app/command/GancaoSyncLogisticsRoute.php b/server/app/command/GancaoSyncLogisticsRoute.php index 8ce1ca38..ac986310 100755 --- a/server/app/command/GancaoSyncLogisticsRoute.php +++ b/server/app/command/GancaoSyncLogisticsRoute.php @@ -18,6 +18,7 @@ use think\console\Output; * 数据流: * zyt_tcm_prescription_order (甘草已上传) * ↓ 调用 igc_scm.logistics.client_opt.pull / GET_TASK_ROUTE_LIST + * ↓ 甘草报快递任务不存在等(如 10101)且业务单已有运单号 → 降级快递100 * zyt_express_tracking + zyt_express_trace + zyt_express_state_log + zyt_express_query_log * * 使用方法: diff --git a/server/app/common/service/ExpressTrackingService.php b/server/app/common/service/ExpressTrackingService.php index 60dd6c29..2bee0ab0 100755 --- a/server/app/common/service/ExpressTrackingService.php +++ b/server/app/common/service/ExpressTrackingService.php @@ -162,6 +162,76 @@ class ExpressTrackingService return $stats; } + /** + * 甘草路由不可用时的降级:按业务订单运单号走快递100 查询并落库(自发货等场景) + * + * @return array{ + * success: bool, + * message: string, + * traces_count: int, + * state: string, + * source: string, + * assistant_sync?: array|null + * } + */ + public static function queryKuaidiForPrescriptionOrder(PrescriptionOrder $order, bool $isAuto = true): array + { + $fail = static fn (string $msg): array => [ + 'success' => false, + 'message' => $msg, + 'traces_count' => 0, + 'state' => '', + 'source' => 'kuaidi100_fallback', + 'assistant_sync' => null, + ]; + + $tn = trim((string) ($order->tracking_number ?? '')); + if ($tn === '') { + return $fail('甘草无快递任务且业务单未填写快递单号,无法走快递100'); + } + + $tracking = self::resolveTrackingByNumber($tn); + if (!$tracking) { + return $fail('未找到运单对应的物流追踪记录'); + } + + self::backfillRecipientPhoneFromPrescriptionOrder($tracking); + self::syncTrackingExpressCompanyFromNumber($tracking); + + try { + $result = self::queryAndUpdate((int) $tracking->id, $isAuto); + $ok = self::isKuaidiQuerySuccessful($result); + $tracking = ExpressTracking::where('id', (int) $tracking->id)->whereNull('delete_time')->find(); + $state = $tracking ? (string) ($tracking->current_state ?? '') : ''; + $hint = trim((string) ($result['hint'] ?? '')); + $message = $ok + ? 'ok(甘草无快递任务,已降级快递100)' + : ($hint !== '' ? $hint : '快递100 查询未返回有效轨迹'); + + $assistantSync = null; + if (is_array($result) && isset($result['_assistant_sync']) && is_array($result['_assistant_sync'])) { + $assistantSync = $result['_assistant_sync']; + } + + return [ + 'success' => $ok, + 'message' => $message, + 'traces_count' => count($result['traces'] ?? []), + 'state' => $state, + 'source' => 'kuaidi100_fallback', + 'assistant_sync' => $assistantSync, + ]; + } catch (\Throwable $e) { + Log::error('queryKuaidiForPrescriptionOrder failed', [ + 'order_id' => (int) $order->id, + 'tracking_number' => $tn, + 'error' => $e->getMessage(), + ]); + + return $fail('快递100 降级异常:' . $e->getMessage()); + } + } + /** * 确保 express_tracking 存在(不发起查询) */ diff --git a/server/app/common/service/gancao/GancaoLogisticsRouteService.php b/server/app/common/service/gancao/GancaoLogisticsRouteService.php index 4af62941..17ed64df 100755 --- a/server/app/common/service/gancao/GancaoLogisticsRouteService.php +++ b/server/app/common/service/gancao/GancaoLogisticsRouteService.php @@ -69,7 +69,11 @@ final class GancaoLogisticsRouteService $resp = self::callRouteApi($appOrderNo); if (!$resp['success']) { - self::logQuery($order, '', 'auto', false, 0, $resp['message']); + self::logQuery($order, '', 'auto', false, (int) ($resp['runtime_ms'] ?? 0), $resp['message']); + if (self::shouldFallbackToKuaidi100($resp)) { + return self::syncOneViaKuaidi100($order, (string) $resp['message']); + } + return ['success' => false, 'message' => $resp['message'], 'traces_count' => 0, 'state' => '']; } @@ -87,6 +91,10 @@ final class GancaoLogisticsRouteService if ($trackingNumber === '') { self::logQuery($order, '', 'auto', false, $resp['runtime_ms'], '甘草未返回 sp_order_no(快递单号),可能尚未发货'); + if (trim((string) ($order->tracking_number ?? '')) !== '') { + return self::syncOneViaKuaidi100($order, '甘草未返回快递单号,业务单已填写运单号'); + } + return ['success' => false, 'message' => '尚未发货(无快递单号)', 'traces_count' => 0, 'state' => '']; } @@ -136,11 +144,54 @@ final class GancaoLogisticsRouteService 'message' => 'ok', 'traces_count' => $tracesCount, 'state' => $newState, + 'source' => 'gancao', 'raw' => $result, 'assistant_sync' => $assistantSync, ]; } + /** + * 甘草侧无快递任务 / 路由拉取失败时,按业务单运单号降级快递100(自发货) + * + * @return array{success:bool, message:string, traces_count:int, state:string, source?:string, assistant_sync?:array|null} + */ + private static function syncOneViaKuaidi100(PrescriptionOrder $order, string $gancaoReason): array + { + $ret = ExpressTrackingService::queryKuaidiForPrescriptionOrder($order, true); + if (!$ret['success']) { + $ret['message'] = trim((string) $ret['message']) . ';甘草:' . mb_substr($gancaoReason, 0, 200); + } + + return $ret; + } + + /** + * 是否因甘草「快递任务」类错误降级走快递100 + * + * @param array{success?:bool, message?:string, api_code?:string} $gancaoResp + */ + private static function shouldFallbackToKuaidi100(array $gancaoResp): bool + { + $code = trim((string) ($gancaoResp['api_code'] ?? '')); + if ($code === '10101') { + return true; + } + + $msg = (string) ($gancaoResp['message'] ?? ''); + if ($msg === '') { + return false; + } + + $needles = ['快递任务', '任务id不存在', '任务不存在', '无快递任务', '物流任务']; + foreach ($needles as $needle) { + if (mb_strpos($msg, $needle) !== false) { + return true; + } + } + + return false; + } + /** * 调用甘草 GET_TASK_ROUTE_LIST 接口 * @@ -181,6 +232,7 @@ final class GancaoLogisticsRouteService return [ 'success' => false, 'message' => 'API 错误:' . GancaoScmRecipelService::apiStatusMessage($body), + 'api_code' => (string) ($body['status']['code'] ?? ''), 'runtime_ms' => $runtimeMs, ]; } @@ -499,6 +551,7 @@ final class GancaoLogisticsRouteService 'message' => $r['message'], 'traces' => $r['traces_count'], 'state' => $r['state'], + 'source' => $r['source'] ?? 'gancao', ]; if ($r['success']) { $stats['success']++; @@ -507,8 +560,10 @@ final class GancaoLogisticsRouteService $act = (string) ($sync['action'] ?? ''); if ($act === 'cleared') { $stats['assistant_cleared']++; + $channel = (($r['source'] ?? '') === 'kuaidi100_fallback') ? '快递100降级' : '甘草路由'; $stats['assistant_lines'][] = sprintf( - '[移除医助+指派日志][甘草路由] 诊单=%d 业务订单=%d 运单=%s 原医助ID=%s 履约状态=%d', + '[移除医助+指派日志][%s] 诊单=%d 业务订单=%d 运单=%s 原医助ID=%s 履约状态=%d', + $channel, (int) ($sync['diagnosis_id'] ?? 0), (int) ($sync['prescription_order_id'] ?? 0), (string) ($sync['tracking_number'] ?? ''),