-
Notifications
You must be signed in to change notification settings - Fork 12k
fix: adjust free monthly credits for orgs #23798
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
541a204
8e6103a
820c81b
fcd1bbd
0abac1d
4b5f1a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -588,8 +588,6 @@ export class CreditService { | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!team) return 0; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| let totalMonthlyCredits = 0; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const teamBillingService = new InternalTeamBilling(team); | ||||||||||||||||||||||||||||||
| const subscriptionStatus = await teamBillingService.getSubscriptionStatus(); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
@@ -599,25 +597,25 @@ export class CreditService { | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const activeMembers = team.members.filter((member) => member.accepted).length; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const billingService = new StripeBillingService(); | ||||||||||||||||||||||||||||||
| if (team.isOrganization) { | ||||||||||||||||||||||||||||||
| const orgMonthlyCredits = process.env.ORG_MONTHLY_CREDITS; | ||||||||||||||||||||||||||||||
| const creditsPerSeat = orgMonthlyCredits ? parseInt(orgMonthlyCredits) : 1000; | ||||||||||||||||||||||||||||||
| return activeMembers * creditsPerSeat; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+600
to
+604
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Robust parsing of ORG_MONTHLY_CREDITS (0 treated as falsy today). Current code ignores an explicit 0 and lacks NaN/range handling; also no radix. Parse safely, accept 0, clamp to >= 0. - const orgMonthlyCredits = process.env.ORG_MONTHLY_CREDITS;
- const creditsPerSeat = orgMonthlyCredits ? parseInt(orgMonthlyCredits) : 1000;
+ const rawOrgMonthlyCredits = process.env.ORG_MONTHLY_CREDITS;
+ const parsedOrgMonthlyCredits =
+ rawOrgMonthlyCredits != null ? Number(rawOrgMonthlyCredits) : NaN;
+ const creditsPerSeat = Number.isFinite(parsedOrgMonthlyCredits)
+ ? Math.max(0, Math.floor(parsedOrgMonthlyCredits))
+ : 1000;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const priceId = team.isOrganization | ||||||||||||||||||||||||||||||
| ? process.env.STRIPE_ORG_MONTHLY_PRICE_ID | ||||||||||||||||||||||||||||||
| : process.env.STRIPE_TEAM_MONTHLY_PRICE_ID; | ||||||||||||||||||||||||||||||
| const billingService = new StripeBillingService(); | ||||||||||||||||||||||||||||||
| const priceId = process.env.STRIPE_TEAM_MONTHLY_PRICE_ID; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!priceId) { | ||||||||||||||||||||||||||||||
| log.warn("Monthly price ID not configured", { teamId, isOrganization: team.isOrganization }); | ||||||||||||||||||||||||||||||
| log.warn("Monthly price ID not configured", { teamId }); | ||||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const monthlyPrice = await billingService.getPrice(priceId || ""); | ||||||||||||||||||||||||||||||
| const monthlyPrice = await billingService.getPrice(priceId); | ||||||||||||||||||||||||||||||
| const pricePerSeat = monthlyPrice.unit_amount ?? 0; | ||||||||||||||||||||||||||||||
| const creditsPerSeat = pricePerSeat * 0.5; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Teams get 50% of the price as credits, organizations get 20% | ||||||||||||||||||||||||||||||
| const creditMultiplier = team.isOrganization ? 0.2 : 0.5; | ||||||||||||||||||||||||||||||
| totalMonthlyCredits = activeMembers * pricePerSeat * creditMultiplier; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return totalMonthlyCredits; | ||||||||||||||||||||||||||||||
| return activeMembers * creditsPerSeat; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| calculateCreditsFromPrice(price: number) { | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -120,6 +120,7 @@ | |
| "NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE_MONTHLY", | ||
| "NEXT_PUBLIC_STRIPE_PRICING_TABLE_PUBLISHABLE_KEY", | ||
| "NEXT_PUBLIC_STRIPE_CREDITS_PRICE_ID", | ||
| "ORG_MONTHLY_CREDITS", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: turbo json has env variables in alphabetical order
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. doesn't really look sorted to me 🤔 |
||
| "NEXT_PUBLIC_PLAIN_CHAT_ID", | ||
| "NEXT_PUBLIC_PLAIN_CHAT_EXCLUDED_PATHS", | ||
| "NEXT_PUBLIC_BOOKER_NUMBER_OF_DAYS_TO_LOAD", | ||
|
|
@@ -187,6 +188,7 @@ | |
| "STRIPE_TEAM_MONTHLY_PRICE_ID", | ||
| "STRIPE_TEAM_PRODUCT_ID", | ||
| "STRIPE_ORG_MONTHLY_PRICE_ID", | ||
| "ORG_MONTHLY_CREDITS", | ||
| "TANDEM_BASE_URL", | ||
| "TANDEM_CLIENT_ID", | ||
| "TANDEM_CLIENT_SECRET", | ||
|
|
@@ -331,6 +333,7 @@ | |
| "STRIPE_TEAM_MONTHLY_PRICE_ID", | ||
| "NEXT_PUBLIC_STRIPE_CREDITS_PRICE_ID", | ||
| "STRIPE_TEAM_PRODUCT_ID", | ||
| "ORG_MONTHLY_CREDITS", | ||
| "STRIPE_ORG_MONTHLY_PRICE_ID", | ||
| "STRIPE_ORG_PRODUCT_ID", | ||
| "NEXT_PUBLIC_API_V2_URL", | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix env cleanup: use vi.unstubEnv instead of passing undefined
vi.stubEnv expects a string; passing undefined can throw or leak prior value. Unset the var explicitly.
it("should calculate credits for organizations with default 1000 credits per seat", async () => { // Clear ORG_MONTHLY_CREDITS to test default behavior - vi.stubEnv("ORG_MONTHLY_CREDITS", undefined); + vi.unstubEnv("ORG_MONTHLY_CREDITS");Consider also asserting Stripe is not called here, mirroring the previous test.
📝 Committable suggestion
🤖 Prompt for AI Agents