优化
This commit is contained in:
@@ -116,25 +116,52 @@ function snapshotMatches(tree, original, loaded, remaining, activeSuffix) {
|
||||
&& activeMatches && quantityConserved(tree)
|
||||
}
|
||||
|
||||
function containerPayload(marker, sequence, warehouseId, candidate) {
|
||||
function bookingPayload(marker, sequence, source) {
|
||||
const suffix = `${marker}-${sequence}`.replace(/[^A-Za-z0-9]/g, '').slice(-18)
|
||||
return {
|
||||
containerNo: `SPLIT-${suffix}`.slice(0, 64), cabinetNo: `SI-${suffix}`.slice(0, 64),
|
||||
warehouseId, warehouseName: null, billOfLadingNo: `BL-${suffix}`.slice(0, 64),
|
||||
vesselName: `SPLIT-VESSEL-${suffix}`.slice(0, 128), voyageNo: `V-${suffix}`.slice(0, 64),
|
||||
containerType: '40HQ', shippingCompanyId: null, shippingCompanyName: `SPLIT-SHIPPING-${suffix}`.slice(0, 128),
|
||||
customerId: source.tenantId, customerName: source.customerName,
|
||||
channelCode: source.channelCode, channelName: source.channelName,
|
||||
warehouseId: source.warehouseId, warehouseName: source.warehouseName,
|
||||
shippingCompanyId: null, shippingCompanyName: `SPLIT-SHIPPING-${suffix}`.slice(0, 128),
|
||||
bookingAgentId: null, bookingAgentName: `SPLIT-AGENT-${suffix}`.slice(0, 128),
|
||||
departurePortCode: 'CNSZX', departurePortName: '深圳', destinationPortCode: 'USLAX', destinationPortName: '洛杉矶',
|
||||
destinationWarehouseCode: candidate.destinationWarehouseCode || null,
|
||||
destinationWarehouseName: candidate.destinationWarehouseName || null,
|
||||
capacityCbm: 100, maxWeightKg: 100000, terminalTruckingCompany: `SPLIT-TRUCK-${suffix}`.slice(0, 128),
|
||||
loadingAt: '2026-09-10T08:00:00', estimatedSailingAt: '2026-09-11T08:00:00',
|
||||
estimatedPortArrivalAt: '2026-09-28T08:00:00', estimatedWarehouseArrivalAt: '2026-09-29T08:00:00',
|
||||
placeOfDelivery: 'LAX', serviceTerm: 'CY/CY', freightTerm: 'PREPAID', remark: marker,
|
||||
parties: [{ partyType: 'SHIPPER', partyName: `SPLIT-SHIPPER-${suffix}` },
|
||||
{ partyType: 'CONSIGNEE', partyName: `SPLIT-CONSIGNEE-${suffix}` },
|
||||
{ partyType: 'NOTIFY_PARTY', partyName: `SPLIT-NOTIFY-${suffix}` }],
|
||||
containerRequirements: [{ containerType: '40HQ', containerKind: 'FCL', capacityCbm: 100,
|
||||
maxWeightKg: 100000, quantity: 1 }],
|
||||
}
|
||||
}
|
||||
|
||||
async function loadOneFragment(context, state) {
|
||||
const { tenantId, rootOrderId, sourceOrderId, sourceOrderNo, warehouseId, sourcePackageCount, sequence } = state
|
||||
const candidatesResponse = await context.request('GET', `${SMART}/candidates?warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const operationBase = `${context.marker}-chain-${sequence}`.slice(0, 100)
|
||||
const bookingCreate = await request(context, 'POST', '/api/platform/v1/ocean-bookings', {
|
||||
expectedVersion: 0, data: bookingPayload(context.marker, sequence, state),
|
||||
}, { 'Idempotency-Key': `${operationBase}-booking-create` })
|
||||
const bookingCreated = context.apiSuccess(MODULE, `为 ${sourceOrderNo} 创建渠道仓库一致的订舱`, bookingCreate, '', OPTIONS)
|
||||
const oceanBookingId = id(bookingCreated?.oceanBooking?.id)
|
||||
if (!oceanBookingId) return null
|
||||
context.createdResources.phase3OrderSplitting.retainedAuditRecordIds.push(oceanBookingId)
|
||||
|
||||
const bookingSubmit = await request(context, 'POST', `/api/platform/v1/ocean-bookings/${oceanBookingId}/submit`, {
|
||||
expectedVersion: Number(bookingCreated?.oceanBooking?.version), reason: context.marker,
|
||||
}, { 'Idempotency-Key': `${operationBase}-booking-submit` })
|
||||
const bookingSubmitted = context.apiSuccess(MODULE, `提交 ${sourceOrderNo} 的订舱`, bookingSubmit, '', OPTIONS)
|
||||
const bookingConfirm = await request(context, 'POST', `/api/platform/v1/ocean-bookings/${oceanBookingId}/confirm`, {
|
||||
expectedVersion: Number(bookingSubmitted?.oceanBooking?.version), reason: context.marker,
|
||||
}, { 'Idempotency-Key': `${operationBase}-booking-confirm` })
|
||||
const bookingConfirmed = context.apiSuccess(MODULE, `确认 ${sourceOrderNo} 的订舱并自动分配柜次`, bookingConfirm, '', OPTIONS)
|
||||
const containerId = id(bookingConfirmed?.containerAllocations?.[0]?.containerBookingId)
|
||||
context.assert(MODULE, `${sourceOrderNo} 订舱确认后取得稳定柜次`, bookingConfirm,
|
||||
isPositiveId(containerId) && id(bookingConfirmed?.oceanBooking?.id) === oceanBookingId,
|
||||
`oceanBookingId=${oceanBookingId}, containerBookingId=${containerId || 'missing'}`, OPTIONS)
|
||||
if (!containerId) return null
|
||||
context.createdResources.phase3OrderSplitting.retainedAuditRecordIds.push(containerId)
|
||||
|
||||
const candidatesPath = `${SMART}/candidates?bookingId=${encodeURIComponent(containerId)}&warehouseId=${encodeURIComponent(warehouseId)}`
|
||||
const candidatesResponse = await context.request('GET', candidatesPath)
|
||||
const candidates = context.apiSuccess(MODULE, `查询余量 ${sourceOrderNo} 的真实装柜候选`, candidatesResponse, '', OPTIONS)
|
||||
const candidate = Array.isArray(candidates)
|
||||
? candidates.find((row) => id(row.orderId) === sourceOrderId && id(row.accountId) === tenantId)
|
||||
@@ -145,20 +172,12 @@ async function loadOneFragment(context, state) {
|
||||
`orderId=${sourceOrderId}, available=${candidate?.availablePackageCount ?? 'missing'}`, OPTIONS)
|
||||
if (!candidate?.inboundId || !candidate?.inboundDetailId) return null
|
||||
|
||||
const createContainer = await request(context, 'POST', CONTAINERS,
|
||||
containerPayload(context.marker, sequence, warehouseId, candidate))
|
||||
const container = context.apiSuccess(MODULE, `为 ${sourceOrderNo} 创建隔离柜次`, createContainer, '', OPTIONS)
|
||||
const containerId = id(container?.id)
|
||||
if (!containerId) return null
|
||||
context.createdResources.phase3OrderSplitting.retainedAuditRecordIds.push(containerId)
|
||||
|
||||
const createPlan = await request(context, 'POST', `${SMART}/plans`, { bookingId: containerId, remark: context.marker })
|
||||
const plan = context.apiSuccess(MODULE, `为 ${sourceOrderNo} 创建装柜计划`, createPlan, '', OPTIONS)
|
||||
const planId = id(plan?.id)
|
||||
if (!planId) return null
|
||||
context.createdResources.phase3OrderSplitting.retainedAuditRecordIds.push(planId)
|
||||
|
||||
const operationBase = `${context.marker}-chain-${sequence}`.slice(0, 100)
|
||||
const assignPayload = {
|
||||
inboundId: id(candidate.inboundId), inboundDetailId: id(candidate.inboundDetailId), packageCount: 1,
|
||||
expectedVersion: Number(plan.version), operationId: `${operationBase}-assign`,
|
||||
@@ -180,16 +199,31 @@ async function loadOneFragment(context, state) {
|
||||
|
||||
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} 的真实 PDA 任务`, push, '', OPTIONS)
|
||||
if (pushed?.status !== 'LOADING') return null
|
||||
const pushed = context.apiSuccess(MODULE, `推送 ${sourceOrderNo} 的预装计划`, push, '', OPTIONS)
|
||||
context.assert(MODULE, `${sourceOrderNo} 未补真实柜号时计划保持 EDITING`, push,
|
||||
pushed?.status === 'EDITING', `status=${pushed?.status || 'missing'}`, OPTIONS)
|
||||
if (pushed?.status !== 'EDITING') return null
|
||||
|
||||
const containerDetailResponse = await context.request('GET', `${CONTAINERS}/${encodeURIComponent(containerId)}`)
|
||||
const containerDetail = context.apiSuccess(MODULE, `回查 ${sourceOrderNo} 的自动柜次`, containerDetailResponse, '', OPTIONS)
|
||||
const realContainerNo = `SPLIT-${operationBase.replace(/[^A-Za-z0-9]/g, '').slice(-18)}`.slice(0, 64)
|
||||
const transportResponse = await request(context, 'PATCH', `${CONTAINERS}/${encodeURIComponent(containerId)}/transport`, {
|
||||
containerNo: realContainerNo, voyageNo: `V-${sequence}`,
|
||||
version: Number(containerDetail?.version), reason: context.marker,
|
||||
})
|
||||
const transported = context.apiSuccess(MODULE, `为 ${sourceOrderNo} 补充真实柜号并开放 PDA`, transportResponse, '', OPTIONS)
|
||||
context.assert(MODULE, `${sourceOrderNo} 真实柜号已绑定到稳定柜次`, transportResponse,
|
||||
transported?.containerNo === realContainerNo,
|
||||
`containerBookingId=${containerId}, containerNo=${transported?.containerNo || 'missing'}`, OPTIONS)
|
||||
|
||||
const taskResponse = await context.request('GET',
|
||||
`${PDA}/tasks?containerNo=${encodeURIComponent(container.containerNo)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const task = context.apiSuccess(MODULE, `读取 ${sourceOrderNo} 的 PDA 任务`, taskResponse, '', OPTIONS)
|
||||
const taskId = id(task?.id)
|
||||
const pickItem = task?.items?.find?.((row) => id(row.loadingPlanItemId) === id(planItem.id))
|
||||
context.assert(MODULE, `余量 ${sourceOrderNo} 不继承已拣数量`, taskResponse,
|
||||
Boolean(taskId) && Boolean(pickItem?.id) && Number(pickItem?.plannedPackageCount) === 1
|
||||
Boolean(taskId) && id(task?.loadingPlanId) === planId && id(task?.containerBookingId) === containerId
|
||||
&& task?.currentContainerNo === realContainerNo && Boolean(pickItem?.id) && Number(pickItem?.plannedPackageCount) === 1
|
||||
&& Number(pickItem?.pickedPackageCount) === 0,
|
||||
`taskId=${taskId || 'missing'}, picked=${pickItem?.pickedPackageCount ?? 'missing'}, planned=${pickItem?.plannedPackageCount ?? 'missing'}`, OPTIONS)
|
||||
if (!taskId || !pickItem?.id) return null
|
||||
@@ -237,13 +271,13 @@ async function loadOneFragment(context, state) {
|
||||
|
||||
const treeResponse = await context.request('GET', treePath(rootOrderId, tenantId))
|
||||
const tree = context.apiSuccess(MODULE, `回查 ${sourceOrderNo} 拆分后的根聚合`, treeResponse, '', OPTIONS)
|
||||
const candidatesAfter = await context.request('GET', `${SMART}/candidates?warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const candidatesAfter = await context.request('GET', candidatesPath)
|
||||
const candidateRowsAfter = context.apiSuccess(MODULE, `回查 ${sourceOrderNo} 不可重复消费`, candidatesAfter, '', OPTIONS)
|
||||
context.assert(MODULE, `来源 ${sourceOrderNo} 同时最多成功拆分一次`, candidatesAfter,
|
||||
Array.isArray(candidateRowsAfter) && !candidateRowsAfter.some((row) => id(row.orderId) === sourceOrderId),
|
||||
`sourceOrderId=${sourceOrderId}, stillCandidate=${Array.isArray(candidateRowsAfter) && candidateRowsAfter.some((row) => id(row.orderId) === sourceOrderId)}`, OPTIONS)
|
||||
|
||||
return { tree, treeResponse, containerId, planId, taskId, sourceInboundId: id(candidate.inboundId) }
|
||||
return { tree, treeResponse, oceanBookingId, containerId, planId, taskId, sourceInboundId: id(candidate.inboundId) }
|
||||
}
|
||||
|
||||
export async function run(context) {
|
||||
@@ -263,10 +297,15 @@ export async function run(context) {
|
||||
const inbound = context.apiSuccess(MODULE, '读取本轮来源入库单', inboundResponse,
|
||||
`tenantId=${tenantId}, inboundId=${inboundId}`, OPTIONS)
|
||||
const orderId = id(inbound?.summary?.orderId)
|
||||
const channelCode = id(inbound?.summary?.channelCode || fixture?.channelCode)
|
||||
const channelName = inbound?.summary?.channelName || fixture?.channelName || channelCode
|
||||
const warehouseName = inbound?.summary?.warehouseName || fixture?.warehouseName
|
||||
const customerName = inbound?.summary?.customerName || `验收客户-${tenantId}`
|
||||
context.assert(MODULE, '来源入库单归属本轮客户与根订单', inboundResponse,
|
||||
isPositiveId(orderId) && id(inbound?.summary?.tenantId) === tenantId,
|
||||
`orderId=${orderId || 'missing'}, tenantId=${id(inbound?.summary?.tenantId) || 'missing'}`, OPTIONS)
|
||||
if (!orderId) return
|
||||
isPositiveId(orderId) && id(inbound?.summary?.tenantId) === tenantId
|
||||
&& Boolean(channelCode && channelName && warehouseName),
|
||||
`orderId=${orderId || 'missing'}, tenantId=${id(inbound?.summary?.tenantId) || 'missing'}, channelCode=${channelCode || 'missing'}, warehouseName=${warehouseName || 'missing'}`, OPTIONS)
|
||||
if (!orderId || !channelCode || !channelName || !warehouseName) return
|
||||
|
||||
const firstTreeResponse = await context.request('GET', treePath(orderId, tenantId))
|
||||
const firstTree = context.apiSuccess(MODULE, '查询首次拆分后的根履约树', firstTreeResponse,
|
||||
@@ -340,7 +379,8 @@ export async function run(context) {
|
||||
|
||||
const result = await loadOneFragment(context, {
|
||||
tenantId, rootOrderId: orderId, sourceOrderId: id(source.orderId), sourceOrderNo: source.orderNo,
|
||||
warehouseId, sourcePackageCount: step.sourcePackageCount, sequence: step.sourceSuffix,
|
||||
customerName, channelCode, channelName, warehouseId, warehouseName,
|
||||
sourcePackageCount: step.sourcePackageCount, sequence: step.sourceSuffix,
|
||||
})
|
||||
if (!result?.tree) return
|
||||
tree = result.tree
|
||||
|
||||
Reference in New Issue
Block a user