| @@ -8,12 +8,13 @@ | ||
| 8 | 8 | // Payment Manager object |
| 9 | 9 | window.EasyInvoicePayment = { |
| 10 | 10 | // Default settings |
| 11 | 11 | settings: { |
| 12 | - discountType: 'percentage', // percentage or fixed | |
| 12 | + discountType: 'none', // none, percentage or fixed | |
| 13 | 13 | discountValue: 0, |
| 14 | 14 | taxRate: 0, |
| 15 | 15 | calculationMethod: 'before_tax', // before_tax or after_tax |
| 16 | + pricesIncludeTax: 'no', // yes or no | |
| 16 | 17 | currency: 'USD', |
| 17 | 18 | currencySymbol: '$' |
| 18 | 19 | }, |
| 19 | 20 | |
| @@ -58,12 +59,17 @@ | ||
| 58 | 59 | if (!isNaN(taxRate)) { |
| 59 | 60 | this.settings.taxRate = taxRate; |
| 60 | 61 | } |
| 61 | 62 | |
| 62 | - var calculationMethod = $('input[name="calculation_method"]:checked').val(); | |
| 63 | + var calculationMethod = $('select[name="discount_calculation_method"]').val(); | |
| 63 | 64 | if (calculationMethod) { |
| 64 | 65 | this.settings.calculationMethod = calculationMethod; |
| 65 | 66 | } |
| 67 | + | |
| 68 | + var pricesIncludeTax = $('select[name="prices_include_tax"]').val(); | |
| 69 | + if (pricesIncludeTax) { | |
| 70 | + this.settings.pricesIncludeTax = pricesIncludeTax; | |
| 71 | + } | |
| 66 | 72 | |
| 67 | 73 | var currency = $('#currency').val(); |
| 68 | 74 | if (currency) { |
| 69 | 75 | this.settings.currency = currency; |
| @@ -92,12 +98,18 @@ | ||
| 92 | 98 | self.updateTotals(); |
| 93 | 99 | }); |
| 94 | 100 | |
| 95 | 101 | // Calculation method change |
| 96 | - $('input[name="calculation_method"]').on('change', function() { | |
| 102 | + $('select[name="discount_calculation_method"]').on('change', function() { | |
| 97 | 103 | self.settings.calculationMethod = $(this).val(); |
| 98 | 104 | self.updateTotals(); |
| 99 | 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 | + }); | |
| 100 | 112 | |
| 101 | 113 | // Currency change |
| 102 | 114 | $('#currency_code').on('change', function() { |
| 103 | 115 | self.settings.currency = $(this).val(); |
| @@ -156,9 +168,13 @@ | ||
| 156 | 168 | var items = window.EasyInvoiceBuilder.getItems(); |
| 157 | 169 | |
| 158 | 170 | items.forEach(function(item) { |
| 159 | 171 | var baseTotal = item.quantity * item.price; |
| 160 | - var adjustPercentage = parseFloat(item.adjust_percentage) || 0; | |
| 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 | + } | |
| 161 | 177 | var itemTotal = baseTotal * (1 + adjustPercentage / 100); |
| 162 | 178 | subtotal += itemTotal; |
| 163 | 179 | |
| 164 | 180 | if (item.taxable) { |
| @@ -166,9 +182,9 @@ | ||
| 166 | 182 | } |
| 167 | 183 | }); |
| 168 | 184 | } else { |
| 169 | 185 | // Fallback: Calculate directly from DOM using dynamic field helpers |
| 170 | - $('.invoice-item').each(function(index) { | |
| 186 | + $('.invoice-item, .quote-item').each(function(index) { | |
| 171 | 187 | var $item = $(this); |
| 172 | 188 | |
| 173 | 189 | // Use dynamic field helpers if available |
| 174 | 190 | if (window.EasyInvoiceFieldHelpers) { |
| @@ -173,9 +189,13 @@ | ||
| 173 | 189 | // Use dynamic field helpers if available |
| 174 | 190 | if (window.EasyInvoiceFieldHelpers) { |
| 175 | 191 | var quantity = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('quantity', $item)) || 0; |
| 176 | 192 | var price = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('price', $item)) || 0; |
| 177 | - var adjustPercentage = parseFloat(window.EasyInvoiceFieldHelpers.getFieldValue('adjust_percentage', $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 | + } | |
| 178 | 198 | var baseTotal = quantity * price; |
| 179 | 199 | var itemTotal = baseTotal * (1 + adjustPercentage / 100); |
| 180 | 200 | var isTaxable = window.EasyInvoiceFieldHelpers.getFieldValue('taxable', $item) === '1'; |
| 181 | 201 | |
| @@ -187,9 +207,13 @@ | ||
| 187 | 207 | } else { |
| 188 | 208 | // Fallback to hardcoded field names |
| 189 | 209 | var quantity = parseFloat($(this).find('input[name*="[quantity]"]').val()) || 0; |
| 190 | 210 | var price = parseFloat($(this).find('input[name*="[price]"]').val()) || 0; |
| 191 | - var adjustPercentage = parseFloat($(this).find('input[name*="[adjust_percentage]"]').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 | + } | |
| 192 | 216 | var baseTotal = quantity * price; |
| 193 | 217 | var itemTotal = baseTotal * (1 + adjustPercentage / 100); |
| 194 | 218 | var isTaxable = $(this).find('input[name*="[taxable]"]').is(':checked'); |
| 195 | 219 | |
| @@ -203,9 +227,11 @@ | ||
| 203 | 227 | } |
| 204 | 228 | |
| 205 | 229 | // Calculate discount amount |
| 206 | 230 | var discountAmount = 0; |
| 207 | - if (this.settings.discountType === 'percentage') { | |
| 231 | + if (this.settings.discountType === 'none') { | |
| 232 | + discountAmount = 0; | |
| 233 | + } else if (this.settings.discountType === 'percentage') { | |
| 208 | 234 | discountAmount = subtotal * (this.settings.discountValue / 100); |
| 209 | 235 | } else { // fixed amount |
| 210 | 236 | discountAmount = Math.min(this.settings.discountValue, subtotal); // Don't discount more than subtotal |
| 211 | 237 | } |
| @@ -214,25 +240,36 @@ | ||
| 214 | 240 | var afterDiscountAmount = subtotal - discountAmount; |
| 215 | 241 | |
| 216 | 242 | // Calculate tax amount |
| 217 | 243 | var taxAmount = 0; |
| 218 | - if (this.settings.calculationMethod === 'before_tax') { | |
| 219 | - // For before_tax: Apply discount first, then calculate tax on remaining taxable amount | |
| 220 | - var discountRatio = discountAmount / subtotal; | |
| 221 | - var taxableAmount = taxableSubtotal * (1 - discountRatio); | |
| 222 | - taxAmount = taxableAmount * (this.settings.taxRate / 100); | |
| 223 | - } else { // after_tax | |
| 224 | - // For after_tax: Calculate tax first, then apply discount | |
| 225 | - taxAmount = taxableSubtotal * (this.settings.taxRate / 100); | |
| 226 | - // Recalculate percentage discount based on total including tax if needed | |
| 227 | - if (this.settings.discountType === 'percentage') { | |
| 228 | - var totalBeforeDiscount = subtotal + taxAmount; | |
| 229 | - discountAmount = (totalBeforeDiscount * this.settings.discountValue) / 100; | |
| 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 | + } | |
| 230 | 267 | } |
| 268 | + total = afterDiscountAmount + taxAmount; | |
| 269 | + } else { | |
| 270 | + total = afterDiscountAmount; | |
| 231 | 271 | } |
| 232 | - | |
| 233 | - // Calculate total | |
| 234 | - var total = afterDiscountAmount + taxAmount; | |
| 235 | 272 | |
| 236 | 273 | // Update UI |
| 237 | 274 | $('#subtotal_value').text(this.formatCurrency(subtotal)); |
| 238 | 275 | $('#discount_amount_value').text(this.formatCurrency(discountAmount)); |