Implemented tax collection for subscriptions (#723)

* Implemented tax collection for subscriptions

* Cleanup for Sales Tax

* Code review fixes for Tax Rate implementation

* Code review fixes for Tax Rate implementation
This commit is contained in:
Addison Beck 2020-12-04 12:05:44 -05:00 committed by GitHub
parent 512b9e0a92
commit 7c4d0a15dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 9 deletions

View File

@ -206,16 +206,22 @@
</label>
</div>
<hr class="my-3">
<div class="text-lg">
<strong>{{'total' | i18n}}:</strong> {{subtotal | currency:'USD $'}} /{{selectedPlanInterval | i18n}}
<h2 class="spaced-header mb-4">{{ (createOrganization ? 'paymentInformation' : 'billingInformation') | i18n}}</h2>
<app-payment *ngIf="createOrganization" [hideCredit]="true"></app-payment>
<app-tax-info (onCountryChanged)="changedCountry()"></app-tax-info>
<div id="price" class="my-4">
<div class="text-muted text-sm">
{{ 'planPrice' | i18n }}: {{ subtotal | currency: 'USD $' }}
<br />
<ng-container>
{{ 'estimatedTax' | i18n }}: {{ taxCharges | currency: 'USD $' }}
</ng-container>
</div>
<hr class="my-1 col-3 ml-0">
<p class="text-lg"><strong>{{'total' | i18n}}:</strong>
{{total | currency:'USD $'}}/{{selectedPlanInterval | i18n}}</p>
</div>
<ng-container *ngIf="createOrganization">
<small
class="text-muted font-italic">{{'paymentChargedWithTrial' | i18n : (selectedPlanInterval | i18n) }}</small>
<h2 class="spaced-header mb-4">{{'paymentInformation' | i18n}}</h2>
<app-payment [hideCredit]="true"></app-payment>
<app-tax-info (onCountryChanged)="changedCountry()"></app-tax-info>
</ng-container>
<small class="text-muted font-italic">{{'paymentChargedWithTrial' | i18n : (selectedPlanInterval | i18n) }}</small>
<ng-container *ngIf="!createOrganization">
<app-payment [showMethods]="false"></app-payment>
</ng-container>

View File

@ -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);

View File

@ -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();

View File

@ -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"
}
}