const MICROS_PER_YUAN = 1_000_000 const POLICY_SETTLERS = { record_only() { return 0 }, fixed_points(policy) { return policy.points }, cost_ratio(policy, supplierCost) { return Math.ceil(supplierCost.supplier_cost_micros * policy.points_per_yuan / MICROS_PER_YUAN) }, } /** * 模型供应商成本到用户积分的唯一结算入口。 * @param {{ deduct:(input:object)=>Promise<{balance_after:number,ledger_id:string}> }} deps */ export function createModelBilling({ deduct }) { return async function settleModelBilling(input) { const settlement = modelSettlement(input.policy, input.supplier_cost) if (settlement.charged_points === 0) return { ...settlement, ledger_id: null } const ledger = await deduct({ user_id: input.user_id, amount: settlement.charged_points, reason: 'model_usage', ref_type: input.call_ref.type, ref_id: input.call_ref.id, idempotency_key: input.idempotency_key, }) return { ...settlement, ledger_id: ledger.ledger_id } } } /** * 结算入口的唯一数据构造点。非法策略和金额在写 ledger 前立即失败。 * @param {Record} input */ function modelSettlement(policy, supplierCost) { const billingPolicySnapshot = policySnapshot(policy) const chargedPoints = POLICY_SETTLERS[policy.mode](billingPolicySnapshot, supplierCost) return { billing_mode: billingPolicySnapshot.mode, billing_policy_snapshot: billingPolicySnapshot, charged_points: chargedPoints, } } /** 校验并构造可审计的精确策略快照;不接受未声明字段。 */ function policySnapshot(policy) { switch (policy.mode) { case 'record_only': return { mode: policy.mode, reason: policy.reason } case 'fixed_points': return { mode: policy.mode, points: policy.points } case 'cost_ratio': return { mode: policy.mode, points_per_yuan: policy.points_per_yuan } default: throw new Error(`Unhandled billing mode: ${policy.mode}`) } }