feat(gateway): 闭合积分环 —— 充值/发放 + 提交前余额硬拦截(默认关)
让预付费积分成为闭环(发放→消耗→见底拦住): - POST /admin/credits/grant:给租户充值/发放(正=grant,负=adjust 校正), 复用 store.GrantCredits(账本分录 + 物化余额,一事务)。 - 提交门控:credit_enforce 开启且租户余额≤0 → 拒绝新任务 402;默认关=软扣不拦。 开关入 billing-config(sundynix_setting KV,后台可切)。 - 修 bug:GrantCredits 是跨租户管理操作,须 store.WithoutTenant——否则 tenant 插件 会把账本分录的 tenant_id 覆盖成 admin 自己的租户(余额记目标、分录记 admin,破坏对账)。 live 验证:enforce 关→余额0可提交;开→余额0拒 402;充值后可提交、余额递减; 修复后 grant 分录落到目标租户、balance==SUM(ledger) 不变量成立。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,13 @@ func (h *Handler) SubmitTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 积分硬拦截(默认关;开关 credit_enforce):租户积分余额 ≤0 则拒绝新任务,提示充值。
|
||||
if tid := tenantID(c); tid != "" && h.db.CreditEnforceEnabled(c.Request.Context()) {
|
||||
if h.db.TenantBalance(c.Request.Context(), tid) <= 0 {
|
||||
c.JSON(http.StatusPaymentRequired, gin.H{"error": "租户积分余额不足,请充值后再试", "balance_micro": 0})
|
||||
return
|
||||
}
|
||||
}
|
||||
// 附上用户标识(召回偏好记忆)与会话标识(召回短期多轮历史)。
|
||||
// 真实场景由鉴权/会话中间件注入;此处用请求头,缺省匿名/默认会话。
|
||||
task.Meta[contract.MetaUserID] = userID(c)
|
||||
|
||||
Reference in New Issue
Block a user