Skip to content
Snippets Groups Projects
Commit fe431c85 authored by bird's avatar bird
Browse files

chore: cleanup payment form

parent 78bcbd1b
1 merge request!12Integrate new Square Payments API
...@@ -7,159 +7,156 @@ ...@@ -7,159 +7,156 @@
<script type="text/javascript" src="web.squarecdn.com/v1/square.js"></script> <script type="text/javascript" src="web.squarecdn.com/v1/square.js"></script>
{# bring the location IDs into javascript so the next bits know about them #} {# bring the location IDs into javascript so the next bits know about them #}
<script type="text/javascript"> <script type="text/javascript">
var appId = "{{ app_id }}";
var locationId = "{{ loc_id }}";
var amount = "{{ payment.amount }}";
async function initializeCard(payments) {
const card = await payments.card();
await card.attach('#card-container');
return card;
}
// Call this function to send a payment token, buyer name, and other details
// to the project server code so that a payment can be created with
// Payments API
async function createPayment(token, verificationToken) {
const csrfToken = document.querySelector('input[name=csrfmiddlewaretoken]').value;
const body = JSON.stringify({
locationId,
sourceId: token,
verificationToken: verificationToken,
});
// if (verificationToken !== undefined) { var appId = "{{ app_id }}";
// body.verificationToken = verificationToken; var locationId = "{{ loc_id }}";
// } var amount = "{{ payment.amount }}";
const paymentResponse = await fetch(location.href, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken,
},
body,
credentials: 'same-origin',
});
return paymentResponse.json(); async function initializeCard(payments) {
} const card = await payments.card();
await card.attach('#card-container');
// This function tokenizes a payment method. return card;
// The ‘error’ thrown from this async function denotes a failed tokenization,
// which is due to buyer error (such as an expired card). It is up to the
// developer to handle the error and provide the buyer the chance to fix
// their mistakes.
async function tokenize(paymentMethod) {
const tokenResult = await paymentMethod.tokenize();
if (tokenResult.status === 'OK') {
return tokenResult.token;
} else {
let errorMessage = `Tokenization failed-status: ${tokenResult.status}`;
if (tokenResult.errors) {
errorMessage += ` and errors: ${JSON.stringify(
tokenResult.errors
)}`;
}
throw new Error(errorMessage);
} }
}
async function verifyBuyer(payments, token) {
const verificationDetails = {
amount: '{{ payment.amount }}',
/* collected from the buyer */
billingContact: {},
currencyCode: 'AUD',
intent: 'CHARGE',
};
const verificationResults = await payments.verifyBuyer(
token,
verificationDetails
);
return verificationResults.token;
}
// Helper method for displaying the Payment Status on the screen.
// status is either SUCCESS or FAILURE;
function displayPaymentResults(status) {
const cardButton = document.getElementById(
'card-button'
);
if (status === 'SUCCESS') {
cardButton.classList.remove('failure');
cardButton.classList.add('success');
cardButton.innerText = 'Payment successful! Redirecting...';
} else {
cardButton.classList.remove('success');
cardButton.classList.add('failure');
cardButton.innerText = 'Payment failed :( Refreshing...';
}
}
// Call this function to send a payment token, buyer name, and other details
// to the project server code so that a payment can be created with
// Payments API
async function createPayment(token, verificationToken) {
const csrfToken = document.querySelector('input[name=csrfmiddlewaretoken]').value;
const body = JSON.stringify({
locationId,
sourceId: token,
verificationToken: verificationToken,
});
const paymentResponse = await fetch(location.href, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken,
},
body,
credentials: 'same-origin',
});
return paymentResponse.json();
}
document.addEventListener('DOMContentLoaded', async function() { // This function tokenizes a payment method.
const loader = document.getElementById('spinner'); // The ‘error’ thrown from this async function denotes a failed tokenization,
const cardButton = document.getElementById( // which is due to buyer error (such as an expired card). It is up to the
'card-button' // developer to handle the error and provide the buyer the chance to fix
); // their mistakes.
async function tokenize(paymentMethod) {
const tokenResult = await paymentMethod.tokenize();
if (tokenResult.status === 'OK') {
return tokenResult.token;
} else {
let errorMessage = `Tokenization failed-status: ${tokenResult.status}`;
if (tokenResult.errors) {
errorMessage += ` and errors: ${JSON.stringify(
tokenResult.errors
)}`;
}
throw new Error(errorMessage);
}
}
cardButton.disabled = true; async function verifyBuyer(payments, token) {
if (!window.Square) { const verificationDetails = {
throw new Error('Square.js failed to load properly'); amount: '{{ payment.amount }}',
/* collected from the buyer */
billingContact: {},
currencyCode: 'AUD',
intent: 'CHARGE',
};
const verificationResults = await payments.verifyBuyer(
token,
verificationDetails
);
return verificationResults.token;
} }
const payments = window.Square.payments(appId, locationId);
let card; // Helper method for displaying the Payment Status on the screen.
try { // status is either SUCCESS or FAILURE;
card = await initializeCard(payments); function displayPaymentResults(status) {
loader.style.display = 'none'; const cardButton = document.getElementById(
cardButton.disabled = false; 'card-button'
} catch (e) { );
console.error('Initializing Card failed', e); if (status === 'SUCCESS') {
return; cardButton.classList.remove('failure');
cardButton.classList.add('success');
cardButton.innerText = 'Payment successful! Redirecting...';
} else {
cardButton.classList.remove('success');
cardButton.classList.add('failure');
cardButton.innerText = 'Payment failed :( Refreshing...';
}
} }
async function handlePaymentMethodSubmission(event, paymentMethod, shouldVerify = true) {
event.preventDefault(); document.addEventListener('DOMContentLoaded', async function () {
const token = await tokenize(paymentMethod); const loader = document.getElementById('spinner');
const cardButton = document.getElementById(
'card-button'
);
cardButton.disabled = true; cardButton.disabled = true;
cardButton.innerText = "Processing..."; if (!window.Square) {
throw new Error('Square.js failed to load properly');
let verificationToken;
if (shouldVerify) {
verificationToken = await verifyBuyer(
payments,
token
);
} }
const payments = window.Square.payments(appId, locationId);
const paymentResults = await createPayment(token, verificationToken); let card;
if (paymentResults.success) { try {
displayPaymentResults('SUCCESS'); card = await initializeCard(payments);
setTimeout( loader.style.display = 'none';
function(){window.location.href = "{{ payment.completed_url }}";}, 3000
);
} else {
cardButton.disabled = false; cardButton.disabled = false;
displayPaymentResults('FAILURE'); } catch (e) {
console.error(paymentResults.errors); console.error('Initializing Card failed', e);
setTimeout( return;
function(){window.location.href = "{{ payment.completed_url }}";}, 3000
);
} }
console.debug('Payment Success', paymentResults);
} async function handlePaymentMethodSubmission(event, paymentMethod, shouldVerify = true) {
event.preventDefault();
const token = await tokenize(paymentMethod);
cardButton.disabled = true;
cardButton.innerText = "Processing...";
let verificationToken;
if (shouldVerify) {
verificationToken = await verifyBuyer(
payments,
token
);
}
const paymentResults = await createPayment(token, verificationToken);
if (paymentResults.success) {
displayPaymentResults('SUCCESS');
setTimeout(
function () { window.location.href = "{{ payment.completed_url }}"; }, 3000
);
} else {
cardButton.disabled = false;
displayPaymentResults('FAILURE');
console.error(paymentResults.errors);
setTimeout(
function () { window.location.href = "{{ payment.completed_url }}"; }, 3000
);
}
console.debug('Payment Success', paymentResults);
cardButton.addEventListener('click', async function(event) { }
await handlePaymentMethodSubmission(event, card, true);
}); cardButton.addEventListener('click', async function (event) {
await handlePaymentMethodSubmission(event, card, true);
});
}); });
</script> </script>
<link rel="stylesheet" type="text/css" href="{% static 'squarepay.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'squarepay.css' %}">
...@@ -173,16 +170,16 @@ document.addEventListener('DOMContentLoaded', async function() { ...@@ -173,16 +170,16 @@ document.addEventListener('DOMContentLoaded', async function() {
<div class="form-header"> <div class="form-header">
<span class="tips {% if payment.is_paid %}error{% endif %}">{% block tips %} <span class="tips {% if payment.is_paid %}error{% endif %}">{% block tips %}
{% if payment.is_paid %} {% if payment.is_paid %}
<p><b>It appears you have already successfully attempted this payment.</b> <p><b>It appears you have already successfully attempted this payment.</b>
{% if payment.completed_url %} {% if payment.completed_url %}
<br><br>Perhaps you were meaning to find <a href="{{ payment.completed_url }}">this page</a>. <br><br>Perhaps you were meaning to find <a href="{{ payment.completed_url }}">this page</a>.
{% endif %} {% endif %}
</p> </p>
{% else %} {% else %}
<b><i>Please fill in your card details below.</i></b> <b><i>Please fill in your card details below.</i></b>
{% endif %} {% endif %}
</span> </span>
{% endblock %} {% endblock %}
<noscript> <noscript>
<span class="tips error">Please enable javascript to use the payment form.</span> <span class="tips error">Please enable javascript to use the payment form.</span>
...@@ -203,7 +200,12 @@ document.addEventListener('DOMContentLoaded', async function() { ...@@ -203,7 +200,12 @@ document.addEventListener('DOMContentLoaded', async function() {
<div id="form-container" class="payment-info"> <div id="form-container" class="payment-info">
<div class="float-container"> <div class="float-container">
{% csrf_token %} {% csrf_token %}
<div id=spinner class="lds-ellipsis" id="payment-form"><div></div><div></div><div></div><div></div></div> <div id=spinner class="lds-ellipsis" id="payment-form">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<form id="payment-form"> <form id="payment-form">
<div id="card-container"></div> <div id="card-container"></div>
<button id="card-button" type="button">Pay {{ amount }}</button> <button id="card-button" type="button">Pay {{ amount }}</button>
...@@ -213,4 +215,4 @@ document.addEventListener('DOMContentLoaded', async function() { ...@@ -213,4 +215,4 @@ document.addEventListener('DOMContentLoaded', async function() {
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment