From 2a7531af42cd7394328bc64aa68f16c862878656 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Tue, 24 Feb 2026 10:44:44 +0000 Subject: [PATCH] fix pug in pos --- assets/js/main.js | 178 +++++++++++++++++++++++----------------------- pos.php | 14 +++- 2 files changed, 101 insertions(+), 91 deletions(-) diff --git a/assets/js/main.js b/assets/js/main.js index d547d9c..51e3e17 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -12,6 +12,13 @@ document.addEventListener('DOMContentLoaded', () => { } }); + // Global settings with fallbacks + const settings = (typeof COMPANY_SETTINGS !== 'undefined') ? COMPANY_SETTINGS : { + currency_symbol: '$', + currency_decimals: 2, + vat_rate: 0 + }; + let cart = []; let currentOrderId = null; // Track order ID for updates const cartItemsContainer = document.getElementById('cart-items'); @@ -49,11 +56,11 @@ document.addEventListener('DOMContentLoaded', () => { let currentTableName = null; const tableDisplay = document.getElementById('current-table-display'); const tableModalEl = document.getElementById('tableSelectionModal'); - const tableSelectionModal = new bootstrap.Modal(tableModalEl); + const tableSelectionModal = tableModalEl ? new bootstrap.Modal(tableModalEl) : null; // Variant Management const variantModalEl = document.getElementById('variantSelectionModal'); - const variantSelectionModal = new bootstrap.Modal(variantModalEl); + const variantSelectionModal = variantModalEl ? new bootstrap.Modal(variantModalEl) : null; let pendingProduct = null; // Customer Search Elements @@ -67,7 +74,7 @@ document.addEventListener('DOMContentLoaded', () => { // Payment Modal const paymentModalEl = document.getElementById('paymentSelectionModal'); - const paymentSelectionModal = new bootstrap.Modal(paymentModalEl); + const paymentSelectionModal = paymentModalEl ? new bootstrap.Modal(paymentModalEl) : null; const paymentMethodsContainer = document.getElementById('payment-methods-container'); // Product Search & Filter @@ -77,7 +84,6 @@ document.addEventListener('DOMContentLoaded', () => { // Helper for currency function formatCurrency(amount) { - const settings = (typeof COMPANY_SETTINGS !== 'undefined') ? COMPANY_SETTINGS : { currency_symbol: '$', currency_decimals: 2 }; const symbol = settings.currency_symbol || '$'; const decimals = parseInt(settings.currency_decimals || 2); return symbol + parseFloat(amount).toFixed(decimals); @@ -106,8 +112,6 @@ document.addEventListener('DOMContentLoaded', () => { if (btnElement) { document.querySelectorAll('.category-btn').forEach(btn => btn.classList.remove('active')); btnElement.classList.add('active'); - } else if (typeof btnElement === 'undefined' && categoryId !== 'all') { - // Try to find the button corresponding to this category ID } filterProducts(); @@ -194,10 +198,7 @@ document.addEventListener('DOMContentLoaded', () => { } // Populate Cart - cart = data.items; // Assuming format matches - - // Note: In auto-VAT mode, we don't load data.order.discount into cartVatInput - // as it will be re-calculated based on subtotal. + cart = data.items; updateCart(); if (recallModal) recallModal.hide(); @@ -263,7 +264,6 @@ document.addEventListener('DOMContentLoaded', () => { customerSearchInput.disabled = true; // Lock input customerResults.style.display = 'none'; clearCustomerBtn.classList.remove('d-none'); - // customerInfo.classList.remove('d-none'); // Loyalty Logic if (loyaltySection && typeof LOYALTY_SETTINGS !== 'undefined' && LOYALTY_SETTINGS.is_enabled) { @@ -280,7 +280,6 @@ document.addEventListener('DOMContentLoaded', () => { } } - // Reset redemption state when switching customer (though usually we clear first) isLoyaltyRedemption = false; } @@ -291,9 +290,8 @@ document.addEventListener('DOMContentLoaded', () => { customerSearchInput.value = ''; customerSearchInput.disabled = false; clearCustomerBtn.classList.add('d-none'); - customerInfo.classList.add('d-none'); + if (customerInfo) customerInfo.classList.add('d-none'); - // Hide Loyalty if (loyaltySection) loyaltySection.classList.add('d-none'); isLoyaltyRedemption = false; updateCart(); @@ -312,7 +310,6 @@ document.addEventListener('DOMContentLoaded', () => { return; } - // --- STRICT ONE ITEM RESTRICTION --- if (cart.length > 1) { showToast("Can only redeem a free meal with exactly one item in cart!", "warning"); return; @@ -332,8 +329,6 @@ document.addEventListener('DOMContentLoaded', () => { if (result.isConfirmed) { isLoyaltyRedemption = true; updateCart(); - - // Directly process order with Loyalty payment type processOrder(null, 'Loyalty Redeem'); } }); @@ -396,7 +391,7 @@ document.addEventListener('DOMContentLoaded', () => { const selected = checked.value; if (selected === 'dine-in') { - if (!currentTableId) openTableSelectionModal(); + if (!currentTableId && tableSelectionModal) openTableSelectionModal(); if (tableDisplay) tableDisplay.style.display = 'inline-block'; } else { if (tableDisplay) tableDisplay.style.display = 'none'; @@ -408,7 +403,9 @@ document.addEventListener('DOMContentLoaded', () => { }); function openTableSelectionModal() { + if (!tableSelectionModal) return; const container = document.getElementById('table-list-container'); + if (!container) return; container.innerHTML = '
'; // Update Modal Title @@ -436,6 +433,7 @@ document.addEventListener('DOMContentLoaded', () => { function renderTables(tables) { const container = document.getElementById('table-list-container'); + if (!container) return; container.innerHTML = ''; if (tables.length === 0) { @@ -473,7 +471,7 @@ document.addEventListener('DOMContentLoaded', () => { tableDisplay.innerHTML = `Table: ${name}`; tableDisplay.style.display = 'block'; } - tableSelectionModal.hide(); + if (tableSelectionModal) tableSelectionModal.hide(); showToast(`Selected Table: ${name}`, 'success'); }; @@ -502,19 +500,20 @@ document.addEventListener('DOMContentLoaded', () => { }); function openVariantModal(product) { + if (!variantSelectionModal) return; pendingProduct = product; - const variants = PRODUCT_VARIANTS[product.id] || []; + const variants = (typeof PRODUCT_VARIANTS !== 'undefined') ? (PRODUCT_VARIANTS[product.id] || []) : []; const list = document.getElementById('variant-list'); const title = document.getElementById('variantModalTitle'); - title.textContent = `Select option for ${product.name}`; + if (title) title.textContent = `Select option for ${product.name}`; + if (!list) return; list.innerHTML = ''; variants.forEach(v => { const btn = document.createElement('button'); btn.className = 'list-group-item list-group-item-action d-flex justify-content-between align-items-center'; const adj = parseFloat(v.price_adjustment); - const sign = adj > 0 ? '+' : ''; const finalPrice = product.base_price + adj; btn.innerHTML = ` @@ -562,69 +561,71 @@ document.addEventListener('DOMContentLoaded', () => { } if (cart.length === 0) { - cartItemsContainer.innerHTML = ` -
- -

Cart is empty

-
`; - cartSubtotal.innerText = formatCurrency(0); - cartVatInput.value = 0; - cartTotalPrice.innerText = formatCurrency(0); + if (cartItemsContainer) { + cartItemsContainer.innerHTML = ` +
+ +

Cart is empty

+
`; + } + if (cartSubtotal) cartSubtotal.innerText = formatCurrency(0); + if (cartVatInput) cartVatInput.value = 0; + if (cartTotalPrice) cartTotalPrice.innerText = formatCurrency(0); if (quickOrderBtn) quickOrderBtn.disabled = true; if (placeOrderBtn) placeOrderBtn.disabled = true; return; } - cartItemsContainer.innerHTML = ''; + if (cartItemsContainer) cartItemsContainer.innerHTML = ''; let subtotal = 0; cart.forEach((item, index) => { const itemTotal = item.price * item.quantity; subtotal += itemTotal; - const row = document.createElement('div'); - row.className = 'd-flex justify-content-between align-items-center mb-3 border-bottom pb-2'; - - const variantLabel = item.variant_name ? `${item.variant_name}` : ''; - const arabicNameDisplay = item.name_ar ? `
${item.name_ar}
` : ''; + if (cartItemsContainer) { + const row = document.createElement('div'); + row.className = 'd-flex justify-content-between align-items-center mb-3 border-bottom pb-2'; + + const variantLabel = item.variant_name ? `${item.variant_name}` : ''; + const arabicNameDisplay = item.name_ar ? `
${item.name_ar}
` : ''; - row.innerHTML = ` -
-
${item.name}
- ${arabicNameDisplay} -
${formatCurrency(item.price)} ${variantLabel}
-
-
- - ${item.quantity} - -
-
-
${formatCurrency(itemTotal)}
- -
- `; - cartItemsContainer.appendChild(row); + row.innerHTML = ` +
+
${item.name}
+ ${arabicNameDisplay} +
${formatCurrency(item.price)} ${variantLabel}
+
+
+ + ${item.quantity} + +
+
+
${formatCurrency(itemTotal)}
+ +
+ `; + cartItemsContainer.appendChild(row); + } }); - cartSubtotal.innerText = formatCurrency(subtotal); + if (cartSubtotal) cartSubtotal.innerText = formatCurrency(subtotal); let vat = 0; if (isLoyaltyRedemption) { - // Internal trick: send negative VAT to represent discount for loyalty vat = -subtotal; } else { - // Automatic VAT calculation from system settings - const vatRate = parseFloat(COMPANY_SETTINGS.vat_rate) || 0; + const vatRate = parseFloat(settings.vat_rate) || 0; vat = subtotal * (vatRate / 100); } - cartVatInput.value = vat.toFixed(2); + if (cartVatInput) cartVatInput.value = vat.toFixed(2); let total = subtotal + vat; if (total < 0) total = 0; - cartTotalPrice.innerText = formatCurrency(total); + if (cartTotalPrice) cartTotalPrice.innerText = formatCurrency(total); if (quickOrderBtn) quickOrderBtn.disabled = false; if (placeOrderBtn) placeOrderBtn.disabled = false; } @@ -647,7 +648,7 @@ document.addEventListener('DOMContentLoaded', () => { }).then((result) => { if (result.isConfirmed) { cart = []; - cartVatInput.value = 0; + if (cartVatInput) cartVatInput.value = 0; currentOrderId = null; isLoyaltyRedemption = false; updateCart(); @@ -707,7 +708,7 @@ document.addEventListener('DOMContentLoaded', () => { if (quickOrderBtn) { quickOrderBtn.addEventListener('click', () => { - if (validateOrder()) { + if (validateOrder() && paymentSelectionModal) { paymentSelectionModal.show(); } }); @@ -738,19 +739,19 @@ document.addEventListener('DOMContentLoaded', () => { const orderTypeInput = document.querySelector('input[name="order_type"]:checked'); const orderType = orderTypeInput ? orderTypeInput.value : 'takeaway'; const subtotal = cart.reduce((acc, item) => acc + (item.price * item.quantity), 0); - const vat = parseFloat(cartVatInput.value) || 0; + const vat = parseFloat(cartVatInput ? cartVatInput.value : 0) || 0; const totalAmount = Math.max(0, subtotal + vat); - const custId = selectedCustomerId.value; + const custId = selectedCustomerId ? selectedCustomerId.value : null; const orderData = { - order_id: currentOrderId, // Include ID if updating + order_id: currentOrderId, table_number: (orderType === 'dine-in') ? currentTableId : null, order_type: orderType, customer_id: custId || null, outlet_id: new URLSearchParams(window.location.search).get('outlet_id') || 1, payment_type_id: paymentTypeId, total_amount: totalAmount, - vat: vat, // Send as vat + vat: vat, redeem_loyalty: isLoyaltyRedemption, items: cart.map(item => ({ product_id: item.id, @@ -782,7 +783,7 @@ document.addEventListener('DOMContentLoaded', () => { if (quickOrderBtn) quickOrderBtn.disabled = false; if (placeOrderBtn) placeOrderBtn.disabled = false; - paymentSelectionModal.hide(); + if (paymentSelectionModal) paymentSelectionModal.hide(); if (data.success) { // Print Receipt @@ -800,9 +801,9 @@ document.addEventListener('DOMContentLoaded', () => { }); cart = []; - cartVatInput.value = 0; - currentOrderId = null; // Reset - isLoyaltyRedemption = false; // Reset + if (cartVatInput) cartVatInput.value = 0; + currentOrderId = null; + isLoyaltyRedemption = false; updateCart(); if (clearCustomerBtn) clearCustomerBtn.click(); showToast(`Order #${data.order_id} placed!`, 'success'); @@ -818,7 +819,7 @@ document.addEventListener('DOMContentLoaded', () => { if (quickOrderBtn) quickOrderBtn.disabled = false; if (placeOrderBtn) placeOrderBtn.disabled = false; - paymentSelectionModal.hide(); + if (paymentSelectionModal) paymentSelectionModal.hide(); showToast('Network Error', 'danger'); }); }; @@ -839,7 +840,7 @@ document.addEventListener('DOMContentLoaded', () => { if (!currentOrderId) return; const subtotal = cart.reduce((acc, item) => acc + (item.price * item.quantity), 0); - const vat = parseFloat(cartVatInput.value) || 0; + const vat = parseFloat(cartVatInput ? cartVatInput.value : 0) || 0; const totalAmount = Math.max(0, subtotal + vat); const orderType = document.querySelector('input[name="order_type"]:checked').value; @@ -858,7 +859,6 @@ document.addEventListener('DOMContentLoaded', () => { }; function printReceipt(data) { - const settings = (typeof COMPANY_SETTINGS !== "undefined") ? COMPANY_SETTINGS : {}; const width = 400; const height = 800; const left = (screen.width - width) / 2; @@ -934,7 +934,10 @@ document.addEventListener('DOMContentLoaded', () => { const loyaltyHtml = data.loyaltyRedeemed ? `
* Loyalty Reward Applied *
` : ''; const subtotal = data.total - data.vat; - const logoHtml = settings.logo_url ? `` : ''; + const baseUrl = (typeof BASE_URL !== 'undefined') ? BASE_URL : ''; + const logoHtml = settings.logo_url ? `` : ''; + const outletName = (typeof CURRENT_OUTLET !== 'undefined') ? CURRENT_OUTLET.name : ''; + const staffName = (typeof CURRENT_USER !== 'undefined') ? CURRENT_USER.name : ''; const html = ` @@ -971,7 +974,7 @@ document.addEventListener('DOMContentLoaded', () => {
${logoHtml}

${settings.company_name}

-
${CURRENT_OUTLET.name}
+
${outletName}
${settings.address}
Tel: ${settings.phone}
${settings.vat_number ? `
VAT No / الرقم الضريبي: ${settings.vat_number}
` : ''} @@ -994,8 +997,8 @@ document.addEventListener('DOMContentLoaded', () => { ${tr['Date']}: ${data.date}
- Staff: ${CURRENT_USER.name} - ${tr['Staff']}: ${CURRENT_USER.name} + Staff: ${staffName} + ${tr['Staff']}: ${staffName}
@@ -1078,20 +1081,12 @@ document.addEventListener('DOMContentLoaded', () => { checkOrderType(); // --- Add Customer Logic --- - const addCustomerBtn = document.getElementById('add-customer-btn'); const addCustomerModalEl = document.getElementById('addCustomerModal'); - if (addCustomerBtn && addCustomerModalEl) { - const addCustomerModal = new bootstrap.Modal(addCustomerModalEl); - const saveCustomerBtn = document.getElementById('save-new-customer'); - const newCustomerName = document.getElementById('new-customer-name'); - const newCustomerPhone = document.getElementById('new-customer-phone'); - - addCustomerBtn.addEventListener('click', () => { - newCustomerName.value = ''; - newCustomerPhone.value = ''; - addCustomerModal.show(); - }); + const saveCustomerBtn = document.getElementById('save-new-customer'); + const newCustomerName = document.getElementById('new-customer-name'); + const newCustomerPhone = document.getElementById('new-customer-phone'); + if (saveCustomerBtn && newCustomerName && newCustomerPhone) { saveCustomerBtn.addEventListener('click', () => { const name = newCustomerName.value.trim(); const phone = newCustomerPhone.value.trim(); @@ -1115,7 +1110,10 @@ document.addEventListener('DOMContentLoaded', () => { saveCustomerBtn.textContent = 'Save Customer'; if (data.success) { - addCustomerModal.hide(); + if (addCustomerModalEl) { + const modal = bootstrap.Modal.getInstance(addCustomerModalEl); + if (modal) modal.hide(); + } selectCustomer(data.customer); showToast('Customer created successfully', 'success'); } else { @@ -1129,4 +1127,4 @@ document.addEventListener('DOMContentLoaded', () => { }); }); } -}); +}); \ No newline at end of file diff --git a/pos.php b/pos.php index 9c4f423..2a667a9 100644 --- a/pos.php +++ b/pos.php @@ -539,6 +539,18 @@ if (!$loyalty_settings) { + + + + - + \ No newline at end of file