优化
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { verifyReceivedOrderHold } from './phase4-tail-order-controls.mjs'
|
||||
|
||||
const MODULE = 'phase4-overseas-pda-operations'
|
||||
const SCENARIO = 'phase4-overseas-pda-p2-p5'
|
||||
const OPTIONS = { scenario: SCENARIO, deploymentBlocker: true }
|
||||
@@ -460,8 +462,20 @@ async function verifyRelabel(context, token, merchantToken, fixture) {
|
||||
return false
|
||||
}
|
||||
const unitPath = `${pdaBase}/${encodeURIComponent(relabelNo)}/units`
|
||||
if (item.operationType === 'CARTON_AND_SKU') {
|
||||
const carton = await request(context, token, 'POST', 'P5正常换标先确认箱标阶段',
|
||||
`${pdaBase}/${encodeURIComponent(relabelNo)}/cartons/scan`, {
|
||||
cartonMark: item.cartonMark, expectedVersion: Number(detail.version),
|
||||
idempotencyKey: key(context, 'RELABEL-NORMAL-CARTON'),
|
||||
})
|
||||
if (!success(carton.response)) return false
|
||||
detail = carton.data
|
||||
}
|
||||
const scanBody = { itemId: id(item.itemId), oldLabel: item.cartonMark,
|
||||
newLabel: item.fbaCartonMark || item.newSkuCode,
|
||||
skuVerifications: (item.skuItems || []).map(sku => ({
|
||||
skuCode: sku.skuCode, newSkuCode: sku.newSkuCode, quantity: Number(sku.quantity),
|
||||
})),
|
||||
expectedVersion: Number(detail.version), idempotencyKey: key(context, 'RELABEL-NORMAL') }
|
||||
const scanned = await request(context, token, 'POST', 'P5正常换标一箱', unitPath, scanBody)
|
||||
const scanReplay = await request(context, token, 'POST', 'P5正常换标同键重放', unitPath, scanBody)
|
||||
@@ -516,43 +530,45 @@ async function verifyRelabel(context, token, merchantToken, fixture) {
|
||||
if (!photoId) return false
|
||||
const completePath = `${pdaBase}/${encodeURIComponent(relabelNo)}/complete`
|
||||
const completeBody = { photoFileIds: [photoId], expectedVersion: Number(detail.version),
|
||||
idempotencyKey: key(context, 'RELABEL-COMPLETE-1'), remark: `${context.marker}-complete-1` }
|
||||
const completed = await request(context, token, 'POST', 'P5首次完成换标进入WAIT_REVIEW', completePath, completeBody)
|
||||
manualCompletion: true, idempotencyKey: key(context, 'RELABEL-COMPLETE-1'), remark: `${context.marker}-complete-1` }
|
||||
const completed = await request(context, token, 'POST', 'P5异常手动完成换标进入WAIT_REVIEW', completePath, completeBody)
|
||||
if (!success(completed.response)) return false
|
||||
const completeReplay = await request(context, token, 'POST', 'P5首次完成同键重放', completePath, completeBody)
|
||||
context.assert(MODULE, 'P5首次完成重放保持WAIT_REVIEW', completeReplay.response,
|
||||
completeReplay.data?.taskStatus === 'WAIT_REVIEW', trace(completeReplay.response), OPTIONS)
|
||||
const reviewPath = `${pdaBase}/${encodeURIComponent(relabelNo)}/review`
|
||||
const reworkBody = { decision: 'REWORK', expectedVersion: Number(completed.data?.version),
|
||||
const reviewPath = `${relabelBase}/${encodeURIComponent(relabelNo)}/rework`
|
||||
const reworkBody = { decision: 'REWORK', expectedVersion: Number(completed.data.version),
|
||||
idempotencyKey: key(context, 'RELABEL-REWORK'), remark: `${context.marker}-rework` }
|
||||
const reworked = await request(context, token, 'POST', 'P5复核退回REWORK', reviewPath, reworkBody)
|
||||
const reworkReplay = await request(context, token, 'POST', 'P5 REWORK同键重放', reviewPath, reworkBody)
|
||||
const reworked = await request(context, context.overseasToken, 'POST', 'P5平台复核退回REWORK', reviewPath, reworkBody)
|
||||
if (!success(reworked.response)) return false
|
||||
const reworkReplay = await request(context, context.overseasToken, 'POST', 'P5 REWORK同键重放', reviewPath, reworkBody)
|
||||
context.assert(MODULE, 'P5 REWORK重放保持PROCESSING', reworkReplay.response,
|
||||
reworkReplay.data?.taskStatus === 'PROCESSING', trace(reworkReplay.response), OPTIONS)
|
||||
const secondCompleteBody = { photoFileIds: [photoId], expectedVersion: Number(reworked.data?.version),
|
||||
idempotencyKey: key(context, 'RELABEL-COMPLETE-2'), remark: `${context.marker}-complete-2` }
|
||||
const secondCompleted = await request(context, token, 'POST', 'P5返工后再次完成WAIT_REVIEW',
|
||||
completePath, secondCompleteBody)
|
||||
const secondReplay = await request(context, token, 'POST', 'P5再次完成同键重放', completePath, secondCompleteBody)
|
||||
context.assert(MODULE, 'P5再次完成重放保持WAIT_REVIEW', secondReplay.response,
|
||||
secondReplay.data?.taskStatus === 'WAIT_REVIEW', trace(secondReplay.response), OPTIONS)
|
||||
const approveBody = { decision: 'APPROVE', expectedVersion: Number(secondCompleted.data?.version),
|
||||
idempotencyKey: key(context, 'RELABEL-APPROVE'), remark: `${context.marker}-approved` }
|
||||
const approved = await request(context, token, 'POST', 'P5复核批准换标完成', reviewPath, approveBody)
|
||||
const approveReplay = await request(context, token, 'POST', 'P5批准同键重放', reviewPath, approveBody)
|
||||
context.assert(MODULE, 'P5 PDA批准后等待客户确认', approveReplay.response,
|
||||
approved.data?.taskStatus === 'COMPLETED' && approved.data?.applicationStatus === 'CUSTOMER_CONFIRM_PENDING'
|
||||
&& approveReplay.data?.taskStatus === 'COMPLETED', trace(approveReplay.response), OPTIONS)
|
||||
if (approved.data?.applicationStatus !== 'CUSTOMER_CONFIRM_PENDING') return false
|
||||
|
||||
const confirmBody = { idempotencyKey: key(context, 'RELABEL-CUSTOMER-CONFIRM'),
|
||||
remark: `${context.marker}-customer-confirmed` }
|
||||
const confirmedResponse = await context.requestOverseas('POST',
|
||||
`${merchantRelabelBase}/${encodeURIComponent(relabelNo)}/confirm-completion`, confirmBody, {}, merchantToken)
|
||||
const confirmed = success(confirmedResponse) ? confirmedResponse.body?.data : null
|
||||
context.addStep(MODULE, 'P5客户确认换标完成进入待排车', confirmedResponse,
|
||||
confirmed?.application?.status === 'READY_FOR_OUTBOUND'
|
||||
&& confirmed?.application?.fulfillmentStatus === 'WAIT_PRE_DISPATCH', trace(confirmedResponse), OPTIONS)
|
||||
if (confirmed?.application?.status !== 'READY_FOR_OUTBOUND') return false
|
||||
reworkReplay.data?.taskStatus === 'PROCESSING' && Number(reworkReplay.data.relabelledPackages) === 0,
|
||||
trace(reworkReplay.response), OPTIONS)
|
||||
detail = reworked.data
|
||||
for (const redoItem of detail.items || []) {
|
||||
if (redoItem.operationType === 'CARTON_AND_SKU') {
|
||||
const carton = await request(context, token, 'POST', 'P5返工重新确认箱标阶段',
|
||||
`${pdaBase}/${encodeURIComponent(relabelNo)}/cartons/scan`, {
|
||||
cartonMark: redoItem.cartonMark, expectedVersion: Number(detail.version),
|
||||
idempotencyKey: key(context, `RELABEL-REDO-CARTON-${redoItem.itemId}`),
|
||||
})
|
||||
if (!success(carton.response)) return false
|
||||
detail = carton.data
|
||||
}
|
||||
const redo = await request(context, token, 'POST', 'P5返工重新完成SKU阶段', unitPath, {
|
||||
itemId: id(redoItem.itemId), oldLabel: redoItem.cartonMark, newLabel: redoItem.newSkuCode,
|
||||
skuVerifications: (redoItem.skuItems || []).map(sku => ({
|
||||
skuCode: sku.skuCode, newSkuCode: sku.newSkuCode, quantity: Number(sku.quantity),
|
||||
})),
|
||||
expectedVersion: Number(detail.version), idempotencyKey: key(context, `RELABEL-REDO-SKU-${redoItem.itemId}`),
|
||||
})
|
||||
if (!success(redo.response)) return false
|
||||
detail = redo.data
|
||||
}
|
||||
const bindingResponse = await context.requestOverseas('GET', `${relabelBase}/${encodeURIComponent(relabelNo)}`)
|
||||
const bindingDetail = success(bindingResponse) ? bindingResponse.body.data : null
|
||||
if (!Array.isArray(bindingDetail?.items) || bindingDetail.items.length !== 3) return false
|
||||
|
||||
const operationBase = '/api/pda/v1/last-leg/pallet-operations'
|
||||
const printKeyA = key(context, 'RELABEL-PRINT-A')
|
||||
@@ -574,7 +590,7 @@ async function verifyRelabel(context, token, merchantToken, fixture) {
|
||||
const targets = [printedA.data, printedB.data]
|
||||
const beforeBySource = new Map()
|
||||
const movedFacts = []
|
||||
const sourceCodes = confirmed.items.map((itemDetail) => {
|
||||
const sourceCodes = bindingDetail.items.map((itemDetail) => {
|
||||
const sourcePositionId = id(itemDetail?.sourceInventoryPositionId)
|
||||
return sourceLines.find((line) => id(line.position.positionId) === sourcePositionId)?.position?.palletNo || ''
|
||||
})
|
||||
@@ -584,12 +600,12 @@ async function verifyRelabel(context, token, merchantToken, fixture) {
|
||||
}, new Map())
|
||||
const splitSource = [...sourceFrequency.entries()].find(([, count]) => count >= 2)?.[0] || ''
|
||||
let splitSourceMoves = 0
|
||||
for (const [index, itemDetail] of confirmed.items.entries()) {
|
||||
for (const [index, itemDetail] of bindingDetail.items.entries()) {
|
||||
const sourcePositionId = id(itemDetail?.sourceInventoryPositionId)
|
||||
const sourceLine = sourceLines.find((line) => id(line.position.positionId) === sourcePositionId)
|
||||
const sourcePalletCode = sourceLine?.position?.palletNo
|
||||
if (!sourcePalletCode || !itemDetail?.cartonMark) {
|
||||
blocker(context, 'P5换标拆托来源快照', `item=${index + 1}缺少来源托盘或箱唛`, confirmedResponse)
|
||||
blocker(context, 'P5换标拆托来源快照', `item=${index + 1}缺少来源托盘或箱唛`, bindingResponse)
|
||||
return false
|
||||
}
|
||||
const sourceBefore = (await resolvePallet(context, token, sourcePalletCode,
|
||||
@@ -670,6 +686,27 @@ async function verifyRelabel(context, token, merchantToken, fixture) {
|
||||
&& relabelLedgers.every((row) => String(row?.remark || '').startsWith('换标拆托')),
|
||||
`rows=${relabelLedgers.length}, deltas=${relabelLedgers.map((row) => row.deltaPackages).join(',')}; ${trace(ledgerResponse)}`, OPTIONS)
|
||||
|
||||
const afterBinding = await request(context, token, 'GET', 'P5组托后刷新任务版本',
|
||||
`${pdaBase}/${encodeURIComponent(relabelNo)}`)
|
||||
if (!success(afterBinding.response)) return false
|
||||
const finalBody = { photoFileIds: [photoId], expectedVersion: Number(afterBinding.data.version),
|
||||
idempotencyKey: key(context, 'RELABEL-COMPLETE-2'), remark: `${context.marker}-complete-2` }
|
||||
const approved = await request(context, token, 'POST', 'P5返工组托后提交完工等待客户确认', completePath, finalBody)
|
||||
if (!success(approved.response) || approved.data?.applicationStatus !== 'CUSTOMER_CONFIRM_PENDING') return false
|
||||
const finalReplay = await request(context, token, 'POST', 'P5返工完工同键重放', completePath, finalBody)
|
||||
context.assert(MODULE, 'P5返工完工重放保持待客户确认', finalReplay.response,
|
||||
finalReplay.data?.taskStatus === 'WAIT_REVIEW' && finalReplay.data?.applicationStatus === 'CUSTOMER_CONFIRM_PENDING',
|
||||
trace(finalReplay.response), OPTIONS)
|
||||
const confirmBody = { idempotencyKey: key(context, 'RELABEL-CUSTOMER-CONFIRM'),
|
||||
remark: `${context.marker}-customer-confirmed` }
|
||||
const confirmedResponse = await context.requestOverseas('POST',
|
||||
`${merchantRelabelBase}/${encodeURIComponent(relabelNo)}/confirm-completion`, confirmBody, {}, merchantToken)
|
||||
const confirmed = success(confirmedResponse) ? confirmedResponse.body?.data : null
|
||||
context.addStep(MODULE, 'P5客户确认换标完成进入待排车', confirmedResponse,
|
||||
confirmed?.application?.status === 'READY_FOR_OUTBOUND'
|
||||
&& confirmed?.application?.fulfillmentStatus === 'WAIT_PRE_DISPATCH', trace(confirmedResponse), OPTIONS)
|
||||
if (confirmed?.application?.status !== 'READY_FOR_OUTBOUND') return false
|
||||
|
||||
context.createdResources.phase4OverseasRelabel = {
|
||||
marker: context.marker, relabelNo, customerId, overseasWarehouseId: id(fixture.overseasWarehouseId),
|
||||
targetPalletIds: [...new Set(movedFacts.map((fact) => fact.targetPalletId))],
|
||||
@@ -719,6 +756,7 @@ export async function run(context) {
|
||||
return
|
||||
}
|
||||
fixture.overseasWarehouseId = id(handoff.overseasWarehouseId)
|
||||
await verifyReceivedOrderHold(context)
|
||||
await verifyStocktake(context, token, fixture)
|
||||
await verifyInventoryMove(context, token, fixture)
|
||||
await verifyPalletOperations(context, token, fixture)
|
||||
|
||||
Reference in New Issue
Block a user