Skip to content

Commit 726b137

Browse files
FelixMalfaitcursoragentgithub-actions[bot]
authored
fix: convert metered tier upTo from internal to display credits in listPlans (#18108)
## Summary - The `listPlans` GraphQL query was returning metered tier `upTo` values in internal credit units (1000x the display value), causing "Credits by period" and "Credit Plan" dropdowns to show "50M" instead of "50k" - Applied the existing `INTERNAL_CREDITS_PER_DISPLAY_CREDIT` (1000) divisor in `formatBillingDatabasePriceToMeteredPriceDTO`, matching the conversion already used in `getMeteredProductsUsage` resolver - Updated frontend mock data to reflect the corrected display-unit values ## Test plan - [x] Unit tests pass for `format-database-product-to-graphql-dto.util` - [x] Unit tests pass for `metered-credit.service` and `billing-credit-rollover.service` - [ ] Verify billing page shows correct credit amounts (50k, not 50M) for "Credits by period" and "Credit Plan" Made with [Cursor](https://cursor.com) --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
1 parent 783e57f commit 726b137

File tree

3 files changed

+82
-28
lines changed

3 files changed

+82
-28
lines changed

packages/twenty-front/src/testing/mock-data/billing-plans.ts

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const mockBillingPlans = {
5858
__typename: 'BillingPriceTier',
5959
flatAmount: 999000,
6060
unitAmount: null,
61-
upTo: 7500000000,
61+
upTo: 7500000,
6262
},
6363
{
6464
__typename: 'BillingPriceTier',
@@ -78,7 +78,7 @@ export const mockBillingPlans = {
7878
__typename: 'BillingPriceTier',
7979
flatAmount: 399000,
8080
unitAmount: null,
81-
upTo: 2600000000,
81+
upTo: 2600000,
8282
},
8383
{
8484
__typename: 'BillingPriceTier',
@@ -98,7 +98,7 @@ export const mockBillingPlans = {
9898
__typename: 'BillingPriceTier',
9999
flatAmount: 199000,
100100
unitAmount: null,
101-
upTo: 1200000000,
101+
upTo: 1200000,
102102
},
103103
{
104104
__typename: 'BillingPriceTier',
@@ -118,7 +118,7 @@ export const mockBillingPlans = {
118118
__typename: 'BillingPriceTier',
119119
flatAmount: 99000,
120120
unitAmount: null,
121-
upTo: 540000000,
121+
upTo: 540000,
122122
},
123123
{
124124
__typename: 'BillingPriceTier',
@@ -138,7 +138,7 @@ export const mockBillingPlans = {
138138
__typename: 'BillingPriceTier',
139139
flatAmount: 29000,
140140
unitAmount: null,
141-
upTo: 130000000,
141+
upTo: 130000,
142142
},
143143
{
144144
__typename: 'BillingPriceTier',
@@ -158,7 +158,7 @@ export const mockBillingPlans = {
158158
__typename: 'BillingPriceTier',
159159
flatAmount: 0,
160160
unitAmount: null,
161-
upTo: 50000000,
161+
upTo: 50000,
162162
},
163163
{
164164
__typename: 'BillingPriceTier',
@@ -178,7 +178,7 @@ export const mockBillingPlans = {
178178
__typename: 'BillingPriceTier',
179179
flatAmount: 99900,
180180
unitAmount: null,
181-
upTo: 700000000,
181+
upTo: 700000,
182182
},
183183
{
184184
__typename: 'BillingPriceTier',
@@ -198,7 +198,7 @@ export const mockBillingPlans = {
198198
__typename: 'BillingPriceTier',
199199
flatAmount: 39900,
200200
unitAmount: null,
201-
upTo: 240000000,
201+
upTo: 240000,
202202
},
203203
{
204204
__typename: 'BillingPriceTier',
@@ -218,7 +218,7 @@ export const mockBillingPlans = {
218218
__typename: 'BillingPriceTier',
219219
flatAmount: 19900,
220220
unitAmount: null,
221-
upTo: 110000000,
221+
upTo: 110000,
222222
},
223223
{
224224
__typename: 'BillingPriceTier',
@@ -238,7 +238,7 @@ export const mockBillingPlans = {
238238
__typename: 'BillingPriceTier',
239239
flatAmount: 9900,
240240
unitAmount: null,
241-
upTo: 50000000,
241+
upTo: 50000,
242242
},
243243
{
244244
__typename: 'BillingPriceTier',
@@ -258,7 +258,7 @@ export const mockBillingPlans = {
258258
__typename: 'BillingPriceTier',
259259
flatAmount: 2900,
260260
unitAmount: null,
261-
upTo: 10000000,
261+
upTo: 10000,
262262
},
263263
{
264264
__typename: 'BillingPriceTier',
@@ -278,7 +278,7 @@ export const mockBillingPlans = {
278278
__typename: 'BillingPriceTier',
279279
flatAmount: 0,
280280
unitAmount: null,
281-
upTo: 5000000,
281+
upTo: 5000,
282282
},
283283
{
284284
__typename: 'BillingPriceTier',
@@ -348,7 +348,7 @@ export const mockBillingPlans = {
348348
__typename: 'BillingPriceTier',
349349
flatAmount: 999000,
350350
unitAmount: null,
351-
upTo: 7500000000,
351+
upTo: 7500000,
352352
},
353353
{
354354
__typename: 'BillingPriceTier',
@@ -368,7 +368,7 @@ export const mockBillingPlans = {
368368
__typename: 'BillingPriceTier',
369369
flatAmount: 399000,
370370
unitAmount: null,
371-
upTo: 2600000000,
371+
upTo: 2600000,
372372
},
373373
{
374374
__typename: 'BillingPriceTier',
@@ -388,7 +388,7 @@ export const mockBillingPlans = {
388388
__typename: 'BillingPriceTier',
389389
flatAmount: 199000,
390390
unitAmount: null,
391-
upTo: 1200000000,
391+
upTo: 1200000,
392392
},
393393
{
394394
__typename: 'BillingPriceTier',
@@ -408,7 +408,7 @@ export const mockBillingPlans = {
408408
__typename: 'BillingPriceTier',
409409
flatAmount: 99000,
410410
unitAmount: null,
411-
upTo: 540000000,
411+
upTo: 540000,
412412
},
413413
{
414414
__typename: 'BillingPriceTier',
@@ -428,7 +428,7 @@ export const mockBillingPlans = {
428428
__typename: 'BillingPriceTier',
429429
flatAmount: 29000,
430430
unitAmount: null,
431-
upTo: 130000000,
431+
upTo: 130000,
432432
},
433433
{
434434
__typename: 'BillingPriceTier',
@@ -448,7 +448,7 @@ export const mockBillingPlans = {
448448
__typename: 'BillingPriceTier',
449449
flatAmount: 0,
450450
unitAmount: null,
451-
upTo: 50000000,
451+
upTo: 50000,
452452
},
453453
{
454454
__typename: 'BillingPriceTier',
@@ -468,7 +468,7 @@ export const mockBillingPlans = {
468468
__typename: 'BillingPriceTier',
469469
flatAmount: 99900,
470470
unitAmount: null,
471-
upTo: 700000000,
471+
upTo: 700000,
472472
},
473473
{
474474
__typename: 'BillingPriceTier',
@@ -488,7 +488,7 @@ export const mockBillingPlans = {
488488
__typename: 'BillingPriceTier',
489489
flatAmount: 39900,
490490
unitAmount: null,
491-
upTo: 240000000,
491+
upTo: 240000,
492492
},
493493
{
494494
__typename: 'BillingPriceTier',
@@ -508,7 +508,7 @@ export const mockBillingPlans = {
508508
__typename: 'BillingPriceTier',
509509
flatAmount: 19900,
510510
unitAmount: null,
511-
upTo: 110000000,
511+
upTo: 110000,
512512
},
513513
{
514514
__typename: 'BillingPriceTier',
@@ -528,7 +528,7 @@ export const mockBillingPlans = {
528528
__typename: 'BillingPriceTier',
529529
flatAmount: 9900,
530530
unitAmount: null,
531-
upTo: 50000000,
531+
upTo: 50000,
532532
},
533533
{
534534
__typename: 'BillingPriceTier',
@@ -548,7 +548,7 @@ export const mockBillingPlans = {
548548
__typename: 'BillingPriceTier',
549549
flatAmount: 2900,
550550
unitAmount: null,
551-
upTo: 10000000,
551+
upTo: 10000,
552552
},
553553
{
554554
__typename: 'BillingPriceTier',
@@ -568,7 +568,7 @@ export const mockBillingPlans = {
568568
__typename: 'BillingPriceTier',
569569
flatAmount: 0,
570570
unitAmount: null,
571-
upTo: 5000000,
571+
upTo: 5000,
572572
},
573573
{
574574
__typename: 'BillingPriceTier',

packages/twenty-server/src/engine/core-modules/billing/utils/__tests__/format-database-product-to-graphql-dto.util.spec.ts

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
3131
{
3232
interval: SubscriptionInterval.Month,
3333
tiers: [
34-
{ up_to: 10, flat_amount: 500, unit_amount: null },
34+
{
35+
up_to: 10000000,
36+
flat_amount: 500,
37+
unit_amount: null,
38+
},
3539
{ up_to: null, flat_amount: null, unit_amount: 0.001 },
3640
],
3741
stripePriceId: 'price_metered1',
@@ -81,7 +85,11 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
8185
{
8286
interval: SubscriptionInterval.Month,
8387
tiers: [
84-
{ up_to: 10, flat_amount: 500, unit_amount: null },
88+
{
89+
up_to: 10000000,
90+
flat_amount: 500,
91+
unit_amount: null,
92+
},
8593
{ up_to: null, flat_amount: null, unit_amount: 0.001 },
8694
],
8795
stripePriceId: 'price_metered1',
@@ -91,7 +99,7 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
9199
prices: [
92100
{
93101
tiers: [
94-
{ upTo: 10, flatAmount: 500, unitAmount: null },
102+
{ upTo: 10000, flatAmount: 500, unitAmount: null },
95103
{ upTo: null, flatAmount: null, unitAmount: 0.001 },
96104
],
97105
recurringInterval: SubscriptionInterval.Month,
@@ -103,4 +111,49 @@ describe('formatBillingDatabaseProductToGraphqlDTO', () => {
103111
],
104112
});
105113
});
114+
115+
it('should convert internal credits to display credits in metered tier upTo', () => {
116+
const mockPlan = {
117+
planKey: BillingPlanKey.PRO,
118+
licensedProducts: [],
119+
meteredProducts: [
120+
{
121+
id: 'product-2',
122+
name: 'Test Metered Product',
123+
billingPrices: [
124+
{
125+
interval: SubscriptionInterval.Month,
126+
tiers: [
127+
{
128+
up_to: 50000000,
129+
flat_amount: 0,
130+
unit_amount: null,
131+
},
132+
{
133+
up_to: null,
134+
flat_amount: null,
135+
unit_amount: null,
136+
},
137+
],
138+
stripePriceId: 'price_metered1',
139+
priceUsageType: BillingUsageType.METERED,
140+
},
141+
],
142+
},
143+
],
144+
};
145+
146+
const result = formatBillingDatabaseProductToGraphqlDTO(
147+
mockPlan as unknown as BillingGetPlanResult,
148+
);
149+
150+
const meteredPrices = result.meteredProducts[0].prices;
151+
152+
expect(meteredPrices![0].tiers[0]).toEqual(
153+
expect.objectContaining({ upTo: 50000 }),
154+
);
155+
expect(meteredPrices![0].tiers[1]).toEqual(
156+
expect.objectContaining({ upTo: null }),
157+
);
158+
});
106159
});

packages/twenty-server/src/engine/core-modules/billing/utils/format-database-product-to-graphql-dto.util.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { type BillingPriceEntity } from 'src/engine/core-modules/billing/entitie
77
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum';
88
import { BillingUsageType } from 'src/engine/core-modules/billing/enums/billing-usage-type.enum';
99
import { type BillingGetPlanResult } from 'src/engine/core-modules/billing/types/billing-get-plan-result.type';
10+
import { toDisplayCredits } from 'src/engine/core-modules/billing/utils/to-display-credits.util';
1011

1112
export const formatBillingDatabaseProductToGraphqlDTO = (
1213
plan: BillingGetPlanResult,
@@ -42,7 +43,7 @@ const formatBillingDatabasePriceToMeteredPriceDTO = (
4243
return {
4344
tiers:
4445
billingPrice?.tiers?.map((tier) => ({
45-
upTo: tier.up_to,
46+
upTo: tier.up_to !== null ? toDisplayCredits(tier.up_to) : tier.up_to,
4647
flatAmount: tier.flat_amount,
4748
unitAmount: tier.unit_amount,
4849
})) ?? [],

0 commit comments

Comments
 (0)