完善财务全量验收链路
This commit is contained in:
@@ -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/金额')
|
||||
|
||||
Reference in New Issue
Block a user