Files
Horux360/scripts/update-cfdi-xml.js
Consultoria AS 8c3fb76406 feat(cfdi): redesign invoice viewer with professional layout
- Add gradient header with emisor info and prominent serie/folio
- Improve status badges with pill design
- Add receptor section with left accent border
- Show complete uso CFDI descriptions
- Create card grid for payment method, forma pago, moneda
- Improve conceptos table with zebra striping and SAT keys
- Add elegant totals box with blue footer
- Enhance timbre fiscal section with QR placeholder and SAT URL
- Add update-cfdi-xml.js script for bulk XML import

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 06:17:29 +00:00

136 lines
3.8 KiB
JavaScript

#!/usr/bin/env node
/**
* Script para actualizar CFDIs existentes con su XML original
* Uso: node scripts/update-cfdi-xml.js <directorio> <schema>
* Ejemplo: node scripts/update-cfdi-xml.js /root/xmls tenant_roem691011ez4
*/
const fs = require('fs');
const path = require('path');
const { Pool } = require('pg');
// Configuración de la base de datos
const pool = new Pool({
host: 'localhost',
port: 5432,
database: 'horux360',
user: 'postgres',
password: 'postgres',
});
// Extraer UUID del XML
function extractUuidFromXml(xmlContent) {
// Buscar UUID en TimbreFiscalDigital
const uuidMatch = xmlContent.match(/UUID=["']([A-Fa-f0-9-]{36})["']/i);
return uuidMatch ? uuidMatch[1].toUpperCase() : null;
}
// Procesar archivos en lotes
async function processFiles(directory, schema, batchSize = 500) {
const files = fs.readdirSync(directory).filter(f => f.toLowerCase().endsWith('.xml'));
console.log(`\nEncontrados ${files.length} archivos XML en ${directory}`);
console.log(`Schema: ${schema}`);
console.log(`Tamaño de lote: ${batchSize}\n`);
let updated = 0;
let notFound = 0;
let errors = 0;
let processed = 0;
const startTime = Date.now();
// Procesar en lotes
for (let i = 0; i < files.length; i += batchSize) {
const batch = files.slice(i, i + batchSize);
const updates = [];
// Leer y parsear XMLs del lote
for (const file of batch) {
try {
const filePath = path.join(directory, file);
const xmlContent = fs.readFileSync(filePath, 'utf8');
const uuid = extractUuidFromXml(xmlContent);
if (uuid) {
updates.push({ uuid, xmlContent });
} else {
errors++;
if (errors <= 5) {
console.log(` ⚠ No se encontró UUID en: ${file}`);
}
}
} catch (err) {
errors++;
if (errors <= 5) {
console.log(` ✗ Error leyendo ${file}: ${err.message}`);
}
}
}
// Actualizar base de datos en una transacción
const client = await pool.connect();
try {
await client.query('BEGIN');
for (const { uuid, xmlContent } of updates) {
const result = await client.query(
`UPDATE "${schema}".cfdis SET xml_original = $1 WHERE UPPER(uuid_fiscal) = $2 AND xml_original IS NULL`,
[xmlContent, uuid]
);
if (result.rowCount > 0) {
updated++;
} else {
notFound++;
}
}
await client.query('COMMIT');
} catch (err) {
await client.query('ROLLBACK');
console.error(`Error en lote: ${err.message}`);
errors += batch.length;
} finally {
client.release();
}
processed += batch.length;
// Progreso
const percent = ((processed / files.length) * 100).toFixed(1);
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
const rate = (processed / elapsed).toFixed(0);
process.stdout.write(`\r Procesando: ${processed}/${files.length} (${percent}%) - ${updated} actualizados - ${rate} archivos/seg `);
}
const totalTime = ((Date.now() - startTime) / 1000).toFixed(1);
console.log(`\n\n✓ Completado en ${totalTime} segundos`);
console.log(` - Actualizados: ${updated}`);
console.log(` - No encontrados (UUID no existe en BD): ${notFound}`);
console.log(` - Errores: ${errors}`);
await pool.end();
}
// Main
const args = process.argv.slice(2);
if (args.length < 2) {
console.log('Uso: node scripts/update-cfdi-xml.js <directorio> <schema>');
console.log('Ejemplo: node scripts/update-cfdi-xml.js /root/xmls tenant_roem691011ez4');
process.exit(1);
}
const [directory, schema] = args;
if (!fs.existsSync(directory)) {
console.error(`Error: El directorio ${directory} no existe`);
process.exit(1);
}
processFiles(directory, schema).catch(err => {
console.error('Error fatal:', err);
process.exit(1);
});