Skip to content

Commit 4a45788

Browse files
committed
[server] BillingMode: Only paid UBP team seats are "greedy"
1 parent 431f526 commit 4a45788

File tree

3 files changed

+32
-19
lines changed

3 files changed

+32
-19
lines changed

components/gitpod-protocol/src/billing-mode.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ interface Chargebee {
5656
interface UsageBased {
5757
mode: "usage-based";
5858

59+
/** True iff this is a team, and is based on a paid plan. Currently only set for teams! */
60+
paid?: boolean;
61+
5962
/** User is already converted, but is member with at least one Chargebee-based "Team Plan" */
6063
hasChargebeeTeamPlan?: boolean;
6164

components/server/ee/src/billing/billing-mode.spec.db.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ class BillingModeSpec {
202202
},
203203
// user: chargebee
204204
{
205-
name: "user: chargbee paid personal",
205+
name: "user: chargebee paid personal",
206206
subject: user(),
207207
config: {
208208
enablePayment: true,
@@ -214,7 +214,7 @@ class BillingModeSpec {
214214
},
215215
},
216216
{
217-
name: "user: chargbee paid team seat",
217+
name: "user: chargebee paid team seat",
218218
subject: user(),
219219
config: {
220220
enablePayment: true,
@@ -226,7 +226,7 @@ class BillingModeSpec {
226226
},
227227
},
228228
{
229-
name: "user: chargbee paid personal + team seat",
229+
name: "user: chargebee paid personal + team seat",
230230
subject: user(),
231231
config: {
232232
enablePayment: true,
@@ -239,7 +239,7 @@ class BillingModeSpec {
239239
},
240240
// user: transition chargebee -> UBB
241241
{
242-
name: "user: chargbee paid personal (cancelled) + team seat",
242+
name: "user: chargebee paid personal (cancelled) + team seat",
243243
subject: user(),
244244
config: {
245245
enablePayment: true,
@@ -255,7 +255,7 @@ class BillingModeSpec {
255255
},
256256
},
257257
{
258-
name: "user: chargbee paid personal (cancelled) + team seat (cancelled)",
258+
name: "user: chargebee paid personal (cancelled) + team seat (cancelled)",
259259
subject: user(),
260260
config: {
261261
enablePayment: true,
@@ -271,7 +271,7 @@ class BillingModeSpec {
271271
},
272272
},
273273
{
274-
name: "user: chargbee paid personal (cancelled) + team seat (active) + stripe",
274+
name: "user: chargebee paid personal (cancelled) + team seat (active) + stripe",
275275
subject: user(),
276276
config: {
277277
enablePayment: true,
@@ -289,7 +289,7 @@ class BillingModeSpec {
289289
},
290290
// user: usage-based
291291
{
292-
name: "user: stripe free, chargbee paid personal (inactive) + team seat (inactive)",
292+
name: "user: stripe free, chargebee paid personal (inactive) + team seat (inactive)",
293293
subject: user(),
294294
config: {
295295
enablePayment: true,
@@ -304,7 +304,7 @@ class BillingModeSpec {
304304
},
305305
},
306306
{
307-
name: "user: stripe paid, chargbee paid personal (inactive) + team seat (inactive)",
307+
name: "user: stripe paid, chargebee paid personal (inactive) + team seat (inactive)",
308308
subject: user(),
309309
config: {
310310
enablePayment: true,
@@ -378,7 +378,7 @@ class BillingModeSpec {
378378
},
379379
// team: chargebee
380380
{
381-
name: "team: chargbee paid",
381+
name: "team: chargebee paid",
382382
subject: team(),
383383
config: {
384384
enablePayment: true,
@@ -390,7 +390,7 @@ class BillingModeSpec {
390390
},
391391
},
392392
{
393-
name: "team: chargbee paid (UBB)",
393+
name: "team: chargebee paid (UBB)",
394394
subject: team(),
395395
config: {
396396
enablePayment: true,
@@ -403,7 +403,7 @@ class BillingModeSpec {
403403
},
404404
// team: transition chargebee -> UBB
405405
{
406-
name: "team: chargbee paid (TeamSubscription2, cancelled)",
406+
name: "team: chargebee paid (TeamSubscription2, cancelled)",
407407
subject: team(),
408408
config: {
409409
enablePayment: true,
@@ -416,7 +416,7 @@ class BillingModeSpec {
416416
},
417417
},
418418
{
419-
name: "team: chargbee paid (old TeamSubscription, cancelled)",
419+
name: "team: chargebee paid (old TeamSubscription, cancelled)",
420420
subject: team(),
421421
config: {
422422
enablePayment: true,
@@ -440,7 +440,7 @@ class BillingModeSpec {
440440
},
441441
},
442442
{
443-
name: "team: stripe free, chargbee (inactive)",
443+
name: "team: stripe free, chargebee (inactive)",
444444
subject: team(),
445445
config: {
446446
enablePayment: true,
@@ -452,7 +452,7 @@ class BillingModeSpec {
452452
},
453453
},
454454
{
455-
name: "team: stripe paid, chargbee (inactive)",
455+
name: "team: stripe paid, chargebee (inactive)",
456456
subject: team(),
457457
config: {
458458
enablePayment: true,
@@ -462,6 +462,7 @@ class BillingModeSpec {
462462
},
463463
expectation: {
464464
mode: "usage-based",
465+
paid: true,
465466
},
466467
},
467468
{
@@ -474,6 +475,7 @@ class BillingModeSpec {
474475
},
475476
expectation: {
476477
mode: "usage-based",
478+
paid: true,
477479
},
478480
},
479481
];

components/server/ee/src/billing/billing-mode.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,12 @@ export class BillingModesImpl implements BillingModes {
135135
// 3. Check team memberships/plans
136136
// UBB overrides wins if there is _any_. But if there is none, use the existing Chargebee subscription.
137137
const teamsModes = await Promise.all(teams.map((t) => this.getBillingModeForTeam(t, now)));
138-
const hasUbbTeam = teamsModes.some((tm) => tm.mode === "usage-based");
138+
const hasUbbPaidTeamSeat = teamsModes.some((tm) => tm.mode === "usage-based" && !!tm.paid);
139139
const hasCbTeam = teamsModes.some((tm) => tm.mode === "chargebee");
140140
const hasCbTeamSeat = cbTeamSubscriptions.length > 0;
141141

142-
if (hasUbbTeam || hasUbbPersonal) {
143-
// UBB is gready: once a user has at least a team seat, they should benefit from it!
142+
if (hasUbbPaidTeamSeat || hasUbbPersonal) {
143+
// UBB is greedy: once a user has at least a team seat, they should benefit from it!
144144
const result: BillingMode = { mode: "usage-based" };
145145
if (hasCbTeam) {
146146
result.hasChargebeeTeamPlan = true;
@@ -196,7 +196,15 @@ export class BillingModesImpl implements BillingModes {
196196
return { mode: "chargebee" };
197197
}
198198

199-
// 3. If not: we don't even have to check for a team subscription
200-
return { mode: "usage-based" };
199+
// 3. Now we're usage-based. We only have to figure out whether we have a plan yet or not.
200+
const result: BillingMode = { mode: "usage-based" };
201+
const customer = await this.stripeSvc.findCustomerByUserId(team.id);
202+
if (customer) {
203+
const subscription = await this.stripeSvc.findUncancelledSubscriptionByCustomer(customer.id);
204+
if (subscription) {
205+
result.paid = true;
206+
}
207+
}
208+
return result;
201209
}
202210
}

0 commit comments

Comments
 (0)