345d5db9c9
Extend Courier adapter for XFX sign photos and route callbacks; mini-user logistics UI with timeline, phone dial, and estimated arrival. Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
2.6 KiB
TypeScript
87 lines
2.6 KiB
TypeScript
import type { PrismaService } from '../../common/prisma/prisma.module';
|
|
import { XIAOFEIXIA_CMD } from './xiaofeixia/xiaofeixia.constants';
|
|
|
|
const CMD_SCENE: Record<string, string> = {
|
|
[XIAOFEIXIA_CMD.CREATE_ORDER]: 'CREATE_SHIPMENT',
|
|
[XIAOFEIXIA_CMD.TRACK_ROUTE]: 'GET_TRACK',
|
|
[XIAOFEIXIA_CMD.CANCEL_ORDER]: 'CANCEL_SHIPMENT',
|
|
[XIAOFEIXIA_CMD.GET_ORDER]: 'GET_SHIPMENT',
|
|
[XIAOFEIXIA_CMD.ESTIMATE_FREIGHT]: 'ESTIMATE_FREIGHT',
|
|
[XIAOFEIXIA_CMD.BATCH_GET_ORDER]: 'BATCH_GET_SHIPMENT',
|
|
[XIAOFEIXIA_CMD.DELIVERY_COVERAGE]: 'CHECK_COVERAGE',
|
|
[XIAOFEIXIA_CMD.SIGN_PHOTOS]: 'GET_SIGN_PHOTOS',
|
|
};
|
|
|
|
export type CourierLogRef = {
|
|
refType?: string;
|
|
refId?: bigint;
|
|
};
|
|
|
|
export type LogCourierCallInput = {
|
|
scene: string;
|
|
requestUrl: string;
|
|
requestBody?: Record<string, unknown>;
|
|
responseBody?: unknown;
|
|
externalNo?: string;
|
|
status: 'SUCCESS' | 'FAILED' | 'PENDING';
|
|
errorMessage?: string;
|
|
ref?: CourierLogRef;
|
|
};
|
|
|
|
function maskMchId(mchId?: string) {
|
|
if (!mchId) return mchId;
|
|
if (mchId.length <= 4) return '****';
|
|
return `${mchId.slice(0, 4)}****`;
|
|
}
|
|
|
|
/** 请求体入库前脱敏(去掉 sign,商户号打码) */
|
|
export function sanitizeXfxRequestBody(body: Record<string, unknown>) {
|
|
const { sign: _sign, mchId, ...rest } = body;
|
|
return {
|
|
...rest,
|
|
...(mchId != null ? { mchId: maskMchId(String(mchId)) } : {}),
|
|
};
|
|
}
|
|
|
|
export function sceneForXfxCmd(cmd: string) {
|
|
return CMD_SCENE[cmd] ?? `XFX_CMD_${cmd}`;
|
|
}
|
|
|
|
export async function logCourierCall(prisma: PrismaService, input: LogCourierCallInput) {
|
|
const responseBody =
|
|
input.responseBody === undefined
|
|
? undefined
|
|
: typeof input.responseBody === 'object' && input.responseBody !== null
|
|
? (input.responseBody as Record<string, unknown>)
|
|
: { value: input.responseBody };
|
|
|
|
const row = await prisma.logThirdParty.create({
|
|
data: {
|
|
provider: 'XFX',
|
|
scene: input.scene,
|
|
refType: input.ref?.refType,
|
|
refId: input.ref?.refId,
|
|
requestUrl: input.requestUrl.slice(0, 512),
|
|
requestBody: input.requestBody as never,
|
|
responseBody: responseBody as never,
|
|
externalNo: input.externalNo?.slice(0, 128),
|
|
status: input.status,
|
|
errorMessage: input.errorMessage?.slice(0, 512),
|
|
},
|
|
});
|
|
return row.id;
|
|
}
|
|
|
|
export async function resolveOrderRefByOutNumber(
|
|
prisma: PrismaService,
|
|
outNumber?: string,
|
|
): Promise<CourierLogRef | undefined> {
|
|
if (!outNumber?.trim()) return undefined;
|
|
const order = await prisma.order.findUnique({
|
|
where: { orderNo: outNumber.trim() },
|
|
select: { id: true },
|
|
});
|
|
if (!order) return undefined;
|
|
return { refType: 'ORDER', refId: order.id };
|
|
}
|