PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.3.3
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.3.3
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
easy-invoice / assets / js / payment-manager.js

payment-manager.js in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.3.3, at assets/js/payment-manager.js

310 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Payment Manager for Easy Invoice
3 * Handles payment calculations, discounts, and tax calculations
4 */
5 (function($) {
6 'use strict';
7
8 // Payment Manager object
9 window.EasyInvoicePayment = {
10 // Default settings
11 settings: {
12 discountType: 'none', // none, percentage or fixed
13 discountValue: 0,
14 taxRate: 0,
15 calculationMethod: 'before_tax', // before_tax or after_tax
16 pricesIncludeTax: 'no', // yes or no
17 currency: 'USD',
18 currencySymbol: '$'
19 },
20
21 // Initialize the payment manager
22 init: function() {
23
24
25 // Load settings from form fields first (preserves PHP-set values)
26 this.loadSettingsFromForm();
27
28 // Then override with localized data if available
29 if (typeof easyInvoicePayment !== 'undefined') {
30 this.settings.discountType = easyInvoicePayment.discountType || this.settings.discountType;
31 this.settings.discountValue = parseFloat(easyInvoicePayment.discountValue) || this.settings.discountValue;
32 this.settings.taxRate = parseFloat(easyInvoicePayment.taxRate) || this.settings.taxRate;
33 this.settings.calculationMethod = easyInvoicePayment.calculationMethod || this.settings.calculationMethod;
34 this.settings.currency = easyInvoicePayment.currency || this.settings.currency;
35 this.settings.currencySymbol = easyInvoicePayment.currencySymbol || this.settings.currencySymbol;
36 }
37
38 // Set up event handlers
39 this.setupEventHandlers();
40
41 // Update totals (but don't overwrite field values)
42 this.updateTotals();
43 },
44
45 // Load settings from form fields
46 loadSettingsFromForm: function() {
47 // Read values from form fields if they exist
48 var discountType = $('#discount_type').val();
49 if (discountType) {
50 this.settings.discountType = discountType;
51 }
52
53 var discountValue = parseFloat($('#discount_value').val());
54 if (!isNaN(discountValue)) {
55 this.settings.discountValue = discountValue;
56 }
57
58 var taxRate = parseFloat($('#tax_rate').val());
59 if (!isNaN(taxRate)) {
60 this.settings.taxRate = taxRate;
61 }
62
63 var calculationMethod = $('select[name="discount_calculation_method"]').val();
64 if (calculationMethod) {
65 this.settings.calculationMethod = calculationMethod;
66 }
67
68 var pricesIncludeTax = $('select[name="prices_include_tax"]').val();
69 if (pricesIncludeTax) {
70 this.settings.pricesIncludeTax = pricesIncludeTax;
71 }
72
73 var currency = $('#currency').val();
74 if (currency) {
75 this.settings.currency = currency;
76 }
77 },
78
79 // Set up event handlers for payment-related elements
80 setupEventHandlers: function() {
81 var self = this;
82
83 // Discount type change
84 $('#discount_type').on('change', function() {
85 self.settings.discountType = $(this).val();
86 self.updateTotals();
87 });
88
89 // Discount value change
90 $('#discount_value').on('input', function() {
91 self.settings.discountValue = parseFloat($(this).val()) || 0;
92 self.updateTotals();
93 });
94
95 // Tax rate change
96 $('#tax_rate').on('input', function() {
97 self.settings.taxRate = parseFloat($(this).val()) || 0;
98 self.updateTotals();
99 });
100
101 // Calculation method change
102 $('select[name="discount_calculation_method"]').on('change', function() {
103 self.settings.calculationMethod = $(this).val();
104 self.updateTotals();
105 });
106
107 // Prices include tax change
108 $('select[name="prices_include_tax"]').on('change', function() {
109 self.settings.pricesIncludeTax = $(this).val();
110 self.updateTotals();
111 });
112
113 // Currency change
114 $('#currency_code').on('change', function() {
115 self.settings.currency = $(this).val();
116
117 // Get the currency symbol for the selected currency
118 switch($(this).val()) {
119 case 'USD':
120 self.settings.currencySymbol = '$';
121 break;
122 case 'EUR':
123 self.settings.currencySymbol = '';
124 break;
125 case 'GBP':
126 self.settings.currencySymbol = '£';
127 break;
128 default:
129 self.settings.currencySymbol = '$';
130 }
131
132 self.updateTotals();
133 });
134 },
135
136 // Update UI with current settings
137 updateUI: function() {
138 // Only set form field values if they are empty or if we have explicit settings
139 // This preserves values set by PHP/HTML
140 if (!$('#discount_type').val()) {
141 $('#discount_type').val(this.settings.discountType);
142 }
143 if (!$('#discount_value').val()) {
144 $('#discount_value').val(this.settings.discountValue);
145 }
146 if (!$('#tax_rate').val()) {
147 $('#tax_rate').val(this.settings.taxRate);
148 }
149 if (!$('input[name="calculation_method"]:checked').val()) {
150 $('input[name="calculation_method"][value="' + this.settings.calculationMethod + '"]').prop('checked', true);
151 }
152 if (!$('#currency_code').val()) {
153 $('#currency_code').val(this.settings.currency);
154 }
155
156 // Update totals
157 this.updateTotals();
158 },
159
160 // Update totals based on invoice items and settings
161 updateTotals: function() {
162 // Calculate subtotal from invoice items
163 var subtotal = 0;
164 var taxableSubtotal = 0;
165
166 // Get items from invoice builder if available
167 if (window.EasyInvoiceBuilder && typeof window.EasyInvoiceBuilder.getItems === 'function') {
168 var items = window.EasyInvoiceBuilder.getItems();
169
170 items.forEach(function(item) {
171 var baseTotal = item.quantity * item.price;
172 var adjustPercentage = 0;
173 // Only apply adjust percentage if the adjust field is enabled
174 if (window.easyInvoice && window.easyInvoice.showAdjustField) {
175 adjustPercentage = parseFloat(item.adjust_percentage) || 0;
176 }
177 var itemTotal = baseTotal * (1 + adjustPercentage / 100);
178 subtotal += itemTotal;
179
180 if (item.taxable) {
181 taxableSubtotal += itemTotal;
182 }
183 });
184 } else {
185 // Fallback: Calculate directly from DOM using dynamic field helpers
186 $('.invoice-item, .quote-item').each(function(index) {
187 var $item = $(this);
188
189 // Use dynamic field helpers if available
190 if (window.EasyInvoiceFieldHelpers) {
191 var quantity = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('quantity', $item)) || 0;
192 var price = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('price', $item)) || 0;
193 var adjustPercentage = 0;
194 // Only apply adjust percentage if the adjust field is enabled
195 if (window.easyInvoice && window.easyInvoice.showAdjustField) {
196 adjustPercentage = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('adjust_percentage', $item)) || 0;
197 }
198 var baseTotal = quantity * price;
199 var itemTotal = baseTotal * (1 + adjustPercentage / 100);
200 var isTaxable = window.EasyInvoiceFieldHelpers.getFieldValue('taxable', $item) === '1';
201
202 subtotal += itemTotal;
203
204 if (isTaxable) {
205 taxableSubtotal += itemTotal;
206 }
207 } else {
208 // Fallback to hardcoded field names
209 var quantity = parseFloat($(this).find('input[name*="[quantity]"]').val()) || 0;
210 var price = parseFloat($(this).find('input[name*="[price]"]').val()) || 0;
211 var adjustPercentage = 0;
212 // Only apply adjust percentage if the adjust field is enabled
213 if (window.easyInvoice && window.easyInvoice.showAdjustField) {
214 adjustPercentage = parseFloat($(this).find('input[name*="[adjust_percentage]"]').val()) || 0;
215 }
216 var baseTotal = quantity * price;
217 var itemTotal = baseTotal * (1 + adjustPercentage / 100);
218 var isTaxable = $(this).find('input[name*="[taxable]"]').is(':checked');
219
220 subtotal += itemTotal;
221
222 if (isTaxable) {
223 taxableSubtotal += itemTotal;
224 }
225 }
226 });
227 }
228
229 // Calculate discount amount
230 var discountAmount = 0;
231 if (this.settings.discountType === 'none') {
232 discountAmount = 0;
233 } else if (this.settings.discountType === 'percentage') {
234 discountAmount = subtotal * (this.settings.discountValue / 100);
235 } else { // fixed amount
236 discountAmount = Math.min(this.settings.discountValue, subtotal); // Don't discount more than subtotal
237 }
238
239 // Calculate after discount amount
240 var afterDiscountAmount = subtotal - discountAmount;
241
242 // Calculate tax amount
243 var taxAmount = 0;
244 var total = 0;
245 var pricesIncludeTax = this.settings.pricesIncludeTax === 'yes';
246 var discountRatio = (subtotal > 0) ? (discountAmount / subtotal) : 0;
247
248 if (pricesIncludeTax && this.settings.taxRate > 0) {
249 // Tax is already included in prices: extract it from the taxable portion after discount
250 var taxableAfterDiscount = taxableSubtotal * (1 - discountRatio);
251 taxAmount = taxableAfterDiscount - (taxableAfterDiscount / (1 + this.settings.taxRate / 100));
252 total = afterDiscountAmount;
253 } else if (this.settings.taxRate > 0) {
254 if (this.settings.calculationMethod === 'before_tax') {
255 // Discount first, then tax on remaining taxable amount
256 var taxableAfterDiscount = taxableSubtotal * (1 - discountRatio);
257 taxAmount = taxableAfterDiscount * (this.settings.taxRate / 100);
258 } else { // after_tax
259 // Tax first on full taxable subtotal, then discount
260 taxAmount = taxableSubtotal * (this.settings.taxRate / 100);
261 // Recalculate percentage discount based on total including tax
262 if (this.settings.discountType === 'percentage') {
263 var totalBeforeDiscount = subtotal + taxAmount;
264 discountAmount = (totalBeforeDiscount * this.settings.discountValue) / 100;
265 afterDiscountAmount = subtotal - discountAmount;
266 }
267 }
268 total = afterDiscountAmount + taxAmount;
269 } else {
270 total = afterDiscountAmount;
271 }
272
273 // Update UI
274 $('#subtotal_value').text(this.formatCurrency(subtotal));
275 $('#discount_amount_value').text(this.formatCurrency(discountAmount));
276 $('#after_discount_value').text(this.formatCurrency(afterDiscountAmount));
277 $('#tax_amount_value').text(this.formatCurrency(taxAmount));
278 $('#total_value').text(this.formatCurrency(total));
279
280 // Update hidden fields for form submission
281 $('#subtotal_field').val(subtotal);
282 $('#discount_amount_field').val(discountAmount);
283 $('#tax_amount_field').val(taxAmount);
284 $('#total_field').val(total);
285 },
286
287 // Format currency value
288 formatCurrency: function(value) {
289 return this.settings.currencySymbol + parseFloat(value).toFixed(2);
290 },
291
292 // Get payment settings for saving
293 getPaymentSettings: function() {
294 return {
295 discountType: this.settings.discountType,
296 discountValue: this.settings.discountValue,
297 taxRate: this.settings.taxRate,
298 calculationMethod: this.settings.calculationMethod,
299 currency: this.settings.currency,
300 currencySymbol: this.settings.currencySymbol
301 };
302 }
303 };
304
305 // Initialize payment manager when document is ready
306 $(document).ready(function() {
307 EasyInvoicePayment.init();
308 });
309
310 })(jQuery);