Files
Autoparts-DB/pos/templates/pos.html
consultoria-as d9741b21f6 feat(pos): add Cut Z (close register) UI flow
- Add 'Corte Z' button in secondary actions panel
- Add modal showing register summary before closing:
  - opening amount, total sales, cash sales, change given
  - cash movements in/out, cancellations, expected cash
  - payment method breakdown and movement detail list
- loadCutX() fetches current register summary (read-only)
- confirmCutZ() calls POST /pos/api/register/cut-z with counted amount
- Auto-fills closing amount with expected cash
- Shows toast with difference after closing
- Resets register state to 'Sin caja abierta' after close
- Bump pos.css and pos.js cache-bust to v=3
2026-05-18 06:59:18 +00:00

625 lines
29 KiB
HTML

<!DOCTYPE html>
<html lang="es" data-theme="industrial">
<head>
<script>/*pos_theme_early*/(function(){var t=localStorage.getItem("pos_theme")||"industrial";document.documentElement.setAttribute("data-theme",t);})()</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nexus Autoparts — Punto de Venta</title>
<link rel="stylesheet" href="/pos/static/css/tokens.css" />
<link rel="stylesheet" href="/pos/static/css/common.css" />
<link rel="stylesheet" href="/pos/static/css/sidebar.css" />
<link rel="stylesheet" href="/pos/static/css/pos-glass.css" />
<link rel="stylesheet" href="/pos/static/css/chat.css" />
<link rel="manifest" href="/pos/static/pwa/manifest.json" />
<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?v=3">
</head>
<body class="pos-shell" id="appBody">
<!-- ================================================================
STATUS BAR
================================================================ -->
<header class="status-bar" role="banner">
<div class="status-bar__store">
<span class="status-bar__store-dot"></span>
<span id="branchName">Nexus Autoparts</span>
</div>
<div class="status-bar__center">
<span id="registerInfo">Caja #--</span>
<span id="statusClock"></span>
</div>
<div class="status-bar__right">
<div class="status-bar__user" aria-label="Usuario activo">
<div class="status-bar__user-avatar" aria-hidden="true">--</div>
<span id="employeeName">Empleado</span>
</div>
</div>
</header>
<!-- ================================================================
MAIN POS LAYOUT
================================================================ -->
<main class="pos-main" role="main">
<!-- ============================================================
LEFT -- PRODUCT BROWSER
============================================================ -->
<section class="panel-products" aria-label="Catalogo de productos">
<div class="search-row">
<div class="search-wrap">
<svg class="search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<input class="search-input" type="search" id="itemSearch"
placeholder="Buscar por nombre, No. parte, codigo..."
autocomplete="off" spellcheck="false" aria-label="Buscar productos" />
</div>
</div>
<!-- Search Results Dropdown -->
<div id="searchResults" class="product-grid-wrap" style="display:none;"></div>
<!-- Totals Panel / Product Grid -->
<div class="product-grid-wrap" id="totalsPanel">
<div class="product-grid" id="productGrid" role="list" aria-label="Productos disponibles">
<!-- Populated by search -->
</div>
</div>
</section>
<!-- ============================================================
RIGHT -- CART / TICKET
============================================================ -->
<aside class="panel-cart" aria-label="Carrito de venta">
<!-- Cart Header -->
<div class="cart-header">
<div class="cart-header__top">
<div class="cart-header__sale-id">Venta Activa</div>
<button class="cost-toggle" id="costToggle" title="Mostrar costo/margen (Admin)" style="display:none;">C/M</button>
<span class="cart-header__status">Activa</span>
</div>
<!-- Customer Search -->
<div class="customer-row" id="customerSearchWrap">
<div class="customer-icon" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
</svg>
</div>
<div class="customer-info" style="flex:1;position:relative;">
<input type="text" id="customerSearch" class="search-input"
style="height:34px;font-size:var(--text-body-sm);padding-left:var(--space-3);"
placeholder="F2 — Buscar cliente..." autocomplete="off" />
<div id="customerAutocomplete" style="display:none;position:absolute;top:100%;left:0;right:0;z-index:100;background:var(--color-bg-elevated);border:1px solid var(--color-border);border-radius:var(--radius-md);max-height:200px;overflow-y:auto;box-shadow:var(--shadow-lg);">
</div>
</div>
<button class="btn-change-customer" onclick="POS.showNewCustomerModal()" aria-label="Nuevo cliente">+ Nuevo</button>
</div>
<!-- Selected Customer Display -->
<div id="customerSelected" style="display:none;" class="customer-row">
<div class="customer-icon" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
</svg>
</div>
<div class="customer-info">
<div class="customer-info__name" id="customerName">--</div>
<div class="customer-info__label">
<span id="customerTier">P1</span> |
<span id="customerCredit">Credito: $0 / $0</span>
</div>
</div>
<button class="btn-change-customer" onclick="POS.clearCustomer()" aria-label="Cambiar cliente">Cambiar</button>
</div>
</div>
<!-- Banner Cliente (shown when customer selected) -->
<div class="banner-cliente" id="vehicleBanner">
<div class="banner-info">
<div class="banner-info-item">
<div class="banner-info-label">Vehiculo</div>
<div class="banner-info-value" id="vehicleInfo">--</div>
</div>
<div class="banner-info-item">
<div class="banner-info-label">Ultima compra</div>
<div class="banner-info-value" id="lastPurchaseInfo">--</div>
</div>
</div>
</div>
<!-- Cart Items -->
<div class="cart-items" id="cartItems" role="list" aria-label="Articulos en carrito">
<!-- Empty state -->
<div id="cartEmpty" class="cart-empty" role="status">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.5" opacity="0.4" aria-hidden="true">
<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>
</svg>
<span>Carrito vacio -- agrega productos con F1</span>
</div>
<!-- Cart table -->
<table id="cartTable" style="display:none;width:100%;border-collapse:collapse;font-size:var(--text-body-sm);">
<thead>
<tr style="border-bottom:1px solid var(--color-border);">
<th style="text-align:left;padding:var(--space-2);">#</th>
<th style="text-align:left;padding:var(--space-2);">Producto</th>
<th style="text-align:center;padding:var(--space-2);">Cant</th>
<th style="text-align:right;padding:var(--space-2);">P.Unit</th>
<th style="text-align:center;padding:var(--space-2);">Desc%</th>
<th style="text-align:right;padding:var(--space-2);">Importe</th>
<th id="thCost" style="display:none;text-align:right;padding:var(--space-2);">Costo</th>
<th id="thMargin" style="display:none;text-align:center;padding:var(--space-2);">Margen</th>
<th style="width:30px;"></th>
</tr>
</thead>
<tbody id="cartBody"></tbody>
</table>
</div>
<!-- Margin Summary -->
<div class="margin-summary" id="marginSummary">
<span>Margen promedio:</span>
<span class="margin-summary__value" id="avgMargin">--</span>
</div>
<!-- Cart Footer -->
<div class="cart-footer">
<div class="totals-block">
<div class="totals-row">
<span class="totals-row__label">Subtotal</span>
<span class="totals-row__value" id="dispSubtotal">$0.00</span>
</div>
<div class="totals-row" id="discountRow" style="display:none;">
<span class="totals-row__label">Descuento</span>
<span class="totals-row__value" id="dispDiscount">$0.00</span>
</div>
<div class="totals-row">
<span class="totals-row__label">IVA (16%)</span>
<span class="totals-row__value" id="dispTax">$0.00</span>
</div>
<div class="totals-row totals-row--total">
<span class="totals-row__label">Total</span>
<span class="totals-row__value" id="dispTotal">$0.00</span>
</div>
</div>
<!-- COBRAR Button -->
<button class="btn-cobrar" id="btnCobrar" onclick="POS.checkout()" aria-label="Procesar cobro">
<span>COBRAR</span>
</button>
<!-- Secondary Actions -->
<div class="secondary-actions" role="toolbar" aria-label="Acciones secundarias">
<button class="btn-secondary-action" onclick="POS.saveQuotation()" title="Cotizacion (F4)">Cotizar</button>
<button class="btn-secondary-action" onclick="POS.showLastSale()" title="Ultima venta (F5)">Ult.Venta</button>
<button class="btn-secondary-action" onclick="POS.showCutZModal()" title="Corte Z - Cerrar caja">Corte Z</button>
<button class="btn-secondary-action danger" id="btnCancelSale" title="Cancelar (Esc)">Cancelar</button>
</div>
</div>
</aside>
</main>
<!-- ================================================================
F-KEYS FOOTER BAR
================================================================ -->
<div class="fkeys-footer" id="fkeysFooter">
<div class="fkey" onclick="document.getElementById('itemSearch').focus()" title="Buscar producto">
<span class="fkey-key">F1</span><span class="fkey-label">Buscar</span>
</div>
<div class="fkey" onclick="document.getElementById('customerSearch').focus()" title="Seleccionar cliente">
<span class="fkey-key">F2</span><span class="fkey-label">Cliente</span>
</div>
<div class="fkey highlight" onclick="POS.checkout()" title="Cobrar venta">
<span class="fkey-key">F3</span><span class="fkey-label">Cobrar</span>
</div>
<div class="fkey" onclick="POS.saveQuotation()" title="Cotizacion">
<span class="fkey-key">F4</span><span class="fkey-label">Cotizacion</span>
</div>
<div class="fkey-sep"></div>
<div class="fkey" onclick="POS.showLastSale()" title="Ultima venta">
<span class="fkey-key">F5</span><span class="fkey-label">Ult.Venta</span>
</div>
<div class="fkey" onclick="POS.openDrawer()" title="Abrir cajon">
<span class="fkey-key">F6</span><span class="fkey-label">Cajon</span>
</div>
<div class="fkey-sep"></div>
<div class="fkey" title="Cantidad +/-">
<span class="fkey-key">+/-</span><span class="fkey-label">Cantidad</span>
</div>
<div class="fkey" title="Descuento">
<span class="fkey-key">*</span><span class="fkey-label">Descuento</span>
</div>
<div class="fkey-sep"></div>
<div class="fkey" id="fkeyEsc" title="Cancelar">
<span class="fkey-key">Esc</span><span class="fkey-label">Cancelar</span>
</div>
</div>
<!-- ================================================================
PAYMENT MODAL (modal-pago + calculadora-cambio)
================================================================ -->
<div class="modal-overlay" id="paymentModal">
<div class="modal-pago">
<!-- Header -->
<div class="modal-header">
<h3>Cobrar Venta</h3>
<button class="modal-close" onclick="POS.closePaymentModal()">&#x2715;</button>
</div>
<!-- Total Banner -->
<div class="total-banner">
<span class="total-label">Total a Cobrar</span>
<span class="total-amount" id="modalTotal">$0.00</span>
</div>
<!-- Items Summary -->
<div class="items-summary" id="modalSummary">
<span id="modalItemCount">0 productos</span>
<span>&#x2022;</span>
<span id="modalCustomerName">Publico General</span>
</div>
<!-- Payment Tabs -->
<div class="pago-tabs">
<button class="pago-tab active" data-method="efectivo" onclick="POS.selectPaymentMethod('efectivo', this)">
Efectivo
</button>
<button class="pago-tab" data-method="transferencia" onclick="POS.selectPaymentMethod('transferencia', this)">
Transferencia
</button>
<button class="pago-tab" data-method="tarjeta" onclick="POS.selectPaymentMethod('tarjeta', this)">
Tarjeta
</button>
<button class="pago-tab" data-method="mixto" onclick="POS.selectPaymentMethod('mixto', this)">
Mixto
</button>
</div>
<!-- TAB: Efectivo -->
<div class="tab-content active" id="cashPayment">
<div class="form-group">
<label class="form-label">Monto recibido</label>
<input type="number" class="form-input form-input-lg" id="cashReceived"
placeholder="0.00" step="0.01" min="0" oninput="POS.updateChange()" />
</div>
<div class="quick-amounts" id="quickAmounts">
<!-- Populated dynamically -->
</div>
<div class="cambio-display">
<span class="cambio-label">Cambio</span>
<span class="cambio-amount positive" id="changeDisplay">$0.00</span>
</div>
</div>
<!-- TAB: Transferencia / Tarjeta -->
<div class="tab-content" id="refPayment">
<div class="form-group">
<label class="form-label">Monto</label>
<input type="text" class="form-input form-input-lg" id="refAmount" readonly />
</div>
<div class="form-group">
<label class="form-label">Referencia / No. operacion</label>
<input type="text" class="form-input" id="paymentRef" placeholder="No. de referencia" />
</div>
<div class="form-hint">Verificar que el pago se haya recibido antes de confirmar</div>
</div>
<!-- TAB: Mixto -->
<div class="tab-content" id="mixedPayment">
<div class="mixed-row" style="margin-bottom:var(--space-3);">
<div class="form-group">
<label class="form-label">Metodo 1</label>
<select class="form-input" style="margin-bottom:var(--space-2);">
<option value="efectivo">Efectivo</option>
<option value="tarjeta">Tarjeta</option>
<option value="transferencia">Transferencia</option>
</select>
<input type="number" class="form-input mixed-amount" placeholder="0.00" step="0.01" oninput="POS.updateMixedTotal()" />
<input type="text" class="form-input" placeholder="Referencia (si aplica)" style="margin-top:var(--space-2);" />
</div>
</div>
<div class="mixed-row" style="margin-bottom:var(--space-3);">
<div class="form-group">
<label class="form-label">Metodo 2</label>
<select class="form-input" style="margin-bottom:var(--space-2);">
<option value="tarjeta">Tarjeta</option>
<option value="efectivo">Efectivo</option>
<option value="transferencia">Transferencia</option>
</select>
<input type="number" class="form-input mixed-amount" placeholder="0.00" step="0.01" oninput="POS.updateMixedTotal()" />
<input type="text" class="form-input" placeholder="Referencia (si aplica)" style="margin-top:var(--space-2);" />
</div>
</div>
<div class="split-remaining">
<span>Restante:</span>
<span class="amount" id="mixedRemaining">$0.00</span>
</div>
</div>
<!-- CFDI Checkbox -->
<div class="cfdi-check">
<input type="checkbox" id="cfdiCheck" />
<label for="cfdiCheck">Facturar CFDI</label>
<span class="cfdi-hint" id="cfdiHint"></span>
</div>
<!-- Footer -->
<div class="modal-footer">
<button class="btn btn-ghost" onclick="POS.closePaymentModal()">Cancelar</button>
<button class="btn btn-primary btn-lg" id="btnConfirmPayment" onclick="POS.confirmPayment()">Confirmar Pago</button>
</div>
</div>
</div>
<!-- ================================================================
CANCEL SALE CONFIRMATION MODAL
================================================================ -->
<div class="confirm-overlay" id="overlay-cancelar-venta" onclick="if(event.target===this) closeCancelModal()"></div>
<div class="confirm-dialog" id="modal-cancelar-venta">
<div class="modal__icon modal__icon--warning">&#x26A0;</div>
<div class="modal__title">Cancelar venta?</div>
<div class="modal__desc">Se perderan los articulos agregados al ticket actual.</div>
<div class="modal__actions">
<button class="modal__btn modal__btn--secondary" onclick="closeCancelModal()">No, continuar</button>
<button class="modal__btn modal__btn--danger" id="btnConfirmCancel">Si, cancelar</button>
</div>
</div>
<!-- ================================================================
TICKET PRINT AREA (hidden div for thermal print)
================================================================ -->
<div class="ticket-print-area" id="ticketPrintArea">
<div class="ticket ticket-80" id="ticketContent">
<!-- Populated by JS after successful sale -->
</div>
</div>
<!-- ================================================================
TICKET PREVIEW MODAL (on-screen after sale)
================================================================ -->
<div class="modal-overlay" id="ticketModal">
<div class="modal-pago" style="width:380px;">
<div class="modal-header">
<h3>Ticket de Venta</h3>
<button class="modal-close" onclick="POS.closeTicketModal()">&#x2715;</button>
</div>
<div style="padding:var(--space-4);display:flex;justify-content:center;">
<div class="ticket ticket-80" id="ticketPreviewContent">
<!-- Populated by JS -->
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="POS.closeTicketModal()">Cerrar</button>
<button class="btn btn-ghost" id="btnConnectPrinter" onclick="POS.connectThermal()" title="Conectar impresora termica USB/Serial">&#x1F5A8; Conectar</button>
<button class="btn btn-secondary" id="btnThermalPrint" onclick="POS.thermalPrint()" style="display:none;" title="Imprimir en impresora termica">&#x1F5A8; Termica</button>
<button class="btn btn-primary" onclick="POS.printTicket()">Imprimir</button>
</div>
</div>
</div>
<!-- ================================================================
NEW CUSTOMER MODAL
================================================================ -->
<div class="modal-overlay" id="newCustomerModal">
<div class="modal-pago" style="width:480px;">
<div class="modal-header">
<h3>Nuevo Cliente</h3>
<button class="modal-close" onclick="POS.closeNewCustomerModal()">&#x2715;</button>
</div>
<div style="padding:var(--space-6);">
<div class="form-group">
<label class="form-label">Nombre *</label>
<input type="text" class="form-input" id="ncName" placeholder="Nombre o Razon Social" />
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3);">
<div class="form-group">
<label class="form-label">RFC</label>
<input type="text" class="form-input" id="ncRfc" placeholder="XAXX010101000" maxlength="13" />
</div>
<div class="form-group">
<label class="form-label">Telefono</label>
<input type="text" class="form-input" id="ncPhone" placeholder="55 1234 5678" />
</div>
</div>
<div class="form-group">
<label class="form-label">Razon Social</label>
<input type="text" class="form-input" id="ncRazonSocial" placeholder="Razon Social para facturacion" />
</div>
<div class="form-group">
<label class="form-label">Email</label>
<input type="email" class="form-input" id="ncEmail" placeholder="correo@ejemplo.com" />
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3);">
<div class="form-group">
<label class="form-label">Lista de precios</label>
<select class="form-input" id="ncPriceTier">
<option value="1">P1 Mostrador</option>
<option value="2">P2 Taller</option>
<option value="3">P3 Mayoreo</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Limite de credito</label>
<input type="number" class="form-input" id="ncCreditLimit" placeholder="0.00" step="0.01" />
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3);">
<div class="form-group">
<label class="form-label">Regimen Fiscal</label>
<select class="form-input" id="ncRegimenFiscal">
<option value="">-- Seleccionar --</option>
<option value="601">601 - General de Ley PM</option>
<option value="612">612 - Personas Fisicas</option>
<option value="621">621 - Inc. Fiscal</option>
<option value="626">626 - RESICO</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Uso CFDI</label>
<select class="form-input" id="ncUsoCfdi">
<option value="G03">G03 - Gastos en general</option>
<option value="G01">G01 - Adq. de mercancias</option>
<option value="P01">P01 - Por definir</option>
</select>
</div>
</div>
<div style="margin-top:var(--space-4);border-top:1px solid var(--color-border);padding-top:var(--space-4);">
<div class="form-label" style="margin-bottom:var(--space-3);">Vehiculo (opcional)</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3);">
<div class="form-group"><input type="text" class="form-input" id="ncVehMake" placeholder="Marca" /></div>
<div class="form-group"><input type="text" class="form-input" id="ncVehModel" placeholder="Modelo" /></div>
<div class="form-group"><input type="text" class="form-input" id="ncVehYear" placeholder="Ano" /></div>
<div class="form-group"><input type="text" class="form-input" id="ncVehPlates" placeholder="Placas" /></div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="POS.closeNewCustomerModal()">Cancelar</button>
<button class="btn btn-primary" onclick="POS.saveNewCustomer()">Guardar Cliente</button>
</div>
</div>
</div>
<!-- ================================================================
CUT Z MODAL (Cerrar Caja)
================================================================ -->
<div class="modal-overlay" id="cutZModal">
<div class="modal-pago" style="width:520px;max-height:90vh;overflow-y:auto;">
<div class="modal-header">
<h3>Corte Z — Cerrar Caja</h3>
<button class="modal-close" onclick="POS.closeCutZModal()">&#x2715;</button>
</div>
<div style="padding:var(--space-6);">
<div id="cutZSummary" style="margin-bottom:var(--space-4);">
<p style="color:var(--color-text-muted);font-size:var(--text-body-sm);">Cargando resumen...</p>
</div>
<div style="border-top:1px solid var(--color-border);padding-top:var(--space-4);">
<div class="form-group">
<label class="form-label">Efectivo contado en caja *</label>
<input type="number" class="form-input" id="cutZClosingAmount" value="0" min="0" step="0.01" />
</div>
</div>
<div id="cutZResult" style="min-height:1.5em;font-size:var(--text-body-sm);margin-top:var(--space-3);"></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="POS.closeCutZModal()">Cancelar</button>
<button class="btn btn-secondary" onclick="POS.loadCutX()">Ver Resumen (Corte X)</button>
<button class="btn btn-primary" onclick="POS.confirmCutZ()">Cerrar Caja</button>
</div>
</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
================================================================ -->
<div class="toast-container" id="toastContainer" aria-live="assertive" aria-atomic="true"></div>
<!-- ================================================================
JAVASCRIPT
================================================================ -->
<script src="/pos/static/js/i18n.js" defer></script>
<script src="/pos/static/js/kiosk.js" defer></script>
<script src="/pos/static/js/pos-utils.js" defer></script>
<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?v=3" defer></script>
<script>
// Cancel sale button wiring
document.getElementById('btnCancelSale').addEventListener('click', function() {
document.getElementById('overlay-cancelar-venta').classList.add('active');
document.getElementById('modal-cancelar-venta').classList.add('active');
document.body.style.overflow = 'hidden';
});
document.getElementById('btnConfirmCancel').addEventListener('click', function() {
closeCancelModal();
// Clear cart via POS module
if (typeof POS !== 'undefined') {
// Clear each item
const tbody = document.getElementById('cartBody');
while (tbody && tbody.firstChild) {
POS.removeFromCart(0);
}
POS.clearCustomer();
}
});
function closeCancelModal() {
const overlay = document.getElementById('overlay-cancelar-venta');
const dialog = document.getElementById('modal-cancelar-venta');
overlay.classList.add('closing');
dialog.classList.add('closing');
setTimeout(() => {
overlay.classList.remove('active', 'closing');
dialog.classList.remove('active', 'closing');
document.body.style.overflow = '';
}, 200);
}
// Cost toggle (show only if permitted)
document.getElementById('costToggle').addEventListener('click', function() {
document.body.classList.toggle('show-cost-columns');
this.classList.toggle('active');
});
// Clock
function updateClock() {
const now = new Date();
const opts = { year: 'numeric', month: 'short', day: 'numeric',
hour: '2-digit', minute: '2-digit', hour12: true };
const el = document.getElementById('statusClock');
if (el) el.textContent = now.toLocaleString('es-MX', opts);
}
updateClock();
setInterval(updateClock, 30000);
</script>
<script src="/pos/static/js/chat.js" defer></script>
<script src="/pos/static/js/sync-engine.js" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>
<script src="/pos/static/js/pwa-install.js" defer></script>
</body>
</html>