/** * cuentas.js — Accounts receivable logic for Nexus Autoparts */ (function () { 'use strict'; var API = ''; var currentCustomerId = null; var customerPage = 1; // ================================================================ // Utility // ================================================================ function toast(msg, type) { var el = document.createElement('div'); el.className = 'toast ' + (type || 'success'); el.textContent = msg; document.body.appendChild(el); setTimeout(function () { el.remove(); }, 3000); } function api(path, opts) { opts = opts || {}; return fetch(API + path, opts).then(function (r) { if (!r.ok) return r.json().then(function (d) { throw new Error(d.error || 'Error'); }); return r.json(); }); } function esc(s) { if (!s) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; } function fmt(n) { return '$' + (parseFloat(n) || 0).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ','); } function fmtDate(d) { if (!d) return ''; var dt = new Date(d); return dt.toLocaleDateString('es-MX', { day: '2-digit', month: 'short', year: 'numeric' }); } // ================================================================ // Customer List // ================================================================ var searchTimer = null; document.getElementById('customer-search').addEventListener('input', function () { clearTimeout(searchTimer); searchTimer = setTimeout(function () { customerPage = 1; loadCustomers(); }, 400); }); function loadCustomers() { var search = document.getElementById('customer-search').value; var grid = document.getElementById('customer-grid'); grid.innerHTML = '
Cargando...
'; var params = '?page=' + customerPage + '&per_page=30'; if (search) params += '&search=' + encodeURIComponent(search); api('/api/pos/customers' + params).then(function (res) { var data = res.data || []; if (data.length === 0) { grid.innerHTML = '
No se encontraron clientes
'; document.getElementById('customer-pagination').innerHTML = ''; return; } grid.innerHTML = data.map(function (c) { return '
' + '
' + esc(c.name) + '
' + '
' + esc(c.rfc || 'Sin RFC') + '
' + '
' + '' + fmt(c.balance) + '' + 'Limite: ' + fmt(c.credit_limit) + '
'; }).join(''); grid.querySelectorAll('.customer-card-item').forEach(function (card) { card.addEventListener('click', function () { showCustomerDetail(parseInt(card.getAttribute('data-id'))); }); }); // Pagination var pag = res.pagination; var pagEl = document.getElementById('customer-pagination'); if (pag.total_pages <= 1) { pagEl.innerHTML = ''; return; } pagEl.innerHTML = '' + 'Pag ' + pag.page + '/' + pag.total_pages + '' + ''; pagEl.querySelectorAll('button').forEach(function (btn) { btn.addEventListener('click', function () { customerPage = parseInt(btn.getAttribute('data-p')); loadCustomers(); }); }); }).catch(function (err) { console.error('Error loading customers:', err); grid.innerHTML = '
Error al cargar clientes
'; }); } // ================================================================ // Customer Detail // ================================================================ function showCustomerDetail(customerId) { currentCustomerId = customerId; document.getElementById('list-view').style.display = 'none'; document.getElementById('detail-view').style.display = 'block'; api('/api/pos/customers/' + customerId + '/statement').then(function (res) { var c = res.customer; document.getElementById('dh-name').textContent = c.name; document.getElementById('dh-rfc').textContent = c.rfc || 'Sin RFC'; var balEl = document.getElementById('dh-balance'); balEl.textContent = fmt(c.balance); balEl.className = 'dh-value ' + (c.balance > 0 ? 'danger' : 'success'); document.getElementById('dh-limit').textContent = fmt(c.credit_limit); document.getElementById('dh-terms').textContent = c.payment_terms + ' dias'; // Invoices var invBody = document.getElementById('invoice-list'); if (res.invoices.length === 0) { invBody.innerHTML = 'Sin facturas'; } else { invBody.innerHTML = res.invoices.map(function (i) { return '' + '' + esc(i.folio) + '' + '' + fmtDate(i.date_issued) + '' + '' + fmt(i.total) + '' + '' + fmt(i.amount_paid) + '' + '' + i.status + ''; }).join(''); } // Payments var payBody = document.getElementById('payment-list'); if (res.payments.length === 0) { payBody.innerHTML = 'Sin pagos'; } else { payBody.innerHTML = res.payments.map(function (p) { return '' + '' + fmtDate(p.date_payment) + '' + '' + fmt(p.amount) + '' + '' + esc(p.payment_method) + '' + '' + esc(p.reference || '') + '' + '' + esc(p.invoice_folio || 'General') + ''; }).join(''); } // Populate invoice dropdown for payment form var invSelect = document.getElementById('pay-invoice'); invSelect.innerHTML = ''; res.invoices.filter(function (i) { return i.status !== 'paid' && i.status !== 'cancelled'; }) .forEach(function (i) { invSelect.innerHTML += ''; }); }); } document.getElementById('btn-back-list').addEventListener('click', function () { document.getElementById('detail-view').style.display = 'none'; document.getElementById('list-view').style.display = 'block'; currentCustomerId = null; loadCustomers(); }); // ================================================================ // Register Payment // ================================================================ document.getElementById('btn-pay').addEventListener('click', function () { var amount = parseFloat(document.getElementById('pay-amount').value); if (!amount || amount <= 0) { toast('Ingresa un monto valido', 'error'); return; } var invoiceId = document.getElementById('pay-invoice').value; api('/api/pos/payments', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ customer_id: currentCustomerId, amount: amount, payment_method: document.getElementById('pay-method').value, reference: document.getElementById('pay-reference').value.trim() || null, invoice_id: invoiceId ? parseInt(invoiceId) : null, notes: document.getElementById('pay-notes').value.trim() || null }) }).then(function () { toast('Pago de ' + fmt(amount) + ' registrado'); // Clear form document.getElementById('pay-amount').value = ''; document.getElementById('pay-reference').value = ''; document.getElementById('pay-notes').value = ''; // Refresh detail showCustomerDetail(currentCustomerId); }).catch(function (err) { toast(err.message, 'error'); }); }); // ================================================================ // Init // ================================================================ loadCustomers(); })();