Files
baiyue-firstleg/scripts/admin-test-env-modules/phase4-overseas-warehouse.mjs
T

363 lines
26 KiB
JavaScript

const MODULE = 'phase4-overseas-warehouse'
const SCENARIO = 'phase4-overseas-warehouse'
const OPTIONS = { scenario: SCENARIO }
function id(value) { return value == null ? '' : String(value) }
function nonBlank(value) { return typeof value === 'string' && value.trim().length > 0 }
function nonNegative(value) { return Number.isFinite(Number(value)) && Number(value) >= 0 }
function longId(value) { return /^\d+$/.test(id(value)) && id(value) !== '0' }
function trace(response) {
return `HTTP=${response?.http ?? 'missing'}, code=${response?.body?.code ?? 'missing'}, requestId=${response?.requestId || 'missing'}, traceId=${response?.traceId || 'missing'}`
}
function query(path, params) {
const search = new URLSearchParams()
for (const [key, value] of Object.entries(params)) if (value !== undefined && value !== null && value !== '') search.set(key, String(value))
return `${path}?${search}`
}
function records(page) { return Array.isArray(page?.records) ? page.records : [] }
function pageValid(page) {
return Array.isArray(page?.records) && Number.isInteger(Number(page?.page)) && Number(page.page) >= 1
&& Number.isInteger(Number(page?.size)) && Number(page.size) >= 1
&& nonNegative(page?.total) && nonNegative(page?.pages)
}
function assertEnvelope(context, name, response) {
context.assert(MODULE, `${name}响应包络正确`, response,
response?.http === 200 && String(response?.body?.code) === '200' && Object.hasOwn(response?.body || {}, 'data'),
trace(response), OPTIONS)
}
async function domesticGet(context, name, path) {
const response = await context.request('GET', path)
assertEnvelope(context, name, response)
return { response, data: context.apiSuccess(MODULE, name, response, trace(response), OPTIONS) }
}
async function overseasGet(context, name, path) {
const response = await context.requestOverseas('GET', path)
assertEnvelope(context, name, response)
return { response, data: context.apiSuccess(MODULE, name, response, trace(response), OPTIONS) }
}
async function overseasMutation(context, method, name, path, body) {
const response = await context.requestOverseas(method, path, body)
const passed = response?.http === 200 && String(response?.body?.code) === '200'
context.addStep(MODULE, name, response, passed, trace(response), OPTIONS)
return { response, data: passed ? response.body?.data : null }
}
async function domesticMutation(context, method, name, path, body) {
const response = await context.request(method, path, body)
const passed = response?.http === 200 && String(response?.body?.code) === '200'
context.addStep(MODULE, name, response, passed, trace(response), OPTIONS)
return { response, data: passed ? response.body?.data : null }
}
async function overseasCsv(context, name, path) {
const response = await context.requestOverseasBinary('GET', path)
context.addStep(MODULE, name, response,
response?.http === 200 && Number(response?.bytes?.length) > 0 && String(response?.contentType || '').toLowerCase().includes('csv'),
`bytes=${response?.bytes?.length ?? 0}, contentType=${response?.contentType || 'missing'}, requestId=${response?.requestId || 'missing'}, traceId=${response?.traceId || 'missing'}`, OPTIONS)
return response
}
function assertPage(context, name, result) {
context.assert(MODULE, `${name}分页结构正确`, result.response, pageValid(result.data),
`records=${result.data?.records?.length ?? 'missing'}, page=${result.data?.page ?? 'missing'}, size=${result.data?.size ?? 'missing'}, total=${result.data?.total ?? 'missing'}; ${trace(result.response)}`, OPTIONS)
}
function businessConflict(response) {
return response?.http === 409 || (response?.http === 200 && String(response?.body?.code) === 'A0409')
}
function voidMutationSucceeded(result) {
return result?.response?.http === 200 && String(result?.response?.body?.code) === '200'
&& result.data == null
}
function businessNotFound(response) {
return response?.http === 404 || (response?.http === 200 && String(response?.body?.code) === 'A0404')
}
export async function run(context) {
context.createdResources.phase4OverseasWarehouse = { marker: context.marker, customerId: null, warehouseId: null, palletId: null, terminalStatus: null }
const tenantsResult = await domesticGet(context, '查询可用客户候选', '/api/platform/v1/iam/tenants?page=1&size=100&status=ACTIVE')
assertPage(context, '可用客户候选', tenantsResult)
const customer = records(tenantsResult.data).find((item) => longId(item?.id) && item?.status === 'ACTIVE')
const customerId = id(customer?.id)
if (!customerId) {
context.assert(MODULE, '海外仓验收必须取得ACTIVE客户', tenantsResult.response, false,
`IAM ACTIVE 客户列表未返回可用 customerId;${trace(tenantsResult.response)}`, OPTIONS)
return
}
const scoped = { customerId, page: 1, size: 20 }
const orders = await overseasGet(context, '查询尾程订单列表', query('/api/platform/v1/last-leg/orders', scoped))
assertPage(context, '尾程订单列表', orders)
const order = records(orders.data)[0]
if (order) {
context.assert(MODULE, '尾程订单关键字段正确', orders.response,
longId(order.id) && nonBlank(order.orderNo) && nonBlank(order.currentStatus),
`id=${id(order.id) || 'missing'}, orderNo=${order.orderNo || 'missing'}, status=${order.currentStatus || 'missing'}; ${trace(orders.response)}`, OPTIONS)
const detail = await overseasGet(context, '查询尾程订单详情', query(`/api/platform/v1/last-leg/orders/${encodeURIComponent(id(order.id))}`, { customerId }))
context.assert(MODULE, '尾程订单详情对应列表记录', detail.response,
id(detail.data?.order?.id) === id(order.id) && Array.isArray(detail.data?.cargo) && Array.isArray(detail.data?.statusHistory),
`listId=${id(order.id)}, detailId=${id(detail.data?.order?.id) || 'missing'}; ${trace(detail.response)}`, OPTIONS)
}
const relabels = await overseasGet(context, '查询换标单列表', query('/api/platform/v1/last-leg/relabel-applications', scoped))
assertPage(context, '换标单列表', relabels)
const relabel = records(relabels.data)[0]
if (relabel) {
context.assert(MODULE, '换标单关键字段正确', relabels.response,
longId(relabel.id) && nonBlank(relabel.relabelNo) && nonBlank(relabel.status),
`id=${id(relabel.id) || 'missing'}, relabelNo=${relabel.relabelNo || 'missing'}, status=${relabel.status || 'missing'}; ${trace(relabels.response)}`, OPTIONS)
const detail = await overseasGet(context, '查询换标单详情', query(`/api/platform/v1/last-leg/relabel-applications/${encodeURIComponent(relabel.relabelNo)}`, { customerId }))
context.assert(MODULE, '换标单详情对应列表记录', detail.response,
detail.data?.application?.relabelNo === relabel.relabelNo && Array.isArray(detail.data?.items) && Array.isArray(detail.data?.history),
`listNo=${relabel.relabelNo}, detailNo=${detail.data?.application?.relabelNo || 'missing'}; ${trace(detail.response)}`, OPTIONS)
}
const plans = await overseasGet(context, '查询入仓计划列表', query('/api/platform/v1/last-leg/inbound-plans', scoped))
assertPage(context, '入仓计划列表', plans)
const plan = records(plans.data)[0]
if (plan) {
context.assert(MODULE, '入仓计划关键字段正确', plans.response,
longId(plan.lineId) && longId(plan.planId) && longId(plan.orderId)
&& nonBlank(plan.planNo) && id(plan.customerId) === customerId && nonBlank(plan.status),
`lineId=${id(plan.lineId) || 'missing'}, planId=${id(plan.planId) || 'missing'}, orderId=${id(plan.orderId) || 'missing'}, planNo=${plan.planNo || 'missing'}, status=${plan.status || 'missing'}; ${trace(plans.response)}`, OPTIONS)
const detail = await overseasGet(context, '查询入仓计划详情', query(`/api/platform/v1/last-leg/inbound-plans/${encodeURIComponent(plan.planNo)}`, { customerId }))
context.assert(MODULE, '入仓计划详情对应列表记录', detail.response,
detail.data?.planNo === plan.planNo && longId(detail.data?.sourceOrderId)
&& Array.isArray(detail.data?.lines) && Array.isArray(detail.data?.pallets) && Array.isArray(detail.data?.allocations),
`listNo=${plan.planNo}, detailNo=${detail.data?.planNo || 'missing'}, sourceOrderId=${id(detail.data?.sourceOrderId) || 'missing'}; ${trace(detail.response)}`, OPTIONS)
}
const summary = await overseasGet(context, '查询库存汇总(不传分页参数)', query('/api/platform/v1/last-leg/inventory/summary', { customerId }))
context.assert(MODULE, '库存汇总关键数量非负', summary.response,
['inboundOrderCount', 'palletCount', 'totalPackages', 'availablePackages', 'holdPackages', 'inTransitPackages', 'receivingPackages', 'procurementPackages']
.every((field) => nonNegative(summary.data?.[field])),
`total=${summary.data?.totalPackages ?? 'missing'}, available=${summary.data?.availablePackages ?? 'missing'}; ${trace(summary.response)}`, OPTIONS)
const balances = await overseasGet(context, '查询SKU库存余额', query('/api/platform/v1/last-leg/inventory/balances', scoped))
assertPage(context, 'SKU库存余额', balances)
const balance = records(balances.data)[0]
if (balance) {
context.assert(MODULE, 'SKU库存余额关键字段正确', balances.response,
longId(balance.id) && id(balance.customerId) === customerId && nonBlank(balance.skuCode)
&& nonNegative(balance.totalPackages) && nonNegative(balance.availablePackages) && nonBlank(balance.updatedAt),
`id=${id(balance.id) || 'missing'}, sku=${balance.skuCode || 'missing'}, total=${balance.totalPackages ?? 'missing'}; ${trace(balances.response)}`, OPTIONS)
const positions = await overseasGet(context, '查询库存库位详情', query(`/api/platform/v1/last-leg/inventory/balances/${encodeURIComponent(id(balance.id))}/positions`, { customerId }))
context.assert(MODULE, '库存库位详情结构正确', positions.response,
Array.isArray(positions.data) && positions.data.every((item) => longId(item?.id) && id(item?.balanceId) === id(balance.id) && nonNegative(item?.totalPackages)),
`balanceId=${id(balance.id)}, positions=${positions.data?.length ?? 'missing'}; ${trace(positions.response)}`, OPTIONS)
}
const ledger = await overseasGet(context, '查询进销存流水', query('/api/platform/v1/last-leg/inventory/ledger', scoped))
assertPage(context, '进销存流水', ledger)
const ledgerRow = records(ledger.data)[0]
if (ledgerRow) context.assert(MODULE, '进销存流水关键字段正确', ledger.response,
longId(ledgerRow.id) && id(ledgerRow.customerId) === customerId && nonBlank(ledgerRow.businessType)
&& Number.isFinite(Number(ledgerRow.beforePackages)) && Number.isFinite(Number(ledgerRow.deltaPackages))
&& Number.isFinite(Number(ledgerRow.afterPackages)) && nonBlank(ledgerRow.occurredAt),
`id=${id(ledgerRow.id) || 'missing'}, type=${ledgerRow.businessType || 'missing'}, delta=${ledgerRow.deltaPackages ?? 'missing'}; ${trace(ledger.response)}`, OPTIONS)
await overseasCsv(context, '下载SKU库存余额CSV(不传分页参数)', query('/api/platform/v1/last-leg/inventory/balances/export', { customerId }))
await overseasCsv(context, '下载进销存流水CSV(不传分页参数)', query('/api/platform/v1/last-leg/inventory/ledger/export', { customerId }))
let warehouse = await findWarehouse(context, records(tenantsResult.data), customerId)
let ownedWarehouse = false
if (!warehouse) {
warehouse = await createWarehouseFixture(context, customerId)
ownedWarehouse = Boolean(warehouse)
}
if (!warehouse) return
const warehouseId = id(warehouse.id)
context.createdResources.phase4OverseasWarehouse.customerId = customerId
context.createdResources.phase4OverseasWarehouse.warehouseId = warehouseId
const locations = await overseasGet(context, '查询公共库位列表', query(`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations`, { page: 1, size: 20 }))
assertPage(context, '公共库位列表', locations)
const location = records(locations.data)[0]
if (location) {
context.assert(MODULE, '公共库位关键字段正确', locations.response,
longId(location.id) && id(location.warehouseId) === warehouseId && id(location.customerId) === '0'
&& nonBlank(location.locationCode) && nonBlank(location.status),
`id=${id(location.id) || 'missing'}, customerId=${id(location.customerId) || 'missing'}, status=${location.status || 'missing'}; ${trace(locations.response)}`, OPTIONS)
const detail = await overseasGet(context, '查询公共库位详情', `/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations/${encodeURIComponent(id(location.id))}`)
context.assert(MODULE, '公共库位详情对应列表记录', detail.response,
id(detail.data?.id) === id(location.id) && id(detail.data?.warehouseId) === warehouseId && id(detail.data?.customerId) === '0',
`listId=${id(location.id)}, detailId=${id(detail.data?.id) || 'missing'}; ${trace(detail.response)}`, OPTIONS)
}
const pallets = await overseasGet(context, '查询公共托盘列表', query(`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets`, { page: 1, size: 20 }))
assertPage(context, '公共托盘列表', pallets)
const pallet = records(pallets.data)[0]
if (pallet) {
context.assert(MODULE, '公共托盘关键字段正确', pallets.response,
longId(pallet.id) && id(pallet.warehouseId) === warehouseId && id(pallet.customerId) === '0'
&& nonBlank(pallet.palletCode) && ['IDLE', 'OCCUPIED', 'SCRAPPED'].includes(pallet.status),
`id=${id(pallet.id) || 'missing'}, customerId=${id(pallet.customerId) || 'missing'}, status=${pallet.status || 'missing'}; ${trace(pallets.response)}`, OPTIONS)
const detail = await overseasGet(context, '查询公共托盘详情', `/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets/${encodeURIComponent(id(pallet.id))}`)
context.assert(MODULE, '公共托盘详情对应列表记录', detail.response,
id(detail.data?.id) === id(pallet.id) && id(detail.data?.warehouseId) === warehouseId && id(detail.data?.customerId) === '0',
`listId=${id(pallet.id)}, detailId=${id(detail.data?.id) || 'missing'}; ${trace(detail.response)}`, OPTIONS)
}
try {
await verifyLocationLifecycle(context, warehouseId)
await verifyPalletLifecycle(context, warehouseId)
context.context.phase4OverseasWarehouse = {
customerId, warehouseId,
palletId: context.createdResources.phase4OverseasWarehouse.palletId,
}
} finally {
if (ownedWarehouse) await retireWarehouseFixture(context, customerId, warehouseId)
}
}
async function verifyLocationLifecycle(context, warehouseId) {
const marker = String(context.marker || '').replace(/[^A-Za-z0-9_-]/g, '').slice(-40).toUpperCase() || 'PHASE4'
const locationCode = `ACC-${marker}`.slice(0, 64)
let locationId = ''
try {
const created = await overseasMutation(context, 'POST', '创建本轮公共库位',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations`, {
zoneCode: 'ACC', locationCode, locationType: 'STORAGE', maxLoadKg: 1000,
status: 'ACTIVE', remark: context.marker,
})
locationId = id(created.data)
context.createdResources.phase4OverseasWarehouse.locationId = locationId || null
context.assert(MODULE, '公共库位创建返回长ID', created.response, longId(locationId),
`locationId=${locationId || 'missing'}, marker=${context.marker}; ${trace(created.response)}`, OPTIONS)
if (!locationId) return
const detailPath = `/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations/${encodeURIComponent(locationId)}`
const detail = await overseasGet(context, '查询本轮公共库位详情', detailPath)
context.assert(MODULE, '本轮公共库位创建事实正确', detail.response,
id(detail.data?.id) === locationId && id(detail.data?.customerId) === '0'
&& detail.data?.locationCode === locationCode && detail.data?.remark === context.marker,
`locationId=${id(detail.data?.id) || 'missing'}, code=${detail.data?.locationCode || 'missing'}; ${trace(detail.response)}`, OPTIONS)
const updated = await overseasMutation(context, 'PUT', '编辑本轮公共库位', detailPath, {
zoneCode: 'ACC', locationCode, locationType: 'STORAGE', maxLoadKg: 1200,
status: 'ACTIVE', remark: `${context.marker}-edited`,
})
context.assert(MODULE, '公共库位编辑成功', updated.response, voidMutationSucceeded(updated),
`locationId=${locationId}; ${trace(updated.response)}`, OPTIONS)
const after = await overseasGet(context, '回查公共库位编辑结果', detailPath)
context.assert(MODULE, '公共库位编辑字段已生效', after.response,
Number(after.data?.maxLoadKg) === 1200 && after.data?.remark === `${context.marker}-edited`,
`maxLoadKg=${after.data?.maxLoadKg ?? 'missing'}, remark=${after.data?.remark || 'missing'}; ${trace(after.response)}`, OPTIONS)
} finally {
if (locationId) {
const removed = await overseasMutation(context, 'DELETE', '删除本轮公共库位',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations/${encodeURIComponent(locationId)}`)
const deletedDetail = await context.requestOverseas('GET',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations/${encodeURIComponent(locationId)}`)
const deleted = voidMutationSucceeded(removed) && businessNotFound(deletedDetail)
context.createdResources.phase4OverseasWarehouse.locationTerminalStatus = deleted ? 'DELETED' : null
context.assert(MODULE, '本轮公共库位已删除且回查不存在', deletedDetail, deleted,
`locationId=${locationId}, terminalStatus=${context.createdResources.phase4OverseasWarehouse.locationTerminalStatus || 'missing'}; delete=${trace(removed.response)}, readback=${trace(deletedDetail)}`, OPTIONS)
}
}
}
async function createWarehouseFixture(context, customerId) {
const suffix = String(context.marker || '').replace(/[^A-Za-z0-9]/g, '').slice(-20).toUpperCase()
const payload = {
tenantId: 0, warehouseCode: `P4W-${suffix}`.slice(0, 50), warehouseName: `${context.marker} 海外仓`,
warehouseType: 'OVERSEAS', countryCode: 'US', timezone: 'America/Los_Angeles',
contactName: 'Phase4 QA', contactPhone: '12135550188', contactEmail: null,
status: 'ACTIVE', remark: `${context.marker}-warehouse-fixture`,
address: { addressType: 'WAREHOUSE', countryCode: 'US', stateProvince: 'California', city: 'Los Angeles',
district: 'Commerce', postalCode: '90040', addressLine1: '501 Phase Four Warehouse Avenue',
addressLine2: null, latitude: null, longitude: null },
capabilities: [{ capabilityCode: 'STORAGE', capabilityName: 'Storage', enabled: true,
cutoffTime: null, description: `${context.marker} acceptance` }],
}
const created = await domesticMutation(context, 'POST', '创建本轮客户海外仓', '/api/platform/v1/warehouse-admin', payload)
const warehouseId = id(created.data)
context.assert(MODULE, '客户海外仓创建返回长ID', created.response, longId(warehouseId),
`warehouseId=${warehouseId || 'missing'}, customerId=${customerId}; ${trace(created.response)}`, OPTIONS)
if (!warehouseId) return null
const detail = await domesticGet(context, '查询本轮公共海外仓详情', query(`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}`, { tenantId: 0 }))
context.assert(MODULE, '本轮公共海外仓类型和状态正确', detail.response,
id(detail.data?.warehouse?.id || detail.data?.id) === warehouseId
&& (detail.data?.warehouse?.warehouseType || detail.data?.warehouseType) === 'OVERSEAS'
&& (detail.data?.warehouse?.status || detail.data?.status) === 'ACTIVE',
`warehouseId=${warehouseId}, warehouseType=${detail.data?.warehouse?.warehouseType || detail.data?.warehouseType || 'missing'}; ${trace(detail.response)}`, OPTIONS)
return { id: warehouseId, customerId, warehouseCode: payload.warehouseCode, warehouseName: payload.warehouseName, status: 'ACTIVE' }
}
async function retireWarehouseFixture(context, customerId, warehouseId) {
const retired = await context.request('PATCH', query(`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/status`, { tenantId: 0, status: 'INACTIVE' }))
context.addStep(MODULE, '本轮客户海外仓已停用收口', retired,
retired?.http === 200 && String(retired?.body?.code) === '200', trace(retired), OPTIONS)
}
async function verifyPalletLifecycle(context, warehouseId) {
const marker = String(context.marker || '').replace(/[^A-Za-z0-9_-]/g, '').slice(-48) || 'PHASE4'
const palletCode = `ACC-${marker}`.slice(0, 128)
let palletId = ''
try {
const created = await overseasMutation(context, 'POST', '创建本轮公共托盘',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets`, {
palletCode, palletType: '木托盘', capacityCbm: 2, unitPrice: 0, status: 'IDLE', remark: context.marker,
})
palletId = id(created.data)
context.createdResources.phase4OverseasWarehouse.palletId = palletId || null
context.assert(MODULE, '公共托盘创建返回长ID', created.response, longId(palletId),
`palletId=${palletId || 'missing'}, marker=${context.marker}; ${trace(created.response)}`, OPTIONS)
if (!palletId) return
const detailPath = `/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets/${encodeURIComponent(palletId)}`
const detail = await overseasGet(context, '查询本轮公共托盘详情', detailPath)
context.assert(MODULE, '本轮公共托盘创建事实正确', detail.response,
id(detail.data?.id) === palletId && id(detail.data?.warehouseId) === warehouseId
&& id(detail.data?.customerId) === '0' && detail.data?.palletCode === palletCode && detail.data?.status === 'IDLE',
`palletId=${id(detail.data?.id) || 'missing'}, code=${detail.data?.palletCode || 'missing'}, customerId=${id(detail.data?.customerId) || 'missing'}; ${trace(detail.response)}`, OPTIONS)
const updated = await overseasMutation(context, 'PUT', '编辑本轮公共托盘', detailPath, {
palletCode, palletType: '木托盘', capacityCbm: 2.5, unitPrice: 1, status: 'IDLE',
locationId: id(detail.data?.locationId) || undefined, remark: `${context.marker}-edited`, version: Number(detail.data?.version),
})
context.assert(MODULE, '公共托盘编辑成功', updated.response, voidMutationSucceeded(updated),
`palletId=${palletId}; ${trace(updated.response)}`, OPTIONS)
const after = await overseasGet(context, '回查公共托盘编辑结果', detailPath)
context.assert(MODULE, '公共托盘编辑字段已生效', after.response,
id(after.data?.id) === palletId && Number(after.data?.capacityCbm) === 2.5
&& Number(after.data?.unitPrice) === 1 && after.data?.remark === `${context.marker}-edited`,
`capacity=${after.data?.capacityCbm ?? 'missing'}, unitPrice=${after.data?.unitPrice ?? 'missing'}, remark=${after.data?.remark || 'missing'}; ${trace(after.response)}`, OPTIONS)
const stale = await context.requestOverseas('PUT', detailPath, {
palletCode, palletType: '木托盘', capacityCbm: 9, unitPrice: 9, status: 'IDLE',
remark: 'STALE-DO-NOT-APPLY', version: Number(detail.data?.version),
})
context.addStep(MODULE, '公共托盘旧版本编辑返回冲突', stale,
stale?.http === 409 || (stale?.http === 200 && String(stale?.body?.code).endsWith('409')), trace(stale), OPTIONS)
} finally {
if (palletId) {
const retired = await overseasMutation(context, 'PUT', '报废本轮公共托盘',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets/${encodeURIComponent(palletId)}`, {
palletCode, palletType: '木托盘', capacityCbm: 2.5, unitPrice: 1, status: 'SCRAPPED',
remark: `${context.marker}-acceptance-retired`, version: Number((await overseasGet(context,
'读取公共托盘报废前最新版本',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets/${encodeURIComponent(palletId)}`)).data?.version),
})
context.createdResources.phase4OverseasWarehouse.terminalStatus = voidMutationSucceeded(retired) ? 'SCRAPPED' : null
context.assert(MODULE, '本轮公共托盘已报废收口', retired.response, voidMutationSucceeded(retired),
`palletId=${palletId}, terminalStatus=${context.createdResources.phase4OverseasWarehouse.terminalStatus || 'missing'}; ${trace(retired.response)}`, OPTIONS)
const retiredDetail = await overseasGet(context, '回查本轮公共托盘报废状态',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets/${encodeURIComponent(palletId)}`)
context.assert(MODULE, '本轮公共托盘终态为已报废', retiredDetail.response,
id(retiredDetail.data?.id) === palletId && retiredDetail.data?.status === 'SCRAPPED',
`palletId=${id(retiredDetail.data?.id) || 'missing'}, status=${retiredDetail.data?.status || 'missing'}; ${trace(retiredDetail.response)}`, OPTIONS)
}
}
}
async function findWarehouse(context, tenants, preferredCustomerId) {
const result = await domesticGet(context, '查询可用公共海外仓', query('/api/platform/v1/warehouse-admin', {
tenantId: 0, warehouseType: 'OVERSEAS', page: 1, size: 100, status: 'ACTIVE',
}))
assertPage(context, '可用公共海外仓', result)
const warehouse = records(result.data).find((item) => longId(item?.id)
&& item?.status === 'ACTIVE' && item?.warehouseType === 'OVERSEAS')
if (warehouse) {
context.assert(MODULE, '海外仓关键字段正确', result.response,
nonBlank(warehouse.warehouseCode) && nonBlank(warehouse.warehouseName),
`warehouseId=${id(warehouse.id)}, code=${warehouse.warehouseCode || 'missing'}; ${trace(result.response)}`, OPTIONS)
const detail = await domesticGet(context, '查询海外仓详情', query(`/api/platform/v1/warehouse-admin/${encodeURIComponent(id(warehouse.id))}`, { tenantId: 0 }))
context.assert(MODULE, '海外仓详情对应列表记录', detail.response,
id(detail.data?.warehouse?.id || detail.data?.id) === id(warehouse.id),
`listId=${id(warehouse.id)}, detailId=${id(detail.data?.warehouse?.id || detail.data?.id) || 'missing'}; ${trace(detail.response)}`, OPTIONS)
return warehouse
}
return null
}