mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-22 14:20:58 -04:00
322 lines
9.6 KiB
JavaScript
Vendored
322 lines
9.6 KiB
JavaScript
Vendored
/**
|
|
* Invoice Ninja (https://invoiceninja.com).
|
|
*
|
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
*
|
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
|
*
|
|
* @license https://www.elastic.co/licensing/elastic-license
|
|
*/
|
|
|
|
import { instant, wait } from '../wait';
|
|
|
|
let focusCreditCard = false;
|
|
|
|
function setup() {
|
|
const publicKey = document.querySelector('meta[name=public_key]');
|
|
const gatewayId = document.querySelector('meta[name=gateway_id]');
|
|
const env = document.querySelector('meta[name=environment]');
|
|
const supportedCards = document.querySelector('meta[name=supported_cards]');
|
|
|
|
const widget = new cba.HtmlWidget(
|
|
'#widget',
|
|
publicKey?.content,
|
|
gatewayId?.content
|
|
);
|
|
|
|
widget.setEnv(env?.content);
|
|
widget.useAutoResize();
|
|
|
|
if (supportedCards?.content) {
|
|
try {
|
|
const supportedCardsArray = JSON.parse(supportedCards.content);
|
|
widget.setSupportedCardIcons(supportedCardsArray, true);
|
|
} catch (error) {
|
|
}
|
|
}
|
|
|
|
widget.interceptSubmitForm('#stepone');
|
|
widget.onFinishInsert(
|
|
'#server-response input[name="gateway_response"]',
|
|
'payment_source'
|
|
);
|
|
|
|
widget.setFormFields(['card_name*']);
|
|
widget.reload();
|
|
|
|
let payNow = document.getElementById('pay-now');
|
|
|
|
payNow.disabled = false;
|
|
payNow.querySelector('svg').classList.add('hidden');
|
|
payNow.querySelector('span').classList.remove('hidden');
|
|
|
|
document.querySelector(
|
|
'#server-response input[name="gateway_response"]'
|
|
).value = '';
|
|
|
|
return widget;
|
|
}
|
|
|
|
function reload() {
|
|
document.querySelector('#widget')?.replaceChildren();
|
|
document.querySelector('#widget')?.classList.remove('hidden');
|
|
|
|
document.querySelector('#widget-3dsecure')?.replaceChildren();
|
|
}
|
|
|
|
function pay() {
|
|
reload();
|
|
|
|
const gatewayId = document.querySelector('meta[name=gateway_id]')?.content;
|
|
|
|
if(!gatewayId) {
|
|
|
|
let payNow = document.getElementById('pay-now');
|
|
payNow.disabled = true;
|
|
payNow.querySelector('svg').classList.remove('hidden');
|
|
payNow.querySelector('span').classList.add('hidden');
|
|
document.getElementById(
|
|
'errors'
|
|
).textContent = 'Gateway not found or verified';
|
|
document.getElementById('errors').hidden = false;
|
|
|
|
}
|
|
|
|
const widget = setup();
|
|
|
|
widget.on('finish', () => {
|
|
document.getElementById('errors').hidden = true;
|
|
|
|
process3ds();
|
|
});
|
|
|
|
widget.on('submit', function (data) {
|
|
document.getElementById('errors').hidden = true;
|
|
});
|
|
|
|
let payNow = document.getElementById('pay-now');
|
|
|
|
payNow.addEventListener('click', () => {
|
|
const div = document.getElementById('widget');
|
|
|
|
widget.getValidationState();
|
|
|
|
if (!widget.isValidForm() && div.offsetParent !== null) {
|
|
payNow.disabled = false;
|
|
payNow.querySelector('svg').classList.add('hidden');
|
|
payNow.querySelector('span').classList.remove('hidden');
|
|
|
|
return;
|
|
}
|
|
|
|
payNow.disabled = true;
|
|
payNow.querySelector('svg').classList.remove('hidden');
|
|
payNow.querySelector('span').classList.add('hidden');
|
|
|
|
let storeCard = document.querySelector(
|
|
'input[name=token-billing-checkbox]:checked'
|
|
);
|
|
|
|
if (storeCard) {
|
|
document.getElementById('store_card').value = storeCard.value;
|
|
}
|
|
|
|
if (div.offsetParent !== null)
|
|
document.getElementById('stepone_submit').click();
|
|
else document.getElementById('server-response').submit();
|
|
});
|
|
|
|
document
|
|
.getElementById('toggle-payment-with-credit-card')
|
|
.addEventListener('click', (element) => {
|
|
let widget = document.getElementById('widget');
|
|
|
|
widget.classList.remove('hidden');
|
|
|
|
document.getElementById('save-card--container').style.display =
|
|
'grid';
|
|
document.querySelector('input[name=token]').value = '';
|
|
|
|
document
|
|
.querySelector('#powerboard-payment-container')
|
|
?.classList.remove('hidden');
|
|
});
|
|
|
|
Array.from(
|
|
document.getElementsByClassName('toggle-payment-with-token')
|
|
).forEach((element) =>
|
|
element.addEventListener('click', (element) => {
|
|
document.getElementById('widget').classList.add('hidden');
|
|
document.getElementById('save-card--container').style.display =
|
|
'none';
|
|
document.querySelector('input[name=token]').value =
|
|
element.target.dataset.token;
|
|
|
|
document
|
|
.querySelector('#powerboard-payment-container')
|
|
?.classList.add('hidden');
|
|
})
|
|
);
|
|
|
|
const first = document.querySelector('input[name="payment-type"]');
|
|
|
|
if (first) {
|
|
first.click();
|
|
}
|
|
|
|
if (focusCreditCard) {
|
|
document.getElementById('toggle-payment-with-credit-card')?.click();
|
|
}
|
|
}
|
|
|
|
async function process3ds() {
|
|
try {
|
|
const resource = await get3dsToken();
|
|
|
|
if (
|
|
!resource ||
|
|
!resource.status ||
|
|
resource.status === 'not_authenticated' ||
|
|
resource === 'not_authenticated'
|
|
) {
|
|
focusCreditCard = true;
|
|
|
|
pay();
|
|
|
|
throw new Error(
|
|
'There was an issue authenticating this payment method.'
|
|
);
|
|
}
|
|
|
|
if (resource.status === 'authentication_not_supported') {
|
|
document.querySelector('input[name="browser_details"]').value =
|
|
null;
|
|
|
|
document.querySelector('input[name="charge"]').value =
|
|
JSON.stringify(resource);
|
|
|
|
let storeCard = document.querySelector(
|
|
'input[name=token-billing-checkbox]:checked'
|
|
);
|
|
|
|
if (storeCard) {
|
|
document.getElementById('store_card').value = storeCard.value;
|
|
}
|
|
|
|
return document.getElementById('server-response').submit();
|
|
}
|
|
|
|
const canvas = new cba.Canvas3ds(
|
|
'#widget-3dsecure',
|
|
resource._3ds.token
|
|
);
|
|
canvas.load();
|
|
|
|
let widget = document.getElementById('widget');
|
|
widget.classList.add('hidden');
|
|
|
|
canvas.on('chargeAuthSuccess', function (data) {
|
|
document.querySelector('input[name="browser_details"]').value =
|
|
null;
|
|
|
|
document.querySelector('input[name="charge"]').value =
|
|
JSON.stringify(data);
|
|
|
|
let storeCard = document.querySelector(
|
|
'input[name=token-billing-checkbox]:checked'
|
|
);
|
|
|
|
if (storeCard) {
|
|
document.getElementById('store_card').value = storeCard.value;
|
|
}
|
|
|
|
document.getElementById('server-response').submit();
|
|
});
|
|
|
|
canvas.on('chargeAuthReject', function (data) {
|
|
document.getElementById(
|
|
'errors'
|
|
).textContent = `Sorry, your transaction could not be processed...`;
|
|
document.getElementById('errors').hidden = false;
|
|
|
|
focusCreditCard = true;
|
|
|
|
pay();
|
|
});
|
|
|
|
canvas.load();
|
|
} catch (error) {
|
|
|
|
const msg = error.message ?? 'Unknown error.';
|
|
|
|
document.getElementById(
|
|
'errors'
|
|
).textContent = `Sorry, your transaction could not be processed...\n\n${msg}`;
|
|
document.getElementById('errors').hidden = false;
|
|
|
|
focusCreditCard = true;
|
|
|
|
pay();
|
|
}
|
|
}
|
|
|
|
async function get3dsToken() {
|
|
const browserDetails = {
|
|
name: navigator.userAgent.substring(0, 100), // The full user agent string, which contains the browser name and version
|
|
java_enabled: navigator.javaEnabled() ? 'true' : 'false', // Indicates if Java is enabled in the browser
|
|
language: navigator.language || navigator.userLanguage, // The browser language
|
|
screen_height: window.screen.height.toString(), // Screen height in pixels
|
|
screen_width: window.screen.width.toString(), // Screen width in pixels
|
|
time_zone: (new Date().getTimezoneOffset() * -1).toString(), // Timezone offset in minutes (negative for behind UTC)
|
|
color_depth: window.screen.colorDepth.toString(), // Color depth in bits per pixel
|
|
};
|
|
|
|
document.querySelector('input[name="browser_details"]').value =
|
|
JSON.stringify(browserDetails);
|
|
|
|
const formData = JSON.stringify(
|
|
Object.fromEntries(
|
|
new FormData(document.getElementById('server-response'))
|
|
)
|
|
);
|
|
|
|
const paymentsRoute = document.querySelector('meta[name=payments_route]');
|
|
|
|
try {
|
|
// Return the fetch promise to handle it externally
|
|
const response = await fetch(paymentsRoute.content, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
Accept: 'application/json',
|
|
'X-CSRF-Token': document.querySelector(
|
|
'meta[name="csrf-token"]'
|
|
).content,
|
|
},
|
|
body: formData,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
return await response.json().then((errorData) => {
|
|
throw new Error(errorData.message ?? 'Unknown error.');
|
|
});
|
|
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
|
|
document.getElementById(
|
|
'errors'
|
|
).textContent = `Sorry, your transaction could not be processed...\n\n${error.message}`;
|
|
document.getElementById('errors').hidden = false;
|
|
|
|
focusCreditCard = true;
|
|
|
|
pay();
|
|
}
|
|
}
|
|
|
|
instant() ? pay() : wait('#powerboard-credit-card-payment').then(() => pay());
|