Update: nueva version Horux Despachos
This commit is contained in:
67
apps/api/scripts/breakdown-ingresos.ts
Normal file
67
apps/api/scripts/breakdown-ingresos.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Breakdown ingresos por grupo + filas que el drill-down mostraría,
|
||||
* para un contribuyente + mes. Identifica discrepancias entre el
|
||||
* dashboard y el drill.
|
||||
*/
|
||||
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] || 'b3761db6-0b8d-4251-8078-4ddc31e9c75b';
|
||||
const yearMonth = process.argv[4] || '2025-05';
|
||||
|
||||
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 [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 ctx = await resolveContribuyenteContext(pool, tenant.id, contribuyenteId);
|
||||
console.log(`\n=== ${yearMonth} ${contribuyenteId} RFC=${ctx.rfc} ===\n`);
|
||||
console.log(`esEmisor: ${ctx.esEmisor}`);
|
||||
console.log(`esReceptor: ${ctx.esReceptor}\n`);
|
||||
|
||||
// Todos los CFDIs donde el contribuyente es emisor en el mes (ingresos potenciales)
|
||||
const { rows: emitidos } = await pool.query(
|
||||
`SELECT uuid, fecha_emision, tipo_comprobante, metodo_pago,
|
||||
cfdi_tipo_relacion, regimen_fiscal_emisor, regimen_fiscal_receptor,
|
||||
total_mxn, monto_pago_mxn
|
||||
FROM cfdis
|
||||
WHERE ${ctx.esEmisor}
|
||||
AND status NOT IN ('Cancelado', '0')
|
||||
AND ((tipo_comprobante='P' AND fecha_pago_p >= $1::date AND fecha_pago_p < ($2::date + interval '1 day'))
|
||||
OR (tipo_comprobante<>'P' AND fecha_emision >= $1::date AND fecha_emision < ($2::date + interval '1 day')))
|
||||
ORDER BY fecha_emision, uuid`,
|
||||
[fi, ff],
|
||||
);
|
||||
|
||||
console.log(`EMITIDOS por el contribuyente en el mes: ${emitidos.length}`);
|
||||
let sumaTotal = 0, sumaPagos = 0;
|
||||
const porRegimen: Record<string, { n: number; total: number; pago: number; types: Record<string, number> }> = {};
|
||||
for (const r of emitidos) {
|
||||
const reg = r.regimen_fiscal_emisor || 'NULL';
|
||||
const tcKey = `${r.tipo_comprobante}${r.metodo_pago ? '/' + r.metodo_pago : ''}${r.cfdi_tipo_relacion ? '/rel=' + r.cfdi_tipo_relacion : ''}`;
|
||||
if (!porRegimen[reg]) porRegimen[reg] = { n: 0, total: 0, pago: 0, types: {} };
|
||||
porRegimen[reg].n++;
|
||||
porRegimen[reg].total += Number(r.total_mxn || 0);
|
||||
porRegimen[reg].pago += Number(r.monto_pago_mxn || 0);
|
||||
porRegimen[reg].types[tcKey] = (porRegimen[reg].types[tcKey] || 0) + 1;
|
||||
sumaTotal += Number(r.total_mxn || 0);
|
||||
sumaPagos += Number(r.monto_pago_mxn || 0);
|
||||
}
|
||||
|
||||
console.log(`Suma total_mxn: ${sumaTotal.toFixed(2)} | Suma monto_pago_mxn: ${sumaPagos.toFixed(2)}\n`);
|
||||
for (const [reg, v] of Object.entries(porRegimen)) {
|
||||
console.log(` Régimen ${reg}: n=${v.n} total=${v.total.toFixed(2)} pago=${v.pago.toFixed(2)}`);
|
||||
for (const [tc, n] of Object.entries(v.types)) {
|
||||
console.log(` ${tc}: ${n}`);
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
main().catch(async e => { console.error(e); await prisma.$disconnect().catch(() => {}); process.exit(1); });
|
||||
Reference in New Issue
Block a user