1var tilaContentAlreadyLoaded = {}; 2/** 3 * Rounds the instalment amounts when the result is a periodic number. 4 * @param {number} total - Total amount to be divided into instalments 5 * @param {number} numInstalments - Number of instalments 6 * @param {string} roundingMode - Rounding mode: 'ROUND_UP', 'ROUND_DOWN', or 'NONE' 7 * @returns {Array<number>} - Array with the amount for each instalment 8 */ 9function calculateInstalments(total, numInstalments, roundingMode) { 10 // Basic validations 11 if (total <= 0 || numInstalments <= 0) { 12 throw new Error('Total amount and number of instalments must be greater than zero'); 13 } 14 15 // If there's only one instalment, return the total 16 if (numInstalments === 1) { 17 return [total]; 18 } 19 20 // Calculate the exact value of each instalment 21 const exactInstalment = total / numInstalments; 22 23 // If rounding mode is NONE or there are no periodic decimals, return equal instalments 24 if (roundingMode === 'NONE' || Number.isInteger(exactInstalment * 100)) { 25 return Array(numInstalments).fill(parseFloat(exactInstalment.toFixed(2))); 26 } 27 28 let roundedInstalment; 29 30 // Apply rounding according to the mode 31 if (roundingMode === 'ROUND_UP') { 32 roundedInstalment = Math.ceil(exactInstalment * 100) / 100; 33 } else { 34 roundedInstalment = Math.round(exactInstalment * 100) / 100; 35 } 36 37 // Calculate the total after rounding all instalments 38 const roundedTotal = roundedInstalment * numInstalments; 39 40 // Calculate the difference that needs to be adjusted in the first instalment 41 const difference = total - roundedTotal; 42 43 // Create the array of instalments 44 const instalments = Array(numInstalments).fill(roundedInstalment); 45 46 // Adjust the first instalment with the difference 47 instalments[0] = parseFloat((instalments[0] + difference).toFixed(2)); 48 49 return instalments; 50} 51 52/* Payment Plan Widget Functions */ 53 54function initializePaymentPlanWidget() { 55 console.log('Payment plan widget initialized'); 56 // Handle payment plan selection with visual feedback and hidden field update 57 $(document).on('change', 'input[name="paymentplan_purchase_option"]', function() { 58 try { 59 var selectedPlan = $(this); 60 var planId = selectedPlan.data('plan-id'); 61 var widget = selectedPlan.closest('.payment-plan-widget'); 62 63 // Remove selected class from all options 64 widget.find('.payment-option').removeClass('selected'); 65 66 // Add selected class to current option 67 selectedPlan.closest('.payment-option').addClass('selected'); 68 69 // Store selection for form submission 70 widget.data('selected-plan-id', planId); 71 72 // Update or create hidden field with selected payment plan ID 73 updatePaymentPlanHiddenField(planId); 74 75 // Trigger custom event for other scripts to listen to 76 $(document).trigger('paymentPlanChanged', { 77 planId: planId, 78 entityType: widget.data('entity-type'), 79 entityId: widget.data('entity-id'), 80 widget: widget 81 }); 82 83 updatePaymentPlanWarning(); 84 85 if (planId > 0) { 86 getTilaForPaymentPlan(); 87 } 88 }catch (error) { 89 console.error('Error handling payment plan selection:', error); 90 } 91 }); 92 93 // Initialize selected state on page load and set initial hidden field value 94 $('.payment-plan-widget input[name="paymentplan_purchase_option"]:checked').each(function() { 95 $(this).closest('.payment-option').addClass('selected'); 96 var initialPlanId = $(this).data('plan-id'); 97 updatePaymentPlanHiddenField(initialPlanId); 98 }); 99 100} 101 102function updatePaymentPlanHiddenField(planId) { 103 // Find the form that contains the payment plan widget 104 var form = $('.payment-plan-widget').closest('form'); 105 106 if (form.length > 0) { 107 // Remove any existing payment plan hidden field 108 form.find('input[name="selectedPaymentPlanID"]').remove(); 109 110 // Add new hidden field with selected payment plan ID 111 form.append('<input type="hidden" name="selectedPaymentPlanID" value="' + planId + '" />'); 112 } else { 113 // Fallback: create a global hidden field if no form is found 114 $('body').find('input[name="selectedPaymentPlanID"]').remove(); 115 $('body').append('<input type="hidden" name="selectedPaymentPlanID" value="' + planId + '" />'); 116 } 117} 118 119function updatePaymentPlanWarning() { 120 const $warning = $('#payment-plan-existing-warning'); 121 const $paymentWidget = $('#payment-plan-widget'); 122 123 if ($warning.length > 0 && $paymentWidget.length > 0) { 124 // Check if a payment plan option (not "Pay in Full") is selected 125 const $selectedOption = $paymentWidget.find('input[name="paymentplan_purchase_option"]:checked'); 126 127 if ($selectedOption.length > 0) { 128 const selectedValue = $selectedOption.val(); 129 const isPaymentPlanSelected = selectedValue === 'plan'; 130 131 if (isPaymentPlanSelected) { 132 $warning.show(); 133 } else { 134 $warning.hide(); 135 } 136 } else { 137 // Default to hiding warning if nothing is selected or "Pay in Full" is selected 138 $warning.hide(); 139 } 140 } 141} 142 143/* TILA Modal Functions */ 144 145var isProcessingPaymentPlan = false; 146 147function showTilaModal() { 148 console.log('showTilaModal called'); 149 // Prevent multiple modals 150 if (isProcessingPaymentPlan) { 151 return false; 152 } 153 resetModal(); 154 155 var selectedPlan = $('input[name="selectedPaymentPlanID"]').val(); 156 157 // Temporarily comment to test 158 if (!selectedPlan || selectedPlan === '0') { 159 return false; // No payment plan selected, proceed normally 160 } 161 162 loadTilaContent(selectedPlan, '$'); 163
164 $('#tilaModal').fadeIn(300); 165 $('body').css('overflow', 'hidden'); 166 167 return true; 168} 169 170function closeTilaModal(event) { 171 console.log('closeTilaModal called'); 172 isProcessingPaymentPlan = false; 173 174 // Prevent event propagation and default behavior 175 if (event) { 176 event.preventDefault(); 177 event.stopPropagation(); 178 event.stopImmediatePropagation(); 179 } 180 181 $('#tilaModal').fadeOut(300); 182 $('body').css('overflow', ''); 183 184 // Re-enable submit buttons 185 $('.sw-button-primary').attr('disabled', false); 186 return false; 187} 188 189function getTilaForPaymentPlan() { 190 var selectedPlan = $('input[name="selectedPaymentPlanID"]').val(); 191 if (tilaContentAlreadyLoaded[selectedPlan]) { 192 $('#tilaHeader').text(tilaContentAlreadyLoaded[selectedPlan].tilaTitle + ' - Payment Plan Disclosure'); 193 $('#tilaTerms').html(tilaContentAlreadyLoaded[selectedPlan].tilaText); 194 console.log('TILA content already loaded for plan', selectedPlan); 195 return null; 196 } 197 198 if (selectedPlan && selectedPlan !== '0') { 199 $('#tilaTerms').html('Loading TILA terms...'); 200 $.post('include/modules/paymentPlans/requests/ppAjax.asp', { paymentPlanSelection: selectedPlan, action: 'getPaymentPlanTILA' }, 201 function(data) { 202 data = JSON.parse(data); 203 $('#tilaHeader').text(data.tilaTitle + ' - Payment Plan Disclosure'); 204 $('#tilaTerms').html(data.tilaText); 205 tilaContentAlreadyLoaded[selectedPlan] = { 206 tilaText: data.tilaText, 207 tilaID: data.tilaID, 208 tilaTitle: data.tilaTitle 209 }; 210 console.log('TILA content loaded for plan', selectedPlan); 211 } 212 ).fail(function() { 213 console.error('Failed to load TILA content.'); 214 $('#tilaTerms').html('Error loading TILA terms. Please try again.'); 215 }); 216 } 217 return null; 218} 219 220function saveTILAAcknowledgement() { 221 var selectedPlan = $('input[name="selectedPaymentPlanID"]').val(); 222 if (selectedPlan && selectedPlan !== '0') { 223 $.post('include/modules/paymentPlans/requests/ppAjax.asp', { paymentPlanSelection: selectedPlan, action: 'saveTILAAcknowledgement' }, 224 function(data) { 225 //console.log('TILA acknowledgement saved:', data); 226 } 227 ).fail(function() { 228 console.error('Failed to save TILA acknowledgement.'); 229 }); 230 } 231 return null; 232} 233 234function removeTILAAcknowledgement() { 235 $.post('include/modules/paymentPlans/requests/ppAjax.asp', { action: 'removeTILAAcknowledgement' }, 236 function(data) { 237 //console.log('TILA acknowledgement removed:', data); 238 } 239 ).fail(function() { 240 console.error('Failed to remove TILA acknowledgement.'); 241 }); 242 243 return null; 244} 245 246function loadTilaContent(planId, currencySymbol) { 247 // Calculate total from selected tickets 248 var total = 0; 249 250 if (!currencySymbol) { 251 currencySymbol = '$'; // Default fallback 252 } 253 254 // Calculate total for GA tickets 255 $('.ga-price-code-row').each(function() { 256 var quantityInput = $(this).find('.qty-small-text'); 257 var quantity = parseInt(quantityInput.val()) || 0; 258 259 if (quantity > 0) { 260 var priceText = $(this).find('.price-cell').text().trim(); 261 var price = parseFloat(priceText.replace(/[^0-9.]/g, '')) || 0; 262 total += price * quantity; 263 } 264 }); 265 266 // Calculate total for reserved seats if applicable 267 $('.selected-seat-price.reserved-seat').each(function() { 268 var selectedOption = $(this).find('option:selected'); 269 if (selectedOption.length > 0) { 270 var optionText = selectedOption.text(); 271 const escapedCurrencySymbol = currencySymbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 272 var priceRegex = new RegExp(escapedCurrencySymbol + '([\\d,]+\\.?\\d*)'); 273 var priceMatch = optionText.match(priceRegex); 274 if (priceMatch) { 275 var price = parseFloat(priceMatch[1].replace(/,/g, '')) || 0; 276 total += price; 277 } 278 } 279 });
280 281 // For GA seats 282 $('.selected-seat-price.ga-seat').each(function() { 283 const selectedOption = $(this).find('option:selected'); 284 if (selectedOption.length > 0) { 285 // Extract price from the option text (format: "Price Code Name - $XX.XX") 286 const optionText = selectedOption.text(); 287 const priceRegex = new RegExp(escapedCurrencySymbol + '([\\d,]+\\.?\\d*)'); 288 const priceMatch = optionText.match(priceRegex); 289 if (priceMatch) { 290 const price = parseFloat(priceMatch[1].replace(/,/g, '')) || 0; 291 total += price; 292 } 293 } 294 }); 295 296 // Get installment count from selected plan 297 var installments = 1; 298 var selectedPlanOption = $('.payment-plan-option input:checked'); 299 if (selectedPlanOption.length > 0) { 300 installments = parseInt(selectedPlanOption.data('installments')) || 1; 301 } 302 303 var paymentAmount = (total / installments).toFixed(2); 304 305 $('#tilaFinanceAmount').text(currencySymbol + total.toFixed(2));
306 $('#tilaInstallments').text(installments); 307 $('#tilaPaymentAmount').text(currencySymbol + paymentAmount); 308 309 // Reset checkbox 310 $('#tilaAcknowledge').prop('checked', false); 311 updateContinueButton(); 312} 313 314function updateContinueButton() { 315 var isChecked = $('#tilaAcknowledge').is(':checked'); 316 $('#continueWithPlan').prop('disabled', !isChecked); 317 318 if (isChecked) { 319 $('#continueWithPlan').removeClass('sw-button-muted').addClass('sw-button-primary'); 320 } else { 321 $('#continueWithPlan').removeClass('sw-button-primary').addClass('sw-button-muted'); 322 } 323} 324 325function disableModalClose() { 326 $('.modal-close').prop('disabled', true).css('pointer-events', 'none').css('opacity', '0.5'); 327 328 $(document).off('keydown'); 329 330 $('#tilaModal').off('click'); 331} 332 333function payInFull() { 334 disableModalClose(); 335 // Add loading state to button 336 var $button = $('#payInFullButton'); 337 $button.addClass('button-loading'); 338 $button.prop('disabled', true); 339 340 // Hide the "Continue with Payment Plan" button 341 $('#continueWithPlan').prop('disabled', true); 342 $('#tilaAcknowledge').prop('disabled', true); 343 344 // Disable close button 345 $('.modal-close').prop('disabled', true).css('pointer-events', 'none').css('opacity', '0.5'); 346 347 // Clear payment plan selection 348 $('input[name="selectedPaymentPlanID"]').val('0'); 349 $('.payment-plan-option input').prop('checked', false); 350 351 // Trigger payment plan change event to update UI 352 $(document).trigger('paymentPlanChanged', {planId: 0}); 353 354 // Mark as processed so form submission can continue 355 isProcessingPaymentPlan = true; 356 357 358 // Small delay to ensure UI updates, then submit 359 setTimeout(function() { 360 if ($('#priceCodeForm').length > 0) { 361 var form = document.getElementById('priceCodeForm'); 362 if (form) { 363 form.submit(); 364 } 365 } else if ($('#bundle-ga-form').length > 0) { 366 var bundleForm = document.getElementById('bundle-ga-form'); 367 if (bundleForm) { 368 bundleForm.submit(); 369 } 370 } else { 371 // For qualifier purchases 372 var qualifierSeats = validateQualifierAdd(false); 373 if (qualifierSeats) { 374 validateQualifierAdd(true); 375 } 376 } 377 }, 300); 378} 379 380function resetModal() { 381 // Reset modal state 382 removeTILAAcknowledgement(); 383 $('#tilaAcknowledge').prop('checked', false); 384 updateContinueButton(); 385 $('.sw-button-primary').attr('disabled', false); 386 $('.modal-close').prop('disabled', false).css('pointer-events', '').css('opacity', ''); 387 $('#payInFullButton').prop('disabled', false).text('Pay in Full Instead'); 388 $('#continueWithPlan').prop('disabled', true).text('Continue with Payment Plan'); 389 isProcessingPaymentPlan = false; 390} 391 392function continueWithPaymentPlan() { 393 disableModalClose(); 394 395 if (!$('#tilaAcknowledge').is(':checked')) { 396 alert('Please acknowledge that you have read and agree to the payment plan terms.'); 397 $('#tilaAcknowledge').focus(); 398 resetModal(); 399 return false; 400 }else{ 401 saveTILAAcknowledgement(); 402 } 403 404 // Add loading state to button 405 var $button = $('#continueWithPlan'); 406 $button.addClass('button-loading'); 407 $button.prop('disabled', true); 408 409 // Hide the "Pay in Full" button 410 $('#payInFullButton').prop('disabled', true); 411 $('#payInFullButton').css('opacity', '0.5'); 412 $('#payInFullButton').css('pointer-events', 'none'); 413 $('#tilaAcknowledge').prop('disabled', true); 414 415 // Disable close button 416 $('.modal-close').prop('disabled', true).css('pointer-events', 'none').css('opacity', '0.5'); 417 418 // Mark as processed 419 isProcessingPaymentPlan = true; 420 421 // Small delay to show processing state 422 setTimeout(function() { 423 if ($('#priceCodeForm').length > 0) { 424 $('#priceCodeForm').submit(); 425 } else if ($('#bundle-ga-form').length > 0) { 426 $('#bundle-ga-form').submit(); 427 } 428 }, 300); 429} 430 431/* Generic Payment Plan and TILA Integration */ 432 433function initializePaymentPlanIntegration(options) { 434 var defaults = { 435 formSelectors: ['#priceCodeForm', '#bundle-ga-form'], // Forms to intercept 436 submitButtonSelectors: ['button[name="addtobasket"]', 'input[type="submit"]'], // Buttons that trigger submission 437 qualifierFunction: 'validateQualifierAdd', // Function name for qualifier validation 438 currencySymbol: '$' // Default currency symbol 439 }; 440 441 var config = $.extend({}, defaults, options); 442 443 // Initialize the widget 444 initializePaymentPlanWidget(); 445 446 // Override showTilaModal to use config 447 window.originalShowTilaModal = window.showTilaModal; 448 window.showTilaModal = function() { 449 console.log('showTilaModal called with config'); 450 // Prevent multiple modals 451 if (isProcessingPaymentPlan) { 452 return false; 453 } 454 resetModal(); 455 456 var selectedPlan = $('input[name="selectedPaymentPlanID"]').val(); 457 458 if (!selectedPlan || selectedPlan === '0') { 459 return false; // No payment plan selected, proceed normally 460 } 461 462 loadTilaContent(selectedPlan, config.currencySymbol); 463
464 $('#tilaModal').fadeIn(300); 465 $('body').css('overflow', 'hidden'); 466 467 return true; 468 }; 469 470 // Override payInFull to use config 471 window.originalPayInFull = window.payInFull; 472 window.payInFull = function() { 473 disableModalClose(); 474 // Add loading state to button 475 var $button = $('#payInFullButton'); 476 $button.addClass('button-loading'); 477 $button.prop('disabled', true); 478 479 // Hide the "Continue with Payment Plan" button 480 $('#continueWithPlan').prop('disabled', true); 481 $('#tilaAcknowledge').prop('disabled', true); 482 483 // Disable close button 484 $('.modal-close').prop('disabled', true).css('pointer-events', 'none').css('opacity', '0.5'); 485 486 // Clear payment plan selection 487 $('input[name="selectedPaymentPlanID"]').val('0'); 488 $('.payment-plan-option input').prop('checked', false); 489 490 // Trigger payment plan change event to update UI 491 $(document).trigger('paymentPlanChanged', {planId: 0}); 492 493 // Mark as processed so form submission can continue 494 isProcessingPaymentPlan = true; 495 496 497 // Small delay to ensure UI updates, then submit 498 setTimeout(function() { 499 var submitted = false; 500 for (var i = 0; i < config.formSelectors.length; i++) { 501 var form = $(config.formSelectors[i]); 502 if (form.length > 0) { 503 form[0].submit(); 504 submitted = true; 505 break; 506 } 507 } 508 if (!submitted && config.qualifierFunction && window[config.qualifierFunction]) { 509 // For qualifier purchases 510 var qualifierSeats = window[config.qualifierFunction](false); 511 if (qualifierSeats) { 512 window[config.qualifierFunction](true); 513 } 514 } 515 }, 300); 516 }; 517 518 // Override continueWithPaymentPlan to use config 519 window.originalContinueWithPaymentPlan = window.continueWithPaymentPlan; 520 window.continueWithPaymentPlan = function() { 521 disableModalClose(); 522 523 if (!$('#tilaAcknowledge').is(':checked')) { 524 alert('Please acknowledge that you have read and agree to the payment plan terms.'); 525 $('#tilaAcknowledge').focus(); 526 resetModal(); 527 return false; 528 }else{ 529 saveTILAAcknowledgement(); 530 } 531 532 // Add loading state to button 533 var $button = $('#continueWithPlan'); 534 $button.addClass('button-loading'); 535 $button.prop('disabled', true); 536 537 // Hide the "Pay in Full" button 538 $('#payInFullButton').prop('disabled', true); 539 $('#payInFullButton').css('opacity', '0.5'); 540 $('#payInFullButton').css('pointer-events', 'none'); 541 $('#tilaAcknowledge').prop('disabled', true); 542 543 // Disable close button 544 $('.modal-close').prop('disabled', true).css('pointer-events', 'none').css('opacity', '0.5'); 545 546 // Mark as processed 547 isProcessingPaymentPlan = true; 548 549 // Small delay to show processing state 550 setTimeout(function() { 551 var submitted = false; 552 for (var i = 0; i < config.formSelectors.length; i++) { 553 var form = $(config.formSelectors[i]); 554 if (form.length > 0) { 555 form[0].submit(); 556 submitted = true; 557 break; 558 } 559 } 560 if (!submitted) { 561 console.error('No form found to submit'); 562 } 563 }, 300); 564 }; 565 566 // Set up event listeners for submit buttons 567 $(document).ready(function() { 568 // Update checkbox listener 569 $('#tilaAcknowledge').on('change', updateContinueButton); 570 571 // Initialize continue button state 572 updateContinueButton(); 573 574 // Intercept form submission for configured forms
575 config.formSelectors.forEach(function(selector) { 576 $(selector).on('submit', function(e) { 577 if (isProcessingPaymentPlan) { 578 // Already processed, allow submission 579 return true; 580 } 581 582 // Check if payment plan is selected 583 var selectedPlan = $('input[name="selectedPaymentPlanID"]').val(); 584 if (selectedPlan && selectedPlan !== '0') { 585 e.preventDefault(); 586 if (showTilaModal()) { 587 return false; // Modal shown, prevent submission 588 } 589 } 590 // No payment plan or modal not shown, allow submission 591 return true; 592 }); 593 }); 594 595 // Handle configured submit button clicks 596 config.submitButtonSelectors.forEach(function(selector) { 597 $(document).on('click', selector, function(e) { 598 if (isProcessingPaymentPlan) { 599 return true; 600 } 601 // Payment plan check will be handled in form submit 602 }); 603 }); 604 605 // Close modal when clicking outside 606 $('#tilaModal').on('click', function(e) { 607 if (e.target === this) { 608 e.preventDefault(); 609 e.stopPropagation(); 610 closeTilaModal(e); 611 } 612 }); 613 614 // Prevent clicks inside modal from propagating 615 $('.modal-container').on('click', function(e) { 616 e.stopPropagation(); 617 }); 618 619 // Close modal on ESC key 620 $(document).on('keydown', function(e) { 621 if (e.key === 'Escape' && $('#tilaModal').is(':visible')) { 622 e.preventDefault(); 623 e.stopPropagation(); 624 closeTilaModal(e); 625 } 626 }); 627 628 // Update payment plan selection when Pay in Full button is clicked 629 $('#tilaModal').on('click', 'button', function(e) { 630 if ($(this).attr('id') === 'payInFullButton') { 631 // Select the "Pay in Full" radio option 632 $('.payment-plan-options .full-payment [name="paymentplan_purchase_option"]')[0].click(); 633 634 // Also update the hidden input to reflect no payment plan 635 $('input[name="selectedPaymentPlanID"]').val('0'); 636 } 637 }); 638 }); 639}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.