// Invoice Form Logic const initInvoiceForm = (searchInputId, suggestionsId, tableBodyId, grandTotalId, subtotalId, totalVatId) => { const searchInput = document.getElementById(searchInputId); const suggestions = document.getElementById(suggestionsId); const tableBody = document.getElementById(tableBodyId); const grandTotalEl = document.getElementById(grandTotalId); const subtotalEl = document.getElementById(subtotalId); const totalVatEl = document.getElementById(totalVatId); if (!searchInput || !tableBody) return; let timeout = null; searchInput.addEventListener('input', function() { clearTimeout(timeout); const q = this.value.trim(); if (q.length < 2) { suggestions.style.display = 'none'; return; } timeout = setTimeout(() => { fetch(`index.php?action=search_items&q=${encodeURIComponent(q)}`) .then(res => res.ok ? res.json() : []) .then(data => { suggestions.innerHTML = ''; if (data.length > 0) { data.forEach(item => { const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'list-group-item list-group-item-action'; btn.innerHTML = `
${item.sku} - ${item.name_en} / ${item.name_ar} Stock: ${item.stock_quantity}
`; btn.onclick = () => addItemToTable(item, tableBody, searchInput, suggestions, grandTotalEl, subtotalEl, totalVatEl); suggestions.appendChild(btn); }); suggestions.style.display = 'block'; } else { suggestions.style.display = 'none'; } }); }, 300); }); // Close suggestions when clicking outside document.addEventListener('click', function(e) { if (!searchInput.contains(e.target) && !suggestions.contains(e.target)) { suggestions.style.display = 'none'; } }); }; function addItemToTable(item, tableBody, searchInput, suggestions, grandTotalEl, subtotalEl, totalVatEl, customData = null) { if (suggestions) suggestions.style.display = 'none'; if (searchInput) searchInput.value = ''; const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1'); const currentStock = parseFloat(item.stock_quantity) || 0; if (invoiceType === 'sale' && !allowZeroStock && !customData) { const existingInTable = Array.from(tableBody.querySelectorAll('.item-row')).find(row => row.querySelector('.item-id-input').value == item.id); let currentQtyInTable = 0; if (existingInTable) { currentQtyInTable = parseFloat(existingInTable.querySelector('.item-qty').value) || 0; } if (currentQtyInTable + 1 > currentStock) { alert('Insufficient stock! Available: ' + currentStock); return; } } const existingRow = Array.from(tableBody.querySelectorAll('.item-id-input')).find(input => input.value == item.id); if (existingRow && !customData) { const row = existingRow.closest('tr'); const qtyInput = row.querySelector('.item-qty'); qtyInput.value = parseFloat(qtyInput.value) + 1; recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl); return; } const row = document.createElement('tr'); row.className = 'item-row'; const price = customData ? customData.unit_price : (invoiceType === 'sale' ? item.sale_price : item.purchase_price); const qty = customData ? customData.quantity : 1; const vatRate = item.vat_rate || 0; row.innerHTML = `
${item.name_en}
${item.name_ar} (${item.sku})
`; tableBody.appendChild(row); attachRowListeners(row, tableBody, grandTotalEl, subtotalEl, totalVatEl); recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl); } function recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl) { let subtotal = 0; let totalVat = 0; tableBody.querySelectorAll('.item-row').forEach(row => { const qty = parseFloat(row.querySelector('.item-qty').value) || 0; const price = parseFloat(row.querySelector('.item-price').value) || 0; const vatRate = parseFloat(row.querySelector('.item-vat-rate').value) || 0; const total = qty * price; const vatAmount = total * (vatRate / 100); row.querySelector('.item-total').value = total.toFixed(3); subtotal += total; totalVat += vatAmount; }); const grandTotal = subtotal + totalVat; if (subtotalEl) subtotalEl.textContent = 'OMR ' + subtotal.toFixed(3); if (totalVatEl) totalVatEl.textContent = 'OMR ' + totalVat.toFixed(2); if (grandTotalEl) grandTotalEl.textContent = 'OMR ' + grandTotal.toFixed(3); } function attachRowListeners(row, tableBody, grandTotalEl, subtotalEl, totalVatEl) { row.querySelector('.item-qty').addEventListener('input', function() { const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1'); if (invoiceType === 'sale' && !allowZeroStock) { const stock = parseFloat(row.querySelector('.item-row-stock').value) || 0; const qty = parseFloat(this.value) || 0; if (qty > stock) { alert('Insufficient stock! Available: ' + stock); this.value = stock; } } recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl); }); row.querySelector('.item-price').addEventListener('input', () => recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl)); row.querySelector('.remove-row').addEventListener('click', function() { row.remove(); recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl); }); } const invoiceType = ''; initInvoiceForm('productSearchInput', 'searchSuggestions', 'invoiceItemsTableBody', 'grandTotal', 'subtotal', 'totalVat'); initInvoiceForm('editProductSearchInput', 'editSearchSuggestions', 'editInvoiceItemsTableBody', 'edit_grandTotal', 'edit_subtotal', 'edit_totalVat');