test(order): accept omitted identifiers on failed import rows

This commit is contained in:
2026-10-02 21:46:39 +08:00
parent 58dfcc21f6
commit 8c1905418e
2 changed files with 24 additions and 3 deletions
@@ -69,6 +69,25 @@ test('partial import validates physical row, exact counts, failure details and i
}
})
test('PARTIAL wire response accepts only null or omitted failed-row identifiers', () => {
const r = runtime()
// Shape captured from r1: Jackson omits all null fields on both failed and successful rows.
const wire = JSON.parse('{"mode":"PARTIAL","batchNo":"OBI-contract","sourceFileId":"101","errorReportFileId":"102","result":{"total":2,"succeeded":1,"failed":1,"items":[{"index":0,"clientRowId":"excel-row-3","success":false,"errorCode":"A0422","errorMessage":"货物名称不能为空"},{"index":1,"clientRowId":"excel-row-4","success":true,"orderId":"2106016937331458049","orderNo":"FL2106016937331458049"}]}}')
r.assertImportResult(wire, 'PARTIAL', [false, true])
for (const field of ['orderId', 'orderNo', 'inboundCode']) {
const explicitNull = structuredClone(wire); explicitNull.result.items[0][field] = null
r.assertImportResult(explicitNull, 'PARTIAL', [false, true])
for (const value of ['2106016937331458049', 'FL-example', 'NYEXX-example', '', 0, false, NaN, [], {}]) {
const invalid = structuredClone(wire); invalid.result.items[0][field] = value
assert.throws(() => r.assertImportResult(invalid, 'PARTIAL', [false, true]), new RegExp(`no ${field}`))
}
}
for (const field of ['orderId', 'orderNo']) {
const missingSuccess = structuredClone(wire); delete missingSuccess.result.items[1][field]
assert.throws(() => r.assertImportResult(missingSuccess, 'PARTIAL', [false, true]), /created order/)
}
})
function templateFixture(r) {
return new Map([
['xl/workbook.xml', '<workbook><sheets><sheet name="订单导入"/><sheet name="选项数据"/></sheets></workbook>'],
@@ -213,9 +232,9 @@ function importHarness(fault = '') {
const masterData = { receiving: { id: 'domestic', warehouseName: '国内仓', warehouseCode: 'CN' },
destination: { id: 'fba', warehouseName: '目的仓', warehouseCode: 'US' }, channel: { channelName: '海运渠道', channelCode: 'SEA' } }
let nextKey = 0, r
const resultItem = (index, success, orderId) => ({ index, clientRowId: `excel-row-${index + 3}`, success,
const resultItem = (index, success, orderId) => Object.fromEntries(Object.entries({ index, clientRowId: `excel-row-${index + 3}`, success,
orderId: success ? orderId : null, orderNo: success ? `FL${orderId}` : null,
errorCode: success ? null : 'A0422', errorMessage: success ? null : 'cargo required' })
errorCode: success ? null : 'A0422', errorMessage: success ? null : 'cargo required' }).filter(([, value]) => value !== null))
const responseData = (mode, items) => ({ mode, batchNo: 'batch', sourceFileId: 'source-file', errorReportFileId: 'error-file',
result: { total: items.length, succeeded: items.filter(item => item.success).length, failed: items.filter(item => !item.success).length, items } })
const addDraft = (id, cells) => orders.set(id, { order: { id, orderNo: `FL${id}`, version: 0, status: 'DRAFT', tenantId: 'tenant',