fix: remove truncated management totals

This commit is contained in:
hectorzhao
2026-07-12 10:56:00 +08:00
parent 24cb632a45
commit 390b970032
19 changed files with 107 additions and 80 deletions
-1
View File
@@ -21,7 +21,6 @@ export class AuditService {
return this.prisma.operationLog.findMany({
where: tenantId ? { tenantId } : undefined,
orderBy: { createdAt: 'desc' },
take: 100,
});
}
+2 -6
View File
@@ -89,7 +89,7 @@ export class BillingService {
constructor(private readonly prisma: PrismaService) {}
listPlans() {
return this.prisma.billingPlan.findMany({ orderBy: { createdAt: 'desc' }, take: 100 });
return this.prisma.billingPlan.findMany({ orderBy: { createdAt: 'desc' } });
}
createPlan(data: CreateBillingPlanDto) {
@@ -109,7 +109,6 @@ export class BillingService {
return this.prisma.tenantAccount.findMany({
include: { tenant: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -129,7 +128,6 @@ export class BillingService {
where: tenantId ? { tenantId } : undefined,
include: { plan: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -141,7 +139,6 @@ export class BillingService {
},
include: { plan: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
const orderIds = orders.map((order) => order.id);
if (orderIds.length === 0) {
@@ -328,12 +325,11 @@ export class BillingService {
return this.prisma.smsBillingRecord.findMany({
where: { tenantId, taskId },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
listRules() {
return this.prisma.billingRule.findMany({ orderBy: { createdAt: 'desc' }, take: 100 });
return this.prisma.billingRule.findMany({ orderBy: { createdAt: 'desc' } });
}
createRule(data: CreateBillingRuleDto) {
@@ -35,7 +35,6 @@ export class CertificationService {
},
include: { tenant: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -715,13 +715,11 @@ describe('ChannelsService', () => {
expect(prisma.cmppConnectionState.findMany).toHaveBeenCalledWith({
where: { channelId: 'channel-1' },
orderBy: { updatedAt: 'desc' },
take: 100,
});
expect(prisma.cmppConnectionState.findMany).toHaveBeenCalledWith({
where: { tenantId: 'tenant-1' },
include: { channel: true },
orderBy: { updatedAt: 'desc' },
take: 100,
});
expect(prisma.operationLog.create).toHaveBeenCalledWith({
data: expect.objectContaining({
-9
View File
@@ -198,7 +198,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
return this.prisma.smsChannel.findMany({
include: { connectionStates: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -531,7 +530,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
return this.prisma.cmppConnectionState.findMany({
where: { channelId },
orderBy: { updatedAt: 'desc' },
take: 100,
});
}
@@ -576,7 +574,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
where: { tenantId },
include: { channel: true },
orderBy: { updatedAt: 'desc' },
take: 100,
});
}
@@ -705,7 +702,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
return this.prisma.smsChannelGroup.findMany({
include: { items: { include: { channel: { include: { connectionStates: true } } }, orderBy: [{ province: 'asc' }, { priority: 'asc' }] } },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -857,7 +853,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
return this.prisma.channelRouteRule.findMany({
include: { group: true, channel: true },
orderBy: [{ priority: 'asc' }, { createdAt: 'desc' }],
take: 100,
});
}
@@ -900,7 +895,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
return this.prisma.channelReportField.findMany({
where: channelId ? { channelId } : undefined,
orderBy: [{ sortOrder: 'asc' }, { createdAt: 'desc' }],
take: 200,
});
}
@@ -926,7 +920,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
channelId,
},
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -958,7 +951,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
where: { tenantId, status },
include: { signature: true, channel: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -1021,7 +1013,6 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
return this.prisma.channelSignatureReportRecord.findMany({
where: { taskId, channelId },
orderBy: { createdAt: 'desc' },
take: 200,
});
}
+1 -4
View File
@@ -140,7 +140,6 @@ export class DictionariesService {
] : undefined,
},
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -173,7 +172,6 @@ export class DictionariesService {
] : undefined,
},
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -214,7 +212,6 @@ export class DictionariesService {
},
include: { tenant: true, application: true },
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -254,7 +251,7 @@ export class DictionariesService {
}
listDrainageFields() {
return this.prisma.drainageField.findMany({ orderBy: { createdAt: 'desc' }, take: 200 });
return this.prisma.drainageField.findMany({ orderBy: { createdAt: 'desc' } });
}
createDrainageField(data: CreateDrainageFieldDto) {
-1
View File
@@ -37,7 +37,6 @@ export class FilesService {
return this.prisma.fileObject.findMany({
where: tenantId ? { tenantId } : undefined,
orderBy: { createdAt: 'desc' },
take: 100,
}).then((items) => items.map(serializeFileObject));
}
@@ -202,7 +202,6 @@ describe('OperationsService', () => {
},
include: { tenant: true, application: true, channel: true, submitRecords: true, receiptRecords: true },
orderBy: { queuedAt: 'desc' },
take: 500,
});
});
@@ -229,7 +228,6 @@ describe('OperationsService', () => {
},
},
orderBy: { receivedAt: 'desc' },
take: 500,
});
});
-4
View File
@@ -81,7 +81,6 @@ export class OperationsService {
where: { tenantId: query.tenantId, status: query.status },
include: { apiRequests: true },
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -90,7 +89,6 @@ export class OperationsService {
where: messageWhere(query),
include: { tenant: true, application: true, channel: true, submitRecords: true, receiptRecords: true },
orderBy: { queuedAt: 'desc' },
take: 500,
});
}
@@ -112,7 +110,6 @@ export class OperationsService {
},
},
orderBy: { receivedAt: 'desc' },
take: 500,
});
}
@@ -303,7 +300,6 @@ export class OperationsService {
return this.prisma.operationLog.findMany({
where: { tenantId: query.tenantId, userId: query.userId },
orderBy: { createdAt: 'desc' },
take: 500,
});
}
@@ -118,7 +118,6 @@ export class RiskReviewService {
return this.prisma.riskRule.findMany({
where: tenantId ? { OR: [{ tenantId: null }, { tenantId }] } : undefined,
orderBy: [{ priority: 'asc' }, { createdAt: 'asc' }],
take: 200,
});
}
@@ -146,7 +145,6 @@ export class RiskReviewService {
taskId,
},
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -158,7 +156,6 @@ export class RiskReviewService {
},
include: { riskHits: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
+13 -10
View File
@@ -331,19 +331,28 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
return this.getBatchTask(task.id);
}
listBatchTasks(tenantId?: string, status?: string) {
return this.prisma.smsBatchTask.findMany({
async listBatchTasks(tenantId?: string, status?: string) {
const tasks = await this.prisma.smsBatchTask.findMany({
where: { tenantId, status },
include: {
tenant: true,
application: true,
template: true,
apiRequests: true,
messages: { include: { channel: true }, orderBy: { queuedAt: 'asc' }, take: 100000 },
},
orderBy: { createdAt: 'desc' },
take: 100,
});
const taskIds = tasks.map((task) => task.id);
const messageStats = taskIds.length > 0 ? await this.prisma.smsMessageRecord.groupBy({
by: ['batchTaskId', 'carrier', 'province', 'status'],
where: { batchTaskId: { in: taskIds } },
_count: { _all: true },
_sum: { billingUnits: true },
}) : [];
return tasks.map((task) => ({
...task,
messageStats: messageStats.filter((item) => item.batchTaskId === task.id),
}));
}
getBatchTask(taskId: string) {
@@ -378,7 +387,6 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
receiptRecords: { include: { channel: true }, orderBy: { createdAt: 'asc' } },
},
orderBy: { queuedAt: 'desc' },
take: 500,
});
}
@@ -386,7 +394,6 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
return this.prisma.smsSubmitRecord.findMany({
where: { batchTaskId: taskId },
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -394,7 +401,6 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
return this.prisma.smsReceiptRecord.findMany({
where: { batchTaskId: taskId },
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -403,7 +409,6 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
where: { tenantId, channelId },
include: { application: true, channel: true, messageRecord: { include: { application: true } } },
orderBy: { receivedAt: 'desc' },
take: 200,
});
}
@@ -542,7 +547,6 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
const tasks = await this.prisma.smsBatchTask.findMany({
where: { status: 'scheduled', scheduledAt: { lte: now } },
orderBy: { scheduledAt: 'asc' },
take: 100,
});
const results: Array<{ taskId: string; status: string; enqueued?: number; reason?: string }> = [];
for (const task of tasks) {
@@ -1812,7 +1816,6 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
const rules = await this.prisma.phoneCarrierRule.findMany({
where: { status: 'active' },
orderBy: [{ priority: 'asc' }, { createdAt: 'asc' }],
take: 100,
});
for (const rule of rules) {
try {
+14 -1
View File
@@ -16,7 +16,6 @@ function createPrismaMock() {
interfaceType: 'cmpp20',
queuePriority: 'normal',
tenant: { id: 'tenant-1', name: '租户A', code: 'TENANT-A' },
messageRecords: [{ status: 'delivered' }, { status: 'undelivered' }],
}]),
findUnique: jest.fn().mockResolvedValue({
id: 'app-1',
@@ -106,6 +105,12 @@ function createPrismaMock() {
update: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'downstream-1', ...data })),
updateMany: jest.fn().mockResolvedValue({ count: 0 }),
},
smsMessageRecord: {
groupBy: jest.fn().mockResolvedValue([
{ applicationId: 'app-1', status: 'delivered', _count: { _all: 1 } },
{ applicationId: 'app-1', status: 'undelivered', _count: { _all: 1 } },
]),
},
smsChannel: {
findFirst: jest.fn().mockResolvedValue({
id: 'channel-1',
@@ -177,6 +182,14 @@ describe('SmsConfigService', () => {
cmppConnections: [expect.objectContaining({ connectionId: 'gateway-1-1', account: '100001' })],
}),
]);
expect(prisma.smsApplication.findMany).toHaveBeenCalledWith(expect.objectContaining({
include: { tenant: true, ipAllowlist: true },
}));
expect(prisma.smsApplication.findMany.mock.calls[0][0]).not.toHaveProperty('take');
expect(prisma.smsMessageRecord.groupBy).toHaveBeenCalledWith(expect.objectContaining({
by: ['applicationId', 'status'],
_count: { _all: true },
}));
});
it('returns CMPP params from persisted application and channel config', async () => {
+27 -27
View File
@@ -123,7 +123,7 @@ export class SmsConfigService {
if (query.includeConnections) {
await this.markTimedOutDownstreamConnections();
}
return this.prisma.smsApplication.findMany({
const applications = await this.prisma.smsApplication.findMany({
where: {
tenantId: query.tenantId,
OR: query.keyword ? [
@@ -134,32 +134,36 @@ export class SmsConfigService {
include: {
tenant: true,
ipAllowlist: true,
messageRecords: { where: { queuedAt: { gte: startOfToday() } }, take: 1000 },
},
orderBy: { createdAt: 'desc' },
take: 100,
}).then(async (applications) => {
if (!query.includeConnections) {
return applications;
}
const applicationIds = applications.map((application) => application.id);
const connections = await this.prisma.cmppDownstreamConnection.findMany({
});
if (!query.includeConnections) {
return applications;
}
const applicationIds = applications.map((application) => application.id);
const [connections, messageStats] = await Promise.all([
this.prisma.cmppDownstreamConnection.findMany({
where: { applicationId: { in: applicationIds } },
orderBy: { updatedAt: 'desc' },
take: 500,
});
return applications.map((application) => {
const appConnections = connections.filter((connection) => connection.applicationId === application.id);
const todayTotal = application.messageRecords.length;
const delivered = application.messageRecords.filter((message) => message.status === 'delivered').length;
return {
...application,
cmppConnections: appConnections,
cmppStatus: normalizeApplicationCmppStatus(appConnections, application.status),
sentToday: todayTotal,
deliveryRate: todayTotal > 0 ? Number(((delivered / todayTotal) * 100).toFixed(1)) : 0,
};
});
}),
this.prisma.smsMessageRecord.groupBy({
by: ['applicationId', 'status'],
where: { applicationId: { in: applicationIds }, queuedAt: { gte: startOfToday() } },
_count: { _all: true },
}),
]);
return applications.map((application) => {
const appConnections = connections.filter((connection) => connection.applicationId === application.id);
const appStats = messageStats.filter((item) => item.applicationId === application.id);
const todayTotal = appStats.reduce((sum, item) => sum + item._count._all, 0);
const delivered = appStats.find((item) => item.status === 'delivered')?._count._all ?? 0;
return {
...application,
cmppConnections: appConnections,
cmppStatus: normalizeApplicationCmppStatus(appConnections, application.status),
sentToday: todayTotal,
deliveryRate: todayTotal > 0 ? Number(((delivered / todayTotal) * 100).toFixed(1)) : 0,
};
});
}
@@ -366,7 +370,6 @@ export class SmsConfigService {
const connections = await this.prisma.cmppDownstreamConnection.findMany({
where: { applicationId },
orderBy: { updatedAt: 'desc' },
take: 100,
});
return {
application,
@@ -513,7 +516,6 @@ export class SmsConfigService {
},
include: { materials: true, tenant: true, application: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -596,7 +598,6 @@ export class SmsConfigService {
},
include: { variables: true, application: true, tenant: true, signature: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -696,7 +697,6 @@ export class SmsConfigService {
targetId,
},
orderBy: { createdAt: 'desc' },
take: 100,
});
}
+2
View File
@@ -93,6 +93,8 @@ describe('TenantsService', () => {
expect(prisma.tenant.findMany).toHaveBeenCalledWith(expect.objectContaining({
where: { status: { not: 'deleted' } },
}));
expect(prisma.tenant.findMany.mock.calls[0][0]).not.toHaveProperty('take');
expect(prisma.tenantAccount.findMany).toHaveBeenCalledWith();
expect(prisma.smsMessageRecord.groupBy).toHaveBeenCalledWith(expect.objectContaining({
by: ['tenantId'],
_sum: { amountCents: true },
+1 -3
View File
@@ -40,7 +40,6 @@ export class TenantsService {
return this.prisma.tenant.findMany({
include: { enterpriseCertifications: { orderBy: { submittedAt: 'desc' }, take: 1 } },
orderBy: { createdAt: 'desc' },
take: 100,
}).then((items) => items.map(withEnterpriseProfile));
}
@@ -51,9 +50,8 @@ export class TenantsService {
where: { status: { not: 'deleted' } },
include: { enterpriseCertifications: { orderBy: { submittedAt: 'desc' }, take: 1 } },
orderBy: { createdAt: 'desc' },
take: 100,
}),
this.prisma.tenantAccount.findMany({ take: 200 }),
this.prisma.tenantAccount.findMany(),
this.prisma.smsMessageRecord.groupBy({
by: ['tenantId'],
where: { queuedAt: { gte: sinceToday } },
+1 -3
View File
@@ -79,7 +79,6 @@ export class UsersService {
},
include: { tenant: true, roles: { include: { role: true } } },
orderBy: { createdAt: 'desc' },
take: 200,
});
}
@@ -240,7 +239,6 @@ export class UsersService {
return this.prisma.role.findMany({
include: { permissions: { include: { permission: true } } },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
@@ -256,7 +254,7 @@ export class UsersService {
}
listPermissions() {
return this.prisma.permission.findMany({ orderBy: { createdAt: 'desc' }, take: 200 });
return this.prisma.permission.findMany({ orderBy: { createdAt: 'desc' } });
}
createPermission(data: CreatePermissionDto) {