- 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
76 lines
3.2 KiB
JavaScript
76 lines
3.2 KiB
JavaScript
#!/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');
|
|
}
|