fix overseas PDA producer fixture selection

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