fix(dropship): generate pallet numbers atomically and extend full regressions

This commit is contained in:
2026-09-09 12:19:16 +08:00
100 changed files with 2889 additions and 234 deletions
@@ -22,7 +22,18 @@ function failure(response) {
|| (response?.http === 200 && codeOf(response) !== '200')
}
function records(page) { return Array.isArray(page?.records) ? page.records : [] }
function containerRecord(value) { return value?.container || value }
function containerRecord(value) { return value?.container }
export function containerWorkbenchGaps(value) {
return [
!value?.container?.id && 'container.id',
!value?.container?.cabinetNo && 'container.cabinetNo',
!Number.isInteger(value?.container?.version) && 'container.version',
!value?.workbenchStage && 'workbenchStage',
(!value?.statusSummary || typeof value.statusSummary !== 'object') && 'statusSummary',
!Array.isArray(value?.allowedActions) && 'allowedActions',
].filter(Boolean)
}
async function waitForCompletedTask(context, taskId, warehouseId, attempts = 45) {
let response = null
@@ -262,6 +273,18 @@ export async function run(context) {
const containerDetailResponse = await context.request('GET', `${DOMESTIC_CONTAINERS}/${containerId}`)
const containerDetail = containerRecord(context.apiSuccess(MODULE, '回查货柜详情', containerDetailResponse, '', OPTIONS))
const workbenchGaps = containerWorkbenchGaps(containerDetailResponse.body?.data)
context.assert(MODULE, '货柜详情返回正式工作台 DTO 而非旧扁平实体', containerDetailResponse,
workbenchGaps.length === 0, `missing=${workbenchGaps.join('|') || 'none'}`, OPTIONS)
const pageResponse = await context.request('GET',
`${DOMESTIC_CONTAINERS}?page=1&size=20&scope=ACTIVE&status=${encodeURIComponent(containerDetail?.planStatus || '')}&keyword=${encodeURIComponent(containerDetail?.cabinetNo || '')}`)
const page = context.apiSuccess(MODULE, '按货柜页面筛选参数查询本轮模拟柜', pageResponse, '', OPTIONS)
const ownRows = records(page).filter((item) => id(item?.container?.id) === containerId)
context.assert(MODULE, '货柜页面列表返回唯一模拟柜和工作台动作状态', pageResponse,
ownRows.length === 1 && records(page).every((item) => containerWorkbenchGaps(item).length === 0)
&& ownRows[0]?.container?.cabinetNo === containerDetail?.cabinetNo
&& ownRows[0]?.container?.planStatus === containerDetail?.planStatus,
`matches=${ownRows.length}, rows=${records(page).length}`, OPTIONS)
context.assert(MODULE, '货柜详情保留候选货物路线约束', containerDetailResponse,
(!containerDetail?.destinationWarehouseCode || !candidate.destinationWarehouseCode
|| containerDetail.destinationWarehouseCode === candidate.destinationWarehouseCode)
@@ -475,7 +498,7 @@ export async function run(context) {
const activeContainersResponse = await context.request('GET',
`${DOMESTIC_CONTAINERS}?page=1&size=50&scope=ACTIVE&keyword=${encodeURIComponent(realContainerNo)}`)
const activeContainers = context.apiSuccess(MODULE, '关联后按真实柜号回查正常货柜列表', activeContainersResponse, '', OPTIONS)
const activeRealRows = records(activeContainers).map(containerRecord).filter((item) => item.containerNo === realContainerNo)
const activeRealRows = records(activeContainers).map(containerRecord).filter((item) => item?.containerNo === realContainerNo)
context.assert(MODULE, '关联后列表仅保留模拟柜原地补全的一条 ACTIVE 操作身份', activeContainersResponse,
activeRealRows.length === 1 && id(activeRealRows[0]?.id) === containerId,
`activeIds=${activeRealRows.map((item) => id(item?.id)).join('|') || 'none'}`, OPTIONS)
@@ -592,7 +615,7 @@ export async function run(context) {
if (!taskId || !pickItem?.id) return
const releasedContainerResponse = await context.request('GET', `${DOMESTIC_CONTAINERS}/${containerId}`)
const releasedContainer = context.apiSuccess(MODULE, '任务生成后回查货柜运输版本', releasedContainerResponse, '', OPTIONS)
const releasedContainer = containerRecord(context.apiSuccess(MODULE, '任务生成后回查货柜运输版本', releasedContainerResponse, '', OPTIONS))
const stableIdentity = {
taskId, loadingPlanId: id(task.loadingPlanId), containerBookingId: id(task.containerBookingId),