feat: complete reporting and filing workflows

This commit is contained in:
hectorzhao
2026-07-28 20:28:47 +08:00
parent 352a6293b4
commit 99c8c7c68b
52 changed files with 3490 additions and 376 deletions
@@ -521,6 +521,96 @@ describe('OperationsService', () => {
await expect(service.sendQuality('2026-02-31')).rejects.toThrow('统计日期无效');
});
it('returns paged registered-signature quality with channel and carrier breakdowns', async () => {
const prisma = createPrismaMock();
prisma.$queryRaw
.mockResolvedValueOnce([{
signatureId: 'signature-1',
signatureName: '【测试签名】',
tenantId: 'tenant-1',
tenantName: '租户A',
applicationNames: '通知应用、营销应用',
total: 5,
acceptedCount: 4,
submitFailureCount: 1,
successCount: 3,
unknownCount: 1,
failureCount: 0,
successRate: 75,
averageArrivalMs: 1200,
rowCount: 12,
}])
.mockResolvedValueOnce([
{
signatureId: 'signature-1',
channelId: 'channel-1',
channelName: '通道一',
carrier: 'mobile',
total: 4,
acceptedCount: 4,
submitFailureCount: 0,
successCount: 3,
unknownCount: 1,
failureCount: 0,
successRate: 75,
averageArrivalMs: 1200,
},
{
signatureId: 'signature-1',
channelId: 'channel-2',
channelName: '通道二',
carrier: 'telecom',
total: 2,
acceptedCount: 1,
submitFailureCount: 1,
successCount: 1,
unknownCount: 0,
failureCount: 0,
successRate: 100,
averageArrivalMs: 1800,
},
]);
const service = new OperationsService(prisma as never);
await expect(service.signatureQuality({
date: '2026-07-24',
keyword: '测试',
page: 2,
pageSize: 5,
})).resolves.toEqual({
date: '2026-07-24',
items: [expect.objectContaining({
signatureId: 'signature-1',
signatureName: '【测试签名】',
total: 5,
channelSubmitTotal: 6,
breakdowns: [
expect.objectContaining({ channelId: 'channel-1', carrier: 'mobile', total: 4 }),
expect.objectContaining({ channelId: 'channel-2', carrier: 'telecom', total: 2 }),
],
})],
total: 12,
page: 2,
pageSize: 5,
});
expect(prisma.$queryRaw).toHaveBeenCalledTimes(2);
});
it('does not query channel details when the selected date has no registered signatures', async () => {
const prisma = createPrismaMock();
prisma.$queryRaw.mockResolvedValueOnce([]);
const service = new OperationsService(prisma as never);
await expect(service.signatureQuality({ date: '2026-07-24' })).resolves.toEqual({
date: '2026-07-24',
items: [],
total: 0,
page: 1,
pageSize: 10,
});
expect(prisma.$queryRaw).toHaveBeenCalledTimes(1);
});
it('returns trace details and reconciliation diffs', async () => {
const prisma = createPrismaMock();
const service = new OperationsService(prisma as never);
@@ -813,6 +903,8 @@ describe('OperationsService', () => {
state: 'waiting_connection',
failureCategory: 'client_disconnected',
keyword: '100001',
updatedAtFrom: '2026-07-02',
updatedAtTo: '2026-07-08',
page: 1,
pageSize: 10,
})).resolves.toEqual({
@@ -832,6 +924,14 @@ describe('OperationsService', () => {
],
},
});
expect(prisma.gatewayDownstreamRecoveryStatus.findMany).toHaveBeenCalledWith(expect.objectContaining({
where: expect.objectContaining({
updatedAt: {
gte: new Date('2026-07-01T16:00:00.000Z'),
lte: new Date('2026-07-08T15:59:59.999Z'),
},
}),
}));
});
it('returns downstream recovery status detail', async () => {
@@ -860,6 +960,8 @@ describe('OperationsService', () => {
tenantId: 'tenant-1',
state: 'waiting_connection',
keyword: '100001',
updatedAtFrom: '2026-07-02',
updatedAtTo: '2026-07-08',
})).resolves.toEqual(expect.objectContaining({
total: 1,
fileName: expect.stringMatching(/^gateway-downstream-recovery-statuses-\d{8}-\d{6}\.csv$/),
@@ -868,6 +970,10 @@ describe('OperationsService', () => {
expect(prisma.gatewayDownstreamRecoveryStatus.findMany).toHaveBeenCalledWith(expect.objectContaining({
where: expect.objectContaining({
failureCategory: undefined,
updatedAt: {
gte: new Date('2026-07-01T16:00:00.000Z'),
lte: new Date('2026-07-08T15:59:59.999Z'),
},
}),
}));
});