This commit is contained in:
2026-09-07 15:07:54 +08:00
parent 65962eb940
commit ee99854a39
9 changed files with 94 additions and 24 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ test('missing user-visible relationships use explicit empty labels instead of ID
read('../src/components/ReceivingSessionSummary.vue'),
read('../src/pages/pallet/pallet.vue')
])
assert.match(summary, /overseasWarehouseName \|\| '—'/)
assert.match(summary, /overseasWarehouseCode[\s\S]*overseasWarehouseName/)
assert.match(summary, /unique\.length \? unique : \['—'\]/)
assert.match(pallet, /inboundCode \|\| '无入仓码'/)
assert.match(pallet, /locationCode \|\| '未绑定库位'/)
+24 -3
View File
@@ -2,7 +2,7 @@ import test from 'node:test'
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import { normalizeReceivingCandidate, normalizeReceivingSession } from '../src/api/receiving-adapter.js'
import { assertReceivingWarehouse, normalizeReceivingCandidate, normalizeReceivingSession, normalizeReceivingWarehouseProfile } from '../src/api/receiving-adapter.js'
import { receiving, receivingPhase, receivingProgress, resetReceivingSession, setCurrentReceiving } from '../src/stores/receiving.js'
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8')
@@ -21,6 +21,7 @@ const inbounds = Array.from({ length: 15 }, (_, index) => ({
test('one container candidate aggregates fifteen independent one-inbound plans', () => {
const candidate = normalizeReceivingCandidate({
sourceContainerBookingId: '2093166483653849089', containerNo: 'C10000000', status: 'WAIT_SIGN',
overseasWarehouseCode: 'US-LAX-RCV', overseasWarehouseName: '洛杉矶接柜仓',
plannedArrivalAt: '2026-08-29T09:30:00', totalOrderCount: 15, planCount: 15, inboundCodeCount: 15,
missingInboundCodeCount: 0, plannedInboundCodeCount: 15, pendingPlanCount: 0, allPlansReady: true, operable: true, blockReason: '',
destinationCodes: ['ABE3', 'US-LAX-01'], plannedPalletCount: 15,
@@ -28,6 +29,7 @@ test('one container candidate aggregates fifteen independent one-inbound plans',
})
assert.deepEqual(candidate, {
sourceContainerBookingId: '2093166483653849089', containerNo: 'C10000000', status: 'WAIT_SIGN',
overseasWarehouseCode: 'US-LAX-RCV', overseasWarehouseName: '洛杉矶接柜仓',
plannedArrivalAt: '2026-08-29T09:30:00', totalOrderCount: 15, planCount: 15, inboundCodeCount: 15,
missingInboundCodeCount: 0, plannedInboundCodeCount: 15, pendingPlanCount: 0, allPlansReady: true, operable: true, blockReason: '',
destinationCodes: ['ABE3', 'US-LAX-01'], plannedPalletCount: 15,
@@ -37,6 +39,21 @@ test('one container candidate aggregates fifteen independent one-inbound plans',
assert.equal(candidate.sourceContainerBookingId, '2093166483653849089')
})
test('receiving warehouse facts are explicit and fail closed when absent or assigned elsewhere', () => {
const profile = normalizeReceivingWarehouseProfile({ warehouseId: '900', warehouseCode: 'US-LAX-RCV', warehouseName: '洛杉矶接柜仓' })
const assigned = normalizeReceivingCandidate({ containerNo: 'C10000002', overseasWarehouseCode: 'US-LAX-RCV', overseasWarehouseName: '洛杉矶接柜仓' })
assert.equal(assertReceivingWarehouse(assigned, profile, '柜号 C10000002'), assigned)
assert.throws(() => assertReceivingWarehouse(normalizeReceivingCandidate({ containerNo: 'C10000003' }), profile), (error) => {
assert.equal(error.code, 'RECEIVING_WAREHOUSE_CONTRACT_INVALID')
return /缺少已分配海外接柜仓/.test(error.message)
})
assert.throws(() => assertReceivingWarehouse(normalizeReceivingCandidate({ containerNo: 'C10000004', overseasWarehouseCode: 'US-NYC-RCV', overseasWarehouseName: '纽约接柜仓' }), profile), (error) => {
assert.equal(error.code, 'RECEIVING_WAREHOUSE_MISMATCH')
return /已分配至其他海外接柜仓/.test(error.message)
})
assert.throws(() => normalizeReceivingWarehouseProfile({ warehouseId: '900', warehouseName: '洛杉矶接柜仓' }), /绑定仓信息不完整/)
})
test('incomplete containers remain visible but fail closed from server readiness facts', () => {
const candidate = normalizeReceivingCandidate({
sourceContainerBookingId: '2093166483653849099', containerNo: 'C10000001',
@@ -60,7 +77,7 @@ test('incomplete containers remain visible but fail closed from server readiness
test('current recovery retains all independent-plan inbound facts while progress remains container-level', () => {
const session = normalizeReceivingSession({
containerNo: 'C10000000', status: 'RECEIVING', totalPackages: 60,
containerNo: 'C10000000', overseasWarehouseCode: 'US-LAX-RCV', overseasWarehouseName: '洛杉矶接柜仓', status: 'RECEIVING', totalPackages: 60,
receivedPackages: 4, pendingPackages: 56, photos: [], inbounds
})
setCurrentReceiving(session)
@@ -90,6 +107,10 @@ test('container UI locks and signs once across independent plans, then renders o
assert.match(inboundApi, /current\('\/sign'\)/)
assert.match(operation, /prepareReceivingContainer\(this\.selected\.containerNo, \{ idempotencyKey: key\.value \}\)/)
assert.match(operation, /getCurrentReceiving\(\)[\s\S]*applyCurrentReceiving\(current\)/)
assert.match(operation, /applyWarehouseProfile\(await getCurrentWarehouseProfile\(\)\)/)
assert.match(operation, /values\.map\(\(item\) => this\.validateReceivingWarehouse/)
assert.match(operation, /prepareReceivingContainer[\s\S]*validateReceivingWarehouse/)
assert.match(summary, /overseasWarehouseCode[\s\S]*overseasWarehouseName/)
for (const forbidden of ['customerId', 'planNo', 'allocationId', 'warehouseId', 'locationId']) {
assert.doesNotMatch(inboundApi, new RegExp(forbidden))
}
@@ -108,7 +129,7 @@ test('PDA does not infer container eligibility from partial plan workflow states
assert.match(adapter, /operable: value\.operable === true/)
assert.match(operation, /if \(!candidate\.operable\) \{ receiving\.selected = candidate; this\.detailOpen = true; return \}/)
assert.match(operation, /if \(!this\.selected\?\.containerNo \|\| !this\.selected\?\.allPlansReady \|\| !this\.selected\?\.operable/)
assert.match(operation, /catch \(error\) \{ await this\.recoverCurrentAfterConflict\(error, true\) \}/)
assert.match(operation, /recoverCurrentAfterConflict\(error, true\)/)
assert.match(operation, /preserveEvidence \? error : null[\s\S]*this\.candidateError = preserveEvidence \? error : null/)
assert.doesNotMatch(inbound, /sort\(/)
})
+2 -1
View File
@@ -178,10 +178,11 @@ test('business and network errors retain diagnostics without refreshing or clear
prepareSession(); let refreshCount = 0
globalThis.uni.request = (options) => {
if (options.url.endsWith('/auth/refresh')) refreshCount += 1
options.success({ statusCode: 200, data: { code: 'A0409', message: 'locked', requestId: 'business-request', traceId: 'business-trace' }, header: {} })
options.success({ statusCode: 200, data: { code: 'A0409', message: '当前柜已分配至其他海外接柜仓,无法在本仓操作', requestId: 'business-request', traceId: 'business-trace' }, header: {} })
}
await assert.rejects(overseasRequest('POST', '/pda/locked'), (error) => {
assert.equal(error.code, 'A0409')
assert.equal(error.message, '当前柜已分配至其他海外接柜仓,无法在本仓操作')
assert.equal(error.requestId, 'business-request')
assert.equal(error.traceId, 'business-trace')
return true