需求背景
09-23-refund-zero-source-rounding(PRD prd.md)、09-24-price-change-refund-pure-difference(PRD prd.md)与 09-30-refund-write-off-cap-strategy(PRD prd.md);2026-09-26 首次发布小额退款政策,2026-09-27 发布改价纯差额,2026-09-28 评审合并为「退款政策与金额口径」统一文档,2026-09-30 迭代为「按支付 Order 独立碎额上限 + 两次退款与最终关闭」。preview 可能允许提交而预留/执行拒绝;小额剩余也没有统一规则,用户需要在多个不连续区间试探。同时,改价降价退款一度按「扣除不可退支付手续费后的有效上限减新价格」计算,把本应留给客户的差额扣成了手续费。本期用一套可解释的规则收口:每笔 Commission 最多两次有效退款、正额退款不得低于平台最低退款金额、无法执行的极小碎额按上限抹平,改价降价按业务纯差额退款并增加新价下限。cancellation/preview|request|accept)与改价(work_task_price_changes/preview|create|approve)两条既有退款入口新增政策字段与政策错误码,引入「按支付 Order 独立的碎额上限」「final closure 逐来源关闭」与终局 refund_closed 状态;本次不新增任意金额退款入口、不改退款去向与渠道能力(保留 original / credit 双去向)、不改含手续费全额退款入口的开放范围,也不修改前端源码(前端仓库只读,仅提供对接交接)。WorkTask(委托);commissions 是 worktask 的对外展示名;credit = 站内 Credit 钱包。T;refund_policy.minimum_refund_amount)= 平台最低退款金额,默认等值 USD 0.10;换算成业务币时向上取整。M;refund_policy.remaining_refundable_amount)= 当前剩余可退金额,等于 financials.refund_limits.maximum。R)= 改价降价时后端按「未占用已付金额 − 新价格」算出的退款额,写在 financials.refund.amount;它不是用户直接输入。M)。R = M)与第二次退款共用的执行模式:逐来源按账本事实退回剩余原币净额 S(该来源仍对应客户可退权益的剩余业务容量记为 B),不再运行普通比例分配、当前汇率换算与碎额准入;R = M 全退不受最低退款金额限制。scope = 'request',reason = 'rounding_zero'):本次退款分配给某资金来源时,因汇率换算与最小货币单位向下取整导致「业务币为正(如 1 分钱),但底层原币向下取整为 0」的尾差。它包含在本次请求退款额内,但无法发往底层渠道执行,由平台在账面按抹平核销,实际出款给客户时扣除该金额。scope = 'residual',reason = 'unexecutable_fragment'):本次退款执行后,某资金来源在底层原币已无可用余额(原币剩余 ≤ 0),但业务币账面仍残留的微小尾数。该尾数不属于本次请求(不影响本次到账),但在原币下已永久无法单独执行,由平台在本次一并建立抹平计划彻底核销。C;refund_policy.write_off_cap_amount)= 每个支付 Order 各自可抹平的碎额合计上限,默认等值 USD 0.01;换算成业务币时向下取整。同一 Order 内的 Gateway 与所有 Wallet 来源先按碎额类型聚合,不会为每条来源各放一份上限;不同 Order 的额度互不借用、也不跨 Order 合计阻断。F)= 订单已发生的实际不可退支付手续费合计,financials.payment_fee.amount。N)= 改价发起方填写的新稿酬;其下限为 N ≥ F(见 4.3)。建议阅读顺序:第 1 章(一分钟上手,含会议疑问 FAQ)→ 第 2 章(接口变更)→ 第 3 章(接口示例)→ 第 4 章(字段与规则补充说明)→ 第 5 章(兼容性说明)。遇到「这个金额为什么被拒」先看第 1.3 节 FAQ 与第 4.2 节。
| 章 | 内容 | 什么时候看 |
|---|---|---|
| 1.0 符号速查 | R / M / T / C / N / F / B / S 等符号的含义与对应响应字段 | 看到符号不知道什么意思 |
| 1. 一分钟上手 | 退款次数状态机、小额与碎额流程、会议疑问 FAQ、对接要点 | 第一次接触本规则 |
| 2. 接口变更 | 改了哪些接口 | 定位影响面 |
| 3. 接口示例 | 字段与错误示例 | 写绑定 / 联调 |
| 4. 字段与规则补充说明 | 每个字段含义、改价纯差额与前端交接 | 对齐口径 |
| 5. 兼容性说明 | 上线协同与旧快照行为 | 发布前 |
面向读者:前端(用户端 + 画师端)、联调、测试。本文描述的是开发阶段契约,新增字段为向后兼容增量,错误码为新增。建议先看图再看 FAQ,最后翻字段表。
下文流程图、公式与 FAQ 使用少量单字母符号,含义与后端已落地实现一致。符号只用于阅读,前端对接一律以后端同次响应的字段为准。
| 符号 | 读作 | 含义 | 与响应字段的对应 |
|---|---|---|---|
T | 最低退款金额 | 平台最低退款金额,默认等值 USD 0.10;换算成业务币时向上取整。只限制第一次正额部分退款,全退(R = M)不受 T 限制 | refund_policy.minimum_refund_amount |
C | 执行碎额上限 | 每个支付 Order 各自可抹平的碎额合计上限,默认等值 USD 0.01;换算成业务币时向下取整。同一 Order 内的 Gateway 与所有 Wallet 来源先按碎额类型聚合,不同 Order 的额度互不借用 | refund_policy.write_off_cap_amount |
M | 剩余可退金额 | 当前剩余可退金额 = 已付业务金额 − 不可退支付手续费 − 历史实际退款 − 已应用抹平 − 其他有效占用 | refund_policy.remaining_refundable_amount(等于 financials.refund_limits.maximum) |
R | 本次请求退款金额 | 本次退款请求额(业务币):改价场景由新价格派生,取消场景由双方协商;R = M 表示全退 | financials.refund.amount |
N | 新价格 | 改价发起方填写的新稿酬,下限为 N ≥ F | 请求参数 price;响应 data.new_price |
F | 不可退支付手续费 | 该约稿已发生的实际不可退支付手续费合计 | financials.payment_fee.amount |
B | 剩余业务容量 | final closure 时某个资金来源仍对应客户可退权益的剩余业务币容量(B > 0 才可能退款) | 无独立响应字段,由后端账本事实派生 |
S | 剩余原币净额 | final closure 时某个资金来源的剩余原币净额,已扣不可退原币手续费、历史实际退款与有效预留 | 无独立响应字段,由后端账本事实派生 |
T/C是平台自定规则,不代表任何支付渠道的最低金额或限额;B/S只在 final closure(首次全退R = M与第二次退款)内部使用,不额外暴露给前端。第 4.3 节的改价纯差额公式另用局部变量P(累计实付)、O(已占用容量)、U(未占用已付金额),与上表的C(执行碎额上限)、B(final closure 剩余业务容量)不是同一个量。
一笔 Commission 生命周期内最多两次有效退款:第一次可以部分退款,第二次只能退回当前剩余全部可退金额。失败重试与幂等重放不额外计数;升价补款与无退款改价不计数,补款也不会重置次数。第一次直接全退(R = M)不关闭委托;第二次退款在全部资金动作与对账完成后把委托置为终局 refund_closed,不再接受新付款与退款。本节与下图用到 M(剩余可退金额)、R(本次请求退款金额)、T(最低退款金额)、C(每个支付 Order 的执行碎额上限),定义见 1.0 符号速查。
下图为一次退款从试算到收口的完整分支,用到 M(剩余可退金额)、R(本次请求退款金额)、T(最低退款金额)与 C(每个支付 Order 的执行碎额上限);符号定义见 1.0 符号速查。
整笔余额满足
0 < M < T时不再自动抹平:M保持开放,R = M全退走 final closure 分支(豁免最低退款金额)。未被申请的余额由取消 / 正常完成时的终局结算收口;取消是终局决定,第二次退款后的refund_closed关闭只作用于改价等继续场景,取消路径仍为user_canceled。
政策金额的取值来源(T = 最低退款金额、C = 执行碎额上限,两者来自平台后台配置并换算成业务币,定义见 1.0 符号速查):
以下四条疑问来自 2026-09-28 会议 Speaker 1 的原始提问,逐条给出结论、依据字段/错误码与对应示例。(本节继续使用 1.0 符号速查中的 T / C / M / R / N / F,读到不熟悉的符号可直接对照该表。)
结论:门槛校验的是本次请求退款额,不是「退款后的余额」。以已付 100.00、不可退支付手续费 3.00 为例(当前剩余可退金额上限为 100.00 − 3.00 = 97.00):当新价改为 99.99 时,由改价差额算出的退款额为 0.01(100.00 − 99.99 = 0.01),低于最低退款金额 0.10,因此被拒:预览 can_submit = false、disabled_reason = below_minimum_amount,正式提交返回 22022。但若派生退款额恰好等于当前剩余全部可退金额(R = M,全退),则豁免最低退款金额,即使 M < 0.10 也可提交。
依据字段 / 错误码:financials.refund.amount(本次请求退款额)、refund_policy.minimum_refund_amount、disabled_reason = below_minimum_amount、22022(CommissionRefundBelowMinimumAmount)。disabled_reason = below_minimum_amount 现在只出现在改价入口(派生退款额既低于门槛、又不等于剩余全部);取消入口的试算不再因整笔剩余低于门槛而禁用输入——用户始终可以选择 R = M 全退。
对应示例:3.0 节场景 1、场景 3、场景 4、场景 11。
请注意:不是「退款后的余额小于门槛就拒绝本次退款」。退款后余额低于门槛不会拒绝本次退款,也不会被自动抹平:余额保持开放,用户可以随时以
R = M全退;未被申请的余额由终局结算收口(见 Q2)。
结论:两件事要分开看。
N)的下限是 N ≥ F(F = 订单已发生的实际不可退支付手续费合计)。N < F 时预览 disabled_reason = below_payment_fee、can_submit = false,正式提交返回 60001(WorkTaskPriceChangeInvalid)。R = M 的全退(0.09 低于门槛也被豁免),或由取消 / 正常完成时的终局结算收口。前端无需引导用户再次提交,可按需展示「剩余 0.09 可全额退完」的引导。依据字段 / 错误码:refund_policy.minimum_refund_amount、remaining_refundable_amount、financials.payment_fee.amount、disabled_reason = below_minimum_amount / below_payment_fee、22022、60001。
对应示例:3.0 节场景 2、场景 3、场景 4、场景 5、场景 6。
不存在「离散禁退区间」:平台不会要求每个来源余款都达到最低退款金额,也不会为保护未来的退款而拒绝本次合法退款。
结论:碎额是指因货币最小精度或向下取整导致无法在支付渠道原币正常执行的极小尾差(通常等值 1 分钱)。系统将其分为两类不同性质的碎额;每个支付 Order 各有一份执行碎额上限(默认等值 USD 0.01),同一 Order 内的 Gateway 与所有 Wallet 来源先按类型聚合后再判断:
本次请求碎额(Request Write-Off Fragment):
can_submit = false,disabled_reason = write_off_cap_exceeded 或 exchange_rate_unavailable)。一个 Order 超限不会被另一个 Order 的剩余额度抵消,也不会把多个 Order 的碎额合并成一次阻断。来源残余碎额(Residual Write-Off Fragment):
source_amount 剩余 ≤ 0),但受多期换算精度影响,该来源在业务币账面上仍残留着 1 分钱的死余数。由于底层原币已无款可退,未来任何退款都无法再从该来源执行;can_submit = true),避免「为了保护未来的残差,反而拒绝用户当下完全合法的退款」;该 Order 超限的残余本次不建抹平计划、延期到终局收口,不会被静默吞掉。前端提示建议:
disabled_reason 提示即可:
disabled_reason === 'write_off_cap_exceeded' 时,提示:「本次退款的小额尾差超过平台可抹平上限,请调整金额或联系客服」。disabled_reason === 'exchange_rate_unavailable' 时,提示:「当前币种汇率暂不可用,暂不支持自动处理小额尾差,请稍后重试」。write_off_explained === true),可在明细说明中展示:「含极小系统抹平尾差 $0.01(实际到账以各渠道出款为准)」。依据字段 / 错误码:refund_policy.write_off_cap_amount、estimated_write_off_amount、write_off_cap_exceeded、write_off_explained、exchange_rate_unavailable。
对应示例:3.0 节场景 7–场景 11。
核心记忆口诀:
- 本次请求碎额:本次退款里的钱,渠道退不出 0 元,平台账面抹平它,客户实收扣减它,同一 Order 内超限才阻断本次。
- 来源残余碎额:本次退完后的残余(底层原币已退尽),平台顺手核销它,客户实收不扣它,超限不阻断本次,延期到终局收口。
结论:计的是有效退款次数(非作废退款单最多 2 笔),不是改价次数。
22024(CommissionRefundFinalRefundMustBeRemaining),预览对应 disabled_reason = final_refund_must_be_remaining;第二次退款全部来源成功对账后 WorkTask 置 refund_closed,不再接受付款与退款。第三次返回 22023(CommissionRefundAttemptsExhausted),但它现在只是异常数据防御——正常流程下 WorkTask 已在第二次退款时关闭。N ≥ F。当 N = F 时刚好把剩余可退金额全部退完,但新价格仍是发起方填写的新稿酬。依据字段 / 错误码:refund_policy.attempts_used、attempts_remaining、final_refund_only、disabled_reason、22023、22024、60001、work_tasks.status = refund_closed。
对应示例:3.0 节场景 12–场景 16。
(本节与第 3 章的 R / M / T / C 均见 1.0 符号速查。)
POST …/cancellation/preview 与 POST …/work_task_price_changes/preview 的 refund_policy 直接给出 minimum_refund_amount、remaining_refundable_amount、attempts_used、attempts_remaining、final_refund_only、write_off_cap_amount、estimated_write_off_amount、write_off_cap_exceeded、write_off_explained、exchange_rate_unavailable;同一个 Commission 的改价对象、退款债权与取消对象也返回同一组政策字段,前端不要自行重算门槛、次数或手续费。disabled_reason 只描述退款额输入 / 本次固定退款是否可用,与 can_submit 相互独立:
below_minimum_amount:仅改价入口返回,表示由改价差额算出的退款额低于最低退款金额且不等于剩余全部(提交禁用);取消入口不再因整笔剩余低于门槛而禁用输入,用户始终可选 R = M 全退。refund_attempts_exhausted:两次机会已用完(正常流程下 WorkTask 已 refund_closed,此原因仅异常数据防御)。final_refund_must_be_remaining:第二次由改价差额算出的退款额不等于剩余全部可退金额。write_off_cap_exceeded:本次退款中某个支付 Order 的请求碎额合计超过该 Order 的执行碎额上限,预览即阻断;仅另一个 Order 的残余碎额超限不产生本原因、不阻断本次合法退款。exchange_rate_unavailable:该币种缺少 USD 汇率,换算不可用且禁止自动抹平。below_payment_fee:改价新价格低于不可退支付手续费合计 F。R = M)与第二次退款进入同一个 final closure:不判断最低退款金额、不做碎额准入、不依赖当前退款汇率,业务币缺少 USD 汇率也不影响全退;执行期间暂停创建新付款,全部资金来源成功对账后本次退款完成。paying Order、待处理 checkout session 或未完成的改价补款时拒绝创建(22005),需等待其完成或失败收口后再提交;创建后到账的旧支付走人工复核(Stripe / Alipay 返回 21013,PayPal 返回 21001),不并入已确认计划。22026);final closure 的 final_closure 抹平不计入 estimated_write_off_amount(该字段只统计普通部分退款的碎额计划),也不使 write_off_explained 为 true。minimum_refund_amount(且不等于剩余全部)、两次机会已用完、或第二次不等于剩余全部时,disabled_reason 给出对应原因且 can_submit = false(同一个新价格没有「零退款」的等价提交);升价补款与无退款改价(退款额 0)不受影响,仍为 can_submit = true。attempts_remaining = 1(即 final_refund_only = true)时,第二次退款金额必须精确等于 remaining_refundable_amount;提交部分金额会收到 22024。{ amount, currency } 结构,amount 是业务币最小单位整数;minimum_refund_amount 与 remaining_refundable_amount 都是平台规则值,不表示渠道最低金额。示例中的 USD 数值不得直接套用到人民币等其它币种。estimated_write_off_amount 是预计不支付的极小尾差,只统计在生效上限内的抹平计划(本次请求碎额 + 本次可应用的来源残余碎额);某个 Order 超过该 Order 上限的残余不计入,它延期到终局收口,既不阻断本次也不被静默吞掉。整笔剩余低于最低退款金额时不再自动抹平:余额保持开放,R = M 全退始终可提交(全退豁免最低退款金额),未被申请的余额由取消 / 正常完成时的终局结算收口。work_tasks.status 变为 refund_closed,该状态不再接受付款、改价、取消与退款;首次全退处理期间暂停创建新付款,成功对账且委托仍可继续后恢复。普通部分退款不冻结收款(等待选择去向或执行中的拦截由既有付款校验规则承担)。付款入口在 refund_closed 时返回 22027(CommissionRefundClosedPaymentBlocked),在 final closure 资金动作未结清时返回 22013(CommissionRefundExecutionIncomplete)。22022 正额部分退款低于最低退款金额(不含全退 R = M);22023 两次机会已用完;22024 第二次必须退剩余全部;22025 抹平数据完整性校验失败(fail-closed,按系统异常处理);22026 正额部分退款的所有来源原币向下取整为 0(不创建、不占次数;final closure 纯抹平全退不走此拒绝);22027 委托已因最终退款关闭,不接受新付款;21013 冻结资金集合前发起的旧支付晚到账(Stripe / Alipay;PayPal 为 21001),需人工处理;改价新价格低于不可退支付手续费 60001;改价旧条款变化 60002。N ≥ F。N < F 时 preview 返回 disabled_reason = below_payment_fee,financials.payment_fee.amount 显示手续费金额;直接调用 create 返回 60001。cancellation/request 使用 idempotency_key,重放或失败重试不消耗新次数、不重复抹平;已抹平的剩余不会再次成为可退余额。| 文档 | 内容 | 什么时候看 |
|---|---|---|
| 2026-09-09_commission_cancellation_and_refunds.md | 取消/改价/退款领域模型、字段字典、端点详解(financials、退款上限、去向能力) | 需要整体领域模型或字段全表 |
| 2026-09-21_commission_refund_notifications.md | 退款通知与页面事件(站内信场景、worktask_page_event_list.type) | 对接通知与待办入口 |
| 2026-09-22_commission_refund_auto_destination.md | 退款去向七天未选自动执行(destination_deadline_at) | 对接退款去向倒计时与自动选定 |
| 2026-09-22_net_paid_amount.md | 约稿详情/列表净已支付金额(展示口径,net_paid_amount) | 展示合同覆盖净额与支付进度 |
| 本文 | 退款政策与金额口径(最低退款金额、两次退款、按支付 Order 的碎额抹平、最终关闭、改价纯差额) | 判断某次退款/改价为什么被拒或为什么被抹平 |
原
2026-09-27_price_change_pure_difference_refund.md(改价纯差额)与2026-09-22_price_change_preview_credit_allocation_fix.md(credit 分配修复)已并入本文并删除;后台财务与其它管理后台接口文档不再保留在对外api-changes目录。
POST /api/work_tasks/cancellation/preview
refund_policy 新增小额退款政策字段;⚠️ 顶层 disabled_reason 新增 refund_attempts_exhausted 取值;below_minimum_amount 不再由取消入口返回(整笔剩余低于门槛时仍可选择 R = M 全退)。POST /api/work_tasks/cancellation/request
22022 / 22023 / 22024;⚠️ 全退(R = M)豁免最低退款金额,0 < M < T 的小额余额可选择全退,不再返回 22022 或自动抹平;✨ 全部来源原币向下取整为 0 时拒绝并返回 22026,不占退款次数。POST /api/work_tasks/cancellation/accept
22022 / 22023 / 22024 / 22026;全退(R = M)豁免最低退款金额。POST /api/work_task_price_changes/preview
refund_policy 新增政策字段;⚠️ 顶层 disabled_reason 新增 below_minimum_amount、refund_attempts_exhausted、final_refund_must_be_remaining、write_off_cap_exceeded、exchange_rate_unavailable、below_payment_fee 取值;被政策拒绝时 can_submit = false。⚠️ 全退(派生 R = M,含小额余额)豁免最低退款金额与碎额准入,below_minimum_amount 只用于非全退的部分降价。POST /api/work_task_price_changes/create
F 时拒绝并返回 60001;用户端本接口只落待批改价,政策拒绝(22022 / 22023 / 22024 / 22026)发生在 approve 阶段,画师端直连退款单、在本接口返回;无退款改价与升价补款不受门槛与次数影响。POST /api/work_task_price_changes/approve
22022 / 22023 / 22024 / 22026;条款与快照不符返回 60002。POST /api/artist_center/work_tasks/cancellation/preview
refund_policy 新增政策字段,⚠️ disabled_reason 新增 refund_attempts_exhausted 取值(below_minimum_amount 不再由取消入口返回)。POST /api/artist_center/work_tasks/cancellation/request
22022 / 22023 / 22024 / 22026;全退(R = M)豁免最低退款金额。POST /api/artist_center/work_tasks/cancellation/accept
POST /api/artist_center/work_task_price_changes/preview
refund_policy 新增政策字段,⚠️ disabled_reason 新增取值(含 below_payment_fee)且被拒时 can_submit = false。POST /api/artist_center/work_task_price_changes/create
60001;降价退款适用政策拒绝 22022 / 22023 / 22024 / 22026。POST /api/artist_center/work_task_price_changes/approve
60002。以下场景使用同一种业务币,其最低退款金额 = 0.10、执行碎额上限 = 0.01(平台默认的 USD 0.10 / USD 0.01 等值)。表中「本次请求退款额」即 R、「剩余可退金额」即 M、「最低退款金额」即 T,符号定义见 1.0 符号速查。金额均为业务币最小单位整数,示例数值与测试实测一致,不得把 USD 数字直接套用到人民币等其它币种。
字段说明:表中「剩余可退金额」为发起本次操作前该委托当前的最大可退容量上限(即
financials.refund_limits.maximum与refund_policy.remaining_refundable_amount,等于累计实付 − 不可退支付手续费 − 历史占用),它不是改价后的新合同金额(新价),也不是退款执行后的未来剩余。例如场景 1 中累计实付 100.00、不可退支付手续费 3.00,因此操作前剩余可退金额为 100.00 − 3.00 = 97.00。
场景 15 前提:
22023仅位于“异常数据仍可操作”的分支。正常流程下第二次退款对账完成后委托已refund_closed:改价返回22007(状态不允许),取消入口直接不可发起,不会再走到退款政策层。
| 场景 | 渠道 | 本次请求退款额 | 剩余可退金额 | 最低退款金额 | 已用次数 | 预览 can_submit | 预览 disabled_reason | 正式提交结果 |
|---|---|---|---|---|---|---|---|---|
| 1 改价 100.00 → 99.99(已付 100.00、手续费 3.00) | 改价 | 0.01 | 97.00 | 0.10 | 0 | false | below_minimum_amount | 22022(非全退的部分降价) |
| 2 改价 100.00 → 99.90(已付 100.00、手续费 3.00,差额 = 0.10 = 门槛) | 改价 | 0.10 | 97.00 | 0.10 | 0 | true | null | 成功 |
| 3 剩余 10.00 退 9.90(退款后余额 0.10) | 取消 | 9.90 | 10.00 | 0.10 | 0 | true | null | 成功;余 0.10 后续仍可退 |
| 4 剩余 10.00 退 9.91(退款后余额 0.09) | 取消 | 9.91 | 10.00 | 0.10 | 0 | true | null | 成功;余 0.09 保持开放,可随时以 R = M 全额退完 |
| 5 新价 ≥ 手续费(已付 600.00、手续费 27.71、新价 550.00) | 改价 | 50.00 | 572.29 | 0.10 | 0 | true | null | 成功;新价下限 N ≥ F 通过 |
| 6 新价 < 手续费(已付 600.00、手续费 27.71、新价 20.00) | 改价 | — | 572.29 | 0.10 | 0 | false | below_payment_fee | 60001 |
| 7 同一 Order 本次请求碎额 0.01(在该 Order 上限内) | 取消 | 1.00 | ≥ 1.00 | 0.10 | 0 | true | null | 成功;estimated_write_off_amount = 0.01 |
| 8 同一 Order 本次请求碎额 0.02(Gateway + Wallet 各 0.01,超该 Order 上限) | 取消 | — | ≥ 0.02 | 0.10 | 0 | false | write_off_cap_exceeded | 被拒(预览即阻断) |
| 8b 两个不同 Order 各 0.01 本次请求碎额 | 取消 | 2.00 | ≥ 2.00 | 0.10 | 0 | true | null | 成功;每个 Order 各用一份上限,合计可抹平 0.02 |
| 9 同一 Order 仅来源残余碎额 0.02(本次请求干净) | 取消 | 5.00 | ≥ 7.00 | 0.10 | 0 | true | null | 成功;残余超限不阻断本次,延期到终局收口 |
| 10 业务币缺 USD 汇率且本次请求带碎额 | 取消 | — | ≥ 0.01 | 不可换算 | 0 | false | exchange_rate_unavailable | 被拒(禁止自动抹平) |
| 11 整笔剩余 0.08(低于门槛)选择全退 | 取消 / 改价 | 0.08(R = M) | 0.08 | 0.10 | 0 | true | null | 成功;全退豁免门槛,不做抹平 |
| 11b 整笔剩余 0.08 却只申请部分(如 0.05) | 取消 / 改价 | 0.05 | 0.08 | 0.10 | 0 | 取消 true / 改价 false | 取消 null / 改价 below_minimum_amount | 22022(余额状态不变,全退仍可用) |
| 12 第一次部分退款 | 取消 / 改价 | 2.00 | 10.00 | 0.10 | 0 | true | null | 成功;attempts_used 变 1 |
| 13 第二次退部分(如 2.00) | 取消 / 改价 | 2.00 | 8.00 | 0.10 | 1 | false(改价) | final_refund_must_be_remaining | 22024 |
| 14 第二次退剩余全部(8.00) | 取消 / 改价 | 8.00 | 8.00 | 0.10 | 1 | true | null | 成功;全部来源对账后 WorkTask 置 refund_closed |
| 15 第三次请求 | 取消 / 改价 | 任意 | 0 | 0.10 | 2 | false | refund_attempts_exhausted | 22023(仅异常数据防御,正常流程委托已关闭) |
| 16 升价补款 / 无退款改价 | 改价 | 0 | 不变 | 0.10 | 不变 | true | null | 成功;不占次数、不重置次数 |
| 17 全部来源原币向下取整为 0 的部分退款 | 取消 / 改价 | 1.00 | ≥ 1.00 | 0.10 | 0 | — | — | 22026;不创建、不占次数、不建抹平 |
18 final closure 中某来源 B > 0 且 S = 0 | 取消 / 改价 | B(全退) | M | 不判断 | 0 或 1 | true | null | 该来源差额记 final closure 抹平,其余来源逐来源退回原币净额 |
POST /api/work_tasks/cancellation/previewrefund_policy 新增政策字段;⚠️ disabled_reason 新增 below_minimum_amount、refund_attempts_exhausted。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | number | 是 | WorkTask id |
business_refund_amount | number | 否 | 期望退款额(业务币最小单位);不传时后端给出默认建议值 |
金额对象的
currency实际还包含id、symbol、is_zero_decimal,此处按节选约定省略;下同。
无新增错误码;沿用试算原有的计算事实与状态校验。
POST /api/work_tasks/cancellation/request22022 / 22023 / 22024 / 22026;全退(R = M)豁免最低退款金额。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | number | 是 | WorkTask id |
business_refund_amount | number | 否 | 本次请求退款额(业务币最小单位);0 表示零退款取消 |
idempotency_key | string | 是 | 幂等键,长度 8–128 |
refund_destination | string | 否 | 退款去向偏好:original(原路退回,默认)、credit(站内 Credit 钱包) |
400:正额部分退款低于最低退款金额(全退 R = M 豁免,即使整笔剩余低于门槛也可提交)
400:全部来源原币向下取整为 0,本次退款无法实际出款
400:两次退款机会均已用完
400:第二次退款必须退回剩余全部可退金额
POST /api/work_tasks/cancellation/acceptcancellation/request;全退(R = M)豁免最低退款金额。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id | number | 是 | 取消申请 id |
refund_destination | string | 否 | 退款去向偏好:original 或 credit |
同 POST /api/work_tasks/cancellation/request 的 22022 / 22023 / 22024 / 22026。
POST /api/work_task_price_changes/previewmax(0, 未占用已付金额 − 新价格);新价格必须满足 N ≥ F。refund_policy 新增政策字段;⚠️ disabled_reason 新增 below_minimum_amount、refund_attempts_exhausted、final_refund_must_be_remaining、write_off_cap_exceeded、exchange_rate_unavailable、below_payment_fee;被政策拒绝时 can_submit = false。can_submit 判定与实际响应一致:below_minimum_amount、refund_attempts_exhausted、final_refund_must_be_remaining、write_off_cap_exceeded、exchange_rate_unavailable、below_payment_fee 都表示本次由改价差额算出的退款/改价本身不可执行,降价又没有「零退款」的同价提交,因此一律 can_submit = false;仅来源残余碎额超限、合法升价与无退款改价不受影响,仍为 can_submit = true。在已付款且派生退款恰好等于剩余全部可退金额(R = M)时,上述 below_minimum_amount、write_off_cap_exceeded、exchange_rate_unavailable 与碎额准入都不适用,仍为 can_submit = true。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_id | number | 是 | WorkTask id |
price | number | 是 | 新价格(业务币最小单位),最小 0 |
已付 600.00、不可退支付手续费 27.71、新价 550.00:由改价差额算出的退款额为 50.00。
已付 100.00、不可退支付手续费 3.00(当前剩余可退金额上限 97.00)、新价 99.99:退款额 0.01 低于最低退款金额 0.10。
已付 600.00、不可退支付手续费 27.71、新价 20.00。
无新增错误码;试算只返回 can_submit 与 disabled_reason,正式提交在 create / approve 阶段返回 22022 / 22023 / 22024 / 22026 / 60001 / 60002。
POST /api/work_task_price_changes/createF 时拒绝并返回 60001;降价产生的正额退款适用政策门槛与次数限制;升价补款、无退款改价不受影响。用户端 create 只落待批改价、不建退款单,政策拒绝(22022 / 22023 / 22024 / 22026)发生在 approve(建单)阶段;画师端 create 直接建单,政策拒绝发生在该接口。试算响应的 can_submit = false(见 …/price_changes/preview)是前端的提前阻断依据。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_id | number | 是 | WorkTask id |
price | number | 是 | 新价格(业务币最小单位),最小 0 |
refund_destination | string | 否 | 退款去向偏好(降价时可选:original 原路、credit 站内余额) |
400:新价格低于不可退支付手续费合计
用户端:本接口不返回 22022 / 22023 / 22024 / 22026 政策拒绝,这些在 approve 阶段返回,语义同上。画师端:同 22022 / 22023 / 22024 / 22026。
POST /api/work_task_price_changes/approve60002。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | number | 是 | 改价申请 id |
同 22022 / 22023 / 22024 / 22026;条款与快照不符时:
POST /api/artist_center/work_tasks/cancellation/previewPOST /api/work_tasks/cancellation/preview 相同;role_view 为画师视角。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | number | 是 | WorkTask id |
business_refund_amount | number | 否 | 期望退款额(业务币最小单位) |
同用户端示例,refund_policy 新增字段一致。
无新增错误码。
POST /api/artist_center/work_tasks/cancellation/request22022 / 22023 / 22024 / 22026。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | number | 是 | WorkTask id |
business_refund_amount | number | 否 | 本次请求退款额(业务币最小单位) |
idempotency_key | string | 是 | 幂等键,长度 8–128 |
画师端发起取消时不传
refund_destination参数;款项退还给买家,退款去向由买家在接受时选择或由系统后续规则处理。
同用户端 22022 / 22023 / 22024 / 22026。
POST /api/artist_center/work_tasks/cancellation/accept| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id | number | 是 | 取消申请 id |
同 22022 / 22023 / 22024 / 22026。
POST /api/artist_center/work_task_price_changes/previewPOST /api/work_task_price_changes/preview 相同(同一计算链路),退款额按纯差额计算,refund_policy 新增政策字段,disabled_reason 新增取值(含 below_payment_fee),被拒时 can_submit = false。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_id | number | 是 | WorkTask id,须属于当前画师 |
price | number | 是 | 新价格(业务币最小单位) |
无新增错误码;create / approve 阶段返回 22022 / 22023 / 22024 / 22026 / 60001 / 60002。
POST /api/artist_center/work_task_price_changes/create60001;降价退款适用政策拒绝 22022 / 22023 / 22024 / 22026。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_id | number | 是 | WorkTask id |
price | number | 是 | 新价格(业务币最小单位) |
已付 600.00、手续费 27.71、新价 550.00,差额 50.00 即时生成退款单。
同 22022 / 22023 / 22024 / 22026 / 60001 / 60002。
POST /api/artist_center/work_task_price_changes/approve| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | number | 是 | 改价申请 id |
同 22022 / 22023 / 22024 / 22026 / 60002。
refund_policy 新增政策字段(T / C / M 等符号的含义与字段对应见 1.0 符号速查。)
以下字段由已付款的取消试算(cancellation/preview)与改价试算(work_task_price_changes/preview)返回;同一个 Commission 的改价对象、退款债权与取消对象也返回同一组政策字段。未付款试算(无可退额度)不返回这些政策字段。
| 字段 | 类型 | 说明 |
|---|---|---|
minimum_refund_amount | Money | 平台最低退款金额,默认等值 USD 0.10;业务币按汇率向上取整。只限制第一次正额部分退款,全退(R = M)豁免、不受门槛约束;汇率不可换算时为 0,以 exchange_rate_unavailable 为准 |
remaining_refundable_amount | Money | 当前剩余可退金额(等于 financials.refund_limits.maximum) |
attempts_used | number | 已使用的退款机会数(按非作废退款单计,最大 2) |
attempts_remaining | number | 剩余退款机会数(2 − attempts_used) |
final_refund_only | boolean | true 表示下一次退款只能退剩余全部;等价于 attempts_remaining = 1 |
write_off_cap_amount | Money | 每个支付 Order 各自可抹平的执行碎额合计上限,默认等值 USD 0.01;业务币向下取整。同一 Order 内的 Gateway 与 Wallet 来源先按类型聚合 |
estimated_write_off_amount | Money | 本次试算预计不支付的碎额合计,只统计在生效上限内的抹平计划(本次请求碎额 + 本次可应用的来源残余碎额);某 Order 超限、延期到终局收口的残余不计入,也不阻断本次;final closure 的 final_closure 抹平同样不计入;整笔低余额不再有兜底抹平 |
write_off_cap_exceeded | boolean | true 表示某个支付 Order 的本次请求碎额合计超过该 Order 的上限、本次请求无法完整履约,预览即阻断;另一 Order 的残余碎额超限不产生本值 |
write_off_explained | boolean | true 表示本次存在可说明的抹平金额(生效上限内 estimated_write_off_amount > 0) |
exchange_rate_unavailable | boolean | true 表示业务币种缺少 USD 汇率,USD 基准的门槛与碎额上限换算不可用:上表两个换算金额字段退化为 0,不代表 USD 等值,且禁止任何自动抹平(含带碎额的本次请求会被阻断);全退不受影响 |
refund_policy 同时携带既有的去向能力字段 maximum_policy、can_exceed_standard、can_refund_to_credit、has_stripe_connected_order、all_orders_stripe_connected、has_unknown_order(语义见《2026-09-09_commission_cancellation_and_refunds.md》),本次未改动。
disabled_reason 取值(本节出现的 F、R = M 等符号见 1.0 符号速查。)
| 取值 | 含义 | 前端处理 |
|---|---|---|
calculation_incomplete | 计算事实未就绪 | 禁止提交,展示 issues |
no_refundable_amount | 无可退额度(未付款或已退完) | 退款额输入禁用,零退款业务仍可提交 |
below_minimum_amount | 仅改价入口:由改价差额算出的退款额低于最低退款金额,且不等于剩余全部可退金额 | 提交禁用(can_submit = false),提示「本次由改价差额算出的退款额低于最低退款金额」;取消入口不再返回本原因,整笔剩余低于门槛时仍可选择 R = M 全退 |
refund_attempts_exhausted | 两次退款机会已用完 | 退款额输入禁用,提示已无退款机会(提交 22023);正常流程下委托已 refund_closed,本原因仅异常数据防御 |
final_refund_must_be_remaining | 第二次由改价差额算出的退款额不等于剩余可退金额(仅改价入口) | 提交禁用(can_submit = false),说明第二次只能退回剩余全部可退金额(提交 22024) |
write_off_cap_exceeded | 某个支付 Order 的本次请求碎额合计超过该 Order 的执行碎额上限 | 提交禁用,说明本次退款的小额尾差超过平台可抹平上限;另一 Order 的残余碎额超限不产生本原因、不阻断本次合法退款 |
exchange_rate_unavailable | 业务币种缺少 USD 汇率且本次请求需要抹平碎额 | 退款额输入/提交禁用,提示稍后重试或联系客服;换算不可用期间禁止自动抹平 |
below_payment_fee | 改价新价格低于不可退支付手续费合计 F(仅改价入口) | 提交禁用(can_submit = false),提示「新稿酬不能低于已发生的支付手续费」;提交会被 60001 拒绝 |
below_minimum_amount现在只由改价入口返回(派生退款额不足且不等于剩余全部);取消入口不再返回本原因,整笔剩余低于门槛时仍可选择R = M全退。原文档曾把「整笔剩余不足」也写成取消入口的below_minimum_amount,本次修正。
改价降价退款额按业务纯差额计算,不再预先扣减支付手续费:
这里的
P/O/U是本节公式的局部变量,不是 1.0 符号速查里的C(执行碎额上限)或B(final closure 剩余业务容量);R/N/F则与速查表同义。
estimated_artist_net 反映 新稿酬 − 实际支付手续费 − 平台费),不会在改价时重复扣费,也不会把手续费当成残余抹平。N ≥ F;N < F 时预览 disabled_reason = below_payment_fee、can_submit = false,create 返回 60001。下限与最低退款金额是两个独立门槛,必须分别满足。U = P − O),不会因累计 paid_amount 未扣减而重复退款。newPrice > oldPrice(升价)时退款额严格为 0,不派生退款、不触发退款政策限制,按现有 need_pay_amount 补款链路处理(用户发起升价直接进入待付款 WAIT_PAY,画师发起升价先进入待审批 PENDING);newPrice == oldPrice(同价)时禁止发起改价,preview 允许试算并返回退款额 0,但 create 会校验拦截并返回 60001(WorkTaskPriceChangeInvalid,提示同价不可改价)。Pending / WaitPay / Working),非法状态返回 22007(RefundWorkTaskStatusInvalid);存在进行中支付订单(paying)时,preview 返回 22005(RefundPaymentDataIncomplete),create 经互斥服务返回 20001(WorkTaskHasPayingOrder)。22005(RefundPaymentDataIncomplete)。(本节 R / M / T / C / N / F 均见 1.0 符号速查。)
本节目标是让前端在输入层就把非法值拦住,不等接口报错再提示。所有约束的取值都来自同一次预览响应(取消用 cancellation/preview,改价用 work_task_price_changes/preview),前端不要自行换算币种、重算次数、手续费或汇率。改价对象 / 退款债权 / 取消对象也返回同一组 refund_policy 字段,可在二次进入时直接复用。
分层约定:4.4.1 / 4.4.2 是前端可主动拦截的部分(优先级最高,输入层拦掉)→ 4.4.3 是前端无法预防、必须写专门文案的部分 → 4.4.4 是输入层已拦截、服务端仍可能返回的兜底文案(优先级低于 4.4.1 / 4.4.2)→ 4.4.5 无需单独处理。
改价场景(用户输入的是新价格 N,不是 R)
| 输入约束 | 规则 | 依据字段 | 拦掉的错误 |
|---|---|---|---|
N 下限 | 降价分支要求 N ≥ F(F ≤ old_price 时输入框 min 直接设为 F) | financials.payment_fee.amount(F) | below_payment_fee / 60001 |
N 上限 | 不设上限 | — | 升价合法,派生 R = 0 走补款链路 |
派生退款额 R | 只读展示 financials.refund.amount,前端不自算 | financials.refund.amount | 与后端纯差额口径漂移 |
| 同价 | N == old_price 不可改价(属改价条款校验,不属退款政策);可在输入层直接禁用同价提交 | old_price | 60001 |
第二次改价(final_refund_only = true) | 只要选择降价,派生 R 必须等于 M;把 N 锁定到使 R = M 的唯一值并提示「本次降价将退回全部剩余金额」 | refund_policy.final_refund_only、financials.refund.amount、refund_policy.remaining_refundable_amount | 22024 / final_refund_must_be_remaining |
升价 / R = 0 | 不触发退款政策,正常提交(不占次数、不重置次数) | — | — |
第二次降价为什么只能取唯一新价格:由改价差额算出的退款额为
R = max(0, U − N)(U为未占用已付金额,见 4.3),而当前剩余可退金额M = refund_policy.remaining_refundable_amount。两式相减可得R = M ⟺ N = U − M:
- 用响应字段表达即
N = financials.refund_limits.absolute.amount − refund_policy.remaining_refundable_amount.amount(absolute已扣历史退款与抹平,即U)。- 当
maximum_policy = standard(can_exceed_standard = false,绝大多数场景)时该值等于不可退支付手续费F(financials.payment_fee.amount),即「N = F时刚好退完剩余全部」;- 当
maximum_policy = stripe_connected_absolute(can_exceed_standard = true,全部为纯 Stripe Connect destination charge)时该值为0。因此前端不要硬编码
F,直接按financials.refund.amount === refund_policy.remaining_refundable_amount判断是否满足final_refund_only即可;N < F已被below_payment_fee拦掉,N > U − M派生出的R < M会被final_refund_must_be_remaining/22024拒绝。边界:
maximum_policy = stripe_connected_absolute(全部为纯 Stripe Connect destination charge,且手续费由画师连接账户承担)时M = U,公式给出的N = 0会先被新价下限N ≥ F(below_payment_fee/60001)拦下,改价入口无法派生R = M;这种形态下前端以预览返回的can_submit/disabled_reason为准,是否需要改用取消协商入口(取消可直接协商R = M)由业务决定。
取消场景(用户输入的是协商退款额 R)
⚠️ 取消预览在无固定请求金额时不返回
below_minimum_amount(小额时disabled_reason = null):服务端不替前端禁用输入,必须由前端自己限制。
| 输入约束 | 规则 | 依据字段 |
|---|---|---|
| 合法值集合 | {0} ∪ [T, M]:部分退款 [T, M)、全退 R = M(豁免 T,必须始终可选)、零退款 R = 0 | refund_policy.minimum_refund_amount(T)、refund_policy.remaining_refundable_amount(M) |
| 上限 | R ≤ M;输入框 max 设为 M | refund_policy.remaining_refundable_amount |
小额 0 < M < T | 合法值只剩 {0, M}([T, M) 为空);输入组件降级为「不退 / 全退」二选一 | 同上 |
第二次退款(final_refund_only = true) | 正额条款只有 M 一个值:隐藏自由输入,只提供「退全部剩余(M)」;零退款取消仍可选 | refund_policy.final_refund_only、refund_policy.remaining_refundable_amount |
M = 0 | 只有 {0}:隐藏退款输入,仅展示「无剩余可退金额」 | refund_policy.remaining_refundable_amount(或 financials.refund_limits.maximum) |
不能把合法区间写成
T ≤ R < M:R = M是合法的全退,写成半开区间会误伤全退。正确写法是R = 0、或T ≤ R < M、或R = M(等价于{0} ∪ [T, M])。
minimum_refund_amount在exchange_rate_unavailable = true时退化为0,此时不要把它当真实门槛;disabled_reason非空也不一定代表不能提交:no_refundable_amount时can_submit = true,零退款取消仍可提交(见 4.2 与 1.4)。
| 场景 | 拦截方式 | 依据字段 |
|---|---|---|
WorkTask 已 refund_closed | 隐藏付款 / 改价 / 取消全部入口 + 展示终局关闭文案 | work_tasks.status(终局枚举值 refund_closed,本次新增,前端必须适配) |
M = 0(无可退余额) | 隐藏退款输入,仅展示「无剩余可退金额」 | refund_policy.remaining_refundable_amount(或 financials.refund_limits.maximum) |
attempts_remaining = 0 | 同 refund_closed 处理(异常数据防御,正常流程不可达) | refund_policy.attempts_remaining |
| 退款单处理中(final closure 执行期间) | 付款按钮禁用 + 「退款处理中」提示(服务端 22013 兜底) | commission_refunds/list 每笔的 obligation_status / execution_status;建议以服务端 22013 为准 |
「退款单处理中」的本地判断依据是
commission_refunds/list的每笔退款单:obligation_status = open,或execution_status不在{completed, not_required},都表示资金动作(含画师侧追回与渠道对账)尚未结清。但普通部分退款等待选择去向时不应冻结收款(本次设计明确普通部分退款不冻结收款),前端只做「正在执行」的近似禁用即可,最终以服务端22013为准,避免误拦合法付款;final_closure标记不在列表响应里,本判断无需精确复刻服务端口径。
| 错误码 | 场景 | 文案方向 |
|---|---|---|
22026 | 请求金额 ≥ T,但全部分配到各来源后取整为 0(纯分配结果,输入层不可预测) | 「该金额在各支付渠道均无法实际出款,请调整金额或联系客服」 |
22005 | 填表期间另一端发起了付款 / 资金事实待核实(竞态窗口) | 「存在未完成的支付或资金数据待核实,请稍后重试」 |
| 错误码 | 被什么拦截 | 兜底文案方向 |
|---|---|---|
60001 | 4.4.1 改价 N ≥ F 下限 | 「新价格不能低于已发生的支付手续费」 |
22022 | 4.4.1 取消 R ∈ {0} ∪ [T, M] | 「本次退款金额低于平台最低退款额」 |
22024 | 4.4.1 二次锁定 M | 「第二次退款只能退回全部剩余金额」 |
22027 | 4.4.2 refund_closed 隐藏入口 | 「该委托已因退款完成关闭,无法付款」 |
22013 | 4.4.2 处理中禁用按钮 | 「退款处理中,暂不可付款」 |
21013(Stripe / Alipay)/ 21001(PayPal) | 支付侧竞态(冻结资金集合前发起的旧支付晚到账转人工),前端无法预防 | 「该笔支付需要人工核实,请留意通知」——两码渠道不同,都要映射 |
22023 / 22007 | 异常数据防御 | 通用「操作不可用」即可 |
60002 | 改价条款竞态(条款已被对方更新) | 「条款已被对方更新,请刷新后重试」 |
22025 / 22006 等 fail-closed 系统类错误按既有「系统异常」统一处理即可。below_minimum_amount 等预览 disabled_reason 提示逻辑保留现状(4.2 的提示文案仍适用);本节只补充「输入层前置拦截」,不替换 disabled_reason 提示。below_minimum_amount 只出现在改价入口,提示「本次由改价差额算出的退款额低于最低退款金额」;取消入口的小额余额可选择 R = M 全退,不再出现本原因。refund_attempts_exhausted → 「已无可用的退款机会」;final_refund_must_be_remaining → 「第二次退款仅支持退回剩余全部可退金额」;below_payment_fee → 「新稿酬不能低于已发生的支付手续费」;write_off_cap_exceeded → 「本次退款的小额尾差超过平台可抹平上限」。不要写「某渠道最低退款额为 X」。final_refund_only = true,或 attempts_remaining = 1)。disabled_reason 非空且 can_submit = true 时只表示退款额输入不可用,零退款取消、升价补款、无退款改价仍可提交;改价降价的固定退款被政策拒绝时 can_submit = false,前端应直接禁用提交而不是允许重试。F(financials.payment_fee.amount)约束(N ≥ F),不再用 paid_amount 作为下限;提交前调用 preview,按 can_submit 与 disabled_reason 控制按钮与提示。改价退款金额必须取自后端响应的 financials.refund.amount,禁止前端用 paid_amount 减新价计算。pipipen-front 由前端负责人实现,本仓库(pipipen-api / pipipen-docs)只读参考。paid_amount)以下为对 pipipen-front 仓库检索核对的 5 处历史绑定,前端负责人维护时请按建议处理(行号以当时检索为准):
pages/user_center/work_tasks.vue 列表页支付进度百分比
(item.paid_amount / item.price) * 100。paid_amount 保持不变,若合同降价可能计算出大于 100% 的异常进度;降价后又升价时简单截断又会掩盖待补款。net_paid_amount。百分比计算注意防御零价:item.price <= 0 ? 100 : (item.net_paid_amount / item.price) * 100。严禁在前端使用 min(paid_amount, price) 截断。pages/user_center/work_task_details.vue 约稿详情金额组件展示
paid_amount。net_paid_amount;展示付款历史流水时保留 paid_amount 并标注为「累计实付」。pages/user_center/work_task_details.vue 详情页支付进度条
paid_amount / price。price <= 0 ? 100 : (net_paid_amount / price) * 100,确保退款与调价后的进度条落在当前合同真实进度区间。严禁用前端 min(paid_amount, price) 简单截断掩盖口径。pages/user_center/work_task_details.vue 与 pages/artist_center/worktask_info.vue 改价弹窗下限校验与提示
:min 硬编码绑定为 paid_amount,并在改价提交逻辑中存在前端拦截 modify_price < paid_amount,触发提示 change_price_tip2(“修改后的稿酬不能小于已支付的稿酬”)。modify_price < paid_amount 的前端强制下限拦截;纯差额业务允许降价至 paid_amount 以下(产生退款)。F(preview 返回的 financials.payment_fee.amount)约束(N ≥ F)。preview,依据返回的 can_submit 与 disabled_reason 动态控制提交按钮与提示文案(如 disabled_reason === 'below_payment_fee' 时提示「新稿酬不能低于支付手续费」)。financials.refund.amount,禁止前端自行用 paid_amount 减新价计算。pages/user_center/application_details.vue 企划详情支付百分比
paid_amount。price <= 0 ? 100 : (net_paid_amount / price) * 100,严禁前端截断。为什么严禁前端使用 min(paid_amount, price) 简单截断? 截断方案与真实合同覆盖额 net_paid_amount 在存在退款的场景下完全不等价。以「付 100 → 退 50 → 升 80」为例:paid_amount 始终是 100(单调不可逆流水),当前合同留存 net_paid_amount 是 50;若前端用 min(paid_amount, new_price) / new_price 计算新价覆盖率,会得出 min(100, 80) / 80 = 100%,把已经退还给用户的 50 当成仍在合同内的资金,掩盖 30 元待补款缺口。因此合同进度一律用 net_paid_amount,百分比公式统一为 price <= 0 ? 100 : Math.min(100, Math.max(0, (net_paid_amount / price) * 100));待生效改价的 need_pay_amount 只在改价模块独立展示;paid_amount 仅用于展示「累计支付流水 / 实付总额」。
(本章 M / R / T 等符号见 1.0 符号速查。)
refund_policy 字段即可继续工作;但无法据此禁用退款输入,建议与后端同版本上线。改价试算新增的政策字段与 disabled_reason 也是增量。can_submit:work_task_price_changes/preview 原本只可能因计算不完整而为 false;现在由改价差额算出的退款受政策限制、或新价低于手续费时会额外返回 false。旧客户端若忽略 can_submit,仍会在 create / approve 收到 22022–22024 / 22026 / 60001,不会产生错误退款,只是体验较差。22022–22027 为新增值,未修改任何已发布错误码的值或含义;60001 / 60002 为改价域既有错误码。work_tasks.status 新增终局枚举值 refund_closed;commission_refund_write_offs.reason 新增 final_closure。前端需按 code 分支展示政策文案,而非依赖 message;对 refund_closed 必须新增状态文案并禁用付款 / 改价 / 取消 / 退款入口。0 < M < T 不再自动抹平、不再禁用入口,可选择 R = M 全退;整笔低余额入口收尾(below_minimum_balance)已移除。首次全退与第二次退款统一为 final closure 逐来源关闭;第二次退款对账完成后 work_tasks.status = refund_closed,不再接受新付款与新退款。旧客户端若按「小额不可退」的旧文案引导,会与后端实际行为不一致,需同步提示。attempts_used 计数,但不改写其既有执行结果;历史已 applied 的 below_minimum_balance 抹平仅作为账本事实被新规则读取(开发阶段无存量数据迁移)。已冻结并完成的改价与退款单按原快照执行,不追溯重算或补发历史差额;发版前已创建但未审批的降价申请,在发版后审批时若条款与快照不符会返回 60002(WorkTaskPriceChangeTermsChanged),前端提示重新发起即可。preview 误报的 22006 已恢复为正常返回。22006 语义与 refund_limits 口径不变。