Files
HoruxDespachos/apps/api/scripts/detail-iva-mes.ts
2026-04-27 22:09:36 -06:00

69 lines
3.4 KiB
TypeScript

/** Breakdown: qué CFDIs contribuyen al IVA acreditable vs al gasto. */
import { prisma, tenantDb } from '../src/config/database.js';
import { resolveContribuyenteContext } from '../src/utils/contribuyente-context.js';
const tenantRfc = process.argv[2] || 'DESPACHO_MO3NI6U8_B9VGG';
const contribuyenteId = process.argv[3] || 'd745a915-6a23-4818-944b-a7e1e18e536a';
const yearMonth = process.argv[4] || '2025-12';
async function main() {
const tenant = await prisma.tenant.findFirst({ where: { rfc: tenantRfc }, select: { id: true, databaseName: true } });
if (!tenant) return;
const pool = await tenantDb.getPool(tenant.id, tenant.databaseName);
const ctx = await resolveContribuyenteContext(pool, tenant.id, contribuyenteId);
const [anio, mes] = yearMonth.split('-').map(Number);
const lastDay = new Date(anio, mes, 0).getDate();
const fi = `${yearMonth}-01`;
const ff = `${yearMonth}-${String(lastDay).padStart(2, '0')}`;
const IMP_TRAS = `COALESCE(iva_traslado_mxn,0) + COALESCE(ieps_traslado_mxn,0) + COALESCE(impuestos_locales_trasladado_mxn,0)`;
// I PUE recibidas
const { rows: facturas } = await pool.query(
`SELECT uuid, total_mxn, iva_traslado_mxn, cfdi_tipo_relacion, cfdis_relacionados,
(COALESCE(total_mxn,0) - (${IMP_TRAS})) AS neto_normal
FROM cfdis
WHERE ${ctx.esReceptor} AND tipo_comprobante='I' AND metodo_pago='PUE'
AND status NOT IN ('Cancelado','0')
AND fecha_emision >= $1::date AND fecha_emision < ($2::date + interval '1 day')
ORDER BY total_mxn DESC`,
[fi, ff],
);
console.log(`\n=== I PUE recibidas ${yearMonth} ===`);
console.log(`# | UUID | total | IVA | neto_normal | rel | cfdis_relacionados`);
for (const r of facturas) {
const rel = r.cfdi_tipo_relacion || '-';
const cr = r.cfdis_relacionados ? `${r.cfdis_relacionados.substring(0,36)}` : '';
console.log(` ${r.uuid.substring(0,8)} total=${Number(r.total_mxn).toFixed(2).padStart(12)} IVA=${Number(r.iva_traslado_mxn).toFixed(2).padStart(10)} neto=${Number(r.neto_normal).toFixed(2).padStart(12)} rel=${rel.padEnd(3)}${cr}`);
}
// I PUE recibidas con relación 07 — verificar si el anticipo está en otro mes
const i07 = facturas.filter((r: any) => r.cfdi_tipo_relacion === '07');
if (i07.length > 0) {
console.log(`\nI/07 recibidas en ${yearMonth}: ${i07.length}`);
for (const r of i07) {
const relsUuids = (r.cfdis_relacionados || '').split('|').filter(Boolean).map((u: string) => u.toLowerCase());
if (relsUuids.length > 0) {
const { rows: rels } = await pool.query(
`SELECT uuid, fecha_emision, total_mxn, iva_traslado_mxn
FROM cfdis a
WHERE LOWER(a.uuid) = ANY($1::text[])
AND a.status NOT IN ('Cancelado','0')`,
[relsUuids],
);
console.log(`\n I/07 ${r.uuid.substring(0,8)} total=${Number(r.total_mxn).toFixed(2)} IVA=${Number(r.iva_traslado_mxn).toFixed(2)}`);
for (const a of rels) {
const fecha = a.fecha_emision.toISOString().slice(0,10);
const fuera = fecha.substring(0,7) !== yearMonth ? ' ← FUERA DEL MES' : '';
console.log(` anticipo ${a.uuid.substring(0,8)} fecha=${fecha} total=${Number(a.total_mxn).toFixed(2)} IVA=${Number(a.iva_traslado_mxn).toFixed(2)}${fuera}`);
}
}
}
}
await prisma.$disconnect();
}
main().catch(async e => { console.error(e); await prisma.$disconnect().catch(() => {}); process.exit(1); });