This commit is contained in:
2026-08-20 16:13:51 +08:00
parent 164d862588
commit 09f6e28c1f
10 changed files with 164 additions and 15 deletions
@@ -15,7 +15,8 @@ test('Finance AP consumes only published fin_fee_source rows and never substitut
assert.match(source, /!isUnboundContainerCost\(source\.raw\) \|\| hasContainerAllocations/)
})
const financePermissions = [
'platform:finance:customer-account:list', 'platform:finance:customer-statement:list',
'platform:finance:customer-account:list', 'platform:finance:customer-arap:list',
'platform:finance:fee-source:review', 'platform:finance:customer-statement:list',
'platform:finance:reconciliation:create', 'platform:finance:reconciliation:review',
'platform:finance:reconciliation:issue', 'platform:finance:reconciliation:adjust',
'platform:finance:reconciliation:void', 'platform:finance:settlement-ar:create',
@@ -58,12 +59,13 @@ function fakeContext(withFixture = true, permissions = financePermissions, denyF
const calls = []
const steps = []
const coverageGaps = []
const reviewedSourceIds = new Set()
function responseForStatement(statement) { return structuredClone(statement) }
function applyAction(statement, body) {
const status = { SUBMIT: 'PENDING_REVIEW', APPROVE: 'APPROVED', REJECT: 'REJECTED',
ISSUE: 'ISSUED', ADJUST: 'ISSUED', VOID: 'VOIDED', REOPEN: 'DRAFT' }[body.action]
statement.revisions.push({ action: `RECONCILIATION_${body.action}` })
statement.revisions.push({ action: body.action })
statement.status = status
statement.version += 1
if (body.action === 'ADJUST') {
@@ -112,6 +114,20 @@ function fakeContext(withFixture = true, permissions = financePermissions, denyF
reviewStatus: 'APPROVED', sourceStatus: 'AVAILABLE' }
}))
}
const feeSourceDetailMatch = requestPath.match(/\/fee-sources\/(\d+)$/)
if (method === 'GET' && feeSourceDetailMatch) {
const localId = feeSourceDetailMatch[1]
return ok({ feeSourceId: localId, reviewStatus: reviewedSourceIds.has(localId) ? 'APPROVED' : 'PENDING',
sourceStatus: 'AVAILABLE', statementGenerated: false, operationVersion: reviewedSourceIds.has(localId) ? 1 : 0 })
}
const feeSourceReviewMatch = requestPath.match(/\/fee-sources\/(\d+)\/review$/)
if (method === 'POST' && feeSourceReviewMatch) {
reviewedSourceIds.add(feeSourceReviewMatch[1])
const reviewed = { feeSourceId: feeSourceReviewMatch[1], reviewStatus: 'APPROVED',
sourceStatus: 'AVAILABLE', statementGenerated: false, operationVersion: 1 }
if (idem) idempotency.set(idem, reviewed)
return ok(reviewed)
}
if (method === 'POST' && requestPath.endsWith('/statements')) {
if (body.currency !== 'CNY') return { http: 200, body: { code: 'FIN_400' } }
if (String(body.customerId) !== '11') return { http: 200, body: { code: 'FIN_404' } }