Skip to content

Commit

Permalink
Merge branch 'master' into dawn-use-setup-intent-in-usage-based-subsc…
Browse files Browse the repository at this point in the history
…riptions
  • Loading branch information
dawn-stripe authored Jul 14, 2020
2 parents dd37fa2 + 2d3cbb0 commit 80b2497
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 37 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ See a hosted version of the [sample](https://xt7b9.sse.codesandbox.io/) in test

The hosted demo is running in test mode -- use `4242424242424242` as a test card number with any CVC + future expiration date.

Use the `4000000000003220` test card number to trigger a 3D Secure challenge flow.
Use the `4000002500003155` test card number to trigger a 3D Secure challenge flow.

Read more about test cards on Stripe at https://stripe.com/docs/testing.

Expand Down
2 changes: 1 addition & 1 deletion fixed-price-subscriptions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ See a hosted version of the [sample](https://xt7b9.sse.codesandbox.io/) in test

The hosted demo is running in test mode -- use `4242424242424242` as a test card number with any CVC + future expiration date.

Use the `4000000000003220` test card number to trigger a 3D Secure challenge flow.
Use the `4000002500003155` test card number to trigger a 3D Secure challenge flow.

Read more about test cards on Stripe at https://stripe.com/docs/testing.

Expand Down
8 changes: 7 additions & 1 deletion fixed-price-subscriptions/client/react/src/Account.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ function Account({ location }) {
}

function cancelSubscription() {
console.log(accountInformation.subscription);
fetch('/cancel-subscription', {
method: 'post',
headers: {
Expand All @@ -81,6 +82,11 @@ function Account({ location }) {
});
}

function resetDemo() {
localStorage.clear();
window.location.href = '/';
}

return (
<div className="p-6">
<TopNavigationBar />
Expand All @@ -93,7 +99,7 @@ function Account({ location }) {
<button
className="bg-pasha hover:bg-white hover:shadow-outline hover:text-pasha hover:border hover:border-black focus:shadow-outline text-white focus:bg-white focus:text-pasha font-light py-2 px-4 rounded"
type="button"
onClick={() => (window.location.href = '/')}
onClick={() => resetDemo()}
>
Restart demo
</button>
Expand Down
105 changes: 91 additions & 14 deletions fixed-price-subscriptions/client/react/src/PaymentForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ const CheckoutForm = ({ productSelected, customer }) => {
const elements = useElements();
const [subscribing, setSubscribing] = useState(false);
const [accountInformation, setAccountInformation] = useState(null);
let [errorToDisplay, setErrorToDisplay] = useState('');

function handleCustomerActionRequired({
function handlePaymentThatRequiresCustomerAction({
subscription,
invoice,
priceId,
Expand Down Expand Up @@ -79,7 +80,7 @@ const CheckoutForm = ({ productSelected, customer }) => {
}
}

function handlePaymentMethodRequired({
function handleRequiresPaymentMethod({
subscription,
paymentMethodId,
priceId,
Expand All @@ -99,17 +100,75 @@ const CheckoutForm = ({ productSelected, customer }) => {
'latestInvoicePaymentIntentStatus',
subscription.latest_invoice.payment_intent.status
);
throw new Error({ error: { message: 'Your card was declined.' } });
throw new Error('Your card was declined.');
} else {
return { subscription, priceId, paymentMethodId };
}
}

function retryInvoiceWithNewPaymentMethod({ paymentMethodId, invoiceId }) {
const priceId = productSelected.name.toUpperCase();
return (
fetch('/retry-invoice', {
method: 'post',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({
customerId: customer.id,
paymentMethodId: paymentMethodId,
invoiceId: invoiceId,
}),
})
.then((response) => {
return response.json();
})
// If the card is declined, display an error to the user.
.then((result) => {
if (result.error) {
// The card had an error when trying to attach it to a customer.
throw result;
}
return result;
})
// Normalize the result to contain the object returned by Stripe.
// Add the addional details we need.
.then((result) => {
return {
// Use the Stripe 'object' property on the
// returned result to understand what object is returned.
invoice: result,
paymentMethodId: paymentMethodId,
priceId: priceId,
isRetry: true,
};
})
// Some payment methods require a customer to be on session
// to complete the payment process. Check the status of the
// payment intent to handle these actions.
.then(handlePaymentThatRequiresCustomerAction)
// No more actions required. Provision your service for the user.
.then(onSubscriptionComplete)
.catch((error) => {
console.log(error);
// An error has happened. Display the failure to the user here.
setSubscribing(false);
setErrorToDisplay(error && error.error && error.error.decline_code);
})
);
}

function onSubscriptionComplete(result) {
console.log(result);
// Payment was successful. Provision access to your service.
// Remove invoice from localstorage because payment is now complete.
// clearCache();
if (result && !result.subscription) {
const subscription = { id: result.invoice.subscription };
result.subscription = subscription;
localStorage.clear();
}

setAccountInformation(result);
// Change your UI to show a success message to your customer.
// onSubscriptionSampleDemoComplete(result);
Expand Down Expand Up @@ -157,18 +216,18 @@ const CheckoutForm = ({ productSelected, customer }) => {
// Some payment methods require a customer to do additional
// authentication with their financial institution.
// Eg: 2FA for cards.
.then(handleCustomerActionRequired)
.then(handlePaymentThatRequiresCustomerAction)
// If attaching this card to a Customer object succeeds,
// but attempts to charge the customer fail. You will
// get a requires_payment_method error.
.then(handlePaymentMethodRequired)
.then(handleRequiresPaymentMethod)
// No more actions required. Provision your service for the user.
.then(onSubscriptionComplete)
.catch((error) => {
// An error has happened. Display the failure to the user here.
// We utilize the HTML element we created.
console.log(error);
// displayError(error);
setSubscribing(false);
setErrorToDisplay(error.message || error.error.decline_code);
})
);
}
Expand All @@ -190,17 +249,37 @@ const CheckoutForm = ({ productSelected, customer }) => {
// each type of element.
const cardElement = elements.getElement(CardElement);

// If a previous payment was attempted, get the lastest invoice
const latestInvoicePaymentIntentStatus = localStorage.getItem(
'latestInvoicePaymentIntentStatus'
);

// Use your card Element with other Stripe.js APIs
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});

if (error) {
console.log('[error]', error);
console.log('[createPaymentMethod error]', error);
setSubscribing(false);
setErrorToDisplay(error && error.message);
} else {
console.log('[PaymentMethod]', paymentMethod);
createSubscription({ paymentMethodId: paymentMethod.id });
const paymentMethodId = paymentMethod.id;
if (latestInvoicePaymentIntentStatus === 'requires_payment_method') {
// Update the payment method and retry invoice payment
const invoiceId = localStorage.getItem('latestInvoiceId');
retryInvoiceWithNewPaymentMethod({
paymentMethodId: paymentMethodId,
invoiceId: invoiceId,
});
} else {
// Create the subscription
createSubscription({
paymentMethodId: paymentMethodId,
});
}
}
};

Expand Down Expand Up @@ -273,11 +352,9 @@ const CheckoutForm = ({ productSelected, customer }) => {
}}
/>
</div>
<div
id="card-element-errors"
className="text-gray-700 text-base mt-2"
role="alert"
></div>
<div className="text-gray-700 text-base mt-2" role="alert">
{errorToDisplay ? errorToDisplay : null}
</div>
</div>
</div>
<button
Expand Down
10 changes: 5 additions & 5 deletions fixed-price-subscriptions/client/vanillajs/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ function createCustomer() {
});
}

function handleCustomerActionRequired({
function handlePaymentThatRequiresCustomerAction({
subscription,
invoice,
priceId,
Expand Down Expand Up @@ -311,7 +311,7 @@ function handleCustomerActionRequired({
}
}

function handlePaymentMethodRequired({
function handleRequiresPaymentMethod({
subscription,
paymentMethodId,
priceId,
Expand Down Expand Up @@ -387,11 +387,11 @@ function createSubscription({ customerId, paymentMethodId, priceId }) {
// Some payment methods require a customer to do additional
// authentication with their financial institution.
// Eg: 2FA for cards.
.then(handleCustomerActionRequired)
.then(handlePaymentThatRequiresCustomerAction)
// If attaching this card to a Customer object succeeds,
// but attempts to charge the customer fail. You will
// get a requires_payment_method error.
.then(handlePaymentMethodRequired)
.then(handleRequiresPaymentMethod)
// No more actions required. Provision your service for the user.
.then(onSubscriptionComplete)
.catch((error) => {
Expand Down Expand Up @@ -446,7 +446,7 @@ function retryInvoiceWithNewPaymentMethod({
// Some payment methods require a customer to be on session
// to complete the payment process. Check the status of the
// payment intent to handle these actions.
.then(handleCustomerActionRequired)
.then(handlePaymentThatRequiresCustomerAction)
// No more actions required. Provision your service for the user.
.then(onSubscriptionComplete)
.catch((error) => {
Expand Down
6 changes: 3 additions & 3 deletions fixed-price-subscriptions/server/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"scripts": {
"server": "node server.js",
"reactClient": "cd ../../client/react && npm start",
"startReact": "concurrently \"npm run reactClient\" \"npm run server\"",
"startVanillajs": "npm run server",
"start": "npm run server",
"startReact": "concurrently \"yarn reactClient\" \"yarn server\"",
"startVanillajs": "yarn server",
"start": "yarn server",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "stripe-demos",
Expand Down
2 changes: 1 addition & 1 deletion per-seat-subscriptions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ See a hosted version of the [sample](https://fqizg.sse.codesandbox.io/) in test

The hosted demo is running in test mode -- use `4242424242424242` as a test card number with any CVC + future expiration date.

Use the `4000000000003220` test card number to trigger a 3D Secure challenge flow.
Use the `4000002500003155` test card number to trigger a 3D Secure challenge flow.

Read more about test cards on Stripe at https://stripe.com/docs/testing.

Expand Down
10 changes: 5 additions & 5 deletions per-seat-subscriptions/client/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ function createCustomer() {
});
}

function handleCustomerActionRequired({
function handlePaymentThatRequiresCustomerAction({
subscription,
invoice,
priceId,
Expand Down Expand Up @@ -373,7 +373,7 @@ function handleCustomerActionRequired({
}
}

function handlePaymentMethodRequired({
function handleRequiresPaymentMethod({
subscription,
paymentMethodId,
priceId,
Expand Down Expand Up @@ -450,11 +450,11 @@ function createSubscription(customerId, paymentMethodId, priceId, quantity) {
// Some payment methods require a customer to do additional
// authentication with their financial institution.
// Eg: 2FA for cards.
.then(handleCustomerActionRequired)
.then(handlePaymentThatRequiresCustomerAction)
// If attaching this card to a Customer object succeeds,
// but attempts to charge the customer fail. You will
// get a requires_payment_method error.
.then(handlePaymentMethodRequired)
.then(handleRequiresPaymentMethod)
// No more actions required. Provision your service for the user.
.then(onSubscriptionComplete)
.catch((error) => {
Expand Down Expand Up @@ -509,7 +509,7 @@ function retryInvoiceWithNewPaymentMethod(
// Some payment methods require a customer to be on session
// to complete the payment process. Check the status of the
// payment intent to handle these actions.
.then(handleCustomerActionRequired)
.then(handlePaymentThatRequiresCustomerAction)
// No more actions required. Provision your service for the user.
.then(onSubscriptionComplete)
.catch((error) => {
Expand Down
2 changes: 1 addition & 1 deletion usage-based-subscriptions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ See a hosted version of the [sample](https://l2sny.sse.codesandbox.io/) in test

The hosted demo is running in test mode -- use `4242424242424242` as a test card number with any CVC + future expiration date.

Use the `4000000000003220` test card number to trigger a 3D Secure challenge flow.
Use the `4000002500003155` test card number to trigger a 3D Secure challenge flow.

Read more about test cards on Stripe at https://stripe.com/docs/testing.

Expand Down
10 changes: 5 additions & 5 deletions usage-based-subscriptions/client/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ function handleCardSetupRequired({
}


function handleCustomerActionRequired({
function handlePaymentThatRequiresCustomerAction({
subscription,
invoice,
priceId,
Expand Down Expand Up @@ -348,7 +348,7 @@ function handleCustomerActionRequired({
}
}

function handlePaymentMethodRequired({
function handleRequiresPaymentMethod({
subscription,
paymentMethodId,
priceId,
Expand Down Expand Up @@ -425,11 +425,11 @@ function createSubscription(customerId, paymentMethodId, priceId) {
// authentication with their financial institution.
// Eg: 2FA for cards.
.then(handleCardSetupRequired)
.then(handleCustomerActionRequired)
.then(handlePaymentThatRequiresCustomerAction)
// If attaching this card to a Customer object succeeds,
// but attempts to charge the customer fail. You will
// get a requires_payment_method error.
.then(handlePaymentMethodRequired)
.then(handleRequiresPaymentMethod)
// No more actions required. Provision your service for the user.
.then(onSubscriptionComplete)
.catch((error) => {
Expand Down Expand Up @@ -484,7 +484,7 @@ function retryInvoiceWithNewPaymentMethod(
// Some payment methods require a customer to be on session
// to complete the payment process. Check the status of the
// payment intent to handle these actions.
.then(handleCustomerActionRequired)
.then(handlePaymentThatRequiresCustomerAction)
// No more actions required. Provision your service for the user.
.then(onSubscriptionComplete)
.catch((error) => {
Expand Down

0 comments on commit 80b2497

Please sign in to comment.