import { Injectable } from '@nestjs/common'; import { PrismaService } from '../common/prisma/prisma.module'; import { CourierService } from '../integrations/courier/courier.service'; import { XiaofeixiaProvider } from '../integrations/courier/xiaofeixia/xiaofeixia.provider'; import { logCourierCall } from '../integrations/courier/courier-log.util'; import { TradeService } from '../modules/trade/trade.service'; const XFX_PROVIDER_ALIASES = new Set(['xfx', 'xiaofeixia']); @Injectable() export class DeliveryCallbackService { constructor( private readonly prisma: PrismaService, private readonly courier: CourierService, private readonly xiaofeixiaProvider: XiaofeixiaProvider, private readonly tradeService: TradeService, ) {} async handleTrackCallback(providerKey: string, body: unknown, requestUrl: string) { const normalized = providerKey.trim().toLowerCase(); const baseLog = { scene: 'TRACK_CALLBACK', requestUrl, requestBody: (body && typeof body === 'object' ? body : { value: body }) as Record< string, unknown >, }; if (!XFX_PROVIDER_ALIASES.has(normalized) && normalized !== 'logistics') { await logCourierCall(this.prisma, { ...baseLog, status: 'FAILED', errorMessage: `不支持的承运商: ${providerKey}`, }); return this.courier.buildTrackCallbackResponse(false); } if (normalized === 'logistics') { await logCourierCall(this.prisma, { ...baseLog, status: 'SUCCESS', errorMessage: '跨城物流回调暂未接入,已记录', }); return this.courier.buildTrackCallbackResponse(true); } const payload = this.xiaofeixiaProvider.parseTrackCallback(body); if (!payload) { const response = this.courier.buildTrackCallbackResponse(false); await logCourierCall(this.prisma, { ...baseLog, responseBody: response, status: 'FAILED', errorMessage: '回调体解析失败', }); return response; } const order = payload.outNumber ? await this.prisma.order.findUnique({ where: { orderNo: payload.outNumber } }) : payload.trackingNumber ? await this.prisma.order.findFirst({ where: { delivery: { trackingNo: payload.trackingNumber } }, }) : null; if (!order) { const response = this.courier.buildTrackCallbackResponse(false); await logCourierCall(this.prisma, { ...baseLog, responseBody: response, status: 'FAILED', errorMessage: '订单不存在', externalNo: payload.outNumber || payload.trackingNumber, }); return response; } const targetStatus = this.xiaofeixiaProvider.mapTrackStatus( payload.status, payload.statusName, ); let applied = false; if (targetStatus && targetStatus !== order.status) { await this.tradeService.applyStatusTransition( order.id, order.status, targetStatus, 'COURIER_TRACK_CALLBACK', payload.trackInfo || payload.statusName, ); applied = true; } const response = this.courier.buildTrackCallbackResponse(true); await logCourierCall(this.prisma, { ...baseLog, responseBody: response, status: 'SUCCESS', externalNo: order.orderNo, ref: { refType: 'ORDER', refId: order.id }, errorMessage: applied ? undefined : '状态未变更', }); return response; } }