补充财务主体缺失阻断诊断
This commit is contained in:
@@ -18,7 +18,7 @@ function ok(data) {
|
||||
return { http: 200, body: { code: '200', data }, requestId: 'request-test', traceId: 'trace-test' }
|
||||
}
|
||||
|
||||
function fakeContext(withFixture = true, permissions = financePermissions, denyFinanceWrites = false) {
|
||||
function fakeContext(withFixture = true, permissions = financePermissions, denyFinanceWrites = false, missingSubject = false) {
|
||||
const marker = 'FIN-TEST-MARKER'
|
||||
const receivables = [
|
||||
{ feeSourceId: '101', orderId: '201', direction: 'RECEIVABLE', currency: 'CNY', businessDate: '2026-08-10' },
|
||||
@@ -85,6 +85,8 @@ function fakeContext(withFixture = true, permissions = financePermissions, denyF
|
||||
}
|
||||
if (method === 'POST' && requestPath.endsWith('/statements')) {
|
||||
if (body.currency !== 'CNY') return { http: 200, body: { code: 'FIN_400' } }
|
||||
if (missingSubject) return { http: 200, body: { code: 'FIN_409', message: '平台财务主体未配置' },
|
||||
requestId: 'request-subject', traceId: 'trace-subject' }
|
||||
const selected = body.generationMode === 'BY_CUTOFF'
|
||||
? receivables.filter((item) => item.businessDate >= body.periodStart && item.businessDate <= body.periodEnd)
|
||||
: feeSources.filter((item) => body.feeSourceIds.includes(item.feeSourceId))
|
||||
@@ -146,6 +148,7 @@ test('静态契约覆盖日期、SELECTED、三 AR、AP、状态机和数组输
|
||||
assert.match(source, /\/api\/platform\/v1\/iam\/authorization\/permissions/)
|
||||
assert.match(source, /rejectedWith\(currencyResponse, 'FIN_400'\)/)
|
||||
assert.match(source, /stale-finance-token-authorities/)
|
||||
assert.match(source, /missing-active-finance-subject/)
|
||||
assert.match(source, /businessDates\.size < 2/)
|
||||
assert.match(source, /receivables\.length < 4/)
|
||||
assert.match(source, /const groups = \[cutoffSources/)
|
||||
@@ -225,3 +228,15 @@ test('权限快照已授权但 Finance 返回 A0403 时立即停止并保留诊
|
||||
assert.equal(context.calls.some((call) => call.body?.generationMode === 'SELECTED'
|
||||
&& call.body?.currency === 'CNY'), false)
|
||||
})
|
||||
|
||||
test('平台财务主体缺失时报明确 blocker 且不继续状态流转', async () => {
|
||||
const context = fakeContext(true, financePermissions, false, true)
|
||||
await run(context)
|
||||
assert.equal(context.coverageGaps.some((gap) => gap.category === 'missing-active-finance-subject'
|
||||
&& gap.reason.includes('requestId=request-subject') && gap.reason.includes('traceId=trace-subject')), true)
|
||||
assert.equal(context.calls.filter((call) => call.method === 'POST'
|
||||
&& call.path.endsWith('/statements')).length, 2)
|
||||
assert.equal(context.calls.some((call) => call.path.includes('/actions')
|
||||
|| call.path.endsWith('/receivable-settlements') || call.path.endsWith('/payable-settlements')), false)
|
||||
assert.equal(context.steps.some((step) => step.name === '第 1 张对账单出账'), false)
|
||||
})
|
||||
|
||||
@@ -29,6 +29,10 @@ function rejectedWith(response, code) {
|
||||
return response?.http === 200 && String(response?.body?.code) === code
|
||||
}
|
||||
function accessDenied(response) { return rejectedWith(response, 'A0403') }
|
||||
function financeSubjectMissing(response) {
|
||||
return rejectedWith(response, 'FIN_409')
|
||||
&& String(response?.body?.message ?? '').includes('平台财务主体未配置')
|
||||
}
|
||||
function sameIds(actual, expected) {
|
||||
const left = [...new Set(actual)].sort()
|
||||
const right = [...new Set(expected)].sort()
|
||||
@@ -301,6 +305,13 @@ export async function run(context) {
|
||||
finish(context, start)
|
||||
return
|
||||
}
|
||||
if (financeSubjectMissing(created.response)) {
|
||||
blocker(context, '平台财务主体 Fixture 门禁',
|
||||
`POST ${BASE}/statements 返回 FIN_409 平台财务主体未配置;sourceIds=${created.body.feeSourceIds.join(',')}, requestId=${created.response.requestId ?? 'null'}, traceId=${created.response.traceId ?? 'null'};需在测试库 fin_subject 中提供 ACTIVE 主体`,
|
||||
'missing-active-finance-subject', created.response)
|
||||
finish(context, start)
|
||||
return
|
||||
}
|
||||
context.assert(MODULE, `第 ${index + 1} 张仅使用分组来源`, created.response,
|
||||
created.statement && sameIds(lineSourceIds(created.statement), groups[index].map((source) => source.feeSourceId)),
|
||||
`expected=${groups[index].length}, actual=${lineSourceIds(created.statement).length}`, OPTIONS)
|
||||
|
||||
Reference in New Issue
Block a user