Skip to content

Commit 2481e08

Browse files
committed
[ubp] add chargebee cost center on cancellation
1 parent 2eead4a commit 2481e08

File tree

10 files changed

+455
-332
lines changed

10 files changed

+455
-332
lines changed

components/ee/payment-endpoint/BUILD.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ packages:
1010
deps:
1111
- components/gitpod-db:lib
1212
- components/gitpod-protocol:lib
13+
- components/usage-api/typescript:lib
1314
config:
1415
packaging: offline-mirror
1516
yarnLock: ${coreYarnLockBase}/../yarn.lock
@@ -24,6 +25,7 @@ packages:
2425
deps:
2526
- components/gitpod-db:lib
2627
- components/gitpod-protocol:lib
28+
- components/usage-api/typescript:lib
2729
- :dbtest
2830
config:
2931
packaging: library
@@ -54,6 +56,7 @@ packages:
5456
- components/gitpod-db:dbtest-init
5557
- components/gitpod-db:lib
5658
- components/gitpod-protocol:lib
59+
- components/usage-api/typescript:lib
5760
config:
5861
packaging: library
5962
yarnLock: ${coreYarnLockBase}/../yarn.lock

components/ee/payment-endpoint/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"dependencies": {
88
"@gitpod/gitpod-db": "0.1.5",
99
"@gitpod/gitpod-protocol": "0.1.5",
10+
"@gitpod/usage-api": "0.1.5",
1011
"@octokit/rest": "18.5.6",
1112
"@octokit/webhooks": "9.17.0",
1213
"body-parser": "^1.19.2",

components/ee/payment-endpoint/src/chargebee/subscription-handler.ts

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,30 @@
44
* See License.enterprise.txt in the project root folder.
55
*/
66

7-
import { inject, injectable } from 'inversify';
8-
9-
import { SubscriptionService } from '../accounting/subscription-service';
10-
import { AccountingDB } from '@gitpod/gitpod-db/lib/accounting-db';
11-
import { log, LogContext } from '@gitpod/gitpod-protocol/lib/util/logging';
12-
import { SubscriptionMapperFactory } from './subscription-mapper';
13-
import { Plans } from '@gitpod/gitpod-protocol/lib/plans';
14-
import { Chargebee as chargebee } from './chargebee-types';
15-
import { EventHandler } from './chargebee-event-handler';
16-
import { UpgradeHelper } from './upgrade-helper';
7+
import { inject, injectable } from "inversify";
8+
9+
import { SubscriptionService } from "../accounting/subscription-service";
10+
import { AccountingDB } from "@gitpod/gitpod-db/lib/accounting-db";
11+
import { log, LogContext } from "@gitpod/gitpod-protocol/lib/util/logging";
12+
import { SubscriptionMapper } from "./subscription-mapper";
13+
import { Plans } from "@gitpod/gitpod-protocol/lib/plans";
14+
import { Chargebee as chargebee } from "./chargebee-types";
15+
import { EventHandler } from "./chargebee-event-handler";
16+
import { UpgradeHelper } from "./upgrade-helper";
1717
import { formatDate } from "@gitpod/gitpod-protocol/lib/util/date-time";
18-
import { getUpdatedAt } from './chargebee-subscription-helper';
19-
import { UserPaidSubscription } from '@gitpod/gitpod-protocol/lib/accounting-protocol';
20-
import { DBSubscriptionAdditionalData } from '@gitpod/gitpod-db/lib/typeorm/entity/db-subscription';
18+
import { getUpdatedAt } from "./chargebee-subscription-helper";
19+
import { UserPaidSubscription } from "@gitpod/gitpod-protocol/lib/accounting-protocol";
20+
import { DBSubscriptionAdditionalData } from "@gitpod/gitpod-db/lib/typeorm/entity/db-subscription";
2121

2222
@injectable()
2323
export class SubscriptionHandler implements EventHandler<chargebee.SubscriptionEventV2> {
2424
@inject(SubscriptionService) protected readonly subscriptionService: SubscriptionService;
2525
@inject(AccountingDB) protected readonly db: AccountingDB;
26-
@inject(SubscriptionMapperFactory) protected readonly mapperFactory: SubscriptionMapperFactory;
26+
@inject(SubscriptionMapper) protected readonly mapper: SubscriptionMapper;
2727
@inject(UpgradeHelper) protected readonly upgradeHelper: UpgradeHelper;
2828

2929
canHandle(event: chargebee.Event<any>): boolean {
30-
if (event.event_type.startsWith('subscription')) {
30+
if (event.event_type.startsWith("subscription")) {
3131
const evt = event as chargebee.Event<chargebee.SubscriptionEventV2>;
3232
const plan = Plans.getById(evt.content.subscription.plan_id);
3333
return !!plan && !plan.team;
@@ -44,16 +44,16 @@ export class SubscriptionHandler implements EventHandler<chargebee.SubscriptionE
4444
log.debug(logContext, `Start SubscriptionHandler.handleSingleEvent`, { eventType });
4545
try {
4646
if (!event.content.subscription) {
47-
log.error(logContext, 'Ignoring event, because it does not contain a subscription', event);
47+
log.error(logContext, "Ignoring event, because it does not contain a subscription", event);
4848
} else {
4949
try {
5050
await this.storeAdditionalData(event.content.subscription, event.content.invoice);
51-
} catch(err) {
52-
log.error(logContext, 'Failed to store additional subscription data', event);
51+
} catch (err) {
52+
log.error(logContext, "Failed to store additional subscription data", event);
5353
}
5454
}
5555

56-
if (event.event_type === 'subscription_changed') {
56+
if (event.event_type === "subscription_changed") {
5757
await this.checkAndChargeForUpgrade(userId, chargebeeSubscription);
5858
}
5959

@@ -70,11 +70,12 @@ export class SubscriptionHandler implements EventHandler<chargebee.SubscriptionE
7070
const paymentReference = subscription.id;
7171
const coupons = subscription.coupons;
7272
const mrr = subscription.mrr || 0;
73-
const nextBilling = subscription.next_billing_at && new Date(subscription.next_billing_at * 1000).toISOString() || '';
74-
let lastInvoice = '';
73+
const nextBilling =
74+
(subscription.next_billing_at && new Date(subscription.next_billing_at * 1000).toISOString()) || "";
75+
let lastInvoice = "";
7576
let lastInvoiceAmount: number = 0;
7677
if (invoice) {
77-
lastInvoice = invoice.date && new Date(invoice.date * 1000).toISOString() || '';
78+
lastInvoice = (invoice.date && new Date(invoice.date * 1000).toISOString()) || "";
7879
lastInvoiceAmount = invoice.total || 0;
7980
}
8081

@@ -84,7 +85,7 @@ export class SubscriptionHandler implements EventHandler<chargebee.SubscriptionE
8485
mrr,
8586
lastInvoice,
8687
lastInvoiceAmount,
87-
nextBilling
88+
nextBilling,
8889
};
8990
await this.db.storeSubscriptionAdditionalData(data);
9091
}
@@ -100,18 +101,28 @@ export class SubscriptionHandler implements EventHandler<chargebee.SubscriptionE
100101
protected async checkAndChargeForUpgrade(userId: string, chargebeeSubscription: chargebee.Subscription) {
101102
const gitpodSubscriptions = await this.db.findSubscriptionForUserByPaymentRef(userId, chargebeeSubscription.id);
102103
if (gitpodSubscriptions.length === 0) {
103-
throw new Error(`Expected existing Gitpod subscription for PaymentRef ${chargebeeSubscription.id} and user ${userId}, found none.`);
104+
throw new Error(
105+
`Expected existing Gitpod subscription for PaymentRef ${chargebeeSubscription.id} and user ${userId}, found none.`,
106+
);
104107
}
105-
const currentGitpodSubscription = gitpodSubscriptions[0]; // Ordered by startDate DESC
108+
const currentGitpodSubscription = gitpodSubscriptions[0]; // Ordered by startDate DESC
106109
const oldPlan = Plans.getById(currentGitpodSubscription.planId)!;
107110
const newPlan = Plans.getById(chargebeeSubscription.plan_id)!;
108111

109112
if (newPlan.pricePerMonth > oldPlan.pricePerMonth) {
110113
// Upgrade: Charge for it!
111-
const diffInCents = (newPlan.pricePerMonth * 100) - (oldPlan.pricePerMonth * 100);
114+
const diffInCents = newPlan.pricePerMonth * 100 - oldPlan.pricePerMonth * 100;
112115
const upgradeTimestamp = getUpdatedAt(chargebeeSubscription);
113-
const description = `Difference on Upgrade from '${oldPlan.name}' to '${newPlan.name}' (${formatDate(upgradeTimestamp)})`;
114-
await this.upgradeHelper.chargeForUpgrade(userId, chargebeeSubscription.id, diffInCents, description, upgradeTimestamp);
116+
const description = `Difference on Upgrade from '${oldPlan.name}' to '${newPlan.name}' (${formatDate(
117+
upgradeTimestamp,
118+
)})`;
119+
await this.upgradeHelper.chargeForUpgrade(
120+
userId,
121+
chargebeeSubscription.id,
122+
diffInCents,
123+
description,
124+
upgradeTimestamp,
125+
);
115126
}
116127
}
117128

@@ -123,14 +134,13 @@ export class SubscriptionHandler implements EventHandler<chargebee.SubscriptionE
123134
protected async mapToGitpodSubscription(userId: string, event: chargebee.Event<chargebee.SubscriptionEventV2>) {
124135
await this.db.transaction(async (db) => {
125136
const subscriptions = await db.findAllSubscriptionsForUser(userId);
126-
const userPaidSubscriptions = subscriptions.filter(s => UserPaidSubscription.is(s));
137+
const userPaidSubscriptions = subscriptions.filter((s) => UserPaidSubscription.is(s));
127138

128-
const mapper = this.mapperFactory.newMapper();
129-
const delta = mapper.map(userPaidSubscriptions, event).getResult();
139+
const delta = this.mapper.map(userPaidSubscriptions, event).getResult();
130140

131141
await Promise.all([
132-
...delta.updates.map(s => db.storeSubscription(s)),
133-
...delta.inserts.map(s => db.newSubscription(s))
142+
...delta.updates.map((s) => db.storeSubscription(s)),
143+
...delta.inserts.map((s) => db.newSubscription(s)),
134144
]);
135145
});
136146
}
@@ -142,4 +152,4 @@ export class SubscriptionHandler implements EventHandler<chargebee.SubscriptionE
142152
// 3. Apply all events to handleSingleEvent
143153
// 4. Compare result with the one from the API
144154
}
145-
}
155+
}

0 commit comments

Comments
 (0)