document.addEventListener('DOMContentLoaded', function() {
// Initialize POS
initPOS();
// Event listeners
document.getElementById('productSearch').addEventListener('input', filterProducts);
document.getElementById('scanBarcode').addEventListener('click', scanBarcode);
document.getElementById('cancelOrder').addEventListener('click', cancelOrder);
document.getElementById('checkoutBtn').addEventListener('click', showPaymentModal);
document.getElementById('discountInput').addEventListener('input', updateOrderSummary);
document.getElementById('amountPaid').addEventListener('input', calculateChange);
document.getElementById('paymentMethod').addEventListener('change', toggleCashPaymentFields);
document.getElementById('cancelPayment').addEventListener('click', hidePaymentModal);
document.getElementById('completePayment').addEventListener('click', processPayment);
document.getElementById('printReceiptBtn').addEventListener('click', printReceipt);
document.getElementById('newOrderBtn').addEventListener('click', startNewOrder);
// Close modals when clicking on X
document.querySelectorAll('.close-modal').forEach(button => {
button.addEventListener('click', function() {
this.closest('.modal').classList.remove('show');
});
});
});
// Cart state
let cart = [];
let categories = [];
let products = [];
let customers = [];
// Initialize POS
async function initPOS() {
try {
// Fetch categories
const categoryResponse = await apiRequest('inventory/categories');
if (categoryResponse.status === 'success') {
categories = categoryResponse.data;
renderCategories();
}
// Fetch products
const productResponse = await apiRequest('inventory/products');
if (productResponse.status === 'success') {
products = productResponse.data;
renderProducts(products);
}
// Fetch customers
const customerResponse = await apiRequest('customers');
if (customerResponse.status === 'success') {
customers = customerResponse.data;
renderCustomers();
}
// Initialize empty cart
updateOrderSummary();
} catch (error) {
console.error('Failed to initialize POS:', error);
showNotification('Error initializing POS system', 'error');
}
}
// Render categories filter
function renderCategories() {
const container = document.querySelector('.category-filter');
categories.forEach(category => {
const button = document.createElement('button');
button.className = 'btn btn-sm';
button.textContent = category.name;
button.dataset.category = category.id;
button.addEventListener('click', function() {
// Remove active class from all buttons
document.querySelectorAll('.category-filter .btn').forEach(btn => {
btn.classList.remove('active');
});
// Add active class to clicked button
this.classList.add('active');
// Filter products
filterProductsByCategory(category.id);
});
container.appendChild(button);
});
}
// Filter products by category
function filterProductsByCategory(categoryId) {
if (categoryId === 'all') {
renderProducts(products);
} else {
const filtered = products.filter(product => product.category_id == categoryId);
renderProducts(filtered);
}
}
// Render products grid
function renderProducts(productsToRender) {
const grid = document.getElementById('productGrid');
grid.innerHTML = '';
if (productsToRender.length === 0) {
grid.innerHTML = '
ไม่พบสินค้า
';
return;
}
productsToRender.forEach(product => {
if (product.status !== 'active') return;
// สร้าง DOM element แยกเพื่อประสิทธิภาพที่ดีขึ้น
const item = document.createElement('div');
item.className = 'product-item';
// เพิ่ม data attributes สำหรับความสะดวกในการเข้าถึงข้อมูล
item.dataset.id = product.id;
item.dataset.sku = product.sku;
item.dataset.name = product.name;
item.dataset.price = product.price;
// แสดงสถานะสินค้าหมดสต็อก
let outOfStockClass = '';
let stockLabel = '';
if (product.quantity <= 0) {
outOfStockClass = 'out-of-stock';
stockLabel = 'หมด ';
}
item.innerHTML = `
${stockLabel}
${product.name}
${formatCurrency(product.price)}
`;
// ให้เพิ่มเฉพาะสินค้าที่มีสต็อก
if (product.quantity > 0) {
item.addEventListener('click', function() {
addToCart(product);
});
} else {
item.addEventListener('click', function() {
showNotification('สินค้าหมด', 'warning');
});
}
grid.appendChild(item);
});
}
// Filter products by search term
function filterProducts() {
const searchTerm = document.getElementById('productSearch').value.toLowerCase();
if (searchTerm === '') {
renderProducts(products);
return;
}
const filtered = products.filter(product => {
return product.name.toLowerCase().includes(searchTerm) ||
product.sku.toLowerCase().includes(searchTerm) ||
(product.barcode && product.barcode.includes(searchTerm));
});
renderProducts(filtered);
}
// Barcode scanner simulation
function scanBarcode() {
const barcode = prompt('Enter barcode:');
if (!barcode) return;
const product = products.find(p => p.barcode === barcode);
if (product) {
addToCart(product);
} else {
showNotification('Product not found', 'error');
}
}
// Add product to cart
function addToCart(product) {
// Check if product is already in cart
const existingItemIndex = cart.findIndex(item => item.id === product.id);
if (existingItemIndex !== -1) {
// Update quantity if already in cart
cart[existingItemIndex].quantity += 1;
} else {
// Add new item to cart
cart.push({
id: product.id,
sku: product.sku,
name: product.name,
price: product.price,
quantity: 1
});
}
// Update UI
renderCart();
updateOrderSummary();
showNotification(`${product.name} added to cart`, 'success');
}
// Render cart items
function renderCart() {
const container = document.getElementById('orderItems');
container.innerHTML = '';
if (cart.length === 0) {
container.innerHTML = `
`;
return;
}
cart.forEach((item, index) => {
const itemElement = document.createElement('div');
itemElement.className = 'order-item';
itemElement.innerHTML = `
${item.name}
-
${item.quantity}
+
${formatCurrency(item.price * item.quantity)}
`;
container.appendChild(itemElement);
});
// Add event listeners to quantity buttons
container.querySelectorAll('.qty-btn.decrease').forEach(button => {
button.addEventListener('click', function() {
const index = parseInt(this.dataset.index);
decreaseQuantity(index);
});
});
container.querySelectorAll('.qty-btn.increase').forEach(button => {
button.addEventListener('click', function() {
const index = parseInt(this.dataset.index);
increaseQuantity(index);
});
});
container.querySelectorAll('.remove-item').forEach(button => {
button.addEventListener('click', function() {
const index = parseInt(this.dataset.index);
removeCartItem(index);
});
});
}
// Increase item quantity
function increaseQuantity(index) {
cart[index].quantity += 1;
renderCart();
updateOrderSummary();
}
// Decrease item quantity
function decreaseQuantity(index) {
if (cart[index].quantity > 1) {
cart[index].quantity -= 1;
} else {
removeCartItem(index);
}
renderCart();
updateOrderSummary();
}
// Remove item from cart
function removeCartItem(index) {
cart.splice(index, 1);
renderCart();
updateOrderSummary();
}
// Update order summary calculations
function updateOrderSummary() {
const subtotal = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const discount = parseFloat(document.getElementById('discountInput').value) || 0;
const taxRate = 0.07; // 7% tax
const tax = (subtotal - discount) * taxRate;
const total = subtotal - discount + tax;
document.getElementById('subtotal').textContent = formatCurrency(subtotal);
document.getElementById('tax').textContent = formatCurrency(tax);
document.getElementById('total').textContent = formatCurrency(total);
// Update payment modal total too if it's open
const paymentTotalElement = document.getElementById('paymentTotal');
if (paymentTotalElement) {
paymentTotalElement.textContent = formatCurrency(total);
}
// Enable/disable checkout button
const checkoutBtn = document.getElementById('checkoutBtn');
checkoutBtn.disabled = cart.length === 0;
}
// Cancel current order
function cancelOrder() {
if (cart.length === 0) return;
if (confirm('Are you sure you want to cancel this order?')) {
cart = [];
renderCart();
updateOrderSummary();
document.getElementById('discountInput').value = 0;
showNotification('Order cancelled', 'info');
}
}
// Render customer dropdown
function renderCustomers() {
const select = document.getElementById('customerSelect');
customers.forEach(customer => {
const option = document.createElement('option');
option.value = customer.id;
option.textContent = customer.name;
select.appendChild(option);
});
}
// Show payment modal
function showPaymentModal() {
if (cart.length === 0) {
showNotification('Add items to cart before checkout', 'error');
return;
}
const subtotal = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const discount = parseFloat(document.getElementById('discountInput').value) || 0;
const taxRate = 0.07; // 7% tax
const tax = (subtotal - discount) * taxRate;
const total = subtotal - discount + tax;
document.getElementById('paymentTotal').textContent = formatCurrency(total);
document.getElementById('amountPaid').value = total.toFixed(2);
document.getElementById('changeAmount').textContent = formatCurrency(0);
document.getElementById('paymentNotes').value = '';
document.getElementById('paymentModal').classList.add('show');
}
// Hide payment modal
function hidePaymentModal() {
document.getElementById('paymentModal').classList.remove('show');
}
// Calculate change
function calculateChange() {
const total = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const discount = parseFloat(document.getElementById('discountInput').value) || 0;
const taxRate = 0.07;
const tax = (total - discount) * taxRate;
const finalTotal = total - discount + tax;
const amountPaid = parseFloat(document.getElementById('amountPaid').value) || 0;
const change = amountPaid - finalTotal;
document.getElementById('changeAmount').textContent = formatCurrency(Math.max(0, change));
// Enable/disable complete payment button
const completePaymentBtn = document.getElementById('completePayment');
completePaymentBtn.disabled = amountPaid < finalTotal;
}
// Toggle cash payment fields based on payment method
function toggleCashPaymentFields() {
const paymentMethod = document.getElementById('paymentMethod').value;
const cashGroup = document.getElementById('cashPaymentGroup');
if (paymentMethod === 'cash') {
cashGroup.style.display = 'block';
calculateChange();
} else {
cashGroup.style.display = 'none';
document.getElementById('completePayment').disabled = false;
}
}
// Process payment
async function processPayment() {
try {
const subtotal = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const discount = parseFloat(document.getElementById('discountInput').value) || 0;
const taxRate = 0.07;
const tax = (subtotal - discount) * taxRate;
const total = subtotal - discount + tax;
const paymentMethod = document.getElementById('paymentMethod').value;
const customerId = document.getElementById('customerSelect').value;
const notes = document.getElementById('paymentNotes').value;
// Prepare sale data
const saleData = {
customer_id: customerId,
items: cart.map(item => ({
product_id: item.id,
quantity: item.quantity,
unit_price: item.price
})),
discount_amount: discount,
tax_amount: tax,
payment_method: paymentMethod,
notes: notes
};
// Submit to API
const response = await apiRequest('sales/create', 'POST', saleData);
if (response.status === 'success') {
hidePaymentModal();
showReceipt(response.data);
showNotification('Payment completed successfully', 'success');
} else {
showNotification(response.message || 'Payment processing failed', 'error');
}
} catch (error) {
console.error('Payment processing error:', error);
showNotification('An error occurred during payment processing', 'error');
}
}
// Show receipt
function showReceipt(saleData) {
const receiptContainer = document.getElementById('receipt');
const date = new Date(saleData.created_at).toLocaleDateString();
const time = new Date(saleData.created_at).toLocaleTimeString();
let itemsHtml = '';
saleData.items.forEach(item => {
itemsHtml += `
${item.product_name}
${item.quantity}
${formatCurrency(item.unit_price)}
${formatCurrency(item.total)}
`;
});
receiptContainer.innerHTML = `
Receipt #: ${saleData.reference_no}
Date: ${date} ${time}
Cashier: ${saleData.cashier_name}
Customer: ${saleData.customer_name}
Item
Qty
Price
Total
${itemsHtml}
Subtotal
${formatCurrency(saleData.total_amount)}
Discount
${formatCurrency(saleData.discount_amount)}
Tax
${formatCurrency(saleData.tax_amount)}
Total
${formatCurrency(saleData.grand_total)}
Payment Method
${saleData.payment_method.toUpperCase()}
`;
document.getElementById('receiptModal').classList.add('show');
}
// Print receipt
function printReceipt() {
const receiptContent = document.getElementById('receipt').innerHTML;
const printWindow = window.open('', '_blank');
printWindow.document.write(`
Receipt
${receiptContent}
`);
printWindow.document.close();
printWindow.focus();
printWindow.print();
printWindow.close();
}
// Start new order after payment
function startNewOrder() {
cart = [];
renderCart();
updateOrderSummary();
document.getElementById('discountInput').value = 0;
document.getElementById('receiptModal').classList.remove('show');
document.getElementById('customerSelect').value = 1; // Reset to default customer
}
// Show notification
function showNotification(message, type = 'info') {
// You can implement a notification system here
// For simplicity, we'll use alert for now
alert(message);
}