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

75
restore_inventory3.js Normal file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env node
/* Restauración v3: TODAS las funciones/globales que el parche borró de inventory.js
(comparando HEAD vs actual por referencias de templates + exposiciones window). */
const fs = require('fs');
const { execSync } = require('child_process');
const old = execSync('git show HEAD:pos/static/js/inventory.js', { maxBuffer: 20 * 1024 * 1024 }).toString();
let cur = fs.readFileSync('pos/static/js/inventory.js', 'utf8');
// 1. Identificadores referenciados por templates (onclick/onchange/oninput/onkeydown)
const tpl = fs.readFileSync('pos/templates/inventory.html', 'utf8');
const handlers = new Set();
const reH = /on(?:click|change|input|keydown|keyup|blur|focus)="([^"]+)"/g;
let m;
while ((m = reH.exec(tpl))) {
const body = m[1];
const reId = /([A-Za-z_$][\w$]*)\s*\(/g;
let mm;
while ((mm = reId.exec(body))) {
const fn = mm[1];
if (!['if', 'event', 'this', 'return', 'parseInt', 'parseFloat', 'String', 'Number', 'confirm', 'alert'].includes(fn)) {
handlers.add(fn);
}
}
}
// 2. window.X = X sin definición en el archivo actual
const exposeRe = /window\.([A-Za-z_$][\w$]*)\s*=\s*\1\b/g;
const exposed = new Set();
while ((m = exposeRe.exec(cur))) exposed.add(m[1]);
// 3. Referencias directas dentro del JS (llamadas sin definición)
const calledMissing = [];
for (const name of handlers) {
const defined = new RegExp('function\\s+' + name + '\\b').test(cur) ||
new RegExp('\\b' + name + '\\s*=\\s*function').test(cur) ||
cur.includes('window.' + name + ' ');
if (!defined) calledMissing.push(name);
}
console.log('handlers de template SIN definición:', calledMissing);
console.log('exposiciones window sin función:', [...exposed].filter(n => !new RegExp('function\\s+' + n + '\\b').test(cur) && !new RegExp('\\b' + n + '\\s*=\\s*function').test(cur)));
// 4. extraer de HEAD cada función faltante (por marcadores de 4 espacios)
function extractFrom(src, name) {
const start = src.indexOf('\n function ' + name + '(');
if (start === -1) return null;
let end = src.length;
const nf = src.indexOf('\n function ', start + 30);
const nm = src.indexOf('\n // =====================================================================', start + 30);
if (nf !== -1) end = Math.min(end, nf);
if (nm !== -1) end = Math.min(end, nm);
return src.slice(start + 1, end);
}
const need = new Set([...calledMissing]);
for (const n of exposed) {
if (!new RegExp('function\\s+' + n + '\\b').test(cur)) need.add(n);
}
const blocks = [];
for (const name of need) {
const b = extractFrom(old, name);
if (b) blocks.push(b.trimEnd());
else console.log(' (no está en HEAD: ' + name + ')');
}
if (blocks.length) {
const anchor = '\n // =====================================================================\n // EXPOSE GLOBALS (for onclick handlers in HTML)';
const idx = cur.indexOf(anchor);
if (idx === -1) { console.log('ERROR: anchor no encontrado'); process.exit(1); }
cur = cur.slice(0, idx) + '\n // ==== RESTAURADAS v3 ====\n\n' + blocks.join('\n\n') + '\n' + cur.slice(idx);
fs.writeFileSync('pos/static/js/inventory.js', cur);
console.log('restauradas ' + blocks.length + ' funciones');
}