-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix confirmCardPayment in localstripe-v3.js and add an example
I wanted to add an example of using localstripe-v3.js, as a way of testing #240 and also because it seems generally useful as documentation. The example includes a --real-stripe argument so you can quickly compare the real (test) Stripe API and Stripe.js against localstripe. Along the way I discovered confirmCardPayment isn't quite right; it skips /confirm and goes right to /_authenticate. This fails on cards that don't require 3D Secure authentication because the /_authenticate endpoint is confused about why it's being called at all. I fixed this, modeled on how confirmCardSetup works. This in turn required a small fix to the localstripe backend to allow calls to /confirm from the browser (i.e., with a client_secret and key as form data).
- Loading branch information
Ben Creech
committed
Nov 10, 2024
1 parent
6b0ff20
commit ecef02f
Showing
9 changed files
with
372 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
localstripe sample: Set up a payment method for future payments | ||
=============================================================== | ||
|
||
This is a demonstration of how to inject localstripe for testing a simplistic | ||
client/server Stripe web integration. This is derived from the Stripe | ||
instructions for collecting payment methods on a single-page web app. | ||
|
||
**This sample is not intended to represent best practice for production code!** | ||
|
||
From the localstripe directory... | ||
|
||
.. code:: shell | ||
# Launch localstripe: | ||
python -m localstripe --from-scratch & | ||
# Launch this sample's server: | ||
python -m samples.pm_setup.server | ||
# ... now browse to http://0.0.0.0:8080 and try the test card | ||
# 4242424242424242. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<head> | ||
<title> | ||
localstripe sample: Set up a payment method for future payments | ||
</title> | ||
<!-- this is a proxy script which chooses whether to load the real Stripe.js | ||
or localstripe's mock: --> | ||
<script src="stripe.js"></script> | ||
<script type="module" src="pm_setup.js"></script> | ||
</head> | ||
<body> | ||
<h1> | ||
localstripe sample: Set up a payment method for future payments | ||
</h1> | ||
<form id="setup-form"> | ||
<button id="setup-submit">Start adding a payment method!</button> | ||
</form> | ||
<fieldset disabled="disabled" id="payment-method-form-fieldset"> | ||
<form id="payment-method-form"> | ||
<p>Enter your (test) card information:</p> | ||
<div id="payment-method-element"></div> | ||
<button id="payment-method-submit">Submit</button> | ||
<div id="payment-method-result-message"></div> | ||
</form> | ||
</fieldset> | ||
<fieldset disabled="disabled" id="payment-form-fieldset"> | ||
<form id="payment-form"> | ||
<label for="payment-amount">Make a payment in cents:</label> | ||
<input id="payment-amount" name="amount" type="number"/> | ||
<button id="payment-submit">Submit</button> | ||
<div id="payment-result-message"></div> | ||
</form> | ||
</fieldset> | ||
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
let seti; | ||
let setiClientSecret; | ||
let stripe; | ||
let paymentElement; | ||
|
||
const init = async () => { | ||
const response = await fetch('/publishable_key', {method: "GET"}); | ||
const { | ||
stripe_api_pk: publishableKey, | ||
} = await response.json(); | ||
|
||
stripe = Stripe(publishableKey); | ||
|
||
document.getElementById( | ||
'setup-form', | ||
).addEventListener('submit', handleSetupSubmit); | ||
|
||
document.getElementById( | ||
'payment-method-form', | ||
).addEventListener('submit', handlePaymentMethodSubmit); | ||
|
||
document.getElementById( | ||
'payment-form', | ||
).addEventListener('submit', handlePaymentSubmit); | ||
} | ||
|
||
const handleSetupSubmit = async (event) => { | ||
event.preventDefault(); | ||
|
||
const response = await fetch('/setup_intent', {method: "POST"}); | ||
const { | ||
id: id, | ||
client_secret: clientSecret, | ||
} = await response.json(); | ||
|
||
seti = id; | ||
setiClientSecret = clientSecret; | ||
|
||
const elements = stripe.elements({ | ||
clientSecret: clientSecret, | ||
}); | ||
|
||
paymentElement = elements.create('card'); | ||
|
||
paymentElement.mount('#payment-method-element'); | ||
|
||
document.getElementById( | ||
'payment-method-form-fieldset', | ||
).removeAttribute('disabled'); | ||
} | ||
|
||
let handlePaymentMethodSubmit = async (event) => { | ||
event.preventDefault(); | ||
|
||
const {error} = await stripe.confirmCardSetup(setiClientSecret, { | ||
payment_method: { | ||
card: paymentElement, | ||
}, | ||
}); | ||
|
||
const container = document.getElementById('payment-method-result-message'); | ||
if (error) { | ||
container.textContent = error.message; | ||
} else { | ||
const response = await fetch('/payment_method', { | ||
method: "POST", | ||
body: JSON.stringify({ setup_intent: seti }) | ||
}); | ||
if (response.ok) { | ||
container.textContent = "Successfully confirmed payment method!"; | ||
document.getElementById( | ||
'payment-form-fieldset', | ||
).removeAttribute('disabled'); | ||
} else { | ||
container.textContent = "Error confirming payment method!"; | ||
} | ||
} | ||
}; | ||
|
||
let handlePaymentSubmit = async (event) => { | ||
event.preventDefault(); | ||
|
||
const response = await fetch('/payment_intent', { | ||
method: "POST", | ||
body: JSON.stringify({ | ||
amount: document.getElementById('payment-amount').value, | ||
}) | ||
}); | ||
const {client_secret: clientSecret} = await response.json(); | ||
|
||
const {error} = await stripe.confirmCardPayment(clientSecret, {}); | ||
|
||
const container = document.getElementById('payment-result-message'); | ||
if (error) { | ||
container.textContent = error.message; | ||
} else { | ||
container.textContent = "Successfully confirmed payment!"; | ||
} | ||
}; | ||
|
||
await init(); |
Oops, something went wrong.