From a58642e370040907ef9a6d46de715d3440d6eb57 Mon Sep 17 00:00:00 2001 From: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:48:22 -0400 Subject: [PATCH] [AC-2959] ACH Direct Debit POC (#10746) * (No Logic) Fix typo in billing-api-service.abstraction file name * (Cleanup) Remove payment method components and API methods from provider portal Product team decided not to have a payment method page in the provider portal for consolidated billing. This just removes all the unused components and API methods. * Add organization endpoints to support new payment method behavior * Add payment-v2.component This component existed in the libs folder because we used it for the provider portal, but since we've removed payment functionality from the provider portal, I moved it into web in this commit. * (No Logic) Move existing payment.component into new payment component folder * Add verify-bank-account.component This component existed in the libs folder because we used it for the provider portal, but since we've removed payment functionality from the provider portal, I moved it into web in this commit. * Add adjust-payment-dialog-v2.component * (No Logic) Move existing adjust-payment-dialog.component into new adjust-payment-dialog component folder * Add organization-payment-method.component * Add feature flag: AC-2476-deprecate-stripe-sources-api * Pivot organization payment method route on new feature flag * Fix broken test --- .../members/members.component.ts | 2 +- .../change-plan-dialog.component.ts | 2 +- .../organization-billing-routing.module.ts | 27 +-- .../organization-billing.module.ts | 2 + .../organization-plans.component.ts | 2 +- ...organization-payment-method.component.html | 63 +++++++ .../organization-payment-method.component.ts | 169 ++++++++++++++++++ .../adjust-payment-dialog-v2.component.html | 24 +++ .../adjust-payment-dialog-v2.component.ts | 123 +++++++++++++ .../adjust-payment-dialog.component.html | 0 .../adjust-payment-dialog.component.ts | 4 +- .../shared/adjust-storage.component.ts | 2 +- .../billing/shared/billing-shared.module.ts | 18 +- apps/web/src/app/billing/shared/index.ts | 2 +- .../shared/offboarding-survey.component.ts | 2 +- .../shared/payment-method.component.ts | 2 +- .../shared/payment/payment-v2.component.html | 15 +- .../shared/payment/payment-v2.component.ts | 135 ++++++++------ .../{ => payment}/payment.component.html | 0 .../shared/{ => payment}/payment.component.ts | 2 +- .../verify-bank-account.component.html | 2 +- .../verify-bank-account.component.ts | 20 ++- .../providers/providers.module.ts | 4 - .../services/web-provider.service.ts | 2 +- .../clients/create-client-dialog.component.ts | 2 +- .../manage-client-name-dialog.component.ts | 2 +- .../clients/manage-clients.component.ts | 2 +- .../src/app/billing/providers/index.ts | 2 - .../provider-payment-method.component.html | 52 ------ .../provider-payment-method.component.ts | 140 --------------- ...elect-payment-method-dialog.component.html | 18 -- ...-select-payment-method-dialog.component.ts | 60 ------- .../provider-subscription.component.ts | 2 +- libs/angular/src/billing/components/index.ts | 2 - libs/angular/src/jslib.module.ts | 6 - ....ts => billing-api.service.abstraction.ts} | 36 ++-- libs/common/src/billing/abstractions/index.ts | 2 +- .../common/src/billing/models/domain/index.ts | 2 - .../models/domain/masked-payment-method.ts | 17 -- .../tokenized-payment-method.request.ts | 14 -- .../tokenized-payment-source.request.ts} | 4 +- .../request/update-payment-method.request.ts | 7 + ...ion-risks-subscription-failure.response.ts | 13 -- ...response.ts => payment-method.response.ts} | 15 +- ...response.ts => payment-source.response.ts} | 2 +- .../billing/services/billing-api.service.ts | 78 ++++---- libs/common/src/enums/feature-flag.enum.ts | 2 + 47 files changed, 623 insertions(+), 481 deletions(-) create mode 100644 apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.html create mode 100644 apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.ts create mode 100644 apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog-v2.component.html create mode 100644 apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog-v2.component.ts rename apps/web/src/app/billing/shared/{ => adjust-payment-dialog}/adjust-payment-dialog.component.html (100%) rename apps/web/src/app/billing/shared/{ => adjust-payment-dialog}/adjust-payment-dialog.component.ts (97%) rename libs/angular/src/billing/components/select-payment-method/select-payment-method.component.html => apps/web/src/app/billing/shared/payment/payment-v2.component.html (89%) rename libs/angular/src/billing/components/select-payment-method/select-payment-method.component.ts => apps/web/src/app/billing/shared/payment/payment-v2.component.ts (50%) rename apps/web/src/app/billing/shared/{ => payment}/payment.component.html (100%) rename apps/web/src/app/billing/shared/{ => payment}/payment.component.ts (99%) rename {libs/angular/src/billing/components => apps/web/src/app/billing/shared}/verify-bank-account/verify-bank-account.component.html (89%) rename {libs/angular/src/billing/components => apps/web/src/app/billing/shared}/verify-bank-account/verify-bank-account.component.ts (57%) delete mode 100644 bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-payment-method.component.html delete mode 100644 bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-payment-method.component.ts delete mode 100644 bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-select-payment-method-dialog.component.html delete mode 100644 bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-select-payment-method-dialog.component.ts rename libs/common/src/billing/abstractions/{billilng-api.service.abstraction.ts => billing-api.service.abstraction.ts} (79%) delete mode 100644 libs/common/src/billing/models/domain/masked-payment-method.ts delete mode 100644 libs/common/src/billing/models/request/tokenized-payment-method.request.ts rename libs/common/src/billing/models/{domain/tokenized-payment-method.ts => request/tokenized-payment-source.request.ts} (70%) create mode 100644 libs/common/src/billing/models/request/update-payment-method.request.ts delete mode 100644 libs/common/src/billing/models/response/organization-risks-subscription-failure.response.ts rename libs/common/src/billing/models/response/{payment-information.response.ts => payment-method.response.ts} (52%) rename libs/common/src/billing/models/response/{masked-payment-method.response.ts => payment-source.response.ts} (88%) diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.ts b/apps/web/src/app/admin-console/organizations/members/members.component.ts index 431a0ac6085..66a62f7acc7 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.component.ts @@ -32,7 +32,7 @@ import { import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request"; -import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction"; +import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { isNotSelfUpgradable, ProductTierType } from "@bitwarden/common/billing/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; diff --git a/apps/web/src/app/billing/organizations/change-plan-dialog.component.ts b/apps/web/src/app/billing/organizations/change-plan-dialog.component.ts index 8b69a8956e3..a359c281ebe 100644 --- a/apps/web/src/app/billing/organizations/change-plan-dialog.component.ts +++ b/apps/web/src/app/billing/organizations/change-plan-dialog.component.ts @@ -37,7 +37,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService, ToastService } from "@bitwarden/components"; -import { PaymentComponent } from "../shared/payment.component"; +import { PaymentComponent } from "../shared/payment/payment.component"; import { TaxInfoComponent } from "../shared/tax-info.component"; type ChangePlanDialogParams = { diff --git a/apps/web/src/app/billing/organizations/organization-billing-routing.module.ts b/apps/web/src/app/billing/organizations/organization-billing-routing.module.ts index 970b40a54bd..3d4c8dd3870 100644 --- a/apps/web/src/app/billing/organizations/organization-billing-routing.module.ts +++ b/apps/web/src/app/billing/organizations/organization-billing-routing.module.ts @@ -1,7 +1,9 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; +import { featureFlaggedRoute } from "@bitwarden/angular/platform/utils/feature-flagged-route"; import { canAccessBillingTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { organizationPermissionsGuard } from "../../admin-console/organizations/guards/org-permissions.guard"; import { organizationIsUnmanaged } from "../../billing/guards/organization-is-unmanaged.guard"; @@ -11,6 +13,7 @@ import { PaymentMethodComponent } from "../shared"; import { OrgBillingHistoryViewComponent } from "./organization-billing-history-view.component"; import { OrganizationSubscriptionCloudComponent } from "./organization-subscription-cloud.component"; import { OrganizationSubscriptionSelfhostComponent } from "./organization-subscription-selfhost.component"; +import { OrganizationPaymentMethodComponent } from "./payment-method/organization-payment-method.component"; const routes: Routes = [ { @@ -25,17 +28,21 @@ const routes: Routes = [ : OrganizationSubscriptionCloudComponent, data: { titleId: "subscription" }, }, - { - path: "payment-method", - component: PaymentMethodComponent, - canActivate: [ - organizationPermissionsGuard((org) => org.canEditPaymentMethods), - organizationIsUnmanaged, - ], - data: { - titleId: "paymentMethod", + ...featureFlaggedRoute({ + defaultComponent: PaymentMethodComponent, + flaggedComponent: OrganizationPaymentMethodComponent, + featureFlag: FeatureFlag.AC2476_DeprecateStripeSourcesAPI, + routeOptions: { + path: "payment-method", + canActivate: [ + organizationPermissionsGuard((org) => org.canEditPaymentMethods), + organizationIsUnmanaged, + ], + data: { + titleId: "paymentMethod", + }, }, - }, + }), { path: "history", component: OrgBillingHistoryViewComponent, diff --git a/apps/web/src/app/billing/organizations/organization-billing.module.ts b/apps/web/src/app/billing/organizations/organization-billing.module.ts index 5d9dd8cf5b5..ccfe12b2e59 100644 --- a/apps/web/src/app/billing/organizations/organization-billing.module.ts +++ b/apps/web/src/app/billing/organizations/organization-billing.module.ts @@ -15,6 +15,7 @@ import { OrganizationBillingRoutingModule } from "./organization-billing-routing import { OrganizationPlansComponent } from "./organization-plans.component"; import { OrganizationSubscriptionCloudComponent } from "./organization-subscription-cloud.component"; import { OrganizationSubscriptionSelfhostComponent } from "./organization-subscription-selfhost.component"; +import { OrganizationPaymentMethodComponent } from "./payment-method/organization-payment-method.component"; import { SecretsManagerAdjustSubscriptionComponent } from "./sm-adjust-subscription.component"; import { SecretsManagerSubscribeStandaloneComponent } from "./sm-subscribe-standalone.component"; import { SubscriptionHiddenComponent } from "./subscription-hidden.component"; @@ -42,6 +43,7 @@ import { SubscriptionStatusComponent } from "./subscription-status.component"; SubscriptionHiddenComponent, SubscriptionStatusComponent, ChangePlanDialogComponent, + OrganizationPaymentMethodComponent, ], }) export class OrganizationBillingModule {} diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.ts b/apps/web/src/app/billing/organizations/organization-plans.component.ts index fe1c1568a9e..20839d5d2b9 100644 --- a/apps/web/src/app/billing/organizations/organization-plans.component.ts +++ b/apps/web/src/app/billing/organizations/organization-plans.component.ts @@ -41,7 +41,7 @@ import { ToastService } from "@bitwarden/components"; import { OrganizationCreateModule } from "../../admin-console/organizations/create/organization-create.module"; import { BillingSharedModule, secretsManagerSubscribeFormFactory } from "../shared"; -import { PaymentComponent } from "../shared/payment.component"; +import { PaymentComponent } from "../shared/payment/payment.component"; import { TaxInfoComponent } from "../shared/tax-info.component"; interface OnSuccessArgs { diff --git a/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.html b/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.html new file mode 100644 index 00000000000..9f9cb9efc65 --- /dev/null +++ b/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.html @@ -0,0 +1,63 @@ + + + + + {{ "loading" | i18n }} + + + + +

+ {{ accountCreditHeaderText }} +

+

{{ Math.abs(accountCredit) | currency: "$" }}

+

{{ "creditAppliedDesc" | i18n }}

+ +
+ + +

{{ "paymentMethod" | i18n }}

+

{{ "noPaymentMethod" | i18n }}

+ + + +

+ + {{ paymentSource.description }} + - {{ "unverified" | i18n }} +

+
+ +

+ {{ "paymentChargedWithUnpaidSubscription" | i18n }} +

+
+ + +

{{ "taxInformation" | i18n }}

+

{{ "taxInformationDesc" | i18n }}

+ + +
+
+
diff --git a/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.ts b/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.ts new file mode 100644 index 00000000000..0756a6c314c --- /dev/null +++ b/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.ts @@ -0,0 +1,169 @@ +import { Component, ViewChild } from "@angular/core"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; +import { ActivatedRoute, Router } from "@angular/router"; +import { from, lastValueFrom, switchMap } from "rxjs"; + +import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions"; +import { PaymentMethodType } from "@bitwarden/common/billing/enums"; +import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request"; +import { VerifyBankAccountRequest } from "@bitwarden/common/billing/models/request/verify-bank-account.request"; +import { PaymentSourceResponse } from "@bitwarden/common/billing/models/response/payment-source.response"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { DialogService, ToastService } from "@bitwarden/components"; + +import { TaxInfoComponent } from "../../shared"; +import { + AddCreditDialogResult, + openAddCreditDialog, +} from "../../shared/add-credit-dialog.component"; +import { + AdjustPaymentDialogV2Component, + AdjustPaymentDialogV2ResultType, +} from "../../shared/adjust-payment-dialog/adjust-payment-dialog-v2.component"; + +@Component({ + templateUrl: "./organization-payment-method.component.html", +}) +export class OrganizationPaymentMethodComponent { + @ViewChild(TaxInfoComponent) taxInfoComponent: TaxInfoComponent; + + organizationId: string; + accountCredit: number; + paymentSource?: PaymentSourceResponse; + subscriptionStatus?: string; + + loading = true; + + protected readonly Math = Math; + + constructor( + private activatedRoute: ActivatedRoute, + private billingApiService: BillingApiServiceAbstraction, + private dialogService: DialogService, + private i18nService: I18nService, + private platformUtilsService: PlatformUtilsService, + private router: Router, + private toastService: ToastService, + ) { + this.activatedRoute.params + .pipe( + takeUntilDestroyed(), + switchMap(({ organizationId }) => { + if (this.platformUtilsService.isSelfHost()) { + return from(this.router.navigate(["/settings/subscription"])); + } + + this.organizationId = organizationId; + return from(this.load()); + }), + ) + .subscribe(); + } + + protected addAccountCredit = async (): Promise => { + const dialogRef = openAddCreditDialog(this.dialogService, { + data: { + organizationId: this.organizationId, + }, + }); + + const result = await lastValueFrom(dialogRef.closed); + + if (result === AddCreditDialogResult.Added) { + await this.load(); + } + }; + + protected load = async (): Promise => { + this.loading = true; + const { accountCredit, paymentSource, subscriptionStatus } = + await this.billingApiService.getOrganizationPaymentMethod(this.organizationId); + this.accountCredit = accountCredit; + this.paymentSource = paymentSource; + this.subscriptionStatus = subscriptionStatus; + this.loading = false; + }; + + protected updatePaymentMethod = async (): Promise => { + const dialogRef = AdjustPaymentDialogV2Component.open(this.dialogService, { + data: { + initialPaymentMethod: this.paymentSource?.type, + organizationId: this.organizationId, + }, + }); + + const result = await lastValueFrom(dialogRef.closed); + + if (result === AdjustPaymentDialogV2ResultType.Submitted) { + await this.load(); + } + }; + + protected updateTaxInformation = async (): Promise => { + this.taxInfoComponent.taxFormGroup.updateValueAndValidity(); + this.taxInfoComponent.taxFormGroup.markAllAsTouched(); + + if (this.taxInfoComponent.taxFormGroup.invalid) { + return; + } + + const request = new ExpandedTaxInfoUpdateRequest(); + request.country = this.taxInfoComponent.country; + request.postalCode = this.taxInfoComponent.postalCode; + request.taxId = this.taxInfoComponent.taxId; + request.line1 = this.taxInfoComponent.line1; + request.line2 = this.taxInfoComponent.line2; + request.city = this.taxInfoComponent.city; + request.state = this.taxInfoComponent.state; + + await this.billingApiService.updateOrganizationTaxInformation(this.organizationId, request); + + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("taxInfoUpdated"), + }); + }; + + protected verifyBankAccount = async (request: VerifyBankAccountRequest): Promise => { + await this.billingApiService.verifyOrganizationBankAccount(this.organizationId, request); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("verifiedBankAccount"), + }); + }; + + protected get accountCreditHeaderText(): string { + const key = this.accountCredit <= 0 ? "accountBalance" : "accountCredit"; + return this.i18nService.t(key); + } + + protected get paymentSourceClasses() { + if (this.paymentSource == null) { + return []; + } + switch (this.paymentSource.type) { + case PaymentMethodType.Card: + return ["bwi-credit-card"]; + case PaymentMethodType.BankAccount: + return ["bwi-bank"]; + case PaymentMethodType.Check: + return ["bwi-money"]; + case PaymentMethodType.PayPal: + return ["bwi-paypal text-primary"]; + default: + return []; + } + } + + protected get subscriptionIsUnpaid(): boolean { + return this.subscriptionStatus === "unpaid"; + } + + protected get updatePaymentSourceButtonText(): string { + const key = this.paymentSource == null ? "addPaymentMethod" : "changePaymentMethod"; + return this.i18nService.t(key); + } +} diff --git a/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog-v2.component.html b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog-v2.component.html new file mode 100644 index 00000000000..fb1ff3e0d00 --- /dev/null +++ b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog-v2.component.html @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog-v2.component.ts b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog-v2.component.ts new file mode 100644 index 00000000000..ccf71dc7f88 --- /dev/null +++ b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog-v2.component.ts @@ -0,0 +1,123 @@ +import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; +import { forwardRef, Component, Inject, ViewChild } from "@angular/core"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions"; +import { PaymentMethodType } from "@bitwarden/common/billing/enums"; +import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request"; +import { UpdatePaymentMethodRequest } from "@bitwarden/common/billing/models/request/update-payment-method.request"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DialogService, ToastService } from "@bitwarden/components"; + +import { TaxInfoComponent } from "../"; +import { PaymentV2Component } from "../payment/payment-v2.component"; + +export interface AdjustPaymentDialogV2Params { + initialPaymentMethod?: PaymentMethodType; + organizationId?: string; +} + +export enum AdjustPaymentDialogV2ResultType { + Closed = "closed", + Submitted = "submitted", +} + +@Component({ + templateUrl: "./adjust-payment-dialog-v2.component.html", +}) +export class AdjustPaymentDialogV2Component { + @ViewChild(PaymentV2Component) paymentComponent: PaymentV2Component; + @ViewChild(forwardRef(() => TaxInfoComponent)) taxInfoComponent: TaxInfoComponent; + + protected readonly PaymentMethodType = PaymentMethodType; + protected readonly ResultType = AdjustPaymentDialogV2ResultType; + + protected dialogHeader: string; + protected initialPaymentMethod: PaymentMethodType; + protected organizationId?: string; + + constructor( + private apiService: ApiService, + private billingApiService: BillingApiServiceAbstraction, + @Inject(DIALOG_DATA) protected dialogParams: AdjustPaymentDialogV2Params, + private dialogRef: DialogRef, + private i18nService: I18nService, + private toastService: ToastService, + ) { + const key = this.dialogParams.initialPaymentMethod ? "changePaymentMethod" : "addPaymentMethod"; + this.dialogHeader = this.i18nService.t(key); + this.initialPaymentMethod = this.dialogParams.initialPaymentMethod ?? PaymentMethodType.Card; + this.organizationId = this.dialogParams.organizationId; + } + + onCountryChanged = () => { + if (this.taxInfoComponent.taxInfo.country === "US") { + this.paymentComponent.showBankAccount = !!this.organizationId; + } else { + this.paymentComponent.showBankAccount = false; + if (this.paymentComponent.selected === PaymentMethodType.BankAccount) { + this.paymentComponent.select(PaymentMethodType.Card); + } + } + }; + + submit = async (): Promise => { + this.taxInfoComponent.taxFormGroup.updateValueAndValidity(); + this.taxInfoComponent.taxFormGroup.markAllAsTouched(); + if (this.taxInfoComponent.taxFormGroup.invalid) { + return; + } + + if (!this.organizationId) { + await this.updatePremiumUserPaymentMethod(); + } else { + await this.updateOrganizationPaymentMethod(); + } + + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("updatedPaymentMethod"), + }); + + this.dialogRef.close(AdjustPaymentDialogV2ResultType.Submitted); + }; + + private updateOrganizationPaymentMethod = async () => { + const paymentSource = await this.paymentComponent.tokenize(); + + const request = new UpdatePaymentMethodRequest(); + request.paymentSource = paymentSource; + request.taxInformation = { + country: this.taxInfoComponent.country, + postalCode: this.taxInfoComponent.postalCode, + taxId: this.taxInfoComponent.taxId, + line1: this.taxInfoComponent.line1, + line2: this.taxInfoComponent.line2, + city: this.taxInfoComponent.city, + state: this.taxInfoComponent.state, + }; + + await this.billingApiService.updateOrganizationPaymentMethod(this.organizationId, request); + }; + + private updatePremiumUserPaymentMethod = async () => { + const { type, token } = await this.paymentComponent.tokenize(); + + const request = new PaymentRequest(); + request.paymentMethodType = type; + request.paymentToken = token; + request.country = this.taxInfoComponent.country; + request.postalCode = this.taxInfoComponent.postalCode; + await this.apiService.postAccountPayment(request); + }; + + static open = ( + dialogService: DialogService, + dialogConfig: DialogConfig, + ) => + dialogService.open( + AdjustPaymentDialogV2Component, + dialogConfig, + ); +} diff --git a/apps/web/src/app/billing/shared/adjust-payment-dialog.component.html b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.html similarity index 100% rename from apps/web/src/app/billing/shared/adjust-payment-dialog.component.html rename to apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.html diff --git a/apps/web/src/app/billing/shared/adjust-payment-dialog.component.ts b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.ts similarity index 97% rename from apps/web/src/app/billing/shared/adjust-payment-dialog.component.ts rename to apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.ts index 08c9bf27660..450c1234567 100644 --- a/apps/web/src/app/billing/shared/adjust-payment-dialog.component.ts +++ b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.ts @@ -10,8 +10,8 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { DialogService, ToastService } from "@bitwarden/components"; -import { PaymentComponent } from "./payment.component"; -import { TaxInfoComponent } from "./tax-info.component"; +import { PaymentComponent } from "../payment/payment.component"; +import { TaxInfoComponent } from "../tax-info.component"; export interface AdjustPaymentDialogData { organizationId: string; diff --git a/apps/web/src/app/billing/shared/adjust-storage.component.ts b/apps/web/src/app/billing/shared/adjust-storage.component.ts index 439bfec82a0..5cf05ea015c 100644 --- a/apps/web/src/app/billing/shared/adjust-storage.component.ts +++ b/apps/web/src/app/billing/shared/adjust-storage.component.ts @@ -12,7 +12,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { DialogService, ToastService } from "@bitwarden/components"; -import { PaymentComponent } from "./payment.component"; +import { PaymentComponent } from "./payment/payment.component"; export interface AdjustStorageDialogData { storageGbPrice: number; diff --git a/apps/web/src/app/billing/shared/billing-shared.module.ts b/apps/web/src/app/billing/shared/billing-shared.module.ts index 0031cff7755..300817bad55 100644 --- a/apps/web/src/app/billing/shared/billing-shared.module.ts +++ b/apps/web/src/app/billing/shared/billing-shared.module.ts @@ -4,19 +4,29 @@ import { HeaderModule } from "../../layouts/header/header.module"; import { SharedModule } from "../../shared"; import { AddCreditDialogComponent } from "./add-credit-dialog.component"; -import { AdjustPaymentDialogComponent } from "./adjust-payment-dialog.component"; +import { AdjustPaymentDialogV2Component } from "./adjust-payment-dialog/adjust-payment-dialog-v2.component"; +import { AdjustPaymentDialogComponent } from "./adjust-payment-dialog/adjust-payment-dialog.component"; import { AdjustStorageComponent } from "./adjust-storage.component"; import { BillingHistoryComponent } from "./billing-history.component"; import { OffboardingSurveyComponent } from "./offboarding-survey.component"; +import { PaymentV2Component } from "./payment/payment-v2.component"; +import { PaymentComponent } from "./payment/payment.component"; import { PaymentMethodComponent } from "./payment-method.component"; -import { PaymentComponent } from "./payment.component"; import { SecretsManagerSubscribeComponent } from "./sm-subscribe.component"; import { TaxInfoComponent } from "./tax-info.component"; import { UpdateLicenseDialogComponent } from "./update-license-dialog.component"; import { UpdateLicenseComponent } from "./update-license.component"; +import { VerifyBankAccountComponent } from "./verify-bank-account/verify-bank-account.component"; @NgModule({ - imports: [SharedModule, PaymentComponent, TaxInfoComponent, HeaderModule], + imports: [ + SharedModule, + PaymentComponent, + TaxInfoComponent, + HeaderModule, + PaymentV2Component, + VerifyBankAccountComponent, + ], declarations: [ AddCreditDialogComponent, AdjustPaymentDialogComponent, @@ -27,6 +37,7 @@ import { UpdateLicenseComponent } from "./update-license.component"; UpdateLicenseComponent, UpdateLicenseDialogComponent, OffboardingSurveyComponent, + AdjustPaymentDialogV2Component, ], exports: [ SharedModule, @@ -38,6 +49,7 @@ import { UpdateLicenseComponent } from "./update-license.component"; UpdateLicenseComponent, UpdateLicenseDialogComponent, OffboardingSurveyComponent, + VerifyBankAccountComponent, ], }) export class BillingSharedModule {} diff --git a/apps/web/src/app/billing/shared/index.ts b/apps/web/src/app/billing/shared/index.ts index ae28e45f789..69a4b93bec8 100644 --- a/apps/web/src/app/billing/shared/index.ts +++ b/apps/web/src/app/billing/shared/index.ts @@ -1,5 +1,5 @@ export * from "./billing-shared.module"; export * from "./payment-method.component"; -export * from "./payment.component"; +export * from "./payment/payment.component"; export * from "./sm-subscribe.component"; export * from "./tax-info.component"; diff --git a/apps/web/src/app/billing/shared/offboarding-survey.component.ts b/apps/web/src/app/billing/shared/offboarding-survey.component.ts index 7ffd40e058d..90ca8e254ce 100644 --- a/apps/web/src/app/billing/shared/offboarding-survey.component.ts +++ b/apps/web/src/app/billing/shared/offboarding-survey.component.ts @@ -2,7 +2,7 @@ import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; import { Component, Inject } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; -import { BillingApiServiceAbstraction as BillingApiService } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction"; +import { BillingApiServiceAbstraction as BillingApiService } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { DialogService, ToastService } from "@bitwarden/components"; diff --git a/apps/web/src/app/billing/shared/payment-method.component.ts b/apps/web/src/app/billing/shared/payment-method.component.ts index 0c089fa0733..06acf2142a5 100644 --- a/apps/web/src/app/billing/shared/payment-method.component.ts +++ b/apps/web/src/app/billing/shared/payment-method.component.ts @@ -19,7 +19,7 @@ import { AddCreditDialogResult, openAddCreditDialog } from "./add-credit-dialog. import { AdjustPaymentDialogResult, openAdjustPaymentDialog, -} from "./adjust-payment-dialog.component"; +} from "./adjust-payment-dialog/adjust-payment-dialog.component"; import { TaxInfoComponent } from "./tax-info.component"; @Component({ diff --git a/libs/angular/src/billing/components/select-payment-method/select-payment-method.component.html b/apps/web/src/app/billing/shared/payment/payment-v2.component.html similarity index 89% rename from libs/angular/src/billing/components/select-payment-method/select-payment-method.component.html rename to apps/web/src/app/billing/shared/payment/payment-v2.component.html index f7e57acb7f8..e701c1ce679 100644 --- a/libs/angular/src/billing/components/select-payment-method/select-payment-method.component.html +++ b/apps/web/src/app/billing/shared/payment/payment-v2.component.html @@ -43,24 +43,31 @@
- +
Visa, MasterCard, Discover, AmEx, JCB, Diners Club, UnionPay
- +
{{ "verifyBankAccountInitialDesc" | i18n }} {{ "verifyBankAccountFailureWarning" | i18n }} -
+
{{ "routingNumber" | i18n }} Promise; +export class PaymentV2Component implements OnInit, OnDestroy { + /** Show account credit as a payment option. */ + @Input() showAccountCredit: boolean = true; + /** Show bank account as a payment option. */ + @Input() showBankAccount: boolean = true; + /** Show PayPal as a payment option. */ + @Input() showPayPal: boolean = true; + + /** The payment method selected by default when the component renders. */ + @Input() private initialPaymentMethod: PaymentMethodType = PaymentMethodType.Card; + /** If provided, will be invoked with the tokenized payment source during form submission. */ + @Input() protected onSubmit?: (request: TokenizedPaymentSourceRequest) => Promise; + + @Output() submitted = new EventEmitter(); private destroy$ = new Subject(); - protected formGroup = this.formBuilder.group({ - paymentMethod: [this.startWith], - bankInformation: this.formBuilder.group({ - routingNumber: ["", [Validators.required]], - accountNumber: ["", [Validators.required]], - accountHolderName: ["", [Validators.required]], - accountHolderType: ["", [Validators.required]], + protected formGroup = new FormGroup({ + paymentMethod: new FormControl(null), + bankInformation: new FormGroup({ + routingNumber: new FormControl("", [Validators.required]), + accountNumber: new FormControl("", [Validators.required]), + accountHolderName: new FormControl("", [Validators.required]), + accountHolderType: new FormControl("", [Validators.required]), }), }); + protected PaymentMethodType = PaymentMethodType; constructor( private billingApiService: BillingApiServiceAbstraction, private braintreeService: BraintreeServiceAbstraction, - private formBuilder: FormBuilder, private stripeService: StripeServiceAbstraction, ) {} - async tokenizePaymentMethod(): Promise { + ngOnInit(): void { + this.formGroup.controls.paymentMethod.patchValue(this.initialPaymentMethod); + + this.stripeService.loadStripe( + { + cardNumber: "#stripe-card-number", + cardExpiry: "#stripe-card-expiry", + cardCvc: "#stripe-card-cvc", + }, + this.initialPaymentMethod === PaymentMethodType.Card, + ); + + if (this.showPayPal) { + this.braintreeService.loadBraintree( + "#braintree-container", + this.initialPaymentMethod === PaymentMethodType.PayPal, + ); + } + + this.formGroup + .get("paymentMethod") + .valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((type) => { + this.onPaymentMethodChange(type); + }); + } + + /** Programmatically select the provided payment method. */ + select = (paymentMethod: PaymentMethodType) => { + this.formGroup.value.paymentMethod = paymentMethod; + }; + + protected submit = async () => { + const { type, token } = await this.tokenize(); + await this.onSubmit({ type, token }); + this.submitted.emit(type); + }; + + /** + * Tokenize the payment method information entered by the user against one of our payment providers. + * + * - {@link PaymentMethodType.Card} => [Stripe.confirmCardSetup]{@link https://docs.stripe.com/js/setup_intents/confirm_card_setup} + * - {@link PaymentMethodType.BankAccount} => [Stripe.confirmUsBankAccountSetup]{@link https://docs.stripe.com/js/setup_intents/confirm_us_bank_account_setup} + * - {@link PaymentMethodType.PayPal} => [Braintree.requestPaymentMethod]{@link https://braintree.github.io/braintree-web-drop-in/docs/current/Dropin.html#requestPaymentMethod} + * */ + async tokenize(): Promise<{ type: PaymentMethodType; token: string }> { const type = this.selected; if (this.usingStripe) { @@ -81,36 +144,6 @@ export class SelectPaymentMethodComponent implements OnInit, OnDestroy { return null; } - submit = async () => { - const tokenizedPaymentMethod = await this.tokenizePaymentMethod(); - await this.onSubmit(tokenizedPaymentMethod); - }; - - ngOnInit(): void { - this.stripeService.loadStripe( - { - cardNumber: "#stripe-card-number", - cardExpiry: "#stripe-card-expiry", - cardCvc: "#stripe-card-cvc", - }, - this.startWith === PaymentMethodType.Card, - ); - - if (this.showPayPal) { - this.braintreeService.loadBraintree( - "#braintree-container", - this.startWith === PaymentMethodType.PayPal, - ); - } - - this.formGroup - .get("paymentMethod") - .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe((type) => { - this.onPaymentMethodChange(type); - }); - } - ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); @@ -133,7 +166,7 @@ export class SelectPaymentMethodComponent implements OnInit, OnDestroy { } } - private get selected(): PaymentMethodType { + get selected(): PaymentMethodType { return this.formGroup.value.paymentMethod; } diff --git a/apps/web/src/app/billing/shared/payment.component.html b/apps/web/src/app/billing/shared/payment/payment.component.html similarity index 100% rename from apps/web/src/app/billing/shared/payment.component.html rename to apps/web/src/app/billing/shared/payment/payment.component.html diff --git a/apps/web/src/app/billing/shared/payment.component.ts b/apps/web/src/app/billing/shared/payment/payment.component.ts similarity index 99% rename from apps/web/src/app/billing/shared/payment.component.ts rename to apps/web/src/app/billing/shared/payment/payment.component.ts index 95b25a74e4e..03269c70a5a 100644 --- a/apps/web/src/app/billing/shared/payment.component.ts +++ b/apps/web/src/app/billing/shared/payment/payment.component.ts @@ -7,7 +7,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PaymentMethodType } from "@bitwarden/common/billing/enums"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { SharedModule } from "../../shared"; +import { SharedModule } from "../../../shared"; @Component({ selector: "app-payment", diff --git a/libs/angular/src/billing/components/verify-bank-account/verify-bank-account.component.html b/apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.html similarity index 89% rename from libs/angular/src/billing/components/verify-bank-account/verify-bank-account.component.html rename to apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.html index f338f5b0817..1b09f4bed51 100644 --- a/libs/angular/src/billing/components/verify-bank-account/verify-bank-account.component.html +++ b/apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.html @@ -11,7 +11,7 @@ $0. - diff --git a/libs/angular/src/billing/components/verify-bank-account/verify-bank-account.component.ts b/apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.ts similarity index 57% rename from libs/angular/src/billing/components/verify-bank-account/verify-bank-account.component.ts rename to apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.ts index c8abb65d819..5a6a7b0cf3d 100644 --- a/libs/angular/src/billing/components/verify-bank-account/verify-bank-account.component.ts +++ b/apps/web/src/app/billing/shared/verify-bank-account/verify-bank-account.component.ts @@ -1,13 +1,19 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; import { FormBuilder, FormControl, Validators } from "@angular/forms"; +import { VerifyBankAccountRequest } from "@bitwarden/common/billing/models/request/verify-bank-account.request"; + +import { SharedModule } from "../../../shared"; + @Component({ selector: "app-verify-bank-account", templateUrl: "./verify-bank-account.component.html", + standalone: true, + imports: [SharedModule], }) export class VerifyBankAccountComponent { - @Input() onSubmit?: (amount1: number, amount2: number) => Promise; - @Output() verificationSubmitted = new EventEmitter(); + @Input() onSubmit?: (request: VerifyBankAccountRequest) => Promise; + @Output() submitted = new EventEmitter(); protected formGroup = this.formBuilder.group({ amount1: new FormControl(null, [ @@ -25,9 +31,11 @@ export class VerifyBankAccountComponent { constructor(private formBuilder: FormBuilder) {} submit = async () => { - if (this.onSubmit) { - await this.onSubmit(this.formGroup.value.amount1, this.formGroup.value.amount2); - } - this.verificationSubmitted.emit(); + const request = new VerifyBankAccountRequest( + this.formGroup.value.amount1, + this.formGroup.value.amount2, + ); + await this.onSubmit(request); + this.submitted.emit(); }; } diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts index 37ef3173602..8ed10a2d6e3 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts @@ -16,8 +16,6 @@ import { ManageClientsComponent, ManageClientSubscriptionDialogComponent, ProviderBillingHistoryComponent, - ProviderPaymentMethodComponent, - ProviderSelectPaymentMethodDialogComponent, ProviderSubscriptionComponent, ProviderSubscriptionStatusComponent, } from "../../billing/providers"; @@ -80,8 +78,6 @@ import { SetupComponent } from "./setup/setup.component"; ManageClientSubscriptionDialogComponent, ProviderBillingHistoryComponent, ProviderSubscriptionComponent, - ProviderSelectPaymentMethodDialogComponent, - ProviderPaymentMethodComponent, ProviderSubscriptionStatusComponent, ], providers: [WebProviderService], diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/services/web-provider.service.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/services/web-provider.service.ts index 16b2d51de47..76094646808 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/services/web-provider.service.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/services/web-provider.service.ts @@ -3,7 +3,7 @@ import { Injectable } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request"; import { ProviderAddOrganizationRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-add-organization.request"; -import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction"; +import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { PlanType } from "@bitwarden/common/billing/enums"; import { CreateClientOrganizationRequest } from "@bitwarden/common/billing/models/request/create-client-organization.request"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts index c0ee21d2ab3..3e019b759f7 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts @@ -2,7 +2,7 @@ import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; import { Component, Inject, OnInit } from "@angular/core"; import { FormControl, FormGroup, Validators } from "@angular/forms"; -import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction"; +import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { PlanType } from "@bitwarden/common/billing/enums"; import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response"; import { ProviderPlanResponse } from "@bitwarden/common/billing/models/response/provider-subscription-response"; diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-name-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-name-dialog.component.ts index 20b7e9aaa7b..2e71a6c2d76 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-name-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-name-dialog.component.ts @@ -2,7 +2,7 @@ import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; import { Component, Inject } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; -import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction"; +import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { UpdateClientOrganizationRequest } from "@bitwarden/common/billing/models/request/update-client-organization.request"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { DialogService, ToastService } from "@bitwarden/components"; diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-clients.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-clients.component.ts index 03ef71482fb..a870b053dba 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-clients.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-clients.component.ts @@ -9,7 +9,7 @@ import { ProviderService } from "@bitwarden/common/admin-console/abstractions/pr import { ProviderUserType } from "@bitwarden/common/admin-console/enums"; import { Provider } from "@bitwarden/common/admin-console/models/domain/provider"; import { ProviderOrganizationOrganizationDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-organization.response"; -import { BillingApiServiceAbstraction as BillingApiService } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction"; +import { BillingApiServiceAbstraction as BillingApiService } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { hasConsolidatedBilling } from "@bitwarden/common/billing/abstractions/provider-billing.service.abstraction"; import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; diff --git a/bitwarden_license/bit-web/src/app/billing/providers/index.ts b/bitwarden_license/bit-web/src/app/billing/providers/index.ts index 87fed1cbd9d..b1294bc8047 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/index.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/index.ts @@ -1,7 +1,5 @@ export * from "./billing-history/provider-billing-history.component"; export * from "./clients"; export * from "./guards/has-consolidated-billing.guard"; -export * from "./payment-method/provider-select-payment-method-dialog.component"; -export * from "./payment-method/provider-payment-method.component"; export * from "./subscription/provider-subscription.component"; export * from "./subscription/provider-subscription-status.component"; diff --git a/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-payment-method.component.html b/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-payment-method.component.html deleted file mode 100644 index 2894752b28f..00000000000 --- a/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-payment-method.component.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - {{ "loading" | i18n }} - - - - -

- {{ "accountCredit" | i18n }} -

-

{{ accountCredit | currency: "$" }}

-

{{ "creditAppliedDesc" | i18n }}

- -
- - -

{{ "paymentMethod" | i18n }}

-

{{ "noPaymentMethod" | i18n }}

- - -

- - {{ paymentMethodDescription }} -

-
- -
- - -

{{ "taxInformation" | i18n }}

-

{{ "taxInformationDesc" | i18n }}

- -
-
diff --git a/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-payment-method.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-payment-method.component.ts deleted file mode 100644 index 42a7dbdec05..00000000000 --- a/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-payment-method.component.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { Component, OnDestroy, OnInit } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { from, lastValueFrom, Subject, switchMap } from "rxjs"; -import { takeUntil } from "rxjs/operators"; - -import { openAddAccountCreditDialog } from "@bitwarden/angular/billing/components"; -import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions"; -import { PaymentMethodType } from "@bitwarden/common/billing/enums"; -import { MaskedPaymentMethod, TaxInformation } from "@bitwarden/common/billing/models/domain"; -import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request"; -import { VerifyBankAccountRequest } from "@bitwarden/common/billing/models/request/verify-bank-account.request"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { DialogService, ToastService } from "@bitwarden/components"; - -import { - openProviderSelectPaymentMethodDialog, - ProviderSelectPaymentMethodDialogResultType, -} from "./provider-select-payment-method-dialog.component"; - -@Component({ - selector: "app-provider-payment-method", - templateUrl: "./provider-payment-method.component.html", -}) -export class ProviderPaymentMethodComponent implements OnInit, OnDestroy { - protected providerId: string; - protected loading: boolean; - - protected accountCredit: number; - protected maskedPaymentMethod: MaskedPaymentMethod; - protected taxInformation: TaxInformation; - - private destroy$ = new Subject(); - - constructor( - private activatedRoute: ActivatedRoute, - private billingApiService: BillingApiServiceAbstraction, - private dialogService: DialogService, - private i18nService: I18nService, - private toastService: ToastService, - ) {} - - addAccountCredit = () => - openAddAccountCreditDialog(this.dialogService, { - data: { - providerId: this.providerId, - }, - }); - - changePaymentMethod = async () => { - const dialogRef = openProviderSelectPaymentMethodDialog(this.dialogService, { - data: { - providerId: this.providerId, - }, - }); - - const result = await lastValueFrom(dialogRef.closed); - - if (result == ProviderSelectPaymentMethodDialogResultType.Submitted) { - await this.load(); - } - }; - - async load() { - this.loading = true; - const paymentInformation = await this.billingApiService.getProviderPaymentInformation( - this.providerId, - ); - this.accountCredit = paymentInformation.accountCredit; - this.maskedPaymentMethod = MaskedPaymentMethod.from(paymentInformation.paymentMethod); - this.taxInformation = TaxInformation.from(paymentInformation.taxInformation); - this.loading = false; - } - - onDataUpdated = async () => await this.load(); - - updateTaxInformation = async (taxInformation: TaxInformation) => { - const request = ExpandedTaxInfoUpdateRequest.From(taxInformation); - await this.billingApiService.updateProviderTaxInformation(this.providerId, request); - this.toastService.showToast({ - variant: "success", - title: null, - message: this.i18nService.t("updatedTaxInformation"), - }); - }; - - verifyBankAccount = async (amount1: number, amount2: number) => { - const request = new VerifyBankAccountRequest(amount1, amount2); - await this.billingApiService.verifyProviderBankAccount(this.providerId, request); - }; - - ngOnInit() { - this.activatedRoute.params - .pipe( - switchMap(({ providerId }) => { - this.providerId = providerId; - return from(this.load()); - }), - takeUntil(this.destroy$), - ) - .subscribe(); - } - - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } - - protected get hasPaymentMethod(): boolean { - return !!this.maskedPaymentMethod; - } - - protected get hasUnverifiedPaymentMethod(): boolean { - return !!this.maskedPaymentMethod && this.maskedPaymentMethod.needsVerification; - } - - protected get paymentMethodClass(): string[] { - switch (this.maskedPaymentMethod.type) { - case PaymentMethodType.Card: - return ["bwi-credit-card"]; - case PaymentMethodType.BankAccount: - return ["bwi-bank"]; - case PaymentMethodType.PayPal: - return ["bwi-paypal tw-text-primary"]; - default: - return []; - } - } - - protected get paymentMethodDescription(): string { - let description = this.maskedPaymentMethod.description; - if (this.maskedPaymentMethod.type === PaymentMethodType.BankAccount) { - if (this.hasUnverifiedPaymentMethod) { - description += " - " + this.i18nService.t("unverified"); - } else { - description += " - " + this.i18nService.t("verified"); - } - } - return description; - } -} diff --git a/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-select-payment-method-dialog.component.html b/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-select-payment-method-dialog.component.html deleted file mode 100644 index 03e8405a48c..00000000000 --- a/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-select-payment-method-dialog.component.html +++ /dev/null @@ -1,18 +0,0 @@ -
- - - {{ "addPaymentMethod" | i18n }} - - - - - - - - - -
diff --git a/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-select-payment-method-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-select-payment-method-dialog.component.ts deleted file mode 100644 index 09a293d12d8..00000000000 --- a/bitwarden_license/bit-web/src/app/billing/providers/payment-method/provider-select-payment-method-dialog.component.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; -import { Component, EventEmitter, Inject, Output, ViewChild } from "@angular/core"; -import { FormGroup } from "@angular/forms"; - -import { SelectPaymentMethodComponent } from "@bitwarden/angular/billing/components"; -import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions"; -import { TokenizedPaymentMethodRequest } from "@bitwarden/common/billing/models/request/tokenized-payment-method.request"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { DialogService, ToastService } from "@bitwarden/components"; - -type ProviderSelectPaymentMethodDialogParams = { - providerId: string; -}; - -export enum ProviderSelectPaymentMethodDialogResultType { - Closed = "closed", - Submitted = "submitted", -} - -export const openProviderSelectPaymentMethodDialog = ( - dialogService: DialogService, - dialogConfig: DialogConfig, -) => - dialogService.open< - ProviderSelectPaymentMethodDialogResultType, - ProviderSelectPaymentMethodDialogParams - >(ProviderSelectPaymentMethodDialogComponent, dialogConfig); - -@Component({ - templateUrl: "provider-select-payment-method-dialog.component.html", -}) -export class ProviderSelectPaymentMethodDialogComponent { - @ViewChild(SelectPaymentMethodComponent) - selectPaymentMethodComponent: SelectPaymentMethodComponent; - @Output() providerPaymentMethodUpdated = new EventEmitter(); - - protected readonly formGroup = new FormGroup({}); - protected readonly ResultType = ProviderSelectPaymentMethodDialogResultType; - - constructor( - private billingApiService: BillingApiServiceAbstraction, - @Inject(DIALOG_DATA) private dialogParams: ProviderSelectPaymentMethodDialogParams, - private dialogRef: DialogRef, - private i18nService: I18nService, - private toastService: ToastService, - ) {} - - submit = async () => { - const tokenizedPaymentMethod = await this.selectPaymentMethodComponent.tokenizePaymentMethod(); - const request = TokenizedPaymentMethodRequest.From(tokenizedPaymentMethod); - await this.billingApiService.updateProviderPaymentMethod(this.dialogParams.providerId, request); - this.providerPaymentMethodUpdated.emit(); - this.toastService.showToast({ - variant: "success", - title: null, - message: this.i18nService.t("updatedPaymentMethod"), - }); - this.dialogRef.close(this.ResultType.Submitted); - }; -} diff --git a/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.ts index 4e428d45143..43521ebe863 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.ts @@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { Subject, concatMap, takeUntil } from "rxjs"; -import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction"; +import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { TaxInformation } from "@bitwarden/common/billing/models/domain"; import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request"; import { diff --git a/libs/angular/src/billing/components/index.ts b/libs/angular/src/billing/components/index.ts index 8c8d5bd292b..675d7555ed2 100644 --- a/libs/angular/src/billing/components/index.ts +++ b/libs/angular/src/billing/components/index.ts @@ -2,5 +2,3 @@ export * from "./add-account-credit-dialog/add-account-credit-dialog.component"; export * from "./invoices/invoices.component"; export * from "./invoices/no-invoices.component"; export * from "./manage-tax-information/manage-tax-information.component"; -export * from "./select-payment-method/select-payment-method.component"; -export * from "./verify-bank-account/verify-bank-account.component"; diff --git a/libs/angular/src/jslib.module.ts b/libs/angular/src/jslib.module.ts index 755d52c0e77..bebac42fd83 100644 --- a/libs/angular/src/jslib.module.ts +++ b/libs/angular/src/jslib.module.ts @@ -7,8 +7,6 @@ import { InvoicesComponent, NoInvoicesComponent, ManageTaxInformationComponent, - SelectPaymentMethodComponent, - VerifyBankAccountComponent, } from "@bitwarden/angular/billing/components"; import { AsyncActionsModule, @@ -116,8 +114,6 @@ import { IconComponent } from "./vault/components/icon.component"; InvoicesComponent, NoInvoicesComponent, ManageTaxInformationComponent, - SelectPaymentMethodComponent, - VerifyBankAccountComponent, TwoFactorIconComponent, ], exports: [ @@ -153,8 +149,6 @@ import { IconComponent } from "./vault/components/icon.component"; InvoicesComponent, NoInvoicesComponent, ManageTaxInformationComponent, - SelectPaymentMethodComponent, - VerifyBankAccountComponent, TwoFactorIconComponent, ], providers: [ diff --git a/libs/common/src/billing/abstractions/billilng-api.service.abstraction.ts b/libs/common/src/billing/abstractions/billing-api.service.abstraction.ts similarity index 79% rename from libs/common/src/billing/abstractions/billilng-api.service.abstraction.ts rename to libs/common/src/billing/abstractions/billing-api.service.abstraction.ts index fd7feab4c32..ef148d1aef4 100644 --- a/libs/common/src/billing/abstractions/billilng-api.service.abstraction.ts +++ b/libs/common/src/billing/abstractions/billing-api.service.abstraction.ts @@ -1,10 +1,10 @@ import { ProviderOrganizationOrganizationDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-organization.response"; import { PaymentMethodType } from "@bitwarden/common/billing/enums"; import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request"; -import { TokenizedPaymentMethodRequest } from "@bitwarden/common/billing/models/request/tokenized-payment-method.request"; +import { UpdatePaymentMethodRequest } from "@bitwarden/common/billing/models/request/update-payment-method.request"; import { VerifyBankAccountRequest } from "@bitwarden/common/billing/models/request/verify-bank-account.request"; import { InvoicesResponse } from "@bitwarden/common/billing/models/response/invoices.response"; -import { PaymentInformationResponse } from "@bitwarden/common/billing/models/response/payment-information.response"; +import { PaymentMethodResponse } from "@bitwarden/common/billing/models/response/payment-method.response"; import { SubscriptionCancellationRequest } from "../../billing/models/request/subscription-cancellation.request"; import { OrganizationBillingMetadataResponse } from "../../billing/models/response/organization-billing-metadata.response"; @@ -33,6 +33,8 @@ export abstract class BillingApiServiceAbstraction { organizationId: string, ) => Promise; + getOrganizationPaymentMethod: (organizationId: string) => Promise; + getPlans: () => Promise>; getProviderClientInvoiceReport: (providerId: string, invoiceId: string) => Promise; @@ -43,37 +45,31 @@ export abstract class BillingApiServiceAbstraction { getProviderInvoices: (providerId: string) => Promise; - /** - * @deprecated This endpoint is currently deactivated. - */ - getProviderPaymentInformation: (providerId: string) => Promise; - getProviderSubscription: (providerId: string) => Promise; + updateOrganizationPaymentMethod: ( + organizationId: string, + request: UpdatePaymentMethodRequest, + ) => Promise; + + updateOrganizationTaxInformation: ( + organizationId: string, + request: ExpandedTaxInfoUpdateRequest, + ) => Promise; + updateProviderClientOrganization: ( providerId: string, organizationId: string, request: UpdateClientOrganizationRequest, ) => Promise; - /** - * @deprecated This endpoint is currently deactivated. - */ - updateProviderPaymentMethod: ( - providerId: string, - request: TokenizedPaymentMethodRequest, - ) => Promise; - updateProviderTaxInformation: ( providerId: string, request: ExpandedTaxInfoUpdateRequest, ) => Promise; - /** - * @deprecated This endpoint is currently deactivated. - */ - verifyProviderBankAccount: ( - providerId: string, + verifyOrganizationBankAccount: ( + organizationId: string, request: VerifyBankAccountRequest, ) => Promise; } diff --git a/libs/common/src/billing/abstractions/index.ts b/libs/common/src/billing/abstractions/index.ts index c3ef8baca29..05d214f424c 100644 --- a/libs/common/src/billing/abstractions/index.ts +++ b/libs/common/src/billing/abstractions/index.ts @@ -1,5 +1,5 @@ export * from "./account/billing-account-profile-state.service"; -export * from "./billilng-api.service.abstraction"; +export * from "./billing-api.service.abstraction"; export * from "./organization-billing.service"; export * from "./payment-processors/braintree.service.abstraction"; export * from "./payment-processors/stripe.service.abstraction"; diff --git a/libs/common/src/billing/models/domain/index.ts b/libs/common/src/billing/models/domain/index.ts index 66d7e29c100..0f53c3e116c 100644 --- a/libs/common/src/billing/models/domain/index.ts +++ b/libs/common/src/billing/models/domain/index.ts @@ -1,4 +1,2 @@ export * from "./bank-account"; -export * from "./masked-payment-method"; export * from "./tax-information"; -export * from "./tokenized-payment-method"; diff --git a/libs/common/src/billing/models/domain/masked-payment-method.ts b/libs/common/src/billing/models/domain/masked-payment-method.ts deleted file mode 100644 index 5756f9f25c0..00000000000 --- a/libs/common/src/billing/models/domain/masked-payment-method.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PaymentMethodType } from "@bitwarden/common/billing/enums"; -import { MaskedPaymentMethodResponse } from "@bitwarden/common/billing/models/response/masked-payment-method.response"; - -export class MaskedPaymentMethod { - type: PaymentMethodType; - description: string; - needsVerification: boolean; - - static from(response: MaskedPaymentMethodResponse | undefined) { - if (response === undefined) { - return null; - } - return { - ...response, - }; - } -} diff --git a/libs/common/src/billing/models/request/tokenized-payment-method.request.ts b/libs/common/src/billing/models/request/tokenized-payment-method.request.ts deleted file mode 100644 index 7f89b216935..00000000000 --- a/libs/common/src/billing/models/request/tokenized-payment-method.request.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { PaymentMethodType } from "@bitwarden/common/billing/enums"; -import { TokenizedPaymentMethod } from "@bitwarden/common/billing/models/domain"; - -export class TokenizedPaymentMethodRequest { - type: PaymentMethodType; - token: string; - - static From(tokenizedPaymentMethod: TokenizedPaymentMethod): TokenizedPaymentMethodRequest { - const request = new TokenizedPaymentMethodRequest(); - request.type = tokenizedPaymentMethod.type; - request.token = tokenizedPaymentMethod.token; - return request; - } -} diff --git a/libs/common/src/billing/models/domain/tokenized-payment-method.ts b/libs/common/src/billing/models/request/tokenized-payment-source.request.ts similarity index 70% rename from libs/common/src/billing/models/domain/tokenized-payment-method.ts rename to libs/common/src/billing/models/request/tokenized-payment-source.request.ts index 5900a1ab242..26faa036d57 100644 --- a/libs/common/src/billing/models/domain/tokenized-payment-method.ts +++ b/libs/common/src/billing/models/request/tokenized-payment-source.request.ts @@ -1,6 +1,6 @@ import { PaymentMethodType } from "@bitwarden/common/billing/enums"; -export type TokenizedPaymentMethod = { +export class TokenizedPaymentSourceRequest { type: PaymentMethodType; token: string; -}; +} diff --git a/libs/common/src/billing/models/request/update-payment-method.request.ts b/libs/common/src/billing/models/request/update-payment-method.request.ts new file mode 100644 index 00000000000..613dc636482 --- /dev/null +++ b/libs/common/src/billing/models/request/update-payment-method.request.ts @@ -0,0 +1,7 @@ +import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request"; +import { TokenizedPaymentSourceRequest } from "@bitwarden/common/billing/models/request/tokenized-payment-source.request"; + +export class UpdatePaymentMethodRequest { + paymentSource: TokenizedPaymentSourceRequest; + taxInformation: ExpandedTaxInfoUpdateRequest; +} diff --git a/libs/common/src/billing/models/response/organization-risks-subscription-failure.response.ts b/libs/common/src/billing/models/response/organization-risks-subscription-failure.response.ts deleted file mode 100644 index 76cf5ab66f9..00000000000 --- a/libs/common/src/billing/models/response/organization-risks-subscription-failure.response.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { BaseResponse } from "../../../models/response/base.response"; - -export class OrganizationRisksSubscriptionFailureResponse extends BaseResponse { - organizationId: string; - risksSubscriptionFailure: boolean; - - constructor(response: any) { - super(response); - - this.organizationId = this.getResponseProperty("OrganizationId"); - this.risksSubscriptionFailure = this.getResponseProperty("RisksSubscriptionFailure"); - } -} diff --git a/libs/common/src/billing/models/response/payment-information.response.ts b/libs/common/src/billing/models/response/payment-method.response.ts similarity index 52% rename from libs/common/src/billing/models/response/payment-information.response.ts rename to libs/common/src/billing/models/response/payment-method.response.ts index a74ec8f406b..34e95032aef 100644 --- a/libs/common/src/billing/models/response/payment-information.response.ts +++ b/libs/common/src/billing/models/response/payment-method.response.ts @@ -1,22 +1,25 @@ import { BaseResponse } from "../../../models/response/base.response"; -import { MaskedPaymentMethodResponse } from "./masked-payment-method.response"; +import { PaymentSourceResponse } from "./payment-source.response"; import { TaxInfoResponse } from "./tax-info.response"; -export class PaymentInformationResponse extends BaseResponse { +export class PaymentMethodResponse extends BaseResponse { accountCredit: number; - paymentMethod?: MaskedPaymentMethodResponse; + paymentSource?: PaymentSourceResponse; + subscriptionStatus?: string; taxInformation?: TaxInfoResponse; constructor(response: any) { super(response); this.accountCredit = this.getResponseProperty("AccountCredit"); - const paymentMethod = this.getResponseProperty("PaymentMethod"); - if (paymentMethod) { - this.paymentMethod = new MaskedPaymentMethodResponse(paymentMethod); + const paymentSource = this.getResponseProperty("PaymentSource"); + if (paymentSource) { + this.paymentSource = new PaymentSourceResponse(paymentSource); } + this.subscriptionStatus = this.getResponseProperty("SubscriptionStatus"); + const taxInformation = this.getResponseProperty("TaxInformation"); if (taxInformation) { this.taxInformation = new TaxInfoResponse(taxInformation); diff --git a/libs/common/src/billing/models/response/masked-payment-method.response.ts b/libs/common/src/billing/models/response/payment-source.response.ts similarity index 88% rename from libs/common/src/billing/models/response/masked-payment-method.response.ts rename to libs/common/src/billing/models/response/payment-source.response.ts index 19ae1b426b0..1aeeb450b11 100644 --- a/libs/common/src/billing/models/response/masked-payment-method.response.ts +++ b/libs/common/src/billing/models/response/payment-source.response.ts @@ -1,7 +1,7 @@ import { PaymentMethodType } from "@bitwarden/common/billing/enums"; import { BaseResponse } from "@bitwarden/common/models/response/base.response"; -export class MaskedPaymentMethodResponse extends BaseResponse { +export class PaymentSourceResponse extends BaseResponse { type: PaymentMethodType; description: string; needsVerification: boolean; diff --git a/libs/common/src/billing/services/billing-api.service.ts b/libs/common/src/billing/services/billing-api.service.ts index 822e6d16871..534b22362d6 100644 --- a/libs/common/src/billing/services/billing-api.service.ts +++ b/libs/common/src/billing/services/billing-api.service.ts @@ -1,5 +1,8 @@ import { ProviderOrganizationOrganizationDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-organization.response"; +import { UpdatePaymentMethodRequest } from "@bitwarden/common/billing/models/request/update-payment-method.request"; +import { VerifyBankAccountRequest } from "@bitwarden/common/billing/models/request/verify-bank-account.request"; import { InvoicesResponse } from "@bitwarden/common/billing/models/response/invoices.response"; +import { PaymentMethodResponse } from "@bitwarden/common/billing/models/response/payment-method.response"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { ToastService } from "@bitwarden/components"; @@ -9,10 +12,7 @@ import { BillingApiServiceAbstraction } from "../../billing/abstractions"; import { PaymentMethodType } from "../../billing/enums"; import { ExpandedTaxInfoUpdateRequest } from "../../billing/models/request/expanded-tax-info-update.request"; import { SubscriptionCancellationRequest } from "../../billing/models/request/subscription-cancellation.request"; -import { TokenizedPaymentMethodRequest } from "../../billing/models/request/tokenized-payment-method.request"; -import { VerifyBankAccountRequest } from "../../billing/models/request/verify-bank-account.request"; import { OrganizationBillingMetadataResponse } from "../../billing/models/response/organization-billing-metadata.response"; -import { PaymentInformationResponse } from "../../billing/models/response/payment-information.response"; import { PlanResponse } from "../../billing/models/response/plan.response"; import { ListResponse } from "../../models/response/list.response"; import { CreateClientOrganizationRequest } from "../models/request/create-client-organization.request"; @@ -85,6 +85,19 @@ export class BillingApiService implements BillingApiServiceAbstraction { return new OrganizationBillingMetadataResponse(r); } + async getOrganizationPaymentMethod(organizationId: string): Promise { + const response = await this.execute(() => + this.apiService.send( + "GET", + "/organizations/" + organizationId + "/billing/payment-method", + null, + true, + true, + ), + ); + return new PaymentMethodResponse(response); + } + async getPlans(): Promise> { const r = await this.apiService.send("GET", "/plans", null, false, true); return new ListResponse(r, PlanResponse); @@ -123,19 +136,6 @@ export class BillingApiService implements BillingApiServiceAbstraction { return new InvoicesResponse(response); } - async getProviderPaymentInformation(providerId: string): Promise { - const response = await this.execute(() => - this.apiService.send( - "GET", - "/providers/" + providerId + "/billing/payment-information", - null, - true, - true, - ), - ); - return new PaymentInformationResponse(response); - } - async getProviderSubscription(providerId: string): Promise { const response = await this.execute(() => this.apiService.send( @@ -149,6 +149,32 @@ export class BillingApiService implements BillingApiServiceAbstraction { return new ProviderSubscriptionResponse(response); } + async updateOrganizationPaymentMethod( + organizationId: string, + request: UpdatePaymentMethodRequest, + ): Promise { + return await this.apiService.send( + "PUT", + "/organizations/" + organizationId + "/billing/payment-method", + request, + true, + false, + ); + } + + async updateOrganizationTaxInformation( + organizationId: string, + request: ExpandedTaxInfoUpdateRequest, + ): Promise { + return await this.apiService.send( + "PUT", + "/organizations/" + organizationId + "/billing/tax-information", + request, + true, + false, + ); + } + async updateProviderClientOrganization( providerId: string, organizationId: string, @@ -163,19 +189,6 @@ export class BillingApiService implements BillingApiServiceAbstraction { ); } - async updateProviderPaymentMethod( - providerId: string, - request: TokenizedPaymentMethodRequest, - ): Promise { - return await this.apiService.send( - "PUT", - "/providers/" + providerId + "/billing/payment-method", - request, - true, - false, - ); - } - async updateProviderTaxInformation(providerId: string, request: ExpandedTaxInfoUpdateRequest) { return await this.apiService.send( "PUT", @@ -186,10 +199,13 @@ export class BillingApiService implements BillingApiServiceAbstraction { ); } - async verifyProviderBankAccount(providerId: string, request: VerifyBankAccountRequest) { + async verifyOrganizationBankAccount( + organizationId: string, + request: VerifyBankAccountRequest, + ): Promise { return await this.apiService.send( "POST", - "/providers/" + providerId + "/billing/payment-method/verify-bank-account", + "/organizations/" + organizationId + "/billing/payment-method/verify-bank-account", request, true, false, diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 1ac4c99b1fa..8e88cda6178 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -33,6 +33,7 @@ export enum FeatureFlag { DelayFido2PageScriptInitWithinMv2 = "delay-fido2-page-script-init-within-mv2", AccountDeprovisioning = "pm-10308-account-deprovisioning", NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements", + AC2476_DeprecateStripeSourcesAPI = "AC-2476-deprecate-stripe-sources-api", } export type AllowedFeatureFlagTypes = boolean | number | string; @@ -76,6 +77,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.DelayFido2PageScriptInitWithinMv2]: FALSE, [FeatureFlag.AccountDeprovisioning]: FALSE, [FeatureFlag.NotificationBarAddLoginImprovements]: FALSE, + [FeatureFlag.AC2476_DeprecateStripeSourcesAPI]: FALSE, } satisfies Record; export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;