From 419681ef66925cb00635933bcd980967e972b891 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Tue, 17 Feb 2026 07:39:57 +0000 Subject: [PATCH] Revert to version 538d43c --- FIX_REPORT.md | 15 -- index.php | 375 ++++++-------------------- test_search_setup.php | 14 - uploads/items/item_6993ed186c662.jfif | Bin 5086 -> 0 bytes 4 files changed, 89 insertions(+), 315 deletions(-) delete mode 100644 FIX_REPORT.md delete mode 100644 test_search_setup.php delete mode 100644 uploads/items/item_6993ed186c662.jfif diff --git a/FIX_REPORT.md b/FIX_REPORT.md deleted file mode 100644 index 3877cde..0000000 --- a/FIX_REPORT.md +++ /dev/null @@ -1,15 +0,0 @@ -I've fixed the search bar functionality and resolved the errors you were seeing. - -**Fixes Applied:** - -1. **Search Bar Not Working:** I wrapped the search initialization code in a `DOMContentLoaded` event listener. This ensures that the search bar elements (like `productSearchInput`) are fully loaded in the browser before the JavaScript tries to attach the search logic to them. Previously, the script was running too early, failing to find the elements, and silently doing nothing. -2. **POS Page Error:** I fixed a critical bug on the POS page where an undefined variable (`$customers`) was causing a PHP warning to be injected into the JavaScript, leading to the "Invalid or unexpected token" syntax error. -3. **PHP Warnings:** I initialized the `$data['customers_list']` variable globally to prevent potential PHP warnings on the Dashboard and other pages where it wasn't being set, which could also break the page layout or scripts. - -**Verification:** - -* **Reload the page.** -* Try searching for an item in the "New Sales Invoice", "New Quotation", or "New Purchase" modals. The search results should now appear correctly. -* Check the POS page to ensure it loads without the previous syntax error. - -Let me know if you encounter any other issues! \ No newline at end of file diff --git a/index.php b/index.php index cb7b448..533eaff 100644 --- a/index.php +++ b/index.php @@ -34,7 +34,6 @@ function numberToWords($num) { if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action'])) { if ($_GET['action'] === 'search_items') { - ob_clean(); // Clear buffer to prevent JSON corruption header('Content-Type: application/json'); $q = $_GET['q'] ?? ''; $stmt = db()->prepare("SELECT id, name_en, name_ar, sku, sale_price, purchase_price, stock_quantity, vat_rate FROM stock_items WHERE name_en LIKE ? OR name_ar LIKE ? OR sku LIKE ? LIMIT 10"); @@ -1051,7 +1050,6 @@ $data['suppliers'] = db()->query("SELECT * FROM customers WHERE type = 'supplier $settings_raw = db()->query("SELECT * FROM settings")->fetchAll(); $data['settings'] = []; -$data['customers_list'] = []; foreach ($settings_raw as $s) { $data['settings'][$s['key']] = $s['value']; } @@ -1112,22 +1110,9 @@ switch ($page) { $where = ["1=1"]; $params = []; if (!empty($_GET['search'])) { - $term = $_GET['search']; - $cleanTerm = str_ireplace(['QUO-', 'INV-'], '', $term); - $cleanTerm = ltrim($cleanTerm, '0'); - - $searchClauses = ["c.name LIKE ?"]; - $params[] = "%$term%"; - - $searchClauses[] = "q.id LIKE ?"; - $params[] = "%$term%"; - - if ($cleanTerm !== '' && $cleanTerm !== $term) { - $searchClauses[] = "q.id LIKE ?"; - $params[] = "%$cleanTerm%"; - } - - $where[] = "(" . implode(" OR ", $searchClauses) . ")"; + $where[] = "(q.id LIKE ? OR c.name LIKE ?)"; + $params[] = "%{$_GET['search']}%"; + $params[] = "%{$_GET['search']}%"; } if (!empty($_GET['customer_id'])) { $where[] = "q.customer_id = ?"; @@ -1158,9 +1143,6 @@ switch ($page) { case 'settings': // Already fetched globally break; - case 'pos': - $data['customers'] = db()->query("SELECT id, name, phone, credit_limit, balance FROM customers WHERE type = 'customer'")->fetchAll(); - break; case 'sales': case 'purchases': $type = ($page === 'sales') ? 'sale' : 'purchase'; @@ -1169,22 +1151,9 @@ switch ($page) { $params = [$type]; if (!empty($_GET['search'])) { - $term = $_GET['search']; - $cleanTerm = str_ireplace(['INV-', 'QUO-'], '', $term); - $cleanTerm = ltrim($cleanTerm, '0'); - - $searchClauses = ["c.name LIKE ?"]; - $params[] = "%$term%"; - - $searchClauses[] = "v.id LIKE ?"; - $params[] = "%$term%"; - - if ($cleanTerm !== '' && $cleanTerm !== $term) { - $searchClauses[] = "v.id LIKE ?"; - $params[] = "%$cleanTerm%"; - } - - $where[] = "(" . implode(" OR ", $searchClauses) . ")"; + $where[] = "(v.id LIKE ? OR c.name LIKE ?)"; + $params[] = "%{$_GET['search']}%"; + $params[] = "%{$_GET['search']}%"; } if (!empty($_GET['customer_id'])) { @@ -2095,7 +2064,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; payments: [], allCreditCustomers: (string)$c['id'], 'text' => $c['name'] . ' (' . ($c['phone'] ?? '') . ')' @@ -3502,12 +3471,12 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; `; }); - const logo = ; - const companyName = ; - const companyPhone = ; - const companyEmail = ; - const companyAddress = ; - const vatNumber = ; + const logo = ""; + const companyName = ""; + const companyPhone = ""; + const companyEmail = ""; + const companyAddress = ""; + const vatNumber = ""; content.innerHTML = `
@@ -3644,6 +3613,53 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; }; document.addEventListener('DOMContentLoaded', function() { + const hasExpiryToggle = document.getElementById('hasExpiryToggle'); + const expiryDateContainer = document.getElementById('expiryDateContainer'); + const suggestSkuBtn = document.getElementById('suggestSkuBtn'); + const skuInput = document.getElementById('skuInput'); + + if (suggestSkuBtn && skuInput) { + suggestSkuBtn.addEventListener('click', function() { + const sku = Math.floor(100000000000 + Math.random() * 900000000000).toString(); + skuInput.value = sku; + }); + } + + // Toggle Expiry Date visibility + if (hasExpiryToggle && expiryDateContainer) { + hasExpiryToggle.addEventListener('change', function() { + expiryDateContainer.style.display = this.checked ? 'block' : 'none'; + if (!this.checked) { + expiryDateContainer.querySelector('input').value = ''; + } + }); + } + + // Status change logic for Paid Amount field + const togglePaidAmount = (statusId, containerId) => { + const statusEl = document.getElementById(statusId); + const containerEl = document.getElementById(containerId); + if (statusEl && containerEl) { + statusEl.addEventListener('change', function() { + if (this.value === 'partially_paid') { + containerEl.style.display = 'block'; + } else { + containerEl.style.display = 'none'; + } + }); + } + }; + togglePaidAmount('add_status', 'addPaidAmountContainer'); + togglePaidAmount('edit_status', 'editPaidAmountContainer'); + + // Show receipt modal if needed + + showReceipt(); + + window.showReceipt = function(paymentId) { fetch(`index.php?action=get_payment_details&payment_id=${paymentId}`) .then(res => res.json()) @@ -3710,60 +3726,6 @@ document.addEventListener('DOMContentLoaded', function() { }); }; - const hasExpiryToggle = document.getElementById('hasExpiryToggle'); - const expiryDateContainer = document.getElementById('expiryDateContainer'); - const suggestSkuBtn = document.getElementById('suggestSkuBtn'); - const skuInput = document.getElementById('skuInput'); - - if (suggestSkuBtn && skuInput) { - suggestSkuBtn.addEventListener('click', function() { - const sku = Math.floor(100000000000 + Math.random() * 900000000000).toString(); - skuInput.value = sku; - }); - } - - // Toggle Expiry Date visibility - if (hasExpiryToggle && expiryDateContainer) { - hasExpiryToggle.addEventListener('change', function() { - expiryDateContainer.style.display = this.checked ? 'block' : 'none'; - if (!this.checked) { - expiryDateContainer.querySelector('input').value = ''; - } - }); - } - - // Status change logic for Paid Amount field - const togglePaidAmount = (statusId, containerId) => { - const statusEl = document.getElementById(statusId); - const containerEl = document.getElementById(containerId); - if (statusEl && containerEl) { - statusEl.addEventListener('change', function() { - if (this.value === 'partially_paid') { - containerEl.style.display = 'block'; - } else { - containerEl.style.display = 'none'; - } - }); - } - }; - togglePaidAmount('add_status', 'addPaidAmountContainer'); - togglePaidAmount('edit_status', 'editPaidAmountContainer'); - - // Show receipt modal if needed - - document.addEventListener('DOMContentLoaded', function() { - if (typeof showReceipt === 'function') { - showReceipt(); - } else { - console.error('showReceipt function not found'); - } - }); - - - document.querySelectorAll('.view-payments-btn').forEach(btn => { btn.addEventListener('click', function() { const invoiceId = this.getAttribute('data-id'); @@ -3835,44 +3797,21 @@ document.addEventListener('DOMContentLoaded', function() { const row = document.createElement('tr'); row.className = 'item-row'; - - // Determine invoice type from the form context - let currentInvoiceType = 'sale'; - const form = tableBody.closest('form'); - if (form) { - const typeInput = form.querySelector('input[name="type"]'); - if (typeInput) { - currentInvoiceType = typeInput.value; - } else if (window.invoiceType) { - currentInvoiceType = window.invoiceType; - } - } else if (window.invoiceType) { - currentInvoiceType = window.invoiceType; - } - + const currentInvoiceType = window.invoiceType || 'sale'; const price = customData ? customData.unit_price : (currentInvoiceType === 'sale' ? item.sale_price : item.purchase_price); const qty = customData ? customData.quantity : 1; const vatRate = item.vat_rate || 0; - const escapeHtml = (unsafe) => { - return String(unsafe) - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); - }; - row.innerHTML = ` - - -
${escapeHtml(item.name_en)}
-
${escapeHtml(item.name_ar)} (${escapeHtml(item.sku)})
+ + +
${item.name_en}
+
${item.name_ar} (${item.sku})
- - - + + + `; @@ -3915,201 +3854,65 @@ document.addEventListener('DOMContentLoaded', function() { window.initInvoiceForm = function(searchInputId, suggestionsId, tableBodyId, grandTotalId, subtotalId, totalVatId) { const searchInput = document.getElementById(searchInputId); - let suggestions = document.getElementById(suggestionsId); + 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) { console.error('Search input not found:', searchInputId); return; } - if (!tableBody) { console.error('Table body not found:', tableBodyId); return; } - - // Move suggestions to body to avoid z-index/overflow issues in modals - if (suggestions && suggestions.parentNode !== document.body) { - if (suggestions.parentNode) suggestions.parentNode.removeChild(suggestions); - document.body.appendChild(suggestions); - suggestions.style.position = 'absolute'; - suggestions.style.zIndex = '10000'; // Ensure it is above everything - suggestions.style.width = Math.max(searchInput.offsetWidth, 300) + 'px'; // Initial width - suggestions.style.maxHeight = '300px'; - suggestions.style.overflowY = 'auto'; - suggestions.style.backgroundColor = 'white'; - suggestions.style.border = '1px solid #ccc'; - suggestions.style.borderRadius = '0.25rem'; - suggestions.style.boxShadow = '0 0.5rem 1rem rgba(0, 0, 0, 0.15)'; - } - - const positionSuggestions = () => { - if (!suggestions || suggestions.style.display === 'none') return; - const rect = searchInput.getBoundingClientRect(); - const scrollTop = window.pageYOffset || document.documentElement.scrollTop; - const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; - - suggestions.style.top = (rect.bottom + scrollTop) + 'px'; - suggestions.style.left = (rect.left + scrollLeft) + 'px'; - suggestions.style.width = Math.max(rect.width, 300) + 'px'; - }; - - window.addEventListener('resize', positionSuggestions); - window.addEventListener('scroll', positionSuggestions, true); - - const escapeHtml = (unsafe) => { - return String(unsafe) - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); - }; + if (!searchInput || !tableBody) return; let timeout = null; - // Prevent form submission on Enter key - Aggressive Fix - const handleEnterKey = function(e) { - if (e.key === 'Enter' || e.keyCode === 13) { - e.preventDefault(); - e.stopPropagation(); - e.stopImmediatePropagation(); - - // If suggestions are visible, click the first one - if (suggestions && suggestions.style.display !== 'none') { - const firstBtn = suggestions.querySelector('button'); - if (firstBtn) firstBtn.click(); - } - return false; - } - }; - // Use capture phase to intercept before bubbling - searchInput.addEventListener('keydown', handleEnterKey, true); - searchInput.addEventListener('keypress', handleEnterKey, true); - searchInput.addEventListener('input', function() { clearTimeout(timeout); const q = this.value.trim(); - if (q.length < 1) { - if (suggestions) suggestions.style.display = 'none'; + suggestions.style.display = 'none'; return; } - // Show loading state - if (suggestions) { - suggestions.innerHTML = '
Searching...
'; - suggestions.style.display = 'block'; - positionSuggestions(); - } - timeout = setTimeout(() => { - console.log(`Searching for: ${q}`); fetch(`index.php?action=search_items&q=${encodeURIComponent(q)}`) - .then(res => { - if (!res.ok) throw new Error('Network response: ' + res.statusText); - return res.text(); - }) - .then(text => { - try { - return JSON.parse(text); - } catch (e) { - console.error('JSON Parse Error:', text); - throw new Error('Invalid JSON response'); - } - }) + .then(res => res.json()) .then(data => { - console.log('Search results:', data); - if (!suggestions) return; suggestions.innerHTML = ''; - if (data && data.length > 0) { + if (data.length > 0) { data.forEach(item => { const btn = document.createElement('button'); btn.type = 'button'; - btn.className = 'list-group-item list-group-item-action p-2'; + btn.className = 'list-group-item list-group-item-action'; btn.innerHTML = ` -
-
-
${escapeHtml(item.sku)}
-
${escapeHtml(item.name_en)}
-
- ${parseFloat(item.stock_quantity).toFixed(2)} +
+ ${item.sku} - ${item.name_en} / ${item.name_ar} + Stock: ${item.stock_quantity}
`; - btn.addEventListener('click', (e) => { - e.preventDefault(); - e.stopPropagation(); - window.addItemToTable(item, tableBody, searchInput, suggestions, grandTotalEl, subtotalEl, totalVatEl); - suggestions.style.display = 'none'; - }); + btn.onclick = () => window.addItemToTable(item, tableBody, searchInput, suggestions, grandTotalEl, subtotalEl, totalVatEl); suggestions.appendChild(btn); }); suggestions.style.display = 'block'; - positionSuggestions(); } else { - suggestions.innerHTML = '
No items found
'; - suggestions.style.display = 'block'; - positionSuggestions(); - } - }) - .catch(err => { - console.error('Search error:', err); - if (suggestions) { - suggestions.innerHTML = '
Error searching items
'; - suggestions.style.display = 'block'; - positionSuggestions(); + suggestions.style.display = 'none'; } }); }, 300); }); document.addEventListener('click', function(e) { - if (suggestions && !searchInput.contains(e.target) && !suggestions.contains(e.target)) { + if (!searchInput.contains(e.target) && !suggestions.contains(e.target)) { suggestions.style.display = 'none'; } }); - - // Hide on modal close - document.querySelectorAll('.modal').forEach(m => { - m.addEventListener('hide.bs.modal', () => { - if (suggestions) suggestions.style.display = 'none'; - }); - // Update position on modal scroll - m.addEventListener('scroll', positionSuggestions); - }); }; window.invoiceType = ''; - document.addEventListener('DOMContentLoaded', function() { - initInvoiceForm('productSearchInput', 'searchSuggestions', 'invoiceItemsTableBody', 'grandTotal', 'subtotal', 'totalVat'); - initInvoiceForm('editProductSearchInput', 'editSearchSuggestions', 'editInvoiceItemsTableBody', 'edit_grandTotal', 'edit_subtotal', 'edit_totalVat'); + initInvoiceForm('productSearchInput', 'searchSuggestions', 'invoiceItemsTableBody', 'grandTotal', 'subtotal', 'totalVat'); + initInvoiceForm('editProductSearchInput', 'editSearchSuggestions', 'editInvoiceItemsTableBody', 'edit_grandTotal', 'edit_subtotal', 'edit_totalVat'); - // Quotation Form Logic - initInvoiceForm('quotProductSearchInput', 'quotSearchSuggestions', 'quotItemsTableBody', 'quot_grand_display', 'quot_subtotal_display', 'quot_vat_display'); - initInvoiceForm('editQuotProductSearchInput', 'editQuotSearchSuggestions', 'editQuotItemsTableBody', 'edit_quot_grand_display', 'edit_quot_subtotal_display', 'edit_quot_vat_display'); - - // Global safeguard: Prevent form submission on Enter for search inputs - document.querySelectorAll('.modal form').forEach(form => { - // Prevent submission if triggered by search input - form.addEventListener('submit', function(e) { - const active = document.activeElement; - if (active && active.tagName === 'INPUT' && active.id && active.id.toLowerCase().includes('searchinput')) { - e.preventDefault(); - e.stopPropagation(); - return false; - } - }); - - // Prevent Keydown/Keypress bubbling up to form submission - const preventEnter = function(e) { - if ((e.key === 'Enter' || e.keyCode === 13) && e.target.tagName === 'INPUT') { - if (e.target.id && e.target.id.toLowerCase().includes('searchinput')) { - e.preventDefault(); - e.stopPropagation(); - return false; - } - } - }; - form.addEventListener('keydown', preventEnter, true); // Capture phase - form.addEventListener('keypress', preventEnter, true); // Capture phase - }); - }); + // Quotation Form Logic + window.initInvoiceForm('quotProductSearchInput', 'quotSearchSuggestions', 'quotItemsTableBody', 'quot_grand_display', 'quot_subtotal_display', 'quot_vat_display'); + window.initInvoiceForm('editQuotProductSearchInput', 'editQuotSearchSuggestions', 'editQuotItemsTableBody', 'edit_quot_grand_display', 'edit_quot_subtotal_display', 'edit_quot_vat_display'); // Global Actions Handler - Delegation for list buttons document.addEventListener('click', function(e) { @@ -4288,7 +4091,7 @@ document.addEventListener('DOMContentLoaded', function() {
- +
@@ -4388,7 +4191,7 @@ document.addEventListener('DOMContentLoaded', function() {
- +
@@ -4470,7 +4273,7 @@ document.addEventListener('DOMContentLoaded', function() {
- +
@@ -4563,7 +4366,7 @@ document.addEventListener('DOMContentLoaded', function() {
- +
diff --git a/test_search_setup.php b/test_search_setup.php deleted file mode 100644 index 00dae94..0000000 --- a/test_search_setup.php +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/uploads/items/item_6993ed186c662.jfif b/uploads/items/item_6993ed186c662.jfif deleted file mode 100644 index d918c283cb06c2870cf1a98e73c5ab45410a9b67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5086 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