This commit is contained in:
2026-08-28 13:58:49 +08:00
parent 6b5f2f0565
commit bb9673358d
3 changed files with 36 additions and 7 deletions
@@ -39,8 +39,13 @@ export function validContainerSummaryPage(data, expected) {
=== String(expected?.sourceContainerBookingId ?? ''))
return Number(data.page) >= 1 && Number(data.size) >= 1 && Number(data.total) >= 1
&& Number(data.pages) >= 1 && String(row?.containerNo ?? '') === String(expected?.containerNo ?? '')
&& Number(row?.orderCount) === Number(expected?.orderCount)
&& Number(row?.totalOrderCount) === Number(expected?.totalOrderCount)
&& Number(row?.inboundCodeCount) === Number(expected?.inboundCodeCount)
&& Number(row?.missingInboundCodeCount) === Number(expected?.missingInboundCodeCount)
&& Number(row?.planCount) === Number(expected?.planCount)
&& Number(row?.plannedInboundCodeCount) === Number(expected?.plannedInboundCodeCount)
&& Number(row?.pendingPlanCount) === Number(expected?.pendingPlanCount)
&& Boolean(row?.allPlansReady) === Boolean(expected?.allPlansReady)
}
export function zeroDrift(before, after) {
@@ -80,8 +80,13 @@ export async function run(context) {
success(summaryResponse) && validContainerSummaryPage(summaryResponse.body?.data, {
sourceContainerBookingId: data.normal.sourceContainerBookingId,
containerNo: data.normal.containerNo,
orderCount: CONTAINER_CONVERT_EXPECTED_ORDERS,
totalOrderCount: CONTAINER_CONVERT_EXPECTED_ORDERS,
inboundCodeCount: CONTAINER_CONVERT_EXPECTED_ORDERS,
missingInboundCodeCount: 0,
planCount: 0,
plannedInboundCodeCount: 0,
pendingPlanCount: CONTAINER_CONVERT_EXPECTED_ORDERS,
allPlansReady: false,
}), `orderPageSize=10, expectedOrderCount=15; ${trace(summaryResponse)}`, OPTIONS)
const normalList = await listOrders(context, data.normal.containerNo)
context.assert(MODULE, 'P1同柜15票列表前置', normalList.response,
@@ -127,4 +132,19 @@ export async function run(context) {
&& after.rows.every((row) => row.currentStatus === 'INBOUND_PLANNED' && row.inboundOrderNo),
`planned=${after.rows.filter((row) => row.currentStatus === 'INBOUND_PLANNED').length}; ${trace(after.response)}`, OPTIONS)
const readySummary = await context.requestOverseas('GET',
`${CONTAINER_SUMMARY_ENDPOINT}?page=1&size=10&containerNo=${encodeURIComponent(data.normal.containerNo)}`)
context.assert(MODULE, 'P0全柜每票独立计划完成后allPlansReady', readySummary,
success(readySummary) && validContainerSummaryPage(readySummary.body?.data, {
sourceContainerBookingId: data.normal.sourceContainerBookingId,
containerNo: data.normal.containerNo,
totalOrderCount: CONTAINER_CONVERT_EXPECTED_ORDERS,
inboundCodeCount: CONTAINER_CONVERT_EXPECTED_ORDERS,
missingInboundCodeCount: 0,
planCount: CONTAINER_CONVERT_EXPECTED_ORDERS,
plannedInboundCodeCount: CONTAINER_CONVERT_EXPECTED_ORDERS,
pendingPlanCount: 0,
allPlansReady: true,
}), trace(readySummary), OPTIONS)
}
@@ -44,9 +44,13 @@ test('semantic contract creates one independent plan per order even for the same
test('server container summary remains complete when the order page would contain only ten rows', () => {
assert.equal(CONTAINER_SUMMARY_ENDPOINT, '/api/platform/v1/last-leg/orders/container-summaries')
assert.equal(validContainerSummaryPage({
records: [{ sourceContainerBookingId: 'CB-1', containerNo: 'C1', orderCount: '15', inboundCodeCount: '15' }],
records: [{ sourceContainerBookingId: 'CB-1', containerNo: 'C1', totalOrderCount: '15', inboundCodeCount: '15',
missingInboundCodeCount: 0, planCount: 0, plannedInboundCodeCount: 0, pendingPlanCount: 15,
allPlansReady: false }],
page: '1', size: '10', total: '1', pages: '1',
}, { sourceContainerBookingId: 'CB-1', containerNo: 'C1', orderCount: 15, inboundCodeCount: 15 }), true)
}, { sourceContainerBookingId: 'CB-1', containerNo: 'C1', totalOrderCount: 15, inboundCodeCount: 15,
missingInboundCodeCount: 0, planCount: 0, plannedInboundCodeCount: 0, pendingPlanCount: 15,
allPlansReady: false }), true)
})
test('atomic failure and replay helpers reject drift', () => {
@@ -75,7 +79,7 @@ test('container API uses one stable long string identity', () => {
assert.match(endpoint, /sourceContainerBookingId:\s*\{ type: string/)
assert.match(controller, /convertContainer/)
assert.match(adminApi, /sourceContainerBookingId: string/)
assert.match(adminView, /sourceContainerBookingId: row\.sourceContainerBookingId/)
assert.match(adminView, /sourceContainerBookingId: container\.sourceContainerBookingId/)
})
test('backend batch conversion is one transaction and never merges same-customer orders', () => {
@@ -89,9 +93,9 @@ test('backend batch conversion is one transaction and never merges same-customer
})
test('Admin consumes a server-paged container summary and never derives 15 from the current order page', () => {
assert.match(adminApi, /(?:listLastMileContainerSummaries|listContainerSummaries)/)
assert.match(adminApi, /listContainerPlanProgress/)
assert.match(adminApi, /container-summaries/)
assert.match(adminView, /(?:listLastMileContainerSummaries|listContainerSummaries)\(/)
assert.match(adminView, /listContainerPlanProgress\(/)
assert.match(adminView, /containerRows\.value\s*=\s*result\.records/)
assert.doesNotMatch(adminView, /(?:rows|result\.records)\.value?\.(?:reduce|filter|forEach)[\s\S]{0,300}containerNo/)
})