Files
Autoparts-DB/audit_js.js
consultoria-as a386ca5b4a
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled
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
2026-10-12 00:57:31 +00:00

86 lines
3.6 KiB
JavaScript

#!/usr/bin/env node
/* Auditoría JS: carga cada página del POS y reporta errores de consola y handlers rotos. */
const { chromium } = require('playwright');
const { execSync } = require('child_process');
const JWT_SECRET = execSync(
"grep -oP 'POS_JWT_SECRET=\\K.*' /etc/systemd/system/nexus-pos.service | head -1"
).toString().trim();
function makeToken() {
const header = { alg: 'HS256', typ: 'JWT' };
const now = Math.floor(Date.now() / 1000);
const payload = {
tenant_id: 32, employee_id: 1, name: 'Audit Admin', role: 'owner',
branch_id: 1, max_discount_pct: 100,
permissions: ['pos.sell', 'pos.view', 'pos.remission', 'pos.discount', 'pos.cancel',
'catalog.view', 'inventory.view', 'inventory.create', 'inventory.edit',
'inventory.adjust', 'inventory.transfer', 'customers.view', 'customers.create',
'invoicing.view', 'invoicing.create', 'reports.view', 'config.view', 'config.edit',
'config.edit_prices', 'workshop.view', 'workshop.edit', 'dashboard.view'],
device_id: 'audit', type: 'pos_access', exp: now + 900, iat: now,
};
const b64 = (o) => Buffer.from(JSON.stringify(o)).toString('base64url');
const crypto = require('crypto');
const sig = crypto.createHmac('sha256', JWT_SECRET)
.update(b64(header) + '.' + b64(payload)).digest('base64url');
return b64(header) + '.' + b64(payload) + '.' + sig;
}
const PAGES = [
'/pos/sale', '/pos/inventory', '/pos/customers', '/pos/config',
'/pos/dashboard', '/pos/invoicing', '/pos/remission-notes', '/pos/catalog',
'/pos/quotations', '/pos/reports', '/pos/accounting', '/pos/workshop',
'/pos/whatsapp', '/pos/marketplace-external',
];
(async () => {
const browser = await chromium.launch();
const ctx = await browser.newContext();
const page = await ctx.newPage();
const brokenHandlers = [];
await page.addInitScript((token) => {
localStorage.setItem('pos_token', token);
localStorage.setItem('pos_employee', JSON.stringify({ id: 1, name: 'Audit Admin', role: 'owner' }));
localStorage.setItem('pos_tenant_id', '32');
document.cookie = 'pos_role=owner; path=/pos; SameSite=Lax';
// Capturar errores de handlers inline (onclick con función inexistente)
window.addEventListener('error', function (e) {
if (e.message && /is not a function|is not defined/.test(e.message)) {
(window.__broken = window.__broken || []).push(e.message + ' @ ' + location.pathname);
}
});
}, makeToken());
for (const p of PAGES) {
const errs = [];
const onConsole = (m) => {
if (m.type() === 'error') errs.push(m.text().slice(0, 160));
};
page.on('pageerror', (e) => errs.push('PAGEERROR: ' + String(e).slice(0, 160)));
page.on('console', onConsole);
try {
await page.goto('http://localhost:5001' + p, { waitUntil: 'load', timeout: 20000 });
await page.waitForTimeout(2200);
// Los errores capturados en window.__broken (handlers inline)
const inline = await page.evaluate(() => (window.__broken || []).splice(0));
const realErrs = errs.filter((t) =>
!/favicon|net::ERR|Failed to load resource|404|sourcemap|DevTools/i.test(t));
if (realErrs.length || inline.length) {
console.log('✗ ' + p);
realErrs.slice(0, 4).forEach((t) => console.log(' consola: ' + t));
inline.slice(0, 6).forEach((t) => console.log(' handler: ' + t));
} else {
console.log('✓ ' + p);
}
} catch (e) {
console.log('✗✗ ' + p + ' → ' + e.message.slice(0, 120));
}
page.removeAllListeners('console');
page.removeAllListeners('pageerror');
}
await browser.close();
})();