Mejoras de sesion: estabilizacion, IA, Nexus Yonke y marketplace B2B
- F0 blindaje: Redis/Celery, pg_hba sin trust LAN, secretos a env 600, backups, webhook auth, jobs muertos - F1 caja: bugs POS, reembolsos al corte, apartados, CFDI, topes de descuento en cotizacion/apartado - F2/F7 IA de catalogo: autocategorizacion, dedup de SKUs con embeddings, OCR de facturas, descripciones, claves SAT, limpieza de fitment - F3 IA en el flujo: vision Yonke, preguntas MeLi, venta cruzada, anomalias, sinonimos, busqueda semantica (rerank/embeddings) - F4/F8 escala y cartera: /metrics+Prometheus+Grafana, pool, score de credito, churn, metricas multi-tenant - Nexus Yonke (M1-M6): modelo de datos 1-de-1, alta por donador, vitrina publica, MeLi usado, consignacion, garantia por dias, reportes, etiquetas - Marketplace B2B entre yonkes (catalogo + pedidos cross-tenant) - Seguridad: auth en /api/admin/* (35 endpoints), alertas por tenant - Migraciones v4.27/v4.28; timers expire-demos y rollup-metrics
This commit is contained in:
@@ -19,6 +19,9 @@
|
||||
<link rel="stylesheet" href="/pos/static/css/pos.css?v=35"></head>
|
||||
|
||||
<body class="pos-shell" id="appBody">
|
||||
<div id="offlineBanner" style="display:none;position:fixed;top:0;left:0;right:0;z-index:9999;padding:10px 16px;align-items:center;justify-content:center;gap:8px;font-size:var(--text-body-sm);">
|
||||
<span id="offlineBannerText"></span>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
STATUS BAR
|
||||
@@ -63,6 +66,13 @@
|
||||
placeholder="Buscar por nombre, No. parte, codigo..."
|
||||
autocomplete="off" spellcheck="false" aria-label="Buscar productos" />
|
||||
</div>
|
||||
<div class="search-wrap" style="max-width:260px;display:flex;gap:6px;">
|
||||
<input class="search-input" type="text" id="vehicleLookup"
|
||||
placeholder="Placa o VIN"
|
||||
autocomplete="off" spellcheck="false" aria-label="Placa o VIN"
|
||||
onkeydown="if(event.key==='Enter'){event.preventDefault();POS.vehicleLookup();}" />
|
||||
<button class="btn-secondary-action" onclick="POS.vehicleLookup()" title="Ver piezas compatibles">🚗</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Results Dropdown -->
|
||||
@@ -177,6 +187,15 @@
|
||||
<span class="margin-summary__value" id="avgMargin">--</span>
|
||||
</div>
|
||||
|
||||
<!-- Cross-sell suggestions (A10) -->
|
||||
<div id="crossSellPanel" style="display:none;margin:6px 0;padding:8px 10px;border:1px dashed var(--color-border);border-radius:var(--radius-sm);background:var(--color-bg-base);">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;font-size:var(--text-caption);font-weight:var(--font-weight-semibold);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:.4px;">
|
||||
<span>¿Ya que estás en eso…?</span>
|
||||
<button type="button" title="Ocultar" onclick="POS.hideCrossSell()" style="background:transparent;border:none;color:var(--color-text-muted);cursor:pointer;font-size:14px;">×</button>
|
||||
</div>
|
||||
<div id="crossSellList" style="display:flex;flex-direction:column;gap:4px;margin-top:6px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Footer -->
|
||||
<div class="cart-footer">
|
||||
<div class="totals-block">
|
||||
@@ -224,6 +243,9 @@
|
||||
<button class="btn-secondary-action" onclick="POS.createLayaway()" title="Apartado (requiere cliente)">Apartado</button>
|
||||
<button class="btn-secondary-action" onclick="POS.createServiceOrder()" title="Orden de servicio (F7)">Orden Taller</button>
|
||||
<button class="btn-secondary-action" onclick="POS.showLastSale()" title="Ultima venta (F5)">Ult.Venta</button>
|
||||
<span id="offlineQueueBadge" style="display:none;background:var(--color-warning);color:#fff;border-radius:999px;padding:2px 10px;font-weight:700;font-size:var(--text-caption);">0</span>
|
||||
<button class="btn-secondary-action" onclick="POS.openReturnModal()" title="Devolución de venta">Devolución</button>
|
||||
<button class="btn-secondary-action" onclick="POS.openLayawaysModal()" title="Apartados activos">Apartados</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" onclick="POS.openCancelModal()" title="Cancelar (Esc)">Cancelar</button>
|
||||
</div>
|
||||
@@ -325,7 +347,15 @@
|
||||
<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 style="display:flex;align-items:center;gap:8px;margin-top:8px;">
|
||||
<label style="font-size:var(--text-caption);color:var(--color-text-muted);">Moneda:</label>
|
||||
<select id="payCurrency" class="form-input" style="width:90px;padding:4px 8px;" onchange="POS.updateChange()">
|
||||
<option value="MXN">MXN $</option>
|
||||
<option value="USD">USD</option>
|
||||
</select>
|
||||
<span id="usdRateHint" style="font-size:var(--text-caption);color:var(--color-text-muted);"></span>
|
||||
</div></div>
|
||||
<div class="quick-amounts" id="quickAmounts">
|
||||
<!-- Populated dynamically -->
|
||||
</div>
|
||||
@@ -416,6 +446,14 @@
|
||||
<span class="cfdi-hint" id="cfdiHint"></span>
|
||||
</div>
|
||||
|
||||
<!-- Repartidor (opcional) -->
|
||||
<div class="form-group" style="margin-top: 12px;">
|
||||
<label class="form-label" for="saleCourier">Repartidor (opcional)</label>
|
||||
<select class="form-input" id="saleCourier">
|
||||
<option value="">— Sin repartidor —</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-ghost" onclick="POS.closePaymentModal()">Cancelar</button>
|
||||
@@ -729,11 +767,11 @@
|
||||
<script src="/pos/static/js/i18n.js?v=39" defer></script>
|
||||
<script src="/pos/static/js/kiosk.js" defer></script>
|
||||
<script src="/pos/static/js/pos-utils.js?v=33" defer></script>
|
||||
<script src="/pos/static/js/app-init.js?v=8" defer></script>
|
||||
<script src="/pos/static/js/app-init.js?v=9" defer></script>
|
||||
<script src="/pos/static/js/splash-loader.js?v=33" 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=42" defer></script>
|
||||
<script src="/pos/static/js/pos.js?v=46" defer></script>
|
||||
|
||||
<script>
|
||||
// Cancel sale button wiring
|
||||
@@ -798,7 +836,68 @@
|
||||
|
||||
<script src="/pos/static/js/chat.js" defer></script>
|
||||
<script src="/pos/static/js/sync-engine.js" defer></script>
|
||||
<script src="/pos/static/js/offline-banner.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>
|
||||
|
||||
<!-- ══════════ RETURN MODAL ══════════ -->
|
||||
<div class="modal-overlay" id="returnModal">
|
||||
<div class="modal-box" style="max-width:640px;">
|
||||
<div class="modal-header">
|
||||
<h3>Devolución de venta</h3>
|
||||
<button class="btn-close" onclick="POS.closeReturnModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div style="display:flex;gap:8px;margin-bottom:12px;">
|
||||
<input type="number" id="returnSaleId" class="form-input" placeholder="Folio de venta (ej. 123)" style="flex:1;" />
|
||||
<button class="btn btn-primary" onclick="POS.searchReturnSale()">Buscar</button>
|
||||
</div>
|
||||
<div id="returnSaleInfo" style="display:none;margin-bottom:10px;font-size:var(--text-body-sm);color:var(--color-text-muted);"></div>
|
||||
<div id="returnItemsList" style="display:none;max-height:280px;overflow-y:auto;border:1px solid var(--color-border);border-radius:8px;"></div>
|
||||
<div style="margin-top:10px;">
|
||||
<input type="text" id="returnNotes" class="form-input" placeholder="Notas (opcional)" />
|
||||
</div>
|
||||
<div id="returnResult" style="margin-top:10px;font-size:var(--text-body-sm);"></div>
|
||||
</div>
|
||||
<div class="modal-footer" id="returnFooter" style="display:none;">
|
||||
<button class="btn btn-ghost" onclick="POS.closeReturnModal()">Cerrar</button>
|
||||
<button class="btn btn-primary" onclick="POS.submitReturn()">Registrar devolución</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══════════ LAYAWAYS MODAL ══════════ -->
|
||||
<div class="modal-overlay" id="layawaysModal">
|
||||
<div class="modal-box" style="max-width:720px;">
|
||||
<div class="modal-header">
|
||||
<h3>Apartados activos</h3>
|
||||
<button class="btn-close" onclick="POS.closeLayawaysModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="layawaysList" style="max-height:340px;overflow-y:auto;">
|
||||
<span style="color:var(--color-text-muted);font-size:var(--text-caption);">Cargando...</span>
|
||||
</div>
|
||||
<div id="layawayActions" style="display:none;margin-top:12px;border-top:1px solid var(--color-border);padding-top:12px;">
|
||||
<div id="layawayDetail" style="font-size:var(--text-body-sm);margin-bottom:10px;"></div>
|
||||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
||||
<input type="number" id="layawayPayAmount" class="form-input" placeholder="Monto abono" style="width:140px;" />
|
||||
<select id="layawayPayMethod" class="form-input" style="width:150px;">
|
||||
<option value="efectivo">Efectivo</option>
|
||||
<option value="tarjeta">Tarjeta</option>
|
||||
<option value="transferencia">Transferencia</option>
|
||||
</select>
|
||||
<button class="btn btn-primary" onclick="POS.layawayPay()">Abonar</button>
|
||||
<button class="btn btn-primary" onclick="POS.layawayComplete()" style="background:var(--color-success);">Liquidar</button>
|
||||
<button class="btn btn-ghost" onclick="POS.layawayCancel()" style="color:var(--color-error);">Cancelar apartado</button>
|
||||
</div>
|
||||
<div id="layawayResult" style="margin-top:8px;font-size:var(--text-body-sm);"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-ghost" onclick="POS.closeLayawaysModal()">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user