This commit is contained in:
2026-10-20 14:22:53 +08:00
parent 19745e46c1
commit bf2508b6d6
24 changed files with 1222 additions and 88 deletions
@@ -504,3 +504,77 @@ test('F04 still rejects a numeric error row pointing to the successful row', asy
const { r } = importHarness('wrong-error-row')
await assert.rejects(() => r.orderExcelImportModule(), /actual Excel error row/)
})
test('F01 client bills module covers customer-only read APIs and rejects unknown documents', async () => {
const source = await readFile(new URL('./client-test-env-acceptance.mjs', import.meta.url), 'utf8')
assert.match(source, /async function merchantFinanceBillsModule\(\)/)
assert.match(source, /await merchantFinanceBillsModule\(\)/)
const callOrder = [
source.indexOf('await orderSubmissionChannelGateModule()'),
source.indexOf('await merchantFinanceBillsModule()'),
source.indexOf('await notificationInboxModule()'),
]
assert.ok(callOrder[0] >= 0 && callOrder[1] > callOrder[0] && callOrder[2] > callOrder[1],
'bills module must run after channel gate and before notifications')
assert.match(source, /const base = '\/api\/client\/finance\/v1'/)
for (const path of ['/bills', '/statements', '/receipts', '/receivable-settlements', '/confirm']) {
assert.ok(source.includes(path), path)
}
assert.match(source, /customerId=0&tenantId=0/)
assert.match(source, /customer bills ignore caller-supplied customer scope/)
assert.match(source, /cross-customer bill detail stays outside the other enterprise/)
assert.match(source, /unknown statement confirmation is rejected with idempotency key/)
assert.match(source, /customer receipts are confirmed-only and customer-scoped/)
assert.doesNotMatch(source, /jdbc|INSERT INTO/i)
})
test('F02 client overseas self-service covers customer-scoped lists and the return forecast write chain', async () => {
const source = await readFile(new URL('./client-test-env-acceptance.mjs', import.meta.url), 'utf8')
assert.match(source, /async function merchantOverseasWarehouseModule\(\)/)
assert.match(source, /await merchantOverseasWarehouseModule\(\)/)
const callOrder = [
source.indexOf('await merchantFinanceBillsModule()'),
source.indexOf('await merchantOverseasWarehouseModule()'),
source.indexOf('await notificationInboxModule()'),
]
assert.ok(callOrder[0] >= 0 && callOrder[1] > callOrder[0] && callOrder[2] > callOrder[1],
'overseas self-service must run after bills and before notifications')
for (const path of ['/api/merchant/v1/warehouses', '/return-orders', '/relabel-applications',
'/warehouse-transfers', '/cargo-discards', '/return-inventory', '/return-inventory/summary',
'/return-inventory/cartons']) {
assert.ok(source.includes(path), path)
}
assert.match(source, /create return forecast with marker-owned payload/)
assert.match(source, /same idempotency key replays the same return order/)
assert.match(source, /return order appears in the customer list/)
assert.match(source, /cross-customer return order is rejected/)
assert.match(source, /overseasWarehouseReadOnlyGaps/)
assert.doesNotMatch(source, /jdbc|INSERT INTO/i)
})
test('F03 client cross-border, warehouse orders and pricing/customs cover current customer pages', async () => {
const source = await readFile(new URL('./client-test-env-acceptance.mjs', import.meta.url), 'utf8')
for (const name of ['merchantCrossBorderModule', 'merchantWarehouseOrdersModule', 'merchantPricingCustomsModule']) {
assert.match(source, new RegExp(`async function ${name}\\(\\)`), name)
assert.match(source, new RegExp(`await ${name}\\(\\)`), name)
}
const order = ['merchantOverseasWarehouseModule', 'merchantCrossBorderModule',
'merchantWarehouseOrdersModule', 'merchantPricingCustomsModule', 'notificationInboxModule']
.map((name) => source.indexOf(`await ${name}()`))
assert.ok(order.every((index) => index >= 0) && order.every((index, position) => position === 0 || index > order[position - 1]),
'new client modules must run in order before notifications')
for (const path of ['/us-truck-orders', '/local-looseboard-orders', '/overseas-procurements',
'/inbound-plans', '/delivery-orders', '/first-leg/pricing/channels', '/customs/pending-summary',
'/customs/orders/']) {
assert.ok(source.includes(path), path)
}
assert.match(source, /same idempotency key replays the same US truck order/)
assert.match(source, /same idempotency key replays the same looseboard order/)
assert.match(source, /same idempotency key replays the same procurement order/)
assert.match(source, /customer inbound plans are customer-scoped/)
assert.match(source, /customer delivery orders are customer-scoped/)
assert.match(source, /customer customs pending summary is readable/)
assert.match(source, /crossBorderLimitations/)
assert.doesNotMatch(source, /jdbc|INSERT INTO/i)
})