feat: improve operations diagnostics and channel management
This commit is contained in:
@@ -15,6 +15,7 @@ export class ChannelGroupRoutingService {
|
||||
|
||||
listGroups() {
|
||||
return this.prisma.smsChannelGroup.findMany({
|
||||
where: { status: { not: 'deleted' } },
|
||||
include: { items: { include: { channel: { include: { connectionStates: true } } }, orderBy: [{ province: 'asc' }, { priority: 'asc' }] } },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
@@ -158,23 +159,78 @@ export class ChannelGroupRoutingService {
|
||||
});
|
||||
}
|
||||
|
||||
async deleteGroup(groupId: string) {
|
||||
const group = await this.prisma.smsChannelGroup.findUnique({ where: { id: groupId } });
|
||||
async getGroupDeletionImpact(groupId: string) {
|
||||
const group = await this.prisma.smsChannelGroup.findUnique({
|
||||
where: { id: groupId },
|
||||
select: { id: true, name: true, items: { select: { id: true } } },
|
||||
});
|
||||
if (!group) {
|
||||
throw new NotFoundException('Channel group not found');
|
||||
}
|
||||
const boundRoute = await this.prisma.channelRouteRule.findFirst({
|
||||
where: {
|
||||
groupId,
|
||||
status: 'active',
|
||||
},
|
||||
select: { id: true },
|
||||
const routes = await this.prisma.channelRouteRule.findMany({
|
||||
where: { groupId, applicationId: { not: null }, status: { not: 'deleted' } },
|
||||
select: { applicationId: true },
|
||||
});
|
||||
if (boundRoute) {
|
||||
throw new BadRequestException('Channel group is used by application route rules and cannot be deleted');
|
||||
const applicationIds = [...new Set(routes.flatMap((route) => route.applicationId ? [route.applicationId] : []))];
|
||||
const [applications, pendingSupplierSubmitCount] = await Promise.all([
|
||||
this.prisma.smsApplication.findMany({
|
||||
where: { id: { in: applicationIds } },
|
||||
select: { id: true, status: true },
|
||||
}),
|
||||
this.prisma.smsSubmitRecord.count({
|
||||
where: { channelGroupId: groupId, submitStatus: 'queued' },
|
||||
}),
|
||||
]);
|
||||
const applicationStatusById = new Map(applications.map((application) => [application.id, application.status]));
|
||||
const deletedApplicationCount = applicationIds.filter((applicationId) => {
|
||||
const status = applicationStatusById.get(applicationId);
|
||||
return status === undefined || status === 'deleted';
|
||||
}).length;
|
||||
|
||||
return {
|
||||
groupId: group.id,
|
||||
groupName: group.name,
|
||||
normalApplicationCount: applicationIds.length - deletedApplicationCount,
|
||||
deletedApplicationCount,
|
||||
channelCount: group.items.length,
|
||||
pendingSupplierSubmitCount,
|
||||
};
|
||||
}
|
||||
|
||||
async deleteGroup(groupId: string) {
|
||||
const group = await this.prisma.smsChannelGroup.findUnique({
|
||||
where: { id: groupId },
|
||||
include: { items: { include: { channel: true }, orderBy: [{ province: 'asc' }, { priority: 'asc' }] } },
|
||||
});
|
||||
if (!group) {
|
||||
throw new NotFoundException('Channel group not found');
|
||||
}
|
||||
await this.prisma.smsChannelGroupItem.deleteMany({ where: { groupId } });
|
||||
return this.prisma.smsChannelGroup.delete({ where: { id: groupId } });
|
||||
if (group.status === 'deleted') {
|
||||
return group;
|
||||
}
|
||||
const impact = await this.getGroupDeletionImpact(groupId);
|
||||
|
||||
// Logical deletion keeps group items and route bindings available for historical
|
||||
// receipts and uplink access-number matching; new submits already require an active group.
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
const deleted = await tx.smsChannelGroup.update({
|
||||
where: { id: groupId },
|
||||
data: { status: 'deleted' },
|
||||
});
|
||||
await tx.operationLog.create({
|
||||
data: {
|
||||
action: 'sms_channel_group.delete',
|
||||
resource: 'sms_channel_group',
|
||||
resourceId: groupId,
|
||||
detail: {
|
||||
before: channelGroupAuditSnapshot(group),
|
||||
impact,
|
||||
deletionMode: 'soft_delete',
|
||||
} as Prisma.InputJsonValue,
|
||||
},
|
||||
});
|
||||
return deleted;
|
||||
}, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable });
|
||||
}
|
||||
|
||||
listRouteRules() {
|
||||
|
||||
Reference in New Issue
Block a user