fix: 资产钱包自动创建机制 — 修复C端购买时钱包不存在报错
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m8s

- client_order: 新增 getOrCreateWallet 兜底,钱包不存在时自动创建
- device_import: 设备导入事务内同步创建设备钱包
- iot_card_import: IoT卡批量导入后批量创建卡钱包
- queue/handler: 传递 AssetWalletStore 给两个导入 handler
- migration 000098: 为存量IoT卡和设备补建资产钱包
This commit is contained in:
2026-03-30 11:37:41 +08:00
parent 40809d11c5
commit f339fb1987
36 changed files with 1811 additions and 26 deletions

View File

@@ -0,0 +1,12 @@
## MODIFIED Requirements
### Requirement: 平台钱包代购支持
后台创建订单时,平台操作人 SHALL 可以使用某代理的钱包,以该代理的成本价,给该代理名下的资产购买套餐。条件:`buyerType == ""(平台)``resourceShopID != nil`(资产归属代理)。
#### Scenario: 平台代用代理钱包购包
- **WHEN** 平台操作人提交订单,`payment_method=wallet`,资产归属代理 A
- **THEN** 系统 SHALL 以代理 A 的成本价作为订单金额,从代理 A 的钱包扣款,订单 `buyer_type` 记录为 `agent``buyer_id` 为代理 A 的 shop_id
#### Scenario: 无归属代理时拒绝
- **WHEN** 平台操作人提交钱包支付订单,但资产无归属代理(`resourceShopID == nil`
- **THEN** 系统 SHALL 返回 `CodeInvalidParam` 错误

View File

@@ -0,0 +1,27 @@
## MODIFIED Requirements
### Requirement: 激活后状态更新为已激活
套餐激活成功后,系统 SHALL 将对应 IoT 卡或设备的 `status` 更新为 3已激活前提是当前 `status < 3`
#### Scenario: 首次套餐激活触发状态变更
- **WHEN** 某卡的套餐首次激活成功,且 `iot_card.status < 3`
- **THEN** 系统 SHALL 更新 `iot_card.status = 3`
#### Scenario: 设备套餐激活触发状态变更
- **WHEN** 某设备的套餐首次激活成功,且 `device.status < 3`
- **THEN** 系统 SHALL 更新 `device.status = 3`
#### Scenario: 已激活状态不被覆盖
- **WHEN** 套餐激活成功,但 `status` 已经 >= 3
- **THEN** 系统 SHALL NOT 修改 `status` 字段
### Requirement: 最后套餐过期后状态更新为已停用
当某卡/设备的最后一个 active 套餐过期后,系统 SHALL 将 `status` 更新为 4已停用
#### Scenario: 最后套餐过期
- **WHEN** 套餐到期处理后,该卡/设备名下无任何 `status=active``package_usage` 记录
- **THEN** 系统 SHALL 更新 `iot_card.status = 4``device.status = 4`
#### Scenario: 还有其他活跃套餐
- **WHEN** 某套餐过期,但该卡/设备名下仍有其他 `status=active` 的套餐
- **THEN** 系统 SHALL NOT 修改 `status` 字段

View File

@@ -0,0 +1,12 @@
## MODIFIED Requirements
### Requirement: C端订单查询通过 Service 层
C端订单列表和订单详情查询 SHALL 通过 `client_order/service.go` 的 Service 方法执行Handler 层 SHALL NOT 直接访问数据库或使用 `SkipPermissionCtx`
#### Scenario: C端查询订单列表
- **WHEN** C端客户请求订单列表
- **THEN** Handler SHALL 调用 `service.ListOrders(ctx, req)`Service 内部执行数据库查询并应用数据权限过滤
#### Scenario: C端查询订单详情
- **WHEN** C端客户请求订单详情
- **THEN** Handler SHALL 调用 `service.GetOrderDetail(ctx, orderID)`Service 内部验证权限并返回数据

View File

@@ -0,0 +1,15 @@
## ADDED Requirements
### Requirement: 佣金链断裂创建待审记录
当佣金链式计算过程中,某代理缺少套餐系列授权导致链路断裂时,系统 SHALL 创建一条 `amount=0, status=99` 的佣金记录,而非静默跳过。该记录的 `remark` SHALL 包含断裂原因(套餐系列 ID + 代理 ID
#### Scenario: 代理缺少套餐系列授权
- **WHEN** 佣金链计算到某代理,该代理未被分配对应套餐系列的成本价
- **THEN** 系统 SHALL 创建 `CommissionRecord{amount: 0, status: CommissionStatusPendingReview(99), remark: "套餐系列[{id}]未分配给该代理,请人工核查"}`,记录 Warn 日志,然后 break 链路
### Requirement: 待审佣金记录可筛选
佣金记录列表接口 SHALL 支持按 `status=99` 筛选待人工修正的记录。
#### Scenario: 平台管理员筛选待审记录
- **WHEN** 管理员查询佣金记录列表且传入 `status=99`
- **THEN** 返回所有待人工修正的佣金记录

View File

@@ -0,0 +1,19 @@
## MODIFIED Requirements
### Requirement: 富友 JSAPI 预下单
`FuiouPayJSAPI` SHALL 使用 `pkg/fuiou/` SDK 完成真实预下单返回前端调起微信支付所需的参数appId, timeStamp, nonceStr, package, signType, paySign。SHALL NOT 再返回"暂未实现"错误。
#### Scenario: 公众号内富友支付
- **WHEN** C端用户在微信公众号内发起订单支付支付通道为富友
- **THEN** 系统 SHALL 从 `tb_wechat_config` 读取激活的富友配置,调用 `fuiou.Client.WxPreCreate` 完成预下单,返回 JS-SDK 调起参数
#### Scenario: 富友配置未激活
- **WHEN** 发起富友支付但 `tb_wechat_config` 中无 `provider_type='fuiou' AND is_active=true` 的配置
- **THEN** 系统 SHALL 返回 `CodeFuiouPayFailed` 错误
### Requirement: 富友 MiniApp 预下单
`FuiouPayMiniApp` SHALL 使用与 JSAPI 相同的流程,但 `tradeType``LETPAY``subAppid` 使用小程序 AppID。
#### Scenario: 小程序内富友支付
- **WHEN** C端用户在微信小程序内发起订单支付支付通道为富友
- **THEN** 系统 SHALL 使用小程序 AppID 和 `LETPAY` 类型完成预下单