完善财务全量验收链路

This commit is contained in:
2026-08-12 13:24:17 +08:00
parent 505e834536
commit d2704f68a6
11 changed files with 295 additions and 44 deletions
@@ -253,16 +253,40 @@ async function createMarkerContainer(context, resource) {
}
}
async function createContainerCost(context, customerId, container, voucherFileId) {
if (context.financeFixtureHooks?.createContainerCost) return context.financeFixtureHooks.createContainerCost(context, customerId, container, voucherFileId)
async function createContainerCost(context, customerId, container, voucherFileId, snapshotInput) {
if (context.financeFixtureHooks?.createContainerCost) return context.financeFixtureHooks.createContainerCost(context, customerId, container, voucherFileId, snapshotInput)
const body = { customerId: Number(customerId), costType: 'CONTAINER_SHARED', orderId: null,
containerId: Number(container.containerBookingId), expenseName: `${context.marker}-整柜成本`, amount: 300,
// Finance names this field containerId, but its Firstleg cost snapshot contract
// resolves it as the loading plan ID, not the physical container booking ID.
containerId: Number(container.loadingPlanId), expenseName: `${context.marker}-整柜成本`, amount: 300,
currency: 'CNY', voucherFileIds: [voucherFileId], remark: context.marker }
const response = await request(context, 'POST', '/api/platform/finance/v1/cost-entries', body)
if (response?.body?.code === 'FIN_400') {
const first = snapshotInput?.items?.[0]
blocker(context, 'Finance 整柜成本请求关联真实装柜计划',
`message=${response.body.message || 'missing'}, loadingPlanId=${container.loadingPlanId || 'missing'}, containerBookingId=${container.containerBookingId || 'missing'}, voucherFileId=${voucherFileId || 'missing'}, publicSnapshotValid=${snapshotInput?.valid === true}, validItems=${snapshotInput?.items?.length || 0}, accountId=${first?.accountId ?? 'missing'}, orderId=${first?.orderId ?? 'missing'}, volumeCbm=${first?.volumeCbm ?? 'missing'}, requestId=${response.requestId || 'missing'}, traceId=${response.traceId || 'missing'};若 publicSnapshotValid=true,说明 fixture ID 与公开装柜明细有效,阻断位于 Finance -> Firstleg 内部快照服务部署/契约`)
}
const cost = context.apiSuccess(MODULE, '创建整柜成本并触发真实体积分摊', response, '', OPTIONS)
return cost?.id ? { costId: id(cost.id), allocations: Array.isArray(cost.allocations) ? cost.allocations : null } : null
}
async function verifyContainerCostSnapshotInput(context, customerId, container) {
if (context.financeFixtureHooks?.verifyContainerCostSnapshotInput) {
return context.financeFixtureHooks.verifyContainerCostSnapshotInput(context, customerId, container)
}
const path = `/api/platform/v1/first-leg/smart-loading/plans/${encodeURIComponent(container.loadingPlanId)}`
const response = await context.request('GET', path)
const plan = context.apiSuccess(MODULE, '回读 Finance 柜次体积快照输入', response,
`loadingPlanId=${container.loadingPlanId}`, OPTIONS)
const items = Array.isArray(plan?.items) ? plan.items : []
const valid = items.filter((item) => id(item?.accountId) === id(customerId)
&& Number(item?.orderId) > 0 && Number(item?.volumeCbm) > 0)
context.assert(MODULE, '装柜明细满足 Finance 内部快照筛选条件', response,
plan?.status === 'COMPLETED' && valid.length > 0,
`status=${plan?.status || 'missing'}, items=${items.length}, validItems=${valid.length}, accountId=${items[0]?.accountId ?? 'missing'}, orderId=${items[0]?.orderId ?? 'missing'}, volumeCbm=${items[0]?.volumeCbm ?? 'missing'}`, OPTIONS)
return { valid: plan?.status === 'COMPLETED' && valid.length > 0, items: valid }
}
export async function run(context) {
const start = context.steps.length
const pricingEvidence = await loadPricingEvidence(context)
@@ -354,10 +378,11 @@ export async function run(context) {
'未通过 /api/platform/finance/v1/vouchers multipart 上传取得真实 fileId;整柜成本不得模拟成功')
let allocations = []
if (containerFixture?.feeSourceId && voucherFileId && supplier?.id) {
const cost = await createContainerCost(context, customerId, container, voucherFileId)
const snapshotInput = await verifyContainerCostSnapshotInput(context, customerId, container)
const cost = snapshotInput.valid ? await createContainerCost(context, customerId, container, voucherFileId, snapshotInput) : null
if (Array.isArray(cost?.allocations)) allocations = cost.allocations
else blocker(context, '回读整柜成本分摊结果',
`costId=${cost?.costId || 'missing'};Finance cost-entries 创建响应未返回逐订单/运单 allocations,禁止从金额和体积自行伪造持久化结果`)
`costId=${cost?.costId || 'missing'};Finance POST /api/platform/finance/v1/cost-entries 仅返回 ResourceResult,GET cost-entries 仅返回成本摘要,当前没有公开接口回读 fin_cost_allocation;禁止从金额和体积自行伪造持久化结果`)
}
if (allocations.length === 0) blocker(context, '输出真实订单/运单分摊',
'缺少已完成柜次、凭证、供应商或 Finance 分摊响应;不伪造 allocation ID/金额')