fix(billing): 修复计费漏洞

- 允许余额透支策略

   ## 问题
   - 扣费失败时只记录日志,不阻止请求完成
   - 用户可以用极少余额无限次免费使用服务
   - 数据库层使用 BalanceGTE 条件防止余额变负,导致余额不足时扣费失败

   ## 修复
   - 移除 DeductBalance 方法中的 BalanceGTE 条件,允许余额变为负数
   - 修改错误返回:用户不存在时返回 ErrUserNotFound
   - 实现透支策略:余额不足时允许本次请求完成,余额变负后阻止后续请求

   ## 测试
   - 更新 TestDeductBalance_InsufficientFunds 测试,验证透支功能
   - 更新 TestDeductBalance_NotFound 测试,验证正确的错误类型
   - 新增 TestDeductBalance_AllowsOverdraft 测试,专门测试透支场景
   - 所有测试通过 
This commit is contained in:
longgexx
2026-01-05 18:48:49 +08:00
committed by long
parent d936eb6518
commit d6f8ac0226
2 changed files with 27 additions and 6 deletions

View File

@@ -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
}