优化
This commit is contained in:
@@ -4,6 +4,7 @@ import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { run, createPartnerWarehouse, retirePartnerWarehouse } from './phase4-overseas-business.mjs'
|
||||
import { verifyUsTruckFulfillment } from './us-truck-fulfillment.mjs'
|
||||
|
||||
test('fixed partner warehouse is reused and never retired', async () => {
|
||||
const calls = []
|
||||
@@ -21,6 +22,32 @@ test('fixed partner warehouse is reused and never retired', async () => {
|
||||
const here = path.dirname(fileURLToPath(import.meta.url))
|
||||
const source = fs.readFileSync(path.join(here, 'phase4-overseas-business.mjs'), 'utf8')
|
||||
|
||||
for (const fault of ['network', 'wrong customer', 'wrong pallet count', 'replay drift']) {
|
||||
test(`truck fulfillment stops and retains original order on ${fault}`, async () => {
|
||||
const context = fixture(), original = context.request.bind(context)
|
||||
let receipts = 0
|
||||
context.request = async (method, path, ...args) => {
|
||||
if (method === 'POST' && path.includes('/receive-pallets?')) {
|
||||
receipts += 1
|
||||
if (fault === 'network') return { http: 0 }
|
||||
const result = structuredClone(await original(method, path, ...args))
|
||||
if (fault === 'wrong customer') result.body.data.summary.customerId = 'other'
|
||||
if (fault === 'wrong pallet count') result.body.data.pallets.push({ ...result.body.data.pallets[0] })
|
||||
if (fault === 'replay drift' && receipts === 2) result.body.data.summary.version += 1
|
||||
return result
|
||||
}
|
||||
return original(method, path, ...args)
|
||||
}
|
||||
await assert.rejects(run(context))
|
||||
const proof = context.createdResources.phase4OverseasBusiness.truck
|
||||
assert.equal(proof.fulfillment.status, 'FAILED')
|
||||
assert.equal(proof.retained, true)
|
||||
assert.equal(receipts, fault === 'replay drift' ? 2 : 1)
|
||||
assert.equal(context.calls.some(c => c.path.includes('/allocate-pallets?') || c.path.includes('/TK1/status?')), false)
|
||||
await assert.rejects(verifyUsTruckFulfillment(context, proof), /本轮未执行/)
|
||||
})
|
||||
}
|
||||
|
||||
test('fixed customer beyond first page is found without creating or retiring a partner warehouse', async () => {
|
||||
const context = fixture(), request = context.request.bind(context), pages = []
|
||||
context.options = { fixedCustomerId: '10001' }
|
||||
@@ -63,7 +90,7 @@ function fixture(options = {}) {
|
||||
}
|
||||
function purchaseCustomer() { return { order: state.purchase, fees: [], progress: [], boxes: [], shipments: [], exceptionSummaries: [] } }
|
||||
function purchasePlatform() { return { customerView: purchaseCustomer(), internalRemark: state.purchase?.remark ?? null, reviewHistory: state.purchaseHistories } }
|
||||
function truckDetail() { return { summary: state.truck, remark: state.truck?.remark ?? null, histories: state.truckHistories } }
|
||||
function truckDetail() { return structuredClone({ summary: state.truck, pallets: state.truckPallets || [], remark: state.truck?.remark ?? null, histories: state.truckHistories }) }
|
||||
function looseboardDetail() { return { summary: state.looseboard, remark: state.looseboard?.remark ?? null, histories: state.looseboardHistories } }
|
||||
|
||||
const context = {
|
||||
@@ -122,7 +149,7 @@ function fixture(options = {}) {
|
||||
const hash = JSON.stringify(body)
|
||||
if (state.truck) return hash === state.truckHash ? response(truckDetail()) : response(null, 'A0409')
|
||||
state.truckHash = hash
|
||||
state.truck = { id: '40001', orderNo: 'TK1', customerId: '10001', status: 'PENDING_REVIEW', version: 0, ...body }
|
||||
state.truck = { id: '40001', orderNo: 'TK1', customerId: '10001', receivedPalletCount: 0, allocatedPalletCount: 0, status: 'PENDING_REVIEW', version: 0, ...body }
|
||||
state.truckHistories.push({ fromStatus: null, toStatus: 'PENDING_REVIEW', remark: marker })
|
||||
return response(truckDetail())
|
||||
}
|
||||
@@ -144,6 +171,32 @@ function fixture(options = {}) {
|
||||
state.truckReviews.set(body.idempotencyKey, { hash, result })
|
||||
return response(result)
|
||||
}
|
||||
const stages = { 'receive-pallets': ['WAITING_INBOUND', 'WAITING_CONSOLIDATION'],
|
||||
'allocate-pallets': ['WAITING_CONSOLIDATION', 'ALLOCATED'], 'prepare-dispatch': ['ALLOCATED', 'PENDING_DISPATCH'],
|
||||
dispatch: ['PENDING_DISPATCH', 'DISPATCHED'], 'start-transit': ['DISPATCHED', 'IN_TRANSIT'], complete: ['IN_TRANSIT', 'COMPLETED'] }
|
||||
const action = requestPath.match(/\/us-truck-orders\/TK1\/([^?]+)\?/)?.[1]
|
||||
if (method === 'POST' && stages[action]) {
|
||||
const existing = state.truckStatuses.get(body.idempotencyKey)
|
||||
if (existing) return response(truckDetail())
|
||||
const [from, to] = stages[action]
|
||||
assert.equal(state.truck.status, from)
|
||||
assert.equal(body.version, state.truck.version)
|
||||
if (action === 'receive-pallets') {
|
||||
assert.deepEqual(body.palletPackageCounts, [2])
|
||||
assert.equal(body.actualPalletCount, 1)
|
||||
state.truckPallets = [{ id: '701', palletNo: 'TK1-P001', packageCount: 2, status: 'RECEIVED' }]
|
||||
state.truck.receivedPalletCount = 1
|
||||
}
|
||||
if (action === 'allocate-pallets') {
|
||||
assert.deepEqual(body.palletIds, ['701'])
|
||||
state.truckPallets[0].status = 'ALLOCATED'
|
||||
state.truck.allocatedPalletCount = 1
|
||||
}
|
||||
state.truck.status = to; state.truck.version += 1
|
||||
state.truckHistories.push({ fromStatus: from, toStatus: to, idempotencyKey: body.idempotencyKey })
|
||||
state.truckStatuses.set(body.idempotencyKey, true)
|
||||
return response(truckDetail())
|
||||
}
|
||||
if (requestPath.includes('/us-truck-orders/TK1/status?') && method === 'PATCH') {
|
||||
assert.equal(body.status, 'CANCELLED')
|
||||
assert.equal(typeof body.idempotencyKey === 'string' && body.idempotencyKey.length > 0, true)
|
||||
@@ -272,7 +325,7 @@ test('procurement creation review boundaries and transport cancellation paths pa
|
||||
assert.notEqual(procurementReviews[3].body.idempotencyKey, procurementReviews[0].body.idempotencyKey)
|
||||
|
||||
const truckCalls = context.calls.filter((call) => call.path.includes('/us-truck-orders'))
|
||||
assert.equal(truckCalls.filter((call) => call.method === 'POST').length, 7)
|
||||
assert.equal(truckCalls.filter((call) => call.method === 'POST').length, 19)
|
||||
assert.equal(truckCalls.filter((call) => call.method === 'GET' && call.path.includes('page=1')).length, 1)
|
||||
const truckReviews = truckCalls.filter((call) => call.method === 'POST' && call.path.includes('/review?'))
|
||||
assert.equal(truckReviews.length, 4)
|
||||
@@ -281,7 +334,7 @@ test('procurement creation review boundaries and transport cancellation paths pa
|
||||
assert.equal(new Set(truckReviews.slice(0, 3).map((call) => call.body.idempotencyKey)).size, 1)
|
||||
assert.notEqual(truckReviews[3].body.idempotencyKey, truckReviews[0].body.idempotencyKey)
|
||||
const truckStatuses = truckCalls.filter((call) => call.method === 'PATCH' && call.path.includes('/status?'))
|
||||
assert.equal(truckStatuses.length, 1)
|
||||
assert.equal(truckStatuses.length, 0)
|
||||
assert.ok(truckStatuses.every((call) => call.body.status === 'CANCELLED'
|
||||
&& typeof call.body.idempotencyKey === 'string' && call.body.idempotencyKey.length > 0))
|
||||
|
||||
@@ -290,20 +343,21 @@ test('procurement creation review boundaries and transport cancellation paths pa
|
||||
assert.equal(looseboardCalls.filter((call) => call.method === 'GET' && call.path.includes('page=1')).length, 1)
|
||||
assert.equal(looseboardCalls.filter((call) => call.method === 'PUT').length, 2)
|
||||
const looseboardStatuses = looseboardCalls.filter((call) => call.method === 'PATCH' && call.path.includes('/status?'))
|
||||
assert.equal(looseboardStatuses.length, 5)
|
||||
assert.equal(looseboardStatuses.length, 4)
|
||||
assert.ok(looseboardStatuses.every((call) => typeof call.body.idempotencyKey === 'string'
|
||||
&& call.body.idempotencyKey.length > 0))
|
||||
assert.equal(new Set(looseboardStatuses.slice(0, 3).map((call) => call.body.idempotencyKey)).size, 1)
|
||||
assert.equal(new Set(looseboardStatuses.slice(3).map((call) => call.body.idempotencyKey)).size, 2)
|
||||
assert.equal(new Set(looseboardStatuses.slice(3).map((call) => call.body.idempotencyKey)).size, 1)
|
||||
assert.ok(looseboardStatuses.slice(3).every((call) => call.body.idempotencyKey !== looseboardStatuses[0].body.idempotencyKey))
|
||||
|
||||
const registry = context.createdResources.phase4OverseasBusiness
|
||||
assert.equal(registry.purchase.finalStatus, 'REJECTED')
|
||||
assert.equal(registry.purchase.retained, false)
|
||||
assert.equal(registry.truck.finalStatus, 'CANCELLED')
|
||||
assert.equal(registry.truck.retained, false)
|
||||
assert.equal(registry.looseboard.finalStatus, 'CANCELLED')
|
||||
assert.equal(registry.looseboard.retained, false)
|
||||
assert.equal(registry.truck.finalStatus, 'COMPLETED')
|
||||
assert.equal(registry.truck.retained, true)
|
||||
assert.equal(registry.truck.fulfillment.status, 'HTTP_VERIFIED')
|
||||
assert.equal(registry.looseboard.finalStatus, 'PENDING_ACCEPTANCE')
|
||||
assert.equal(registry.looseboard.retained, true)
|
||||
assert.equal(registry.partnerWarehouse.finalStatus, 'INACTIVE')
|
||||
assert.equal(registry.partnerWarehouse.retained, false)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user