diff --git a/src/app/settings/organization-plans.component.html b/src/app/settings/organization-plans.component.html index bfafba7c7a..4419910088 100644 --- a/src/app/settings/organization-plans.component.html +++ b/src/app/settings/organization-plans.component.html @@ -206,16 +206,22 @@
-
- {{'total' | i18n}}: {{subtotal | currency:'USD $'}} /{{selectedPlanInterval | i18n}} +

{{ (createOrganization ? 'paymentInformation' : 'billingInformation') | i18n}}

+ + +
+
+ {{ 'planPrice' | i18n }}: {{ subtotal | currency: 'USD $' }} +
+ + {{ 'estimatedTax' | i18n }}: {{ taxCharges | currency: 'USD $' }} + +
+
+

{{'total' | i18n}}: + {{total | currency:'USD $'}}/{{selectedPlanInterval | i18n}}

- - {{'paymentChargedWithTrial' | i18n : (selectedPlanInterval | i18n) }} -

{{'paymentInformation' | i18n}}

- - -
+ {{'paymentChargedWithTrial' | i18n : (selectedPlanInterval | i18n) }} diff --git a/src/app/settings/organization-plans.component.ts b/src/app/settings/organization-plans.component.ts index b8d84f8138..d2ca0f4781 100644 --- a/src/app/settings/organization-plans.component.ts +++ b/src/app/settings/organization-plans.component.ts @@ -159,6 +159,16 @@ export class OrganizationPlansComponent implements OnInit { return subTotal; } + get taxCharges() { + return this.taxComponent != null && this.taxComponent.taxRate != null ? + (this.taxComponent.taxRate / 100) * this.subtotal : + 0; + } + + get total() { + return (this.subtotal + this.taxCharges) || 0; + } + changedProduct() { this.plan = this.selectablePlans[0].type; if (!this.selectedPlan.hasPremiumAccessOption) { @@ -278,6 +288,9 @@ export class OrganizationPlansComponent implements OnInit { request.premiumAccessAddon = this.selectedPlan.hasPremiumAccessOption && this.premiumAccessAddon; request.planType = this.selectedPlan.type; + request.billingAddressCountry = this.taxComponent.taxInfo.country; + request.billingAddressPostalCode = this.taxComponent.taxInfo.postalCode; + const result = await this.apiService.postOrganizationUpgrade(this.organizationId, request); if (!result.success && result.paymentIntentClientSecret != null) { await this.paymentComponent.handleStripeCardPayment(result.paymentIntentClientSecret, null); diff --git a/src/app/settings/tax-info.component.ts b/src/app/settings/tax-info.component.ts index 4a1d8d1bf8..bb7bce1b49 100644 --- a/src/app/settings/tax-info.component.ts +++ b/src/app/settings/tax-info.component.ts @@ -7,6 +7,7 @@ import { ActivatedRoute } from '@angular/router'; import { ApiService } from 'jslib/abstractions/api.service'; import { OrganizationTaxInfoUpdateRequest } from 'jslib/models/request/organizationTaxInfoUpdateRequest'; import { TaxInfoUpdateRequest } from 'jslib/models/request/taxInfoUpdateRequest'; +import { TaxRateResponse } from 'jslib/models/response/taxRateResponse'; @Component({ selector: 'app-tax-info', @@ -28,6 +29,8 @@ export class TaxInfoComponent { includeTaxId: false, }; + taxRates: TaxRateResponse[]; + private pristine: any = { taxId: null, line1: null, @@ -77,9 +80,22 @@ export class TaxInfoComponent { this.onCountryChanged.emit(); } }); + + const taxRates = await this.apiService.getTaxRates(); + this.taxRates = taxRates.data; this.loading = false; } + get taxRate() { + if (this.taxRates != null) { + const localTaxRate = this.taxRates.find(x => + x.country === this.taxInfo.country && + x.postalCode === this.taxInfo.postalCode + ); + return localTaxRate?.rate ?? null; + } + } + getTaxInfoRequest(): TaxInfoUpdateRequest { if (this.organizationId) { const request = new OrganizationTaxInfoUpdateRequest(); diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index b09ec404e7..cb2a07e8b0 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -1662,6 +1662,9 @@ "paymentInformation": { "message": "Payment Information" }, + "billingInformation": { + "message": "Billing Information" + }, "creditCard": { "message": "Credit Card" }, @@ -3355,5 +3358,11 @@ "noSendsInList": { "message": "There are no Sends to list.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "planPrice": { + "message": "Plan price" + }, + "estimatedTax": { + "message": "Estimated tax" } }