This commit is contained in:
Your Name
2026-06-04 10:17:47 +08:00
parent 32f8e19bf1
commit ef014e0d9d
3 changed files with 128 additions and 2 deletions
@@ -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
*
* 使用方法:
@@ -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 存在(不发起查询)
*/
@@ -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'] ?? ''),