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,
};
})();