Skip to content

Commit

Permalink
SCA Updates - PaymentIntents & SetupIntents management (#81)
Browse files Browse the repository at this point in the history
* Update angular-demo to NS6

* Update demo to NS6

* Update android-sdk to 10.2.1

* Remove dev-typescript

* migrate API

* restore SDK 8.7.0

* Use androidx

* fix namespace

* fix app start

* remove bundle and uglify

* Restore 10.2.1 SDK

* Fix merge issue

* Update defs

* Enable multidex

* Bump minSDK version

* Update {N} version on travis

* Remove useless template

* Rename _android var to _widget

* fix commas

* Implements createPaymentMethod

* Add debug run

* Add stripe3ds2 typings

* Init PaymentConfiguration before CustomerSession

* Fix requestPayment on Android

* Cleans

* Update typings

* Update xcode and node versions

* Fix frame is undefined

* Add webpack configs to demos

* confirmPaymentIntent uses StripePaymentIntentParams

* Add create intent endpoint

* Demo Intent

* PaymentConfiguration.init called once

* Update paymentIntent conf

* Update ios podfile to 16.0.6

* Fix creditcard view

* Fix paymentContextDidCreatePaymentResultCompletion

* add debug demo.ios

* Remove deleted createCardSources attribute

* tmp paymentWithAuthent

* Changelog

* Remove unused import

* Fix authentification context

* Add status

* Factorize StripeIntent

* Clean component

* cleans

* Remove source and use payment method

* remove source

* Restore keys

* Update SDK in README

* Fix semicolons

* trailing spaces

* cleans

* refactor stripeIntent for Android

* Update README

* tslint

* Exclude platforms from tslint

* Handle automatic and manual payment intent flows

* fix tslint

* Update README and Changelog

* feedbacks

* cleans

* requiresCapture helper

* Bump version

* Fix ios contextMethod from modals

* fix linter

* Remove confirmPaymentIntent from index.d.ts

* Fix keyUpdateListener.onKeyUpdateFailure error

* Push last PR updates
  • Loading branch information
jeremypele authored and RobertGardner committed Sep 3, 2019
1 parent 9960971 commit fa58a2d
Show file tree
Hide file tree
Showing 32 changed files with 9,462 additions and 5,141 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
Changelog
==============================

## 6.0.0 (2019, August 25)
### Updates
- SDK Updates for SCA compliance

### Implements
- [(# 78)](https://github.com/triniwiz/nativescript-stripe/issues/78) Stripe SDKs out of date; Upgrade needed for latest SCA process
- [(# 45)](https://github.com/triniwiz/nativescript-stripe/issues/45) EU Strong Customer Authentication support integration

### Breaking Changes
- Sources and Tokens are now deprecated, uses Payment Methods and Payment Intents instead
- [Back-end test app](https://github.com/stripe/example-ios-backend) needs to be updated if you want to use the plugin with Intents.
- Stripe Service `completeCharge` has been renamed to `capturePayment`

## 5.5.0 (2019, August 20)
### Updates
- Nativescript 6 compatibility
Expand Down
50 changes: 7 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@

## Android

Stripe Android [v8.7 SDK](https://github.com/stripe/stripe-android/releases/tag/v8.7.0) is being used
Stripe Android [v10.2.1 SDK](https://github.com/stripe/stripe-android/releases/tag/v10.2.1) is being used

## iOS

Stripe [iOS 15 SDK](https://github.com/stripe/stripe-ios/releases/tag/v15.0.1) (pod) is being used
Stripe [iOS 16.0.6 SDK](https://github.com/stripe/stripe-ios/releases/tag/v16.0.6) (pod) is being used

## Angular
To use the Custom Integration's CreditCardView in Angular,
Expand Down Expand Up @@ -84,36 +84,6 @@ const cc = new Card("1111111111111111",2,18,"123");
cc.name = "Osei Fortune";
```

### Get Token

TypeScript
```ts
import {Stripe} from 'nativescript-stripe';
const stripe = new Stripe('yourApiKey');
stripe.createToken(cc, (error,token)=>{
if(!error){
//Do something with your token;

}else{
console.log(error);
}
});
```

JavaScript
```js
var Stripe = require('nativescript-stripe').Stripe;
const stripe = new Stripe('yourApiKey');
stripe.createToken(cc, (error,token)=>{
if(!error){
//Do something with your token;

}else{
console.log(error);
}
});
```

## Standard Integration

The `demo` and `demo-angular` folders contain demos that use the Standard Integration.
Expand Down Expand Up @@ -149,29 +119,23 @@ for some credit card purchases. Stripe supports this, though most of the work to
required on the backend server and in the mobile app, outside the `nativescript-stripe` plugin.

To support SCA, follow the instructions for [iOS](https://stripe.com/docs/payments/payment-intents/ios)
and [Android](https://stripe.com/docs/payments/payment-intents/android) on using `PaymentIntent`s instead
and [Android](https://stripe.com/docs/payments/payment-intents/android) on using `PaymentIntents` instead
of tokens when interacting with your backend server. The `nativescript-stripe` plugin has
cross-platform data structures and method calls that might be helpful. In `index.d.ts` see:
* `PaymentMethod` and related classes
* `StripePaymentIntent` and related classes
* Methods `Stripe.createPaymentMethod`, `Stripe.retrievePaymentIntent`, and `Stripe.confirmPaymentIntent`
* Methods `Stripe.createPaymentMethod`, `Stripe.retrievePaymentIntent`, `Stripe.confirmPaymentIntent` and `Stripe.confirmSetupIntent`

## Handling secondary customer input
SCA requires the customer to enter additional information with some charge cards. Stripe takes care of this
if you properly handle the redirect from the `StripePaymentIntent` returned from the server.

On iOS, `StripeRedirectSession` can help manage the interaction with the customer.
If you're using the [automatic confirmation flow](https://stripe.com/docs/payments/payment-intents/ios#automatic-confirmation-ios), `confirmPaymentIntent` and `confirmSetupIntent` will automatically manage the SCA validation by showing and validating the payment authentification.

On Android, it appears that (as of May 1, 2019) the Android SDK regarding SCA is still undergoing heavy
development and not everything is working as well as it could. For example, the new methods in `Stripe`
cannot be called on the UI thread in Android (but they can on iOS), and the technique for handling
secondary customer interaction is difficult. Hopefully these will be addressed soon.
If you're using the [manual confirmation flow](https://stripe.com/docs/payments/payment-intents/ios#manual-confirmation-ios), where back-end creates the `PaymentIntent`|`SetupIntent` and requires an Intent authentification from the customer, `authenticatePaymentIntent` and `authenticateSetupIntent` will allow to manage that extra step before sending back the Intent to your server.

## Status
Finally, keep in mind that while these SCA support classes and methods have been added to the plugin, they
have not yet been thoroughly tested. The `demo` and `demo-angular` apps do *not* (yet) support `PaymentIntent`,
although they have been modified to work with the current Stripe example backend
(which does fully support `PaymentIntent`). Any help updating the demo apps would be greatly appreciated.
`demo-angular` now supports `SetupIntent` and `PaymentIntent` SCA integration. Any credit card verification will be automatically prompted to the user.

# TODO
* Android Pay
Expand Down
3 changes: 2 additions & 1 deletion demo-angular/app/App_Resources/Android/app.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
//}

android {
defaultConfig {
defaultConfig {
multiDexEnabled true
generatedDensities = []
applicationId = "org.nativescript.stripe.demoangular"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
android:xlargeScreens="true"/>

<uses-sdk
android:minSdkVersion="17"
android:minSdkVersion="19"
android:targetSdkVersion="__APILEVEL__"/>

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Expand Down
2 changes: 0 additions & 2 deletions demo-angular/app/app.component.html

This file was deleted.

2 changes: 1 addition & 1 deletion demo-angular/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Component } from "@angular/core";

@Component({
selector: "ns-app",
templateUrl: "app.component.html",
template: "<page-router-outlet></page-router-outlet>",
})

export class AppComponent { }
7 changes: 6 additions & 1 deletion demo-angular/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { AppRoutingModule } from "./app.routing";
import { CreditCardViewComponent } from "./demo/creditcardview.component";
import { HomeComponent } from "./demo/home.component";
import { StandardComponent } from "./demo/standard.component";
import { IntentComponent } from "./demo/intent.component";
import { StripeService } from "./demo/stripe.service";
import { ItentModalComponent } from "./demo/intent-modal.component";

// Uncomment and add to NgModule imports if you need to use two-way binding
// import { NativeScriptFormsModule } from "nativescript-angular/forms";
Expand All @@ -27,11 +29,14 @@ import { StripeService } from "./demo/stripe.service";
AppComponent,
HomeComponent,
StandardComponent,
CreditCardViewComponent
CreditCardViewComponent,
IntentComponent,
ItentModalComponent
],
providers: [
StripeService
],
entryComponents: [ItentModalComponent],
schemas: [
NO_ERRORS_SCHEMA
]
Expand Down
2 changes: 2 additions & 0 deletions demo-angular/app/app.routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { NativeScriptRouterModule } from "nativescript-angular/router";
import { CreditCardViewComponent } from "./demo/creditcardview.component";
import { HomeComponent } from "./demo/home.component";
import { StandardComponent } from "./demo/standard.component";
import { IntentComponent } from "./demo/intent.component";

const routes: Routes = [
{ path: "", redirectTo: "/home", pathMatch: "full" },
{ path: "home", component: HomeComponent },
{ path: "std", component: StandardComponent },
{ path: "ccview", component: CreditCardViewComponent },
{ path: "intent", component: IntentComponent }
];

@NgModule({
Expand Down
4 changes: 0 additions & 4 deletions demo-angular/app/demo/creditcardview.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ export class CreditCardViewComponent {
}

createPaymentMethod(cardView: CreditCardView): void {
if (isAndroid) {
this.payment = "On Android this call cannot yet be called from UI thread";
return;
}
this.payment = "Fetching payment method...";
this.stripe.createPaymentMethod(cardView.card, (error, pm) => {
this.payment = error ? error.message : this.formatPaymentMethod(pm);
Expand Down
5 changes: 5 additions & 0 deletions demo-angular/app/demo/home.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
<StackLayout class="page p-10">
<Label text="Standard Integration" class="h2"></Label>
<Button text="Demo" [nsRouterLink]="['/std']" class="btn btn-primary btn-active"></Button>

<StackLayout class="hr-light m-10"></StackLayout>
<Label text="Custom Integration" class="h2"></Label>
<Button text="CreditCardView" [nsRouterLink]="['/ccview']" class="btn btn-primary btn-active"></Button>

<StackLayout class="hr-light m-10"></StackLayout>
<Label text="Intent Integration" class="h2"></Label>
<Button text="Intent" [nsRouterLink]="['/intent']" class="btn btn-primary btn-active"></Button>
</StackLayout>
15 changes: 15 additions & 0 deletions demo-angular/app/demo/intent-modal.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<StackLayout class="page">
<CreditCardView #card></CreditCardView>

<Button
text="Save Credit Card - Setup Intent"
(tap)="registerCard(card)"
class="btn btn-primary"></Button>

<Label [text]="status" textWrap="true" class="text-center"></Label>

<Button
text="Close modal"
(tap)="closeModal()"
class="btn btn-cancel"></Button>
</StackLayout>
66 changes: 66 additions & 0 deletions demo-angular/app/demo/intent-modal.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Component, ChangeDetectorRef } from "@angular/core";
import { ModalDialogParams } from "nativescript-angular/modal-dialog";
import { alert } from "tns-core-modules/ui/dialogs";
import { CreditCardView, Stripe } from "nativescript-stripe";

import { publishableKey, StripeService } from "./stripe.service";

@Component({
moduleId: module.id,
templateUrl: "intent-modal.component.html"
})
export class ItentModalComponent {
status: string;
private stripe: Stripe;

constructor(
private stripeService: StripeService,
public changeDetectionRef: ChangeDetectorRef,
private dialogParams: ModalDialogParams
) {
if (-1 !== publishableKey.indexOf("pk_test_yours")) {
throw new Error("publishableKey must be changed from placeholder");
}
this.stripe = new Stripe(publishableKey);
}

/*
* Public methods
*/

closeModal() {
this.dialogParams.closeCallback();
}

registerCard(cardView: CreditCardView) {
this._setStatus("Create Setup Intent...");
this.stripeService.createSetupIntent().then((intent) => {

this._setStatus("Create Payment Method...");
this.stripe.createPaymentMethod(cardView.card, (error, pm) => {
if (error) return this._displayError(error);
this._setStatus("Confirm Setup Intent...");
this.stripe.confirmSetupIntent(pm.id, intent.secret, (error, setupIntent) => {
if (error) this._displayError(error);
this._setStatus(`Setup Intent Status => ${setupIntent.status}`);
});
});
});
}

/*
* Private
*/

private _setStatus(message) {
this.status = message;
this.changeDetectionRef.detectChanges();
}

private _displayError(message) {
alert({
message,
okButtonText: "OK"
}).then(() => this._setStatus(null));
}
}
27 changes: 27 additions & 0 deletions demo-angular/app/demo/intent.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<ActionBar title="Intent Demo" class="action-bar"></ActionBar>

<StackLayout class="page">
<CreditCardView #card></CreditCardView>

<Button
text="Save Credit Card - Setup Intent"
(tap)="registerCard(card)"
class="btn btn-primary"></Button>

<Button
text="Automatic Confirm Intent Payment (12$)"
(tap)="automaticConfirmPayment(card)"
class="btn btn-primary"></Button>

<Button
text="Manual Confirm Intent Payment (12$)"
(tap)="manualConfirmPayment(card)"
class="btn btn-primary"></Button>

<Button
text="From Modal"
(tap)="openModal()"
class="btn btn-primary"></Button>

<Label [text]="status" textWrap="true" class="text-center"></Label>
</StackLayout>
Loading

0 comments on commit fa58a2d

Please sign in to comment.