feat: refine client status and review views
This commit is contained in:
@@ -45,6 +45,7 @@ function createPrismaMock(overrides: Record<string, unknown> = {}) {
|
||||
},
|
||||
smsBatchTask: {
|
||||
count: jest.fn().mockResolvedValue(0),
|
||||
findMany: jest.fn().mockResolvedValue([]),
|
||||
},
|
||||
riskHitRecord: {
|
||||
createMany: jest.fn(),
|
||||
@@ -152,6 +153,21 @@ describe('RiskReviewService', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('adds the associated batch task number to SMS review rows', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
prisma.smsSendTask.findMany.mockResolvedValue([{ id: 'review-task-1', taskNo: 'REVIEW-001' }]);
|
||||
prisma.smsBatchTask.findMany.mockResolvedValue([{ id: 'batch-1', taskNo: 'BATCH-001', riskTaskId: 'review-task-1' }]);
|
||||
const service = new RiskReviewService(prisma as never);
|
||||
|
||||
await expect(service.listTasks(undefined, 'pending_review')).resolves.toEqual([
|
||||
expect.objectContaining({ batchTask: { id: 'batch-1', taskNo: 'BATCH-001' } }),
|
||||
]);
|
||||
expect(prisma.smsBatchTask.findMany).toHaveBeenCalledWith({
|
||||
where: { riskTaskId: { in: ['review-task-1'] } },
|
||||
select: { id: true, taskNo: true, riskTaskId: true },
|
||||
});
|
||||
});
|
||||
|
||||
it('filters SMS review tasks by their submission time', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
prisma.smsSendTask.findMany.mockResolvedValue([]);
|
||||
|
||||
@@ -202,8 +202,8 @@ export class RiskReviewService {
|
||||
});
|
||||
}
|
||||
|
||||
listTasks(tenantId?: string, status?: string, submittedAtFrom?: string, submittedAtTo?: string) {
|
||||
return this.prisma.smsSendTask.findMany({
|
||||
async listTasks(tenantId?: string, status?: string, submittedAtFrom?: string, submittedAtTo?: string) {
|
||||
const tasks = await this.prisma.smsSendTask.findMany({
|
||||
where: {
|
||||
tenantId,
|
||||
status,
|
||||
@@ -231,6 +231,12 @@ export class RiskReviewService {
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
const batchTasks = tasks.length ? await this.prisma.smsBatchTask.findMany({
|
||||
where: { riskTaskId: { in: tasks.map((task) => task.id) } },
|
||||
select: { id: true, taskNo: true, riskTaskId: true },
|
||||
}) : [];
|
||||
const batchByRiskTaskId = new Map(batchTasks.map((task) => [task.riskTaskId, { id: task.id, taskNo: task.taskNo }]));
|
||||
return tasks.map((task) => ({ ...task, batchTask: batchByRiskTaskId.get(task.id) ?? null }));
|
||||
}
|
||||
|
||||
listPendingTasks() {
|
||||
|
||||
@@ -223,14 +223,47 @@ export class SmsSignatureService {
|
||||
updatedAt: true,
|
||||
},
|
||||
},
|
||||
reportTasks: {
|
||||
select: { channelId: true, carrier: true, status: true, approvalScope: true, reportType: true, drainageItemId: true },
|
||||
},
|
||||
_count: { select: { reportMaterials: true } },
|
||||
},
|
||||
orderBy: { updatedAt: 'desc' },
|
||||
skip: query.page && query.pageSize ? (query.page - 1) * query.pageSize : undefined,
|
||||
take: query.pageSize,
|
||||
});
|
||||
const applicationIds = signatures.map((signature) => signature.applicationId).filter((id): id is string => Boolean(id));
|
||||
const routes = applicationIds.length ? await this.prisma.channelRouteRule.findMany({
|
||||
where: { applicationId: { in: applicationIds }, status: 'active' },
|
||||
include: { group: { include: { items: { include: { channel: { include: { reportFields: true } } } } } } },
|
||||
}) : [];
|
||||
const hasCommonDrainageFields = await this.prisma.commonReportField.count({
|
||||
where: { status: 'active', reportType: 'drainage', drainageField: { status: 'active' } },
|
||||
}).then((count) => count > 0);
|
||||
return signatures.map((signature) => {
|
||||
const stored = isRecord(signature.drainageInfo) ? signature.drainageInfo : {};
|
||||
const applicationChannels = [...new Map(routes
|
||||
.filter((route) => route.applicationId === signature.applicationId && route.group)
|
||||
.flatMap((route) => route.group!.items.map((item) => item.channel))
|
||||
.filter((channel) => channel.status !== 'deleted')
|
||||
.map((channel) => [channel.id, channel])).values()];
|
||||
const signatureTasks = signature.reportTasks.filter((task) => task.reportType === 'signature');
|
||||
const carrierReportSummary = Object.fromEntries(['mobile', 'unicom', 'telecom'].map((carrier) => {
|
||||
const targets = applicationChannels.filter((channel) => normalizeChannelCarriers(channel.carriers, channel.carrier).includes(carrier));
|
||||
const statuses = targets.map((channel) => signatureTasks.find((task) => task.channelId === channel.id && task.carrier === carrier)?.status
|
||||
?? signatureTasks.find((task) => task.channelId === channel.id && task.carrier === null && task.approvalScope === 'legacy_channel')?.status
|
||||
?? 'pending');
|
||||
return [carrier, summarizeReportStatuses(statuses)];
|
||||
}));
|
||||
const drainageCarrierReportSummary = Object.fromEntries(signature.drainageItems.map((item) => {
|
||||
const targets = applicationChannels.filter((channel) => hasCommonDrainageFields || channel.reportFields.some((field) => field.status === 'active' && ['drainage', 'both'].includes(field.reportType)));
|
||||
const tasks = signature.reportTasks.filter((task) => task.reportType === 'drainage' && task.drainageItemId === item.id);
|
||||
return [item.id, Object.fromEntries(['mobile', 'unicom', 'telecom'].map((carrier) => {
|
||||
const carrierTargets = targets.filter((channel) => normalizeChannelCarriers(channel.carriers, channel.carrier).includes(carrier));
|
||||
const statuses = carrierTargets.map((channel) => tasks.find((task) => task.channelId === channel.id)?.status ?? 'pending');
|
||||
return [carrier, summarizeReportStatuses(statuses)];
|
||||
}))];
|
||||
}));
|
||||
return {
|
||||
id: signature.id,
|
||||
tenantId: signature.tenantId,
|
||||
@@ -247,6 +280,8 @@ export class SmsSignatureService {
|
||||
application: signature.application,
|
||||
materials: signature.materials,
|
||||
submittedMaterialCount: signature.materials.length + signature._count.reportMaterials,
|
||||
carrierReportSummary,
|
||||
drainageCarrierReportSummary,
|
||||
reportValues: isRecord(stored.signatureReportValues) ? stored.signatureReportValues : {},
|
||||
drainageInfo: {
|
||||
links: signature.drainageItems.map((item) => ({
|
||||
|
||||
Reference in New Issue
Block a user