1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-30 13:03:53 +01:00

handleCardPayment for incomplete payments

This commit is contained in:
Kyle Spearrin 2019-08-09 23:57:30 -04:00
parent 18608a8b63
commit a4571a2617
6 changed files with 68 additions and 25 deletions

2
jslib

@ -1 +1 @@
Subproject commit 393f6c9c20fb7eded5008b65242ea44e69bc349c Subproject commit e28e820286870df0111bd4feb8a219a3ae360ba7

View File

@ -203,6 +203,9 @@
<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>
</ng-container> </ng-container>
<ng-container *ngIf="!createOrganization">
<app-payment [showMethods]="false"></app-payment>
</ng-container>
<small class="text-muted font-italic mt-2 d-block" *ngIf="!createOrganization"> <small class="text-muted font-italic mt-2 d-block" *ngIf="!createOrganization">
{{'paymentCharged' | i18n : (interval | i18n) }}</small> {{'paymentCharged' | i18n : (interval | i18n) }}</small>
</ng-container> </ng-container>

View File

@ -169,7 +169,10 @@ export class OrganizationPlansComponent {
} else { } else {
request.planType = this.plans[this.plan].annualPlanType; request.planType = this.plans[this.plan].annualPlanType;
} }
await this.apiService.postOrganizationUpgrade(this.organizationId, request); const result = await this.apiService.postOrganizationUpgrade(this.organizationId, request);
if (!result.success && result.paymentIntentClientSecret != null) {
await this.paymentComponent.handleStripeCardPayment(result.paymentIntentClientSecret, null);
}
orgId = this.organizationId; orgId = this.organizationId;
} }

View File

@ -1,4 +1,4 @@
<div class="mb-4 text-lg" *ngIf="showOptions"> <div class="mb-4 text-lg" *ngIf="showOptions && showMethods">
<div class="form-check form-check-inline mr-4"> <div class="form-check form-check-inline mr-4">
<input class="form-check-input" type="radio" name="Method" id="method-card" [value]="paymentMethodType.Card" <input class="form-check-input" type="radio" name="Method" id="method-card" [value]="paymentMethodType.Card"
[(ngModel)]="method" (change)="changeMethod()"> [(ngModel)]="method" (change)="changeMethod()">
@ -24,7 +24,7 @@
<i class="fa fa-fw fa-dollar"></i> {{'accountCredit' | i18n}}</label> <i class="fa fa-fw fa-dollar"></i> {{'accountCredit' | i18n}}</label>
</div> </div>
</div> </div>
<ng-container *ngIf="method === paymentMethodType.Card"> <ng-container *ngIf="showMethods && method === paymentMethodType.Card">
<div class="row"> <div class="row">
<div class="form-group col-4"> <div class="form-group col-4">
<label for="stripe-card-number-element">{{'number' | i18n}}</label> <label for="stripe-card-number-element">{{'number' | i18n}}</label>
@ -50,7 +50,7 @@
</div> </div>
</div> </div>
</ng-container> </ng-container>
<ng-container *ngIf="method === paymentMethodType.BankAccount"> <ng-container *ngIf="showMethods && method === paymentMethodType.BankAccount">
<app-callout type="warning" title="{{'verifyBankAccount' | i18n}}"> <app-callout type="warning" title="{{'verifyBankAccount' | i18n}}">
{{'verifyBankAccountInitialDesc' | i18n}} {{'verifyBankAccountFailureWarning' | i18n}} {{'verifyBankAccountInitialDesc' | i18n}} {{'verifyBankAccountFailureWarning' | i18n}}
</app-callout> </app-callout>
@ -81,13 +81,13 @@
</div> </div>
</div> </div>
</ng-container> </ng-container>
<ng-container *ngIf="method === paymentMethodType.PayPal"> <ng-container *ngIf="showMethods && method === paymentMethodType.PayPal">
<div class="mb-3"> <div class="mb-3">
<div id="bt-dropin-container" class="mb-1"></div> <div id="bt-dropin-container" class="mb-1"></div>
<small class="text-muted">{{'paypalClickSubmit' | i18n}}</small> <small class="text-muted">{{'paypalClickSubmit' | i18n}}</small>
</div> </div>
</ng-container> </ng-container>
<ng-container *ngIf="method === paymentMethodType.Credit"> <ng-container *ngIf="showMethods && method === paymentMethodType.Credit">
<app-callout type="note"> <app-callout type="note">
{{'makeSureEnoughCredit' | i18n}} {{'makeSureEnoughCredit' | i18n}}
</app-callout> </app-callout>

View File

@ -6,6 +6,7 @@ import {
import { PaymentMethodType } from 'jslib/enums/paymentMethodType'; import { PaymentMethodType } from 'jslib/enums/paymentMethodType';
import { ApiService } from 'jslib/abstractions/api.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { WebConstants } from '../../services/webConstants'; import { WebConstants } from '../../services/webConstants';
@ -34,6 +35,7 @@ const StripeElementClasses = {
templateUrl: 'payment.component.html', templateUrl: 'payment.component.html',
}) })
export class PaymentComponent implements OnInit { export class PaymentComponent implements OnInit {
@Input() showMethods = true;
@Input() showOptions = true; @Input() showOptions = true;
@Input() method = PaymentMethodType.Card; @Input() method = PaymentMethodType.Card;
@Input() hideBank = false; @Input() hideBank = false;
@ -60,7 +62,7 @@ export class PaymentComponent implements OnInit {
private stripeCardExpiryElement: any = null; private stripeCardExpiryElement: any = null;
private stripeCardCvcElement: any = null; private stripeCardCvcElement: any = null;
constructor(private platformUtilsService: PlatformUtilsService) { constructor(private platformUtilsService: PlatformUtilsService, private apiService: ApiService) {
this.stripeScript = window.document.createElement('script'); this.stripeScript = window.document.createElement('script');
this.stripeScript.src = 'https://js.stripe.com/v3/'; this.stripeScript.src = 'https://js.stripe.com/v3/';
this.stripeScript.async = true; this.stripeScript.async = true;
@ -162,30 +164,60 @@ export class PaymentComponent implements OnInit {
reject(err.message); reject(err.message);
}); });
} else if (this.method === PaymentMethodType.Card || this.method === PaymentMethodType.BankAccount) { } else if (this.method === PaymentMethodType.Card || this.method === PaymentMethodType.BankAccount) {
let sourceObj: any = null;
let createObj: any = null;
if (this.method === PaymentMethodType.Card) { if (this.method === PaymentMethodType.Card) {
sourceObj = this.stripeCardNumberElement; this.apiService.postSetupPayment().then((clientSecret) =>
this.stripe.handleCardSetup(clientSecret, this.stripeCardNumberElement))
.then((result: any) => {
if (result.error) {
reject(result.error.message);
} else if (result.setupIntent && result.setupIntent.status === 'succeeded') {
resolve([result.setupIntent.payment_method, this.method]);
} else {
reject();
}
});
} else { } else {
sourceObj = 'bank_account'; this.stripe.createToken('bank_account', this.bank).then((result: any) => {
createObj = this.bank; if (result.error) {
reject(result.error.message);
} else if (result.token && result.token.id != null) {
resolve([result.token.id, this.method]);
} else {
reject();
}
});
} }
this.stripe.createToken(sourceObj, createObj).then((result: any) => {
if (result.error) {
reject(result.error.message);
} else if (result.token && result.token.id != null) {
resolve([result.token.id, this.method]);
} else {
reject();
}
});
} }
}); });
} }
handleStripeCardPayment(clientSecret: string, successCallback: () => Promise<any>): Promise<any> {
return new Promise((resolve, reject) => {
if (this.showMethods && this.stripeCardNumberElement == null) {
reject();
return;
}
const handleCardPayment = () => this.showMethods ?
this.stripe.handleCardPayment(clientSecret, this.stripeCardNumberElement) :
this.stripe.handleCardPayment(clientSecret);
return handleCardPayment().then(async (result: any) => {
if (result.error) {
reject(result.error.message);
} else if (result.paymentIntent && result.paymentIntent.status === 'succeeded') {
if (successCallback != null) {
await successCallback();
}
resolve();
} else {
reject();
}
});
});
}
private setStripeElement() { private setStripeElement() {
window.setTimeout(() => { window.setTimeout(() => {
if (this.method === PaymentMethodType.Card) { if (this.showMethods && this.method === PaymentMethodType.Card) {
if (this.stripeCardNumberElement == null) { if (this.stripeCardNumberElement == null) {
this.stripeCardNumberElement = this.stripeElements.create('cardNumber', { this.stripeCardNumberElement = this.stripeElements.create('cardNumber', {
style: StripeElementStyle, style: StripeElementStyle,

View File

@ -84,8 +84,13 @@ export class PremiumComponent implements OnInit {
} }
fd.append('additionalStorageGb', (this.additionalStorage || 0).toString()); fd.append('additionalStorageGb', (this.additionalStorage || 0).toString());
return this.apiService.postPremium(fd); return this.apiService.postPremium(fd);
}).then(() => { }).then((paymentResponse) => {
return this.finalizePremium(); if (!paymentResponse.success && paymentResponse.paymentIntentClientSecret != null) {
return this.paymentComponent.handleStripeCardPayment(paymentResponse.paymentIntentClientSecret,
() => this.finalizePremium());
} else {
return this.finalizePremium();
}
}); });
} }
await this.formPromise; await this.formPromise;