const id = value => value == null ? '' : String(value) const positive = value => /^[1-9][0-9]*$/.test(id(value)) && Number.isSafeInteger(Number(value)) /** 仅组合本轮已收货入仓单的权威箱、SKU 和实际托盘位置,不生成箱号或推算每箱件数。 */ export async function readCurrentBoxedInventory(context, token, warehouseId, module) { const pda = context.createdResources?.phase4OverseasPda if (pda?.marker !== context.marker || pda.finalStatus !== 'COMPLETED' || id(pda.overseasWarehouseId) !== id(warehouseId)) throw Error('真实箱来源缺少本轮已收货仓库事实') const inbounds = Object.keys(pda.generatedPalletsByInbound || {}) if (!inbounds.length) throw Error('真实箱来源缺少本轮入仓单') const get = async path => { const response = await context.request('GET', path, undefined, token, {}) const data = context.apiSuccess(module, '核对本轮库存真实箱与SKU来源', response) if (response?.http !== 200 || String(response?.body?.code) !== '200' || !Array.isArray(data)) throw Error('真实箱来源接口未返回完整列表') return data } const physical = await get('/api/merchant/v1/last-leg/cargo-discards/inventory-candidates') const result = [] for (const inboundCode of inbounds) { const scope = { operatingWarehouseId: id(warehouseId), inboundCode } const cartons = await get('/api/merchant/v1/last-leg/warehouse-transfers/inventory-source-cartons?' + new URLSearchParams(scope)) if (!cartons.length) continue const inventory = await get('/api/merchant/v1/last-leg/relabel-applications/inventory-candidates?' + new URLSearchParams({ operationWarehouseId: id(warehouseId), inboundCode })) for (const source of inventory.filter(row => row.sourceType === 'INBOUND' && row.inboundCode === inboundCode && id(row.overseasWarehouseId) === id(warehouseId) && id(row.inventoryBalanceId) && id(row.inboundOrderId))) { const boxes = physical.filter(row => row.inboundCode === inboundCode && id(row.overseasWarehouseId) === id(warehouseId) && id(row.orderId) === id(source.inboundOrderId)).flatMap(row => row.cartons || []) const seen = new Set() const actual = [] for (const carton of cartons) { if (!carton.cartonMark || seen.has(carton.cartonMark)) throw Error('权威来源箱号缺失或重复') seen.add(carton.cartonMark) const matches = boxes.filter(box => box.cartonMark === carton.cartonMark) if (matches.length !== 1) continue const box = matches[0] const positions = (source.positions || []).filter(position => position.palletNo === box.palletNo && box.palletNo && box.palletNo.toUpperCase() !== 'UNBOUND' && Number(position.availablePackages) > 0) const items = carton.items || [] if (positions.length !== 1 || !items.length || items.some(item => !item.skuCode || !positive(item.quantity)) || !items.some(item => item.skuCode === source.skuCode)) continue actual.push({ ...carton, cartonId: id(box.cartonId), positionId: id(positions[0].positionId), palletNo: box.palletNo }) } if (actual.length) result.push({ ...source, cartons: actual }) } } return result }