test(acceptance): reuse fixed customers and align native fulfillment flows
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { verifyReceivedOrderHold } from './phase4-tail-order-controls.mjs'
|
||||
import { verifyPdaWarehouseRevocation } from './unified-pda-session-revocation.mjs'
|
||||
import { readCurrentBoxedInventory } from './current-boxed-inventory.mjs'
|
||||
|
||||
const MODULE = 'phase4-overseas-pda-operations'
|
||||
export const RELABEL_CHARGE_AMOUNT = 0.01
|
||||
@@ -364,14 +365,17 @@ export function selectPhysicalRelabelSources(candidates, preferredBalanceId) {
|
||||
const seen = new Set()
|
||||
for (const source of ordered) {
|
||||
if (!id(source?.inventoryBalanceId) || !id(source?.inboundOrderId)) continue
|
||||
for (const position of source.positions || []) {
|
||||
const usedByPosition = new Map()
|
||||
for (const carton of source.cartons || []) {
|
||||
const position = (source.positions || []).find(row => id(row.positionId) === id(carton.positionId))
|
||||
const positionId = id(position?.positionId)
|
||||
if (!positionId || seen.has(positionId) || !nonBlank(position?.palletNo)
|
||||
const cartonKey = `${id(source.inboundOrderId)}:${carton.cartonMark}`
|
||||
if (!carton.cartonMark || seen.has(cartonKey) || !positionId || !nonBlank(position?.palletNo)
|
||||
|| position.palletNo.toUpperCase() === 'UNBOUND') continue
|
||||
seen.add(positionId)
|
||||
const selected = Math.min(3 - sourceLines.length, Number(position.availablePackages))
|
||||
if (!Number.isInteger(selected) || selected <= 0) continue
|
||||
for (let index = 0; index < selected; index++) sourceLines.push({ source, position, packageCount: 1 })
|
||||
const used = usedByPosition.get(positionId) || 0
|
||||
if (used >= Number(position.availablePackages)) continue
|
||||
seen.add(cartonKey); usedByPosition.set(positionId, used + 1)
|
||||
sourceLines.push({ source, position, carton, packageCount: 1 })
|
||||
if (sourceLines.length === 3) return sourceLines
|
||||
}
|
||||
}
|
||||
@@ -388,25 +392,11 @@ async function verifyRelabel(context, token, merchantToken, fixture) {
|
||||
return false
|
||||
}
|
||||
if (!await fundRelabelWallet(context, customerId)) return false
|
||||
// P4 intentionally leaves one carton UNBOUND. P5 requires physical source pallets,
|
||||
// and may combine only the current completed container's same-destination inbounds.
|
||||
const inboundCodes = [...new Set((context.context.phase4OverseasPdaOperations?.completedFixtures || [])
|
||||
.filter((item) => item.containerNo === fixture.containerNo && item.destinationType === fixture.destinationType
|
||||
&& item.fbaWarehouseCode === fixture.fbaWarehouseCode)
|
||||
.map((item) => item.inboundCode).filter(nonBlank))]
|
||||
const inventoryCandidates = []
|
||||
let inventoryCandidatesResponse = null
|
||||
for (const inboundCode of inboundCodes) {
|
||||
inventoryCandidatesResponse = await context.request('GET', query(
|
||||
'/api/merchant/v1/last-leg/relabel-applications/inventory-candidates', {
|
||||
operationWarehouseId: fixture.overseasWarehouseId, inboundCode,
|
||||
}), undefined, merchantToken, {})
|
||||
context.addStep(MODULE, 'P5读取本轮同柜同目的仓换标候选', inventoryCandidatesResponse,
|
||||
success(inventoryCandidatesResponse), trace(inventoryCandidatesResponse), OPTIONS)
|
||||
if (!success(inventoryCandidatesResponse)) return false
|
||||
inventoryCandidates.push(...records(inventoryCandidatesResponse.body?.data).filter((item) =>
|
||||
item.inboundCode === inboundCode && id(item.overseasWarehouseId) === id(fixture.overseasWarehouseId)))
|
||||
}
|
||||
const boxed = await readCurrentBoxedInventory(context, merchantToken, fixture.overseasWarehouseId, MODULE)
|
||||
// 同一次收货产生的真实有箱库存;优先选一个具备三箱来源的入仓单,避免借用历史库存。
|
||||
const candidate = boxed.find(row => selectPhysicalRelabelSources([row]).length === 3)
|
||||
const inventoryCandidates = candidate ? [candidate] : []
|
||||
const inventoryCandidatesResponse = null
|
||||
const sourceLines = selectPhysicalRelabelSources(inventoryCandidates, inventory.balanceId)
|
||||
const requiredPackages = 3 - sourceLines.length
|
||||
context.addStep(MODULE, 'P5客户库存候选返回换标权威来源', inventoryCandidatesResponse,
|
||||
@@ -426,7 +416,7 @@ async function verifyRelabel(context, token, merchantToken, fixture) {
|
||||
contactName: 'PDA换标验收', contactPhone: '13800000006', chargeAmount: RELABEL_CHARGE_AMOUNT, remark: context.marker,
|
||||
idempotencyKey: key(context, 'RELABEL-CREATE'),
|
||||
deliveryMethod: 'TRUCK', printShippingLabel: false,
|
||||
items: sourceLines.map(({ source, position, packageCount }, index) => {
|
||||
items: sourceLines.map(({ source, position, carton, packageCount }, index) => {
|
||||
const newSkuCode = `${source.skuCode}-NEW-${markerSuffix}-${index + 1}`.slice(0, 128)
|
||||
const changesCartonLabel = nonBlank(source.destinationFbaWarehouseCode)
|
||||
return {
|
||||
@@ -437,11 +427,11 @@ async function verifyRelabel(context, token, merchantToken, fixture) {
|
||||
shipmentNo: `SHIP-${context.marker}-${index + 1}`.slice(0, 128),
|
||||
newSkuCode,
|
||||
labelRequirement: context.marker,
|
||||
cartonMark: nonBlank(source.cartonMark) ? source.cartonMark : `CM-${String(context.marker).slice(-28)}-${index + 1}`,
|
||||
cartonMark: carton.cartonMark,
|
||||
fbaCartonMark: changesCartonLabel ? `FBA-${String(context.marker).slice(-27)}-${index + 1}` : null,
|
||||
destinationFbaWarehouseCode: changesCartonLabel ? source.destinationFbaWarehouseCode : null,
|
||||
operationType: changesCartonLabel ? 'CARTON_AND_SKU' : 'SKU_LABEL',
|
||||
skuItems: [{ skuCode: source.skuCode, newSkuCode, quantity: packageCount, remark: context.marker }],
|
||||
skuItems: carton.items.map(item => ({ skuCode: item.skuCode, newSkuCode, quantity: Number(item.quantity), remark: context.marker })),
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user