Mejoras de sesion: estabilizacion, IA, Nexus Yonke y marketplace B2B
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

- 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:
2026-10-12 00:57:31 +00:00
parent f2d4558b80
commit a386ca5b4a
165 changed files with 31313 additions and 2203 deletions

View File

@@ -367,6 +367,10 @@
<label style="display:flex;align-items:center;gap:var(--space-2);cursor:pointer;"><input type="checkbox" id="receipt-show-payment" style="width:auto;" checked /> Mostrar detalle de pago</label>
<label style="display:flex;align-items:center;gap:var(--space-2);cursor:pointer;"><input type="checkbox" id="receipt-show-employee" style="width:auto;" /> Mostrar nombre del empleado</label>
</div>
<div class="form-group" style="display:flex;align-items:center;gap:8px;">
<input type="checkbox" id="receipt-auto-print" />
<label for="receipt-auto-print" style="margin:0;">Imprimir ticket automáticamente al cobrar</label>
</div>
<div style="margin-top:var(--space-4);text-align:right;">
<button class="btn btn--primary" onclick="Config.saveReceiptConfig()">Guardar ticket</button>
</div>
@@ -454,6 +458,42 @@
</div>
</div>
<!-- ===============================================================
SECTION 4B: ALERTAS POR WHATSAPP (contactos por negocio)
=============================================================== -->
<div class="settings-section" data-tab="general">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
</div>
<div>
<div class="settings-section__title">Alertas por WhatsApp</div>
<div class="settings-section__desc">Números que reciben las alertas automáticas de este negocio. Si no configuras ninguno, las alertas no se envían.</div>
</div>
</div>
<div class="settings-card">
<div class="toggle-row">
<div class="toggle-row__info">
<span class="toggle-row__label">Enviar alertas por WhatsApp</span>
<span class="toggle-row__desc">Activa el reenvío de alertas al número de este negocio</span>
</div>
<label class="toggle">
<input type="checkbox" id="cfg-alert-whatsapp-enabled" />
<span class="toggle__slider"></span>
</label>
</div>
<div class="form-group" style="margin-top:var(--space-3);">
<label class="form-label">Números de alerta</label>
<input type="text" class="form-input" id="alert-phones" placeholder="+5215512345678, +5215587654321" />
<span class="form-hint">Formato internacional, separados por coma. Solo dígitos y "+" (10-15 dígitos).</span>
</div>
<div style="margin-top:var(--space-4);display:flex;justify-content:flex-end;">
<button class="btn btn--primary" id="btn-save-alert-contacts">Guardar alertas</button>
</div>
</div>
</div>
<!-- ===============================================================
SECTION 4: USUARIOS Y PERMISOS
=============================================================== -->
@@ -598,7 +638,7 @@
<span class="toggle-row__desc">Generar CFDI automáticamente al cerrar una venta</span>
</div>
<label class="toggle">
<input type="checkbox" checked />
<input type="checkbox" id="cfg-invoice-auto" checked />
<span class="toggle__slider"></span>
</label>
</div>
@@ -608,7 +648,7 @@
<span class="toggle-row__desc">Enviar PDF y XML al correo del cliente</span>
</div>
<label class="toggle">
<input type="checkbox" checked />
<input type="checkbox" id="cfg-invoice-email" checked />
<span class="toggle__slider"></span>
</label>
</div>
@@ -618,7 +658,7 @@
<span class="toggle-row__desc">Generar CFDI global para ventas sin RFC</span>
</div>
<label class="toggle">
<input type="checkbox" />
<input type="checkbox" id="cfg-invoice-global" />
<span class="toggle__slider"></span>
</label>
</div>
@@ -835,6 +875,42 @@
</div>
</div>
<!-- ===============================================================
SECTION 9B: PRECIOS POR TIPO DE CLIENTE
=============================================================== -->
<div class="settings-section" data-tab="catalog">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="5" x2="5" y2="19"/><circle cx="6.5" cy="6.5" r="2.5"/><circle cx="17.5" cy="17.5" r="2.5"/></svg>
</div>
<div>
<div class="settings-section__title">Precios por Tipo de Cliente</div>
<div class="settings-section__desc">Descuento sobre precio de mostrador para clientes Taller y Mayoreo</div>
</div>
</div>
<div class="settings-card">
<div class="settings-card__title">Descuentos por Nivel de Precio</div>
<div class="form-grid" style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4);">
<div class="form-group">
<label class="form-label">Taller (Nivel 2) — % descuento</label>
<input class="form-input" id="cfg-tier-disc-2" type="number" min="0" max="100" step="0.5" value="0" />
</div>
<div class="form-group">
<label class="form-label">Mayoreo (Nivel 3) — % descuento</label>
<input class="form-input" id="cfg-tier-disc-3" type="number" min="0" max="100" step="0.5" value="0" />
</div>
</div>
<p style="color:var(--color-text-muted);font-size:var(--text-caption);margin-top:var(--space-2);">
El descuento se aplica sobre el precio de mostrador al crear o actualizar el precio de un producto. No modifica los precios ya calculados de productos existentes.
</p>
<div style="margin-top:var(--space-4);display:flex;gap:var(--space-3);align-items:center;justify-content:flex-end;">
<span id="tier-discount-status" style="font-size:var(--text-caption);color:var(--color-text-muted);"></span>
<button class="btn btn--primary" id="btn-save-tier-discounts" onclick="Config.saveTierDiscounts()">Guardar Descuentos</button>
</div>
</div>
</div>
<!-- ===============================================================
SECTION 10: MONEDA / CURRENCY
=============================================================== -->
@@ -900,6 +976,7 @@
<option value="accountant">Contador</option>
<option value="workshop">Taller</option>
<option value="mechanic">Mecánico</option>
<option value="driver">Repartidor</option>
</select>
</div>
@@ -1044,6 +1121,7 @@
<option value="accountant">Contador</option>
<option value="workshop">Taller</option>
<option value="mechanic">Mecanico</option>
<option value="driver">Repartidor</option>
</select>
</div>
<div class="form-group">
@@ -1070,12 +1148,12 @@
</div>
<script src="/pos/static/js/i18n.js?v=39" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/kiosk.js" defer></script>
<script src="/pos/static/js/config.js?v=41" defer></script>
<script src="/pos/static/js/config.js?v=45" 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>