文档
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m2s

This commit is contained in:
2026-01-31 13:06:30 +08:00
parent b8dda7e62a
commit 62708892ec
29 changed files with 6568 additions and 31 deletions

View File

@@ -0,0 +1,103 @@
## MODIFIED Requirements
### Requirement: 订单支付后触发佣金计算
系统 SHALL 在订单支付成功后自动触发佣金计算。计算通过异步任务执行。代购订单和普通订单的佣金计算逻辑不同。
#### Scenario: 普通订单支付成功触发计算
- **WHEN** 普通订单is_purchase_on_behalf = false支付状态变为已支付
- **THEN** 系统发送佣金计算异步任务
#### Scenario: 代购订单支付成功触发计算
- **WHEN** 代购订单is_purchase_on_behalf = true创建成功自动已支付
- **THEN** 系统发送佣金计算异步任务
#### Scenario: 重复支付不重复计算
- **WHEN** 订单已计算过佣金commission_status=2
- **THEN** 系统不重复触发计算
---
### Requirement: 更新累计充值金额
订单支付成功后系统 SHALL 更新卡/设备的累计充值金额,但代购订单除外。
**关键修复**:每次真实充值(个人客户充值或购买套餐)都必须写回累计充值金额,代购订单不更新。
#### Scenario: 普通单卡订单更新累计充值
- **WHEN** 普通单卡订单is_purchase_on_behalf = false支付成功金额 100 元
- **THEN** 系统读取 IotCard.accumulated_recharge 当前值
- **AND** 增加 10000 分100 元 = 10000 分)
- **AND** 将新值写回 IotCard.accumulated_recharge
- **AND** 使用更新后的累计值判断是否触发一次性佣金
#### Scenario: 普通设备订单更新累计充值
- **WHEN** 普通设备订单is_purchase_on_behalf = false支付成功金额 300 元
- **THEN** 系统读取 Device.accumulated_recharge 当前值
- **AND** 增加 30000 分300 元 = 30000 分)
- **AND** 将新值写回 Device.accumulated_recharge
- **AND** 使用更新后的累计值判断是否触发一次性佣金
#### Scenario: 代购订单不更新累计充值
- **WHEN** 代购订单is_purchase_on_behalf = true完成金额 100 元
- **THEN** 系统不更新卡/设备的 accumulated_recharge 字段
- **AND** accumulated_recharge 保持原值
#### Scenario: 累计充值更新使用原子操作
- **WHEN** 更新累计充值金额
- **THEN** 系统使用 SQL 原子操作(如 `accumulated_recharge = accumulated_recharge + ?`
- **OR** 使用 GORM 乐观锁version 字段)
- **AND** 确保并发场景下累计值不会丢失
#### Scenario: 更新失败不影响佣金计算
- **WHEN** 累计充值金额更新失败(数据库错误、并发冲突等)
- **THEN** 系统记录错误日志
- **AND** 继续执行后续的佣金计算流程(成本价差、一次性佣金等)
- **AND** 不因累计值更新失败而导致整个佣金计算失败
---
## ADDED Requirements
### Requirement: 代购订单佣金计算规则
代购订单 SHALL 计算差价佣金,但不触发一次性佣金。
#### Scenario: 代购订单计算差价佣金
- **WHEN** 代购订单is_purchase_on_behalf = true完成买家有上级代理
- **THEN** 系统计算差价佣金(买家成本价 - 上级成本价),发放给上级代理链
#### Scenario: 代购订单不触发一次性佣金
- **WHEN** 代购订单完成,佣金计算时检查订单类型
- **THEN** 系统跳过一次性佣金判断逻辑,不发放一次性佣金
#### Scenario: 代购订单示例
- **WHEN** 平台为三级代理代购,订单金额 100 元(三级成本价),各级成本价:一级 60 → 二级 70 → 三级 80
- **THEN** 二级获得 10 元80 - 70差价佣金一级获得 10 元70 - 60差价佣金
- **AND** 三级、二级、一级都不获得一次性佣金
---
### Requirement: 钱包充值触发一次性佣金
钱包充值成功后 SHALL 更新累计充值,并检查是否触发一次性佣金。
#### Scenario: 充值成功更新累计充值
- **WHEN** 卡钱包充值 100 元成功,当前累计充值 200 元
- **THEN** 系统更新卡的 accumulated_recharge 为 300 元
#### Scenario: 充值达到首次充值阈值
- **WHEN** 卡配置为首次充值触发,阈值 100 元,充值 100 元成功,未发放过佣金
- **THEN** 系统触发一次性佣金计算,发放佣金,标记 first_commission_paid = true
#### Scenario: 充值达到累计充值阈值
- **WHEN** 卡配置为累计充值触发,阈值 1000 元,充值后累计达到 1000 元,未发放过佣金
- **THEN** 系统触发一次性佣金计算,发放佣金,标记 first_commission_paid = true
#### Scenario: 充值未达阈值不触发
- **WHEN** 充值后累计充值未达到阈值
- **THEN** 系统不触发一次性佣金计算
#### Scenario: 已发放过不重复触发
- **WHEN** 卡的一次性佣金已发放过first_commission_paid = true
- **THEN** 系统不触发一次性佣金计算

View File

@@ -0,0 +1,109 @@
## ADDED Requirements
### Requirement: 钱包充值预检
系统 SHALL 提供钱包充值预检接口,返回强充要求、允许的充值金额等信息。
#### Scenario: 无强充要求
- **WHEN** 客户查询卡钱包充值预检,卡配置为累计充值触发且未启用强充
- **THEN** 系统返回 need_force_recharge = falsemin_amount = 1001元max_amount = null
#### Scenario: 首次充值强充
- **WHEN** 客户查询卡钱包充值预检,卡配置为首次充值触发,阈值 10000 分100元未发放佣金
- **THEN** 系统返回 need_force_recharge = trueforce_recharge_amount = 10000trigger_type = "single_recharge"message = "首次充值需充值100元"
#### Scenario: 累计充值启用强充
- **WHEN** 客户查询卡钱包充值预检,卡配置为累计充值触发,启用强充,强充金额 10000 分100元
- **THEN** 系统返回 need_force_recharge = trueforce_recharge_amount = 10000trigger_type = "accumulated_recharge"message = "每次充值需充值100元"
#### Scenario: 一次性佣金已发放
- **WHEN** 客户查询卡钱包充值预检,卡的一次性佣金已发放过
- **THEN** 系统返回 need_force_recharge = false不再强充
#### Scenario: 未启用一次性佣金
- **WHEN** 客户查询卡钱包充值预检,卡关联系列未启用一次性佣金
- **THEN** 系统返回 need_force_recharge = false
---
### Requirement: 套餐购买预检
系统 SHALL 提供套餐购买预检接口,计算实际支付金额、钱包到账金额等信息。
#### Scenario: 无强充要求正常购买
- **WHEN** 客户购买 90 元套餐,无强充要求
- **THEN** 系统返回 total_package_amount = 9000need_force_recharge = falseactual_payment = 9000wallet_credit = 0
#### Scenario: 首次充值强充,套餐价低于阈值
- **WHEN** 客户购买 90 元套餐,首次充值阈值 100 元
- **THEN** 系统返回 total_package_amount = 9000need_force_recharge = trueforce_recharge_amount = 10000actual_payment = 10000wallet_credit = 1000message = "需充值100元购买套餐后余额10元"
#### Scenario: 首次充值强充,套餐价高于阈值
- **WHEN** 客户购买 150 元套餐,首次充值阈值 100 元
- **THEN** 系统返回 total_package_amount = 15000need_force_recharge = trueforce_recharge_amount = 10000actual_payment = 15000wallet_credit = 0message = "套餐总价150元无需额外充值"
#### Scenario: 首次充值强充,套餐价等于阈值
- **WHEN** 客户购买 100 元套餐,首次充值阈值 100 元
- **THEN** 系统返回 total_package_amount = 10000need_force_recharge = trueforce_recharge_amount = 10000actual_payment = 10000wallet_credit = 0
#### Scenario: 累计充值启用强充,套餐价低于强充金额
- **WHEN** 客户购买 50 元套餐,累计充值启用强充,强充金额 100 元
- **THEN** 系统返回 actual_payment = 10000wallet_credit = 5000message = "需充值100元购买套餐后余额50元"
#### Scenario: 累计充值启用强充,套餐价高于强充金额
- **WHEN** 客户购买 150 元套餐,累计充值启用强充,强充金额 100 元
- **THEN** 系统返回 actual_payment = 15000wallet_credit = 0message = "套餐总价150元无需额外充值"
#### Scenario: 购买多个套餐
- **WHEN** 客户购买 3 个套餐,总价 120 元,首次充值阈值 100 元
- **THEN** 系统返回 total_package_amount = 12000actual_payment = 12000wallet_credit = 0
---
### Requirement: 预检接口响应格式
预检接口响应 SHALL 包含完整的充值/购买指引信息。
#### Scenario: 充值预检响应字段
- **WHEN** 调用钱包充值预检接口
- **THEN** 响应包含need_force_recharge, force_recharge_amount, trigger_type, min_amount, max_amount, current_accumulated, threshold, message
#### Scenario: 购买预检响应字段
- **WHEN** 调用套餐购买预检接口
- **THEN** 响应包含total_package_amount, need_force_recharge, force_recharge_amount, actual_payment, wallet_credit, message
---
### Requirement: 预检接口性能
预检接口响应时间 MUST 小于 100ms。
#### Scenario: 快速响应
- **WHEN** 调用预检接口
- **THEN** 系统在 100ms 内返回结果
#### Scenario: 缓存系列分配配置
- **WHEN** 频繁查询同一卡的预检信息
- **THEN** 系统可以缓存系列分配配置,减少数据库查询
---
### Requirement: 预检接口错误处理
预检接口 SHALL 正确处理异常情况。
#### Scenario: 卡不存在
- **WHEN** 查询不存在的卡的充值预检
- **THEN** 系统返回错误 "卡不存在"
#### Scenario: 卡未关联系列
- **WHEN** 查询未关联套餐系列的卡的充值预检
- **THEN** 系统返回 need_force_recharge = false无系列分配无强充要求
#### Scenario: 设备不存在
- **WHEN** 查询不存在的设备的充值预检
- **THEN** 系统返回错误 "设备不存在"
#### Scenario: 套餐不存在
- **WHEN** 套餐购买预检时,套餐 ID 不存在
- **THEN** 系统返回错误 "套餐不存在"

View File

@@ -0,0 +1,93 @@
## ADDED Requirements
### Requirement: 订单类型标识
系统 SHALL 在订单模型中增加 is_purchase_on_behalf 字段,标识是否为代购订单。
#### Scenario: 普通订单创建
- **WHEN** 个人客户或代理为自己创建订单
- **THEN** 系统设置 is_purchase_on_behalf = false
#### Scenario: 代购订单创建
- **WHEN** 平台或代理为其他代理创建代购订单
- **THEN** 系统设置 is_purchase_on_behalf = true
#### Scenario: 查询订单列表返回订单类型
- **WHEN** 查询订单列表或详情
- **THEN** 响应包含 is_purchase_on_behalf 字段
---
## MODIFIED Requirements
### Requirement: 创建套餐购买订单
系统 SHALL 允许买家创建套餐购买订单。订单类型分为单卡购买和设备购买。创建前 MUST 验证购买权限和强充要求。
#### Scenario: 个人客户创建单卡订单
- **WHEN** 个人客户为自己的卡创建订单,选择一个套餐
- **THEN** 系统创建订单状态为待支付is_purchase_on_behalf = false返回订单信息
#### Scenario: 个人客户创建设备订单
- **WHEN** 个人客户为自己的设备创建订单
- **THEN** 系统创建订单订单类型为设备购买is_purchase_on_behalf = false
#### Scenario: 代理创建订单
- **WHEN** 代理为店铺关联的卡/设备创建订单
- **THEN** 系统创建订单买家类型为代理商买家ID为店铺IDis_purchase_on_behalf = false
#### Scenario: 平台创建代购订单
- **WHEN** 平台账号为代理的卡/设备创建订单,支付方式选择 offline
- **THEN** 系统创建订单is_purchase_on_behalf = truepayment_method = "offline"payment_status = 2已支付
#### Scenario: 套餐购买验证强充要求
- **WHEN** 个人客户创建订单,存在强充要求,订单金额低于强充金额
- **THEN** 系统返回错误 "支付金额不符合强充要求"
#### Scenario: 套餐不在可购买范围
- **WHEN** 买家尝试购买不在关联系列下的套餐
- **THEN** 系统返回错误 "该套餐不在可购买范围内"
#### Scenario: 套餐已下架
- **WHEN** 买家尝试购买已下架的套餐
- **THEN** 系统返回错误 "该套餐已下架"
---
### Requirement: 查询订单列表
系统 SHALL 提供订单列表查询,支持按支付状态、订单类型、是否代购筛选。
#### Scenario: 个人客户查询自己的订单
- **WHEN** 个人客户查询订单列表
- **THEN** 系统只返回该客户的订单
#### Scenario: 代理查询店铺订单
- **WHEN** 代理查询订单列表
- **THEN** 系统返回该店铺及下级店铺的订单(包含代购订单和普通订单)
#### Scenario: 按代购类型筛选
- **WHEN** 指定 is_purchase_on_behalf = true 筛选
- **THEN** 系统只返回代购订单
#### Scenario: 按支付状态筛选
- **WHEN** 指定支付状态筛选
- **THEN** 系统只返回匹配状态的订单
---
### Requirement: 取消订单
系统 SHALL 允许买家取消未支付的订单,但代购订单不可取消。
#### Scenario: 取消待支付的普通订单
- **WHEN** 买家取消一个待支付的普通订单is_purchase_on_behalf = false
- **THEN** 系统更新订单状态为已取消
#### Scenario: 取消已支付订单
- **WHEN** 买家尝试取消已支付的订单
- **THEN** 系统返回错误 "已支付订单无法取消"
#### Scenario: 尝试取消代购订单
- **WHEN** 买家尝试取消代购订单is_purchase_on_behalf = true
- **THEN** 系统返回错误 "代购订单不可取消"

View File

@@ -0,0 +1,75 @@
## ADDED Requirements
### Requirement: 线下支付方式
系统 SHALL 支持线下支付方式offline仅用于代购订单。线下支付的订单创建后直接标记为已支付跳过支付流程。
#### Scenario: 创建线下支付订单
- **WHEN** 平台账号创建订单时选择支付方式为 offline
- **THEN** 系统创建订单payment_status 直接设为 2已支付payment_method = "offline"
#### Scenario: 线下支付权限限制
- **WHEN** 非平台账号(代理/个人客户)尝试使用线下支付
- **THEN** 系统返回错误 "只有平台账号可以使用线下支付"
#### Scenario: 线下支付订单自动激活套餐
- **WHEN** 创建线下支付订单成功
- **THEN** 系统自动激活套餐,创建 PackageUsage 记录
#### Scenario: 线下支付不扣钱包
- **WHEN** 订单使用线下支付
- **THEN** 系统不扣减任何钱包余额
---
## MODIFIED Requirements
### Requirement: 第三方支付回调
系统 SHALL 处理微信支付和支付宝的支付回调,支持订单支付和钱包充值两种场景。回调处理 MUST 幂等。
#### Scenario: 微信支付成功回调(订单)
- **WHEN** 收到微信支付成功回调,订单号格式为 ORD 开头
- **THEN** 系统验证签名,更新订单状态,激活套餐,返回成功响应
#### Scenario: 微信支付成功回调(充值)
- **WHEN** 收到微信支付成功回调,订单号格式为 RCH 开头
- **THEN** 系统验证签名,更新充值订单状态,增加钱包余额,更新累计充值,触发佣金判断,返回成功响应
#### Scenario: 支付宝成功回调(订单)
- **WHEN** 收到支付宝支付成功回调,订单号格式为 ORD 开头
- **THEN** 系统验证签名,更新订单状态,激活套餐,返回成功响应
#### Scenario: 支付宝成功回调(充值)
- **WHEN** 收到支付宝支付成功回调,订单号格式为 RCH 开头
- **THEN** 系统验证签名,更新充值订单状态,增加钱包余额,更新累计充值,触发佣金判断,返回成功响应
#### Scenario: 重复回调
- **WHEN** 收到已处理订单的重复回调
- **THEN** 系统返回成功响应,不重复处理
#### Scenario: 签名验证失败
- **WHEN** 回调签名验证失败
- **THEN** 系统拒绝处理,返回失败响应
---
### Requirement: 套餐激活
支付成功后系统 MUST 激活套餐,创建 PackageUsage 记录。代购订单也需激活套餐,但不更新累计充值。
#### Scenario: 单卡套餐激活
- **WHEN** 单卡订单支付成功
- **THEN** 系统创建 PackageUsageusage_type 为 single_card关联 iot_card_id
#### Scenario: 设备套餐激活
- **WHEN** 设备订单支付成功
- **THEN** 系统创建 PackageUsageusage_type 为 device关联 device_id
#### Scenario: 套餐有效期计算
- **WHEN** 套餐激活
- **THEN** 有效期 = 激活时间 + 套餐时长(月)
#### Scenario: 代购订单激活套餐
- **WHEN** 代购订单is_purchase_on_behalf = true创建成功
- **THEN** 系统激活套餐,但不更新卡/设备的 accumulated_recharge

View File

@@ -0,0 +1,139 @@
## ADDED Requirements
### Requirement: 平台创建代购订单
系统 SHALL 允许平台账号为代理创建代购订单,使用线下支付方式,订单创建后直接标记为已支付。
#### Scenario: 平台为一级代理代购
- **WHEN** 平台账号为一级代理的卡创建代购订单,选择套餐,支付方式为线下支付
- **THEN** 系统创建订单buyer_id = 一级代理店铺IDis_purchase_on_behalf = truepayment_method = "offline"payment_status = 2已支付
#### Scenario: 平台为二级代理代购
- **WHEN** 平台账号为二级代理的卡创建代购订单
- **THEN** 系统创建订单buyer_id = 二级代理店铺IDis_purchase_on_behalf = true
#### Scenario: 代购订单价格使用代理成本价
- **WHEN** 平台为代理创建代购订单,套餐价格 100 元,代理成本价 80 元
- **THEN** 订单金额为 80 元(代理成本价)
#### Scenario: 查询卡归属代理
- **WHEN** 平台选择卡创建代购订单
- **THEN** 系统查询卡的 shop_id作为订单的 buyer_id
#### Scenario: 查询设备归属代理
- **WHEN** 平台选择设备创建代购订单
- **THEN** 系统查询设备的 shop_id作为订单的 buyer_id
---
### Requirement: 代理创建代购订单
系统 SHALL 允许代理账号为其他代理(通常是下级代理)创建代购订单。
#### Scenario: 一级代理为二级代理代购
- **WHEN** 一级代理为二级代理的卡创建代购订单,选择套餐,支付方式为线下支付
- **THEN** 系统创建订单buyer_id = 二级代理店铺IDis_purchase_on_behalf = truepayment_method = "offline"
#### Scenario: 代购订单使用买家成本价
- **WHEN** 一级代理为二级代理代购,套餐价格 100 元,二级代理成本价 90 元
- **THEN** 订单金额为 90 元(买家成本价)
---
### Requirement: 代购订单自动完成
代购订单创建后 SHALL 自动完成支付流程,激活套餐,但不触发一次性佣金。
#### Scenario: 代购订单自动激活套餐
- **WHEN** 创建代购订单成功
- **THEN** 系统自动激活套餐(创建 PackageUsage 记录)
#### Scenario: 代购订单不扣钱包
- **WHEN** 创建代购订单
- **THEN** 系统不扣减任何钱包余额(线下已收款)
#### Scenario: 代购订单不更新累计充值
- **WHEN** 代购订单完成
- **THEN** 系统不更新卡/设备的 accumulated_recharge 字段
#### Scenario: 代购订单计算差价佣金
- **WHEN** 代购订单完成,买家有上级代理
- **THEN** 系统计算差价佣金(买家成本价 - 上级成本价),发放给上级代理
#### Scenario: 代购订单不触发一次性佣金
- **WHEN** 代购订单完成
- **THEN** 系统不检查一次性佣金阈值,不发放一次性佣金
---
### Requirement: 代购订单查询
系统 SHALL 在订单列表中正确显示代购订单。
#### Scenario: 平台查询代购订单
- **WHEN** 平台账号查询订单列表
- **THEN** 系统返回所有代购订单is_purchase_on_behalf = true包含创建人信息
#### Scenario: 代理查询收到的代购订单
- **WHEN** 代理查询订单列表,包含别人为自己代购的订单
- **THEN** 系统返回买家为自己的代购订单
#### Scenario: 代购订单标识
- **WHEN** 查询订单详情
- **THEN** 订单响应包含 is_purchase_on_behalf 字段,前端可以显示"代购订单"标签
---
### Requirement: 代购订单权限控制
系统 SHALL 严格控制代购订单的创建权限。
#### Scenario: 只有平台账号可以使用线下支付
- **WHEN** 代理账号尝试创建订单时选择支付方式为 offline
- **THEN** 系统返回错误 "只有平台账号可以使用线下支付"
#### Scenario: 平台账号可以为任何代理代购
- **WHEN** 平台账号为任意层级代理创建代购订单
- **THEN** 系统允许创建
#### Scenario: 代理账号只能为下级代理代购
- **WHEN** 代理账号尝试为上级或平级代理创建代购订单
- **THEN** 系统返回错误 "只能为下级代理代购套餐"
---
### Requirement: 代购订单记录
系统 SHALL 完整记录代购订单的创建人和买家信息。
#### Scenario: 记录创建人
- **WHEN** 平台/代理创建代购订单
- **THEN** 订单的 creator 字段记录创建人账号ID
#### Scenario: 区分创建人和买家
- **WHEN** 查询代购订单详情
- **THEN** creator创建人!= buyer_id买家可以追溯是谁代购的
---
### Requirement: 代购订单不可取消
代购订单创建后 SHALL 不可取消,因为已自动完成。
#### Scenario: 尝试取消代购订单
- **WHEN** 尝试取消一个代购订单is_purchase_on_behalf = true
- **THEN** 系统返回错误 "代购订单不可取消"
---
### Requirement: 线下支付方式常量
系统 SHALL 定义线下支付方式常量。
#### Scenario: 支付方式枚举
- **WHEN** 创建订单时选择支付方式
- **THEN** payment_method 可选值包含wallet, wechat, alipay, offline
#### Scenario: 线下支付只用于代购
- **WHEN** payment_method = "offline"
- **THEN** 订单必须标记为 is_purchase_on_behalf = true

View File

@@ -0,0 +1,85 @@
## ADDED Requirements
### Requirement: 强充配置
系统 SHALL 在套餐系列分配中支持强充配置。仅累计充值触发时可选启用强充,首次充值触发时强充是必须的(无需配置)。
#### Scenario: 累计充值启用强充
- **WHEN** 创建系列分配,一次性佣金触发类型为累计充值,设置 enable_force_recharge = trueforce_recharge_amount = 10000100元
- **THEN** 系统保存强充配置,下级客户每次充值/购买必须充值 100 元
#### Scenario: 累计充值不启用强充
- **WHEN** 创建系列分配,一次性佣金触发类型为累计充值,设置 enable_force_recharge = false
- **THEN** 系统保存配置,下级客户可以自由充值任意金额
#### Scenario: 首次充值无需设置强充
- **WHEN** 创建系列分配,一次性佣金触发类型为首次充值,阈值 10000100元
- **THEN** 系统使用阈值作为强充金额,无需单独配置 force_recharge_amount
#### Scenario: 强充金额为0表示使用阈值
- **WHEN** 创建系列分配启用强充force_recharge_amount = 0
- **THEN** 系统使用一次性佣金阈值作为强充金额
---
## MODIFIED Requirements
### Requirement: 为下级店铺分配套餐系列
系统 SHALL 允许代理为其直属下级店铺分配套餐系列。分配时 MUST 指定基础返佣配置返佣模式和返佣值MAY 启用一次性佣金和强充配置。分配者只能分配自己已被分配的套餐系列。
#### Scenario: 成功分配套餐系列
- **WHEN** 代理为直属下级店铺分配一个自己拥有的套餐系列设置基础返佣为百分比20020%
- **THEN** 系统创建分配记录
#### Scenario: 分配时启用一次性佣金和强充
- **WHEN** 代理为下级分配系列,启用一次性佣金,触发类型为累计充值,阈值 1000001000元启用强充强充金额 10000100元
- **THEN** 系统保存配置enable_one_time_commission = truetrigger = "accumulated_recharge"threshold = 100000enable_force_recharge = trueforce_recharge_amount = 10000
#### Scenario: 尝试分配未拥有的系列
- **WHEN** 代理尝试分配自己未被分配的套餐系列
- **THEN** 系统返回错误 "您没有该套餐系列的分配权限"
#### Scenario: 尝试分配给非直属下级
- **WHEN** 代理尝试分配给非直属下级店铺
- **THEN** 系统返回错误 "只能为直属下级分配套餐"
#### Scenario: 重复分配同一系列
- **WHEN** 代理尝试为同一下级店铺重复分配同一套餐系列
- **THEN** 系统返回错误 "该店铺已分配此套餐系列"
---
### Requirement: 更新套餐系列分配
系统 SHALL 允许代理更新分配的基础返佣配置、一次性佣金配置和强充配置。更新返佣配置时 MUST 创建新的配置版本。
#### Scenario: 更新基础返佣配置时创建新版本
- **WHEN** 代理将基础返佣从20%改为25%
- **THEN** 系统更新分配记录,并创建新配置版本
#### Scenario: 更新强充配置
- **WHEN** 代理将 enable_force_recharge 从 false 改为 true设置 force_recharge_amount = 10000
- **THEN** 系统更新分配记录,后续下级客户需遵守新强充要求
#### Scenario: 禁用强充
- **WHEN** 代理将 enable_force_recharge 从 true 改为 false
- **THEN** 系统更新分配记录,后续下级客户可以自由充值
#### Scenario: 更新不存在的分配
- **WHEN** 代理更新不存在的分配 ID
- **THEN** 系统返回 "分配记录不存在" 错误
---
### Requirement: 平台分配套餐系列
平台管理员 SHALL 能够为一级代理分配套餐系列,可配置强充要求。平台的成本价基准为 Package.suggested_cost_price。
#### Scenario: 平台为一级代理分配
- **WHEN** 平台管理员为一级代理分配套餐系列
- **THEN** 系统创建分配记录
#### Scenario: 平台配置强充要求
- **WHEN** 平台为一级代理分配系列启用强充force_recharge_amount = 10000
- **THEN** 系统保存强充配置,一级代理的客户需遵守强充要求

View File

@@ -0,0 +1,182 @@
## ADDED Requirements
### Requirement: 创建钱包充值订单
系统 SHALL 允许个人客户创建钱包充值订单。创建前 MUST 验证强充要求,强充场景下充值金额必须等于要求的强充金额。
#### Scenario: 无强充要求时自由充值
- **WHEN** 个人客户为卡/设备创建充值订单,该卡/设备无强充要求,充值金额 100 元
- **THEN** 系统创建充值订单,状态为待支付,金额 10000 分
#### Scenario: 首次充值强充
- **WHEN** 卡关联系列配置为首次充值触发,阈值 100 元,客户尝试充值 100 元
- **THEN** 系统验证通过,创建充值订单,金额 10000 分
#### Scenario: 首次充值金额不符
- **WHEN** 卡关联系列配置为首次充值触发,阈值 100 元,客户尝试充值 50 元
- **THEN** 系统返回错误 "必须充值100元"
#### Scenario: 累计充值启用强充
- **WHEN** 卡关联系列配置为累计充值触发,启用强充,强充金额 100 元,客户尝试充值 100 元
- **THEN** 系统验证通过,创建充值订单
#### Scenario: 累计充值强充金额不符
- **WHEN** 卡关联系列配置为累计充值触发,启用强充,强充金额 100 元,客户尝试充值 50 元
- **THEN** 系统返回错误 "必须充值100元"
#### Scenario: 累计充值未启用强充
- **WHEN** 卡关联系列配置为累计充值触发,未启用强充,客户充值任意金额
- **THEN** 系统创建充值订单
#### Scenario: 充值订单号唯一
- **WHEN** 创建充值订单
- **THEN** 系统生成唯一充值单号,格式为 RCH + 14位时间戳 + 6位随机数
---
### Requirement: 查询充值订单列表
系统 SHALL 提供充值订单列表查询,支持按状态筛选、时间范围筛选。
#### Scenario: 查询个人客户的充值订单
- **WHEN** 个人客户查询充值订单列表
- **THEN** 系统返回该客户的所有充值订单
#### Scenario: 按状态筛选
- **WHEN** 客户指定充值状态筛选(待支付/已支付/已完成)
- **THEN** 系统只返回匹配状态的充值订单
#### Scenario: 分页查询
- **WHEN** 查询充值订单列表
- **THEN** 系统使用分页返回,默认每页 20 条,最大 100 条
---
### Requirement: 查询充值订单详情
系统 SHALL 允许个人客户查询充值订单详情。
#### Scenario: 查询自己的充值订单
- **WHEN** 客户查询自己的充值订单详情
- **THEN** 系统返回订单信息(充值单号、金额、支付方式、状态、时间等)
#### Scenario: 查询他人充值订单
- **WHEN** 客户尝试查询不属于自己的充值订单
- **THEN** 系统返回 "充值订单不存在" 错误
---
### Requirement: 充值支付(微信/支付宝)
系统 SHALL 支持通过微信支付和支付宝支付完成充值。
#### Scenario: 微信 JSAPI 支付
- **WHEN** 客户在微信内选择充值,使用微信支付
- **THEN** 系统调用微信支付 JSAPI 接口,返回支付参数
#### Scenario: 微信 H5 支付
- **WHEN** 客户在浏览器内选择充值,使用微信支付
- **THEN** 系统调用微信支付 H5 接口,返回支付跳转 URL
#### Scenario: 支付宝支付
- **WHEN** 客户选择支付宝支付充值
- **THEN** 系统调用支付宝接口,返回支付参数
---
### Requirement: 充值支付回调处理
系统 SHALL 处理微信和支付宝的支付回调,验证签名,更新充值订单状态,增加钱包余额。
#### Scenario: 微信支付回调成功
- **WHEN** 收到微信支付成功回调,验证签名通过
- **THEN** 系统更新充值订单状态为已支付
- **AND** 增加对应钱包余额
- **AND** 创建钱包交易记录
- **AND** 返回成功响应给微信
#### Scenario: 支付宝回调成功
- **WHEN** 收到支付宝支付成功回调,验证签名通过
- **THEN** 系统更新充值订单状态为已支付
- **AND** 增加对应钱包余额
- **AND** 创建钱包交易记录
#### Scenario: 签名验证失败
- **WHEN** 收到支付回调,签名验证失败
- **THEN** 系统记录错误日志,不处理订单,返回失败响应
#### Scenario: 重复回调幂等处理
- **WHEN** 收到同一充值订单的重复支付回调
- **THEN** 系统检查订单状态,如果已支付则直接返回成功,不重复处理
---
### Requirement: 充值成功更新累计充值金额
充值支付成功后系统 SHALL 更新卡/设备的累计充值金额AccumulatedRecharge
#### Scenario: 充值成功累加充值金额
- **WHEN** 卡钱包充值 100 元成功,当前累计充值 200 元
- **THEN** 系统更新卡的累计充值为 300 元200 + 100
#### Scenario: 设备充值成功累加充值金额
- **WHEN** 设备钱包充值 200 元成功,当前累计充值 500 元
- **THEN** 系统更新设备的累计充值为 700 元500 + 200
#### Scenario: 使用原子操作更新
- **WHEN** 更新累计充值金额
- **THEN** 系统使用 SQL 原子操作或 GORM 乐观锁确保并发安全
---
### Requirement: 充值成功触发一次性佣金判断
充值支付成功后系统 SHALL 检查是否达到一次性佣金阈值,如果达到则触发佣金计算。
#### Scenario: 首次充值达到阈值
- **WHEN** 卡配置为首次充值触发,阈值 100 元,客户充值 100 元
- **THEN** 系统触发一次性佣金计算,发放佣金
#### Scenario: 累计充值达到阈值
- **WHEN** 卡配置为累计充值触发,阈值 1000 元,累计充值已达到 1000 元
- **THEN** 系统触发一次性佣金计算,发放佣金
#### Scenario: 未达阈值不触发
- **WHEN** 充值后累计充值未达到阈值
- **THEN** 系统不触发一次性佣金计算
#### Scenario: 已发放过不重复触发
- **WHEN** 卡的一次性佣金已发放过first_commission_paid = true
- **THEN** 系统不触发一次性佣金计算
---
### Requirement: 充值订单状态流转
充值订单状态 SHALL 按以下流程流转:待支付 → 已支付 → 已完成。
#### Scenario: 正常流转
- **WHEN** 创建充值订单 → 支付成功 → 钱包余额增加完成
- **THEN** 订单状态依次为1待支付→ 2已支付→ 3已完成
#### Scenario: 超时未支付
- **WHEN** 充值订单创建 30 分钟后仍未支付
- **THEN** 系统标记订单为已关闭(状态 4
---
### Requirement: 充值金额限制
系统 SHALL 限制单次充值金额范围。
#### Scenario: 充值金额范围
- **WHEN** 创建充值订单
- **THEN** 充值金额必须在 1 元到 100000 元之间
#### Scenario: 充值金额过小
- **WHEN** 客户尝试充值 0.5 元
- **THEN** 系统返回错误 "充值金额不能小于1元"
#### Scenario: 充值金额过大
- **WHEN** 客户尝试充值 200000 元
- **THEN** 系统返回错误 "单次充值金额不能超过100000元"