积分系统
扣减积分
import { CreditsService } from "@readystart/api-core/billing/services/credits.service"
constructor(private readonly creditsService: CreditsService) {}
async handleRequest(req: CustomRequest) {
const result = await this.creditsService.deductCreditsFromTenant({
tenant_id: req.tenant.id,
user_id: req.user.user_id,
credits_to_deduct: 10,
custom_reason: "API 调用",
})
if (!result.success) {
// result.message: "No available credits" | "Credit limit exceeded"
throw new ForbiddenException(result.message)
}
}
扣减流程
1. 检查成员积分限额(tenant_member_credit_limits)
↓ 如果设置了限额(!= -1)且 used_credits >= credit_limit → 返回 "Credit limit exceeded"
2. 查询组织可用积分包(按 priority DESC, expires_at ASC 排序)
↓ 无积分包 → 返回 "No available credits"
3. 按优先级依次扣减,记录交易到 credit_transactions
4. 如果所有积分包用完仍有剩余,剩余部分进入透支(credit_overdrafts)
5. 更新成员已用量(tenant_member_credit_limits.used_credits += credits_to_deduct)
积分包优先级
积分包按 priority 降序消耗,相同优先级按过期时间升序(先过期的先用)。
可通过前端 Credits 页面调整优先级。
成员积分限额
Owner 可以给每个成员设置积分使用上限:
-1= 无限制(默认,不检查限额)500= 最多使用 500 积分
扣减前检查:credit_limit != -1 && used_credits >= credit_limit → 拒绝
扣减后更新:used_credits += credits_to_deduct
允许单次使用超出限额(因为 token 消耗不可预知),但下次请求会被拒绝。
查询积分
// 查询组织可用积分(按创建时间倒序)
const result = await this.creditsService.getActiveByTenant(tenant_id)
// result.data = { all: CreditPackage[], total: number }