Implemented change calculator and various UI fixes

This commit is contained in:
2026-03-09 16:32:23 -03:00
parent 216abc8ad2
commit 8e37f9e776
2 changed files with 104 additions and 5 deletions

View File

@@ -382,7 +382,7 @@
<h1 id="payment-modal-total" class="mb-4" style="color: var(--accent); font-weight: 800; font-size: 3rem;">$0</h1>
<div class="d-grid gap-3 px-3">
<button class="btn btn-lg btn-success py-3" onclick="executeCheckout('efectivo')">
<button class="btn btn-lg btn-success py-3" onclick="openVueltoModal()">
<i class="bi bi-cash-coin me-2" style="font-size: 1.5rem; vertical-align: middle;"></i> Efectivo
</button>
<button class="btn btn-lg btn-secondary py-3" onclick="executeCheckout('tarjeta')">
@@ -393,6 +393,40 @@
</div>
</div>
</div>
<div class="modal fade" id="vueltoModal" tabindex="-1" data-bs-backdrop="static">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content">
<div class="modal-header border-0 pb-0">
<h5 class="modal-title w-100 text-center text-muted text-uppercase" style="font-size: 0.8rem;">Pago en Efectivo</h5>
<button type="button" class="btn-close position-absolute end-0 top-0 m-3" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body text-center pt-1 pb-4">
<div class="mb-3">
<span class="text-muted small">Total a Pagar:</span><br>
<span id="vuelto-total-display" class="fs-4 fw-bold" style="color: var(--text-main);">$0</span>
</div>
<div class="mb-3 text-start">
<label class="text-muted small mb-1">Monto Recibido</label>
<input type="number" id="monto-recibido" class="form-control form-control-lg text-center fw-bold fs-4"
placeholder="$0" onkeyup="calculateVuelto()" onchange="calculateVuelto()"
onkeydown="if(event.key === 'Enter' && !document.getElementById('btn-confirm-vuelto').disabled) executeCheckout('efectivo')">
</div>
<div class="d-flex justify-content-center gap-2 mb-3" id="vuelto-quick-buttons"></div>
<div class="p-3 mb-3" style="background: var(--input-bg); border-radius: 8px;">
<span class="text-muted small text-uppercase fw-bold">Vuelto a Entregar</span><br>
<span id="vuelto-amount" class="fs-1 fw-bold text-muted">$0</span>
</div>
<button id="btn-confirm-vuelto" class="btn btn-success w-100 py-3 fw-bold" onclick="executeCheckout('efectivo')" disabled>
Confirmar Venta
</button>
</div>
</div>
</div>
</div>
<nav class="navbar navbar-expand-md sticky-top px-3 mb-3">
<span class="navbar-brand">SekiPOS <small class="text-muted fw-normal"
style="font-size:0.65rem;">Caja</small></span>
@@ -609,8 +643,13 @@
const result = await response.json();
if (response.ok) {
// Hide the payment modal
bootstrap.Modal.getInstance(document.getElementById('paymentModal')).hide();
// Safely hide whichever modal was open
const pModal = bootstrap.Modal.getInstance(document.getElementById('paymentModal'));
if (pModal) pModal.hide();
const vModal = bootstrap.Modal.getInstance(document.getElementById('vueltoModal'));
if (vModal) vModal.hide();
// Pass the new sale_id from the result to the printer
const total = cart.reduce((sum, item) => sum + item.subtotal, 0);
@@ -752,12 +791,19 @@
document.getElementById('display-barcode').innerText = product.barcode;
document.getElementById('display-img').src = product.image || './static/placeholder.png';
if (product.unit === 'kg') {
// Standardize the unit key because Python sends 'unit_type' but the JS array uses 'unit'
const actualUnit = product.unit || product.unit_type;
if (actualUnit === 'kg') {
pendingProduct = product;
pendingProduct.unit = 'kg'; // Force it to match the cart's expected format
const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('weightModal'));
modal.show();
setTimeout(() => document.getElementById('weight-input').focus(), 500);
} else {
// Ensure unit products also get the standardized key
product.unit = 'unit';
addToCart(product, 1);
}
}
@@ -946,6 +992,59 @@
}
});
function openVueltoModal() {
// Hide the main payment selection modal
bootstrap.Modal.getInstance(document.getElementById('paymentModal')).hide();
const total = cart.reduce((sum, item) => sum + item.subtotal, 0);
document.getElementById('vuelto-total-display').innerText = clp.format(total);
const input = document.getElementById('monto-recibido');
input.value = '';
document.getElementById('vuelto-amount').innerText = '$0';
document.getElementById('vuelto-amount').className = "fs-1 fw-bold text-muted";
document.getElementById('btn-confirm-vuelto').disabled = true;
// Generate smart quick-buttons (Exacto, 5k, 10k, 20k)
const quickBox = document.getElementById('vuelto-quick-buttons');
quickBox.innerHTML = `<button class="btn btn-sm btn-outline-secondary fw-bold" onclick="setMonto(${total})">Exacto</button>`;
[5000, 10000, 20000].forEach(bill => {
if (bill > total && (bill - total) <= 20000) {
quickBox.innerHTML += `<button class="btn btn-sm btn-outline-secondary fw-bold" onclick="setMonto(${bill})">${clp.format(bill)}</button>`;
}
});
const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('vueltoModal'));
modal.show();
// Auto-focus input so you can start typing immediately
setTimeout(() => input.focus(), 500);
}
function setMonto(amount) {
document.getElementById('monto-recibido').value = amount;
calculateVuelto();
}
function calculateVuelto() {
const total = cart.reduce((sum, item) => sum + item.subtotal, 0);
const recibido = parseInt(document.getElementById('monto-recibido').value, 10);
const vueltoDisplay = document.getElementById('vuelto-amount');
const confirmBtn = document.getElementById('btn-confirm-vuelto');
if (isNaN(recibido) || recibido < total) {
vueltoDisplay.innerText = "Falta Dinero";
vueltoDisplay.className = "fs-4 fw-bold text-danger mt-2 d-block";
confirmBtn.disabled = true;
} else {
const vuelto = recibido - total;
vueltoDisplay.innerText = clp.format(vuelto);
vueltoDisplay.className = "fs-1 fw-bold text-success";
confirmBtn.disabled = false;
}
}
// Initialize on load
(function initTheme() {
const savedTheme = localStorage.getItem('theme') || 'light';

View File

@@ -631,7 +631,7 @@
if (d.note) title += ` (${d.note})`;
// Update the actual form
updateForm(d.barcode, d.name, d.price, d.image, title);
updateForm(d.barcode, d.name, d.price, d.image, title, d.stock, d.unit_type);
});
socket.on('scan_error', d => {