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:
@@ -44,7 +44,7 @@
|
||||
var roleLabels = {
|
||||
'owner': _t('role_owner'), 'admin': _t('role_admin'), 'cashier': _t('role_cashier'),
|
||||
'warehouse': _t('role_warehouse'), 'accountant': _t('role_accountant'),
|
||||
'workshop': 'Taller', 'mechanic': 'Mecanico'
|
||||
'workshop': 'Taller', 'mechanic': 'Mecanico', 'driver': 'Repartidor'
|
||||
};
|
||||
var roleLabel = roleLabels[role] || role;
|
||||
var initials = name.split(' ').map(function(p) { return p[0]; }).join('').toUpperCase().substring(0, 2);
|
||||
@@ -199,6 +199,8 @@
|
||||
homeHref = '/pos/sale';
|
||||
} else if (userRole === 'workshop' && userPerms.indexOf('workshop.view') !== -1 && moduleEnabled('workshop')) {
|
||||
homeHref = '/pos/workshop';
|
||||
} else if (userRole === 'driver' && userPerms.indexOf('pos.remission') !== -1) {
|
||||
homeHref = '/pos/remission-notes';
|
||||
}
|
||||
document.querySelectorAll('a[href="/pos/dashboard"]').forEach(function(a) {
|
||||
a.setAttribute('href', homeHref);
|
||||
@@ -208,8 +210,8 @@
|
||||
function isPageAllowed(pagePath, userRole, userPerms) {
|
||||
if (userRole === 'owner' || userRole === 'admin') return true;
|
||||
|
||||
// Restricted roles (workshop/mechanic/counter/cashier) see modules based on permissions.
|
||||
if (['workshop', 'mechanic', 'counter', 'cashier'].indexOf(userRole) !== -1) {
|
||||
// Restricted roles (workshop/mechanic/counter/cashier/driver) see modules based on permissions.
|
||||
if (['workshop', 'mechanic', 'counter', 'cashier', 'driver'].indexOf(userRole) !== -1) {
|
||||
var allowed = [];
|
||||
if ((userRole === 'workshop' || userRole === 'mechanic') && moduleEnabled('workshop')) {
|
||||
allowed = ['/pos/workshop'];
|
||||
@@ -226,7 +228,8 @@
|
||||
'quotations.view': '/pos/quotations',
|
||||
'accounting.view': '/pos/accounting',
|
||||
'reports.view': '/pos/reports',
|
||||
'dashboard.view': '/pos/dashboard'
|
||||
'dashboard.view': '/pos/dashboard',
|
||||
'yonke.view': '/pos/yonke'
|
||||
};
|
||||
for (var p in permMap) {
|
||||
if (userPerms.indexOf(p) !== -1 && allowed.indexOf(permMap[p]) === -1) {
|
||||
@@ -251,7 +254,7 @@
|
||||
var fallback = null;
|
||||
if (userRole === 'owner' || userRole === 'admin') {
|
||||
fallback = '/pos/dashboard';
|
||||
} else if (['workshop', 'mechanic', 'counter', 'cashier'].indexOf(userRole) !== -1) {
|
||||
} else if (['workshop', 'mechanic', 'counter', 'cashier', 'driver'].indexOf(userRole) !== -1) {
|
||||
var allowed = [];
|
||||
if ((userRole === 'workshop' || userRole === 'mechanic') && moduleEnabled('workshop')) {
|
||||
allowed = ['/pos/workshop'];
|
||||
@@ -268,7 +271,8 @@
|
||||
'quotations.view': '/pos/quotations',
|
||||
'accounting.view': '/pos/accounting',
|
||||
'reports.view': '/pos/reports',
|
||||
'dashboard.view': '/pos/dashboard'
|
||||
'dashboard.view': '/pos/dashboard',
|
||||
'yonke.view': '/pos/yonke'
|
||||
};
|
||||
for (var p in permMap) {
|
||||
if (userPerms.indexOf(p) !== -1 && allowed.indexOf(permMap[p]) === -1) {
|
||||
@@ -350,13 +354,18 @@
|
||||
backBtn.style.display = 'none';
|
||||
})();
|
||||
|
||||
// ─── Service Worker update handler ───
|
||||
// ─── Service Worker update handler (patrón controllerchange) ───
|
||||
// Recarga SOLO cuando el SW que controlaba esta página fue reemplazado
|
||||
// (deploy con assets nuevos). La primera activación (sin controlador
|
||||
// previo) NO recarga — así se elimina el doble refresh al cambiar de
|
||||
// pestaña tras cada deploy.
|
||||
var _hadSwController = !!navigator.serviceWorker.controller;
|
||||
var _swRefreshing = false;
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.addEventListener('message', function (event) {
|
||||
if (event.data && event.data.type === 'SW_UPDATED') {
|
||||
console.log('[AppInit] SW updated to', event.data.cacheName, '— reloading...');
|
||||
window.location.reload();
|
||||
}
|
||||
navigator.serviceWorker.addEventListener('controllerchange', function () {
|
||||
if (!_hadSwController || _swRefreshing) return;
|
||||
_swRefreshing = true;
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user