/** * Amplía la inspección: lista TODOS los CFDIs de mayo-2025 donde Horux 360 * aparece como emisor o receptor, marcando cuáles entran al bucket ingresos * y cuáles no + por qué. */ import { prisma, tenantDb } from '../src/config/database.js'; import { resolveContribuyenteContext } from '../src/utils/contribuyente-context.js'; const TENANT_RFC = 'DESPACHO_MO3NI6U8_B9VGG'; const CONTRIB_ID = 'b3761db6-0b8d-4251-8078-4ddc31e9c75b'; const FI = '2025-05-01'; const FF = '2025-05-31'; async function main() { const tenant = await prisma.tenant.findFirst({ where: { rfc: TENANT_RFC }, select: { id: true, databaseName: true }, }); if (!tenant) return; const pool = await tenantDb.getPool(tenant.id, tenant.databaseName); const ctx = await resolveContribuyenteContext(pool, tenant.id, CONTRIB_ID); console.log(`\n=== TODOS los CFDIs de Horux 360 en mayo-2025 (como emisor o receptor) ===\n`); const { rows } = await pool.query( `SELECT uuid, type, tipo_comprobante, metodo_pago, status, regimen_fiscal_emisor, regimen_fiscal_receptor, rfc_emisor, rfc_receptor, nombre_receptor, nombre_emisor, total_mxn, monto_pago_mxn, cfdi_tipo_relacion, fecha_emision, source FROM cfdis WHERE ((${ctx.esEmisor}) OR (${ctx.esReceptor})) AND fecha_emision >= $1::date AND fecha_emision < ($2::date + interval '1 day') ORDER BY fecha_emision, tipo_comprobante, total_mxn DESC`, [FI, FF], ); console.log(`Total CFDIs encontrados: ${rows.length}\n`); const buckets: Record = { ingresosG1: [], ingresosG3: [], ingresosSueldos: [], noIncluye_canceladoOinvalido: [], noIncluye_regimenFuera: [], noIncluye_comoReceptor: [], noIncluye_otroMotivo: [], }; const G1 = ['606', '612', '621', '625', '626']; const G3 = ['601', '603', '607', '608', '610', '611', '614', '615', '620', '622', '623', '624']; for (const r of rows) { const cancel = ['Cancelado', '0'].includes(r.status); const esEmisorRow = String(r.rfc_emisor).toUpperCase() === 'HTS240708LJA'; const regE = r.regimen_fiscal_emisor; const regR = r.regimen_fiscal_receptor; if (cancel) { buckets.noIncluye_canceladoOinvalido.push(r); continue; } if (esEmisorRow) { if (G1.includes(regE)) { if ((r.tipo_comprobante === 'I' && r.metodo_pago === 'PUE') || (r.tipo_comprobante === 'P') || (r.tipo_comprobante === 'E' && r.metodo_pago === 'PUE')) { buckets.ingresosG1.push(r); continue; } } if (G3.includes(regE)) { if ((r.tipo_comprobante === 'I' && ['PUE', 'PPD'].includes(r.metodo_pago)) || (r.tipo_comprobante === 'E' && r.metodo_pago === 'PUE')) { buckets.ingresosG3.push(r); continue; } } if (!G1.includes(regE) && !G3.includes(regE)) { buckets.noIncluye_regimenFuera.push({ ...r, reason: `emisor régimen ${regE} fuera de grupo` }); continue; } buckets.noIncluye_otroMotivo.push({ ...r, reason: `emisor tipo=${r.tipo_comprobante}/${r.metodo_pago} no matchea` }); continue; } // No emisor → receptor if (r.tipo_comprobante === 'N' && r.metodo_pago === 'PUE' && regR === '605') { buckets.ingresosSueldos.push(r); continue; } buckets.noIncluye_comoReceptor.push({ ...r, reason: 'es receptor, no cuenta como ingreso (salvo N/605)' }); } const fmt = (n: any) => Number(n || 0).toFixed(2); for (const [name, list] of Object.entries(buckets)) { if (list.length === 0) continue; console.log(`\n--- ${name} (${list.length}) ---`); for (const r of list) { const fe = r.fecha_emision?.toISOString?.()?.slice(0, 10) || r.fecha_emision; const reason = r.reason ? ` | ${r.reason}` : ''; console.log(` ${fe} ${r.tipo_comprobante}/${r.metodo_pago || '-'} status=${r.status} regE=${r.regimen_fiscal_emisor} regR=${r.regimen_fiscal_receptor} ${r.rfc_emisor}→${r.rfc_receptor} total=${fmt(r.total_mxn)} mp=${fmt(r.monto_pago_mxn)} ${r.uuid.substring(0,8)}${reason}`); } } await prisma.$disconnect(); } main().catch(async e => { console.error(e); await prisma.$disconnect().catch(() => {}); process.exit(1); });