/** * Backfill: re-parsea CFDIs tipo P emitidos vía Facturapi (source='facturapi') * que tienen `monto_pago_mxn` o `fecha_pago_p` NULL, y popula esos campos * desde el XML original. Bug histórico — el INSERT de facturapi.controller.ts * no incluía los campos del complemento Pagos hasta el fix de hoy. * * Idempotente — solo actualiza si el XML tiene datos y el row tiene NULL. */ import { prisma, tenantDb } from '../src/config/database.js'; import { parseXml } from '../src/services/sat/sat-parser.service.js'; async function main() { const tenants = await prisma.tenant.findMany({ where: { active: true }, select: { id: true, rfc: true, nombre: true, databaseName: true }, }); let totalUpdated = 0; let totalChecked = 0; for (const t of tenants) { const pool = await tenantDb.getPool(t.id, t.databaseName); const { rows } = await pool.query(` SELECT uuid, xml_original FROM cfdis WHERE source = 'facturapi' AND tipo_comprobante = 'P' AND xml_original IS NOT NULL AND (monto_pago_mxn IS NULL OR fecha_pago_p IS NULL) `); if (rows.length === 0) continue; console.log(`\n>>> ${t.rfc} (${t.nombre}): ${rows.length} P por backfill`); for (const r of rows) { totalChecked++; const parsed = parseXml(r.xml_original, 'emitidos'); if (!parsed || parsed.tipoComprobante !== 'P') continue; const fechaPagoP = parsed.fechaPagoP ? new Date(String(parsed.fechaPagoP).split('|')[0]) : null; if (!parsed.montoPago && !fechaPagoP) { console.log(` ${r.uuid}: XML sin datos de Pago — skip`); continue; } await pool.query(` UPDATE cfdis SET monto_pago = COALESCE(monto_pago, $1), monto_pago_mxn = COALESCE(monto_pago_mxn, $1), fecha_pago_p = COALESCE(fecha_pago_p, $2), iva_traslado_pago = COALESCE(iva_traslado_pago, $3), iva_traslado_pago_mxn = COALESCE(iva_traslado_pago_mxn, $3), iva_retencion_pago = COALESCE(iva_retencion_pago, $4), iva_retencion_pago_mxn = COALESCE(iva_retencion_pago_mxn, $4), ieps_traslado_pago = COALESCE(ieps_traslado_pago, $5), ieps_traslado_pago_mxn = COALESCE(ieps_traslado_pago_mxn, $5) WHERE uuid = $6 `, [ parsed.montoPago || 0, fechaPagoP, parsed.ivaTrasladoPago || 0, parsed.ivaRetencionPago || 0, parsed.iepsTrasladoPago || 0, r.uuid, ]); totalUpdated++; console.log(` ${r.uuid}: ✓ monto=$${parsed.montoPago} fecha_pago=${fechaPagoP?.toISOString().slice(0, 10)} iva=$${parsed.ivaTrasladoPago}`); } } console.log(`\n[Backfill] Completado: ${totalUpdated}/${totalChecked} actualizadas`); await prisma.$disconnect(); } main().catch(e => { console.error(e); process.exit(1); });