线上 PayPal 支付出现过 PaypalCheckoutSessionStatus: conflicted:用户已经在 PayPal 页面完成支付,但本地订单被自动取消,后续 capture / webhook 回来时发现远端已支付、本地已取消,进入冲突状态。
本次调整的核心原则:
paying 订单。expires_at 只作为巡检/展示信号,不代表远端支付页面已经不可用;本地 expired session 在远端未明确终态前仍可能继续支付。stage_pay、full_pay、price_change。paying_order 查询接口获取最新状态;work_tasks/info 中的 payingOrder 只作为首次进入页面时的展示快照。POST /api/orders/continue 返回支付链接前会重新锁定订单确认仍为 paying,避免极端并发下返回刚被取消或已支付订单的支付链接。POST /api/work_tasks/paying_order
paying 订单时返回订单、支付会话和从订单快照派生的 pre_calc 形态数据;不存在时返回空结果,不再按支付类型重新计算金额。paying 订单,返回 error code 20003;如果同一 paying 订单存在多个 active payment session,返回 error code 21003。POST /api/user/pay/work_task/create_checkout_session
paying 订单,返回 error code 20001。POST /api/orders/cancel_by_worktask
POST /api/orders/continue
pending / processing session 会直接复用已有 pay_url;本地 expired session 会先同步 PayPal 远端状态,远端仍可继续时复用原 pay_url,远端明确不可继续时才允许新建。返回前会重新锁定订单确认仍为 paying;如果新 session 创建后订单已不再是 paying,不会把新支付链接返回给前端。PayPal-Request-Id,避免 capture retry 造成重复处理。GET /api/work_tasks/info
payingOrder 增加金额和计算过程字段,便于首次进入页面展示支付中订单。POST /api/work_task_price_changes/create
paying 订单,返回 error code 20001。该检查与 artist 侧共用同一套后端互斥规则。POST /api/work_task_price_changes/approve
paying 订单,返回 error code 20001。该检查与 artist 侧共用同一套后端互斥规则。POST /api/artist_center/work_task_price_changes/create
paying 订单,返回 error code 20001。该检查与 user 侧共用同一套后端互斥规则。POST /api/artist_center/work_task_price_changes/approve
paying 订单,返回 error code 20001。该检查与 user 侧共用同一套后端互斥规则。paying_order 查询流程POST /api/work_tasks/paying_orderwork_tasks/info 的 payingOrder 快照。paying 订单;不会根据 type、pay_channel、wallets 重新计算金额。404。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_id | number | 是 | work task id |
work_task_id。type、pay_channel、wallets,后端不会使用这些字段做金额计算。pending、processing、conflicted。pending、processing。pending、processing。paying order 同一时刻只应存在一个 active payment session。21003,不会按渠道优先级静默选择。400:同一 work task 存在多个支付中订单,返回 code=20003。正常业务路径不会产生该状态,通常表示历史数据或极端并发异常。
400:同一支付中订单存在多个 active payment session,返回 code=21003。
422:参数校验失败。
POST /api/user/pay/work_task/create_checkout_sessionpaying 订单;存在支付中订单时直接拒绝创建新支付。沿用原有参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_id | number | 是 | work task id |
type | string | 是 | stage_pay / full_pay / price_change |
pay_channel | string | 是 | stripe / alipay / paypal |
wallets | number[] | 否 | 参与抵扣的 credit wallet id 列表 |
callback | string | 否 | 外部支付完成后回跳前端页面地址 |
400:work task 已存在支付中订单,返回 code=20001。
400:存在未完成改价,不能发起 stage_pay / full_pay。
POST /api/orders/continuepending / processing session 会复用已有 pay_url;PayPal 本地 expired session 会先同步远端状态,远端仍可继续时复用旧 pay_url,远端明确不可继续时才创建新 PayPal session。返回支付数据前,后端会重新锁定订单确认仍为 paying。如果新建 session 后订单已经被取消或支付完成,后端不会返回新支付链接。PayPal-Request-Id,同一个 PayPal order 的 capture retry 保持幂等。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | number | 是 | order id |
400:订单不存在、订单状态不是 paying,或新 session 创建后订单已不再是 paying。
400:PayPal session 已进入冲突状态,返回 code=21001。
400:同步本地 expired PayPal session 时发现远端已经完成支付,本地订单已变为非 paying,不会返回任何新支付链接。
400:同一个 PayPal session 正在被其他请求同步或 capture,返回 code=21002。
POST /api/orders/cancel_by_worktask| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_id | number | 是 | work task id |
400:work task 不存在或不属于当前用户。
GET /api/work_tasks/infopayingOrder 增加支付金额和计算过程字段,供首次进入页面展示。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | number | 是 | work task id |
data.payingOrder 现在包含以下字段:
| 字段 | 说明 |
|---|---|
id | order id |
status | order 状态,当前只会返回 paying 的关联订单 |
busable_id / busable_type | 业务关联信息 |
busable_info | 支付业务信息,包含 pay_type 等 |
amount / currency_id | 实际外部支付金额和币种 |
init_amount / init_currency_id | 原始金额和币种 |
amount_calc_process | 金额计算过程 |
created_at | 订单创建时间 |
payingOrder 是页面详情加载时的快照,只用于首次展示。POST /api/work_tasks/paying_order 获取最新状态。POST /api/work_task_price_changes/createpaying 订单,拒绝创建改价。400:work task 已存在支付中订单,返回 code=20001。
POST /api/work_task_price_changes/approvepaying 订单,拒绝审批改价。400:work task 已存在支付中订单,返回 code=20001。
POST /api/artist_center/work_task_price_changes/createpaying 订单,拒绝创建改价。400:work task 已存在支付中订单,返回 code=20001。
POST /api/artist_center/work_task_price_changes/approvepaying 订单,拒绝审批改价。400:work task 已存在支付中订单,返回 code=20001。
paying_order,前端应展示“继续支付”和“取消订单”两个动作。continue 返回旧 pay_url 是预期行为,不表示后端没有刷新状态。expires_at 到期不再代表支付失效;后台 payment:expire-sessions 只同步 PayPal 远端状态,不会自动取消本地 PayPal 订单。400 Order status is not paying,前端应刷新 work task/order 状态,不要继续使用之前缓存的支付链接。stage_pay、full_pay、price_change 在同一个 work task 上互斥;如果用户已经发起改价,在该改价结束前不能再发起阶段支付或全款支付。