diff --git a/pos/blueprints/customers_bp.py b/pos/blueprints/customers_bp.py index 2a43ba3..8f103ba 100644 --- a/pos/blueprints/customers_bp.py +++ b/pos/blueprints/customers_bp.py @@ -140,6 +140,39 @@ def get_customer(customer_id): return jsonify(customer) +@customers_bp.route('//purchases', methods=['GET']) +@require_auth('customers.view') +def get_customer_purchases(customer_id): + """Return full purchase history for a customer.""" + conn = get_tenant_conn(g.tenant_id) + cur = conn.cursor() + + cur.execute(""" + SELECT s.id, s.total, s.payment_method, s.sale_type, s.status, s.created_at, + e.name as employee_name + FROM sales s + LEFT JOIN employees e ON s.employee_id = e.id + WHERE s.customer_id = %s + ORDER BY s.created_at DESC + """, (customer_id,)) + + purchases = [] + for r in cur.fetchall(): + purchases.append({ + 'id': r[0], + 'total': float(r[1]) if r[1] else 0, + 'payment_method': r[2], + 'sale_type': r[3], + 'status': r[4], + 'created_at': str(r[5]), + 'employee_name': r[6], + }) + + cur.close() + conn.close() + return jsonify({'data': purchases}) + + @customers_bp.route('', methods=['POST']) @require_auth('customers.create') def create_customer(): diff --git a/pos/static/js/customers.js b/pos/static/js/customers.js index 6296d28..c8742a9 100644 --- a/pos/static/js/customers.js +++ b/pos/static/js/customers.js @@ -387,10 +387,80 @@ const Customers = (() => { if (btns.length >= 2) btns[1].onclick = () => editCurrent(); if (btns.length >= 3) btns[2].onclick = () => showStatement(); if (btns.length >= 4) btns[3].onclick = () => { - if (currentCustomer) selectCustomer(currentCustomer.id); + if (currentCustomer) showCustomerHistory(currentCustomer.id); }; } + async function showCustomerHistory(customerId) { + try { + const res = await api(`/pos/api/customers/${customerId}/purchases`); + const purchases = res.data || []; + let modal = document.getElementById('customerHistoryModal'); + if (!modal) { + modal = document.createElement('div'); + modal.id = 'customerHistoryModal'; + modal.className = 'modal-overlay'; + modal.style.display = 'none'; + modal.innerHTML = ` + + `; + document.body.appendChild(modal); + } + + const tbody = document.getElementById('customerHistoryBody'); + const title = document.getElementById('customerHistoryName'); + if (title && currentCustomer) title.textContent = currentCustomer.name; + + if (purchases.length === 0) { + tbody.innerHTML = 'Sin compras registradas'; + } else { + tbody.innerHTML = purchases.map(p => { + const statusClass = p.status === 'paid' ? 'mbadge--paid' : p.status === 'cancelled' ? 'mbadge--error' : p.status === 'overdue' ? 'mbadge--overdue' : 'mbadge--pending'; + const statusLabel = p.status === 'paid' ? 'Pagado' : p.status === 'cancelled' ? 'Cancelado' : p.status === 'overdue' ? 'Vencido' : 'Pendiente'; + return ` + ${formatDate(p.created_at)} + NX-${String(p.id).padStart(5, '0')} + ${fmt(p.total)} + ${p.payment_method || '-'} + ${statusLabel} + `; + }).join(''); + } + modal.style.display = 'flex'; + modal.classList.add('active'); + } catch (e) { + console.error('Error loading customer history:', e); + alert('Error al cargar historial: ' + e.message); + } + } + + function closeCustomerHistoryModal() { + const modal = document.getElementById('customerHistoryModal'); + if (modal) { + modal.style.display = 'none'; + modal.classList.remove('active'); + } + } + // ─── Create/Edit Modal ─────────────── function showCreateModal() { const modal = document.getElementById('customerModal'); @@ -819,6 +889,7 @@ const Customers = (() => { showCreateModal, editCurrent, editCustomer, closeModal, save, showStatement, closeStatement, showPaymentModal, closePayment, recordPayment, + showCustomerHistory, closeCustomerHistoryModal, }; // Bulk selection diff --git a/pos/static/pwa/sw.js b/pos/static/pwa/sw.js index 0d71275..412acbe 100644 --- a/pos/static/pwa/sw.js +++ b/pos/static/pwa/sw.js @@ -6,7 +6,7 @@ // The fetch handler normalizes static asset URLs (strips ?v= query strings) // so templates can use cache-busting query params freely. -const CACHE_NAME = 'nexus-pos-v23'; +const CACHE_NAME = 'nexus-pos-v24'; const APP_SHELL = [ '/pos/static/css/tokens.css', diff --git a/pos/templates/customers.html b/pos/templates/customers.html index b149685..b0f4309 100644 --- a/pos/templates/customers.html +++ b/pos/templates/customers.html @@ -648,7 +648,7 @@ - +