feat: densify sms records and improve uplink matching

This commit is contained in:
hectorzhao
2026-08-27 10:15:08 +08:00
parent 898471423f
commit a280b4bb22
25 changed files with 859 additions and 154 deletions
+1
View File
@@ -303,6 +303,7 @@ export function clientUplinkView(message: Record<string, any>) {
applicationId: message.applicationId ?? null,
messageRecordId: message.messageRecordId ?? null,
messageId: message.messageId ?? null,
gatewayMessageId: message.gatewayMessageId ?? null,
phoneNumber: message.phoneNumber,
destId: message.destId,
content: message.content,
@@ -359,6 +359,50 @@ describe('OperationsService', () => {
});
});
it('returns the matched message record and the distinct uplink gateway message id to the client view', async () => {
const prisma = createPrismaMock();
prisma.smsUplinkMessage.findMany.mockResolvedValue([{
id: 'uplink-1',
tenantId: 'tenant-1',
applicationId: 'app-1',
messageRecordId: 'record-1',
messageId: null,
gatewayMessageId: '8412634832294102675',
phoneNumber: '13800000001',
destId: '10690000',
content: 'TD',
matchStatus: 'matched',
matchReason: '手机号 72 小时窗口唯一匹配',
receivedAt: new Date('2026-08-26T01:00:00.000Z'),
createdAt: new Date('2026-08-26T01:00:00.000Z'),
application: { id: 'app-1', name: '应用A' },
messageRecord: {
id: 'record-1',
applicationId: 'app-1',
messageId: 'MSG-1',
phoneNumber: '13800000001',
content: '通知内容',
billingUnits: 1,
amountCents: 325,
status: 'delivered',
queuedAt: new Date('2026-08-25T01:00:00.000Z'),
application: { id: 'app-1', name: '应用A' },
},
matchCandidates: [],
}]);
const service = new OperationsService(prisma as never);
const [uplink] = await service.listClientUplinkMessages({ tenantId: 'tenant-1' });
expect(uplink).toMatchObject({
messageId: null,
gatewayMessageId: '8412634832294102675',
messageRecordId: 'record-1',
matchStatus: 'matched',
messageRecord: { id: 'record-1', messageId: 'MSG-1' },
});
});
it('returns client message views without supplier channel, submit, tenant, or gateway internals', async () => {
const prisma = createPrismaMock();
prisma.smsMessageRecord.findMany.mockResolvedValue([{
@@ -118,6 +118,7 @@ export interface GatewayUplinkEventDto {
eventId?: string;
traceId?: string;
messageId?: string;
gatewayMessageId?: string;
channelId: string;
sequenceId?: number;
phoneNumber: string;
@@ -3749,6 +3749,7 @@ describe('SendChainService', () => {
});
await service.handleUplink({
messageId: 'MSG-1',
gatewayMessageId: '8412634832294102675',
channelId: 'channel-1',
sequenceId: 8,
phoneNumber: '13800000001',
@@ -3761,7 +3762,7 @@ describe('SendChainService', () => {
data: expect.objectContaining({ receiptStatus: 'delivered', rawStatus: 'DELIVRD', messageRecordId: 'record-1' }),
});
expect(prisma.smsUplinkMessage.create).toHaveBeenCalledWith({
data: expect.objectContaining({ tenantId: 'tenant-1', channelId: 'channel-1', content: 'TD' }),
data: expect.objectContaining({ tenantId: 'tenant-1', channelId: 'channel-1', gatewayMessageId: '8412634832294102675', content: 'TD' }),
});
});
@@ -45,6 +45,7 @@ export class SendDownstreamDeliveryService {
messageRecordId: match.messageRecordId,
channelId: data.channelId,
messageId: data.messageId,
gatewayMessageId: data.gatewayMessageId,
sequenceId: data.sequenceId,
phoneNumber: data.phoneNumber,
destId: data.destId,