feat(appointments): unify pre-inbound planning and confirmed FBA bookings

This commit is contained in:
2026-10-10 10:38:06 +08:00
parent 24f5ccf7ff
commit c4c1bddeec
54 changed files with 1623 additions and 744 deletions
@@ -89,22 +89,23 @@ async function inboundAdminLifecycle(context) {
`palletId=${id(supplement?.id) || 'missing'}, status=${supplement?.assignmentStatus || 'missing'}`, OPTIONS)
const suffix = String(context.marker).replace(/[^A-Za-z0-9]/g, '').slice(-18).toUpperCase()
const appointmentNo = `FBA-${suffix}`.slice(0, 64)
const now = Date.now()
const appointmentBody = {
lineIds: fbaLines.map((line) => id(line.id)), appointmentNo,
appointmentAt: new Date(now + 24 * 60 * 60_000).toISOString().slice(0, 19),
expectedLoadingAt: new Date(now + 26 * 60 * 60_000).toISOString().slice(0, 19),
appointmentStatus: 'PENDING', appointmentRemark: context.marker,
originWarehouseId: id(plan.overseasWarehouseId), fbaWarehouseCode: sample.fbaWarehouseCode,
lineIds: fbaLines.map((line) => id(line.id)), idempotencyKey: `fba-${suffix}`,
details: { plannedDate: new Date(now + 24 * 60 * 60_000).toISOString().slice(0, 10),
appointmentStatus: 'PENDING', appointmentRemark: context.marker },
}
const appointment = await request(context, 'POST', '批量创建FBA预约', `${PLAN_BASE}/fba-appointments/batch`, appointmentBody)
const appointmentNo = appointment.appointmentNo
const expectedSources = new Set(fbaLines.map(line => id(line.orderId))).size
const appointmentReplay = await request(context, 'POST', 'FBA预约同单号同载荷重放', `${PLAN_BASE}/fba-appointments/batch`, appointmentBody)
context.assert(MODULE, 'FBA预约重放返回同一聚合且明细一致', null,
id(appointmentReplay?.id) === id(appointment?.id)
&& appointmentReplay?.items?.length === fbaLines.length,
&& appointmentReplay?.items?.length === expectedSources,
`appointmentId=${id(appointment?.id) || 'missing'}, items=${appointmentReplay?.items?.length ?? 'missing'}`, OPTIONS)
const appointmentConflict = await context.request('POST', `${PLAN_BASE}/fba-appointments/batch`, {
...appointmentBody, appointmentRemark: `${context.marker}-different`,
...appointmentBody, details: { ...appointmentBody.details, appointmentRemark: `${context.marker}-different` },
})
context.addStep(MODULE, 'FBA预约同单号异载荷返回A0409', appointmentConflict,
conflict(appointmentConflict), trace(appointmentConflict), OPTIONS)
@@ -112,14 +113,12 @@ async function inboundAdminLifecycle(context) {
`${PLAN_BASE}/fba-appointments/${encodeURIComponent(appointmentNo)}`)
context.assert(MODULE, 'FBA预约详情冻结仓码和所选明细', null,
detail?.appointmentNo === appointmentNo && detail?.fbaWarehouseCode === sample.fbaWarehouseCode
&& detail?.items?.length === fbaLines.length,
&& detail?.items?.length === expectedSources,
`appointmentNo=${detail?.appointmentNo || 'missing'}, warehouse=${detail?.fbaWarehouseCode || 'missing'}`, OPTIONS)
const cancelled = await request(context, 'PUT', '取消本轮FBA预约收口',
`${PLAN_BASE}/fba-appointments/${encodeURIComponent(appointmentNo)}`, {
appointmentAt: appointmentBody.appointmentAt,
expectedLoadingAt: appointmentBody.expectedLoadingAt,
version: detail.version, appointmentEndAt: detail.appointmentEndAt,
appointmentStatus: 'CANCELLED', appointmentRemark: `${context.marker}-cancelled`,
idempotencyKey: `fba-cancel-${suffix}`, version: detail.version,
details: { appointmentStatus: 'CANCELLED', appointmentRemark: `${context.marker}-cancelled` },
})
context.assert(MODULE, 'FBA预约最终为CANCELLED', null,
cancelled?.appointmentStatus === 'CANCELLED', `status=${cancelled?.appointmentStatus || 'missing'}`, OPTIONS)