1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-26 17:08:33 +01:00

Collect tax info for payments

This commit is contained in:
Chad Scharf 2020-06-12 19:33:29 -04:00
parent b1c098614c
commit 4bdb9c8632
15 changed files with 495 additions and 641 deletions

View File

@ -115,6 +115,7 @@ import { PremiumComponent } from './settings/premium.component';
import { ProfileComponent } from './settings/profile.component'; import { ProfileComponent } from './settings/profile.component';
import { PurgeVaultComponent } from './settings/purge-vault.component'; import { PurgeVaultComponent } from './settings/purge-vault.component';
import { SettingsComponent } from './settings/settings.component'; import { SettingsComponent } from './settings/settings.component';
import { TaxInfoComponent } from './settings/tax-info.component';
import { TwoFactorAuthenticatorComponent } from './settings/two-factor-authenticator.component'; import { TwoFactorAuthenticatorComponent } from './settings/two-factor-authenticator.component';
import { TwoFactorDuoComponent } from './settings/two-factor-duo.component'; import { TwoFactorDuoComponent } from './settings/two-factor-duo.component';
import { TwoFactorEmailComponent } from './settings/two-factor-email.component'; import { TwoFactorEmailComponent } from './settings/two-factor-email.component';
@ -350,6 +351,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
ShareComponent, ShareComponent,
StopClickDirective, StopClickDirective,
StopPropDirective, StopPropDirective,
TaxInfoComponent,
ToolsComponent, ToolsComponent,
TrueFalseValueDirective, TrueFalseValueDirective,
TwoFactorAuthenticatorComponent, TwoFactorAuthenticatorComponent,

View File

@ -49,321 +49,9 @@
<h1>{{'taxInformation' | i18n}}</h1> <h1>{{'taxInformation' | i18n}}</h1>
</div> </div>
<p>{{'taxInformationDesc' | i18n}}</p> <p>{{'taxInformationDesc' | i18n}}</p>
<form *ngIf="org && !loading" #form (ngSubmit)="submitTaxInfo()" [appApiAction]="formPromise" ngNativeValidate> <form *ngIf="org && !loading" #formTax (ngSubmit)="submitTaxInfo()" [appApiAction]="formPromise" ngNativeValidate>
<div class="row"> <app-tax-info></app-tax-info>
<div class="col-6"> <button type="submit" class="btn btn-primary btn-submit" [disabled]="formTax.loading">
<div class="form-group">
<label for="addressCountry">{{'country' | i18n}}</label>
<select id="addressCountry" class="form-control" [(ngModel)]="taxInfo.country" required name="addressCountry"
autocomplete="country" (change)="changeCountry()">
<option value="">-- Select --</option>
<option value="US">United States</option>
<option value="CN">China</option>
<option value="FR">France</option>
<option value="DE">Germany</option>
<option value="CA">Canada</option>
<option value="GB">United Kingdom</option>
<option value="AU">Australia</option>
<option value="IN">India</option>
<option value="-" disabled></option>
<option value="AF">Afghanistan</option>
<option value="AX">Åland Islands</option>
<option value="AL">Albania</option>
<option value="DZ">Algeria</option>
<option value="AS">American Samoa</option>
<option value="AD">Andorra</option>
<option value="AO">Angola</option>
<option value="AI">Anguilla</option>
<option value="AQ">Antarctica</option>
<option value="AG">Antigua and Barbuda</option>
<option value="AR">Argentina</option>
<option value="AM">Armenia</option>
<option value="AW">Aruba</option>
<option value="AT">Austria</option>
<option value="AZ">Azerbaijan</option>
<option value="BS">Bahamas</option>
<option value="BH">Bahrain</option>
<option value="BD">Bangladesh</option>
<option value="BB">Barbados</option>
<option value="BY">Belarus</option>
<option value="BE">Belgium</option>
<option value="BZ">Belize</option>
<option value="BJ">Benin</option>
<option value="BM">Bermuda</option>
<option value="BT">Bhutan</option>
<option value="BO">Bolivia, Plurinational State of</option>
<option value="BQ">Bonaire, Sint Eustatius and Saba</option>
<option value="BA">Bosnia and Herzegovina</option>
<option value="BW">Botswana</option>
<option value="BV">Bouvet Island</option>
<option value="BR">Brazil</option>
<option value="IO">British Indian Ocean Territory</option>
<option value="BN">Brunei Darussalam</option>
<option value="BG">Bulgaria</option>
<option value="BF">Burkina Faso</option>
<option value="BI">Burundi</option>
<option value="KH">Cambodia</option>
<option value="CM">Cameroon</option>
<option value="CV">Cape Verde</option>
<option value="KY">Cayman Islands</option>
<option value="CF">Central African Republic</option>
<option value="TD">Chad</option>
<option value="CL">Chile</option>
<option value="CX">Christmas Island</option>
<option value="CC">Cocos (Keeling) Islands</option>
<option value="CO">Colombia</option>
<option value="KM">Comoros</option>
<option value="CG">Congo</option>
<option value="CD">Congo, the Democratic Republic of the</option>
<option value="CK">Cook Islands</option>
<option value="CR">Costa Rica</option>
<option value="CI">Côte d'Ivoire</option>
<option value="HR">Croatia</option>
<option value="CU">Cuba</option>
<option value="CW">Curaçao</option>
<option value="CY">Cyprus</option>
<option value="CZ">Czech Republic</option>
<option value="DK">Denmark</option>
<option value="DJ">Djibouti</option>
<option value="DM">Dominica</option>
<option value="DO">Dominican Republic</option>
<option value="EC">Ecuador</option>
<option value="EG">Egypt</option>
<option value="SV">El Salvador</option>
<option value="GQ">Equatorial Guinea</option>
<option value="ER">Eritrea</option>
<option value="EE">Estonia</option>
<option value="ET">Ethiopia</option>
<option value="FK">Falkland Islands (Malvinas)</option>
<option value="FO">Faroe Islands</option>
<option value="FJ">Fiji</option>
<option value="FI">Finland</option>
<option value="GF">French Guiana</option>
<option value="PF">French Polynesia</option>
<option value="TF">French Southern Territories</option>
<option value="GA">Gabon</option>
<option value="GM">Gambia</option>
<option value="GE">Georgia</option>
<option value="GH">Ghana</option>
<option value="GI">Gibraltar</option>
<option value="GR">Greece</option>
<option value="GL">Greenland</option>
<option value="GD">Grenada</option>
<option value="GP">Guadeloupe</option>
<option value="GU">Guam</option>
<option value="GT">Guatemala</option>
<option value="GG">Guernsey</option>
<option value="GN">Guinea</option>
<option value="GW">Guinea-Bissau</option>
<option value="GY">Guyana</option>
<option value="HT">Haiti</option>
<option value="HM">Heard Island and McDonald Islands</option>
<option value="VA">Holy See (Vatican City State)</option>
<option value="HN">Honduras</option>
<option value="HK">Hong Kong</option>
<option value="HU">Hungary</option>
<option value="IS">Iceland</option>
<option value="ID">Indonesia</option>
<option value="IR">Iran, Islamic Republic of</option>
<option value="IQ">Iraq</option>
<option value="IE">Ireland</option>
<option value="IM">Isle of Man</option>
<option value="IL">Israel</option>
<option value="IT">Italy</option>
<option value="JM">Jamaica</option>
<option value="JP">Japan</option>
<option value="JE">Jersey</option>
<option value="JO">Jordan</option>
<option value="KZ">Kazakhstan</option>
<option value="KE">Kenya</option>
<option value="KI">Kiribati</option>
<option value="KP">Korea, Democratic People's Republic of</option>
<option value="KR">Korea, Republic of</option>
<option value="KW">Kuwait</option>
<option value="KG">Kyrgyzstan</option>
<option value="LA">Lao People's Democratic Republic</option>
<option value="LV">Latvia</option>
<option value="LB">Lebanon</option>
<option value="LS">Lesotho</option>
<option value="LR">Liberia</option>
<option value="LY">Libya</option>
<option value="LI">Liechtenstein</option>
<option value="LT">Lithuania</option>
<option value="LU">Luxembourg</option>
<option value="MO">Macao</option>
<option value="MK">Macedonia, the former Yugoslav Republic of</option>
<option value="MG">Madagascar</option>
<option value="MW">Malawi</option>
<option value="MY">Malaysia</option>
<option value="MV">Maldives</option>
<option value="ML">Mali</option>
<option value="MT">Malta</option>
<option value="MH">Marshall Islands</option>
<option value="MQ">Martinique</option>
<option value="MR">Mauritania</option>
<option value="MU">Mauritius</option>
<option value="YT">Mayotte</option>
<option value="MX">Mexico</option>
<option value="FM">Micronesia, Federated States of</option>
<option value="MD">Moldova, Republic of</option>
<option value="MC">Monaco</option>
<option value="MN">Mongolia</option>
<option value="ME">Montenegro</option>
<option value="MS">Montserrat</option>
<option value="MA">Morocco</option>
<option value="MZ">Mozambique</option>
<option value="MM">Myanmar</option>
<option value="NA">Namibia</option>
<option value="NR">Nauru</option>
<option value="NP">Nepal</option>
<option value="NL">Netherlands</option>
<option value="NC">New Caledonia</option>
<option value="NZ">New Zealand</option>
<option value="NI">Nicaragua</option>
<option value="NE">Niger</option>
<option value="NG">Nigeria</option>
<option value="NU">Niue</option>
<option value="NF">Norfolk Island</option>
<option value="MP">Northern Mariana Islands</option>
<option value="NO">Norway</option>
<option value="OM">Oman</option>
<option value="PK">Pakistan</option>
<option value="PW">Palau</option>
<option value="PS">Palestinian Territory, Occupied</option>
<option value="PA">Panama</option>
<option value="PG">Papua New Guinea</option>
<option value="PY">Paraguay</option>
<option value="PE">Peru</option>
<option value="PH">Philippines</option>
<option value="PN">Pitcairn</option>
<option value="PL">Poland</option>
<option value="PT">Portugal</option>
<option value="PR">Puerto Rico</option>
<option value="QA">Qatar</option>
<option value="RE">Réunion</option>
<option value="RO">Romania</option>
<option value="RU">Russian Federation</option>
<option value="RW">Rwanda</option>
<option value="BL">Saint Barthélemy</option>
<option value="SH">Saint Helena, Ascension and Tristan da Cunha</option>
<option value="KN">Saint Kitts and Nevis</option>
<option value="LC">Saint Lucia</option>
<option value="MF">Saint Martin (French part)</option>
<option value="PM">Saint Pierre and Miquelon</option>
<option value="VC">Saint Vincent and the Grenadines</option>
<option value="WS">Samoa</option>
<option value="SM">San Marino</option>
<option value="ST">Sao Tome and Principe</option>
<option value="SA">Saudi Arabia</option>
<option value="SN">Senegal</option>
<option value="RS">Serbia</option>
<option value="SC">Seychelles</option>
<option value="SL">Sierra Leone</option>
<option value="SG">Singapore</option>
<option value="SX">Sint Maarten (Dutch part)</option>
<option value="SK">Slovakia</option>
<option value="SI">Slovenia</option>
<option value="SB">Solomon Islands</option>
<option value="SO">Somalia</option>
<option value="ZA">South Africa</option>
<option value="GS">South Georgia and the South Sandwich Islands</option>
<option value="SS">South Sudan</option>
<option value="ES">Spain</option>
<option value="LK">Sri Lanka</option>
<option value="SD">Sudan</option>
<option value="SR">Suriname</option>
<option value="SJ">Svalbard and Jan Mayen</option>
<option value="SZ">Swaziland</option>
<option value="SE">Sweden</option>
<option value="CH">Switzerland</option>
<option value="SY">Syrian Arab Republic</option>
<option value="TW">Taiwan, Province of China</option>
<option value="TJ">Tajikistan</option>
<option value="TZ">Tanzania, United Republic of</option>
<option value="TH">Thailand</option>
<option value="TL">Timor-Leste</option>
<option value="TG">Togo</option>
<option value="TK">Tokelau</option>
<option value="TO">Tonga</option>
<option value="TT">Trinidad and Tobago</option>
<option value="TN">Tunisia</option>
<option value="TR">Turkey</option>
<option value="TM">Turkmenistan</option>
<option value="TC">Turks and Caicos Islands</option>
<option value="TV">Tuvalu</option>
<option value="UG">Uganda</option>
<option value="UA">Ukraine</option>
<option value="AE">United Arab Emirates</option>
<option value="UM">United States Minor Outlying Islands</option>
<option value="UY">Uruguay</option>
<option value="UZ">Uzbekistan</option>
<option value="VU">Vanuatu</option>
<option value="VE">Venezuela, Bolivarian Republic of</option>
<option value="VN">Viet Nam</option>
<option value="VG">Virgin Islands, British</option>
<option value="VI">Virgin Islands, U.S.</option>
<option value="WF">Wallis and Futuna</option>
<option value="EH">Western Sahara</option>
<option value="YE">Yemen</option>
<option value="ZM">Zambia</option>
<option value="ZW">Zimbabwe</option>
</select>
</div>
</div>
<div class="col-3">
<div class="form-group">
<label for="addressPostalCode">{{'zipPostalCode' | i18n}}</label>
<input id="addressPostalCode" class="form-control" type="text" name="addressPostalCode"
[(ngModel)]="taxInfo.postalCode" [required]="taxInfo.country === 'US'" autocomplete="postal-code">
</div>
</div>
<div class="col-6" *ngIf="taxInfo.country !== 'US'">
<div class="form-group form-check">
<input class="form-check-input" id="addressIncludeTaxId" name="addressIncludeTaxId" type="checkbox"
[(ngModel)]="taxInfo.includeTaxId">
<label class="form-check-label" for="addressIncludeTaxId">{{'includeVAT' | i18n}}</label>
</div>
</div>
</div>
<div class="row" *ngIf="taxInfo.includeTaxId">
<div class="col-6">
<div class="form-group">
<label for="taxId">{{'taxIdNumber' | i18n}}</label>
<input id="taxId" class="form-control" type="text" name="taxId" [(ngModel)]="taxInfo.taxId">
</div>
</div>
</div>
<div class="row" *ngIf="taxInfo.includeTaxId">
<div class="col-6">
<div class="form-group">
<label for="addressLine1">{{'address1' | i18n}}</label>
<input id="addressLine1" class="form-control" type="text" name="addressLine1"
[(ngModel)]="taxInfo.line1" autocomplete="address-line1">
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="addressLine2">{{'address2' | i18n}}</label>
<input id="addressLine2" class="form-control" type="text" name="addressLine2"
[(ngModel)]="taxInfo.line2" autocomplete="address-line2">
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="addressCity">{{'cityTown' | i18n}}</label>
<input id="addressCity" class="form-control" type="text" name="addressCity"
[(ngModel)]="taxInfo.city" autocomplete="address-level2">
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="addressState">{{'stateProvince' | i18n}}</label>
<input id="addressState" class="form-control" type="text" name="addressState"
[(ngModel)]="taxInfo.state" autocomplete="address-level1">
</div>
</div>
</div>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i> <i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span>{{'save' | i18n}}</span> <span>{{'save' | i18n}}</span>
</button> </button>

View File

@ -18,10 +18,10 @@ import { OrganizationResponse } from 'jslib/models/response/organizationResponse
import { ModalComponent } from '../../modal.component'; import { ModalComponent } from '../../modal.component';
import { PurgeVaultComponent } from '../../settings/purge-vault.component'; import { PurgeVaultComponent } from '../../settings/purge-vault.component';
import { TaxInfoComponent } from '../../settings/tax-info.component';
import { ApiKeyComponent } from './api-key.component'; import { ApiKeyComponent } from './api-key.component';
import { DeleteOrganizationComponent } from './delete-organization.component'; import { DeleteOrganizationComponent } from './delete-organization.component';
import { RotateApiKeyComponent } from './rotate-api-key.component'; import { RotateApiKeyComponent } from './rotate-api-key.component';
import { OrganizationTaxInfoUpdateRequest } from 'jslib/models/request/organizationTaxInfoUpdateRequest';
@Component({ @Component({
selector: 'app-org-account', selector: 'app-org-account',
@ -32,21 +32,12 @@ export class AccountComponent {
@ViewChild('purgeOrganizationTemplate', { read: ViewContainerRef }) purgeModalRef: ViewContainerRef; @ViewChild('purgeOrganizationTemplate', { read: ViewContainerRef }) purgeModalRef: ViewContainerRef;
@ViewChild('apiKeyTemplate', { read: ViewContainerRef }) apiKeyModalRef: ViewContainerRef; @ViewChild('apiKeyTemplate', { read: ViewContainerRef }) apiKeyModalRef: ViewContainerRef;
@ViewChild('rotateApiKeyTemplate', { read: ViewContainerRef }) rotateApiKeyModalRef: ViewContainerRef; @ViewChild('rotateApiKeyTemplate', { read: ViewContainerRef }) rotateApiKeyModalRef: ViewContainerRef;
@ViewChild(TaxInfoComponent) taxInfo: TaxInfoComponent;
loading = true; loading = true;
canUseApi = false; canUseApi = false;
org: OrganizationResponse; org: OrganizationResponse;
formPromise: Promise<any>; formPromise: Promise<any>;
taxInfo: any = {
taxId: null,
line1: null,
line2: null,
city: null,
state: null,
postalCode: null,
country: 'US',
includeTaxId: false,
};
private organizationId: string; private organizationId: string;
private modal: ModalComponent = null; private modal: ModalComponent = null;
@ -62,23 +53,6 @@ export class AccountComponent {
try { try {
this.org = await this.apiService.getOrganization(this.organizationId); this.org = await this.apiService.getOrganization(this.organizationId);
this.canUseApi = this.org.useApi; this.canUseApi = this.org.useApi;
const taxInfo = await this.apiService.getOrganizationTaxInfo(this.organizationId);
if (taxInfo) {
this.taxInfo.taxId = taxInfo.taxId;
this.taxInfo.state = taxInfo.state;
this.taxInfo.line1 = taxInfo.line1;
this.taxInfo.line2 = taxInfo.line2;
this.taxInfo.city = taxInfo.city;
this.taxInfo.state = taxInfo.state;
this.taxInfo.postalCode = taxInfo.postalCode;
this.taxInfo.country = taxInfo.country;
this.taxInfo.includeTaxId = taxInfo.country !== 'US' && (
!!taxInfo.taxId
|| !!taxInfo.line1
|| !!taxInfo.line2
|| !!taxInfo.city
|| !!taxInfo.state);
}
} catch { } } catch { }
}); });
this.loading = false; this.loading = false;
@ -100,16 +74,7 @@ export class AccountComponent {
} }
async submitTaxInfo() { async submitTaxInfo() {
const request = new OrganizationTaxInfoUpdateRequest(); this.formPromise = this.taxInfo.submitTaxInfo();
request.taxId = this.taxInfo.taxId;
request.state = this.taxInfo.state;
request.line1 = this.taxInfo.line1;
request.line2 = this.taxInfo.line2;
request.city = this.taxInfo.city;
request.state = this.taxInfo.state;
request.postalCode = this.taxInfo.postalCode;
request.country = this.taxInfo.country;
this.formPromise = this.apiService.putOrganizationTaxInfo(this.organizationId, request);
await this.formPromise; await this.formPromise;
this.analytics.eventTrack.next({ action: 'Updated Organization Tax Info' }); this.analytics.eventTrack.next({ action: 'Updated Organization Tax Info' });
this.toasterService.popAsync('success', null, this.i18nService.t('taxInfoUpdated')); this.toasterService.popAsync('success', null, this.i18nService.t('taxInfoUpdated'));
@ -175,15 +140,4 @@ export class AccountComponent {
this.modal = null; this.modal = null;
}); });
} }
changeCountry() {
if (this.taxInfo.country === 'US') {
this.taxInfo.includeTaxId = false;
this.taxInfo.taxId = null;
this.taxInfo.line1 = null;
this.taxInfo.line2 = null;
this.taxInfo.city = null;
this.taxInfo.state = null;
}
}
} }

View File

@ -145,9 +145,9 @@ export function initFactory(): Function {
} }
apiService.setUrls({ apiService.setUrls({
base: isDev ? null : window.location.origin, base: isDev ? null : window.location.origin,
api: isDev ? 'http://localhost:7064' : null, api: isDev ? 'http://localhost:5000' : null,
identity: isDev ? 'http://localhost:5000' : null, identity: isDev ? 'http://localhost:33657' : null,
events: isDev ? 'http://localhost:46273' : null, events: isDev ? 'http://localhost:46274' : null,
// Uncomment these (and comment out the above) if you want to target production // Uncomment these (and comment out the above) if you want to target production
// servers for local development. // servers for local development.

View File

@ -30,6 +30,7 @@
</div> </div>
<small class="form-text text-muted">{{'creditDelayed' | i18n}}</small> <small class="form-text text-muted">{{'creditDelayed' | i18n}}</small>
</div> </div>
<app-tax-info></app-tax-info>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading || ppLoading"> <button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading || ppLoading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i> <i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span>{{'submit' | i18n}}</span> <span>{{'submit' | i18n}}</span>

View File

@ -21,6 +21,8 @@ import { BitPayInvoiceRequest } from 'jslib/models/request/bitPayInvoiceRequest'
import { WebConstants } from '../../services/webConstants'; import { WebConstants } from '../../services/webConstants';
import { TaxInfoComponent } from './tax-info.component';
@Component({ @Component({
selector: 'app-add-credit', selector: 'app-add-credit',
templateUrl: 'add-credit.component.html', templateUrl: 'add-credit.component.html',
@ -34,6 +36,7 @@ export class AddCreditComponent implements OnInit {
@Output() onCanceled = new EventEmitter(); @Output() onCanceled = new EventEmitter();
@ViewChild('ppButtonForm', { read: ElementRef }) ppButtonFormRef: ElementRef; @ViewChild('ppButtonForm', { read: ElementRef }) ppButtonFormRef: ElementRef;
@ViewChild(TaxInfoComponent) taxInfoComponent: TaxInfoComponent;
paymentMethodType = PaymentMethodType; paymentMethodType = PaymentMethodType;
ppButtonFormAction = WebConstants.paypal.buttonActionProduction; ppButtonFormAction = WebConstants.paypal.buttonActionProduction;
@ -86,6 +89,7 @@ export class AddCreditComponent implements OnInit {
return; return;
} }
await this.taxInfoComponent.submitTaxInfo();
if (this.method === PaymentMethodType.PayPal) { if (this.method === PaymentMethodType.PayPal) {
this.ppButtonFormRef.nativeElement.submit(); this.ppButtonFormRef.nativeElement.submit();
this.ppLoading = true; this.ppLoading = true;

View File

@ -4,271 +4,7 @@
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<h3 class="card-body-header">{{(currentType != null ? 'changePaymentMethod' : 'addPaymentMethod') | i18n}}</h3> <h3 class="card-body-header">{{(currentType != null ? 'changePaymentMethod' : 'addPaymentMethod') | i18n}}</h3>
<app-payment [hideBank]="!organizationId" [hideCredit]="true"></app-payment> <app-payment [hideBank]="!organizationId" [hideCredit]="true"></app-payment>
<div class="row mb-3"> <app-tax-info (onCountryChanged)="changeCountry()"></app-tax-info>
<div class="form-group col-5">
<label for="address_country">{{'country' | i18n}}</label>
<select id="address_country" class="form-control" [(ngModel)]="address.country" required name="address_country"
autocomplete="country" (change)="changeCountry()">
<option value="">-- Select --</option>
<option value="US">United States</option>
<option value="CN">China</option>
<option value="FR">France</option>
<option value="DE">Germany</option>
<option value="CA">Canada</option>
<option value="GB">United Kingdom</option>
<option value="AU">Australia</option>
<option value="IN">India</option>
<option value="-" disabled></option>
<option value="AF">Afghanistan</option>
<option value="AX">Åland Islands</option>
<option value="AL">Albania</option>
<option value="DZ">Algeria</option>
<option value="AS">American Samoa</option>
<option value="AD">Andorra</option>
<option value="AO">Angola</option>
<option value="AI">Anguilla</option>
<option value="AQ">Antarctica</option>
<option value="AG">Antigua and Barbuda</option>
<option value="AR">Argentina</option>
<option value="AM">Armenia</option>
<option value="AW">Aruba</option>
<option value="AT">Austria</option>
<option value="AZ">Azerbaijan</option>
<option value="BS">Bahamas</option>
<option value="BH">Bahrain</option>
<option value="BD">Bangladesh</option>
<option value="BB">Barbados</option>
<option value="BY">Belarus</option>
<option value="BE">Belgium</option>
<option value="BZ">Belize</option>
<option value="BJ">Benin</option>
<option value="BM">Bermuda</option>
<option value="BT">Bhutan</option>
<option value="BO">Bolivia, Plurinational State of</option>
<option value="BQ">Bonaire, Sint Eustatius and Saba</option>
<option value="BA">Bosnia and Herzegovina</option>
<option value="BW">Botswana</option>
<option value="BV">Bouvet Island</option>
<option value="BR">Brazil</option>
<option value="IO">British Indian Ocean Territory</option>
<option value="BN">Brunei Darussalam</option>
<option value="BG">Bulgaria</option>
<option value="BF">Burkina Faso</option>
<option value="BI">Burundi</option>
<option value="KH">Cambodia</option>
<option value="CM">Cameroon</option>
<option value="CV">Cape Verde</option>
<option value="KY">Cayman Islands</option>
<option value="CF">Central African Republic</option>
<option value="TD">Chad</option>
<option value="CL">Chile</option>
<option value="CX">Christmas Island</option>
<option value="CC">Cocos (Keeling) Islands</option>
<option value="CO">Colombia</option>
<option value="KM">Comoros</option>
<option value="CG">Congo</option>
<option value="CD">Congo, the Democratic Republic of the</option>
<option value="CK">Cook Islands</option>
<option value="CR">Costa Rica</option>
<option value="CI">Côte d'Ivoire</option>
<option value="HR">Croatia</option>
<option value="CU">Cuba</option>
<option value="CW">Curaçao</option>
<option value="CY">Cyprus</option>
<option value="CZ">Czech Republic</option>
<option value="DK">Denmark</option>
<option value="DJ">Djibouti</option>
<option value="DM">Dominica</option>
<option value="DO">Dominican Republic</option>
<option value="EC">Ecuador</option>
<option value="EG">Egypt</option>
<option value="SV">El Salvador</option>
<option value="GQ">Equatorial Guinea</option>
<option value="ER">Eritrea</option>
<option value="EE">Estonia</option>
<option value="ET">Ethiopia</option>
<option value="FK">Falkland Islands (Malvinas)</option>
<option value="FO">Faroe Islands</option>
<option value="FJ">Fiji</option>
<option value="FI">Finland</option>
<option value="GF">French Guiana</option>
<option value="PF">French Polynesia</option>
<option value="TF">French Southern Territories</option>
<option value="GA">Gabon</option>
<option value="GM">Gambia</option>
<option value="GE">Georgia</option>
<option value="GH">Ghana</option>
<option value="GI">Gibraltar</option>
<option value="GR">Greece</option>
<option value="GL">Greenland</option>
<option value="GD">Grenada</option>
<option value="GP">Guadeloupe</option>
<option value="GU">Guam</option>
<option value="GT">Guatemala</option>
<option value="GG">Guernsey</option>
<option value="GN">Guinea</option>
<option value="GW">Guinea-Bissau</option>
<option value="GY">Guyana</option>
<option value="HT">Haiti</option>
<option value="HM">Heard Island and McDonald Islands</option>
<option value="VA">Holy See (Vatican City State)</option>
<option value="HN">Honduras</option>
<option value="HK">Hong Kong</option>
<option value="HU">Hungary</option>
<option value="IS">Iceland</option>
<option value="ID">Indonesia</option>
<option value="IR">Iran, Islamic Republic of</option>
<option value="IQ">Iraq</option>
<option value="IE">Ireland</option>
<option value="IM">Isle of Man</option>
<option value="IL">Israel</option>
<option value="IT">Italy</option>
<option value="JM">Jamaica</option>
<option value="JP">Japan</option>
<option value="JE">Jersey</option>
<option value="JO">Jordan</option>
<option value="KZ">Kazakhstan</option>
<option value="KE">Kenya</option>
<option value="KI">Kiribati</option>
<option value="KP">Korea, Democratic People's Republic of</option>
<option value="KR">Korea, Republic of</option>
<option value="KW">Kuwait</option>
<option value="KG">Kyrgyzstan</option>
<option value="LA">Lao People's Democratic Republic</option>
<option value="LV">Latvia</option>
<option value="LB">Lebanon</option>
<option value="LS">Lesotho</option>
<option value="LR">Liberia</option>
<option value="LY">Libya</option>
<option value="LI">Liechtenstein</option>
<option value="LT">Lithuania</option>
<option value="LU">Luxembourg</option>
<option value="MO">Macao</option>
<option value="MK">Macedonia, the former Yugoslav Republic of</option>
<option value="MG">Madagascar</option>
<option value="MW">Malawi</option>
<option value="MY">Malaysia</option>
<option value="MV">Maldives</option>
<option value="ML">Mali</option>
<option value="MT">Malta</option>
<option value="MH">Marshall Islands</option>
<option value="MQ">Martinique</option>
<option value="MR">Mauritania</option>
<option value="MU">Mauritius</option>
<option value="YT">Mayotte</option>
<option value="MX">Mexico</option>
<option value="FM">Micronesia, Federated States of</option>
<option value="MD">Moldova, Republic of</option>
<option value="MC">Monaco</option>
<option value="MN">Mongolia</option>
<option value="ME">Montenegro</option>
<option value="MS">Montserrat</option>
<option value="MA">Morocco</option>
<option value="MZ">Mozambique</option>
<option value="MM">Myanmar</option>
<option value="NA">Namibia</option>
<option value="NR">Nauru</option>
<option value="NP">Nepal</option>
<option value="NL">Netherlands</option>
<option value="NC">New Caledonia</option>
<option value="NZ">New Zealand</option>
<option value="NI">Nicaragua</option>
<option value="NE">Niger</option>
<option value="NG">Nigeria</option>
<option value="NU">Niue</option>
<option value="NF">Norfolk Island</option>
<option value="MP">Northern Mariana Islands</option>
<option value="NO">Norway</option>
<option value="OM">Oman</option>
<option value="PK">Pakistan</option>
<option value="PW">Palau</option>
<option value="PS">Palestinian Territory, Occupied</option>
<option value="PA">Panama</option>
<option value="PG">Papua New Guinea</option>
<option value="PY">Paraguay</option>
<option value="PE">Peru</option>
<option value="PH">Philippines</option>
<option value="PN">Pitcairn</option>
<option value="PL">Poland</option>
<option value="PT">Portugal</option>
<option value="PR">Puerto Rico</option>
<option value="QA">Qatar</option>
<option value="RE">Réunion</option>
<option value="RO">Romania</option>
<option value="RU">Russian Federation</option>
<option value="RW">Rwanda</option>
<option value="BL">Saint Barthélemy</option>
<option value="SH">Saint Helena, Ascension and Tristan da Cunha</option>
<option value="KN">Saint Kitts and Nevis</option>
<option value="LC">Saint Lucia</option>
<option value="MF">Saint Martin (French part)</option>
<option value="PM">Saint Pierre and Miquelon</option>
<option value="VC">Saint Vincent and the Grenadines</option>
<option value="WS">Samoa</option>
<option value="SM">San Marino</option>
<option value="ST">Sao Tome and Principe</option>
<option value="SA">Saudi Arabia</option>
<option value="SN">Senegal</option>
<option value="RS">Serbia</option>
<option value="SC">Seychelles</option>
<option value="SL">Sierra Leone</option>
<option value="SG">Singapore</option>
<option value="SX">Sint Maarten (Dutch part)</option>
<option value="SK">Slovakia</option>
<option value="SI">Slovenia</option>
<option value="SB">Solomon Islands</option>
<option value="SO">Somalia</option>
<option value="ZA">South Africa</option>
<option value="GS">South Georgia and the South Sandwich Islands</option>
<option value="SS">South Sudan</option>
<option value="ES">Spain</option>
<option value="LK">Sri Lanka</option>
<option value="SD">Sudan</option>
<option value="SR">Suriname</option>
<option value="SJ">Svalbard and Jan Mayen</option>
<option value="SZ">Swaziland</option>
<option value="SE">Sweden</option>
<option value="CH">Switzerland</option>
<option value="SY">Syrian Arab Republic</option>
<option value="TW">Taiwan, Province of China</option>
<option value="TJ">Tajikistan</option>
<option value="TZ">Tanzania, United Republic of</option>
<option value="TH">Thailand</option>
<option value="TL">Timor-Leste</option>
<option value="TG">Togo</option>
<option value="TK">Tokelau</option>
<option value="TO">Tonga</option>
<option value="TT">Trinidad and Tobago</option>
<option value="TN">Tunisia</option>
<option value="TR">Turkey</option>
<option value="TM">Turkmenistan</option>
<option value="TC">Turks and Caicos Islands</option>
<option value="TV">Tuvalu</option>
<option value="UG">Uganda</option>
<option value="UA">Ukraine</option>
<option value="AE">United Arab Emirates</option>
<option value="UM">United States Minor Outlying Islands</option>
<option value="UY">Uruguay</option>
<option value="UZ">Uzbekistan</option>
<option value="VU">Vanuatu</option>
<option value="VE">Venezuela, Bolivarian Republic of</option>
<option value="VN">Viet Nam</option>
<option value="VG">Virgin Islands, British</option>
<option value="VI">Virgin Islands, U.S.</option>
<option value="WF">Wallis and Futuna</option>
<option value="EH">Western Sahara</option>
<option value="YE">Yemen</option>
<option value="ZM">Zambia</option>
<option value="ZW">Zimbabwe</option>
</select>
<small class="text-muted form-text">{{'countryPostalCodeRequiredDesc' | i18n}}</small>
</div>
<div class="form-group col-3">
<label for="address_postal_code">{{'zipPostalCode' | i18n}}</label>
<input id="address_postal_code" class="form-control" type="text" name="address_postal_code"
[(ngModel)]="address.postal_code" [required]="address.country === 'US'" autocomplete="postal-code">
</div>
</div>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading"> <button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i> <i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span>{{'submit' | i18n}}</span> <span>{{'submit' | i18n}}</span>

View File

@ -17,6 +17,7 @@ import { PaymentRequest } from 'jslib/models/request/paymentRequest';
import { PaymentMethodType } from 'jslib/enums/paymentMethodType'; import { PaymentMethodType } from 'jslib/enums/paymentMethodType';
import { PaymentComponent } from './payment.component'; import { PaymentComponent } from './payment.component';
import { TaxInfoComponent } from './tax-info.component';
@Component({ @Component({
selector: 'app-adjust-payment', selector: 'app-adjust-payment',
@ -24,6 +25,7 @@ import { PaymentComponent } from './payment.component';
}) })
export class AdjustPaymentComponent { export class AdjustPaymentComponent {
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent; @ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
@ViewChild(TaxInfoComponent) taxInfoComponent: TaxInfoComponent;
@Input() currentType?: PaymentMethodType; @Input() currentType?: PaymentMethodType;
@Input() organizationId: string; @Input() organizationId: string;
@ -33,17 +35,13 @@ export class AdjustPaymentComponent {
paymentMethodType = PaymentMethodType; paymentMethodType = PaymentMethodType;
formPromise: Promise<any>; formPromise: Promise<any>;
address: any = {
country: 'US',
postal_code: null,
};
constructor(private apiService: ApiService, private i18nService: I18nService, constructor(private apiService: ApiService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService) { } private analytics: Angulartics2, private toasterService: ToasterService) { }
async submit() { async submit() {
try { try {
const request = new PaymentRequest(); const request = new PaymentRequest();
await this.taxInfoComponent.submitTaxInfo();
this.formPromise = this.paymentComponent.createPaymentToken().then((result) => { this.formPromise = this.paymentComponent.createPaymentToken().then((result) => {
request.paymentToken = result[0]; request.paymentToken = result[0];
request.paymentMethodType = result[1]; request.paymentMethodType = result[1];
@ -67,7 +65,7 @@ export class AdjustPaymentComponent {
} }
changeCountry() { changeCountry() {
if (this.address.country === 'US') { if (this.taxInfoComponent.taxInfo.country === 'US') {
this.paymentComponent.hideBank = !this.organizationId; this.paymentComponent.hideBank = !this.organizationId;
} else { } else {
this.paymentComponent.hideBank = true; this.paymentComponent.hideBank = true;

View File

@ -202,6 +202,7 @@
<small class="text-muted font-italic">{{'paymentChargedWithTrial' | i18n : (interval | i18n) }}</small> <small class="text-muted font-italic">{{'paymentChargedWithTrial' | i18n : (interval | i18n) }}</small>
<h2 class="spaced-header mb-4">{{'paymentInformation' | i18n}}</h2> <h2 class="spaced-header mb-4">{{'paymentInformation' | i18n}}</h2>
<app-payment [hideCredit]="true"></app-payment> <app-payment [hideCredit]="true"></app-payment>
<app-tax-info (onCountryChanged)="changedCountry()"></app-tax-info>
</ng-container> </ng-container>
<ng-container *ngIf="!createOrganization"> <ng-container *ngIf="!createOrganization">
<app-payment [showMethods]="false"></app-payment> <app-payment [showMethods]="false"></app-payment>

View File

@ -19,6 +19,7 @@ import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SyncService } from 'jslib/abstractions/sync.service'; import { SyncService } from 'jslib/abstractions/sync.service';
import { PaymentComponent } from './payment.component'; import { PaymentComponent } from './payment.component';
import { TaxInfoComponent } from './tax-info.component';
import { PlanType } from 'jslib/enums/planType'; import { PlanType } from 'jslib/enums/planType';
import { OrganizationCreateRequest } from 'jslib/models/request/organizationCreateRequest'; import { OrganizationCreateRequest } from 'jslib/models/request/organizationCreateRequest';
@ -30,6 +31,7 @@ import { OrganizationUpgradeRequest } from 'jslib/models/request/organizationUpg
}) })
export class OrganizationPlansComponent { export class OrganizationPlansComponent {
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent; @ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
@ViewChild(TaxInfoComponent) taxComponent: TaxInfoComponent;
@Input() organizationId: string; @Input() organizationId: string;
@Input() showFree = true; @Input() showFree = true;
@ -153,6 +155,15 @@ export class OrganizationPlansComponent {
} else { } else {
request.planType = this.plans[this.plan].annualPlanType; request.planType = this.plans[this.plan].annualPlanType;
} }
request.billingAddressPostalCode = this.taxComponent.taxInfo.postalCode;
request.billingAddressCountry = this.taxComponent.taxInfo.country;
if (this.taxComponent.taxInfo.includeTaxId) {
request.taxIdNumber = this.taxComponent.taxInfo.taxId;
request.billingAddressLine1 = this.taxComponent.taxInfo.line1;
request.billingAddressLine2 = this.taxComponent.taxInfo.line2;
request.billingAddressCity = this.taxComponent.taxInfo.city;
request.billingAddressState = this.taxComponent.taxInfo.state;
}
} }
const response = await this.apiService.postOrganization(request); const response = await this.apiService.postOrganization(request);
orgId = response.id; orgId = response.id;
@ -262,6 +273,16 @@ export class OrganizationPlansComponent {
return 0; return 0;
} }
changedCountry() {
this.paymentComponent.hideBank = this.taxComponent.taxInfo.country !== 'US';
// Bank Account payments are only available for US customers
if (this.paymentComponent.hideBank &&
this.paymentComponent.method === PaymentMethodType.BankAccount) {
this.paymentComponent.method = PaymentMethodType.Card;
this.paymentComponent.changeMethod();
}
}
get total(): number { get total(): number {
const annual = this.interval === 'year'; const annual = this.interval === 'year';
return this.baseTotal(annual) + this.seatTotal(annual) + this.additionalStorageTotal(annual) + return this.baseTotal(annual) + this.seatTotal(annual) + this.additionalStorageTotal(annual) +

View File

@ -166,7 +166,7 @@ export class PaymentComponent implements OnInit {
} else if (this.method === PaymentMethodType.Card || this.method === PaymentMethodType.BankAccount) { } else if (this.method === PaymentMethodType.Card || this.method === PaymentMethodType.BankAccount) {
if (this.method === PaymentMethodType.Card) { if (this.method === PaymentMethodType.Card) {
this.apiService.postSetupPayment().then((clientSecret) => this.apiService.postSetupPayment().then((clientSecret) =>
this.stripe.confirmCardSetup(clientSecret, this.stripeCardNumberElement)) this.stripe.handleCardSetup(clientSecret, this.stripeCardNumberElement))
.then((result: any) => { .then((result: any) => {
if (result.error) { if (result.error) {
reject(result.error.message); reject(result.error.message);
@ -198,8 +198,8 @@ export class PaymentComponent implements OnInit {
return; return;
} }
const handleCardPayment = () => this.showMethods ? const handleCardPayment = () => this.showMethods ?
this.stripe.confirmCardPayment(clientSecret, this.stripeCardNumberElement) : this.stripe.handleCardSetup(clientSecret, this.stripeCardNumberElement) :
this.stripe.confirmCardPayment(clientSecret); this.stripe.handleCardSetup(clientSecret);
return handleCardPayment().then(async (result: any) => { return handleCardPayment().then(async (result: any) => {
if (result.error) { if (result.error) {
reject(result.error.message); reject(result.error.message);

View File

@ -75,6 +75,7 @@
<small class="text-muted font-italic">{{'paymentChargedAnnually' | i18n}}</small> <small class="text-muted font-italic">{{'paymentChargedAnnually' | i18n}}</small>
<h2 class="spaced-header mb-4">{{'paymentInformation' | i18n}}</h2> <h2 class="spaced-header mb-4">{{'paymentInformation' | i18n}}</h2>
<app-payment [hideBank]="true"></app-payment> <app-payment [hideBank]="true"></app-payment>
<app-tax-info></app-tax-info>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading"> <button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i> <i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span>{{'submit' | i18n}}</span> <span>{{'submit' | i18n}}</span>

View File

@ -17,6 +17,7 @@ import { TokenService } from 'jslib/abstractions/token.service';
import { UserService } from 'jslib/abstractions/user.service'; import { UserService } from 'jslib/abstractions/user.service';
import { PaymentComponent } from './payment.component'; import { PaymentComponent } from './payment.component';
import { TaxInfoComponent } from './tax-info.component';
@Component({ @Component({
selector: 'app-premium', selector: 'app-premium',
@ -24,6 +25,7 @@ import { PaymentComponent } from './payment.component';
}) })
export class PremiumComponent implements OnInit { export class PremiumComponent implements OnInit {
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent; @ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
@ViewChild(TaxInfoComponent) taxInfoComponent: TaxInfoComponent;
canAccessPremium = false; canAccessPremium = false;
selfHosted = false; selfHosted = false;
@ -76,6 +78,7 @@ export class PremiumComponent implements OnInit {
return this.finalizePremium(); return this.finalizePremium();
}); });
} else { } else {
await this.taxInfoComponent.submitTaxInfo();
this.formPromise = this.paymentComponent.createPaymentToken().then((result) => { this.formPromise = this.paymentComponent.createPaymentToken().then((result) => {
const fd = new FormData(); const fd = new FormData();
fd.append('paymentMethodType', result[1].toString()); fd.append('paymentMethodType', result[1].toString());

View File

@ -0,0 +1,313 @@
<div class="row">
<div class="col-6">
<div class="form-group">
<label for="addressCountry">{{'country' | i18n}}</label>
<select id="addressCountry" class="form-control" [(ngModel)]="taxInfo.country" required name="addressCountry"
autocomplete="country" (change)="changeCountry()">
<option value="">-- Select --</option>
<option value="US">United States</option>
<option value="CN">China</option>
<option value="FR">France</option>
<option value="DE">Germany</option>
<option value="CA">Canada</option>
<option value="GB">United Kingdom</option>
<option value="AU">Australia</option>
<option value="IN">India</option>
<option value="-" disabled></option>
<option value="AF">Afghanistan</option>
<option value="AX">Åland Islands</option>
<option value="AL">Albania</option>
<option value="DZ">Algeria</option>
<option value="AS">American Samoa</option>
<option value="AD">Andorra</option>
<option value="AO">Angola</option>
<option value="AI">Anguilla</option>
<option value="AQ">Antarctica</option>
<option value="AG">Antigua and Barbuda</option>
<option value="AR">Argentina</option>
<option value="AM">Armenia</option>
<option value="AW">Aruba</option>
<option value="AT">Austria</option>
<option value="AZ">Azerbaijan</option>
<option value="BS">Bahamas</option>
<option value="BH">Bahrain</option>
<option value="BD">Bangladesh</option>
<option value="BB">Barbados</option>
<option value="BY">Belarus</option>
<option value="BE">Belgium</option>
<option value="BZ">Belize</option>
<option value="BJ">Benin</option>
<option value="BM">Bermuda</option>
<option value="BT">Bhutan</option>
<option value="BO">Bolivia, Plurinational State of</option>
<option value="BQ">Bonaire, Sint Eustatius and Saba</option>
<option value="BA">Bosnia and Herzegovina</option>
<option value="BW">Botswana</option>
<option value="BV">Bouvet Island</option>
<option value="BR">Brazil</option>
<option value="IO">British Indian Ocean Territory</option>
<option value="BN">Brunei Darussalam</option>
<option value="BG">Bulgaria</option>
<option value="BF">Burkina Faso</option>
<option value="BI">Burundi</option>
<option value="KH">Cambodia</option>
<option value="CM">Cameroon</option>
<option value="CV">Cape Verde</option>
<option value="KY">Cayman Islands</option>
<option value="CF">Central African Republic</option>
<option value="TD">Chad</option>
<option value="CL">Chile</option>
<option value="CX">Christmas Island</option>
<option value="CC">Cocos (Keeling) Islands</option>
<option value="CO">Colombia</option>
<option value="KM">Comoros</option>
<option value="CG">Congo</option>
<option value="CD">Congo, the Democratic Republic of the</option>
<option value="CK">Cook Islands</option>
<option value="CR">Costa Rica</option>
<option value="CI">Côte d'Ivoire</option>
<option value="HR">Croatia</option>
<option value="CU">Cuba</option>
<option value="CW">Curaçao</option>
<option value="CY">Cyprus</option>
<option value="CZ">Czech Republic</option>
<option value="DK">Denmark</option>
<option value="DJ">Djibouti</option>
<option value="DM">Dominica</option>
<option value="DO">Dominican Republic</option>
<option value="EC">Ecuador</option>
<option value="EG">Egypt</option>
<option value="SV">El Salvador</option>
<option value="GQ">Equatorial Guinea</option>
<option value="ER">Eritrea</option>
<option value="EE">Estonia</option>
<option value="ET">Ethiopia</option>
<option value="FK">Falkland Islands (Malvinas)</option>
<option value="FO">Faroe Islands</option>
<option value="FJ">Fiji</option>
<option value="FI">Finland</option>
<option value="GF">French Guiana</option>
<option value="PF">French Polynesia</option>
<option value="TF">French Southern Territories</option>
<option value="GA">Gabon</option>
<option value="GM">Gambia</option>
<option value="GE">Georgia</option>
<option value="GH">Ghana</option>
<option value="GI">Gibraltar</option>
<option value="GR">Greece</option>
<option value="GL">Greenland</option>
<option value="GD">Grenada</option>
<option value="GP">Guadeloupe</option>
<option value="GU">Guam</option>
<option value="GT">Guatemala</option>
<option value="GG">Guernsey</option>
<option value="GN">Guinea</option>
<option value="GW">Guinea-Bissau</option>
<option value="GY">Guyana</option>
<option value="HT">Haiti</option>
<option value="HM">Heard Island and McDonald Islands</option>
<option value="VA">Holy See (Vatican City State)</option>
<option value="HN">Honduras</option>
<option value="HK">Hong Kong</option>
<option value="HU">Hungary</option>
<option value="IS">Iceland</option>
<option value="ID">Indonesia</option>
<option value="IR">Iran, Islamic Republic of</option>
<option value="IQ">Iraq</option>
<option value="IE">Ireland</option>
<option value="IM">Isle of Man</option>
<option value="IL">Israel</option>
<option value="IT">Italy</option>
<option value="JM">Jamaica</option>
<option value="JP">Japan</option>
<option value="JE">Jersey</option>
<option value="JO">Jordan</option>
<option value="KZ">Kazakhstan</option>
<option value="KE">Kenya</option>
<option value="KI">Kiribati</option>
<option value="KP">Korea, Democratic People's Republic of</option>
<option value="KR">Korea, Republic of</option>
<option value="KW">Kuwait</option>
<option value="KG">Kyrgyzstan</option>
<option value="LA">Lao People's Democratic Republic</option>
<option value="LV">Latvia</option>
<option value="LB">Lebanon</option>
<option value="LS">Lesotho</option>
<option value="LR">Liberia</option>
<option value="LY">Libya</option>
<option value="LI">Liechtenstein</option>
<option value="LT">Lithuania</option>
<option value="LU">Luxembourg</option>
<option value="MO">Macao</option>
<option value="MK">Macedonia, the former Yugoslav Republic of</option>
<option value="MG">Madagascar</option>
<option value="MW">Malawi</option>
<option value="MY">Malaysia</option>
<option value="MV">Maldives</option>
<option value="ML">Mali</option>
<option value="MT">Malta</option>
<option value="MH">Marshall Islands</option>
<option value="MQ">Martinique</option>
<option value="MR">Mauritania</option>
<option value="MU">Mauritius</option>
<option value="YT">Mayotte</option>
<option value="MX">Mexico</option>
<option value="FM">Micronesia, Federated States of</option>
<option value="MD">Moldova, Republic of</option>
<option value="MC">Monaco</option>
<option value="MN">Mongolia</option>
<option value="ME">Montenegro</option>
<option value="MS">Montserrat</option>
<option value="MA">Morocco</option>
<option value="MZ">Mozambique</option>
<option value="MM">Myanmar</option>
<option value="NA">Namibia</option>
<option value="NR">Nauru</option>
<option value="NP">Nepal</option>
<option value="NL">Netherlands</option>
<option value="NC">New Caledonia</option>
<option value="NZ">New Zealand</option>
<option value="NI">Nicaragua</option>
<option value="NE">Niger</option>
<option value="NG">Nigeria</option>
<option value="NU">Niue</option>
<option value="NF">Norfolk Island</option>
<option value="MP">Northern Mariana Islands</option>
<option value="NO">Norway</option>
<option value="OM">Oman</option>
<option value="PK">Pakistan</option>
<option value="PW">Palau</option>
<option value="PS">Palestinian Territory, Occupied</option>
<option value="PA">Panama</option>
<option value="PG">Papua New Guinea</option>
<option value="PY">Paraguay</option>
<option value="PE">Peru</option>
<option value="PH">Philippines</option>
<option value="PN">Pitcairn</option>
<option value="PL">Poland</option>
<option value="PT">Portugal</option>
<option value="PR">Puerto Rico</option>
<option value="QA">Qatar</option>
<option value="RE">Réunion</option>
<option value="RO">Romania</option>
<option value="RU">Russian Federation</option>
<option value="RW">Rwanda</option>
<option value="BL">Saint Barthélemy</option>
<option value="SH">Saint Helena, Ascension and Tristan da Cunha</option>
<option value="KN">Saint Kitts and Nevis</option>
<option value="LC">Saint Lucia</option>
<option value="MF">Saint Martin (French part)</option>
<option value="PM">Saint Pierre and Miquelon</option>
<option value="VC">Saint Vincent and the Grenadines</option>
<option value="WS">Samoa</option>
<option value="SM">San Marino</option>
<option value="ST">Sao Tome and Principe</option>
<option value="SA">Saudi Arabia</option>
<option value="SN">Senegal</option>
<option value="RS">Serbia</option>
<option value="SC">Seychelles</option>
<option value="SL">Sierra Leone</option>
<option value="SG">Singapore</option>
<option value="SX">Sint Maarten (Dutch part)</option>
<option value="SK">Slovakia</option>
<option value="SI">Slovenia</option>
<option value="SB">Solomon Islands</option>
<option value="SO">Somalia</option>
<option value="ZA">South Africa</option>
<option value="GS">South Georgia and the South Sandwich Islands</option>
<option value="SS">South Sudan</option>
<option value="ES">Spain</option>
<option value="LK">Sri Lanka</option>
<option value="SD">Sudan</option>
<option value="SR">Suriname</option>
<option value="SJ">Svalbard and Jan Mayen</option>
<option value="SZ">Swaziland</option>
<option value="SE">Sweden</option>
<option value="CH">Switzerland</option>
<option value="SY">Syrian Arab Republic</option>
<option value="TW">Taiwan, Province of China</option>
<option value="TJ">Tajikistan</option>
<option value="TZ">Tanzania, United Republic of</option>
<option value="TH">Thailand</option>
<option value="TL">Timor-Leste</option>
<option value="TG">Togo</option>
<option value="TK">Tokelau</option>
<option value="TO">Tonga</option>
<option value="TT">Trinidad and Tobago</option>
<option value="TN">Tunisia</option>
<option value="TR">Turkey</option>
<option value="TM">Turkmenistan</option>
<option value="TC">Turks and Caicos Islands</option>
<option value="TV">Tuvalu</option>
<option value="UG">Uganda</option>
<option value="UA">Ukraine</option>
<option value="AE">United Arab Emirates</option>
<option value="UM">United States Minor Outlying Islands</option>
<option value="UY">Uruguay</option>
<option value="UZ">Uzbekistan</option>
<option value="VU">Vanuatu</option>
<option value="VE">Venezuela, Bolivarian Republic of</option>
<option value="VN">Viet Nam</option>
<option value="VG">Virgin Islands, British</option>
<option value="VI">Virgin Islands, U.S.</option>
<option value="WF">Wallis and Futuna</option>
<option value="EH">Western Sahara</option>
<option value="YE">Yemen</option>
<option value="ZM">Zambia</option>
<option value="ZW">Zimbabwe</option>
</select>
</div>
</div>
<div class="col-3">
<div class="form-group">
<label for="addressPostalCode">{{'zipPostalCode' | i18n}}</label>
<input id="addressPostalCode" class="form-control" type="text" name="addressPostalCode"
[(ngModel)]="taxInfo.postalCode" [required]="taxInfo.country === 'US'" autocomplete="postal-code">
</div>
</div>
<div class="col-6" *ngIf="organizationId && taxInfo.country !== 'US'">
<div class="form-group form-check">
<input class="form-check-input" id="addressIncludeTaxId" name="addressIncludeTaxId" type="checkbox"
[(ngModel)]="taxInfo.includeTaxId">
<label class="form-check-label" for="addressIncludeTaxId">{{'includeVAT' | i18n}}</label>
</div>
</div>
</div>
<div class="row" *ngIf="organizationId && taxInfo.includeTaxId">
<div class="col-6">
<div class="form-group">
<label for="taxId">{{'taxIdNumber' | i18n}}</label>
<input id="taxId" class="form-control" type="text" name="taxId" [(ngModel)]="taxInfo.taxId">
</div>
</div>
</div>
<div class="row" *ngIf="organizationId && taxInfo.includeTaxId">
<div class="col-6">
<div class="form-group">
<label for="addressLine1">{{'address1' | i18n}}</label>
<input id="addressLine1" class="form-control" type="text" name="addressLine1"
[(ngModel)]="taxInfo.line1" autocomplete="address-line1">
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="addressLine2">{{'address2' | i18n}}</label>
<input id="addressLine2" class="form-control" type="text" name="addressLine2"
[(ngModel)]="taxInfo.line2" autocomplete="address-line2">
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="addressCity">{{'cityTown' | i18n}}</label>
<input id="addressCity" class="form-control" type="text" name="addressCity"
[(ngModel)]="taxInfo.city" autocomplete="address-level2">
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="addressState">{{'stateProvince' | i18n}}</label>
<input id="addressState" class="form-control" type="text" name="addressState"
[(ngModel)]="taxInfo.state" autocomplete="address-level1">
</div>
</div>
</div>

View File

@ -0,0 +1,132 @@
import {
Component,
EventEmitter,
Output,
} from '@angular/core';
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';
@Component({
selector: 'app-tax-info',
templateUrl: 'tax-info.component.html',
})
export class TaxInfoComponent {
@Output() onCountryChanged = new EventEmitter();
loading: boolean = true;
organizationId: string;
taxInfo: any = {
taxId: null,
line1: null,
line2: null,
city: null,
state: null,
postalCode: null,
country: 'US',
includeTaxId: false,
};
private pristine: any = {
taxId: null,
line1: null,
line2: null,
city: null,
state: null,
postalCode: null,
country: 'US',
includeTaxId: false,
};
constructor(private apiService: ApiService, private route: ActivatedRoute) { }
async ngOnInit() {
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
if (this.organizationId) {
try {
const taxInfo = await this.apiService.getOrganizationTaxInfo(this.organizationId);
if (taxInfo) {
this.taxInfo.taxId = taxInfo.taxId;
this.taxInfo.state = taxInfo.state;
this.taxInfo.line1 = taxInfo.line1;
this.taxInfo.line2 = taxInfo.line2;
this.taxInfo.city = taxInfo.city;
this.taxInfo.state = taxInfo.state;
this.taxInfo.postalCode = taxInfo.postalCode;
this.taxInfo.country = taxInfo.country || 'US';
this.taxInfo.includeTaxId = this.taxInfo.country !== 'US' && (
!!taxInfo.taxId
|| !!taxInfo.line1
|| !!taxInfo.line2
|| !!taxInfo.city
|| !!taxInfo.state);
}
} catch { }
} else {
const taxInfo = await this.apiService.getTaxInfo();
if (taxInfo) {
this.taxInfo.postalCode = taxInfo.postalCode;
this.taxInfo.country = taxInfo.country || 'US';
}
}
this.pristine = Object.assign({}, this.taxInfo);
// If not the default (US) then trigger onCountryChanged
if (this.taxInfo.country !== 'US') {
this.onCountryChanged.emit();
}
});
this.loading = false;
}
getTaxInfoRequest(): TaxInfoUpdateRequest {
if (this.organizationId) {
const request = new OrganizationTaxInfoUpdateRequest();
request.taxId = this.taxInfo.taxId;
request.state = this.taxInfo.state;
request.line1 = this.taxInfo.line1;
request.line2 = this.taxInfo.line2;
request.city = this.taxInfo.city;
request.state = this.taxInfo.state;
request.postalCode = this.taxInfo.postalCode;
request.country = this.taxInfo.country;
return request;
} else {
const request = new TaxInfoUpdateRequest();
request.postalCode = this.taxInfo.postalCode;
request.country = this.taxInfo.country;
return request;
}
}
submitTaxInfo(): Promise<any> {
if (!this.hasChanged()) {
return new Promise((resolve) => { resolve(); });
}
const request = this.getTaxInfoRequest();
return this.organizationId ? this.apiService.putOrganizationTaxInfo(this.organizationId,
request as OrganizationTaxInfoUpdateRequest) : this.apiService.putTaxInfo(request);
}
changeCountry() {
if (this.taxInfo.country === 'US') {
this.taxInfo.includeTaxId = false;
this.taxInfo.taxId = null;
this.taxInfo.line1 = null;
this.taxInfo.line2 = null;
this.taxInfo.city = null;
this.taxInfo.state = null;
}
this.onCountryChanged.emit();
}
private hasChanged(): boolean {
for (const key in this.taxInfo) {
if (this.pristine.hasOwnProperty(key) && this.pristine[key] !== this.taxInfo[key]) {
return true;
}
}
return false;
}
}