Skip to content

Commit 9b1097f

Browse files
committed
[server] Introduce BillingMode incl. tests
1 parent 7eeb780 commit 9b1097f

File tree

7 files changed

+789
-1
lines changed

7 files changed

+789
-1
lines changed

components/ee/payment-endpoint/src/accounting/subscription-service.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,17 @@ export class SubscriptionService {
133133
* @returns Whether the user has an active subscription (user-paid or team s.) at the given date
134134
*/
135135
async hasActivePaidSubscription(userId: string, date: Date): Promise<boolean> {
136+
return (await this.getActivePaidSubscription(userId, date)).length > 0;
137+
}
138+
139+
/**
140+
* @param userId
141+
* @param date The date on which the subscription has to be active
142+
* @returns The list of a active subscriptions (user-paid or team s.) at the given date
143+
*/
144+
async getActivePaidSubscription(userId: string, date: Date): Promise<Subscription[]> {
136145
const subscriptions = await this.accountingDB.findActiveSubscriptionsForUser(userId, date.toISOString());
137-
return subscriptions.filter((s) => Subscription.isActive(s, date.toISOString())).length > 0;
146+
return subscriptions.filter((s) => Subscription.isActive(s, date.toISOString()));
138147
}
139148

140149
async store(db: AccountingDB, model: SubscriptionModel) {

components/gitpod-protocol/src/accounting-protocol.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ export namespace Subscription {
199199
export function isActive(s: Subscription, date: string): boolean {
200200
return s.startDate <= date && (s.endDate === undefined || date < s.endDate);
201201
}
202+
export function isCancelled(s: Subscription, date: string): boolean {
203+
return (!!s.cancellationDate && s.cancellationDate < date) || (!!s.endDate && s.endDate < date); // This edge case is meant to handle bad data: If for whatever reason cancellationDate has not been set: treat endDate as such
204+
}
202205
export function isDowngraded(s: Subscription) {
203206
return s.paymentData && s.paymentData.downgradeDate;
204207
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License-AGPL.txt in the project root for license information.
5+
*/
6+
7+
/**
8+
* BillingMode is used to answer the following questions:
9+
* - Should UI piece x be displayed for this user/team?
10+
* - What model should be used to limit this workspace's capabilities (mayStartWorkspace, setTimeout, workspace class, etc...)
11+
* - How is a workspace session charged for?
12+
*/
13+
export type BillingMode =
14+
| None
15+
| ChargebeeFreeTier
16+
| ChargebeePaidTier
17+
| ChargebeePaidTierCancelled
18+
| UBBFreeTier
19+
| UBBPaidTier;
20+
21+
export namespace BillingMode {
22+
export const NONE: BillingMode = {
23+
mode: "none",
24+
};
25+
}
26+
27+
/** Payment is disabled */
28+
interface None {
29+
mode: "none";
30+
}
31+
32+
/** Default case without any subscription, when UBB is disabled */
33+
interface ChargebeeFreeTier {
34+
mode: "chargebee";
35+
tier: "free";
36+
}
37+
38+
/** When there is _any_ paid subscription on Chargbee that's active, either personal or team based */
39+
interface ChargebeePaidTier {
40+
mode: "chargebee";
41+
tier: "paid";
42+
/** All active paid plans ids */
43+
planIds: string[];
44+
45+
/** Whether or not the user has an active personal plan */
46+
hasPersonalPlan?: boolean;
47+
}
48+
49+
/** When there is any paid, active Chargebee subscription , that has already been cancelled, and UBB is enabled */
50+
interface ChargebeePaidTierCancelled {
51+
mode: "chargebee";
52+
tier: "paid_cancelled_and_ubb";
53+
/** All active paid plans ids */
54+
planIds: string[];
55+
}
56+
57+
/** Default case without any subscription, when UBB is enabled */
58+
interface UBBFreeTier {
59+
mode: "usage-based";
60+
tier: "free";
61+
}
62+
63+
/** When UBB is enabled and the user has a paid subscription */
64+
interface UBBPaidTier {
65+
mode: "usage-based";
66+
tier: "paid";
67+
}

components/gitpod-protocol/src/team-subscription-protocol.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ export namespace TeamSubscription2 {
5555
export const isActive = (ts2: TeamSubscription2, date: string): boolean => {
5656
return ts2.startDate <= date && (ts2.endDate === undefined || date < ts2.endDate);
5757
};
58+
export function isCancelled(s: TeamSubscription2, date: string): boolean {
59+
return (!!s.cancellationDate && s.cancellationDate < date) || (!!s.endDate && s.endDate < date); // This edge case is meant to handle bad data: If for whatever reason cancellationDate has not been set: treat endDate as such
60+
}
5861
}
5962

6063
/**

0 commit comments

Comments
 (0)