Add new payment and shipping parsers for various integrations

- Implemented Google Pay parser in bongooglepay.js
- Added Buckaroo 3 payment parser in buckaroo3.js
- Introduced DataTrans CW Mastercard parser in datatranscw.js
- Created DataTrans CW Credit Card parser in datatranscw_creditcard.js
- Developed DHL Assistant shipping parser in dhlassistant.js
- Added Estimated Delivery parser in estimateddelivery.js
- Implemented Floapay payment parser in floapay.js
- Created FS Pickup at Store shipping parser in fspickupatstore.js
- Developed Generic Iframe parser in generic_iframe_parser.js
- Added Geodis Officiel shipping parser in geodisofficiel.js
- Implemented Glob Kurier module shipping parser in globkuriermodule.js
- Created Latvija Post Express Pickup Terminal parser in latvijaspastsexpresspastspostterminalslv.js
- Developed LP Shipping parser in lpshipping.js
- Added Mijora Venipak parser in mijoravenipak.js
- Implemented Apple Pay parser in pm_applepay.js
- Created Przelewy24 payment parser in przelewy24.js
- Developed Pshugls shipping parser in pshugls.js
- Added Redsys Insite payment parser in redsysinsite.js
- Implemented Tpay payment parser in tpay.js
- Updated third-party integration documentation for FedEx DotCom
This commit is contained in:
2025-08-04 23:10:27 +02:00
parent 037a6c5551
commit d39433f0d4
125 changed files with 4986 additions and 1772 deletions

View File

@@ -93,7 +93,7 @@ $(document).ready(function () {
checkAndHideGlobalError();
});
$('body').on('change', '#js-delivery input', function () {
$('body').on('change', '#js-delivery .shipping-radio input', function () {
selectDeliveryOption($('#js-delivery')); // delivery form object as parameter
});
@@ -190,6 +190,12 @@ $(document).ready(function () {
});
$('body').on('change', '[data-link-action=x-ship-to-different-address]', function () {
// Hook to this:
// prestashop.on('thecheckout_changeSecondAddress', function(data) { console.log('second address block toggled!', data); })
prestashop.emit('thecheckout_changeSecondAddress', {
'addressType': 'delivery',
'isCollapsing': $('#thecheckout-address-delivery').is(':visible')
});
if ($('#thecheckout-address-delivery').is(':visible')) {
$(this).prop('checked', false);
@@ -210,6 +216,11 @@ $(document).ready(function () {
});
$('body').on('change', '[data-link-action=x-bill-to-different-address]', function () {
prestashop.emit('thecheckout_changeSecondAddress', {
'addressType': 'invoice',
'isCollapsing': $('#thecheckout-address-invoice').is(':visible')
});
if ($('#thecheckout-address-invoice').is(':visible')) {
$(this).prop('checked', false);
$('#thecheckout-address-invoice').hide(10, function () {
@@ -256,6 +267,7 @@ $(document).ready(function () {
if ($('#dni-placeholder').length && $('#thecheckout-address-invoice .business-field.dni').length) {
swapElements($('#dni-placeholder'), $('#thecheckout-address-invoice .business-field.dni'));
}
removeError('.business-private-checkboxes > .error-msg');
return false;
});
@@ -280,6 +292,7 @@ $(document).ready(function () {
if ($('#dni-placeholder-delivery').length && $('#thecheckout-address-delivery .business-field.dni').length) {
swapElements($('#dni-placeholder-delivery'), $('#thecheckout-address-delivery .business-field.dni'));
}
removeError('.business-private-checkboxes > .error-msg');
return false;
});
@@ -304,6 +317,7 @@ $(document).ready(function () {
if ($('#dni-placeholder-private').length && $('#thecheckout-address-invoice .private-field.dni').length) {
swapElements($('#dni-placeholder-private'), $('#thecheckout-address-invoice .private-field.dni'));
}
removeError('.business-private-checkboxes > .error-msg');
return false;
});
@@ -328,10 +342,37 @@ $(document).ready(function () {
if ($('#dni-placeholder-private-delivery').length && $('#thecheckout-address-delivery .private-field.dni').length) {
swapElements($('#dni-placeholder-private-delivery'), $('#thecheckout-address-delivery .private-field.dni'));
}
removeError('.business-private-checkboxes > .error-msg');
return false;
});
$('body').on('change', '[data-link-action^=x-i-am-private],[data-link-action^=x-i-am-business]', function () {
const linkAction = $(this).data('link-action');
const isBusiness = linkAction.startsWith('x-i-am-business');
const addressType = linkAction.endsWith('delivery') ? 'delivery' : 'invoice';
const isChecked = $(this).prop('checked');
// prestashop.on('thecheckout_businessPrivateChecked', function(data) { console.log('business or private checkbox selected!', data); })
prestashop.emit('thecheckout_businessPrivateChecked', {
addressType, isBusiness, isChecked
});
return false;
});
if (config_use_other_for_business_private) {
prestashop.on('thecheckout_businessPrivateChecked', function (data) {
const field = $(`#thecheckout-address-${data.addressType} [name=other]`);
const isBusinessMsg = i18_business ?? 'business';
const isPrivateMsg = i18_private ?? 'private';
let msg = '';
if (data.isChecked) {
msg = data.isBusiness ? isBusinessMsg : isPrivateMsg;
}
field.val(msg);
});
}
$('body').on('click', '[data-link-action=toggle-password-visibility]', function () {
var input = $(this).closest('label').find('input');
@@ -367,7 +408,10 @@ $(document).ready(function () {
});
$('body').on('click', '[data-link-action=x-update-cart-quantity-up]', function () {
var inputEl = $(this).parent().find('[data-link-action=x-update-cart-quantity]');
inputEl.val(parseInt(inputEl.val()) + 1).data('no-wait', 1); // .trigger('input');
const data = inputEl.data();
const qtyHave = parseInt(inputEl.val());
const qtyChange = data?.step ?? 1;
inputEl.val(qtyHave + qtyChange).data('no-wait', 1); // .trigger('input');
inputEl.get(0).dispatchEvent(new Event('input', {
bubbles: true
}))
@@ -375,8 +419,11 @@ $(document).ready(function () {
});
$('body').on('click', '[data-link-action=x-update-cart-quantity-down]', function () {
var inputEl = $(this).parent().find('[data-link-action=x-update-cart-quantity]');
if (parseInt(inputEl.attr('min')) < parseInt(inputEl.val())) {
inputEl.val(parseInt(inputEl.val()) - 1).data('no-wait', 1); // .trigger('input');
const data = inputEl.data();
const qtyHave = parseInt(inputEl.val());
const qtyChange = data?.step ?? 1;
if (parseInt(inputEl.attr('min')) <= qtyHave - qtyChange) {
inputEl.val(qtyHave - qtyChange).data('no-wait', 1); // .trigger('input');
inputEl.get(0).dispatchEvent(new Event('input', {
bubbles: true
}))
@@ -518,6 +565,11 @@ $(document).ready(function () {
$('[data-link-action="toggle-password-visibility"]').removeClass('hidden');
$(document).ajaxError(function myErrorHandler(event, xhr, ajaxOptions, thrownError) {
if (['abort', 'canceled'].includes(thrownError)) {
// console.log('Ajax aborted', ajaxOptions)
return;
}
console.info("Ajax error \n\nDetails:\nError thrown: " + thrownError + "\n" +
'event: ');
console.info(event);
@@ -534,6 +586,7 @@ $(document).ready(function () {
var modalTriggeredToBeShown = 0;
setTimeout( function() {
$(".js-terms a").off('click');
$(".dm_gdpr_active a.iframe").removeClass('iframe');
$("body#checkout").on("click", ".js-terms a", function (t) {
modalTriggeredToBeShown++;
setTimeout(function() { modalTriggeredToBeShown--; }, 1000);
@@ -597,7 +650,7 @@ $(document).ready(function () {
}
// Attach also loading-remove handler, when (this) ajax is finished
jqxhr.always(function() {
$(settings.customPropAffectedBlocks).find('.inner-area > .tc-ajax-loading').remove();
$(settings.customPropAffectedBlocks).find('.inner-area > .tc-ajax-loading').remove();
});
}
});
@@ -638,13 +691,14 @@ function initBlocksSelectors() {
}
function handleWindowResize(win) {
if (win.width() <= tcMobileViewThreshold && !tcIsMobileView) {
const winWidth = window.innerWidth; // win.width()
if (winWidth <= tcMobileViewThreshold && !tcIsMobileView) {
tcIsMobileView = true;
// Take out all checkout blocks from their desktop layout and put into new container for mobile sorting
$('.checkout-block').each(function () {
$(this).appendTo('#tc-container-mobile');
});
} else if (win.width() > tcMobileViewThreshold && tcIsMobileView) {
} else if (winWidth > tcMobileViewThreshold && tcIsMobileView) {
tcIsMobileView = false;
// Put .checkout-block containers back to desktop (out of mobile / single column layout)
$('.checkout-block').each(function () {
@@ -706,6 +760,13 @@ function checkAndHideGlobalError() {
function showGlobalError() {
$('#tc-payment-confirmation > .error-msg').show();
scrollToError();
if (typeof grecaptcha !== 'undefined' && typeof grecaptcha.reset === 'function') {
try {
grecaptcha.reset();
} catch (error) {
// intentionally empty
}
}
}
function scrollToError() {
@@ -779,6 +840,13 @@ function modifyRadioOption(radioElements) {
});
}
function printContextNotices(blockSel, notices) {
$.each(notices, function (index, value) {
$(blockSel + ' [name=' + index + ']').addClass('-notice');
$(blockSel + ' [name=' + index + ']').after('<div class="field notice-msg">' + value + '</div>');
});
}
function printContextErrors(blockSel, errors, triggerElement, dontShowGlobal) {
var highlightOnElements = [];
@@ -818,6 +886,13 @@ function printContextErrors(blockSel, errors, triggerElement, dontShowGlobal) {
if (switchToStep > 0 && typeof setHash === 'function') {
setHash(switchToStep);
}
// For invisible or non-existing fields, let's collect all errors inside 'general_error'
if (!$(blockSel + ' [name=' + index + ']').is(':visible')) {
value = index + ': ' + value;
index = 'general_error';
}
$(blockSel + ' [name=' + index + ']').addClass('-error');
if ($(blockSel + ' [name=' + index + ']').is(':checkbox') || $(blockSel + ' [name=' + index + ']').is(':radio')) {
$(blockSel + ' [name=' + index + ']').closest('.form-group').append('<div class="field error-msg">' + value + '</div>');
@@ -931,7 +1006,7 @@ function addVoucher() {
// so we need to fetch this again; only enable if voucher affect shipping cost
getShippingAndPaymentBlocks();
} else {
updateCheckoutBlocks(jsonData, true, false, false);
updateCheckoutBlocks(jsonData, true, false, false, true);
}
}
}
@@ -960,7 +1035,7 @@ function removeVoucher(data) {
if (tcGlobal_fetchAgainAfterVoucher) {
getShippingAndPaymentBlocks();
} else {
updateCheckoutBlocks(jsonData, true, true, tc_updatePaymentWithShipping);
updateCheckoutBlocks(jsonData, true, false, tc_updatePaymentWithShipping, true);
}
}
}
@@ -979,6 +1054,7 @@ function confirmOrder(confirmButtonEl) {
var validationFailed = false;
// clear shipping error before validations
$('#thecheckout-shipping .error-msg').not(':first-child').remove();
$('#thecheckout-shipping .error-msg').hide();
$.each(tc_confirmOrderValidations, function (validationName, validationCallback) {
@@ -1113,6 +1189,12 @@ function updateQuantityFromInput(el) {
// $('#thecheckout-cart-summary').prepend('<div class="error-msg">' + errMsg + '</div>')
// $('#thecheckout-cart-summary > .error-msg').show();
// }
prestashop.emit('updateCart', { reason: {
idProduct: data["idProduct"],
idProductAttribute: data["idProductAttribute"],
idProductCustomization: data["idCustomization"],
action: 'updateQuantity'
}, resp: jsonData });
updateCheckoutBlocks(jsonData, true, true, tc_updatePaymentWithShipping);
}
@@ -1213,6 +1295,12 @@ function checkEmail(accountFormSelector, triggerEl, callback) {
blockSel = ':is(#thecheckout-account, #thecheckout-data-privacy, #thecheckout-psgdpr)';
printContextErrors(blockSel, jsonData.errors, undefined, true);
} else {
blockSelAccount = ':is(#thecheckout-account)';
removeError(blockSelAccount + ' .field.notice-msg');
if (typeof jsonData.notices !== 'undefined' && jsonData.notices['email']) {
printContextNotices(blockSelAccount, jsonData.notices);
}
updateAccountToken(jsonData.newToken);
updateStaticToken(jsonData.newStaticToken);
// if out of some reason, shipping/payment blocks are still disallowed, maybe entering email
@@ -1358,6 +1446,10 @@ function _getExtraAccountParams() {
if ($('[name=colissimo_is_mobile_valid]').length) {
extraAccountParams += '&colissimo_is_mobile_valid=' + encodeURIComponent($('[name=colissimo_is_mobile_valid]').val());
}
// lpshipping module (terminal selection)
if ($('[name=lpshipping_express_terminal]').length) {
extraAccountParams += '&lpshipping_express_terminal=' + encodeURIComponent($('[name=lpshipping_express_terminal]').val());
}
// djtalbrazilianregister (CPF/CNPJ fields module)
if ($('[name=document_type]').length && $('[name=document_number]').length) {
$('input[name=document_type]:checked, input[name=document_number], input[name=rg], input[name=ie]').each( (key, item) => {
@@ -1368,6 +1460,19 @@ function _getExtraAccountParams() {
if ($('#parcel_codigo').length === 1) {
extraAccountParams += '&parcel[codigo]=' + encodeURIComponent($('#parcel_codigo').val());
}
// dpdbaltics
if ($('.carrier-extra-content.dpdbaltics:visible [name=dpd-phone]').length === 1) {
extraAccountParams += '&dpd-phone=' + encodeURIComponent($('.carrier-extra-content.dpdbaltics:visible [name=dpd-phone]').val());
}
if ($('.carrier-extra-content.dpdbaltics:visible [name=dpd-phone-area]').length === 1) {
extraAccountParams += '&dpd-phone-area=' + encodeURIComponent($('.carrier-extra-content.dpdbaltics:visible [name=dpd-phone-area]').val());
}
if ($('.carrier-extra-content.dpdbaltics:visible [name=dpd-city]').length === 1) {
extraAccountParams += '&dpd-city=' + encodeURIComponent($('.carrier-extra-content.dpdbaltics:visible [name=dpd-city]').val());
}
if ($('.carrier-extra-content.dpdbaltics:visible [name=dpd-street]').length === 1) {
extraAccountParams += '&dpd-street=' + encodeURIComponent($('.carrier-extra-content.dpdbaltics:visible [name=dpd-street]').val());
}
return extraAccountParams;
}
@@ -1403,8 +1508,8 @@ function modifyAccountAndAddress(triggerElement, callback) {
dataType: "json",
data: "modifyAccountAndAddress=1&ajax_request=1&action=modifyAccountAndAddress&trigger=" + triggerSection +
"&account=" + serializeVisibleFields('form.account-fields') +
"&invoice=" + encodeURIComponent($('#thecheckout-address-invoice form :visible').serialize()) +
"&delivery=" + encodeURIComponent($('#thecheckout-address-delivery form :visible').serialize()) +
"&invoice=" + encodeURIComponent($('#thecheckout-address-invoice form :visible, #thecheckout-address-invoice .use-other-for-business-private input').serialize()) +
"&delivery=" + encodeURIComponent($('#thecheckout-address-delivery form :visible, #thecheckout-address-delivery .use-other-for-business-private input').serialize()) +
"&passwordVisible=" + $('#thecheckout-account input[name=password]:visible').length +
"&passwordRequired=" + $('#thecheckout-account input[name=create-account]:checked').length +
"&invoiceVisible=" + $('#thecheckout-address-invoice form:visible').length +
@@ -1421,13 +1526,31 @@ function modifyAccountAndAddress(triggerElement, callback) {
// Go through account, invoice and delivery errors, show them all
if ("undefined" !== typeof jsonData.account && null !== jsonData.account) {
blockSel = ':is(#thecheckout-account, #thecheckout-data-privacy, #thecheckout-psgdpr)';
printContextErrors(blockSel, jsonData.account.errors);
if (typeof tc_steps !== 'undefined') {
// When steps are enabled, these checkboxes can be on different 'steps' pages, so we need to call printContextError with correct blockSel-ector
var checkboxes = ['data-privacy', 'psgdpr', 'required-checkbox-1', 'required-checkbox-2'];
var checkboxErrors = false
for (const checkboxName of checkboxes) {
if (jsonData.account.errors[checkboxName]?.length) {
printContextErrors(`#thecheckout-${checkboxName}`, jsonData.account.errors);
checkboxErrors = true
break;
}
}
if (!checkboxErrors) {
blockSel = ':is(#thecheckout-account)';
printContextErrors(blockSel, jsonData.account.errors);
}
} else {
blockSel = ':is(#thecheckout-account, #thecheckout-data-privacy, #thecheckout-psgdpr, #thecheckout-required-checkbox-1, #thecheckout-required-checkbox-2)';
printContextErrors(blockSel, jsonData.account.errors);
}
if (jsonData.account.hasErrors) {
if (debug_js_controller) {
var errMsg = formatErrors(jsonData.account.errors, triggerElement);
console.info('modifyAccountAndAddress: account has errros');
console.info('modifyAccountAndAddress: account has errors');
console.info(errMsg);
}
@@ -1515,7 +1638,7 @@ function modifyAccountAndAddress(triggerElement, callback) {
hideConfirmButtonLoader($('[data-link-action=x-save-account-overlay]'));
if ("undefined" !== typeof jsonData.shippingErrors && null !== jsonData.shippingErrors && "undefined" !== typeof jsonData.shippingErrors.errors) {
var errorsTxt = jsonData.shippingErrors.errors.join(', ');
var errorsTxt = Object.values(jsonData.shippingErrors.errors).join(', ');
$('<div class="error-msg shipping-errors">'+errorsTxt+'</div>').prependTo($('#thecheckout-shipping .inner-wrapper')).show();
noErrors = false;
showGlobalError();
@@ -1574,6 +1697,12 @@ function signIn() {
signedInUpdateForm();
}
},
error: function(jqXHR, textStatus, errorThrown) {
if(jqXHR.status === 500) {
console.error("Internal server error occurred: ", errorThrown);
}
location.reload();
}
});
}
@@ -1589,7 +1718,7 @@ function deleteFromCart(data, self) {
// Avanto an_productfields module support
var anGroupId = $(self).attr('href').match('an_group_id.*');
additionalData += (anGroupId)?'&'+anGroupId:'';
// url - implicitly using current
$.ajax({
customPropAffectedBlocks: '#thecheckout-shipping, #thecheckout-payment, #thecheckout-cart-summary',
@@ -1605,6 +1734,13 @@ function deleteFromCart(data, self) {
"&token=" + static_token + additionalData,
success: function (jsonData) {
prestashop.emit('updateCart', { reason: {
idProduct: data["idProduct"],
idProductAttribute: data["idProductAttribute"],
idProductCustomization: data["idCustomization"],
action: 'deleteFromCart'
}, resp: jsonData });
updateCheckoutBlocks(jsonData, true, true, tc_updatePaymentWithShipping);
}
@@ -1852,10 +1988,63 @@ function highlightSelectedPaymentMethod() {
}
}
function updateShippingPrices(shippingBlockHtml) {
if ('undefined' !== shippingBlockHtml && null !== shippingBlockHtml) {
var $parsedShippingBlock = $(shippingBlockHtml);
$parsedShippingBlock.find('.delivery-option').each(function() {
var $parsedDeliveryOption = $(this);
var carrierRef = $parsedDeliveryOption.attr('class').match(/carrier-ref-\d+/)[0];
// if carrierRef is not found, we cannot update prices, skip this .each() iteration
if (!carrierRef) {
return;
}
var $actualDeliveryOption = $('.delivery-options-list .delivery-option.' + carrierRef);
// if respective carrierRef delivery option is not available, skip this .each() iteration
if (!$actualDeliveryOption.length) {
return;
}
var priceTypes = ['carrier-price', 'carrier-price-with-tax-formatted', 'carrier-price-without-tax-formatted'];
priceTypes.forEach(function(priceType) {
var $parsedPrice = $parsedDeliveryOption.find('.delivery-option-detail span.' + priceType + ':first');
$actualDeliveryOption.find('span.' + priceType).each(function() {
var $currentActualPrice = $(this);
$currentActualPrice.text($parsedPrice.text());
});
});
});
}
}
function updateShippingBlock(shippingModulesList, html, checksum, triggerElementName) {
if ('undefined' !== html && null !== html && shippingBlockChecksum != checksum) {
html = parseShippingMethods(shippingModulesList, html);
// save shipping form text input fields and select boxes, so we can restore them after hook update
var shipping_fields_values = {};
shippingBlockElement.find('input[type=text], select, form input[type=radio]:checked, textarea').not('[name^=delivery_option]').each(function () {
if ("undefined" !== typeof $(this).attr('id') && !$(this).is(':radio')) {
shipping_fields_values['[id=' + $(this).attr('id') + ']'] = $(this).val();
} else if ("undefined" !== typeof $(this).attr('name')) {
shipping_fields_values['[name="' + $(this).attr('name') + '"]'] = $(this).val();
}
});
updateHtmlBlock(shippingBlockElement, html);
// restore shipping for input and select fields values
$.each(shipping_fields_values, function (index, value) {
if ($(index).is(':radio')) {
$(index+'[value="'+value+'"]').prop('checked', true);
} else {
$(index).val(value);
}
});
shippingBlockChecksum = checksum;
afterShippingLoadCallbacks(shippingModulesList, html, triggerElementName);
@@ -1882,7 +2071,9 @@ function updateShippingBlock(shippingModulesList, html, checksum, triggerElement
// E.g. packzkomaty (sensbitpaczkomatymap) needs to trigger radio button change in order
// to display list of pickup points; Chronopost and Mondial relay need it as well
// forceRefreshShipping: If ="1", it will always reload shipping methods, so we need to avoid triggering click to avoid endless loop
if ($(deliveryOptionSelector).length && !payment.isConfirmationTrigger(triggerElementName) && !forceRefreshShipping) {
// To disable carrier initialization and 'blink' effect, add Custom JS code: const tc_initCarrierJs = false;
if ((typeof tc_initCarrierJs !== 'undefined' ? tc_initCarrierJs : true) &&
$(deliveryOptionSelector).length && !payment.isConfirmationTrigger(triggerElementName) && !forceRefreshShipping) {
$(deliveryOptionSelector).prop('checked', false).trigger('click');
return true;
} else {
@@ -1940,7 +2131,7 @@ function updatePaymentBlock(paymentModulesList, html, checksum, triggerElementNa
// Shall be input[type=hidden] added here? It did not work with add_gopay_new
// then, we need an exception: .not('[data-payment-module=add_gopay_new] input[type=hidden]')
// Exception for hidden fields: input[name="issuer"] = mollie payments
paymentBlockElement.find('input[type=text], select, input[name="issuer"], input[name="transferGateway"], form input[type=radio]:checked, textarea').each(function () {
paymentBlockElement.find('input[type=text], select, input[name="issuer"], input[name="transferGateway"], form input[type=radio]:checked, textarea, input[type=date]').each(function () {
if ("undefined" !== typeof $(this).attr('id') && !$(this).is(':radio') && $(this).attr('name') !== 'pmethod') {
payment_fields_values['[id=' + $(this).attr('id') + ']'] = $(this).val();
} else if ("undefined" !== typeof $(this).attr('name')) {
@@ -1978,6 +2169,8 @@ function updatePaymentBlock(paymentModulesList, html, checksum, triggerElementNa
afterPaymentLoadCallbacks(paymentModulesList, html, triggerElementName);
// Hook to this:
// prestashop.on('thecheckout_updatePaymentBlock', function() { console.log('payment block updated!'); })
prestashop.emit('thecheckout_updatePaymentBlock', {
reason: 'update',
});
@@ -1985,7 +2178,7 @@ function updatePaymentBlock(paymentModulesList, html, checksum, triggerElementNa
// restore payment for input and select fields values
$.each(payment_fields_values, function (index, value) {
if ($(index).is(':radio')) {
$(index+'[value='+value+']').prop('checked', true);
$(index+'[value="'+value+'"]').prop('checked', true);
} else {
$(index).val(value);
}
@@ -1993,12 +2186,12 @@ function updatePaymentBlock(paymentModulesList, html, checksum, triggerElementNa
// Special molliepayments update - where we need to restore not only input/select value, but also special <button> (which replaces dropdown)
if ($('#mollie-issuer-dropdown-button').length && $('input[name="issuer"]').length && '' != $('input[name="issuer"]').val()) {
var selectedMolliePayment = $('input[name="issuer"]').val();
var selectedMolliePayment = $('input[name="issuer"]').val();
var aMollieEl = $('a[data-ideal-issuer='+selectedMolliePayment+']');
if (aMollieEl.length) {
$('#mollie-issuer-dropdown-button').text(aMollieEl.text());
}
}
}
}
// Init PS Checkout render
@@ -2105,7 +2298,7 @@ function updateAddressBlock(addressType, html, htmlAddressDropdown) {
}
}
// Hook to this:
// Hook to this (alternative of prestashop.emit only on thecheckout page):
// $(document).on('thecheckout_Address_Modified', function(event, { addressType }) {
// console.log('Address modified!', addressType);
// });
@@ -2116,7 +2309,7 @@ function updateAddressBlock(addressType, html, htmlAddressDropdown) {
var cartTotalWeight = 0; // will be changed in updateCheckoutBlocks and then used in updateCartSummaryBlock
function updateCheckoutBlocks(jsonData, updateSummary, updateShipping, updatePayment) {
function updateCheckoutBlocks(jsonData, updateSummary, updateShipping, updatePayment, updateShippingPricesOnly = false) {
if ("undefined" !== typeof jsonData.emptyCart && jsonData.emptyCart === true) {
$('body').addClass('is-empty-cart');
// if ("undefined" !== typeof prestashop && "undefined" !== typeof prestashop.urls) {
@@ -2135,6 +2328,10 @@ function updateCheckoutBlocks(jsonData, updateSummary, updateShipping, updatePay
var shippingBlockUpdated = false;
var paymentBlockUpdated = false;
if ('undefined' !== typeof updateShippingPricesOnly && updateShippingPricesOnly) {
updateShippingPrices(jsonData.shippingBlock);
}
if ('undefined' !== typeof updateShipping && updateShipping) {
shippingBlockUpdated = updateShippingBlock(jsonData.externalShippingModules, jsonData.shippingBlock, jsonData.shippingBlockChecksum, jsonData.triggerElementName);
}
@@ -2178,19 +2375,22 @@ function toggleGiftMessage() {
$(this).addClass('in show')
});
}
selectDeliveryOption($('#js-delivery'));
}
function selectDeliveryOption(deliveryForm) {
highlightSelectedShippingMethod();
// To support mondial relay v3.0+, allow a bit of time for widget markup appear in extra content
setTimeout(function () {
var selectedDeliveryOptionExtra = $(deliveryOptionSelector).closest('.delivery-option-row').next('.carrier-extra-content');
$('.carrier-extra-content').not(selectedDeliveryOptionExtra).hide();
if (selectedDeliveryOptionExtra.height()) {
selectedDeliveryOptionExtra.slideDown();
}
}, 100);
if (installedModules['mondialrelay']) {
setTimeout(function () {
var selectedDeliveryOptionExtra = $(deliveryOptionSelector).closest('.delivery-option-row').next('.carrier-extra-content');
$('.carrier-extra-content').not(selectedDeliveryOptionExtra).hide();
if (selectedDeliveryOptionExtra.height()) {
selectedDeliveryOptionExtra.slideDown();
}
}, 100);
}
// url - implicitly using current
$.ajax({
@@ -2225,3 +2425,97 @@ function setDeliveryMessage() {
}
});
}
const tc_ongoingXhrs = {}
const tc_getTimestamp = () => {
const now = new Date();
return [
now.getTime(),
`${now.getSeconds().toString().padStart(2, '0')}:${now.getMilliseconds().toString().padStart(3, '0')}`
]
}
const tc_getAction = (data) => {
const match = data.match(/action=([-\w]+)/)
if (!match) {
return null
}
// construct 'metaAction', set of actions that we don't want to run in parallel, so that they shall be treated
// as synchronous
const metaAction = {
'modifyAccountAndAddress': 'account-modification',
'checkEmail': 'account-modification',
}
if (typeof metaAction[match[1]] !== 'undefined') {
return metaAction[match[1]]
} else {
return match[1]
}
}
const tc_AJAX = {
SEND: ' send ',
COMPLETE: ' complete '
};
const tc_logAction = (method, action) => {
const [timestamp, timestamp_str] = tc_getTimestamp()
const ongoingXhr = typeof tc_ongoingXhrs[action] !== 'undefined'
if (method == tc_AJAX.COMPLETE && !ongoingXhr) {
return
}
let took = ''
if (method == tc_AJAX.SEND) {
// wait only 1s, if response is not received, release the lock and let the other (potential) xhr to continue
tc_ongoingXhrs[action] = { timestamp, maxWait: 1000 }
} else {
took = ` (took: ${timestamp - tc_ongoingXhrs[action]?.timestamp}ms)`
delete tc_ongoingXhrs[action]
}
if (debug_js_controller) {
console.log(`[${method}] '${action}' @ ${timestamp_str}s${took}`)
}
}
$( document ).on( "ajaxSend", function(event, jqxhr, settings) {
if (typeof settings.data === 'string') {
const action = tc_getAction(settings.data)
if (action) {
tc_logAction(tc_AJAX.SEND, action)
}
}
});
$( document ).on( "ajaxSuccess", function(event, jqxhr, settings) {
if (typeof settings.data === 'string') {
const action = tc_getAction(settings.data)
if (action) {
tc_logAction(tc_AJAX.COMPLETE, action)
}
}
});
/*
Disallow duplicate AJAX requests, but with max timeout (default 1s) to avoid endless waiting
*/
$.ajaxSetup({
beforeSend: function(jqXHR, settings) {
if (typeof settings.data === 'string') {
const action = tc_getAction(settings.data)
if (action && typeof tc_ongoingXhrs[action] !== 'undefined' && tc_ongoingXhrs[action]?.maxWait > 0) {
tc_ongoingXhrs[action].maxWait -= 200
setTimeout(function() {
$.ajax(settings);
}, 200);
return false;
}
}
}
});