约稿详情净已支付金额 (2026-09-22)

需求背景

  • 来源:约稿详情「已支付 / 预计收入」口径调整需求(2026-09-22 评审);2026-09-23 音画会议后经五轮设计与数据评审,口径修正为「引擎事实派生」模型(任务 09-23-net-paid-amount-fee-breakdown)。
  • 动机:paid_amount 是终身累计支付事实、不随退款减少,发生退款后详情页展示的「已支付」会偏高;首版净额公式 paid − Σ已完成退款 在存在不可退支付手续费时仍会超过总稿酬(#191 实测 16746 > 15000),业务上不成立。
  • 范围:两个约稿详情接口的净额字段口径修正并扩展为五个派生字段 + 完整性 issues;两个列表接口新增 net_paid_amount(仅实际口径)。本次不改 paid_amount 语义与所有消费方、不改退款链路、不新增迁移。
  • 面向读者:前端(用户端 + 画师端)、联调、测试。
  • 术语对照:commission = WorkTask(委托);credit = 站内 Credit 钱包余额。

更新记录

  • 2026-09-22 首次发布:新增只读字段 net_paid_amount 与计算口径(开发阶段契约,后端未发版)。
  • 2026-09-23 修订:字段表去除 emoji 前缀(按在途同域迭代规则,展示形式调整,契约无变化)。
  • 2026-09-23 口径迭代:⚠️ net_paid_amount 定义修正为「合同覆盖金额」(working 态 min(retained, price)、取消态 max(0, retained − 不可退手续费));✨ 详情接口新增 projected_net_paid_amount / retained_amount / non_refundable_fee / uncovered_retained_amount / non_refundable_fee_issues;✨ 列表接口新增 net_paid_amount(仅实际口径)。依据:#191 净额 16746 超总稿酬 15000 的根因核验(差额 1746 = 平台留存 PayPal 手续费),见第 4 章。
  • 2026-09-23 账目异常修正:✨ 详情接口再新增 accounting_issues 字段;retained_amount 保留原始账目值(退款合计超过支付史的损坏数据下可为负,不再截零),仅 net_paid_amount 有展示下限 0——保证两条可证明关系在异常账目下仍成立,异常经 accounting_issues 报告。
  • 2026-09-23 事实修订:费用明细改为独立试算接口(《约稿画师端费用明细》方案 B),同步修正本文对详情内嵌 fee_breakdown 的过时引用;契约无变化。

建议阅读顺序:第 1 章(一分钟上手)→ 第 2 章(接口变更总览)→ 第 3 章(接口示例)→ 第 4 章(字段口径与前端跟进清单)→ 第 5 章(兼容性)。遇到「这个数为什么和 paid_amount 不一样」先看第 1 章流程图与第 4 章口径表。

目录

章内容什么时候看
1. 一分钟上手口径模型图 + 取值来源 + 对接要点刚拿到文档
2. 接口变更四个接口与变更摘要找接口
3. 接口示例请求参数、响应示例与错误对接具体接口
4. 字段补充说明净额派生口径、两条可证明关系与前端跟进清单查具体取值与展示
5. 兼容性说明兼容项与发布协同发布前确认

1. 一分钟上手

状态与口径:开发阶段契约、后端未发版;net_paid_amount 为行为变更(口径修正,数值可能与首版契约不同);无错误码与请求参数变化。 本次没有新增状态、枚举、错误码;paid_amount 的语义与所有既有消费方完全不变。

1.1 净额派生模型

working 态净额是合同覆盖金额,不是客户实际净支出:受 price 约束,手续费留存与卡价差额不体现在该字段;要看客户实际留存读 retained_amount。

1.2 取值来源与状态机

只按退款债权债务轴(obligation_status)纳入:fulfilled 计入实际口径;open(含 retryable_failed 等全部执行中状态,债务仍存在)计入预计口径;voided 两口径都剔除。退款作废时 retained_amount 会回弹,而受 price 约束的 net_paid_amount 不一定变化。

1.3 前后端交互时序

1.4 对接要点

  1. net_paid_amount 是只读派生字段,定义为「合同覆盖金额」:working 态 min(retained, price),全额支付且无退款时等于 price;存在不可退手续费留存时(如 #191)也不会超过总稿酬。要看客户实际留存读 retained_amount,两者不要混用。
  2. paid_amount 语义与取值完全不变:它仍是终身累计支付事实。退款上限、付全款门槛、取消/改价判定继续读 paid_amount。
  3. 列表只返回实际口径 net_paid_amount:双口径(projected_net_paid_amount 等)只在详情接口返回;卡片展示直接读列表字段即可。
  4. 债务轴纳入规则:只有 obligation_status 参与——fulfilled 进实际口径、open(含全部执行中状态)进预计口径、voided 剔除;执行状态(retryable_failed 等)不改变纳入。
  5. 未支付返回 0 而非 null:paid_amount 为空或 0 时净额相关字段恒为 0。
  6. non_refundable_fee_issues 非空时的提示义务:issues 非空表示存在订单缺少业务币种手续费事实,此时 non_refundable_fee 是部分和、取消态的 net_paid_amount 是上界估计;working 态不受影响。前端在取消态且 issues 非空时应提示「金额为估算」。
  7. accounting_issues 非空 = 账目异常:退款合计超过累计支付(损坏数据)时,retained_amount 保留原始负值、net_paid_amount 展示下限 0,同时返回 accounting_issues(code=refunds_exceed_paid_amount,scope 区分实际/预计口径)。前端收到该 issues 时应提示「账目异常,金额不可信」,不要按正常金额展示。
  8. 净额 ≠ 画师结算额:取消后净额是「客户计入业务的保留金额」,画师实际结算还要经结算域扣费(实测案例:本金 10000、画师结算 9215),两者不要等同展示。

2. 接口变更

user

  • POST /api/work_tasks/info
    • 功能:用户侧约稿详情
    • 变更:⚠️ net_paid_amount 口径修正为合同覆盖金额;✨ 新增 projected_net_paid_amount / retained_amount / non_refundable_fee / uncovered_retained_amount / non_refundable_fee_issues
  • POST /api/work_tasks/list
    • 功能:用户侧约稿列表
    • 变更:✨ 响应每项新增只读字段 net_paid_amount(仅实际口径)

artist_center

四个接口共用同一套派生服务(CommissionNetPaidAmountService),列表与详情的实际口径由同一批量原语计算,数值保证一致。费用明细走独立试算接口(POST /api/artist_center/work_tasks/fee_estimate),见独立文档《约稿画师端费用明细》。


3. 接口示例

user

POST /api/work_tasks/info

  • 功能说明:查询当前用户的一笔 commission 详情。
  • 变更说明:⚠️ net_paid_amount 口径修正;✨ 新增净额派生字段组。

请求参数

字段类型必填说明
idinteger是commission id(work_tasks.id),必须属于当前用户

请求示例

{
  "id": 1001
}

响应示例

{
  "data": {
    "id": 1001,
    "price": 8000,
    "paid_amount": 10000,
    "net_paid_amount": 8000,
    "projected_net_paid_amount": 8000,
    "retained_amount": 8000,
    "non_refundable_fee": 500,
    "uncovered_retained_amount": 0,
    "non_refundable_fee_issues": [],
    "accounting_issues": []
    // ...其余字段省略
  }
}

上例是一笔「原价 10000、改价到 8000、差价 2000 已退款完成」的 working commission:retained_amount = 10000 − 2000 = 8000,net_paid_amount = min(8000, 8000) = 8000。若存在不可退手续费留存(如 PayPal 手续费),retained_amount 可能高于 price,此时 net_paid_amount 仍受 price 约束,差额见 uncovered_retained_amount。

错误响应

无新增,沿用原有错误语义(如 404 Work task not found、422 id 校验失败)。

POST /api/work_tasks/list

  • 功能说明:查询当前用户的 commission 列表。
  • 变更说明:✨ 每项新增只读字段 net_paid_amount(实际口径)。

请求参数

沿用既有列表参数,无新增。

响应示例

{
  "data": [
    {
      "id": 1001,
      "price": 8000,
      "paid_amount": 10000,
      "net_paid_amount": 8000
      // ...其余字段省略
    }
  ]
}

错误响应

无新增,沿用原有错误语义。

artist_center

POST /api/artist_center/work_tasks/info

  • 功能说明:查询当前画师的一笔 commission 详情。
  • 变更说明:⚠️ net_paid_amount 口径修正;✨ 新增净额派生字段组,与用户侧口径完全一致;费用明细由独立试算接口供数(见《约稿画师端费用明细》)。

请求参数

字段类型必填说明
idinteger是commission id(work_tasks.id),必须属于当前画师

请求示例

{
  "id": 1001
}

响应示例

{
  "data": {
    "id": 1001,
    "price": 8000,
    "paid_amount": 10000,
    "net_paid_amount": 8000,
    "projected_net_paid_amount": 8000,
    "retained_amount": 8000,
    "non_refundable_fee": 500,
    "uncovered_retained_amount": 0,
    "non_refundable_fee_issues": []
    // ...其余字段省略
  }
}

错误响应

无新增,沿用原有错误语义(如 404 Work task not found、422 id 校验失败)。

POST /api/artist_center/work_tasks/list

  • 功能说明:查询当前画师的 commission 列表。
  • 变更说明:✨ 每项新增只读字段 net_paid_amount(实际口径)。

请求参数

沿用既有列表参数,无新增。

响应示例

{
  "data": [
    {
      "id": 1001,
      "price": 8000,
      "paid_amount": 10000,
      "net_paid_amount": 8000
      // ...其余字段省略
    }
  ]
}

错误响应

无新增,沿用原有错误语义。


4. 字段补充说明

4.1 净额派生口径(2026-09-23 修正版)

三个事实量(读取时实时计算,不落库):

retained(口径)    = paid_amount − Σ 已纳入债权(口径)的 business_refund_amount
                    实际口径 → obligation_status = fulfilled
                    预计口径 → obligation_status ∈ {open, fulfilled}
                    voided 两口径剔除;执行轴状态不影响纳入

non_refundable_fee = Σ 逐单实际支付手续费(网关单、业务币种、支付宝 CNY 零费特例)
                     任何退款能力/承担方条件下都返回真实值,不清零;
                     缺失或币种不符 → 已知部分和 + issues

净额两式:
  working   net = min(retained(口径), price)         // 合同覆盖金额
  canceled  net = max(0, retained(口径) − non_refundable_fee)
场景net_paid_amount(实际口径)
从未支付0
已支付、无退款(working)等于 min(paid_amount, price)
改价/取消退款已完成(working)不超过当前 price(手续费留存与卡价差由 uncovered_retained_amount 体现)
退款债权 open(含执行中各状态)实际口径不扣、projected_net_paid_amount 已扣
退款债权 voided两口径都不扣
已取消(全额退款)0(如 #241:retained 4599 − 手续费 4599)
已取消(协商保留)max(0, retained − 不可退手续费);该值 ≠ 画师实际结算额

4.2 两条可证明关系(字段间恒等式)

关系公式说明
关系 1retained_amount − (retained_amount − Σ open 债权退款额) = projected实际与预计口径的差 = 未结退款
关系 2retained_amount − net_paid_amount = uncovered_retained_amount未计入合同覆盖额的留存余额

uncovered_retained_amount 的内部构成(手续费留存 / 零退款卡价差 / 未结退款)不做归因拆分;non_refundable_fee 作为独立事实字段呈现。实测观测:#191 uncovered 1746 恰为手续费;#173 uncovered 4200 含 open 退款 2226 与手续费 1974。

4.3 手续费完整性 issues 与账目异常 issues

"non_refundable_fee_issues": [
  { "code": "business_gateway_fee_missing", "order_id": 462, "message": "缺少业务币种的实际支付手续费" }
]
  • 手续费 issues 非空 → non_refundable_fee 为已知部分和(下界);
  • 取消态的 net_paid_amount = max(0, retained − 部分手续费) 是上界估计,前端需提示「金额为估算」;
  • working 态不受影响(min(retained, price) 不消费手续费)。
"accounting_issues": [
  { "code": "refunds_exceed_paid_amount", "scope": "projected", "paid_amount": 1000, "refunded": 1300, "message": "退款合计超过累计支付,账目异常" }
]
  • accounting_issues 非空 = 退款合计超过支付史的损坏数据:retained_amount 保留原始负值(不截零,保证两条可证明关系成立),net_paid_amount / projected_net_paid_amount 展示下限 0;scope=actual / projected 分别对应实际与预计口径。

4.4 #191 / #241 实测案例(上线即正确,无回填)

约稿paidretained不可退手续费pricenetuncovered
#191(多次改价+退款,working)6261916746174615000150001746
#241(全额退款取消)10000045994599—04599
#173(open 退款中,working)1920019200197415000实际/预计均 150004200

4.5 前端跟进清单

以下为前端(pipipen-front,由前端负责人实施)需要跟随本次后端供数完成的改造项:

  1. 「已支付」改读净额:pages/a/[id]/commissions/info.vue 现用 workTaskInfo.paid_amount,改为 workTaskInfo.net_paid_amount(列表卡片同理改读列表新字段)。
  2. 「预计收入」改读试算接口:画师端费用明细弹窗改用 POST /api/artist_center/work_tasks/fee_estimate(入参 amount = net_paid_amount,见《约稿画师端费用明细》文档),不再由前端写死费率计算。
  3. 未支付显示 0:净额字段未支付时后端返回 0,直接展示,不要显示 --。
  4. 保留稿酬总额小字:净额为主展示,稿酬总额(price)次要小字对照。
  5. 取消态 issues 提示:non_refundable_fee_issues 非空且约稿已取消时,「已支付金额」旁标注估算提示。

5. 兼容性说明

  • net_paid_amount 为行为变更(后端未发版,无线上兼容负担):取值从「paid − 已完成退款」修正为「合同覆盖金额」,依赖该字段的展示口径以前端改绑后为准;paid_amount 及全部既有消费方零改动。
  • 新增字段全部为纯增量:双口径、保留额、手续费、uncovered、issues 在两个详情接口新增;列表仅新增 net_paid_amount;请求参数、错误码零改动。
  • 无迁移、无回填:净额为读取时实时派生,存量数据上线即正确(全量只读验证已通过,见任务档案验证报表)。
  • 无需发布顺序协同:后端先上线即可供数,前端随后切换展示口径。
  • 回滚方式:revert 对应后端提交即可,纯响应字段回退不影响任何存量数据与退款链路。