文件
xionggeshop/addons/shopro_aliyun_express/library/TrackNormalizer.php

297 行
11 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
namespace addons\shopro_aliyun_express\library;
class TrackNormalizer
{
/**
* 将 Provider 原始响应归一化为统一 trackList
*/
public static function normalize(array $providerResult)
{
$provider = $providerResult['provider'] ?? '';
switch ($provider) {
case 'aliyun':
return self::fromAliyun($providerResult);
case 'kdniao':
case 'expressbird':
return self::fromKdniao($providerResult);
default:
return [
'success' => false,
'trackList' => [],
'expressStatus' => '',
'expressCompanyName' => '',
'expressCompanyCode' => '',
];
}
}
protected static function fromAliyun(array $providerResult)
{
$root = $providerResult['raw'] ?? ($providerResult['data'] ?? []);
// kzexpress:logisticsTraceDetailList / logisticsTraceDetails
$dataBlock = $root['data'] ?? $root;
$traceDetails = self::pickKzexpressTraceList($dataBlock);
if (!empty($traceDetails)) {
return self::fromKzexpressTrace($providerResult, $dataBlock, $traceDetails);
}
// 文档格式:data.logisticsEvents
if (!empty($root['data']['logisticsEvents'])) {
return self::fromExprLogisticsEvents($providerResult, $root['data']);
}
// wuliu.market alicloudapi.com/kdi
if (!empty($root['result']['list'])) {
return self::fromWuliuResult($providerResult, $root['result'], $root);
}
// expQuery 等:data[] 含 context/time
if (!empty($root['data']) && is_array($root['data']) && isset($root['data'][0]['context'])) {
return self::fromExpQueryData($providerResult, $root);
}
$data = $root['data'] ?? $root;
if (!empty($data['logisticsEvents'])) {
return self::fromExprLogisticsEvents($providerResult, $data);
}
return [
'success' => !empty($providerResult['success']),
'trackList' => [],
'expressStatus' => is_string($data['status'] ?? null) ? $data['status'] : '',
'expressCompanyName' => $data['expressCompanyName'] ?? ($root['expTextName'] ?? ''),
'expressCompanyCode' => $data['expressCompany'] ?? ($root['expSpellName'] ?? ''),
'lastDescription' => $root['msg'] ?? '',
'lastTime' => '',
];
}
protected static function pickKzexpressTraceList(array $data)
{
foreach (['logisticsTraceDetailList', 'logisticsTraceDetails', 'logisticsTraceDetail'] as $key) {
if (!empty($data[$key]) && is_array($data[$key])) {
return $data[$key];
}
}
return [];
}
protected static function fromKzexpressTrace(array $providerResult, array $data, array $traceDetails)
{
$trackList = [];
foreach ($traceDetails as $item) {
$time = $item['timeDesc'] ?? '';
if ($time === '' && !empty($item['time']) && is_numeric($item['time'])) {
$ts = (string) $item['time'];
if (strlen($ts) >= 13) {
$time = date('Y-m-d H:i:s', (int) floor($item['time'] / 1000));
} elseif (strlen($ts) === 10) {
$time = date('Y-m-d H:i:s', (int) $item['time']);
}
}
$desc = trim((string) ($item['desc'] ?? ($item['description'] ?? '')));
if ($desc === '') {
$area = trim((string) ($item['areaName'] ?? ($item['location'] ?? '')));
$statusText = trim((string) ($item['subLogisticsStatus'] ?? ($item['logisticsStatus'] ?? '')));
$desc = trim($area . ($statusText !== '' ? ' ' . $statusText : ''));
}
$trackList[] = [
'AcceptTime' => $time,
'AcceptStation' => $desc,
'Location' => $item['areaName'] ?? ($item['city'] ?? ''),
'Action' => self::mapAliyunStateToAction($item['logisticsStatus'] ?? ($item['subLogisticsStatus'] ?? '')),
];
}
usort($trackList, function ($a, $b) {
return strcmp($b['AcceptTime'], $a['AcceptTime']);
});
return [
'success' => !empty($providerResult['success']),
'trackList' => $trackList,
'expressStatus' => $data['logisticsStatusDesc'] ?? ($data['logisticsStatus'] ?? ''),
'expressCompanyName' => $data['logisticsCompanyName'] ?? ($data['cpName'] ?? ''),
'expressCompanyCode' => $data['cpCode'] ?? '',
'expressNo' => $data['mailNo'] ?? ($data['expressNo'] ?? ''),
'lastDescription' => $data['theLastMessage'] ?? (!empty($trackList) ? ($trackList[0]['AcceptStation'] ?? '') : ''),
'lastTime' => $data['theLastTime'] ?? (!empty($trackList) ? ($trackList[0]['AcceptTime'] ?? '') : ''),
];
}
protected static function fromExprLogisticsEvents(array $providerResult, array $data)
{
$trackList = [];
foreach ($data['logisticsEvents'] ?? [] as $event) {
$trackList[] = [
'AcceptTime' => $event['date'] ?? '',
'AcceptStation' => $event['description'] ?? '',
'Location' => $event['location'] ?? ($event['city'] ?? ''),
'Action' => self::mapAliyunStateToAction($event['state'] ?? ''),
];
}
usort($trackList, function ($a, $b) {
return strcmp($b['AcceptTime'], $a['AcceptTime']);
});
return [
'success' => !empty($providerResult['success']),
'trackList' => $trackList,
'expressStatus' => $data['status'] ?? '',
'expressCompanyName' => $data['expressCompanyName'] ?? '',
'expressCompanyCode' => $data['expressCompany'] ?? '',
'lastDescription' => $data['lastDescription'] ?? '',
'lastTime' => $data['lastTime'] ?? '',
];
}
protected static function fromWuliuResult(array $providerResult, array $result, array $root)
{
$trackList = [];
foreach ($result['list'] ?? [] as $item) {
$trackList[] = [
'AcceptTime' => $item['time'] ?? ($item['ftime'] ?? ''),
'AcceptStation' => $item['status'] ?? ($item['context'] ?? ''),
'Location' => $item['location'] ?? '',
'Action' => self::mapAliyunStateToAction($item['status'] ?? ''),
];
}
return [
'success' => !empty($providerResult['success']),
'trackList' => $trackList,
'expressStatus' => $result['deliverystatus'] ?? ($root['msg'] ?? ''),
'expressCompanyName' => $result['expName'] ?? ($result['type'] ?? ''),
'expressCompanyCode' => $result['type'] ?? '',
'lastDescription' => !empty($trackList) ? ($trackList[0]['AcceptStation'] ?? '') : '',
'lastTime' => !empty($trackList) ? ($trackList[0]['AcceptTime'] ?? '') : '',
];
}
protected static function fromExpQueryData(array $providerResult, array $root)
{
$trackList = [];
foreach ($root['data'] as $item) {
$trackList[] = [
'AcceptTime' => $item['time'] ?? '',
'AcceptStation' => $item['context'] ?? '',
'Location' => $item['location'] ?? '',
'Action' => self::mapAliyunStateToAction($item['status'] ?? ''),
];
}
return [
'success' => !empty($providerResult['success']),
'trackList' => $trackList,
'expressStatus' => $root['updateStr'] ?? ($root['msg'] ?? ''),
'expressCompanyName' => $root['expTextName'] ?? '',
'expressCompanyCode' => $root['expSpellName'] ?? '',
'lastDescription' => !empty($trackList) ? ($trackList[0]['AcceptStation'] ?? '') : '',
'lastTime' => !empty($trackList) ? ($trackList[0]['AcceptTime'] ?? '') : '',
];
}
protected static function fromKdniao(array $providerResult)
{
$data = $providerResult['data'] ?? [];
$traces = $data['Traces'] ?? [];
$trackList = [];
foreach ($traces as $trace) {
$trackList[] = [
'AcceptTime' => $trace['AcceptTime'] ?? '',
'AcceptStation' => $trace['AcceptStation'] ?? '',
'Location' => $trace['Location'] ?? '',
'Action' => $trace['Action'] ?? ($data['State'] ?? 0),
];
}
$statusMap = [
'0' => '暂无轨迹',
'1' => '已揽收',
'2' => '运输中',
'3' => '已签收',
'4' => '问题件',
];
$state = (string) ($data['State'] ?? '');
return [
'success' => !empty($providerResult['success']),
'trackList' => $trackList,
'expressStatus' => $statusMap[$state] ?? '',
'expressCompanyName' => $data['ShipperCode'] ?? '',
'expressCompanyCode' => $data['ShipperCode'] ?? '',
'lastDescription' => !empty($trackList) ? ($trackList[0]['AcceptStation'] ?? '') : '',
'lastTime' => !empty($trackList) ? ($trackList[0]['AcceptTime'] ?? '') : '',
];
}
public static function mapAliyunStateToAction($state)
{
$state = trim((string) $state);
$map = [
'已揽收' => 1,
'收件扫描' => 1,
'ACCEPT' => 1,
'运送中' => 2,
'运输中' => 2,
'转运中' => 2,
'入中转' => 2,
'出中转' => 2,
'TRANSPORT'=> 2,
'派送中' => 202,
'待派送' => 202,
'DELIVERING' => 202,
'已签收' => 3,
'SIGN' => 3,
'STA_SIGN' => 3,
'AGENT_SIGN' => 304,
'第三方代收' => 304,
'AGENT_SIGN' => 304,
'问题件' => 4,
'拒收' => 4,
'退回件' => 4,
'FAILED' => 4,
];
if (isset($map[$state])) {
return $map[$state];
}
foreach ($map as $keyword => $action) {
if ($state !== '' && mb_strpos($state, $keyword) !== false) {
return $action;
}
}
return 2;
}
/**
* 修正派件图标(与原 OrderExpress::detail 逻辑一致)
*/
public static function fixDeliveringIcons(array $trackList)
{
if (empty($trackList)) {
return $trackList;
}
foreach ($trackList as $k => &$v) {
if (($v['Action'] ?? null) == 202) {
if ($k >= 2) {
$trackList[$k - 2]['Action'] = 3;
$trackList[$k - 1]['Action'] = 4;
}
}
}
unset($v);
return $trackList;
}
}