Fix native dispatch warehouse text projection and TEST receipt setup
This commit is contained in:
@@ -76,10 +76,14 @@ function model(fault = '', countPatch = {}) {
|
||||
if (path === '/api/merchant/v1/iam/tenant/profile') return response({ id: fault === 'foreign login' ? 'OTHER' : merchant.id })
|
||||
if (path === '/api/merchant/v1/last-leg/warehouse-transfers') {
|
||||
assert.ok(merchant); assert.equal(body.inboundCode, undefined); assert.deepEqual(body.sourceLastlegOrderIds, [])
|
||||
assert.equal(body.needRelabel, false); assert.equal(body.items.length, 1); assert.equal(body.items[0].packageCount, 1)
|
||||
assert.equal(body.needRelabel, false); assert.equal(body.items.length, 1); assert.equal(body.items[0].packageCount, 1); assert.equal(body.items[0].quantity, 1)
|
||||
const transferNo = `IN${transfers.length}`
|
||||
const itemId = `FORECAST-ITEM${transfers.length}`
|
||||
const transfer = { transferNo, inboundCode: transferNo, customerId: merchant.id, operatingWarehouseId: body.operatingWarehouseId,
|
||||
status: 'DRAFT', pallets: [] }
|
||||
status: 'DRAFT', packageCount: 1, pallets: [],
|
||||
items: [{ ...copy(body.items[0]), id: itemId, ...(fault === 'missing declared quantity' ? { quantity: null } : {}) }],
|
||||
cartons: fault === 'missing forecast carton' ? [] : [{ cartonMark: `BX-FORECAST${transfers.length}`, status: 'FORECAST',
|
||||
transferItemId: fault === 'foreign forecast item' ? 'OTHER-ITEM' : itemId }] }
|
||||
transfers.push(transfer); return response(transfer)
|
||||
}
|
||||
if (path.includes('/warehouse-transfers/')) {
|
||||
@@ -88,10 +92,39 @@ function model(fault = '', countPatch = {}) {
|
||||
if (path.startsWith('/api/merchant/')) assert.equal(transfer.customerId, merchant.id)
|
||||
if (path.endsWith('/submit')) transfer.status = 'PENDING_REVIEW'
|
||||
else if (path.endsWith('/review')) { assert.equal(url.searchParams.get('customerId'), transfer.customerId); assert.equal(body.decision, 'APPROVE'); transfer.status = 'WAIT_PDA_RECEIVING' }
|
||||
else if (path.endsWith('/pallets/drafts')) transfer.pallets = [{ id: `DRAFT${n}`, status: 'DRAFT', cartonCount: body.cartonCount }]
|
||||
else if (path.endsWith('/pallets/drafts')) {
|
||||
// The actual PalletDraft DTO accepts identity only; never derive measurement from ignored request fields.
|
||||
assert.deepEqual(Object.keys(body), ['idempotencyKey'])
|
||||
transfer.pallets = [{ id: `DRAFT${n}`, status: 'DRAFT', cartonCount: 0, lengthCm: 0, widthCm: 0, heightCm: 0, volumeCbm: 0, grossWeightKg: 0 }]
|
||||
}
|
||||
else if (path.endsWith('/generate')) Object.assign(transfer.pallets[0], { status: 'GENERATED', warehousePalletId: `PAL${n}`, palletNo: `PALLET${n}` })
|
||||
else if (path.endsWith('/bind')) { assert.equal(body.palletCode, transfer.pallets[0].palletNo); transfer.pallets[0].status = 'BOUND' }
|
||||
else if (path.endsWith('/palletize')) { transfer.status = 'WAIT_CUSTOMER_CONFIRMATION'; transfer.pallets[0].status = 'COMPLETED' }
|
||||
else if (path.endsWith('/cartons/count')) {
|
||||
assert.equal(method, 'POST'); assert.equal(transfer.pallets[0].status, 'BOUND')
|
||||
assert.equal(transfer.pallets[0].cartonCount, 0); assert.equal(body.forecastPackageCount, transfer.packageCount)
|
||||
assert.equal(body.boxes.length, 1)
|
||||
const box = body.boxes[0], item = transfer.items[0], carton = transfer.cartons[0], pallet = transfer.pallets[0]
|
||||
assert.equal(box.cartonMark, carton.cartonMark); assert.equal(box.transferItemId, item.id)
|
||||
assert.equal(box.transferPalletId, pallet.id); assert.notEqual(box.transferPalletId, pallet.warehousePalletId)
|
||||
assert.deepEqual([box.length, box.width, box.height, box.weight], [100, 100, 100, 100])
|
||||
assert.deepEqual(box.items, [{ skuCode: item.skuCode, quantity: item.quantity }])
|
||||
Object.assign(carton, { transferPalletId: pallet.id, status: 'COUNTED', countedAt: '2026-10-20T09:00:00',
|
||||
length: box.length, width: box.width, height: box.height, weight: box.weight, quantity: 1,
|
||||
items: [{ transferItemId: item.id, skuCode: item.skuCode, quantity: 1 }] })
|
||||
Object.assign(pallet, { cartonCount: 1, volumeCbm: 1, grossWeightKg: 100 })
|
||||
if (fault === 'uncounted carton') { carton.status = 'FORECAST'; carton.countedAt = null }
|
||||
if (fault === 'wrong counted pallet') carton.transferPalletId = 'OTHER-PALLET'
|
||||
if (fault === 'wrong counted sku') carton.items[0].skuCode = 'OTHER-SKU'
|
||||
if (fault === 'missing carton measurement') carton.weight = null
|
||||
if (fault === 'zero counted pallet') pallet.cartonCount = 0
|
||||
if (fault === 'wrong measured pallet weight') pallet.grossWeightKg = 0
|
||||
}
|
||||
else if (path.endsWith('/palletize')) {
|
||||
assert.equal(transfer.cartons.length, 1); assert.equal(transfer.cartons[0].status, 'COUNTED'); assert.ok(transfer.cartons[0].countedAt)
|
||||
assert.equal(transfer.pallets[0].cartonCount, 1); assert.equal(transfer.pallets[0].grossWeightKg, 100)
|
||||
assert.equal(transfer.pallets[0].volumeCbm, 1); assert.ok(body.photoFileIds.length)
|
||||
transfer.status = 'WAIT_CUSTOMER_CONFIRMATION'; transfer.pallets[0].status = 'COMPLETED'
|
||||
}
|
||||
else if (path.endsWith('/confirm-measurement')) transfer.status = 'READY_FOR_DISPATCH'
|
||||
else assert.equal(method, 'GET')
|
||||
return response(transfer)
|
||||
@@ -182,13 +215,26 @@ test('real helpers build independent current-run customers, receipts and one com
|
||||
assert.equal(proof.status, 'READY'); assert.deepEqual(proof.sessionCleanup.map(row => row.status), ['LOGGED_OUT', 'LOGGED_OUT'])
|
||||
assert.equal(m.trip.dispatches.length, 1); assert.equal(new Set(fixture.members.map(row => row.dispatchNo)).size, 1); assert.deepEqual(m.trip.trip.stops.map(row => row.destinationKey).filter(Boolean), ['FBA:FBA'])
|
||||
assert.equal(m.calls.filter(row => row.method === 'POST' && row.raw === '/api/platform/v1/last-leg/dispatches').length, 1)
|
||||
assert.equal(m.calls.filter(row => row.raw.endsWith('/cartons/count')).length, 2)
|
||||
for (const member of fixture.members) {
|
||||
const prefix = `/api/pda/v1/last-leg/warehouse-transfers/${member.incomingNo}`
|
||||
const draft = m.calls.findIndex(row => row.raw === `${prefix}/pallets/drafts`)
|
||||
const bind = m.calls.findIndex(row => row.raw.startsWith(`${prefix}/pallets/`) && row.raw.endsWith('/bind'))
|
||||
const count = m.calls.findIndex(row => row.raw === `${prefix}/cartons/count`)
|
||||
const photo = m.calls.findIndex(row => row.raw === `${prefix}/measurement-photos/files`)
|
||||
const receipt = m.calls.findIndex(row => row.raw === `${prefix}/palletize`)
|
||||
assert.ok(draft < bind && bind < count && count < photo && photo < receipt)
|
||||
assert.equal(member.measurementReceipt.countedCarton.cartonMark, m.calls[count].body.boxes[0].cartonMark)
|
||||
assert.equal(member.measurementReceipt.syntheticTestMaterials, true)
|
||||
assert.equal(member.measurementReceipt.finalizedPallet.cartonCount, 1)
|
||||
}
|
||||
assert.equal(m.calls.filter(row => row.raw.endsWith('/transfer-delivery')).length, 0)
|
||||
assert.ok(!m.calls.some(row => /\/pick$|\/depart$|\/bookings|\/capacity-plan/.test(row.raw)))
|
||||
const persisted = JSON.stringify(m.context.createdResources)
|
||||
for (const secret of ['caller-pda-secret', 'admin-secret', 'fresh-secret-', 'merchant-100-secret', 'refresh-100-secret']) assert.ok(!persisted.includes(secret))
|
||||
})
|
||||
|
||||
for (const fault of ['disabled receiving', 'reused customer', 'foreign login', 'foreign position', 'truncated ledger', 'wrong raw scope', 'wrong raw ledger position', 'wrong raw ledger balance', 'foreign candidate', 'missing second cargo', 'foreign delivery', 'logout failure']) {
|
||||
for (const fault of ['disabled receiving', 'reused customer', 'foreign login', 'missing forecast carton', 'missing declared quantity', 'foreign forecast item', 'uncounted carton', 'wrong counted pallet', 'wrong counted sku', 'missing carton measurement', 'zero counted pallet', 'wrong measured pallet weight', 'foreign position', 'truncated ledger', 'wrong raw scope', 'wrong raw ledger position', 'wrong raw ledger balance', 'foreign candidate', 'missing second cargo', 'foreign delivery', 'logout failure']) {
|
||||
test(`fail closed, retain partial resources and clean owned sessions: ${fault}`, async () => {
|
||||
const m = model(fault)
|
||||
await assert.rejects(createFleetCrossCustomerFixture(m.context, m.options))
|
||||
@@ -198,6 +244,8 @@ for (const fault of ['disabled receiving', 'reused customer', 'foreign login', '
|
||||
assert.equal(logouts.length, logins.length)
|
||||
assert.ok(!m.calls.some(row => row.method === 'DELETE' || row.raw.includes('/users/')))
|
||||
if (fault === 'disabled receiving') assert.equal(m.calls.filter(row => row.method !== 'GET').length, 0)
|
||||
if (['missing forecast carton', 'missing declared quantity', 'foreign forecast item', 'uncounted carton', 'wrong counted pallet', 'wrong counted sku', 'missing carton measurement', 'zero counted pallet', 'wrong measured pallet weight'].includes(fault))
|
||||
assert.equal(m.calls.some(row => row.raw.endsWith('/palletize') || row.raw === '/api/platform/v1/last-leg/dispatches'), false)
|
||||
const previousCount = m.calls.length
|
||||
await assert.rejects(createFleetCrossCustomerFixture(m.context, m.options), /already started/)
|
||||
assert.equal(m.calls.length, previousCount)
|
||||
|
||||
Reference in New Issue
Block a user