1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 00:03:56 +00:00

[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
This commit is contained in:
Alex Morask
2024-08-28 10:48:22 -04:00
committed by GitHub
parent b0ffac04af
commit a58642e370
47 changed files with 623 additions and 481 deletions

View File

@@ -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<AdjustPaymentDialogV2ResultType>,
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<void> => {
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<AdjustPaymentDialogV2Params>,
) =>
dialogService.open<AdjustPaymentDialogV2ResultType>(
AdjustPaymentDialogV2Component,
dialogConfig,
);
}