PageSourceSearch

https://www.cincyticket.com/include/modules/paymentPlans/ppFunctions.js

js cincyticket.com collected 2026-09-25 18:52:43 UTC 23,409 bytes, 639 lines download raw bytes

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.