更新
This commit is contained in:
@@ -38,7 +38,8 @@ class ExpressAutoUpdate extends Command
|
||||
try {
|
||||
$result = ExpressTrackingService::autoUpdateBatch(1000);
|
||||
$recon = ExpressTrackingService::reconcileAssistantReleaseForShippedPrescriptionOrders(1000);
|
||||
|
||||
|
||||
|
||||
$duration = round(microtime(true) - $startTime, 2);
|
||||
|
||||
$output->writeln("更新完成!");
|
||||
|
||||
@@ -63,29 +63,94 @@ class ExpressTrackService
|
||||
|
||||
$cfg = Config::get('logistics.kuaidi100', []);
|
||||
$enable = !empty($cfg['enable']);
|
||||
|
||||
$result = $out;
|
||||
if (! $enable) {
|
||||
$out['hint'] = '未配置快递100查询密钥或已关闭(LOGISTICS_KUAIDI100_DISABLE),仅可打开官网查件。请在 .env 中配置 LOGISTICS_KUAIDI100_CUSTOMER、LOGISTICS_KUAIDI100_KEY';
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
// 顺丰(及快递100 要求电话的承运商)无 phone 时不请求接口,避免无效调用
|
||||
if ($phoneForKuaidi === '' && self::kuaidiPhoneRequired($kuaidiCom)) {
|
||||
$out['hint'] = '顺丰查询需在快递100 中同时提交单号与收/寄件人电话(可与面单一致的完整手机号或后四位)。请填写收件电话后点「刷新轨迹」。';
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
$lastFail = null;
|
||||
foreach ($comCandidates as $tryCom) {
|
||||
$tryOut = self::queryKuaidiOnce($cfg, $tryCom, $num, $phoneForKuaidi, $carrier, $label);
|
||||
if (!empty($tryOut['traces']) || ($tryOut['state'] ?? '') !== '') {
|
||||
return $tryOut;
|
||||
$result['hint'] = '未配置快递100查询密钥或已关闭(LOGISTICS_KUAIDI100_DISABLE),仅可打开官网查件。请在 .env 中配置 LOGISTICS_KUAIDI100_CUSTOMER、LOGISTICS_KUAIDI100_KEY';
|
||||
} elseif ($phoneForKuaidi === '' && self::kuaidiPhoneRequired($kuaidiCom)) {
|
||||
// 顺丰(及快递100 要求电话的承运商)无 phone 时不请求接口,避免无效调用
|
||||
$result['hint'] = '顺丰查询需在快递100 中同时提交单号与收/寄件人电话(可与面单一致的完整手机号或后四位)。请填写收件电话后点「刷新轨迹」。';
|
||||
} else {
|
||||
$matched = null;
|
||||
$lastFail = null;
|
||||
foreach ($comCandidates as $tryCom) {
|
||||
$tryOut = self::queryKuaidiOnce($cfg, $tryCom, $num, $phoneForKuaidi, $carrier, $label);
|
||||
if (!empty($tryOut['traces']) || ($tryOut['state'] ?? '') !== '') {
|
||||
$matched = $tryOut;
|
||||
break;
|
||||
}
|
||||
$lastFail = $tryOut;
|
||||
}
|
||||
$lastFail = $tryOut;
|
||||
$result = $matched ?? $lastFail ?? $out;
|
||||
}
|
||||
|
||||
return $lastFail ?? $out;
|
||||
// 京东自营单(JDVE…)兜底:快递100 无轨迹/陈旧时,用京东官方接口(更新或更全才采用)。
|
||||
// 未配置京东官方接口时 isConfigured()=false,本段跳过,行为与原先一致。
|
||||
if ($carrier === 'jd' && JdLogisticsService::isConfigured()) {
|
||||
try {
|
||||
$jd = JdLogisticsService::queryTrace($num);
|
||||
if ($jd !== null && !empty($jd['traces']) && self::jdResultPreferred($jd, $result)) {
|
||||
$result['traces'] = $jd['traces'];
|
||||
$result['state'] = (string) $jd['state'];
|
||||
$result['state_text'] = (string) $jd['state_text'];
|
||||
$result['source'] = 'jd_official';
|
||||
$result['hint'] = '';
|
||||
// carrier / carrier_label / official_url / kuaidi_com 保留原值
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('ExpressTrackService jd official fallback failed', [
|
||||
'num' => $num,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 京东官方轨迹是否应优先于快递100 结果采用:
|
||||
* 快递100 无轨迹 → 直接用;否则京东更「新」(最新轨迹时间更晚)或同样新但条目更多 → 用。
|
||||
*
|
||||
* @param array{traces?:array,newest_unix?:int} $jd
|
||||
* @param array{traces?:array} $kuaidi
|
||||
*/
|
||||
private static function jdResultPreferred(array $jd, array $kuaidi): bool
|
||||
{
|
||||
$kuaidiTraces = is_array($kuaidi['traces'] ?? null) ? $kuaidi['traces'] : [];
|
||||
if ($kuaidiTraces === []) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$jdNewest = (int) ($jd['newest_unix'] ?? 0);
|
||||
$kuaidiNewest = self::newestUnixFromTraces($kuaidiTraces);
|
||||
if ($jdNewest > $kuaidiNewest) {
|
||||
return true;
|
||||
}
|
||||
if ($jdNewest === $kuaidiNewest && $jdNewest > 0) {
|
||||
return count($jd['traces'] ?? []) > count($kuaidiTraces);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array{time?:string}> $traces
|
||||
*/
|
||||
private static function newestUnixFromTraces(array $traces): int
|
||||
{
|
||||
$best = 0;
|
||||
foreach ($traces as $t) {
|
||||
if (!is_array($t)) {
|
||||
continue;
|
||||
}
|
||||
$p = strtotime((string) ($t['time'] ?? ''));
|
||||
if ($p !== false && (int) $p > $best) {
|
||||
$best = (int) $p;
|
||||
}
|
||||
}
|
||||
|
||||
return $best;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1047,7 +1047,7 @@ class ExpressTrackingService
|
||||
->field('et.*')
|
||||
->limit($limit)
|
||||
->select();
|
||||
|
||||
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
$assistantCleared = 0;
|
||||
|
||||
@@ -41,6 +41,32 @@ $forceDisable = filter_var($forceDisableRaw, FILTER_VALIDATE_BOOLEAN);
|
||||
// 已填 CUSTOMER+KEY 即启用;需临时关闭时设 LOGISTICS_KUAIDI100_DISABLE=true(LOGISTICS_KUAIDI100_ENABLE 已废弃,可删)
|
||||
$kuaidiEnabled = ! $forceDisable && $hasCreds;
|
||||
|
||||
// 京东官方物流接口(JOS 开放平台 https://api.jd.com/routerjson)
|
||||
// 仅当填好 APP_KEY / APP_SECRET / ACCESS_TOKEN 时启用;作为快递100 对京东自营单(JDVE…)轨迹陈旧时的兜底数据源。
|
||||
// 未配置时本段 enable=false,ExpressTrackService 完全沿用现有快递100 逻辑,互不影响。
|
||||
$envJd = static function (string $suffix, $default = '') use ($stripQuotes) {
|
||||
$top = 'JD_LOGISTICS_' . $suffix;
|
||||
$v = env($top, null);
|
||||
if ($v !== null && $v !== '') {
|
||||
return $stripQuotes((string) $v);
|
||||
}
|
||||
// 兼容误写进 [trtc] 等分区的情况
|
||||
$nested = env('trtc.' . $top, $default);
|
||||
|
||||
return $stripQuotes((string) $nested);
|
||||
};
|
||||
|
||||
$jdAppKey = $envJd('APP_KEY', '');
|
||||
$jdAppSecret = $envJd('APP_SECRET', '');
|
||||
$jdAccessToken = $envJd('ACCESS_TOKEN', '');
|
||||
$jdHasCreds = $jdAppKey !== '' && $jdAppSecret !== '' && $jdAccessToken !== '';
|
||||
$jdDisableRaw = env('JD_LOGISTICS_DISABLE', null);
|
||||
if ($jdDisableRaw === null || $jdDisableRaw === '') {
|
||||
$jdDisableRaw = env('trtc.JD_LOGISTICS_DISABLE', false);
|
||||
}
|
||||
$jdDisabled = filter_var($jdDisableRaw, FILTER_VALIDATE_BOOLEAN);
|
||||
$jdEnabled = ! $jdDisabled && $jdHasCreds;
|
||||
|
||||
return [
|
||||
'kuaidi100' => [
|
||||
'enable' => $kuaidiEnabled,
|
||||
@@ -48,4 +74,18 @@ return [
|
||||
'key' => $key,
|
||||
'query_url' => $envKuaidi('QUERY_URL', 'https://poll.kuaidi100.com/poll/query.do'),
|
||||
],
|
||||
'jd' => [
|
||||
'enable' => $jdEnabled,
|
||||
'app_key' => $jdAppKey,
|
||||
'app_secret' => $jdAppSecret,
|
||||
'access_token' => $jdAccessToken,
|
||||
'gateway' => $envJd('GATEWAY', 'https://api.jd.com/routerjson'),
|
||||
// 青龙运单轨迹查询;如改用 ECLP 等可在 .env 覆盖 method / param_key / waybill_field
|
||||
'method' => $envJd('METHOD', 'jingdong.ldop.receive.trace.get'),
|
||||
'param_key' => $envJd('PARAM_KEY', '360buy_param_json'),
|
||||
'waybill_field' => $envJd('WAYBILL_FIELD', 'waybillCode'),
|
||||
// 部分接口需商家编码 / 事业部编码,可选
|
||||
'customer_code' => $envJd('CUSTOMER_CODE', ''),
|
||||
'api_version' => $envJd('API_VERSION', '2.0'),
|
||||
],
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user