Skip to content

Commit cd36ddd

Browse files
committed
Use upcoming invoice
1 parent 1cd0fbf commit cd36ddd

File tree

13 files changed

+449
-298
lines changed

13 files changed

+449
-298
lines changed

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

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
import { CostCenterDB } from "@gitpod/gitpod-db/lib";
88
import { User } from "@gitpod/gitpod-protocol";
99
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
10-
import { BillableSession, BillableSessionRequest, SortOrder } from "@gitpod/gitpod-protocol/lib/usage";
10+
import { ConfigCatClientFactory } from "@gitpod/gitpod-protocol/lib/experiments/configcat-server";
1111
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
12-
import { CachingUsageServiceClientProvider, UsageService } from "@gitpod/usage-api/lib/usage/v1/sugar";
13-
import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb";
12+
import { GetUpcomingInvoiceResponse } from "@gitpod/usage-api/lib/usage/v1/billing_pb";
13+
import {
14+
CachingUsageServiceClientProvider,
15+
CachingBillingServiceClientProvider,
16+
} from "@gitpod/usage-api/lib/usage/v1/sugar";
1417
import { inject, injectable } from "inversify";
1518
import { UserService } from "../../../src/user/user-service";
1619

@@ -26,6 +29,9 @@ export class BillingService {
2629
@inject(CostCenterDB) protected readonly costCenterDB: CostCenterDB;
2730
@inject(CachingUsageServiceClientProvider)
2831
protected readonly usageServiceClientProvider: CachingUsageServiceClientProvider;
32+
@inject(CachingBillingServiceClientProvider)
33+
protected readonly billingServiceClientProvider: CachingBillingServiceClientProvider;
34+
@inject(ConfigCatClientFactory) protected readonly configCatClientFactory: ConfigCatClientFactory;
2935

3036
async checkSpendingLimitReached(user: User): Promise<SpendingLimitReachedResult> {
3137
const attributionId = await this.userService.getWorkspaceUsageAttributionId(user);
@@ -40,50 +46,53 @@ export class BillingService {
4046
};
4147
}
4248

43-
const allSessions = await this.listBilledUsage({
44-
attributionId: AttributionId.render(attributionId),
45-
startedTimeOrder: SortOrder.Descending,
46-
});
47-
const totalUsage = allSessions.map((s) => s.credits).reduce((a, b) => a + b, 0);
48-
if (totalUsage >= costCenter.spendingLimit) {
49+
if (!(await this.isSpendingLimitCheckEnabled(user))) {
50+
return {
51+
reached: false,
52+
attributionId,
53+
};
54+
}
55+
56+
const upcomingInvoice = await this.getUpcomingInvoice(attributionId);
57+
const currentUsage = upcomingInvoice.getCredits();
58+
if (currentUsage >= costCenter.spendingLimit) {
59+
log.info({ userId: user.id }, "Spending limit reached", {
60+
attributionId,
61+
currentUsage,
62+
spendingLimit: costCenter.spendingLimit,
63+
});
4964
return {
5065
reached: true,
5166
attributionId,
5267
};
53-
} else if (totalUsage > costCenter.spendingLimit * 0.8) {
68+
} else if (currentUsage > costCenter.spendingLimit * 0.8) {
69+
log.info({ userId: user.id }, "Spending limit almost reached", {
70+
attributionId,
71+
currentUsage,
72+
spendingLimit: costCenter.spendingLimit,
73+
});
5474
return {
5575
reached: false,
5676
almostReached: true,
5777
attributionId,
5878
};
5979
}
80+
6081
return {
6182
reached: false,
6283
attributionId,
6384
};
6485
}
6586

66-
// TODO (gpl): Replace this with call to stripeService.getInvoice()
67-
async listBilledUsage(req: BillableSessionRequest): Promise<BillableSession[]> {
68-
const { attributionId, startedTimeOrder, from, to } = req;
69-
let timestampFrom;
70-
let timestampTo;
87+
protected async isSpendingLimitCheckEnabled(user: User): Promise<boolean> {
88+
// introducing this enablement flag to be able to explicitly control the spending limit check during rollout
89+
return await this.configCatClientFactory().getValueAsync("isSpendingLimitCheckEnabled", false, {
90+
user: user,
91+
});
92+
}
7193

72-
if (from) {
73-
timestampFrom = Timestamp.fromDate(new Date(from));
74-
}
75-
if (to) {
76-
timestampTo = Timestamp.fromDate(new Date(to));
77-
}
78-
const usageClient = this.usageServiceClientProvider.getDefault();
79-
const response = await usageClient.listBilledUsage(
80-
{},
81-
attributionId,
82-
startedTimeOrder as number,
83-
timestampFrom,
84-
timestampTo,
85-
);
86-
const sessions = response.getSessionsList().map((s) => UsageService.mapBilledSession(s));
87-
return sessions;
94+
async getUpcomingInvoice(attributionId: AttributionId): Promise<GetUpcomingInvoiceResponse> {
95+
const response = await this.billingServiceClientProvider.getDefault().getUpcomingInvoice(attributionId);
96+
return response;
8897
}
8998
}

0 commit comments

Comments
 (0)