/** * Payment Manager for Easy Invoice * Handles payment calculations, discounts, and tax calculations */ (function($) { 'use strict'; // Payment Manager object window.EasyInvoicePayment = { // Default settings settings: { discountType: 'none', // none, percentage or fixed discountValue: 0, taxRate: 0, calculationMethod: 'before_tax', // before_tax or after_tax pricesIncludeTax: 'no', // yes or no currency: 'USD', currencySymbol: '$' }, // Initialize the payment manager init: function() { // Load settings from form fields first (preserves PHP-set values) this.loadSettingsFromForm(); // Then override with localized data if available if (typeof easyInvoicePayment !== 'undefined') { this.settings.discountType = easyInvoicePayment.discountType || this.settings.discountType; this.settings.discountValue = parseFloat(easyInvoicePayment.discountValue) || this.settings.discountValue; this.settings.taxRate = parseFloat(easyInvoicePayment.taxRate) || this.settings.taxRate; this.settings.calculationMethod = easyInvoicePayment.calculationMethod || this.settings.calculationMethod; this.settings.currency = easyInvoicePayment.currency || this.settings.currency; this.settings.currencySymbol = easyInvoicePayment.currencySymbol || this.settings.currencySymbol; } // Set up event handlers this.setupEventHandlers(); // Update totals (but don't overwrite field values) this.updateTotals(); }, // Load settings from form fields loadSettingsFromForm: function() { // Read values from form fields if they exist var discountType = $('#discount_type').val(); if (discountType) { this.settings.discountType = discountType; } var discountValue = parseFloat($('#discount_value').val()); if (!isNaN(discountValue)) { this.settings.discountValue = discountValue; } var taxRate = parseFloat($('#tax_rate').val()); if (!isNaN(taxRate)) { this.settings.taxRate = taxRate; } var calculationMethod = $('select[name="discount_calculation_method"]').val(); if (calculationMethod) { this.settings.calculationMethod = calculationMethod; } var pricesIncludeTax = $('select[name="prices_include_tax"]').val(); if (pricesIncludeTax) { this.settings.pricesIncludeTax = pricesIncludeTax; } var currency = $('#currency').val(); if (currency) { this.settings.currency = currency; } }, // Set up event handlers for payment-related elements setupEventHandlers: function() { var self = this; // Discount type change $('#discount_type').on('change', function() { self.settings.discountType = $(this).val(); self.updateTotals(); }); // Discount value change $('#discount_value').on('input', function() { self.settings.discountValue = parseFloat($(this).val()) || 0; self.updateTotals(); }); // Tax rate change $('#tax_rate').on('input', function() { self.settings.taxRate = parseFloat($(this).val()) || 0; self.updateTotals(); }); // Calculation method change $('select[name="discount_calculation_method"]').on('change', function() { self.settings.calculationMethod = $(this).val(); self.updateTotals(); }); // Prices include tax change $('select[name="prices_include_tax"]').on('change', function() { self.settings.pricesIncludeTax = $(this).val(); self.updateTotals(); }); // Currency change $('#currency_code').on('change', function() { self.settings.currency = $(this).val(); // Get the currency symbol for the selected currency switch($(this).val()) { case 'USD': self.settings.currencySymbol = '$'; break; case 'EUR': self.settings.currencySymbol = '€'; break; case 'GBP': self.settings.currencySymbol = '£'; break; default: self.settings.currencySymbol = '$'; } self.updateTotals(); }); }, // Update UI with current settings updateUI: function() { // Only set form field values if they are empty or if we have explicit settings // This preserves values set by PHP/HTML if (!$('#discount_type').val()) { $('#discount_type').val(this.settings.discountType); } if (!$('#discount_value').val()) { $('#discount_value').val(this.settings.discountValue); } if (!$('#tax_rate').val()) { $('#tax_rate').val(this.settings.taxRate); } if (!$('input[name="calculation_method"]:checked').val()) { $('input[name="calculation_method"][value="' + this.settings.calculationMethod + '"]').prop('checked', true); } if (!$('#currency_code').val()) { $('#currency_code').val(this.settings.currency); } // Update totals this.updateTotals(); }, // Update totals based on invoice items and settings updateTotals: function() { // Calculate subtotal from invoice items var subtotal = 0; var taxableSubtotal = 0; // Get items from invoice builder if available if (window.EasyInvoiceBuilder && typeof window.EasyInvoiceBuilder.getItems === 'function') { var items = window.EasyInvoiceBuilder.getItems(); items.forEach(function(item) { var baseTotal = item.quantity * item.price; var adjustPercentage = 0; // Only apply adjust percentage if the adjust field is enabled if (window.easyInvoice && window.easyInvoice.showAdjustField) { adjustPercentage = parseFloat(item.adjust_percentage) || 0; } var itemTotal = baseTotal * (1 + adjustPercentage / 100); subtotal += itemTotal; if (item.taxable) { taxableSubtotal += itemTotal; } }); } else { // Fallback: Calculate directly from DOM using dynamic field helpers $('.invoice-item, .quote-item').each(function(index) { var $item = $(this); // Use dynamic field helpers if available if (window.EasyInvoiceFieldHelpers) { var quantity = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('quantity', $item)) || 0; var price = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('price', $item)) || 0; var adjustPercentage = 0; // Only apply adjust percentage if the adjust field is enabled if (window.easyInvoice && window.easyInvoice.showAdjustField) { adjustPercentage = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('adjust_percentage', $item)) || 0; } var baseTotal = quantity * price; var itemTotal = baseTotal * (1 + adjustPercentage / 100); var isTaxable = window.EasyInvoiceFieldHelpers.getFieldValue('taxable', $item) === '1'; subtotal += itemTotal; if (isTaxable) { taxableSubtotal += itemTotal; } } else { // Fallback to hardcoded field names var quantity = parseFloat($(this).find('input[name*="[quantity]"]').val()) || 0; var price = parseFloat($(this).find('input[name*="[price]"]').val()) || 0; var adjustPercentage = 0; // Only apply adjust percentage if the adjust field is enabled if (window.easyInvoice && window.easyInvoice.showAdjustField) { adjustPercentage = parseFloat($(this).find('input[name*="[adjust_percentage]"]').val()) || 0; } var baseTotal = quantity * price; var itemTotal = baseTotal * (1 + adjustPercentage / 100); var isTaxable = $(this).find('input[name*="[taxable]"]').is(':checked'); subtotal += itemTotal; if (isTaxable) { taxableSubtotal += itemTotal; } } }); } // Calculate discount amount var discountAmount = 0; if (this.settings.discountType === 'none') { discountAmount = 0; } else if (this.settings.discountType === 'percentage') { discountAmount = subtotal * (this.settings.discountValue / 100); } else { // fixed amount discountAmount = Math.min(this.settings.discountValue, subtotal); // Don't discount more than subtotal } // Calculate after discount amount var afterDiscountAmount = subtotal - discountAmount; // Calculate tax amount var taxAmount = 0; var total = 0; var pricesIncludeTax = this.settings.pricesIncludeTax === 'yes'; var discountRatio = (subtotal > 0) ? (discountAmount / subtotal) : 0; if (pricesIncludeTax && this.settings.taxRate > 0) { // Tax is already included in prices: extract it from the taxable portion after discount var taxableAfterDiscount = taxableSubtotal * (1 - discountRatio); taxAmount = taxableAfterDiscount - (taxableAfterDiscount / (1 + this.settings.taxRate / 100)); total = afterDiscountAmount; } else if (this.settings.taxRate > 0) { if (this.settings.calculationMethod === 'before_tax') { // Discount first, then tax on remaining taxable amount var taxableAfterDiscount = taxableSubtotal * (1 - discountRatio); taxAmount = taxableAfterDiscount * (this.settings.taxRate / 100); } else { // after_tax // Tax first on full taxable subtotal, then discount taxAmount = taxableSubtotal * (this.settings.taxRate / 100); // Recalculate percentage discount based on total including tax if (this.settings.discountType === 'percentage') { var totalBeforeDiscount = subtotal + taxAmount; discountAmount = (totalBeforeDiscount * this.settings.discountValue) / 100; afterDiscountAmount = subtotal - discountAmount; } } total = afterDiscountAmount + taxAmount; } else { total = afterDiscountAmount; } // Update UI $('#subtotal_value').text(this.formatCurrency(subtotal)); $('#discount_amount_value').text(this.formatCurrency(discountAmount)); $('#after_discount_value').text(this.formatCurrency(afterDiscountAmount)); $('#tax_amount_value').text(this.formatCurrency(taxAmount)); $('#total_value').text(this.formatCurrency(total)); // Update hidden fields for form submission $('#subtotal_field').val(subtotal); $('#discount_amount_field').val(discountAmount); $('#tax_amount_field').val(taxAmount); $('#total_field').val(total); }, // Format currency value formatCurrency: function(value) { return this.settings.currencySymbol + parseFloat(value).toFixed(2); }, // Get payment settings for saving getPaymentSettings: function() { return { discountType: this.settings.discountType, discountValue: this.settings.discountValue, taxRate: this.settings.taxRate, calculationMethod: this.settings.calculationMethod, currency: this.settings.currency, currencySymbol: this.settings.currencySymbol }; } }; // Initialize payment manager when document is ready $(document).ready(function() { EasyInvoicePayment.init(); }); })(jQuery);