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

64
restore_inventory4.js Normal file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env node
/* Restauración v4: extrae funciones de HEAD en ambos formatos (function X / window.X = function). */
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');
// Nombres realmente faltantes (referenciados por templates o expuestos), según auditoría:
const CANDIDATES = ['searchMeliCategories', 'handleMeliCatKeydown', 'onMeliShippingChange',
'validateMeliPublish', 'executeMeliPublish', 'openMeliPublishModal', 'closeMeliPublishModal',
'refreshMeliPublishPreview', 'selectMeliCategory', 'selectMeliCategoryIdx', 'highlightMeliCat',
'loadCategoryAttributes', 'updateMeliTitleCount', 'handleMeliImageUpload', 'showTierDiscountModal',
'closeTierDiscountModal', 'saveTierDiscounts', 'openInventoryFilters'];
function hasDef(src, name) {
return new RegExp('\\n function ' + name + '\\s*\\(').test(src) ||
new RegExp('\\n window\\.' + name + '\\s*=').test(src) ||
new RegExp('\\n (?:var|let|const) ' + name + '\\s*=').test(src);
}
// extrae desde el inicio de la definición hasta el próximo inicio de nivel 4
function extract(src, name) {
const patterns = [
'\n function ' + name + '(',
'\n function ' + name + ' (',
'\n window.' + name + ' = function',
'\n window.' + name + ' = async function',
'\n var ' + name + ' = function',
];
let start = -1;
for (const p of patterns) { start = src.indexOf(p); if (start !== -1) break; }
if (start === -1) return null;
let end = src.length;
const stops = [
src.indexOf('\n function ', start + 30),
src.indexOf('\n window.', start + 30),
src.indexOf('\n var ', start + 30),
src.indexOf('\n // ====', start + 30),
].filter(i => i !== -1);
if (stops.length) end = Math.min(...stops);
return src.slice(start + 1, end);
}
const blocks = [];
const missingNoHead = [];
for (const name of CANDIDATES) {
if (hasDef(cur, name)) continue; // ya existe
const b = extract(old, name);
if (b) blocks.push(b.trimEnd());
else missingNoHead.push(name);
}
console.log('restaurables desde HEAD:', blocks.length);
console.log('no halladas en HEAD:', missingNoHead);
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'); process.exit(1); }
cur = cur.slice(0, idx) + '\n // ==== RESTAURADAS v4 (MELI + descuentos) ====\n\n' + blocks.join('\n\n') + '\n' + cur.slice(idx);
}
fs.writeFileSync('pos/static/js/inventory.js', cur);
console.log('escrito');