Skip to content

Commit

Permalink
Use upcoming invoice
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexTugarev committed Aug 25, 2022
1 parent 1cd0fbf commit dfc62db
Show file tree
Hide file tree
Showing 13 changed files with 443 additions and 298 deletions.
71 changes: 40 additions & 31 deletions components/server/ee/src/billing/billing-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
import { CostCenterDB } from "@gitpod/gitpod-db/lib";
import { User } from "@gitpod/gitpod-protocol";
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
import { BillableSession, BillableSessionRequest, SortOrder } from "@gitpod/gitpod-protocol/lib/usage";
import { ConfigCatClientFactory } from "@gitpod/gitpod-protocol/lib/experiments/configcat-server";
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
import { CachingUsageServiceClientProvider, UsageService } from "@gitpod/usage-api/lib/usage/v1/sugar";
import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb";
import { GetUpcomingInvoiceResponse } from "@gitpod/usage-api/lib/usage/v1/billing_pb";
import {
CachingUsageServiceClientProvider,
CachingBillingServiceClientProvider,
} from "@gitpod/usage-api/lib/usage/v1/sugar";
import { inject, injectable } from "inversify";
import { UserService } from "../../../src/user/user-service";

Expand All @@ -26,6 +29,9 @@ export class BillingService {
@inject(CostCenterDB) protected readonly costCenterDB: CostCenterDB;
@inject(CachingUsageServiceClientProvider)
protected readonly usageServiceClientProvider: CachingUsageServiceClientProvider;
@inject(CachingBillingServiceClientProvider)
protected readonly billingServiceClientProvider: CachingBillingServiceClientProvider;
@inject(ConfigCatClientFactory) protected readonly configCatClientFactory: ConfigCatClientFactory;

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

const allSessions = await this.listBilledUsage({
attributionId: AttributionId.render(attributionId),
startedTimeOrder: SortOrder.Descending,
});
const totalUsage = allSessions.map((s) => s.credits).reduce((a, b) => a + b, 0);
if (totalUsage >= costCenter.spendingLimit) {
if (!(await this.isSpendingLimitCheckEnabled(user))) {
return {
reached: false,
attributionId,
};
}

const upcomingInvoice = await this.getUpcomingInvoice(attributionId);
const currentUsage = upcomingInvoice.getCredits();
if (currentUsage >= costCenter.spendingLimit) {
log.info({ userId: user.id }, "Spending limit reached", {
attributionId,
currentUsage,
spendingLimit: costCenter.spendingLimit,
});
return {
reached: true,
attributionId,
};
} else if (totalUsage > costCenter.spendingLimit * 0.8) {
} else if (currentUsage > costCenter.spendingLimit * 0.8) {
log.info({ userId: user.id }, "Spending limit almost reached", {
attributionId,
currentUsage,
spendingLimit: costCenter.spendingLimit,
});
return {
reached: false,
almostReached: true,
attributionId,
};
}

return {
reached: false,
attributionId,
};
}

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

if (from) {
timestampFrom = Timestamp.fromDate(new Date(from));
}
if (to) {
timestampTo = Timestamp.fromDate(new Date(to));
}
const usageClient = this.usageServiceClientProvider.getDefault();
const response = await usageClient.listBilledUsage(
{},
attributionId,
startedTimeOrder as number,
timestampFrom,
timestampTo,
);
const sessions = response.getSessionsList().map((s) => UsageService.mapBilledSession(s));
return sessions;
async getUpcomingInvoice(attributionId: AttributionId): Promise<GetUpcomingInvoiceResponse> {
const response = await this.billingServiceClientProvider.getDefault().getUpcomingInvoice(attributionId);
return response;
}
}
Loading

0 comments on commit dfc62db

Please sign in to comment.