mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 00:03:56 +00:00
Require provider payment method during setup behind FF (#14550)
This commit is contained in:
@@ -81,7 +81,7 @@
|
|||||||
<!-- Bank Account -->
|
<!-- Bank Account -->
|
||||||
<ng-container *ngIf="showBankAccount && usingBankAccount">
|
<ng-container *ngIf="showBankAccount && usingBankAccount">
|
||||||
<bit-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
<bit-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
||||||
{{ "verifyBankAccountWithStatementDescriptorWarning" | i18n }}
|
{{ bankAccountWarning }}
|
||||||
</bit-callout>
|
</bit-callout>
|
||||||
<div class="tw-grid tw-grid-cols-2 tw-gap-4 tw-mb-4" formGroupName="bankInformation">
|
<div class="tw-grid tw-grid-cols-2 tw-gap-4 tw-mb-4" formGroupName="bankInformation">
|
||||||
<bit-form-field class="tw-col-span-1" disableMargin>
|
<bit-form-field class="tw-col-span-1" disableMargin>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { takeUntil } from "rxjs/operators";
|
|||||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||||
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
||||||
import { TokenizedPaymentSourceRequest } from "@bitwarden/common/billing/models/request/tokenized-payment-source.request";
|
import { TokenizedPaymentSourceRequest } from "@bitwarden/common/billing/models/request/tokenized-payment-source.request";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
|
||||||
import { SharedModule } from "../../../shared";
|
import { SharedModule } from "../../../shared";
|
||||||
import { BillingServicesModule, BraintreeService, StripeService } from "../../services";
|
import { BillingServicesModule, BraintreeService, StripeService } from "../../services";
|
||||||
@@ -37,6 +38,8 @@ export class PaymentComponent implements OnInit, OnDestroy {
|
|||||||
/** If provided, will be invoked with the tokenized payment source during form submission. */
|
/** If provided, will be invoked with the tokenized payment source during form submission. */
|
||||||
@Input() protected onSubmit?: (request: TokenizedPaymentSourceRequest) => Promise<void>;
|
@Input() protected onSubmit?: (request: TokenizedPaymentSourceRequest) => Promise<void>;
|
||||||
|
|
||||||
|
@Input() private bankAccountWarningOverride?: string;
|
||||||
|
|
||||||
@Output() submitted = new EventEmitter<PaymentMethodType>();
|
@Output() submitted = new EventEmitter<PaymentMethodType>();
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
@@ -56,6 +59,7 @@ export class PaymentComponent implements OnInit, OnDestroy {
|
|||||||
constructor(
|
constructor(
|
||||||
private billingApiService: BillingApiServiceAbstraction,
|
private billingApiService: BillingApiServiceAbstraction,
|
||||||
private braintreeService: BraintreeService,
|
private braintreeService: BraintreeService,
|
||||||
|
private i18nService: I18nService,
|
||||||
private stripeService: StripeService,
|
private stripeService: StripeService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -200,4 +204,12 @@ export class PaymentComponent implements OnInit, OnDestroy {
|
|||||||
private get usingStripe(): boolean {
|
private get usingStripe(): boolean {
|
||||||
return this.usingBankAccount || this.usingCard;
|
return this.usingBankAccount || this.usingCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get bankAccountWarning(): string {
|
||||||
|
if (this.bankAccountWarningOverride) {
|
||||||
|
return this.bankAccountWarningOverride;
|
||||||
|
} else {
|
||||||
|
return this.i18nService.t("verifyBankAccountWithStatementDescriptorWarning");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10631,5 +10631,8 @@
|
|||||||
},
|
},
|
||||||
"restart": {
|
"restart": {
|
||||||
"message": "Restart"
|
"message": "Restart"
|
||||||
|
},
|
||||||
|
"verifyProviderBankAccountWithStatementDescriptorWarning": {
|
||||||
|
"message": "Payment with a bank account is only available to customers in the United States. You will be required to verify your bank account. We will make a micro-deposit within the next 1-2 business days. Enter the statement descriptor code from this deposit on the provider's subscription page to verify the bank account. Failure to verify the bank account will result in a missed payment and your subscription being suspended."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
|
|||||||
import { CardComponent, SearchModule } from "@bitwarden/components";
|
import { CardComponent, SearchModule } from "@bitwarden/components";
|
||||||
import { DangerZoneComponent } from "@bitwarden/web-vault/app/auth/settings/account/danger-zone.component";
|
import { DangerZoneComponent } from "@bitwarden/web-vault/app/auth/settings/account/danger-zone.component";
|
||||||
import { OrganizationPlansComponent } from "@bitwarden/web-vault/app/billing";
|
import { OrganizationPlansComponent } from "@bitwarden/web-vault/app/billing";
|
||||||
|
import { PaymentComponent } from "@bitwarden/web-vault/app/billing/shared/payment/payment.component";
|
||||||
import { VerifyBankAccountComponent } from "@bitwarden/web-vault/app/billing/shared/verify-bank-account/verify-bank-account.component";
|
import { VerifyBankAccountComponent } from "@bitwarden/web-vault/app/billing/shared/verify-bank-account/verify-bank-account.component";
|
||||||
import { OssModule } from "@bitwarden/web-vault/app/oss.module";
|
import { OssModule } from "@bitwarden/web-vault/app/oss.module";
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ import { VerifyRecoverDeleteProviderComponent } from "./verify-recover-delete-pr
|
|||||||
ScrollingModule,
|
ScrollingModule,
|
||||||
VerifyBankAccountComponent,
|
VerifyBankAccountComponent,
|
||||||
CardComponent,
|
CardComponent,
|
||||||
|
PaymentComponent,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AcceptProviderComponent,
|
AcceptProviderComponent,
|
||||||
|
|||||||
@@ -12,23 +12,50 @@
|
|||||||
</div>
|
</div>
|
||||||
<p>{{ "setupProviderDesc" | i18n }}</p>
|
<p>{{ "setupProviderDesc" | i18n }}</p>
|
||||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||||
<h2 class="tw-mt-5">{{ "generalInformation" | i18n }}</h2>
|
@if (!(requireProviderPaymentMethodDuringSetup$ | async)) {
|
||||||
<div class="tw-grid tw-grid-flow-col tw-grid-cols-12 tw-gap-4">
|
<h2 class="tw-mt-5">{{ "generalInformation" | i18n }}</h2>
|
||||||
<div class="tw-col-span-6">
|
<div class="tw-grid tw-grid-flow-col tw-grid-cols-12 tw-gap-4">
|
||||||
<bit-form-field>
|
<div class="tw-col-span-6">
|
||||||
<bit-label>{{ "providerName" | i18n }}</bit-label>
|
<bit-form-field>
|
||||||
<input type="text" bitInput formControlName="name" />
|
<bit-label>{{ "providerName" | i18n }}</bit-label>
|
||||||
</bit-form-field>
|
<input type="text" bitInput formControlName="name" />
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="tw-col-span-6">
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "billingEmail" | i18n }}</bit-label>
|
||||||
|
<input type="email" bitInput formControlName="billingEmail" />
|
||||||
|
<bit-hint>{{ "providerBillingEmailHint" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tw-col-span-6">
|
<app-manage-tax-information />
|
||||||
<bit-form-field>
|
} @else {
|
||||||
<bit-label>{{ "billingEmail" | i18n }}</bit-label>
|
<h2 class="tw-mt-5">{{ "billingInformation" | i18n }}</h2>
|
||||||
<input type="email" bitInput formControlName="billingEmail" />
|
<div class="tw-grid tw-grid-flow-col tw-grid-cols-12 tw-gap-4">
|
||||||
<bit-hint>{{ "providerBillingEmailHint" | i18n }}</bit-hint>
|
<div class="tw-col-span-6">
|
||||||
</bit-form-field>
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "providerName" | i18n }}</bit-label>
|
||||||
|
<input type="text" bitInput formControlName="name" />
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="tw-col-span-6">
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "billingEmail" | i18n }}</bit-label>
|
||||||
|
<input type="email" bitInput formControlName="billingEmail" />
|
||||||
|
<bit-hint>{{ "providerBillingEmailHint" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<h2 class="tw-mt-5">{{ "paymentMethod" | i18n }}</h2>
|
||||||
<app-manage-tax-information />
|
<app-payment
|
||||||
|
[showAccountCredit]="false"
|
||||||
|
[bankAccountWarningOverride]="
|
||||||
|
'verifyProviderBankAccountWithStatementDescriptorWarning' | i18n
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<app-manage-tax-information />
|
||||||
|
}
|
||||||
<button class="tw-mt-8" bitButton bitFormButton buttonType="primary" type="submit">
|
<button class="tw-mt-8" bitButton bitFormButton buttonType="primary" type="submit">
|
||||||
{{ "submit" | i18n }}
|
{{ "submit" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||||
import { FormBuilder, Validators } from "@angular/forms";
|
import { FormBuilder, Validators } from "@angular/forms";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { Subject, switchMap } from "rxjs";
|
import { firstValueFrom, Subject, switchMap } from "rxjs";
|
||||||
import { first, takeUntil } from "rxjs/operators";
|
import { first, takeUntil } from "rxjs/operators";
|
||||||
|
|
||||||
import { ManageTaxInformationComponent } from "@bitwarden/angular/billing/components";
|
import { ManageTaxInformationComponent } from "@bitwarden/angular/billing/components";
|
||||||
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
|
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
|
||||||
import { ProviderSetupRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-setup.request";
|
import { ProviderSetupRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-setup.request";
|
||||||
import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request";
|
import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request";
|
||||||
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
@@ -17,12 +18,14 @@ import { ProviderKey } from "@bitwarden/common/types/key";
|
|||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
import { ToastService } from "@bitwarden/components";
|
import { ToastService } from "@bitwarden/components";
|
||||||
import { KeyService } from "@bitwarden/key-management";
|
import { KeyService } from "@bitwarden/key-management";
|
||||||
|
import { PaymentComponent } from "@bitwarden/web-vault/app/billing/shared/payment/payment.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "provider-setup",
|
selector: "provider-setup",
|
||||||
templateUrl: "setup.component.html",
|
templateUrl: "setup.component.html",
|
||||||
})
|
})
|
||||||
export class SetupComponent implements OnInit, OnDestroy {
|
export class SetupComponent implements OnInit, OnDestroy {
|
||||||
|
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
|
||||||
@ViewChild(ManageTaxInformationComponent) taxInformationComponent: ManageTaxInformationComponent;
|
@ViewChild(ManageTaxInformationComponent) taxInformationComponent: ManageTaxInformationComponent;
|
||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
@@ -36,6 +39,10 @@ export class SetupComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
requireProviderPaymentMethodDuringSetup$ = this.configService.getFeatureFlag$(
|
||||||
|
FeatureFlag.PM19956_RequireProviderPaymentMethodDuringSetup,
|
||||||
|
);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
@@ -134,6 +141,14 @@ export class SetupComponent implements OnInit, OnDestroy {
|
|||||||
request.taxInfo.city = taxInformation.city;
|
request.taxInfo.city = taxInformation.city;
|
||||||
request.taxInfo.state = taxInformation.state;
|
request.taxInfo.state = taxInformation.state;
|
||||||
|
|
||||||
|
const requireProviderPaymentMethodDuringSetup = await firstValueFrom(
|
||||||
|
this.requireProviderPaymentMethodDuringSetup$,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (requireProviderPaymentMethodDuringSetup) {
|
||||||
|
request.paymentSource = await this.paymentComponent.tokenize();
|
||||||
|
}
|
||||||
|
|
||||||
const provider = await this.providerApiService.postProviderSetup(this.providerId, request);
|
const provider = await this.providerApiService.postProviderSetup(this.providerId, request);
|
||||||
|
|
||||||
this.toastService.showToast({
|
this.toastService.showToast({
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { ExpandedTaxInfoUpdateRequest } from "../../../../billing/models/request/expanded-tax-info-update.request";
|
import { ExpandedTaxInfoUpdateRequest } from "../../../../billing/models/request/expanded-tax-info-update.request";
|
||||||
|
import { TokenizedPaymentSourceRequest } from "../../../../billing/models/request/tokenized-payment-source.request";
|
||||||
|
|
||||||
export class ProviderSetupRequest {
|
export class ProviderSetupRequest {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -9,4 +10,5 @@ export class ProviderSetupRequest {
|
|||||||
token: string;
|
token: string;
|
||||||
key: string;
|
key: string;
|
||||||
taxInfo: ExpandedTaxInfoUpdateRequest;
|
taxInfo: ExpandedTaxInfoUpdateRequest;
|
||||||
|
paymentSource?: TokenizedPaymentSourceRequest;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export enum FeatureFlag {
|
|||||||
PM12276_BreadcrumbEventLogs = "pm-12276-breadcrumbing-for-business-features",
|
PM12276_BreadcrumbEventLogs = "pm-12276-breadcrumbing-for-business-features",
|
||||||
PM18794_ProviderPaymentMethod = "pm-18794-provider-payment-method",
|
PM18794_ProviderPaymentMethod = "pm-18794-provider-payment-method",
|
||||||
PM17772_AdminInitiatedSponsorships = "pm-17772-admin-initiated-sponsorships",
|
PM17772_AdminInitiatedSponsorships = "pm-17772-admin-initiated-sponsorships",
|
||||||
|
PM19956_RequireProviderPaymentMethodDuringSetup = "pm-19956-require-provider-payment-method-during-setup",
|
||||||
|
|
||||||
/* Data Insights and Reporting */
|
/* Data Insights and Reporting */
|
||||||
CriticalApps = "pm-14466-risk-insights-critical-application",
|
CriticalApps = "pm-14466-risk-insights-critical-application",
|
||||||
@@ -121,6 +122,7 @@ export const DefaultFeatureFlagValue = {
|
|||||||
[FeatureFlag.PM12276_BreadcrumbEventLogs]: FALSE,
|
[FeatureFlag.PM12276_BreadcrumbEventLogs]: FALSE,
|
||||||
[FeatureFlag.PM18794_ProviderPaymentMethod]: FALSE,
|
[FeatureFlag.PM18794_ProviderPaymentMethod]: FALSE,
|
||||||
[FeatureFlag.PM17772_AdminInitiatedSponsorships]: FALSE,
|
[FeatureFlag.PM17772_AdminInitiatedSponsorships]: FALSE,
|
||||||
|
[FeatureFlag.PM19956_RequireProviderPaymentMethodDuringSetup]: FALSE,
|
||||||
|
|
||||||
/* Key Management */
|
/* Key Management */
|
||||||
[FeatureFlag.PrivateKeyRegeneration]: FALSE,
|
[FeatureFlag.PrivateKeyRegeneration]: FALSE,
|
||||||
|
|||||||
Reference in New Issue
Block a user