Files
junhong_cmp_fiber/openspec/changes/archive/2026-03-28-fix-business-completion/design.md
huang f339fb1987
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m8s
fix: 资产钱包自动创建机制 — 修复C端购买时钱包不存在报错
- client_order: 新增 getOrCreateWallet 兜底,钱包不存在时自动创建
- device_import: 设备导入事务内同步创建设备钱包
- iot_card_import: IoT卡批量导入后批量创建卡钱包
- queue/handler: 传递 AssetWalletStore 给两个导入 handler
- migration 000098: 为存量IoT卡和设备补建资产钱包
2026-03-30 11:37:41 +08:00

66 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
修正业务方案 v5 中 5 项业务逻辑补全,涉及佣金计算、订单查询、支付对接、订单创建、资产状态管理共 5 个模块。各项之间无强依赖,但 J-2平台钱包代购与 J-1富友支付涉及同一个文件 `order/service.go`,建议 J-2 先做避免合并冲突。
## Goals / Non-Goals
**Goals:**
- 佣金链断裂可被平台发现F-1
- C端订单查询符合 Handler → Service 分层F-4
- 富友支付 JSAPI/MiniApp 可正常预下单J-1
- 平台可代用代理钱包购包J-2
- 卡/设备状态反映真实使用情况J-3
**Non-Goals:**
- 不修改佣金计算核心算法
- 不新增自动化测试
- 不改动回调链路(已存在且正常工作)
- 不新建 DB 表(仅插入配置数据)
## Decisions
### 1. F-1 零额待审记录的触发点
**决策**:在 `calculateChainOneTimeCommission` 和类似链式计算函数中,当 `getCostPrice` 返回零/无配置时,`break` 之前创建记录。
**原因**:这是佣金链唯一的断裂点——上游代理缺少套餐系列授权。在此处插入最精准。
记录写入失败不阻断主流程(`_ = store.Create()`),仅记 Error 日志。
### 2. F-4 迁移范围
**决策**:仅迁移 `ListOrders``GetOrderDetail` 两个查询方法到 Service 层。不重构其他正常工作的 Handler 方法。
**原因**:最小改动原则。其他 Handler 方法如果没有绕层问题则不动。
迁移后 Handler 中删除 `h.db` 字段引用和 `SkipPermissionCtx` 用法。
### 3. J-1 富友客户端构造方式
**决策**:每次调用时从 `wechatConfigStore.GetActive()` 读配置并构造 `fuiou.Client`,不做全局单例缓存。
**原因**配置可以在管理端切换activate/deactivate缓存可能导致读到旧配置。构造成本很低纯内存操作无需优化。
**替代方案**:全局单例 + 配置变更时刷新 → 增加复杂度,收益不大,拒绝。
### 4. J-2 平台代购的身份伪装
**决策**:平台代购时,`orderBuyerType` 设为 `agent``orderBuyerID` 设为 `*resourceShopID`。成本价和钱包都使用资产所属代理的。
**原因**:从订单归属和佣金计算角度,这笔订单等效于"该代理用自己钱包买的",只是操作人是平台。
### 5. J-3 状态更新时机
**决策**
- `status → 3`:在 `PackageActivationHandler` / `ActivateByRealname` 激活套餐成功后,检查 `card.Status < 3` 则更新为 3
- `status → 4`:在套餐到期处理逻辑中(`OrderExpireHandler` 或类似),当卡的最后一个 active 套餐过期时更新为 4
**原因**:与套餐生命周期绑定最自然——有活跃套餐就是"已激活",无活跃套餐就是"已停用"。
## Risks / Trade-offs
- **[F-1 零额记录堆积]** 如果某代理长期缺配置,会产生大量 status=99 记录 → 平台应定期处理待审记录(这本身就是 F-1 的目的)
- **[F-4 SkipPermissionCtx 移除]** 迁移后 Service 层查询会经过数据权限过滤 → 需确保 C端用户的数据权限配置正确否则可能查不到数据
- **[J-1 凭证安全]** 富友私钥存在 DB → 当前 `wechat_config` 表已有类似敏感数据(微信支付密钥),风险等级一致
- **[J-3 并发更新]** 多个套餐同时激活可能并发更新 status → 使用条件更新 `WHERE status < 3` 避免覆盖