[stripe-v3] Support for handleCardSetup and SetupIntent (#36662)

* Added types for handleCardSetup

* Author

* Fix format. Passes linting
This commit is contained in:
Kim Ehrenpohl
2019-07-08 18:47:06 +02:00
committed by Andrew Branch
parent 8069501d3c
commit 1d1a9e75db
2 changed files with 265 additions and 57 deletions

View File

@@ -9,6 +9,7 @@
// Stefan Langeder <https://github.com/slangeder>
// Marlos Borges <https://github.com/marlosin>
// Thomas Marek <https://github.com/ttmarek>
// Kim Ehrenpohl <https://github.com/kimehrenpohl>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare var Stripe: stripe.StripeStatic;
@@ -24,7 +25,7 @@ declare namespace stripe {
createToken(element: elements.Element, options?: TokenOptions): Promise<TokenResponse>;
createToken(name: 'bank_account', options: BankAccountTokenOptions): Promise<TokenResponse>;
createToken(name: 'pii', options: PiiTokenOptions): Promise<TokenResponse>;
createSource(element: elements.Element, options?: {owner?: OwnerInfo}): Promise<SourceResponse>;
createSource(element: elements.Element, options?: { owner?: OwnerInfo }): Promise<SourceResponse>;
createSource(options: SourceOptions): Promise<SourceResponse>;
retrieveSource(options: RetrieveSourceOptions): Promise<SourceResponse>;
redirectToCheckout(options: StripeCheckoutOptions): Promise<StripeRedirectResponse>;
@@ -49,6 +50,15 @@ declare namespace stripe {
handleCardAction(
clientSecret: string,
): Promise<PaymentIntentResponse>;
handleCardSetup(
clientSecret: string,
element: elements.Element,
data: HandleCardSetupOptions,
): Promise<SetupIntentResponse>;
handleCardSetup(
clientSecret: string,
data: HandleCardSetupOptionsWithoutElementsOptions,
): Promise<SetupIntentResponse>;
confirmPaymentIntent(
clientSecret: string,
element: elements.Element,
@@ -83,9 +93,9 @@ declare namespace stripe {
}
interface StripeOptions {
stripeAccount?: string;
betas?: string[];
locale?: string;
stripeAccount?: string;
betas?: string[];
locale?: string;
}
interface TokenOptions {
@@ -205,12 +215,12 @@ declare namespace stripe {
}
type ErrorType = 'api_connection_error'
| 'api_error'
| 'authentication_error'
| 'card_error'
| 'idempotency_error'
| 'invalid_request_error'
| 'rate_limit_error';
| 'api_error'
| 'authentication_error'
| 'card_error'
| 'idempotency_error'
| 'invalid_request_error'
| 'rate_limit_error';
interface Error {
/**
@@ -450,6 +460,26 @@ declare namespace stripe {
}
};
}
interface HandleCardSetupOptions {
/**
* Use this parameter to supply additional data relevant to
* the payment method, such as billing details.
*/
payment_method_data?: {
/**
* The billing details associated with the card. [Recommended]
*/
billing_details?: BillingDetails,
};
}
interface HandleCardSetupOptionsWithoutElementsOptions extends HandleCardPaymentOptions {
/**
* Only one of payment_method_data and payment_method is required.
* Use payment_method to specify an existing PaymentMethod to use
* for this payment.
*/
payment_method?: string;
}
interface ConfirmPaymentIntentOptions {
/**
@@ -521,6 +551,10 @@ declare namespace stripe {
paymentIntent?: paymentIntents.PaymentIntent;
error?: Error;
}
interface SetupIntentResponse {
setupIntent?: setupIntents.SetupIntent;
error?: Error;
}
// Container for all payment request related types
namespace paymentRequest {
@@ -590,14 +624,14 @@ declare namespace stripe {
}
interface StripePaymentRequest {
canMakePayment(): Promise<{applePay?: boolean} | null>;
canMakePayment(): Promise<{ applePay?: boolean } | null>;
show(): void;
update(options: StripePaymentRequestUpdateOptions): void;
on(event: 'token', handler: (response: StripeTokenPaymentResponse) => void): void;
on(event: 'source', handler: (response: StripeSourcePaymentResponse) => void): void;
on(event: 'cancel', handler: () => void): void;
on(event: 'shippingaddresschange', handler: (response: {updateWith: (options: UpdateDetails) => void, shippingAddress: ShippingAddress}) => void): void;
on(event: 'shippingoptionchange', handler: (response: {updateWith: (options: UpdateDetails) => void, shippingOption: ShippingOption}) => void): void;
on(event: 'shippingaddresschange', handler: (response: { updateWith: (options: UpdateDetails) => void, shippingAddress: ShippingAddress }) => void): void;
on(event: 'shippingoptionchange', handler: (response: { updateWith: (options: UpdateDetails) => void, shippingOption: ShippingOption }) => void): void;
}
}
@@ -615,7 +649,7 @@ declare namespace stripe {
// Cannot find name 'HTMLElement'
mount(domElement: any): void;
on(event: eventTypes, handler: handler): void;
on(event: 'click', handler: (response: {preventDefault: () => void}) => void): void;
on(event: 'click', handler: (response: { preventDefault: () => void }) => void): void;
focus(): void;
blur(): void;
clear(): void;
@@ -718,21 +752,21 @@ declare namespace stripe {
namespace paymentIntents {
type PaymentIntentStatus = 'requires_payment_method'
| 'requires_confirmation'
| 'requires_action'
| 'processing'
| 'requires_capture'
| 'canceled'
| 'succeeded';
| 'requires_confirmation'
| 'requires_action'
| 'processing'
| 'requires_capture'
| 'canceled'
| 'succeeded';
type PaymentIntentCancelationReason = 'duplicate'
| 'fraudulent'
| 'requested_by_customer'
| 'abandoned'
// Generated by Stripe internally:
| 'failed_invoice'
| 'void_invoice'
| 'automatic';
| 'fraudulent'
| 'requested_by_customer'
| 'abandoned'
// Generated by Stripe internally:
| 'failed_invoice'
| 'void_invoice'
| 'automatic';
interface PaymentIntentNextActionRedirectToUrl {
/**
@@ -1324,13 +1358,13 @@ declare namespace stripe {
}
type paymentMethodCardBrand = 'amex'
| 'diners'
| 'discover'
| 'jcb'
| 'mastercard'
| 'unionpay'
| 'visa'
| 'unknown';
| 'diners'
| 'discover'
| 'jcb'
| 'mastercard'
| 'unionpay'
| 'visa'
| 'unknown';
interface PaymentMethodCard {
/**
@@ -1537,4 +1571,156 @@ declare namespace stripe {
verified_name: string;
}
}
namespace setupIntents {
type SetupIntentCancelationReason = 'abandoned'
| 'requested_by_customer'
| 'duplicate';
type SetupIntentStatus = 'requires_payment_method'
| 'requires_confirmation'
| 'requires_action'
| 'processing'
| 'canceled'
| 'succeeded';
interface SetupIntentNextActionRedirectToUrl {
/**
* Type of the next action to perform
*/
type: 'redirect_to_url';
/**
* Contains instructions for authenticating a payment by
* redirecting your customer to another page or application.
*/
redirect_to_url: {
/**
* If the customer does not exit their browser while
* authenticating, they will be redirected to this
* specified URL after completion.
*/
return_url: string;
/**
* The URL you must redirect your customer to in
* order to authenticate.
*/
url: string;
};
}
interface SetupIntentNextActionUseStripeSdk {
/**
* Type of the next action to perform
*/
type: 'use_stripe_sdk';
/**
* When confirming a SetupIntent with Stripe.js, Stripe.js depends on
* the contents of this dictionary to invoke authentication flows. The
* shape of the contents is subject to change and is only intended to
* be used by Stripe.js.
*/
use_stripe_sdk: any;
}
interface SetupIntent {
/**
* Unique identifier for the object.
*/
id: string;
/**
* Value is "setup_intent".
*/
object: 'setup_intent';
/**
* ID of the Connect application that created the SetupIntent.
*/
application: string | null;
/**
* Reason for cancellation of this SetupIntent.
*/
cancelation_reason: SetupIntentCancelationReason | null;
/**
* The client secret of this SetupIntent. Used for client-side retrieval using a publishable key.
* The client secret can be used to complete payment setup from your frontend.
* It should not be stored, logged, embedded in URLs, or exposed to anyone other than the customer.
* Make sure that you have TLS enabled on any page that includes the client secret.
*/
client_secret: string;
/**
* Time at which the object was created. Measured in seconds since the Unix epoch.
*/
created: number;
/**
* ID of the Customer this SetupIntent belongs to, if one exists.
* If present, payment methods used with this SetupIntent can only be attached
* to this Customer, and payment methods attached to other Customers cannot be
* used with this SetupIntent.
*/
customer: string | null;
/**
* An arbitrary string attached to the object. Often useful for displaying to users.
*/
description?: string;
/**
* The error encountered in the previous SetupIntent confirmation.
*/
last_payment_error: Error | null;
/**
* Has the value true if the object exists in live mode or the value
* false if the object exists in test mode.
*/
livemode: boolean;
/**
* Set of key-value pairs that you can attach to an object. This can be
* useful for storing additional information about the object in a structured format.
*/
metadata: Metadata;
/**
* If present, this property tells you what actions you need to take in
* order for your customer to continue payment setup.
*/
next_action: SetupIntentNextActionUseStripeSdk | SetupIntentNextActionRedirectToUrl;
/**
* The account (if any) for which the setup is intended.
*/
on_behalf_of: string | null;
/**
* ID of the payment method used with this SetupIntent.
*/
payment_method: string | null;
/**
* The list of payment method types (e.g. card) that this SetupIntent is allowed to set up.
*/
payment_method_types: string[];
/**
* Status of this SetupIntent
*/
status: SetupIntentStatus;
/**
* Indicates how the payment method is intended to be used in the future.
* Use on_session if you intend to only reuse the payment method
* when the customer is in your checkout flow. Use off_session if your
* customer may or may not be in your checkout flow. If not provided,
* this value defaults to off_session.
*/
usage: 'on_session' | 'off_session';
}
}
}

View File

@@ -57,9 +57,9 @@ describe("Stripe elements", () => {
.then((result: stripe.TokenResponse) => {
console.log(result.token);
},
(error: stripe.Error) => {
console.error(error);
});
(error: stripe.Error) => {
console.error(error);
});
// test 3D secure
const threeDSecureFrame = <HTMLIFrameElement> document.getElementById('3d-secure-frame');
@@ -138,7 +138,7 @@ describe("Stripe elements", () => {
});
});
it ("should use payment request API", () => {
it("should use payment request API", () => {
const paymentRequest = stripe.paymentRequest({
country: 'US',
currency: 'usd',
@@ -156,28 +156,28 @@ describe("Stripe elements", () => {
}
});
paymentRequest.on('token', ev => {
const body = JSON.stringify({token: ev.token.id});
const body = JSON.stringify({ token: ev.token.id });
// post to server...
Promise.resolve({ok: true})
.then(response => {
if (response.ok) {
ev.complete('success');
} else {
ev.complete('fail');
}
});
Promise.resolve({ ok: true })
.then(response => {
if (response.ok) {
ev.complete('success');
} else {
ev.complete('fail');
}
});
});
paymentRequest.on('source', ev => {
const body = JSON.stringify({token: ev.source.id});
const body = JSON.stringify({ token: ev.source.id });
// post to server...
Promise.resolve({ok: true})
.then(response => {
if (response.ok) {
ev.complete('success');
} else {
ev.complete('fail');
}
});
Promise.resolve({ ok: true })
.then(response => {
if (response.ok) {
ev.complete('success');
} else {
ev.complete('fail');
}
});
});
});
@@ -199,7 +199,7 @@ describe("Stripe elements", () => {
it("should use checkout API", () => {
stripe.redirectToCheckout({
items: [
{sku: 'sku_123', quantity: 1}
{ sku: 'sku_123', quantity: 1 }
],
successUrl: 'https://example.com/success',
cancelUrl: 'https://example.com/canceled',
@@ -250,4 +250,26 @@ describe("Stripe elements", () => {
}
});
});
it("should handle card setup", () => {
const card = elements.create('card');
stripe.handleCardSetup(
'pi_18eYalAHEMiOZZp1l9ZTjSU0_secret_NibvRz4PMmJqjfb0sqmT7aq2',
card,
{
payment_method_data: {
billing_details: {
name: 'Jenny Rosen',
},
}
}
).then(result => {
if (result.error) {
console.error(result.error.message);
} else if (result.setupIntent) {
console.log(result.setupIntent.id);
}
});
});
});