fix: align signature review and admin operations

This commit is contained in:
hectorzhao
2026-07-27 22:07:51 +08:00
parent 9891ffee23
commit df70b336a0
22 changed files with 326 additions and 57 deletions
@@ -4,7 +4,16 @@ import { ReviewGovernanceService } from './review-governance.service';
function signature(overrides: Record<string, unknown> = {}) {
return {
id: 'sig-1', tenantId: 'tenant-1', applicationId: 'app-1', name: '签名A', purpose: null,
drainageInfo: { signatureProfile: { companyName: '企业A', creditCode: '9133', legalPersonName: '法人', responsibleName: '责任人', responsiblePhone: '13800000000', credentialFile: { fileObjectId: 'file-1' } } },
drainageInfo: {
signatureReportValues: { companyName: '企业A', credentialFile: { fileObjectId: 'file-1' } },
reportRequirementSnapshot: {
fields: [
{ code: 'companyName', name: '公司名称', required: true, reportTypes: ['signature'] },
{ code: 'credentialFile', name: '资质文件', required: true, reportTypes: ['signature'] },
{ code: 'siteOwner', name: '网站主体', required: true, reportTypes: ['drainage'] },
],
},
},
auditStatus: 'pending', reportStatus: 'waiting_material', rejectReason: null, materialVersion: 1,
pendingReport: true, reportChangedAt: new Date(), createdAt: new Date(), updatedAt: new Date('2026-07-21T08:00:00.000Z'),
tenant: { id: 'tenant-1', name: '企业A' }, application: { id: 'app-1', name: '应用A' }, materials: [],
@@ -32,13 +41,46 @@ function prismaMock() {
describe('ReviewGovernanceService', () => {
it('blocks approval when required signature qualification is incomplete', async () => {
const prisma = prismaMock();
prisma.smsSignature.findUnique.mockResolvedValue(signature({ applicationId: null, application: null, drainageInfo: {}, materials: [] }));
prisma.smsSignature.findUnique.mockResolvedValue(signature({
applicationId: null,
application: null,
drainageInfo: {
signatureReportValues: {},
reportRequirementSnapshot: {
fields: [
{ code: 'companyName', name: '公司名称', required: true, reportTypes: ['signature'] },
{ code: 'credentialFile', name: '资质文件', required: true, reportTypes: ['both'] },
{ code: 'siteOwner', name: '网站主体', required: true, reportTypes: ['drainage'] },
],
},
},
materials: [],
}));
const service = new ReviewGovernanceService(prisma as never);
const result = await service.preflight('signature', 'sig-1');
expect(result.allowedActions).toEqual(['reject']);
expect(result.blockedReasons).toEqual(expect.arrayContaining(['未绑定短信应用', '缺少公司名称', '缺少资质文件']));
expect(result.blockedReasons).not.toContain('缺少网站主体');
});
it('does not invent legacy qualification requirements when the configured channel has no signature fields', async () => {
const prisma = prismaMock();
prisma.smsSignature.findUnique.mockResolvedValue(signature({
drainageInfo: {
signatureReportValues: {},
reportRequirementSnapshot: {
fields: [{ code: 'icpNo', name: 'ICP备案号', required: true, reportTypes: ['drainage'] }],
},
},
}));
const service = new ReviewGovernanceService(prisma as never);
const result = await service.preflight('signature', 'sig-1');
expect(result.allowedActions).toEqual(['approve', 'reject']);
expect(result.blockedReasons).toEqual([]);
});
it('atomically approves the expected version and returns an audit operation id', async () => {