# Phase 4: 退款 + 支付 + 运营修复 - Discussion Log > **Audit trail only.** Do not use as input to planning, research, or execution agents. > Decisions are captured in CONTEXT.md — this log preserves the alternatives considered. **Date:** 2026-03-28 **Phase:** 04-退款-支付-运营修复 **Areas discussed:** Plan 分组策略, 退款状态机细节, OPS-01 卡/设备 status=4 触发路径, PAY-04 平台代购的具体场景 --- ## Plan 分组策略 | Option | Description | Selected | |--------|-------------|----------| | REFUND 一个 Plan | DB迁移+Model+Store+Service+Handler+路由全部一次完成 | ✓ | | REFUND 拆两个 Plan | Plan A: DB迁移+基础层;Plan B: 功能层 | | **User's choice:** 一个 Plan(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | PAY + OPS 合并一个 Plan | PAY 和 OPS 彼此独立,合并一个 Plan 减少上下文切换 | ✓ | | PAY 和 OPS 各自独立 | 两个 Plan,粒度更细 | | **User's choice:** PAY + OPS 合并一个 Plan(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | 内嵌同步(Approve 事务内) | 退款审批和佣金扣减原子,失败可回滚 | ✓ | | 异步 Asynq 任务 | 入队 TaskTypeRefundCommissionDeduct,审批响应快 | | **User's choice:** 内嵌同步(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | REFUND-01 先行,再做 REFUND-02+03 | 与 Phase 3 DEVICE 基础层先行规范一致 | ✓ | | 一次性全部完成 | DB迁移先执行,所有上层代码同时完成 | | **User's choice:** REFUND-01 先行,再做 REFUND-02+03(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | 不需要,OPS-01 独立实现 | OPS-01 是套餐激活/到期直接更新 status,不经过 StopResumeCallback | ✓ | | 需要,提前将 CLEAN-06 并入本阶段 | 一并修复 bootstrap 注入 | | **Notes:** 用户对 CLEAN-06 和 OPS-01 的关系有疑问,确认两者独立后选择不提前。CLEAN-06 保留在 Phase 5。 --- ## 退款状态机细节 | Option | Description | Selected | |--------|-------------|----------| | 审批人退回 | 审批人退回申请人(信息不全/待补充等),返回 returned 状态,申请人可重提 | ✓ | | 申请人自撤回 | 申请人主动撤销,运营后可重提 | | **User's choice:** 审批人退回(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | RF + 时间戳 + 随机数 | 独立生成,不关联订单号 | | | 基于订单号迭代 | {order_no}-RF{seq},关联清晰,seq 解决冲突 | ✓ | **User's choice:** 基于订单号迭代,冲突解法用 {order_no}-RF{seq} --- | Option | Description | Selected | |--------|-------------|----------| | 允许多次退款 | 同一订单可有多条退款记录,审批退款总额不超过实收金额 | | | 同时只有一个待处理申请 | 上一次退款完成前不允许新申请 | ✓ | **User's choice:** 同一订单同时只能有一个待处理的退款申请(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | 可修改金额 | 审批人可调整 approved_refund_amount,以此为佣金扣减基准 | ✓ | | 只能审批全额 | 简化 Approve 逻辑 | | **User's choice:** 可修改金额(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | amount * approvedRefund / actualReceived(int64) | 先乘后除,禁用 float64 | ✓ | | 先确认字段含义再决定 | — | | **Notes:** 用户初始想先确认字段含义。解释了 actual_received_amount(实收)/ approved_refund_amount(审批退款额)以及"先乘后除"的整数精度含义后确认使用 int64 算法。 --- | Option | Description | Selected | |--------|-------------|----------| | 是,更新 payment_status=4 | 审批通过同时更新订单状态 | ✓ | | 不更新订单状态 | 退款表独立记录 | | **User's choice:** 是,更新 payment_status=4 --- ## OPS-01 卡/设备 status=4 触发路径 | Option | Description | Selected | |--------|-------------|----------| | 事务内同步更新 | 套餐激活和卡状态更新原子,失败可回滚 | ✓ | | 异步 goroutine | 套餐激活后异步更新卡/设备状态 | | **User's choice:** 事务内同步更新(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | activateNextMainPackage 后检查 active/pending count | 在现有到期处理循环内,激活下一个失败时检查剩余套餐数量 | ✓ | | 独立轮询任务定期检查 | 新建 Asynq 定时任务扫描无 active 套餐的卡/设备 | | **User's choice:** 调用 activateNextMainPackage 后检查无剩余 active/pending 套餐(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | 分开更新两张表 | 根据 carrierType 分支到 iot_card/device 各自的 Store | ✓ | | 统一封装 UpdateCarrierStatus() | 新建封装方法处理两种类型 | | **User's choice:** 分开更新两张表(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | 直接输出 DB 字段,删除所有映射函数 | DB 存的 payment_status 与管理端完全一致(1/2/3/4) | ✓ | | 先确认 DB 存在的实际值 | 不确定 DB 值是否真的 1/2/3/4 | | **User's choice:** 是,直接输出 DB 字段,删除所有映射函数 --- ## PAY-04 平台代购的具体场景 | Option | Description | Selected | |--------|-------------|----------| | 仅 CreateLegacy | 规格书指定 | | | 仅 CreateAdminOrder | Handler 实际调用的是 CreateAdminOrder,CreateLegacy 已废弃 | ✓ | **Notes:** 用户指出 CreateLegacy 已废弃,讨论后确认修改目标为 CreateAdminOrder。规格书中的引用有误,这是本次讨论中最重要的一个勘误。 --- | Option | Description | Selected | |--------|-------------|----------| | 资产所属代理的钱包(*resourceShopID) | 平台帮代理买,用代理自己的钱包 | ✓ | | 平台自己的测试钱包 | 平台先垫付 | | **User's choice:** 资产所属代理的钱包(*resourceShopID)(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | purchaseRole=purchased_by_platform, operatorType=platform | 使用已有枚举 | ✓ | | purchaseRole=self_purchase | 按代理自购处理 | | **User's choice:** purchaseRole=purchased_by_platform, operatorType=platform(推荐) --- | Option | Description | Selected | |--------|-------------|----------| | 与代理自购相同(sellerCostPrice=资产所属代理成本价) | 上下级佣金链照常计算 | ✓ | | sellerCostPrice=0(不计佣金差) | 平台代购无差价 | | **Notes:** 用户初始对 sellerCostPrice 含义不清楚,解释了佣金差价逻辑后确认:平台代购等同于代理自购,佣金链正常计算。 --- ## the Agent's Discretion - 富友支付 WxPreCreate 调用时的 goodsDesc 字段内容 - 退款 Store 层具体查询方法实现 - status=3/4 更新时的日志内容 - 富友 DTO 字段命名(参考 WechatPayJSAPIResponse 风格) ## Deferred Ideas None — discussion stayed within phase scope.