Skip to content

Commit

Permalink
Make payment optional trial banner work with Stripe sources API depre…
Browse files Browse the repository at this point in the history
…cation (#12146)
  • Loading branch information
amorask-bitwarden authored Dec 2, 2024
1 parent 3fe11b7 commit 0544100
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 39 deletions.
12 changes: 7 additions & 5 deletions apps/web/src/app/vault/individual-vault/vault.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ import {
} from "rxjs/operators";

import {
Unassigned,
CollectionService,
CollectionData,
CollectionDetailsResponse,
CollectionService,
CollectionView,
Unassigned,
} from "@bitwarden/admin-console/common";
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
import { ModalService } from "@bitwarden/angular/services/modal.service";
Expand All @@ -47,6 +47,7 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
import { EventType } from "@bitwarden/common/enums";
Expand Down Expand Up @@ -241,6 +242,7 @@ export class VaultComponent implements OnInit, OnDestroy {
private organizationApiService: OrganizationApiServiceAbstraction,
protected billingApiService: BillingApiServiceAbstraction,
private trialFlowService: TrialFlowService,
private organizationBillingService: OrganizationBillingServiceAbstraction,
) {}

async ngOnInit() {
Expand Down Expand Up @@ -437,13 +439,13 @@ export class VaultComponent implements OnInit, OnDestroy {
.map((org) =>
combineLatest([
this.organizationApiService.getSubscription(org.id),
this.organizationApiService.getBilling(org.id),
this.organizationBillingService.getPaymentSource(org.id),
]).pipe(
map(([subscription, billing]) => {
map(([subscription, paymentSource]) => {
return this.trialFlowService.checkForOrgsWithUpcomingPaymentIssues(
org,
subscription,
billing?.paymentSource,
paymentSource,
);
}),
),
Expand Down
12 changes: 5 additions & 7 deletions apps/web/src/app/vault/org-vault/vault.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions";
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
import { EventType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
Expand Down Expand Up @@ -252,6 +253,7 @@ export class VaultComponent implements OnInit, OnDestroy {
private organizationApiService: OrganizationApiServiceAbstraction,
private trialFlowService: TrialFlowService,
protected billingApiService: BillingApiServiceAbstraction,
private organizationBillingService: OrganizationBillingServiceAbstraction,
) {}

async ngOnInit() {
Expand Down Expand Up @@ -595,15 +597,11 @@ export class VaultComponent implements OnInit, OnDestroy {
combineLatest([
of(org),
this.organizationApiService.getSubscription(org.id),
this.organizationApiService.getBilling(org.id),
this.organizationBillingService.getPaymentSource(org.id),
]),
),
map(([org, sub, billing]) => {
return this.trialFlowService.checkForOrgsWithUpcomingPaymentIssues(
org,
sub,
billing?.paymentSource,
);
map(([org, sub, paymentSource]) => {
return this.trialFlowService.checkForOrgsWithUpcomingPaymentIssues(org, sub, paymentSource);
}),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
Expand Down Expand Up @@ -114,9 +115,9 @@ export class OverviewComponent implements OnInit, OnDestroy {
private smOnboardingTasksService: SMOnboardingTasksService,
private logService: LogService,
private router: Router,

private organizationApiService: OrganizationApiServiceAbstraction,
private trialFlowService: TrialFlowService,
private organizationBillingService: OrganizationBillingServiceAbstraction,
) {}

ngOnInit() {
Expand Down Expand Up @@ -144,15 +145,11 @@ export class OverviewComponent implements OnInit, OnDestroy {
combineLatest([
of(org),
this.organizationApiService.getSubscription(org.id),
this.organizationApiService.getBilling(org.id),
this.organizationBillingService.getPaymentSource(org.id),
]),
),
map(([org, sub, billing]) => {
return this.trialFlowService.checkForOrgsWithUpcomingPaymentIssues(
org,
sub,
billing?.paymentSource,
);
map(([org, sub, paymentSource]) => {
return this.trialFlowService.checkForOrgsWithUpcomingPaymentIssues(org, sub, paymentSource);
}),
takeUntil(this.destroy$),
);
Expand Down
2 changes: 2 additions & 0 deletions libs/angular/src/services/jslib-services.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,8 @@ const safeProviders: SafeProvider[] = [
useClass: OrganizationBillingService,
deps: [
ApiServiceAbstraction,
BillingApiServiceAbstraction,
ConfigService,
KeyServiceAbstraction,
EncryptService,
I18nServiceAbstraction,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { BillingSourceResponse } from "@bitwarden/common/billing/models/response/billing.response";
import { PaymentSourceResponse } from "@bitwarden/common/billing/models/response/payment-source.response";

import { OrganizationResponse } from "../../admin-console/models/response/organization.response";
import { InitiationPath } from "../../models/request/reference-event.request";
import { PaymentMethodType, PlanType } from "../enums";
Expand Down Expand Up @@ -41,11 +44,15 @@ export type SubscriptionInformation = {
};

export abstract class OrganizationBillingServiceAbstraction {
purchaseSubscription: (subscription: SubscriptionInformation) => Promise<OrganizationResponse>;
getPaymentSource: (
organizationId: string,
) => Promise<BillingSourceResponse | PaymentSourceResponse>;

startFree: (subscription: SubscriptionInformation) => Promise<OrganizationResponse>;
purchaseSubscription: (subscription: SubscriptionInformation) => Promise<OrganizationResponse>;

purchaseSubscriptionNoPaymentMethod: (
subscription: SubscriptionInformation,
) => Promise<OrganizationResponse>;

startFree: (subscription: SubscriptionInformation) => Promise<OrganizationResponse>;
}
59 changes: 42 additions & 17 deletions libs/common/src/billing/services/organization-billing.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import {
BillingApiServiceAbstraction,
OrganizationBillingServiceAbstraction,
OrganizationInformation,
PaymentInformation,
PlanInformation,
SubscriptionInformation,
} from "@bitwarden/common/billing/abstractions";
import { BillingSourceResponse } from "@bitwarden/common/billing/models/response/billing.response";
import { PaymentSourceResponse } from "@bitwarden/common/billing/models/response/payment-source.response";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { SyncService } from "@bitwarden/common/platform/sync";
import { KeyService } from "@bitwarden/key-management";

import { ApiService } from "../../abstractions/api.service";
import { OrganizationApiServiceAbstraction as OrganizationApiService } from "../../admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationCreateRequest } from "../../admin-console/models/request/organization-create.request";
Expand All @@ -8,14 +22,6 @@ import { EncryptService } from "../../platform/abstractions/encrypt.service";
import { I18nService } from "../../platform/abstractions/i18n.service";
import { EncString } from "../../platform/models/domain/enc-string";
import { OrgKey } from "../../types/key";
import { SyncService } from "../../vault/abstractions/sync/sync.service.abstraction";
import {
OrganizationBillingServiceAbstraction,
OrganizationInformation,
PaymentInformation,
PlanInformation,
SubscriptionInformation,
} from "../abstractions/organization-billing.service";
import { PlanType } from "../enums";
import { OrganizationNoPaymentMethodCreateRequest } from "../models/request/organization-no-payment-method-create-request";

Expand All @@ -29,13 +35,32 @@ interface OrganizationKeys {
export class OrganizationBillingService implements OrganizationBillingServiceAbstraction {
constructor(
private apiService: ApiService,
private billingApiService: BillingApiServiceAbstraction,
private configService: ConfigService,
private keyService: KeyService,
private encryptService: EncryptService,
private i18nService: I18nService,
private organizationApiService: OrganizationApiService,
private syncService: SyncService,
) {}

async getPaymentSource(
organizationId: string,
): Promise<BillingSourceResponse | PaymentSourceResponse> {
const deprecateStripeSourcesAPI = await this.configService.getFeatureFlag(
FeatureFlag.AC2476_DeprecateStripeSourcesAPI,
);

if (deprecateStripeSourcesAPI) {
const paymentMethod =
await this.billingApiService.getOrganizationPaymentMethod(organizationId);
return paymentMethod.paymentSource;
} else {
const billing = await this.organizationApiService.getBilling(organizationId);
return billing.paymentSource;
}
}

async purchaseSubscription(subscription: SubscriptionInformation): Promise<OrganizationResponse> {
const request = new OrganizationCreateRequest();

Expand All @@ -58,8 +83,10 @@ export class OrganizationBillingService implements OrganizationBillingServiceAbs
return response;
}

async startFree(subscription: SubscriptionInformation): Promise<OrganizationResponse> {
const request = new OrganizationCreateRequest();
async purchaseSubscriptionNoPaymentMethod(
subscription: SubscriptionInformation,
): Promise<OrganizationResponse> {
const request = new OrganizationNoPaymentMethodCreateRequest();

const organizationKeys = await this.makeOrganizationKeys();

Expand All @@ -69,7 +96,7 @@ export class OrganizationBillingService implements OrganizationBillingServiceAbs

this.setPlanInformation(request, subscription.plan);

const response = await this.organizationApiService.create(request);
const response = await this.organizationApiService.createWithoutPayment(request);

await this.apiService.refreshIdentityToken();

Expand All @@ -78,10 +105,8 @@ export class OrganizationBillingService implements OrganizationBillingServiceAbs
return response;
}

async purchaseSubscriptionNoPaymentMethod(
subscription: SubscriptionInformation,
): Promise<OrganizationResponse> {
const request = new OrganizationNoPaymentMethodCreateRequest();
async startFree(subscription: SubscriptionInformation): Promise<OrganizationResponse> {
const request = new OrganizationCreateRequest();

const organizationKeys = await this.makeOrganizationKeys();

Expand All @@ -91,7 +116,7 @@ export class OrganizationBillingService implements OrganizationBillingServiceAbs

this.setPlanInformation(request, subscription.plan);

const response = await this.organizationApiService.createWithoutPayment(request);
const response = await this.organizationApiService.create(request);

await this.apiService.refreshIdentityToken();

Expand Down

0 comments on commit 0544100

Please sign in to comment.