- client_order: 新增 getOrCreateWallet 兜底,钱包不存在时自动创建 - device_import: 设备导入事务内同步创建设备钱包 - iot_card_import: IoT卡批量导入后批量创建卡钱包 - queue/handler: 传递 AssetWalletStore 给两个导入 handler - migration 000098: 为存量IoT卡和设备补建资产钱包
3.4 KiB
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则更新为 3status → 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避免覆盖