Files
junhong_cmp_fiber/.planning/phases/04-refund-pay-ops/04-CONTEXT.md
huang e81d3a58ad
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m6s
docs(04): capture phase context
2026-03-28 14:24:25 +08:00

10 KiB
Raw Blame History

Phase 4: 退款 + 支付 + 运营修复 - Context

Gathered: 2026-03-28 Status: Ready for planning

## Phase Boundary

实现完整退款流程REFUND-0103、补全富友支付 JSAPI/小程序接口PAY-0104、修复运营逻辑断点OPS-01~02。共 9 个需求:

  • REFUND:新功能模块(退款申请→审批→佣金回扣)
  • PAY:留桩替换(富友支付 JSAPI/小程序,平台代购场景修复)
  • OPS:业务逻辑修复(卡/设备 status 3/4 触发、payment_status 枚举统一)
## Implementation Decisions

Plan 分组策略

  • D-01: 拆分为 2 个 Plan
    • Plan 1REFUNDREFUND-01 先行DB 迁移 + Model + Store然后串行完成 REFUND-027 个接口)+ REFUND-03佣金扣减逻辑嵌入 Approve
    • Plan 2PAY + OPS 合并)PAY-0104 + OPS-0102 共 6 个需求,两者互相独立可并行编排
  • D-02: REFUND-01 必须先于 REFUND-02/03 执行DB 迁移和模型是所有上层代码的基础)
  • D-03: 每个子任务独立一个 commit延续 Phase 1/2/3 粒度规范)

退款状态机REFUND

  • D-04: 退款单号生成规则:{order_no}-RF{seq}(同一订单第 1 次退款为 RF1第 2 次为 RF2以此类推。Create 时查询该订单现有退款数量 +1 作为序号
  • D-05: 同一订单同时只允许一个"待处理"状态的退款申请status=pending/returned防止重复退款
  • D-06: 退款状态流转:
    • pendingapproved(审批通过,触发佣金扣减 + 更新订单 payment_status=4
    • pendingrejected(审批拒绝,必填拒绝原因)
    • pendingreturned(审批人退回,申请人可重提)
    • returnedpending(申请人 Resubmit 重提)
  • D-07: Return退回由审批人操作,退回后状态变为 returned,申请人可调用 Resubmit 重新提交变回 pending
  • D-08: 审批人可修改退款金额approved_refund_amount 可与 requested_refund_amount 不同)。佣金扣减以 approved_refund_amount 为准
  • D-09: 审批通过后同步更新订单 payment_status = 4(已退款),与 OPS-02 的 payment_status 枚举统一对齐

退款佣金扣减REFUND-03

  • D-10: 佣金扣减内嵌在 Approve() 事务内同步执行(不走 Asynq 异步任务)。原子性:退款审批通过、佣金扣减、订单状态更新在同一事务中完成,失败可回滚
  • D-11: 佣金扣减算法(禁用 float64使用整数算术
    deductAmount := commission.Amount * refund.ApprovedRefundAmount / refund.ActualReceivedAmount
    
    先乘后除,全程 int64防止整数除法精度丢失。对该订单所有佣金记录逐一计算扣减额写负向交易流水
  • D-12: 佣金扣减允许余额变为负数(规格书明确:允许为负数)

富友支付PAY

  • D-13: FuiouPayJSAPIFuiouPayMiniApp 函数签名需从 error 改为 (*dto.FuiouPayJSAPIResponse, error),参考 WechatPayJSAPI 的返回结构
  • D-14: 新建 FuiouPayJSAPIResponse DTO字段从 pkg/fuiou/types.goWxPreCreateResponse SDK 字段映射SdkAppid, SdkTimestamp, SdkNoncestr, SdkPrepayid, SdkPackage, SdkSigntype, SdkPaysign与微信官方 wx.requestPayment() 参数对齐
  • D-15: JSAPI公众号tradeType = JSAPI;小程序 tradeType = LETPAY(两者逻辑相同,仅此字段不同)
  • D-16: 已有富友 SDK 实现(pkg/fuiou/client.go + wxprecreate.go),直接调用 client.WxPreCreate() 方法

平台代理钱包代购PAY-04

  • D-17: 修改 CreateAdminOrder不是 CreateLegacyCreateLegacy 已废弃Handler 实际调用的是 CreateAdminOrder
  • D-18: 触发条件:buyerType == "" && resourceShopID != nil(平台用户在 Handler 层传入 buyerType="" buyerID=0
  • D-19: 钱包和成本价均来自**资产所属代理(*resourceShopID**的钱包和成本价(等同于代理自购场景)
  • D-20: 订单标记:purchaseRole = purchased_by_platformoperatorType = "platform"
  • D-21: sellerCostPrice = resourceShop 代理的成本价(与代理自购相同,上下级佣金链照常计算)

卡/设备 status 3/4 触发OPS-01

  • D-22: status=3已激活:在 activation_service.go 套餐激活事务内同步更新卡/设备表的 status=3不走 goroutine保证原子性
  • D-23: status=4已停用:在 activation_service.go 的套餐到期检测逻辑中,调用 activateNextMainPackage 后,若无法找到下一个待激活套餐(即无剩余 active/pending 套餐),则同步更新卡/设备 status=4
  • D-24: 卡和设备分开更新两张表tb_iot_card 和 tb_device根据 carrierType 分支处理,无需统一封装
  • D-25: status 更新在已有套餐激活/到期事务内完成,失败可回滚

payment_status 枚举统一OPS-02

  • D-26: 删除所有 C 端映射函数
    • internal/service/client_order/service.go 中的 orderStatusToClientStatus()
    • internal/handler/app/client_order.go 中的 orderStatusToClientPaymentStatus()clientPaymentStatusToOrderStatus()
  • D-27: C 端直接输出 DB 原始 payment_status 字段1=待支付, 2=已支付, 3=已取消, 4=已退款),与管理端完全一致

the Agent's Discretion

  • 富友支付 WxPreCreate 调用时的 goodsDesc 字段内容(可从 order.OrderNo 或套餐名称组合)
  • 退款 Store 层具体查询方法(参考现有 commission_withdrawal_request_store.go 风格)
  • status=3/4 更新时的日志内容(按项目中文日志规范)
  • getCostPrice 函数参数(已有现成封装,直接复用)

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

修复规格(核心参考)

  • .sisyphus/plans/修正业务-完整方案.md — 完整修复规格书:
    • 方案 IREFUND-01~03第 1716 行起退款表结构、7 个接口清单、佣金扣减逻辑)
    • 方案 JPAY + OPS第 1862 行起J-1/J-2/J-3/J-4 各子方案代码片段、人工验收清单)
      • J-1富友支付 JSAPI/小程序PAY-01/02/03
      • J-2平台钱包代购PAY-04—— 注意:规格书错误引用了 CreateLegacy已废弃实际修改目标是 CreateAdminOrder
      • J-3status 3/4 触发逻辑OPS-01
      • J-4payment_status 枚举统一OPS-02

核心修改文件

  • internal/service/order/service.go — FuiouPayJSAPI/FuiouPayMiniApp 留桩替换CreateAdminOrder 钱包支付 platform 分支PAY
  • pkg/fuiou/client.go + pkg/fuiou/wxprecreate.go — 富友 SDK直接调用 WxPreCreate
  • pkg/fuiou/types.go — WxPreCreateResponse 字段FuiouPayJSAPIResponse DTO 来源)
  • internal/service/package/activation_service.go — 套餐激活/到期逻辑OPS-01 插入点)
  • internal/service/client_order/service.go — orderStatusToClientStatus() 删除OPS-02
  • internal/handler/app/client_order.go — orderStatusToClientPaymentStatus() / clientPaymentStatusToOrderStatus() 删除OPS-02

参考结构REFUND 设计参照)

  • internal/service/commission_withdrawal/service.go — Approve/Reject 风格参考REFUND-02 接口设计)
  • internal/model/dto/commission_withdrawal_dto.go — DTO 字段风格参考REFUND DTO 设计)
  • internal/store/postgres/commission_withdrawal_request_store.go — Store 层风格参考REFUND Store

依赖项与约束

  • .planning/REQUIREMENTS.md — REFUND-0103, PAY-0104, OPS-01~02 完整需求定义
  • internal/handler/admin/order.go — PAY-04Handler 层传入 buyerType="" buyerID=0 的逻辑(了解上下游)

</canonical_refs>

<code_context>

Existing Code Insights

Reusable Assets

  • pkg/fuiou/client.go:WxPreCreate() — 富友预下单接口PAY-01/02 直接调用,无需重写
  • internal/service/order/service.go:WechatPayJSAPI() — 参考模板:验证 wechatPayment != nil → 查订单 → 调用 SDK → 返回 DTO
  • internal/service/commission_withdrawal/service.go:Approve() — REFUND Approve 逻辑的最佳参考
  • internal/service/package/activation_service.go — status=3/4 的插入位置activateMainPackage激活+ 到期检测循环(到期)
  • internal/model/order.go:PurchaseRolePurchasedByPlatform — PAY-04 购买角色常量已存在

Established Patterns

  • 佣金扣减:参考 internal/service/commission_withdrawal/service.go 的钱包扣款方式(使用 version 乐观锁)
  • DB 迁移:双文件形式(.up.sql / .down.sql),编号接续现有最大值(当前 Phase 3 使用了 000090/91
  • 退款单号参考提现单号的生成逻辑WD+时间戳+随机数 → 改为 {order_no}-RF{seq}
  • 路由注册:所有新接口通过 internal/routes/registry.goRegister() 注册,并同步更新 cmd/api/docs.gocmd/gendocs/main.go

Integration Points

  • REFUND Handler 注册到 /api/admin/refunds 路由组(参考 commission_withdrawal 的路由注册方式)
  • PAY-04 修改 CreateAdminOrder 的 wallet 分支Handler 层无需改动
  • OPS-01/02 在 activation_service.go 和 client_order 两个文件内修改,无新增路由
  • 富友支付 JSAPI/小程序的 Handler 已存在留桩(internal/handler/app/),替换 Service 层即可

</code_context>

## Specific Ideas
  • 退款佣金允许负数:规格书明确允许,代理佣金钱包余额可降至负值(为了确保退款公平性)
  • CreateLegacy 废弃问题:规格书 J-2 错误引用了已废弃的 CreateLegacy实际修改目标是 CreateAdminOrder这一决策在讨论中由用户确认
  • 富友 SDK 已完整pkg/fuiou/ 包含完整 client + types + notify + wxprecreatePAY 工作量主要是替换留桩和编写 DTO
## Deferred Ideas

None — discussion stayed within phase scope.


Phase: 04-refund-pay-ops Context gathered: 2026-03-28