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
This commit is contained in:
2026-05-18 06:37:42 +00:00
parent 912fe4cef5
commit e38148e8d5
2 changed files with 68 additions and 4 deletions

View File

@@ -120,14 +120,48 @@ const POS = (() => {
document.getElementById('registerInfo').innerHTML =
`<span>Caja #${data.register.register_number}</span>`;
} else {
currentRegister = null;
document.getElementById('registerInfo').innerHTML =
'<span>Sin caja abierta</span>';
'<span style="color:var(--color-error);cursor:pointer;" onclick="POS.showOpenRegisterModal()" title="Clic para abrir caja">&#x26A0; Sin caja abierta — Clic para abrir</span>';
}
} 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 = '<span style="color:var(--color-error);">Numero de caja invalido</span>';
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 = '<span style="color:var(--color-error);">' + (data.error || 'Error') + '</span>';
return;
}
currentRegister = data;
document.getElementById('registerInfo').innerHTML = `<span>Caja #${data.register_number}</span>`;
closeOpenRegisterModal();
showToast(`Caja #${data.register_number} abierta con $${amount.toFixed(2)}`);
} catch (e) {
document.getElementById('registerOpenResult').innerHTML = '<span style="color:var(--color-error);">Error de red</span>';
}
}
// ─── 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,
};
})();

View File

@@ -14,7 +14,7 @@
<meta name="theme-color" content="#F5A623" />
<script src="/pos/static/js/native-bridge.js" defer></script>
<link rel="stylesheet" href="/pos/static/css/pos.css">
<link rel="stylesheet" href="/pos/static/css/pos.css?v=2">
</head>
<body class="pos-shell" id="appBody">
@@ -490,6 +490,35 @@
</div>
</div>
<!-- ================================================================
OPEN REGISTER MODAL
================================================================ -->
<div class="modal-overlay" id="openRegisterModal">
<div class="modal-pago" style="width:420px;">
<div class="modal-header">
<h3>Abrir Caja</h3>
<button class="modal-close" onclick="POS.closeOpenRegisterModal()">&#x2715;</button>
</div>
<div style="padding:var(--space-6);">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3);margin-bottom:var(--space-4);">
<div class="form-group">
<label class="form-label">No. de Caja *</label>
<input type="number" class="form-input" id="regNumber" value="1" min="1" />
</div>
<div class="form-group">
<label class="form-label">Efectivo inicial *</label>
<input type="number" class="form-input" id="regOpeningAmount" value="0" min="0" step="0.01" />
</div>
</div>
<div id="registerOpenResult" style="min-height:1.5em;font-size:var(--text-body-sm);"></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="POS.closeOpenRegisterModal()">Cancelar</button>
<button class="btn btn-primary" onclick="POS.openRegister()">Abrir Caja</button>
</div>
</div>
</div>
<!-- ================================================================
TOAST CONTAINER
================================================================ -->
@@ -504,7 +533,7 @@
<script src="/pos/static/js/app-init.js" defer></script>
<script src="/pos/static/js/push.js" defer></script>
<script src="/pos/static/js/printer.js" defer></script>
<script src="/pos/static/js/pos.js" defer></script>
<script src="/pos/static/js/pos.js?v=2" defer></script>
<script>
// Cancel sale button wiring