test(acceptance): align automatic preload workflows
This commit is contained in:
@@ -335,7 +335,8 @@ export function parseArguments(argv) {
|
||||
channelCode: values.get('channel-code') || '',
|
||||
orderProfileMode: values.get('order-profile-mode') || 'fixed',
|
||||
waitSplitCount: Number(values.get('wait-split-count') || process.env.ADMIN_WAIT_SPLIT_COUNT
|
||||
|| (modules.includes('manual-order-splitting-fixture') ? 6 : 1)),
|
||||
|| (modules.includes('coload-groups') ? 8
|
||||
: modules.includes('manual-order-splitting-fixture') ? 6 : 1)),
|
||||
waitSplitPackageCount: Number(values.get('wait-split-package-count') || 0),
|
||||
waitSplitSequence: Number(values.get('wait-split-sequence') || 1),
|
||||
waitSplitRandomValue: Number(values.get('wait-split-random-value') || values.get('wait-split-sequence') || 1),
|
||||
@@ -826,7 +827,7 @@ export class AcceptanceRun {
|
||||
this.context.phase3LoadingIncrementalPackageCount = variant.packageCountPerSku
|
||||
const profile = this.options.orderProfileMode === 'randomized'
|
||||
? this.randomizedOrderProfile(sequence)
|
||||
: { destinationType: 'FBA', fulfillmentType: 'STANDARD', pickupMethod: 'PICKUP',
|
||||
: { destinationType: 'FBA', fulfillmentType: 'STANDARD', pickupMethod: 'SELF_EXPRESS',
|
||||
taxMode: 'BUY_DECLARATION', containerMode: 'LCL', customsInspection: false }
|
||||
this.context.orderProfile = profile
|
||||
this.context.orderDestinationType = profile.destinationType
|
||||
@@ -1058,15 +1059,30 @@ export class AcceptanceRun {
|
||||
&& /[A-Za-z]/.test(createData.temporaryPassword) && /\d/.test(createData.temporaryPassword),
|
||||
`generated=${typeof createData.temporaryPassword === 'string'}, length=${createData.temporaryPassword?.length || 0}`,
|
||||
ownerProvisioningOptions)
|
||||
this.assert(module, '管理员用户名默认使用联系电话', createResponse,
|
||||
createData.administratorUsername === phone,
|
||||
`matches=${createData.administratorUsername === phone}`,
|
||||
const administratorUsername = String(createData.administratorUsername || '')
|
||||
this.assert(module, '管理员用户名作为独立登录标识返回', createResponse,
|
||||
administratorUsername.length > 0,
|
||||
`present=${administratorUsername.length > 0}`,
|
||||
ownerProvisioningOptions)
|
||||
this.assert(module, '待完善客户的审核字段保持为空', createResponse,
|
||||
customer.unifiedSocialCreditCode == null && customer.approvedAt == null,
|
||||
`creditCode=${customer.unifiedSocialCreditCode ?? 'omitted'}, approvedAt=${customer.approvedAt ?? 'omitted'}`)
|
||||
|
||||
await this.runCustomerDimensionRules(tenantId)
|
||||
const dimensionInitializationPath = `/api/platform/v1/iam/tenants/${tenantId}/dimension-initialization`
|
||||
let dimensionInitializationResponse = null
|
||||
let dimensionInitialization = null
|
||||
for (let attempt = 0; attempt < 30; attempt += 1) {
|
||||
dimensionInitializationResponse = await this.request('GET', dimensionInitializationPath)
|
||||
dimensionInitialization = dimensionInitializationResponse.http === 200
|
||||
&& String(dimensionInitializationResponse.body?.code) === '200'
|
||||
? dimensionInitializationResponse.body?.data : null
|
||||
if (dimensionInitialization?.status === 'READY') break
|
||||
if (attempt < 29) await new Promise((resolve) => setTimeout(resolve, 1_000))
|
||||
}
|
||||
this.assert(module, '客户默认尺寸异步初始化完成', dimensionInitializationResponse,
|
||||
dimensionInitialization?.status === 'READY',
|
||||
`status=${dimensionInitialization?.status || 'missing'}`, ownerProvisioningOptions)
|
||||
if (dimensionInitialization?.status === 'READY') await this.runCustomerDimensionRules(tenantId)
|
||||
|
||||
const listResponse = await this.request('GET', `/api/platform/v1/iam/tenants?page=1&size=20&keyword=${encodeURIComponent(payload.tenantName)}`)
|
||||
const page = this.apiSuccess(module, '查询客户列表', listResponse); const listed = page?.records?.find((item) => String(item.id) === tenantId)
|
||||
@@ -1136,9 +1152,9 @@ export class AcceptanceRun {
|
||||
}
|
||||
const memberResponse = await this.request('GET', `${detailPath}/members`); const members = this.apiSuccess(module, '业务概况查询成员', memberResponse)
|
||||
const owner = members?.find?.((item) => item.memberType === 'OWNER')
|
||||
this.assert(module, '联系电话账号是企业管理员', memberResponse,
|
||||
owner?.username === phone,
|
||||
`ownerFound=${Boolean(owner)}, matches=${owner?.username === phone}`,
|
||||
this.assert(module, '独立用户名账号是企业管理员且联系电话不承担用户名约束', memberResponse,
|
||||
owner?.username === administratorUsername,
|
||||
`ownerFound=${Boolean(owner)}, matches=${owner?.username === administratorUsername}`,
|
||||
ownerProvisioningOptions)
|
||||
const countResponse = await this.request('GET', `/api/platform/v1/orders/first-leg/tenant-counts?tenantIds=${tenantId}`); const counts = this.apiSuccess(module, '业务概况查询运单数量', countResponse); const count = counts?.find?.((item) => String(item.tenantId) === tenantId)
|
||||
this.assert(module, '业务概况返回当前客户运单数', countResponse, count && Number.isFinite(Number(count.orderCount)), `orderCount=${count?.orderCount ?? 'missing'}`)
|
||||
|
||||
@@ -9,7 +9,7 @@ test('同柜不可拆组HTTP验收锁定公开接口与防绕过矩阵', async (
|
||||
'/api/platform/v1/first-leg/coload-groups/by-inbound-code/',
|
||||
'/group-assignments',
|
||||
'/inbound-assignments',
|
||||
'/push-preload',
|
||||
'/plans/by-booking/',
|
||||
'创建同键同载荷精确重放',
|
||||
'创建同键异载荷返回并发冲突',
|
||||
'不同目的仓港仍可创建同柜不可拆组',
|
||||
@@ -31,7 +31,7 @@ test('同柜不可拆组HTTP验收锁定公开接口与防绕过矩阵', async (
|
||||
'短拣完成拒绝后任务、父子树和组锁零漂移',
|
||||
'同柜组足量完成命令可靠受理',
|
||||
'足量完成整组已消费、全部入库完成且不生成余量子单',
|
||||
'未成组普通单推送预装不回归',
|
||||
'未成组普通单自动预装不回归',
|
||||
'未成组普通单仍按既有规则生成唯一余量子单',
|
||||
'拆分余量子单仍可与同仓同渠道订单创建同柜组',
|
||||
'拆分身份不影响当前WAIT_SPLIT片段完整纳组',
|
||||
@@ -42,4 +42,5 @@ test('同柜不可拆组HTTP验收锁定公开接口与防绕过矩阵', async (
|
||||
|
||||
assert.doesNotMatch(source, /跨仓库渠道或目的仓港创建整组被拒绝/)
|
||||
assert.doesNotMatch(source, /已有父子拆分订单创建同柜组被拒绝/)
|
||||
assert.doesNotMatch(source, /push-preload/)
|
||||
})
|
||||
|
||||
@@ -99,10 +99,8 @@ async function createAssignedPushedPlan(context, fixture, groupId, suffix) {
|
||||
evidence(simulationResponse), OPTIONS)
|
||||
const bookingId = id(simulation?.id)
|
||||
if (!bookingId) return null
|
||||
const planResponse = await context.request('POST', `${SMART}/plans`, {
|
||||
bookingId, remark: `${context.marker}-${suffix}`,
|
||||
})
|
||||
let plan = context.apiSuccess(MODULE, `${suffix} 创建组装柜计划`, planResponse,
|
||||
const planResponse = await context.request('GET', `${SMART}/plans/by-booking/${encodeURIComponent(bookingId)}`)
|
||||
let plan = context.apiSuccess(MODULE, `${suffix} 读取模拟柜自动创建的组装柜计划`, planResponse,
|
||||
evidence(planResponse), OPTIONS)
|
||||
const planId = id(plan?.id)
|
||||
if (!planId) return null
|
||||
@@ -112,10 +110,8 @@ async function createAssignedPushedPlan(context, fixture, groupId, suffix) {
|
||||
})
|
||||
plan = context.apiSuccess(MODULE, `${suffix} 整组原子分配`, assignResponse,
|
||||
evidence(assignResponse, `groupId=${groupId}`), OPTIONS)
|
||||
const pushResponse = await context.request('POST', `${SMART}/plans/${encodeURIComponent(planId)}/push-preload`, {
|
||||
expectedVersion: Number(plan?.version),
|
||||
}, undefined, { 'Idempotency-Key': `${context.marker}-${suffix}-push`.slice(0, 128) })
|
||||
const pushed = context.apiSuccess(MODULE, `${suffix} 整组完整推送预装`, pushResponse,
|
||||
const pushResponse = await context.request('GET', `${SMART}/plans/${encodeURIComponent(planId)}`)
|
||||
const pushed = context.apiSuccess(MODULE, `${suffix} 整组分配后自动建立预装关联`, pushResponse,
|
||||
evidence(pushResponse), OPTIONS)
|
||||
return pushed ? { containerBookingId: bookingId, planId, plan: pushed, simulation } : null
|
||||
}
|
||||
@@ -129,10 +125,8 @@ async function createNormalPushedPlan(context, fixture, suffix) {
|
||||
evidence(simulationResponse), OPTIONS)
|
||||
const containerBookingId = id(simulation?.id)
|
||||
if (!containerBookingId) return null
|
||||
const planResponse = await context.request('POST', `${SMART}/plans`, {
|
||||
bookingId: containerBookingId, remark: `${context.marker}-${suffix}`,
|
||||
})
|
||||
let plan = context.apiSuccess(MODULE, `${suffix} 创建普通单装柜计划`, planResponse,
|
||||
const planResponse = await context.request('GET', `${SMART}/plans/by-booking/${encodeURIComponent(containerBookingId)}`)
|
||||
let plan = context.apiSuccess(MODULE, `${suffix} 读取模拟柜自动创建的普通单装柜计划`, planResponse,
|
||||
evidence(planResponse), OPTIONS)
|
||||
const planId = id(plan?.id)
|
||||
if (!planId) return null
|
||||
@@ -149,10 +143,8 @@ async function createNormalPushedPlan(context, fixture, suffix) {
|
||||
context.assert(MODULE, `${suffix} 普通单维持既有部分分配语义`, assignResponse,
|
||||
assignedTotal === assignedCount && assignedCount < Number(fixture.packages),
|
||||
`assigned=${assignedTotal}, source=${fixture.packages}`, OPTIONS)
|
||||
const pushResponse = await context.request('POST', `${SMART}/plans/${encodeURIComponent(planId)}/push-preload`, {
|
||||
expectedVersion: Number(plan?.version),
|
||||
}, undefined, { 'Idempotency-Key': `${context.marker}-${suffix}-push`.slice(0, 128) })
|
||||
const pushed = context.apiSuccess(MODULE, `${suffix} 未成组普通单推送预装不回归`, pushResponse,
|
||||
const pushResponse = await context.request('GET', `${SMART}/plans/${encodeURIComponent(planId)}`)
|
||||
const pushed = context.apiSuccess(MODULE, `${suffix} 未成组普通单自动预装不回归`, pushResponse,
|
||||
evidence(pushResponse), OPTIONS)
|
||||
return pushed ? { containerBookingId, planId, plan: pushed, simulation, assignedCount } : null
|
||||
}
|
||||
@@ -344,7 +336,7 @@ async function createRouteVariantFixture(context, base, variant) {
|
||||
context.marker = `${originalMarker}-${variant === 'DESTINATION' ? 'DEST' : 'ROUTE'}-${attempt}`
|
||||
context.context.orderProfile = {
|
||||
destinationType: variant === 'DESTINATION' && attempt >= 3 ? 'OVERSEAS' : 'FBA', fulfillmentType: 'STANDARD',
|
||||
pickupMethod: 'PICKUP', taxMode: 'BUY_DECLARATION', containerMode: 'LCL', customsInspection: false,
|
||||
pickupMethod: 'SELF_EXPRESS', taxMode: 'BUY_DECLARATION', containerMode: 'LCL', customsInspection: false,
|
||||
}
|
||||
context.context.orderDestinationType = context.context.orderProfile.destinationType
|
||||
context.context.orderFulfillmentType = 'STANDARD'
|
||||
@@ -510,10 +502,8 @@ export async function run(context) {
|
||||
evidence(simulationResponse), OPTIONS)
|
||||
let bookingId = id(simulation?.id)
|
||||
if (!bookingId) return
|
||||
const planResponse = await context.request('POST', '/api/platform/v1/first-leg/smart-loading/plans', {
|
||||
bookingId, remark: `${context.marker} 同柜不可拆组验收`,
|
||||
})
|
||||
let plan = context.apiSuccess(MODULE, '创建容量拒绝专用空计划', planResponse,
|
||||
const planResponse = await context.request('GET', `${SMART}/plans/by-booking/${encodeURIComponent(bookingId)}`)
|
||||
let plan = context.apiSuccess(MODULE, '读取容量拒绝专用自动空计划', planResponse,
|
||||
evidence(planResponse, `bookingId=${bookingId}`), OPTIONS)
|
||||
let planId = id(plan?.id)
|
||||
if (!planId) return
|
||||
@@ -580,10 +570,8 @@ export async function run(context) {
|
||||
recommendSimulationResponse, evidence(recommendSimulationResponse), OPTIONS)
|
||||
const recommendBookingId = id(recommendSimulation?.id)
|
||||
if (!recommendBookingId) return
|
||||
const recommendPlanResponse = await context.request('POST', `${SMART}/plans`, {
|
||||
bookingId: recommendBookingId, remark: `${context.marker} 智能推荐整组全取`,
|
||||
})
|
||||
let recommendPlan = context.apiSuccess(MODULE, '创建智能推荐整组成功专用计划', recommendPlanResponse,
|
||||
const recommendPlanResponse = await context.request('GET', `${SMART}/plans/by-booking/${encodeURIComponent(recommendBookingId)}`)
|
||||
let recommendPlan = context.apiSuccess(MODULE, '读取智能推荐整组成功专用自动计划', recommendPlanResponse,
|
||||
evidence(recommendPlanResponse), OPTIONS)
|
||||
const recommendPlanId = id(recommendPlan?.id)
|
||||
if (!recommendPlanId) return
|
||||
@@ -628,10 +616,8 @@ export async function run(context) {
|
||||
evidence(workingSimulationResponse), OPTIONS)
|
||||
bookingId = id(workingSimulation?.id)
|
||||
if (!bookingId) return
|
||||
const workingPlanResponse = await context.request('POST', `${SMART}/plans`, {
|
||||
bookingId, remark: `${context.marker} 同柜不可拆组PDA主链`,
|
||||
})
|
||||
plan = context.apiSuccess(MODULE, '创建PDA主链同柜装柜计划', workingPlanResponse,
|
||||
const workingPlanResponse = await context.request('GET', `${SMART}/plans/by-booking/${encodeURIComponent(bookingId)}`)
|
||||
plan = context.apiSuccess(MODULE, '读取PDA主链自动创建的同柜装柜计划', workingPlanResponse,
|
||||
evidence(workingPlanResponse, `bookingId=${bookingId}`), OPTIONS)
|
||||
planId = id(plan?.id)
|
||||
if (!planId) return
|
||||
@@ -718,12 +704,8 @@ export async function run(context) {
|
||||
evidence(manualGroupResponse), OPTIONS)
|
||||
if (!plan) return
|
||||
|
||||
const pushKey = `${context.marker}-coload-push`.slice(0, 128)
|
||||
const pushResponse = await context.request('POST',
|
||||
`/api/platform/v1/first-leg/smart-loading/plans/${encodeURIComponent(planId)}/push-preload`, {
|
||||
expectedVersion: Number(plan.version),
|
||||
}, undefined, { 'Idempotency-Key': pushKey })
|
||||
const pushed = context.apiSuccess(MODULE, '整组完整时推送预装成功', pushResponse,
|
||||
const pushResponse = await context.request('GET', `${SMART}/plans/${encodeURIComponent(planId)}`)
|
||||
const pushed = context.apiSuccess(MODULE, '整组完整时自动预装关联可读', pushResponse,
|
||||
evidence(pushResponse), OPTIONS)
|
||||
const pushedTotals = new Map()
|
||||
for (const item of pushed?.items || []) pushedTotals.set(id(item?.inboundId),
|
||||
@@ -956,10 +938,9 @@ export async function run(context) {
|
||||
const uiSimulation = context.apiSuccess(MODULE, '为Admin页面保留可编辑智能装柜柜次', uiSimulationResponse,
|
||||
evidence(uiSimulationResponse), OPTIONS)
|
||||
const uiBookingId = id(uiSimulation?.id)
|
||||
const uiPlanResponse = uiBookingId ? await context.request('POST', `${SMART}/plans`, {
|
||||
bookingId: uiBookingId, remark: `${context.marker} Admin整组候选人工验收保留`,
|
||||
}) : null
|
||||
const uiPlan = uiPlanResponse ? context.apiSuccess(MODULE, '为Admin页面保留未分配空计划', uiPlanResponse,
|
||||
const uiPlanResponse = uiBookingId
|
||||
? await context.request('GET', `${SMART}/plans/by-booking/${encodeURIComponent(uiBookingId)}`) : null
|
||||
const uiPlan = uiPlanResponse ? context.apiSuccess(MODULE, '为Admin页面保留自动创建的未分配空计划', uiPlanResponse,
|
||||
evidence(uiPlanResponse, `bookingId=${uiBookingId}`), OPTIONS) : null
|
||||
const uiMembers = memberFacts(uiGroup)
|
||||
context.assert(MODULE, '页面验收保留组仍为ACTIVE且未锁定', uiGroupResponse,
|
||||
|
||||
@@ -7,7 +7,7 @@ const source = readFileSync(new URL('./manual-state-loading-pda.mjs', import.met
|
||||
test('retains all clickable container, loading-list and PDA workflow states through public APIs', () => {
|
||||
for (const status of ['WAIT_LOADING', 'EDITING', 'LOADING', 'COMPLETED',
|
||||
'UNASSIGNED', 'IN_PROGRESS', 'AWAITING_REVIEW']) assert.match(source, new RegExp(`['"]${status}['"]`))
|
||||
for (const endpoint of ['/ocean-bookings', '/smart-loading', '/push-preload', '/inventory-snapshot',
|
||||
for (const endpoint of ['/ocean-bookings', '/smart-loading', '/plans/by-booking/', '/inventory-snapshot',
|
||||
'/batch', '/complete', '/loading-plans', '/loading-lists']) assert.match(source, new RegExp(endpoint))
|
||||
assert.match(source, /requiredStatuses/)
|
||||
assert.match(source, /detailPath/)
|
||||
@@ -18,7 +18,7 @@ test('retains all clickable container, loading-list and PDA workflow states thro
|
||||
assert.match(source, /\.\/inbound-measurement\.mjs/)
|
||||
assert.match(source, /context\.request\('POST', CONTAINERS/)
|
||||
assert.match(source, /summary\?\.processStatus === 'WAIT_SPLIT'/)
|
||||
const pushIndex = source.indexOf('`${SMART}/plans/${plan.id}/push-preload`')
|
||||
const pushIndex = source.indexOf('`${SMART}/plans/${plan.id}`')
|
||||
const transportIndex = source.indexOf('ocean-booking-link')
|
||||
assert.ok(transportIndex >= 0 && pushIndex > transportIndex)
|
||||
const unconfirmedTaskIndex = source.indexOf('`${PDA}/tasks?loadingPlanId=${planId}&warehouseId=${source.warehouseId}`', pushIndex)
|
||||
@@ -26,6 +26,7 @@ test('retains all clickable container, loading-list and PDA workflow states thro
|
||||
const canonicalTaskIndex = source.indexOf('`${PDA}/tasks?loadingPlanId=${planId}&warehouseId=${source.warehouseId}`', unconfirmedTaskIndex + 1)
|
||||
assert.ok(unconfirmedTaskIndex > pushIndex && confirmIndex > unconfirmedTaskIndex
|
||||
&& canonicalTaskIndex > confirmIndex)
|
||||
assert.doesNotMatch(source, /push-preload/)
|
||||
assert.match(source, /计划确认前不生成 PDA 任务/)
|
||||
assert.match(source, /summary\?\.readiness\?\.canConfirm === true/)
|
||||
assert.match(source, /Object\.freeze\(\{ expectedVersion: confirmableVersion \}\)/)
|
||||
|
||||
@@ -193,18 +193,15 @@ async function createPlanTask(context, label) {
|
||||
: null
|
||||
if (!candidate?.inboundDetailId) throw new Error(`${label} 独立入库单未进入同渠道排柜候选`)
|
||||
|
||||
const planResponse = await context.request('POST', `${SMART}/plans`,
|
||||
{ bookingId: containerId, remark: `${context.marker}-${label}` })
|
||||
let plan = context.apiSuccess(MODULE, `${label} 创建智能排柜计划`, planResponse, '', OPTIONS)
|
||||
const planResponse = await context.request('GET', `${SMART}/plans/by-booking/${containerId}`)
|
||||
let plan = context.apiSuccess(MODULE, `${label} 读取模拟柜自动创建的智能排柜计划`, planResponse, '', OPTIONS)
|
||||
const assignResponse = await context.request('POST', `${SMART}/plans/${plan.id}/assignments`, {
|
||||
inboundId: source.inboundId, inboundDetailId: id(candidate.inboundDetailId), packageCount: 1,
|
||||
expectedVersion: Number(plan.version), operationId: operationId(context, `${label}-assign`),
|
||||
})
|
||||
plan = context.apiSuccess(MODULE, `${label} 分配独立候选货物`, assignResponse, '', OPTIONS)
|
||||
const containerNo = iso6346ContainerNumber(`${context.marker}-manual-${label}`)
|
||||
const pushResponse = await post(context, `${SMART}/plans/${plan.id}/push-preload`,
|
||||
{ expectedVersion: Number(plan.version) }, `${label}-push`)
|
||||
plan = context.apiSuccess(MODULE, `${label} 补真实柜号后推送预装`, pushResponse, '', OPTIONS)
|
||||
const pushResponse = await context.request('GET', `${SMART}/plans/${plan.id}`)
|
||||
plan = context.apiSuccess(MODULE, `${label} 分配后自动建立预装关联`, pushResponse, '', OPTIONS)
|
||||
const planId = id(plan?.id)
|
||||
const unconfirmedTaskResponse = await context.request('GET',
|
||||
`${PDA}/tasks?loadingPlanId=${planId}&warehouseId=${source.warehouseId}`)
|
||||
|
||||
@@ -23,7 +23,7 @@ test('each remainder uses a simulation linked to a released booking requirement'
|
||||
assert.match(source, /oceanBooking\?\.status === 'RELEASED' && releasedAllocationMatches/)
|
||||
assert.match(source, /id\(item\?\.containerBookingId\) === containerId/)
|
||||
assert.match(source, /candidates\?bookingId=\$\{encodeURIComponent\(containerId\)\}&warehouseId=\$\{encodeURIComponent\(warehouseId\)\}/)
|
||||
assert.match(source, /`\$\{SMART\}\/plans`, \{ bookingId: containerId/)
|
||||
assert.match(source, /`\$\{SMART\}\/plans\/by-booking\/\$\{containerId\}`/)
|
||||
assert.doesNotMatch(source, /candidates\?warehouseId=/)
|
||||
})
|
||||
|
||||
@@ -37,7 +37,7 @@ test('release freezes and detail replays the same complete transport snapshot',
|
||||
})
|
||||
|
||||
test('PDA opens only after linking a released requirement and uses stable plan identity', () => {
|
||||
const pushIndex = source.indexOf("`${SMART}/plans/${planId}/push-preload`")
|
||||
const pushIndex = source.indexOf("`${SMART}/plans/${planId}`")
|
||||
const linkIndex = source.indexOf("`${CONTAINERS}/${containerId}/ocean-booking-link`")
|
||||
const releaseIndex = source.indexOf("`/api/platform/v1/ocean-bookings/${oceanBookingId}/release`")
|
||||
const confirmIndex = source.indexOf("`/api/platform/v1/first-leg/loading-plans/${encodeURIComponent(planId)}/confirm`")
|
||||
@@ -60,6 +60,7 @@ test('PDA opens only after linking a released requirement and uses stable plan i
|
||||
assert.match(source, /id\(task\?\.loadingPlanId\) === planId/)
|
||||
assert.match(source, /id\(task\?\.containerBookingId\) === containerId/)
|
||||
assert.doesNotMatch(source, /\$\{PDA\}\/tasks\?containerNo=/)
|
||||
assert.doesNotMatch(source, /push-preload/)
|
||||
})
|
||||
|
||||
test('each remainder settles only through inventory snapshot, atomic batch and explicit complete', () => {
|
||||
|
||||
@@ -230,8 +230,8 @@ async function loadOneFragment(context, state) {
|
||||
`orderId=${sourceOrderId}, available=${candidate?.availablePackageCount ?? 'missing'}`, OPTIONS)
|
||||
if (!candidate?.inboundId || !candidate?.inboundDetailId) return null
|
||||
|
||||
const createPlan = await request(context, 'POST', `${SMART}/plans`, { bookingId: containerId, remark: context.marker })
|
||||
const plan = context.apiSuccess(MODULE, `为 ${sourceOrderNo} 创建装柜计划`, createPlan, '', OPTIONS)
|
||||
const createPlan = await request(context, 'GET', `${SMART}/plans/by-booking/${containerId}`)
|
||||
const plan = context.apiSuccess(MODULE, `读取 ${sourceOrderNo} 模拟柜自动创建的装柜计划`, createPlan, '', OPTIONS)
|
||||
const planId = id(plan?.id)
|
||||
if (!planId) return null
|
||||
context.createdResources.phase3OrderSplitting.retainedAuditRecordIds.push(planId)
|
||||
@@ -289,11 +289,11 @@ async function loadOneFragment(context, state) {
|
||||
`status=${bookingDetail?.oceanBooking?.status || 'missing'}, containerBookingId=${containerId}`, OPTIONS)
|
||||
if (bookingDetail?.oceanBooking?.status !== 'RELEASED' || !releasedAllocationMatches) return null
|
||||
|
||||
const push = await request(context, 'POST', `${SMART}/plans/${planId}/push-preload`,
|
||||
{ expectedVersion: Number(assigned.version) }, { 'Idempotency-Key': `${operationBase}-push` })
|
||||
const pushed = context.apiSuccess(MODULE, `推送 ${sourceOrderNo} 的预装计划`, push, '', OPTIONS)
|
||||
context.assert(MODULE, `${sourceOrderNo} 补真实柜号后计划保持 EDITING`, push,
|
||||
pushed?.status === 'EDITING', `status=${pushed?.status || 'missing'}`, OPTIONS)
|
||||
const push = await request(context, 'GET', `${SMART}/plans/${planId}`)
|
||||
const pushed = context.apiSuccess(MODULE, `读取 ${sourceOrderNo} 自动关联的预装计划`, push, '', OPTIONS)
|
||||
context.assert(MODULE, `${sourceOrderNo} 补真实柜号后自动预装计划保持 EDITING`, push,
|
||||
pushed?.status === 'EDITING' && Number(pushed?.version) === Number(assigned.version),
|
||||
`status=${pushed?.status || 'missing'}, version=${pushed?.version ?? 'missing'}`, OPTIONS)
|
||||
if (pushed?.status !== 'EDITING') return null
|
||||
|
||||
const unconfirmedTaskResponse = await context.request('GET',
|
||||
|
||||
Reference in New Issue
Block a user