fix(billing): 修复计费漏洞
- 允许余额透支策略
## 问题
- 扣费失败时只记录日志,不阻止请求完成
- 用户可以用极少余额无限次免费使用服务
- 数据库层使用 BalanceGTE 条件防止余额变负,导致余额不足时扣费失败
## 修复
- 移除 DeductBalance 方法中的 BalanceGTE 条件,允许余额变为负数
- 修改错误返回:用户不存在时返回 ErrUserNotFound
- 实现透支策略:余额不足时允许本次请求完成,余额变负后阻止后续请求
## 测试
- 更新 TestDeductBalance_InsufficientFunds 测试,验证透支功能
- 更新 TestDeductBalance_NotFound 测试,验证正确的错误类型
- 新增 TestDeductBalance_AllowsOverdraft 测试,专门测试透支场景
- 所有测试通过 ✅
This commit is contained in:
@@ -329,17 +329,20 @@ func (r *userRepository) UpdateBalance(ctx context.Context, id int64, amount flo
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeductBalance 扣除用户余额
|
||||
// 透支策略:允许余额变为负数,确保当前请求能够完成
|
||||
// 中间件会阻止余额 <= 0 的用户发起后续请求
|
||||
func (r *userRepository) DeductBalance(ctx context.Context, id int64, amount float64) error {
|
||||
client := clientFromContext(ctx, r.client)
|
||||
n, err := client.User.Update().
|
||||
Where(dbuser.IDEQ(id), dbuser.BalanceGTE(amount)).
|
||||
Where(dbuser.IDEQ(id)).
|
||||
AddBalance(-amount).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == 0 {
|
||||
return service.ErrInsufficientBalance
|
||||
return service.ErrUserNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user