69 lines
3.4 KiB
TypeScript
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); });
|