贴标申请,仓储转运
This commit is contained in:
@@ -9,6 +9,7 @@ const overseas = process.env.ADMIN_OVERSEAS_GATEWAY || 'http://127.0.0.1:9300'
|
||||
let customerId = process.env.OVERSEAS_TEST_CUSTOMER_ID || ''
|
||||
let warehouseId = process.env.OVERSEAS_TEST_WAREHOUSE_ID || ''
|
||||
const destinationCode = process.env.OVERSEAS_TEST_DESTINATION_CODE || 'ONT8'
|
||||
const partialRelabel = process.env.WAREHOUSE_TRANSFER_PARTIAL_RELABEL === 'true'
|
||||
const output = resolve(process.env.WAREHOUSE_TRANSFER_REMAINING_OUTPUT
|
||||
|| 'reports/warehouse-transfer-remaining-acceptance.json')
|
||||
const marker = `WT-REMAIN-${new Date().toISOString().replace(/\D/g, '').slice(0, 14)}-${process.pid}`
|
||||
@@ -189,13 +190,14 @@ try {
|
||||
}
|
||||
|
||||
const cartonMarks = [`CM-${marker}-1`, `CM-${marker}-2`]
|
||||
const cartonRelabelBindings = partialRelabel ? cartonMarks.slice(0, 1) : cartonMarks
|
||||
const transfer = await api(overseas, merchant.overseasAccessToken, 'POST',
|
||||
'/api/merchant/v1/last-leg/warehouse-transfers', {
|
||||
operatingWarehouseId: warehouseId,
|
||||
fbaWarehouseCode: destinationCode,
|
||||
destinationType: 'FBA',
|
||||
destinationWarehouseCode: destinationCode,
|
||||
destinationWarehouseName: destinationCode,
|
||||
fbaWarehouseCode: partialRelabel ? null : destinationCode,
|
||||
destinationType: partialRelabel ? null : 'FBA',
|
||||
destinationWarehouseCode: partialRelabel ? null : destinationCode,
|
||||
destinationWarehouseName: partialRelabel ? null : destinationCode,
|
||||
deliveryAddress: `Acceptance inbound address ${marker}`,
|
||||
packageCount: 2,
|
||||
volumeCbm: 0.12,
|
||||
@@ -214,7 +216,7 @@ try {
|
||||
idempotencyKey: key('CREATE'),
|
||||
items: [{ skuCode: `SKU-${marker}`.slice(0, 128), productNameZh: 'Acceptance cargo',
|
||||
packageCount: 2, shippingMark: cartonMarks.join(',') }],
|
||||
relabelItems: cartonMarks.map((cartonMark, index) => ({
|
||||
relabelItems: cartonRelabelBindings.map((cartonMark, index) => ({
|
||||
operationType: 'CARTON_AND_SKU', customerCartonMarks: [cartonMark],
|
||||
originalSku: `SKU-${marker}`.slice(0, 128),
|
||||
newSku: `NEW-${marker}-${index + 1}`.slice(0, 128), quantity: 1,
|
||||
@@ -278,9 +280,18 @@ try {
|
||||
status: transferDetail.status, relabelNo,
|
||||
})
|
||||
|
||||
const reviewedRelabel = await api(overseas, admin.overseasAccessToken, 'PUT',
|
||||
`/api/platform/v1/last-leg/relabel-applications/${relabelNo}/status`, {
|
||||
status: 'PENDING_PROCESSING', remark: marker,
|
||||
})
|
||||
assert(reviewedRelabel.application.status === 'PENDING_PROCESSING',
|
||||
`Linked relabel review did not approve execution: ${reviewedRelabel.application.status}`)
|
||||
step('Platform approved linked relabel for PDA execution', { status: reviewedRelabel.application.status })
|
||||
|
||||
let relabel = await api(overseas, pda.token, 'POST',
|
||||
`/api/pda/v1/last-leg/relabel-tasks/${relabelNo}/claim`, { idempotencyKey: key('RELABEL-CLAIM') })
|
||||
assert(relabel.items.length === 2, `Expected two linked relabel items, got ${relabel.items.length}`)
|
||||
assert(relabel.items.length === (partialRelabel ? 1 : 2),
|
||||
`Expected ${partialRelabel ? 1 : 2} linked relabel items, got ${relabel.items.length}`)
|
||||
for (const [index, item] of relabel.items.entries()) {
|
||||
relabel = await api(overseas, pda.token, 'POST',
|
||||
`/api/pda/v1/last-leg/relabel-tasks/${relabelNo}/cartons/scan`, {
|
||||
@@ -330,7 +341,8 @@ try {
|
||||
transferDetail = await api(overseas, merchant.overseasAccessToken, 'GET',
|
||||
`/api/merchant/v1/last-leg/warehouse-transfers/${transferNo}`)
|
||||
assert(confirmedRelabel.application.status === 'READY_FOR_OUTBOUND', 'Linked relabel did not reach outbound-ready')
|
||||
assert(transferDetail.status === 'READY_FOR_DISPATCH', 'Warehouse transfer did not return to dispatch-ready')
|
||||
assert(transferDetail.status === (partialRelabel ? 'WAIT_FBA_DESTINATION' : 'READY_FOR_DISPATCH'),
|
||||
`Warehouse transfer reached unexpected status ${transferDetail.status}`)
|
||||
step('Completed linked relabel and released transfer for dispatch', {
|
||||
relabelStatus: confirmedRelabel.application.status, transferStatus: transferDetail.status,
|
||||
})
|
||||
@@ -339,17 +351,30 @@ try {
|
||||
`/api/platform/v1/last-leg/dispatches/candidates?orderNo=${encodeURIComponent(relabelNo)}&sourceStage=RECEIVED`)
|
||||
const targetIds = new Set(targetPallets.map((value) => id(value.palletId)))
|
||||
const rows = candidates.filter((value) => value.sourceStage === 'RELABEL' && targetIds.has(id(value.warehousePalletId)))
|
||||
assert(rows.length === 2, `Expected two smart-dispatch pallets, got ${rows.length}`)
|
||||
assert(rows.length === (partialRelabel ? 1 : 2),
|
||||
`Expected ${partialRelabel ? 1 : 2} smart-dispatch pallets, got ${rows.length}`)
|
||||
const dispatch = await api(overseas, admin.overseasAccessToken, 'POST',
|
||||
'/api/platform/v1/last-leg/dispatches/pre-arrange', {
|
||||
planPalletIds: rows.map((value) => id(value.warehousePalletId)), route: marker, relabelNo,
|
||||
})
|
||||
step('Created smart pre-dispatch', { dispatchNo: dispatch.dispatchNo, status: dispatch.status })
|
||||
|
||||
if (partialRelabel) {
|
||||
const outboundCandidates = await api(overseas, admin.overseasAccessToken, 'GET',
|
||||
`/api/platform/v1/last-leg/outbound-orders/warehouse-transfer/candidates?customerId=${encodeURIComponent(customerId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const remaining = outboundCandidates.filter((value) => value.transferNo === transferNo)
|
||||
assert(remaining.length === 1 && Number(remaining[0].packageCount) === 1,
|
||||
`Expected one unlabelled carton in warehouse-transfer outbound candidates, got ${JSON.stringify(remaining)}`)
|
||||
step('Verified split outbound routing', {
|
||||
relabelDispatchPallets: rows.length, remainingOutboundCandidates: remaining.length,
|
||||
remainingPackageCount: remaining[0].packageCount,
|
||||
})
|
||||
}
|
||||
|
||||
const sourceReport = resolve('reports', `${marker}-relabel-source.json`)
|
||||
const fulfillmentReport = resolve('reports', `${marker}-fulfillment.json`)
|
||||
await writeFile(sourceReport, JSON.stringify({ marker, passed: true, scenarios: [{
|
||||
name: 'SPLIT-TWO-TARGETS', relabelNo, dispatchNo: dispatch.dispatchNo,
|
||||
name: 'SPLIT-TWO-TARGETS', relabelNo, dispatchNo: dispatch.dispatchNo, partialRelabel,
|
||||
}] }, null, 2), 'utf8')
|
||||
const child = spawnSync(process.execPath, [resolve('scripts', 'overseas-relabel-fulfillment-acceptance.mjs')], {
|
||||
cwd: resolve('.'), stdio: 'inherit', env: {
|
||||
@@ -366,11 +391,70 @@ try {
|
||||
})
|
||||
if (child.error) throw child.error
|
||||
if (child.status !== 0) throw new Error(`Fulfillment acceptance failed with exit code ${child.status}`)
|
||||
const finalTransfer = await api(overseas, merchant.overseasAccessToken, 'GET',
|
||||
let finalTransfer = await api(overseas, merchant.overseasAccessToken, 'GET',
|
||||
`/api/merchant/v1/last-leg/warehouse-transfers/${transferNo}`)
|
||||
let remainingDispatchNo = null
|
||||
let remainingFulfillmentReport = null
|
||||
if (partialRelabel) {
|
||||
assert(finalTransfer.status === 'WAIT_FBA_DESTINATION',
|
||||
`Partial relabel dispatch incorrectly closed the transfer: ${finalTransfer.status}`)
|
||||
const beforeBind = await api(overseas, admin.overseasAccessToken, 'GET',
|
||||
`/api/platform/v1/last-leg/outbound-orders/warehouse-transfer/candidates?customerId=${encodeURIComponent(customerId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const remainingBeforeBind = beforeBind.filter((value) => value.transferNo === transferNo)
|
||||
assert(remainingBeforeBind.length === 1 && Number(remainingBeforeBind[0].packageCount) === 1
|
||||
&& remainingBeforeBind[0].palletId && remainingBeforeBind[0].warehousePalletId,
|
||||
`Expected one selectable remaining pallet before destination binding, got ${JSON.stringify(remainingBeforeBind)}`)
|
||||
await api(overseas, admin.overseasAccessToken, 'POST',
|
||||
'/api/platform/v1/last-leg/warehouse-transfers/bind-destination', {
|
||||
transfers: [{ customerId, transferNo }], destinationType: 'FBA',
|
||||
destinationWarehouseCode: destinationCode, destinationWarehouseName: destinationCode,
|
||||
idempotencyKey: key('BIND-REMAINING-DESTINATION'),
|
||||
})
|
||||
const afterBind = await api(overseas, admin.overseasAccessToken, 'GET',
|
||||
`/api/platform/v1/last-leg/outbound-orders/warehouse-transfer/candidates?customerId=${encodeURIComponent(customerId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
assert(!afterBind.some((value) => value.transferNo === transferNo),
|
||||
'Destination-bound transfer remained in the destination-completion outbound list')
|
||||
const remainingCandidates = await api(overseas, admin.overseasAccessToken, 'GET',
|
||||
`/api/platform/v1/last-leg/dispatches/candidates?orderNo=${encodeURIComponent(transferNo)}&sourceStage=RECEIVED`)
|
||||
const remainingRows = remainingCandidates.filter((value) => value.sourceStage === 'RECEIVED'
|
||||
&& Number(value.packageCount) === 1 && value.destinationWarehouseCode === destinationCode)
|
||||
assert(remainingRows.length === 1,
|
||||
`Expected one destination-bound smart-dispatch pallet, got ${JSON.stringify(remainingRows)}`)
|
||||
const remainingDispatch = await api(overseas, admin.overseasAccessToken, 'POST',
|
||||
'/api/platform/v1/last-leg/dispatches/pre-arrange', {
|
||||
planPalletIds: remainingRows.map((value) => id(value.planPalletId)), route: `${marker}-REMAINING`,
|
||||
})
|
||||
remainingDispatchNo = remainingDispatch.dispatchNo
|
||||
const remainingSourceReport = resolve('reports', `${marker}-remaining-source.json`)
|
||||
remainingFulfillmentReport = resolve('reports', `${marker}-remaining-fulfillment.json`)
|
||||
await writeFile(remainingSourceReport, JSON.stringify({ marker, passed: true, scenarios: [{
|
||||
name: 'SPLIT-TWO-TARGETS', relabelNo: '', dispatchNo: remainingDispatchNo, partialRelabel: true,
|
||||
}] }, null, 2), 'utf8')
|
||||
const remainingChild = spawnSync(process.execPath,
|
||||
[resolve('scripts', 'overseas-relabel-fulfillment-acceptance.mjs')], {
|
||||
cwd: resolve('.'), stdio: 'inherit', env: {
|
||||
...process.env, ADMIN_TEST_GATEWAY: domestic, ADMIN_OVERSEAS_GATEWAY: overseas,
|
||||
ADMIN_OVERSEAS_ACCESS_TOKEN: admin.overseasAccessToken,
|
||||
MERCHANT_OVERSEAS_ACCESS_TOKEN: merchant.overseasAccessToken,
|
||||
PDA_OVERSEAS_ACCESS_TOKEN: pda.token, OVERSEAS_TEST_CUSTOMER_ID: customerId,
|
||||
OVERSEAS_ACCEPTANCE_SOURCE: remainingSourceReport,
|
||||
OVERSEAS_FULFILLMENT_OUTPUT: remainingFulfillmentReport,
|
||||
},
|
||||
})
|
||||
if (remainingChild.error) throw remainingChild.error
|
||||
if (remainingChild.status !== 0) throw new Error(`Remaining fulfillment failed with exit code ${remainingChild.status}`)
|
||||
finalTransfer = await api(overseas, merchant.overseasAccessToken, 'GET',
|
||||
`/api/merchant/v1/last-leg/warehouse-transfers/${transferNo}`)
|
||||
assert(finalTransfer.status === 'OUTBOUNDED',
|
||||
`Remaining transfer did not complete outbound: ${finalTransfer.status}`)
|
||||
step('Bound remaining carton destination and completed its smart dispatch', {
|
||||
remainingDispatchNo, remainingPackageCount: 1, transferStatus: finalTransfer.status,
|
||||
})
|
||||
}
|
||||
Object.assign(report, {
|
||||
passed: true, transferNo, relabelNo, dispatchNo: dispatch.dispatchNo,
|
||||
transferStatus: finalTransfer.status, fulfillmentReport, finishedAt: new Date().toISOString(),
|
||||
remainingDispatchNo, transferStatus: finalTransfer.status, fulfillmentReport,
|
||||
remainingFulfillmentReport, finishedAt: new Date().toISOString(),
|
||||
})
|
||||
} catch (error) {
|
||||
report.error = error instanceof Error ? error.message : String(error)
|
||||
|
||||
Reference in New Issue
Block a user