feat: 订阅套餐支持限定额度可用分组(quota_usable_groups) - #6133
Conversation
套餐新增 quota_usable_groups 字段(逗号分隔,留空不限制): - 预扣费时跳过不适用于当前请求分组的订阅,仅消耗匹配的订阅额度 - subscription_first 策略下,请求分组无可用订阅时直接改走钱包余额 (分组不匹配不属于额度耗尽,不受 allow_wallet_overflow 限制) - 管理端创建/更新套餐接口校验并持久化该字段 - default / classic 两套前端套餐表单支持配置该字段
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
✅ Files skipped from review due to trivial changes (3)
🚧 Files skipped from review as they are similar to previous changes (2)
WalkthroughSubscription plans gain optional quota-usable group restrictions. Admin APIs validate and persist groups, billing filters subscription funding by request group, tests cover the behavior, and both subscription administration UIs expose localized form fields. ChangesSubscription quota enforcement
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant AdminUI
participant SubscriptionController
participant SubscriptionPlan
participant BillingSession
participant Wallet
AdminUI->>SubscriptionController: submit quota usable groups
SubscriptionController->>SubscriptionPlan: validate and persist groups
BillingSession->>SubscriptionPlan: check request group eligibility
alt eligible subscription
BillingSession->>SubscriptionPlan: pre-consume subscription quota
else ineligible subscription
BillingSession->>Wallet: use wallet funding
end
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx (1)
328-346: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider a multi-select instead of freeform text for consistency and typo-safety.
groupOptionsis already fetched here and used to populateupgrade_groupas aForm.Select.quota_usable_groupsinstead uses a plainForm.Inputfor comma-separated names, so a typo only surfaces as a server-side error after submit ("额度可用分组不存在: ..." percontroller/subscription.go). Sourcing this field from the samegroupOptions(e.g. a multi-select) would prevent invalid group names up front and align the UX with the adjacent field.Also applies to: 348-358
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx` around lines 328 - 346, The upgrade_group and quota_usable_groups fields should use a multi-select sourced from the existing groupOptions instead of freeform text or single selection. Update the Form.Select configuration and the adjacent quota_usable_groups field to support selecting multiple valid groups, preserving the existing loading, clear, labels, and translation behavior while preventing arbitrary group names.web/default/src/features/subscriptions/components/subscriptions-mutate-drawer.tsx (1)
478-501: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider a multi-select bound to
groupOptionsinstead of free-text CSV.
upgrade_group/downgrade_groupuse aSelectpopulated fromgroupOptionsto prevent typos;quota_usable_groupsaccepts arbitrary comma-separated text with no client-side validation against known groups. Invalid group names will only be caught after a round-trip to the admin API (额度可用分组不存在: ...), which is a worse UX than the existing group pickers in this same form.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/features/subscriptions/components/subscriptions-mutate-drawer.tsx` around lines 478 - 501, Replace the free-text quota_usable_groups Input with the form’s existing multi-select pattern, binding selected values to quota_usable_groups and populating options from groupOptions. Preserve empty selection as no restriction, and reuse the established group picker behavior used by upgrade_group and downgrade_group so users can only choose valid groups.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@web/default/src/features/subscriptions/components/subscriptions-mutate-drawer.tsx`:
- Around line 492-496: The FormDescription in the subscription quota
configuration must reflect billing preference behavior: under
subscription_first, unmatched groups fall back to wallet balance; under
subscription_only, they are treated as insufficient subscription quota. Update
the translation text around the subscription quota field to communicate this
distinction accurately.
---
Nitpick comments:
In
`@web/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx`:
- Around line 328-346: The upgrade_group and quota_usable_groups fields should
use a multi-select sourced from the existing groupOptions instead of freeform
text or single selection. Update the Form.Select configuration and the adjacent
quota_usable_groups field to support selecting multiple valid groups, preserving
the existing loading, clear, labels, and translation behavior while preventing
arbitrary group names.
In
`@web/default/src/features/subscriptions/components/subscriptions-mutate-drawer.tsx`:
- Around line 478-501: Replace the free-text quota_usable_groups Input with the
form’s existing multi-select pattern, binding selected values to
quota_usable_groups and populating options from groupOptions. Preserve empty
selection as no restriction, and reuse the established group picker behavior
used by upgrade_group and downgrade_group so users can only choose valid groups.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 48abc81c-753e-469e-8374-15f444d08422
📒 Files selected for processing (16)
controller/subscription.gomodel/subscription.gomodel/subscription_group_limit_test.gomodel/task_cas_test.goservice/billing_session.goservice/billing_session_group_test.goservice/funding_source.goservice/task_billing_test.goweb/classic/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsxweb/classic/src/i18n/locales/en.jsonweb/default/src/features/subscriptions/components/subscriptions-mutate-drawer.tsxweb/default/src/features/subscriptions/lib/plan-form.tsweb/default/src/features/subscriptions/types.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/zh.jsonweb/default/src/i18n/static-keys.ts
- 额度可用分组改为基于分组列表的多选下拉(default / classic),无效分组名在前端即可拦截,与相邻的升级/降级分组字段交互一致 - 修正字段描述:分组不匹配回退钱包仅适用于订阅优先策略,计费偏好为仅订阅时将按订阅额度不足处理
|
撤回此 PR:该功能改为在自建部署侧自行维护,不再推进上游合并。感谢 review,打扰了。 |
📝 变更描述 / Description
问题:订阅计费选择资金来源时只看
billing_preference与是否存在活跃订阅,PreConsumeUserSubscription挑选订阅只按end_time排序,全程不校验请求使用的分组。导致订阅额度可以被任意分组消耗——典型套利场景:套餐绑定 1x 分组,用户创建 0.05x 低倍率分组的令牌烧订阅额度,等效额度被放大 20 倍(即 #5200 的根因)。方案:给套餐增加独立字段
quota_usable_groups(varchar(255),逗号分隔,留空 = 不限制,完全向后兼容),不绑死在upgrade_group上(不升级分组的套餐同样需要限制):PreConsumeUserSubscription增加group参数(来自relayInfo.UsingGroup,即请求实际使用的分组),候选循环中跳过额度不适用于该分组的订阅;多订阅共存时只消耗匹配的订阅NewBillingSession默认策略(subscription_first)下,若无额度可用于当前分组的活跃订阅,直接走钱包余额。分组不匹配不属于额度耗尽,因此不受allow_wallet_overflow限制;subscription_only则按订阅额度不足报错GroupRatio并持久化(更新走 updateMap,避免旧前端保存时抹掉该字段)按「请求分组」而非「模型名」校验的原因:计费倍率本身按分组计算,同一模型可存在于多个分组,按分组限制与计费闭环一致。
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
📸 运行证明 / Proof of Work
单元测试(新增
model/subscription_group_limit_test.go、service/billing_session_group_test.go,覆盖:分组匹配/不匹配、多订阅只消耗匹配项、无匹配订阅时回退钱包):生产实测(套餐
quota_usable_groups='codex团队版',同一用户同一模型各请求一次,logs.other 摘录):留空
quota_usable_groups的既有套餐行为与现状完全一致;新列由 AutoMigrate 自动创建。Summary by CodeRabbit
quota_usable_groupssupport across admin and operator subscription plan forms (multi-select; empty means unrestricted).