fix overseas PDA producer fixture selection
This commit is contained in:
@@ -1607,6 +1607,11 @@ export class AcceptanceRun {
|
|||||||
if (!hasStandardFbaProducer()) {
|
if (!hasStandardFbaProducer()) {
|
||||||
await this.runPhase4ProducerVariant('FBA-STANDARD', 'FBA', 'STANDARD', true)
|
await this.runPhase4ProducerVariant('FBA-STANDARD', 'FBA', 'STANDARD', true)
|
||||||
}
|
}
|
||||||
|
const hasSecondStandardFbaProducer = () => (this.createdResources.phase4InboundProducerFixtures?.containers || [])
|
||||||
|
.some((item) => /-P4-FBA-SECOND(?:-R\d+)?:/.test(String(item?.resourceKey || '')))
|
||||||
|
if (!hasSecondStandardFbaProducer()) {
|
||||||
|
await this.runPhase4ProducerVariant('FBA-SECOND', 'FBA', 'STANDARD', true)
|
||||||
|
}
|
||||||
if (Number(readiness().overseasContainerCount || 0) < 1) {
|
if (Number(readiness().overseasContainerCount || 0) < 1) {
|
||||||
await this.runPhase4ProducerVariant('OVERSEAS-PRIMARY', 'OVERSEAS', 'ONE_CLICK_DROPSHIP', true)
|
await this.runPhase4ProducerVariant('OVERSEAS-PRIMARY', 'OVERSEAS', 'ONE_CLICK_DROPSHIP', true)
|
||||||
}
|
}
|
||||||
@@ -1622,11 +1627,14 @@ export class AcceptanceRun {
|
|||||||
&& item?.fulfillmentType !== 'ONE_CLICK_DROPSHIP'
|
&& item?.fulfillmentType !== 'ONE_CLICK_DROPSHIP'
|
||||||
&& /-P4-FBA-STANDARD(?:-R\d+)?:/.test(String(item?.resourceKey || '')))
|
&& /-P4-FBA-STANDARD(?:-R\d+)?:/.test(String(item?.resourceKey || '')))
|
||||||
const overseasReady = containers.find((item) => item?.destinationType === 'OVERSEAS')
|
const overseasReady = containers.find((item) => item?.destinationType === 'OVERSEAS')
|
||||||
|
const secondStandardFbaReady = containers.find((item) =>
|
||||||
|
/-P4-FBA-SECOND(?:-R\d+)?:/.test(String(item?.resourceKey || '')))
|
||||||
const awaitingVariants = containers.filter((item) => ['SECONDARY']
|
const awaitingVariants = containers.filter((item) => ['SECONDARY']
|
||||||
.some((label) => new RegExp(`-P4-${label}(?:-R\\d+)?:`).test(String(item?.resourceKey || ''))))
|
.some((label) => new RegExp(`-P4-${label}(?:-R\\d+)?:`).test(String(item?.resourceKey || ''))))
|
||||||
const shippingMatrixReady = dropshipReady?.shippingReady === true
|
const shippingMatrixReady = dropshipReady?.shippingReady === true
|
||||||
&& Boolean(dropshipReady?.carrierScheduleQueryId)
|
&& Boolean(dropshipReady?.carrierScheduleQueryId)
|
||||||
&& standardFbaReady?.shippingReady === true && Boolean(standardFbaReady?.carrierScheduleQueryId)
|
&& standardFbaReady?.shippingReady === true && Boolean(standardFbaReady?.carrierScheduleQueryId)
|
||||||
|
&& secondStandardFbaReady?.shippingReady === true && Boolean(secondStandardFbaReady?.carrierScheduleQueryId)
|
||||||
&& overseasReady?.shippingReady === true && Boolean(overseasReady?.carrierScheduleQueryId)
|
&& overseasReady?.shippingReady === true && Boolean(overseasReady?.carrierScheduleQueryId)
|
||||||
&& awaitingVariants.length >= 1
|
&& awaitingVariants.length >= 1
|
||||||
&& awaitingVariants.every((item) => item.shippingReady === false
|
&& awaitingVariants.every((item) => item.shippingReady === false
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ export async function run(context) {
|
|||||||
- `dropship-outbound-edge-cases.mjs` 是 `dropship-pallet-matrix` 内部探针,不单独运行:使用本轮库存验证超量、错误 SKU、不存在/重复箱唛、箱数不符、同键异载荷、未拣齐完成、并发同键创建、未拣取消和重放。单票单托额外先拣一箱再拣剩余箱;部分拣货被拒时仍保留失败及部署阻断,只有回查冻结事实无变化才继续整条明细拣货以采集后续证据,不能将此计为分批通过。多票共托使用同一 SKU,来源区分必须依赖入仓码。成功数据保留,未拣并发探针出库单正常取消。本扩展不代表跨客户、跨仓、多 SKU 混箱、逐箱不等件数、跨区故障注入均已覆盖,结论以当轮真实报告为准。
|
- `dropship-outbound-edge-cases.mjs` 是 `dropship-pallet-matrix` 内部探针,不单独运行:使用本轮库存验证超量、错误 SKU、不存在/重复箱唛、箱数不符、同键异载荷、未拣齐完成、并发同键创建、未拣取消和重放。单票单托额外先拣一箱再拣剩余箱;部分拣货被拒时仍保留失败及部署阻断,只有回查冻结事实无变化才继续整条明细拣货以采集后续证据,不能将此计为分批通过。多票共托使用同一 SKU,来源区分必须依赖入仓码。成功数据保留,未拣并发探针出库单正常取消。本扩展不代表跨客户、跨仓、多 SKU 混箱、逐箱不等件数、跨区故障注入均已覆盖,结论以当轮真实报告为准。
|
||||||
- `phase3-container-documents` 从本轮货柜详情读取渠道:海铁验证 DO 上传被明确拒绝且聚合中没有 DO,其他渠道继续验证 DO 上传、重放及零漂移;缺渠道不猜测适用性。
|
- `phase3-container-documents` 从本轮货柜详情读取渠道:海铁验证 DO 上传被明确拒绝且聚合中没有 DO,其他渠道继续验证 DO 上传、重放及零漂移;缺渠道不猜测适用性。
|
||||||
- `phase4-overseas-pda-operations` 用三个独立逐箱任务分别验证正常换标、跳过和异常,异常不得重复使用前两箱。前一步失败时保留失败并停止该链,不继续使用空响应版本。
|
- `phase4-overseas-pda-operations` 用三个独立逐箱任务分别验证正常换标、跳过和异常,异常不得重复使用前两箱。前一步失败时保留失败并停止该链,不继续使用空响应版本。
|
||||||
|
- 海外 PDA 生产矩阵为实际作业准备 `FBA-STANDARD`、`FBA-SECOND` 两个通过真实出仓和船节点达到 `PICKUP_READY` 的标准 FBA 柜,同时保留 `SECONDARY` 未放行柜用于负向门禁;不得将负向柜当作第二个收货柜。
|
||||||
- 海外 PDA 按真实柜号去重执行签收,缺少一件代发生产者不得用 FBA 生产者替代;原生产矩阵失败仍保留。P4 解绑样本保留为 `UNBOUND`,P5 只从本轮已完成同柜、同目的仓的入仓码中选择三箱实物托盘库存,排除 `UNBOUND` 和重复仓位,不借用历史订单。
|
- 海外 PDA 按真实柜号去重执行签收,缺少一件代发生产者不得用 FBA 生产者替代;原生产矩阵失败仍保留。P4 解绑样本保留为 `UNBOUND`,P5 只从本轮已完成同柜、同目的仓的入仓码中选择三箱实物托盘库存,排除 `UNBOUND` 和重复仓位,不借用历史订单。
|
||||||
- 排车详情按 `DispatchResponse.Item` 核对托盘与箱数,不读取 DTO 未提供的箱唛字段;`phase5-overseas-fulfillment` 将同一换标排车转为待出库单,通过 `OutboundDetail.pallets.cartonMarks` 验证全部新箱唛、排除原箱唛和重复箱。该测试生成的待出库单及派送单保留为本轮证据,不推进人工退货样本。
|
- 排车详情按 `DispatchResponse.Item` 核对托盘与箱数,不读取 DTO 未提供的箱唛字段;`phase5-overseas-fulfillment` 将同一换标排车转为待出库单,通过 `OutboundDetail.pallets.cartonMarks` 验证全部新箱唛、排除原箱唛和重复箱。该测试生成的待出库单及派送单保留为本轮证据,不推进人工退货样本。
|
||||||
- 出库前同操作员、同草稿允许重复预排并更新原排车;脚本核对排车身份与业务数量不漂移,不要求重新生成的明细行 ID 不变。其他草稿抢锁仍必须冲突,生成出库单后仍验证托盘编辑被拒绝。
|
- 出库前同操作员、同草稿允许重复预排并更新原排车;脚本核对排车身份与业务数量不漂移,不要求重新生成的明细行 ID 不变。其他草稿抢锁仍必须冲突,生成出库单后仍验证托盘编辑被拒绝。
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export function buildPendingActions(task) {
|
|||||||
async function request(context, method, path, body, headers = {}) {
|
async function request(context, method, path, body, headers = {}) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${context.options.gateway}${path}`, { method,
|
const response = await fetch(`${context.options.gateway}${path}`, { method,
|
||||||
headers: { Accept: 'application/json', Authorization: `Bearer ${context.pdaToken && /\/pda-loading\/tasks\/\d+/.test(path) ? context.pdaToken : context.token}`,
|
headers: { Accept: 'application/json', Authorization: `Bearer ${context.pdaToken && /\/pda-loading\/tasks\/(?:\d+|pending)(?:[/?]|$)/.test(path) ? context.pdaToken : context.token}`,
|
||||||
...(body === undefined ? {} : { 'Content-Type': 'application/json; charset=utf-8' }), ...headers },
|
...(body === undefined ? {} : { 'Content-Type': 'application/json; charset=utf-8' }), ...headers },
|
||||||
body: body === undefined ? undefined : JSON.stringify(body), signal: AbortSignal.timeout(60_000) })
|
body: body === undefined ? undefined : JSON.stringify(body), signal: AbortSignal.timeout(60_000) })
|
||||||
const raw = await response.text(); let payload = null
|
const raw = await response.text(); let payload = null
|
||||||
@@ -55,25 +55,8 @@ export async function run(context) {
|
|||||||
const pendingResponse = await request(context, 'GET',
|
const pendingResponse = await request(context, 'GET',
|
||||||
`/api/platform/v1/first-leg/pda-loading/tasks/pending?warehouseId=${encodeURIComponent(warehouseId)}&keyword=${encodeURIComponent(containerNo)}`)
|
`/api/platform/v1/first-leg/pda-loading/tasks/pending?warehouseId=${encodeURIComponent(warehouseId)}&keyword=${encodeURIComponent(containerNo)}`)
|
||||||
const pendingTasks = context.apiSuccess(MODULE, '读取当前操作员 PDA pending 列表', pendingResponse, '', OPTIONS)
|
const pendingTasks = context.apiSuccess(MODULE, '读取当前操作员 PDA pending 列表', pendingResponse, '', OPTIONS)
|
||||||
const pendingRecords = Array.isArray(pendingTasks) ? pendingTasks
|
const pendingTask = Array.isArray(pendingTasks)
|
||||||
: pendingTasks?.records || pendingTasks?.items || []
|
? pendingTasks.find((item) => id(item?.taskId) === taskId) : null
|
||||||
let pendingTask = pendingRecords.find((item) => id(item?.taskId || item?.id) === taskId)
|
|
||||||
if (!pendingTask) {
|
|
||||||
const currentKeyword = id(taskDetail?.currentContainerNo)
|
|
||||||
const currentPendingResponse = currentKeyword ? await request(context, 'GET',
|
|
||||||
`/api/platform/v1/first-leg/pda-loading/tasks/pending?warehouseId=${encodeURIComponent(warehouseId)}&keyword=${encodeURIComponent(currentKeyword)}`) : null
|
|
||||||
const currentPending = currentPendingResponse
|
|
||||||
? context.apiSuccess(MODULE, '按任务当前真实柜号回查 PDA pending 列表', currentPendingResponse, '', OPTIONS) : []
|
|
||||||
const currentRecords = Array.isArray(currentPending) ? currentPending : currentPending?.records || currentPending?.items || []
|
|
||||||
pendingTask = currentRecords.find((item) => id(item?.taskId || item?.id) === taskId)
|
|
||||||
}
|
|
||||||
if (!pendingTask) {
|
|
||||||
const broadPendingResponse = await request(context, 'GET',
|
|
||||||
`/api/platform/v1/first-leg/pda-loading/tasks/pending?warehouseId=${encodeURIComponent(warehouseId)}`)
|
|
||||||
const broadPending = context.apiSuccess(MODULE, '无关键词回查当前操作员 PDA pending 列表', broadPendingResponse, '', OPTIONS)
|
|
||||||
const broadRecords = Array.isArray(broadPending) ? broadPending : broadPending?.records || broadPending?.items || []
|
|
||||||
pendingTask = broadRecords.find((item) => id(item?.taskId || item?.id) === taskId)
|
|
||||||
}
|
|
||||||
const unresolvedItems = (taskDetail?.items || []).filter((item) =>
|
const unresolvedItems = (taskDetail?.items || []).filter((item) =>
|
||||||
['PENDING', 'PICKING'].includes(item?.itemStatus))
|
['PENDING', 'PICKING'].includes(item?.itemStatus))
|
||||||
context.assert(MODULE, 'pending 与 detail 使用同一 workflowStatus 和未完成数量事实', pendingResponse,
|
context.assert(MODULE, 'pending 与 detail 使用同一 workflowStatus 和未完成数量事实', pendingResponse,
|
||||||
|
|||||||
@@ -129,6 +129,8 @@ test('only PDA-operated variants traverse real outbound and carrier nodes before
|
|||||||
const entry = read('../admin-test-env-acceptance.mjs')
|
const entry = read('../admin-test-env-acceptance.mjs')
|
||||||
assert.match(entry, /runPhase4ProducerVariant\('OVERSEAS-PRIMARY', 'OVERSEAS', 'ONE_CLICK_DROPSHIP', true\)/)
|
assert.match(entry, /runPhase4ProducerVariant\('OVERSEAS-PRIMARY', 'OVERSEAS', 'ONE_CLICK_DROPSHIP', true\)/)
|
||||||
assert.match(entry, /runPhase4ProducerVariant\('FBA-STANDARD', 'FBA', 'STANDARD', true\)/)
|
assert.match(entry, /runPhase4ProducerVariant\('FBA-STANDARD', 'FBA', 'STANDARD', true\)/)
|
||||||
|
assert.match(entry, /runPhase4ProducerVariant\('FBA-SECOND', 'FBA', 'STANDARD', true\)/)
|
||||||
|
assert.match(entry, /secondStandardFbaReady\?\.shippingReady === true/)
|
||||||
assert.match(entry, /runPhase4ProducerVariant\('SECONDARY', 'FBA', 'STANDARD', false\)/)
|
assert.match(entry, /runPhase4ProducerVariant\('SECONDARY', 'FBA', 'STANDARD', false\)/)
|
||||||
assert.match(entry, /const hasSecondaryProducer =/)
|
assert.match(entry, /const hasSecondaryProducer =/)
|
||||||
assert.match(entry, /if \(!hasSecondaryProducer\(\)\)/)
|
assert.match(entry, /if \(!hasSecondaryProducer\(\)\)/)
|
||||||
|
|||||||
@@ -934,6 +934,8 @@ export async function run(context) {
|
|||||||
const dropship = matrix?.containers?.find((item) => item?.fulfillmentType === 'ONE_CLICK_DROPSHIP')
|
const dropship = matrix?.containers?.find((item) => item?.fulfillmentType === 'ONE_CLICK_DROPSHIP')
|
||||||
const standardFbaProducers = (matrix?.byDestinationType?.FBA || [])
|
const standardFbaProducers = (matrix?.byDestinationType?.FBA || [])
|
||||||
.filter((item) => item?.fulfillmentType !== 'ONE_CLICK_DROPSHIP')
|
.filter((item) => item?.fulfillmentType !== 'ONE_CLICK_DROPSHIP')
|
||||||
|
.filter((item) => /-P4-(?:FBA-STANDARD|FBA-SECOND)(?:-R\d+)?:/.test(String(item?.resourceKey || '')))
|
||||||
|
.sort((left, right) => String(left?.resourceKey).localeCompare(String(right?.resourceKey)))
|
||||||
.slice(0, 2)
|
.slice(0, 2)
|
||||||
// The sealed dropship pallet proves the indivisible handover. A separate standard FBA
|
// The sealed dropship pallet proves the indivisible handover. A separate standard FBA
|
||||||
// fixture supplies multiple cartons for reversible operations. The second standard FBA
|
// fixture supplies multiple cartons for reversible operations. The second standard FBA
|
||||||
|
|||||||
Reference in New Issue
Block a user