96 lines
5.1 KiB
JavaScript
96 lines
5.1 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import { normalizeModuleOrder } from '../admin-test-env-acceptance.mjs'
|
|
import { sameOutboundTask } from './dropship-pallet-matrix.mjs'
|
|
|
|
test('outbound replay preserves business identity and database millisecond timestamps', () => {
|
|
const task = { id: '1', taskNo: 'PDA1', outboundNo: 'OD1', status: 'PENDING', pushedAt: '2026-09-14T20:24:45.920278604' }
|
|
assert.equal(sameOutboundTask(task, { ...task, pushedAt: '2026-09-14T20:24:45.92' }), true)
|
|
assert.equal(sameOutboundTask({ ...task, pushedAt: '2026-09-14T20:24:45.9999' },
|
|
{ ...task, pushedAt: '2026-09-14T20:24:46' }), true)
|
|
for (const key of ['id', 'taskNo', 'outboundNo', 'status', 'pushedAt']) {
|
|
assert.equal(sameOutboundTask(task, { ...task, [key]: 'changed' }), false)
|
|
}
|
|
})
|
|
|
|
const source = readFileSync(new URL('./dropship-pallet-matrix.mjs', import.meta.url), 'utf8')
|
|
|
|
test('dedicated outbound uses exact source cartons and verifies completion and stock deduction', () => {
|
|
assert.match(source, /await outboundOverseas\(group, picker.token\)/)
|
|
assert.match(source, /one-click-dropship\?customerId=/)
|
|
assert.match(source, /position.inboundCode === candidate.inboundCode/)
|
|
assert.match(source, /cartonMarks: inputs\[index\].cartonMarks/)
|
|
assert.match(source, /outbound.outbound\?\.status === 'OUTBOUNDED'/)
|
|
assert.match(source, /!remaining.some/)
|
|
})
|
|
|
|
test('dropship matrix has a real customer prerequisite without generic dispatch fixtures', () => {
|
|
const modules = normalizeModuleOrder(['dropship-pallet-matrix'])
|
|
assert.ok(modules.includes('merchant-qualification-fixture'))
|
|
assert.ok(modules.includes('dropship-pallet-matrix'))
|
|
assert.ok(!modules.includes('phase5-overseas-fulfillment'))
|
|
})
|
|
|
|
test('all four physical pallet shapes are explicitly produced', () => {
|
|
assert.match(source, /prepare\('SINGLE-MULTI', 2\)/)
|
|
assert.match(source, /prepare\('SINGLE-SINGLE', 1\)/)
|
|
assert.match(source, /prepare\('SINGLE-MERGE', 2, \{ mergeToFirstPallet: true \}\)/)
|
|
assert.match(source, /prepare\('MULTI-MERGE-A', 1, \{ deferSeal: true \}\)/)
|
|
assert.match(source, /prepare\('MULTI-MERGE-B', 1, \{ targetPalletNo \}\)/)
|
|
assert.match(source, /await verify\(first, 1\)/)
|
|
assert.match(source, /await verify\(second, 1\)/)
|
|
})
|
|
|
|
test('allocation checks both physical summaries and uncollapsed per-inbound quantities', () => {
|
|
assert.match(source, /first-leg\/loading-plans\/\$\{plan.id\}/)
|
|
assert.match(source, /const actual = detail.items.filter/)
|
|
assert.match(source, /plan.items\?\.length === pallets.length/)
|
|
assert.match(source, /actual.reduce\([\s\S]*?record.expectedCartonMarks.length/)
|
|
assert.match(source, /await conserve\('手工加入后'\)/)
|
|
assert.match(source, /await conserve\('智能推荐后'\)/)
|
|
assert.match(source, /fullFlowVerified: false/)
|
|
})
|
|
|
|
test('each scenario reaches physical loading through released booking and asynchronous completion', () => {
|
|
assert.match(source, /ocean-booking-link/)
|
|
assert.match(source, /readiness\?\.canConfirm === true/)
|
|
assert.match(source, /action: 'PICK_PALLET'/)
|
|
assert.match(source, /inventorySnapshotToken: inventory.snapshotToken/)
|
|
for (const type of ['PHOTO_STEP_1', 'PHOTO_STEP_2', 'PHOTO_STEP_3', 'PHOTO_STEP_4', 'SEAL']) {
|
|
assert.ok(source.includes(`'${type}'`))
|
|
}
|
|
assert.match(source, /await waitForCompletion\(context/)
|
|
assert.match(source, /finalTask\?\.taskStatus === 'COMPLETED'/)
|
|
assert.match(source, /inbound.summary\?\.processStatus === 'LOADED'/)
|
|
})
|
|
|
|
test('shipping uses the current group and requires real departure and pickup readiness', () => {
|
|
assert.match(source, /for \(const group of groups\) await progressShipping\(group\)/)
|
|
assert.match(source, /containerBookingId: String\(record.loading.cabinet.id\)/)
|
|
assert.match(source, /\['customs', completeCustoms\]/)
|
|
assert.match(source, /\['departure', confirmDomesticDeparture\]/)
|
|
assert.match(source, /\['pickup-ready', runUntilPickupReady\]/)
|
|
assert.match(source, /confirmedStatus === 'WAITING_FOR_LOADING'/)
|
|
assert.match(source, /phase4CarrierPickupReady\?\.ready === true/)
|
|
})
|
|
|
|
test('overseas plans preserve per-inbound ownership and shared physical identity', () => {
|
|
assert.match(source, /inbound-plans\/convert-container/)
|
|
assert.match(source, /matching.length === 1/)
|
|
assert.match(source, /JSON.stringify\(expectedNos\) === JSON.stringify\(actualNos\)/)
|
|
assert.match(source, /byPallet.get\(pallet.palletNo\) === identity/)
|
|
assert.match(source, /JSON.stringify\(replay\) === JSON.stringify\(plans\)/)
|
|
})
|
|
|
|
test('overseas receipt uses scoped PDA identity and scans each physical pallet once', () => {
|
|
assert.match(source, /await createPicker\(context/)
|
|
assert.match(source, /await disablePicker\(context/)
|
|
assert.match(source, /const sourceNos = \[\.\.\.new Set\(group.flatMap/)
|
|
assert.match(source, /current\/receipts\/pallet/)
|
|
assert.match(source, /duplicate.result === 'ALREADY_RECEIVED'/)
|
|
assert.match(source, /Number\(inbound.receivedPackages\) === item.expectedCartonMarks.length/)
|
|
assert.match(source, /completed.status === 'COMPLETED'/)
|
|
assert.match(source, /fullFlowVerified: false/)
|
|
})
|