document.addEventListener('DOMContentLoaded', () => {
// SweetAlert2 Toast Mixin
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer);
toast.addEventListener('mouseleave', Swal.resumeTimer);
}
});
let cart = [];
let currentOrderId = null; // Track order ID for updates
const cartItemsContainer = document.getElementById('cart-items');
const cartTotalPrice = document.getElementById('cart-total-price');
const cartSubtotal = document.getElementById('cart-subtotal');
const cartVatInput = document.getElementById('cart-vat-input');
// Updated Button References
const quickOrderBtn = document.getElementById('quick-order-btn');
const placeOrderBtn = document.getElementById('place-order-btn');
const recallBtn = document.getElementById('recall-bill-btn');
const reprintReceiptBtn = document.getElementById('reprint-receipt-btn');
// Recall Modal
const recallModalEl = document.getElementById('recallOrderModal');
const recallModal = recallModalEl ? new bootstrap.Modal(recallModalEl) : null;
const recallList = document.getElementById('recall-orders-list');
// Loyalty State
let isLoyaltyRedemption = false;
const loyaltySection = document.getElementById('loyalty-section');
const loyaltyPointsDisplay = document.getElementById('loyalty-points-display');
const loyaltyMessage = document.getElementById('loyalty-message');
const redeemLoyaltyBtn = document.getElementById('redeem-loyalty-btn');
const viewPointsHistoryBtn = document.getElementById('view-points-history-btn');
// Points History Modal
const pointsHistoryModalEl = document.getElementById('pointsHistoryModal');
const pointsHistoryModal = pointsHistoryModalEl ? new bootstrap.Modal(pointsHistoryModalEl) : null;
const pointsHistoryBody = document.getElementById('points-history-body');
const pointsHistoryEmpty = document.getElementById('points-history-empty');
// Table Management
let currentTableId = null;
let currentTableName = null;
const tableDisplay = document.getElementById('current-table-display');
const tableModalEl = document.getElementById('tableSelectionModal');
const tableSelectionModal = new bootstrap.Modal(tableModalEl);
// Variant Management
const variantModalEl = document.getElementById('variantSelectionModal');
const variantSelectionModal = new bootstrap.Modal(variantModalEl);
let pendingProduct = null;
// Customer Search Elements
const customerSearchInput = document.getElementById('customer-search');
const customerResults = document.getElementById('customer-results');
const selectedCustomerId = document.getElementById('selected-customer-id');
const clearCustomerBtn = document.getElementById('clear-customer');
const customerInfo = document.getElementById('customer-info');
const customerNameDisplay = document.getElementById('customer-name-display');
let currentCustomer = null;
// Payment Modal
const paymentModalEl = document.getElementById('paymentSelectionModal');
const paymentSelectionModal = new bootstrap.Modal(paymentModalEl);
const paymentMethodsContainer = document.getElementById('payment-methods-container');
// Product Search & Filter
const productSearchInput = document.getElementById('product-search-input');
let currentCategory = 'all';
let currentSearchQuery = '';
// 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);
}
// --- Product Filtering (Category + Search) ---
function filterProducts() {
const items = document.querySelectorAll('.product-item');
items.forEach(item => {
const matchesCategory = (currentCategory == 'all' || item.dataset.categoryId == currentCategory);
const name = item.querySelector('.card-title').textContent.toLowerCase();
const matchesSearch = name.includes(currentSearchQuery);
if (matchesCategory && matchesSearch) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
});
}
window.filterCategory = function(categoryId, btnElement) {
currentCategory = categoryId;
// Update Active Button State
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();
};
if (productSearchInput) {
productSearchInput.addEventListener('input', (e) => {
currentSearchQuery = e.target.value.trim().toLowerCase();
filterProducts();
});
}
// --- Recall Order Logic ---
if (recallBtn) {
recallBtn.addEventListener('click', () => {
fetchRecallOrders();
});
}
function fetchRecallOrders() {
if (!recallList) return;
recallList.innerHTML = '
';
if (recallModal) recallModal.show();
const outletId = new URLSearchParams(window.location.search).get('outlet_id') || 1;
fetch(`api/recall_orders.php?action=list&outlet_id=${outletId}`)
.then(res => res.json())
.then(data => {
recallList.innerHTML = '';
if (data.success && data.orders.length > 0) {
data.orders.forEach(order => {
const item = document.createElement('button');
item.className = 'list-group-item list-group-item-action d-flex justify-content-between align-items-center';
item.innerHTML = `
Order #${order.id} ${order.order_type}
${order.customer_name || 'Guest'}
${order.table_number ? ' • Table ' + order.table_number : ''}
• ${order.time_formatted}
${formatCurrency(order.total_amount)}
${order.item_count} items
`;
item.onclick = () => loadRecalledOrder(order.id);
recallList.appendChild(item);
});
} else {
recallList.innerHTML = 'No unpaid bills found.
';
}
})
.catch(err => {
recallList.innerHTML = 'Error fetching orders.
';
});
}
function loadRecalledOrder(orderId) {
fetch(`api/recall_orders.php?action=details&id=${orderId}`)
.then(res => res.json())
.then(data => {
if (data.success) {
// Set Order ID
currentOrderId = data.order.id;
// Set Customer
if (data.customer) {
selectCustomer(data.customer);
} else {
if (clearCustomerBtn) clearCustomerBtn.click();
}
// Set Table/Order Type
const otInput = document.querySelector(`input[name="order_type"][value="${data.order.order_type}"]`);
if (otInput) {
otInput.checked = true;
if (data.order.order_type === 'dine-in' && data.order.table_id) {
selectTable(data.order.table_id, data.order.table_number);
} else {
checkOrderType();
}
}
// 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.
updateCart();
if (recallModal) recallModal.hide();
showToast(`Order #${orderId} loaded!`, 'success');
} else {
showToast(data.error || 'Failed to load order', 'danger');
}
})
.catch(err => showToast('Error loading order details', 'danger'));
}
// --- Customer Search ---
let searchTimeout;
if (customerSearchInput) {
customerSearchInput.addEventListener('input', (e) => {
const query = e.target.value.trim();
clearTimeout(searchTimeout);
if (query.length < 2) {
customerResults.style.display = 'none';
return;
}
searchTimeout = setTimeout(() => {
fetch(`api/search_customers.php?q=${encodeURIComponent(query)}`)
.then(res => res.json())
.then(data => {
customerResults.innerHTML = '';
if (data.length > 0) {
data.forEach(cust => {
const a = document.createElement('a');
a.href = '#';
a.className = 'list-group-item list-group-item-action';
a.innerHTML = `${cust.name}
${cust.phone || ''}
`;
a.onclick = (ev) => {
ev.preventDefault();
selectCustomer(cust);
};
customerResults.appendChild(a);
});
customerResults.style.display = 'block';
} else {
customerResults.innerHTML = 'No results found
';
customerResults.style.display = 'block';
}
});
}, 300);
});
// Close search on click outside
document.addEventListener('click', (e) => {
if (!customerSearchInput.contains(e.target) && !customerResults.contains(e.target)) {
customerResults.style.display = 'none';
}
});
}
function selectCustomer(cust) {
currentCustomer = cust;
selectedCustomerId.value = cust.id;
customerNameDisplay.textContent = cust.name;
customerSearchInput.value = cust.name; // Show name in input
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) {
loyaltySection.classList.remove('d-none');
loyaltyPointsDisplay.textContent = cust.points + ' pts';
if (cust.eligible_for_free_meal) {
redeemLoyaltyBtn.disabled = false;
loyaltyMessage.innerHTML = 'Eligible for Free Meal!';
} else {
redeemLoyaltyBtn.disabled = true;
const needed = cust.points_needed || 0;
loyaltyMessage.textContent = `${needed} pts away from a free meal.`;
}
}
// Reset redemption state when switching customer (though usually we clear first)
isLoyaltyRedemption = false;
}
if (clearCustomerBtn) {
clearCustomerBtn.addEventListener('click', () => {
currentCustomer = null;
selectedCustomerId.value = '';
customerSearchInput.value = '';
customerSearchInput.disabled = false;
clearCustomerBtn.classList.add('d-none');
customerInfo.classList.add('d-none');
// Hide Loyalty
if (loyaltySection) loyaltySection.classList.add('d-none');
isLoyaltyRedemption = false;
updateCart();
customerSearchInput.focus();
});
}
// Loyalty Redeem Click
if (redeemLoyaltyBtn) {
redeemLoyaltyBtn.addEventListener('click', () => {
if (typeof LOYALTY_SETTINGS === 'undefined' || !LOYALTY_SETTINGS.is_enabled) return;
if (cart.length === 0) {
showToast("Cart is empty!", "warning");
return;
}
// --- STRICT ONE ITEM RESTRICTION ---
if (cart.length > 1) {
showToast("Can only redeem a free meal with exactly one item in cart!", "warning");
return;
}
if (!currentCustomer || !currentCustomer.eligible_for_free_meal) return;
Swal.fire({
title: 'Redeem Loyalty?',
text: "Redeem points for a free meal? This will finalize the order immediately.",
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#198754',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Yes, redeem and finish!'
}).then((result) => {
if (result.isConfirmed) {
isLoyaltyRedemption = true;
updateCart();
// Directly process order with Loyalty payment type
processOrder(null, 'Loyalty Redeem');
}
});
});
}
// Points History View
if (viewPointsHistoryBtn) {
viewPointsHistoryBtn.addEventListener('click', () => {
if (!currentCustomer) return;
fetchPointsHistory(currentCustomer.id);
});
}
function fetchPointsHistory(customerId) {
if (!pointsHistoryBody || !pointsHistoryModal) return;
pointsHistoryBody.innerHTML = '| Loading... |
';
pointsHistoryEmpty.classList.add('d-none');
pointsHistoryModal.show();
fetch(`api/customer_loyalty_history.php?customer_id=${customerId}`)
.then(res => res.json())
.then(data => {
pointsHistoryBody.innerHTML = '';
if (data.success && data.history.length > 0) {
data.history.forEach(item => {
const tr = document.createElement('tr');
const dateObj = new Date(item.created_at);
const date = dateObj.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' }) + ' ' +
dateObj.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });
const pointsClass = item.points_change > 0 ? 'text-success' : 'text-danger';
const pointsPrefix = item.points_change > 0 ? '+' : '';
tr.innerHTML = `
${date} |
${item.reason}
${item.order_id ? `Order #${item.order_id} ` : ''}
|
${pointsPrefix}${item.points_change} |
`;
pointsHistoryBody.appendChild(tr);
});
} else {
pointsHistoryEmpty.classList.remove('d-none');
}
})
.catch(err => {
pointsHistoryBody.innerHTML = '| Error loading history |
';
});
}
// --- Table & Order Type Logic ---
const orderTypeInputs = document.querySelectorAll('input[name="order_type"]');
function checkOrderType() {
const checked = document.querySelector('input[name="order_type"]:checked');
if (!checked) return;
const selected = checked.value;
if (selected === 'dine-in') {
if (!currentTableId) openTableSelectionModal();
if (tableDisplay) tableDisplay.style.display = 'inline-block';
} else {
if (tableDisplay) tableDisplay.style.display = 'none';
}
}
orderTypeInputs.forEach(input => {
input.addEventListener('change', checkOrderType);
});
function openTableSelectionModal() {
const container = document.getElementById('table-list-container');
container.innerHTML = '';
// Update Modal Title
const modalTitle = document.querySelector('#tableSelectionModal .modal-title');
if (modalTitle && typeof CURRENT_OUTLET !== 'undefined') {
modalTitle.textContent = `Select Table - ${CURRENT_OUTLET.name}`;
}
tableSelectionModal.show();
const outletId = new URLSearchParams(window.location.search).get('outlet_id') || 1;
fetch(`api/tables.php?outlet_id=${outletId}`)
.then(res => res.json())
.then(data => {
if (data.success) {
renderTables(data.tables);
} else {
container.innerHTML = `${data.error}
`;
}
})
.catch(() => {
container.innerHTML = `Error loading tables.
`;
});
}
function renderTables(tables) {
const container = document.getElementById('table-list-container');
container.innerHTML = '';
if (tables.length === 0) {
const outletName = (typeof CURRENT_OUTLET !== 'undefined') ? CURRENT_OUTLET.name : 'this outlet';
container.innerHTML = `
No tables found for ${outletName}.
`;
return;
}
tables.forEach(table => {
const isOccupied = table.is_occupied;
const col = document.createElement('div');
col.className = 'col-6 col-md-4 col-lg-3';
col.innerHTML = `
${table.name}
${table.capacity} Pax
${isOccupied ? 'Occupied' : 'Available'}
`;
container.appendChild(col);
});
}
window.selectTable = function(id, name) {
currentTableId = id;
currentTableName = name;
if (tableDisplay) {
tableDisplay.innerHTML = `Table: ${name}`;
tableDisplay.style.display = 'block';
}
tableSelectionModal.hide();
showToast(`Selected Table: ${name}`, 'success');
};
// --- Cart Logic ---
document.querySelectorAll('.add-to-cart').forEach(card => {
card.addEventListener('click', (e) => {
const target = e.currentTarget;
const product = {
id: target.dataset.id,
name: target.dataset.name,
name_ar: target.dataset.nameAr || '',
price: parseFloat(target.dataset.price),
base_price: parseFloat(target.dataset.price),
hasVariants: target.dataset.hasVariants === 'true',
quantity: 1,
variant_id: null,
variant_name: null
};
if (product.hasVariants) {
openVariantModal(product);
} else {
addToCart(product);
}
});
});
function openVariantModal(product) {
pendingProduct = product;
const variants = PRODUCT_VARIANTS[product.id] || [];
const list = document.getElementById('variant-list');
const title = document.getElementById('variantModalTitle');
title.textContent = `Select option for ${product.name}`;
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 = `
${v.name}
${formatCurrency(finalPrice)}
`;
btn.onclick = () => {
pendingProduct.variant_id = v.id;
pendingProduct.variant_name = v.name;
pendingProduct.price = finalPrice;
addToCart(pendingProduct);
variantSelectionModal.hide();
};
list.appendChild(btn);
});
variantSelectionModal.show();
}
function addToCart(product) {
const existing = cart.find(item => item.id === product.id && item.variant_id === product.variant_id);
if (existing) {
existing.quantity++;
} else {
cart.push({...product});
}
updateCart();
}
window.changeQuantity = function(index, delta) {
if (cart[index]) {
cart[index].quantity += delta;
if (cart[index].quantity <= 0) {
removeFromCart(index);
} else {
updateCart();
}
}
};
function updateCart() {
if (reprintReceiptBtn) {
if (currentOrderId) reprintReceiptBtn.classList.remove('d-none');
else reprintReceiptBtn.classList.add('d-none');
}
if (cart.length === 0) {
cartItemsContainer.innerHTML = `
`;
cartSubtotal.innerText = formatCurrency(0);
cartVatInput.value = 0;
cartTotalPrice.innerText = formatCurrency(0);
if (quickOrderBtn) quickOrderBtn.disabled = true;
if (placeOrderBtn) placeOrderBtn.disabled = true;
return;
}
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}
` : '';
row.innerHTML = `
${item.name}
${arabicNameDisplay}
${formatCurrency(item.price)} ${variantLabel}
${item.quantity}
${formatCurrency(itemTotal)}
`;
cartItemsContainer.appendChild(row);
});
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;
vat = subtotal * (vatRate / 100);
}
cartVatInput.value = vat.toFixed(2);
let total = subtotal + vat;
if (total < 0) total = 0;
cartTotalPrice.innerText = formatCurrency(total);
if (quickOrderBtn) quickOrderBtn.disabled = false;
if (placeOrderBtn) placeOrderBtn.disabled = false;
}
window.removeFromCart = function(index) {
cart.splice(index, 1);
updateCart();
};
window.clearCart = function() {
if (cart.length === 0) return;
Swal.fire({
title: 'Clear Cart?',
text: "Are you sure you want to remove all items from the cart?",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#dc3545',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Yes, clear it!'
}).then((result) => {
if (result.isConfirmed) {
cart = [];
cartVatInput.value = 0;
currentOrderId = null;
isLoyaltyRedemption = false;
updateCart();
showToast("Cart cleared", "success");
}
});
};
// --- Payment Selection Logic ---
function renderPaymentMethods() {
if (!paymentMethodsContainer) return;
paymentMethodsContainer.innerHTML = '';
if (typeof PAYMENT_TYPES !== 'undefined' && PAYMENT_TYPES.length > 0) {
PAYMENT_TYPES.forEach(pt => {
const col = document.createElement('div');
col.className = 'col-6';
col.innerHTML = `
`;
paymentMethodsContainer.appendChild(col);
});
} else {
paymentMethodsContainer.innerHTML = 'No payment methods configured.
';
}
}
function getPaymentIcon(name) {
const n = name.toLowerCase();
if (n.includes('cash')) return 'bi-cash-coin';
if (n.includes('card') || n.includes('visa') || n.includes('master')) return 'bi-credit-card';
if (n.includes('qr') || n.includes('scan')) return 'bi-qr-code';
if (n.includes('bank') || n.includes('transfer')) return 'bi-building-columns';
return 'bi-wallet2';
}
renderPaymentMethods();
// --- Checkout Flow (Quick Order) ---
function validateOrder() {
if (cart.length === 0) return false;
const orderTypeInput = document.querySelector('input[name="order_type"]:checked');
const orderType = orderTypeInput ? orderTypeInput.value : 'takeaway';
if (orderType === 'dine-in' && !currentTableId) {
showToast('Please select a table first', 'warning');
openTableSelectionModal();
return false;
}
return true;
}
if (quickOrderBtn) {
quickOrderBtn.addEventListener('click', () => {
if (validateOrder()) {
paymentSelectionModal.show();
}
});
}
// --- Place Order (Pay Later) Flow ---
if (placeOrderBtn) {
placeOrderBtn.addEventListener('click', () => {
if (validateOrder()) {
Swal.fire({
title: 'Place Order?',
text: "Place order without immediate payment?",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#ffc107',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Yes, place order'
}).then((result) => {
if (result.isConfirmed) {
processOrder(null, 'Pay Later');
}
});
}
});
}
window.processOrder = function(paymentTypeId, paymentTypeName) {
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 totalAmount = Math.max(0, subtotal + vat);
const custId = selectedCustomerId.value;
const orderData = {
order_id: currentOrderId, // Include ID if updating
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
redeem_loyalty: isLoyaltyRedemption,
items: cart.map(item => ({
product_id: item.id,
quantity: item.quantity,
unit_price: item.price,
variant_id: item.variant_id
}))
};
// Disable buttons
if (paymentMethodsContainer) {
const btns = paymentMethodsContainer.querySelectorAll('button');
btns.forEach(b => b.disabled = true);
}
if (quickOrderBtn) quickOrderBtn.disabled = true;
if (placeOrderBtn) placeOrderBtn.disabled = true;
fetch('api/order.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(orderData)
})
.then(res => res.json())
.then(data => {
if (paymentMethodsContainer) {
const btns = paymentMethodsContainer.querySelectorAll('button');
btns.forEach(b => b.disabled = false);
}
if (quickOrderBtn) quickOrderBtn.disabled = false;
if (placeOrderBtn) placeOrderBtn.disabled = false;
paymentSelectionModal.hide();
if (data.success) {
// Print Receipt
printReceipt({
orderId: data.order_id,
customer: currentCustomer,
items: [...cart],
total: totalAmount,
vat: vat,
orderType: orderType,
tableNumber: (orderType === 'dine-in') ? currentTableName : null,
date: new Date().toLocaleString(),
paymentMethod: paymentTypeName,
loyaltyRedeemed: isLoyaltyRedemption
});
cart = [];
cartVatInput.value = 0;
currentOrderId = null; // Reset
isLoyaltyRedemption = false; // Reset
updateCart();
if (clearCustomerBtn) clearCustomerBtn.click();
showToast(`Order #${data.order_id} placed!`, 'success');
} else {
showToast(`Error: ${data.error}`, 'danger');
}
})
.catch(err => {
if (paymentMethodsContainer) {
const btns = paymentMethodsContainer.querySelectorAll('button');
btns.forEach(b => b.disabled = false);
}
if (quickOrderBtn) quickOrderBtn.disabled = false;
if (placeOrderBtn) placeOrderBtn.disabled = false;
paymentSelectionModal.hide();
showToast('Network Error', 'danger');
});
};
function showToast(msg, type = 'primary') {
let icon = 'info';
if (type === 'success') icon = 'success';
if (type === 'danger') icon = 'error';
if (type === 'warning') icon = 'warning';
Toast.fire({
icon: icon,
title: msg
});
}
window.reprintCurrentReceipt = function() {
if (!currentOrderId) return;
const subtotal = cart.reduce((acc, item) => acc + (item.price * item.quantity), 0);
const vat = parseFloat(cartVatInput.value) || 0;
const totalAmount = Math.max(0, subtotal + vat);
const orderType = document.querySelector('input[name="order_type"]:checked').value;
printReceipt({
orderId: currentOrderId,
customer: currentCustomer,
items: [...cart],
total: totalAmount,
vat: vat,
orderType: orderType,
tableNumber: (orderType === 'dine-in') ? currentTableName : null,
date: new Date().toLocaleString() + ' (Reprint)',
paymentMethod: 'Previously Settled',
loyaltyRedeemed: isLoyaltyRedemption
});
};
function printReceipt(data) {
const settings = (typeof COMPANY_SETTINGS !== "undefined") ? COMPANY_SETTINGS : {};
const width = 400;
const height = 800;
const left = (screen.width - width) / 2;
const top = (screen.height - height) / 2;
const win = window.open('', 'Receipt', `width=${width},height=${height},top=${top},left=${left}`);
if (!win) {
alert('Please allow popups for this website to print receipts.');
return;
}
const tr = {
'Order': 'الطلب',
'Type': 'النوع',
'Date': 'التاريخ',
'Staff': 'الموظف',
'Table': 'طاولة',
'Payment': 'الدفع',
'ITEM': 'الصنف',
'TOTAL': 'المجموع',
'Subtotal': 'المجموع الفرعي',
'VAT': 'ضريبة القيمة المضافة',
'Tax Included': 'شامل الضريبة',
'THANK YOU FOR YOUR VISIT!': 'شكراً لزيارتكم!',
'Please come again.': 'يرجى زيارتنا مرة أخرى.',
'Customer Details': 'تفاصيل العميل',
'Tel': 'هاتف',
'takeaway': 'سفري',
'dine-in': 'محلي',
'delivery': 'توصيل',
'VAT No': 'الرقم الضريبي',
'CTR No': 'رقم السجل التجاري'
};
const itemsHtml = data.items.map(item => `
|
${item.name}
${item.name_ar ? `${item.name_ar} ` : ''}
${item.variant_name ? `(${item.variant_name}) ` : ''}
${item.quantity} x ${formatCurrency(item.price)}
|
${formatCurrency(item.quantity * item.price)} |
`).join('');
const customerHtml = data.customer ? `
Customer Details
${tr['Customer Details']}
${data.customer.name}
${data.customer.phone ? `
Tel: ${data.customer.phone}
` : ''}
${data.customer.address ? `
${data.customer.address}
` : ''}
` : '';
const tableHtml = data.tableNumber ? `
Table: ${data.tableNumber}
${tr['Table']}: ${data.tableNumber}
` : '';
const paymentHtml = data.paymentMethod ? `
Payment: ${data.paymentMethod}
${tr['Payment']}: ${data.paymentMethod}
` : '';
const loyaltyHtml = data.loyaltyRedeemed ? `* Loyalty Reward Applied *
` : '';
const subtotal = data.total - data.vat;
const logoHtml = settings.logo_url ? `
` : '';
const html = `
Receipt #${data.orderId}
Order: #${data.orderId}
${tr['Order']}: #${data.orderId}
Type: ${data.orderType.toUpperCase()}
${tr['Type']}: ${tr[data.orderType] || data.orderType}
Date: ${data.date}
${tr['Date']}: ${data.date}
Staff: ${CURRENT_USER.name}
${tr['Staff']}: ${CURRENT_USER.name}
${tableHtml}
${paymentHtml}
${loyaltyHtml}
${customerHtml}
|
ITEM / الصنف
|
TOTAL / المجموع
|
${itemsHtml}
| Subtotal / ${tr['Subtotal']} |
${formatCurrency(subtotal)} |
${Math.abs(data.vat) > 0 ? `
| ${data.vat < 0 ? 'Discount' : 'VAT'} / ${tr['VAT']} |
${data.vat < 0 ? '-' : '+'}${formatCurrency(Math.abs(data.vat))} |
` : ''}
| TOTAL / ${tr['TOTAL']} |
${formatCurrency(data.total)} |
`;
win.document.write(html);
win.document.close();
}
// Initialize logic
const urlParams = new URLSearchParams(window.location.search);
if (!urlParams.has('order_type')) {
const otTakeaway = document.getElementById('ot-takeaway');
if (otTakeaway) {
otTakeaway.checked = true;
}
}
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();
});
saveCustomerBtn.addEventListener('click', () => {
const name = newCustomerName.value.trim();
const phone = newCustomerPhone.value.trim();
if (name === '') {
showToast('Name is required', 'warning');
return;
}
saveCustomerBtn.disabled = true;
saveCustomerBtn.textContent = 'Saving...';
fetch('api/create_customer.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name, phone: phone })
})
.then(res => res.json())
.then(data => {
saveCustomerBtn.disabled = false;
saveCustomerBtn.textContent = 'Save Customer';
if (data.success) {
addCustomerModal.hide();
selectCustomer(data.customer);
showToast('Customer created successfully', 'success');
} else {
showToast(data.error || 'Error creating customer', 'danger');
}
})
.catch(err => {
saveCustomerBtn.disabled = false;
saveCustomerBtn.textContent = 'Save Customer';
showToast('Network error', 'danger');
});
});
}
});