From e38148e8d51c0d7ed4aafbd6944fa44ec53c0a3a Mon Sep 17 00:00:00 2001 From: consultoria-as Date: Mon, 18 May 2026 06:37:42 +0000 Subject: [PATCH] feat(pos): add open-register UI flow - Add 'Open Register' modal with register number and opening amount inputs - loadRegister now shows clickable warning when no register is open - checkout() opens register modal instead of plain alert when no register - Add openRegister() API call to POST /pos/api/register/open - Expose showOpenRegisterModal, closeOpenRegisterModal, openRegister globally - Add cache-bust query params to pos.css and pos.js --- pos/static/js/pos.js | 39 +++++++++++++++++++++++++++++++++++++-- pos/templates/pos.html | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/pos/static/js/pos.js b/pos/static/js/pos.js index 0a0ee77..e22cac4 100644 --- a/pos/static/js/pos.js +++ b/pos/static/js/pos.js @@ -120,14 +120,48 @@ const POS = (() => { document.getElementById('registerInfo').innerHTML = `Caja #${data.register.register_number}`; } else { + currentRegister = null; document.getElementById('registerInfo').innerHTML = - 'Sin caja abierta'; + '⚠ Sin caja abierta — Clic para abrir'; } } catch (e) { console.warn('Register check failed:', e); } } + function showOpenRegisterModal() { + document.getElementById('openRegisterModal').classList.add('open'); + document.getElementById('registerOpenResult').innerHTML = ''; + } + function closeOpenRegisterModal() { + document.getElementById('openRegisterModal').classList.remove('open'); + document.getElementById('registerOpenResult').innerHTML = ''; + } + async function openRegister() { + const number = parseInt(document.getElementById('regNumber').value); + const amount = parseFloat(document.getElementById('regOpeningAmount').value) || 0; + if (!number || number < 1) { + document.getElementById('registerOpenResult').innerHTML = 'Numero de caja invalido'; + return; + } + try { + const data = await api('/pos/api/register/open', { + method: 'POST', + body: JSON.stringify({ register_number: number, opening_amount: amount }) + }); + if (data.error) { + document.getElementById('registerOpenResult').innerHTML = '' + (data.error || 'Error') + ''; + return; + } + currentRegister = data; + document.getElementById('registerInfo').innerHTML = `Caja #${data.register_number}`; + closeOpenRegisterModal(); + showToast(`Caja #${data.register_number} abierta con $${amount.toFixed(2)}`); + } catch (e) { + document.getElementById('registerOpenResult').innerHTML = 'Error de red'; + } + } + // ─── Cart ──────────────────────────── function addToCart(item) { const existing = cart.find(c => c.inventory_id === item.inventory_id); @@ -548,7 +582,7 @@ const POS = (() => { // ─── Payment ───────────────────────── function checkout() { if (cart.length === 0) { showToast('Carrito vacio'); return; } - if (!currentRegister) { alert('No hay caja abierta. Abra una caja primero.'); return; } + if (!currentRegister) { showOpenRegisterModal(); return; } paymentMethod = 'efectivo'; const total = getTotal(); @@ -1160,5 +1194,6 @@ const POS = (() => { showLastSale, openDrawer, showTicket, closeTicketModal, printTicket, connectThermal, thermalPrint, + showOpenRegisterModal, closeOpenRegisterModal, openRegister, }; })(); diff --git a/pos/templates/pos.html b/pos/templates/pos.html index f4a8309..ac40483 100644 --- a/pos/templates/pos.html +++ b/pos/templates/pos.html @@ -14,7 +14,7 @@ - + @@ -490,6 +490,35 @@ + + + @@ -504,7 +533,7 @@ - +