Update: nueva version Horux Despachos
This commit is contained in:
97
apps/api/scripts/validate-dashboard-impuestos.ts
Normal file
97
apps/api/scripts/validate-dashboard-impuestos.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Valida la alineación dashboard ≡ impuestos tras refactor de getResumenIva.
|
||||
* Para 5 muestras aleatorias por contribuyente, compara:
|
||||
* dashboard.calcularIvaBalancePorRegimen().total vs
|
||||
* impuestos.getResumenIva().resultado
|
||||
*
|
||||
* Deben coincidir céntimo por céntimo (Resultado = Trasladado − Acreditable − Retenido,
|
||||
* usando los mismos 6 buckets del dashboard).
|
||||
*
|
||||
* Uso:
|
||||
* pnpm --filter @horux/api exec tsx scripts/validate-dashboard-impuestos.ts
|
||||
* METRICAS_BYPASS_CACHE=1 pnpm --filter @horux/api exec tsx scripts/validate-dashboard-impuestos.ts
|
||||
*/
|
||||
import { prisma, tenantDb } from '../src/config/database.js';
|
||||
import * as dashboard from '../src/services/dashboard.service.js';
|
||||
import { getResumenIva } from '../src/services/impuestos.service.js';
|
||||
|
||||
const TOL = 0.01;
|
||||
|
||||
function cmp(a: number, b: number): boolean { return Math.abs(a - b) <= TOL; }
|
||||
function fmt(n: number): string {
|
||||
return n.toLocaleString('es-MX', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('=== Validación dashboard.balance ≡ impuestos.resultado ===');
|
||||
console.log(` BYPASS_CACHE=${process.env.METRICAS_BYPASS_CACHE === '1' ? 'YES' : 'no'}\n`);
|
||||
|
||||
const tenants = await prisma.tenant.findMany({
|
||||
where: { active: true },
|
||||
select: { id: true, rfc: true, databaseName: true },
|
||||
});
|
||||
|
||||
let total = 0;
|
||||
let pass = 0;
|
||||
let fail = 0;
|
||||
|
||||
for (const t of tenants) {
|
||||
const pool = await tenantDb.getPool(t.id, t.databaseName);
|
||||
const { rows: contribs } = await pool.query<{ entidad_id: string; nombre: string }>(
|
||||
`SELECT c.entidad_id, eg.nombre
|
||||
FROM contribuyentes c
|
||||
JOIN entidades_gestionadas eg ON eg.id = c.entidad_id
|
||||
WHERE EXISTS (SELECT 1 FROM metricas_mensuales m WHERE m.contribuyente_id = c.entidad_id)`,
|
||||
);
|
||||
if (contribs.length === 0) continue;
|
||||
console.log(`[${t.rfc}] ${contribs.length} contribuyentes`);
|
||||
|
||||
for (const c of contribs) {
|
||||
const { rows: samples } = await pool.query<{ anio: number; mes: number }>(
|
||||
`SELECT anio, mes FROM (
|
||||
SELECT DISTINCT anio, mes FROM metricas_mensuales WHERE contribuyente_id = $1
|
||||
) t
|
||||
ORDER BY random() LIMIT 5`,
|
||||
[c.entidad_id],
|
||||
);
|
||||
console.log(` ${c.nombre}:`);
|
||||
|
||||
for (const s of samples) {
|
||||
total++;
|
||||
const fi = `${s.anio}-${String(s.mes).padStart(2, '0')}-01`;
|
||||
const lastDay = new Date(s.anio, s.mes, 0).getDate();
|
||||
const ff = `${s.anio}-${String(s.mes).padStart(2, '0')}-${String(lastDay).padStart(2, '0')}`;
|
||||
|
||||
const bal = await dashboard.calcularIvaBalancePorRegimen(
|
||||
pool, t.id, fi, ff, [], undefined, false, c.entidad_id,
|
||||
);
|
||||
const resumen = await getResumenIva(pool, fi, ff, t.id, false, c.entidad_id);
|
||||
|
||||
const mesLabel = `${s.anio}-${String(s.mes).padStart(2, '0')}`;
|
||||
if (cmp(bal.total, resumen.resultado)) {
|
||||
pass++;
|
||||
console.log(` ✓ ${mesLabel} balance=$${fmt(bal.total)} resultado=$${fmt(resumen.resultado)}`);
|
||||
} else {
|
||||
fail++;
|
||||
const delta = bal.total - resumen.resultado;
|
||||
console.log(` ✗ ${mesLabel} balance=$${fmt(bal.total)} resultado=$${fmt(resumen.resultado)} Δ=$${fmt(delta)}`);
|
||||
console.log(` T=$${fmt(resumen.trasladado)} A=$${fmt(resumen.acreditable)} R=$${fmt(resumen.retenido)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n=== Resumen ===`);
|
||||
console.log(` Muestras: ${total}`);
|
||||
console.log(` PASS: ${pass}`);
|
||||
console.log(` FAIL: ${fail}`);
|
||||
|
||||
await prisma.$disconnect();
|
||||
process.exit(fail > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
main().catch(async (err) => {
|
||||
console.error('Fatal:', err);
|
||||
await prisma.$disconnect().catch(() => {});
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user