From 889b5e4ee212bfc1e6956b060477911da5fbf39e Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Fri, 10 Jan 2025 13:55:59 +0100 Subject: [PATCH] [PM-16921] Verify tax information is being passed correctly and validated. --- .../premium/premium-v2.component.html | 7 ++- .../premium/premium-v2.component.ts | 44 ++++++++++++++----- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/billing/individual/premium/premium-v2.component.html b/apps/web/src/app/billing/individual/premium/premium-v2.component.html index 7adc93fd962..b5e508ecc7d 100644 --- a/apps/web/src/app/billing/individual/premium/premium-v2.component.html +++ b/apps/web/src/app/billing/individual/premium/premium-v2.component.html @@ -131,7 +131,12 @@

{{ "paymentInformation" | i18n }}

- +
{{ "planPrice" | i18n }}: {{ subtotal | currency: "USD $" }} diff --git a/apps/web/src/app/billing/individual/premium/premium-v2.component.ts b/apps/web/src/app/billing/individual/premium/premium-v2.component.ts index 11b55f92b40..b00490bc49b 100644 --- a/apps/web/src/app/billing/individual/premium/premium-v2.component.ts +++ b/apps/web/src/app/billing/individual/premium/premium-v2.component.ts @@ -1,35 +1,37 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Component, ViewChild } from "@angular/core"; +import { Component, OnInit, ViewChild } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormControl, FormGroup, Validators } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { combineLatest, concatMap, from, Observable, of, switchMap } from "rxjs"; import { debounceTime } from "rxjs/operators"; +import { ManageTaxInformationComponent } from "@bitwarden/angular/billing/components"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; import { TaxServiceAbstraction } from "@bitwarden/common/billing/abstractions/tax.service.abstraction"; +import { TaxInformation } from "@bitwarden/common/billing/models/domain"; import { PreviewIndividualInvoiceRequest } from "@bitwarden/common/billing/models/request/preview-individual-invoice.request"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SyncService } from "@bitwarden/common/platform/sync"; import { ToastService } from "@bitwarden/components"; import { PaymentV2Component } from "../../shared/payment/payment-v2.component"; -import { TaxInfoComponent } from "../../shared/tax-info.component"; @Component({ templateUrl: "./premium-v2.component.html", }) -export class PremiumV2Component { +export class PremiumV2Component implements OnInit { @ViewChild(PaymentV2Component) paymentComponent: PaymentV2Component; - @ViewChild(TaxInfoComponent) taxInfoComponent: TaxInfoComponent; + @ViewChild(ManageTaxInformationComponent) taxInfoComponent: ManageTaxInformationComponent; protected hasPremiumFromAnyOrganization$: Observable; @@ -53,6 +55,8 @@ export class PremiumV2Component { protected readonly premiumPrice = 10; protected readonly storageGBPrice = 4; + protected taxInformation: TaxInformation; + constructor( private activatedRoute: ActivatedRoute, private apiService: ApiService, @@ -67,6 +71,7 @@ export class PremiumV2Component { private tokenService: TokenService, private taxService: TaxServiceAbstraction, private accountService: AccountService, + private logService: LogService, ) { this.isSelfHost = this.platformUtilsService.isSelfHost(); @@ -104,6 +109,15 @@ export class PremiumV2Component { }); } + async ngOnInit(): Promise { + try { + const taxInfo = await this.apiService.getTaxInfo(); + this.taxInformation = TaxInformation.from(taxInfo) || new TaxInformation(); + } catch (e) { + this.logService.error(e); + } + } + finalizeUpgrade = async () => { await this.apiService.refreshIdentityToken(); await this.syncService.fullSync(true); @@ -155,8 +169,7 @@ export class PremiumV2Component { }; submitPayment = async (): Promise => { - this.taxInfoComponent.taxFormGroup.markAllAsTouched(); - if (this.taxInfoComponent.taxFormGroup.invalid) { + if (!this.taxInfoComponent.validate()) { return; } @@ -166,8 +179,14 @@ export class PremiumV2Component { formData.append("paymentMethodType", type.toString()); formData.append("paymentToken", token); formData.append("additionalStorageGb", this.addOnFormGroup.value.additionalStorage.toString()); - formData.append("country", this.taxInfoComponent.country); - formData.append("postalCode", this.taxInfoComponent.postalCode); + + const taxInformation = this.taxInfoComponent.getTaxInformation(); + formData.append("country", taxInformation.country); + formData.append("postalCode", taxInformation.postalCode); + formData.append("line1", taxInformation.line1); + formData.append("line2", taxInformation.line2); + formData.append("city", taxInformation.city); + formData.append("state", taxInformation.state); await this.apiService.postPremium(formData); await this.finalizeUpgrade(); @@ -195,7 +214,7 @@ export class PremiumV2Component { } private refreshSalesTax(): void { - if (!this.taxInfoComponent.country || !this.taxInfoComponent.postalCode) { + if (!this.taxInformation.country || !this.taxInformation.postalCode) { return; } const request: PreviewIndividualInvoiceRequest = { @@ -203,8 +222,8 @@ export class PremiumV2Component { additionalStorage: this.addOnFormGroup.value.additionalStorage, }, taxInformation: { - postalCode: this.taxInfoComponent.postalCode, - country: this.taxInfoComponent.country, + postalCode: this.taxInformation.postalCode, + country: this.taxInformation.country, }, }; @@ -222,7 +241,8 @@ export class PremiumV2Component { }); } - protected onTaxInformationChanged(): void { + protected onTaxInformationChanged(event: TaxInformation): void { + this.taxInformation = event; this.refreshSalesTax(); } }