Update: nueva version Horux Despachos

This commit is contained in:
consultoria-as
2026-04-27 22:09:36 -06:00
commit 6b36db1403
614 changed files with 125926 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
/**
* Detecta complementos P cuya ieps_traslado_pago_mxn parece inflada
* respecto al monto pagado y respecto a la factura referenciada.
*
* Heurísticas:
* 1. IEPS del P > monto_pago × 1.6 (tasa máxima teórica SAT para bebidas
* con alto contenido alcohólico; cualquier cosa arriba es sospechoso).
* 2. IEPS del P > IEPS de la factura original a la que se refiere
* (imposible — un pago parcial no puede transferir más IEPS que el total).
* 3. Ratio IEPS / monto_pago vs IEPS_original / total_original, donde la
* proporción del P excede la del original por >5pp (señal de error
* del proveedor).
*/
import { prisma, tenantDb } from '../src/config/database.js';
async function main() {
const tenants = await prisma.tenant.findMany({
select: { id: true, rfc: true, databaseName: true },
});
for (const t of tenants) {
let pool;
try {
pool = await tenantDb.getPool(t.id, t.databaseName);
} catch {
continue;
}
console.log(`\n=== Tenant ${t.rfc} (${t.databaseName}) ===`);
// Heurística 1: IEPS > 160% del monto
const { rows: h1 } = await pool.query(`
SELECT uuid, rfc_emisor, rfc_receptor, monto_pago_mxn, ieps_traslado_pago_mxn,
(ieps_traslado_pago_mxn / NULLIF(monto_pago_mxn, 0))::numeric(10,4) AS ratio
FROM cfdis
WHERE tipo_comprobante = 'P'
AND status NOT IN ('Cancelado', '0')
AND COALESCE(ieps_traslado_pago_mxn, 0) > 0
AND COALESCE(monto_pago_mxn, 0) > 0
AND ieps_traslado_pago_mxn > monto_pago_mxn * 1.6
ORDER BY ieps_traslado_pago_mxn DESC
LIMIT 10
`);
console.log(`\n-- H1: IEPS > monto_pago × 1.6 (${h1.length}) --`);
for (const r of h1) {
console.log(` ${r.uuid.substring(0, 8)} ${r.rfc_emisor}${r.rfc_receptor} pago=${Number(r.monto_pago_mxn).toFixed(2)} IEPS=${Number(r.ieps_traslado_pago_mxn).toFixed(2)} ratio=${r.ratio}`);
}
// Heurística 2: IEPS del P > IEPS de la factura referenciada (imposible)
// uuid_relacionado es pipe-separated; normalizar
const { rows: h2 } = await pool.query(`
SELECT p.uuid AS p_uuid, p.rfc_emisor, p.monto_pago_mxn, p.ieps_traslado_pago_mxn,
i.uuid AS i_uuid, i.total_mxn AS i_total, i.ieps_traslado_mxn AS i_ieps
FROM cfdis p
JOIN cfdis i
ON LOWER(i.uuid) = ANY(string_to_array(LOWER(COALESCE(p.uuid_relacionado, '')), '|'))
AND i.status NOT IN ('Cancelado', '0')
WHERE p.tipo_comprobante = 'P'
AND p.status NOT IN ('Cancelado', '0')
AND COALESCE(p.ieps_traslado_pago_mxn, 0) > 0
AND COALESCE(p.ieps_traslado_pago_mxn, 0) > COALESCE(i.ieps_traslado_mxn, 0)
ORDER BY p.ieps_traslado_pago_mxn DESC
LIMIT 10
`);
console.log(`\n-- H2: IEPS del P > IEPS de la factura referenciada (${h2.length}) --`);
for (const r of h2) {
const ratio = r.i_ieps > 0 ? Number(r.ieps_traslado_pago_mxn) / Number(r.i_ieps) : 0;
console.log(` P=${r.p_uuid.substring(0, 8)} IEPS_P=${Number(r.ieps_traslado_pago_mxn).toFixed(2)} I=${r.i_uuid.substring(0, 8)} IEPS_I=${Number(r.i_ieps || 0).toFixed(2)} ratio=${ratio.toFixed(2)}x`);
}
// Heurística 3: ratio IEPS/pago del P muy distinto del ratio IEPS/total del I
const { rows: h3 } = await pool.query(`
SELECT p.uuid AS p_uuid, p.monto_pago_mxn, p.ieps_traslado_pago_mxn,
i.uuid AS i_uuid, i.total_mxn AS i_total, i.ieps_traslado_mxn AS i_ieps,
(p.ieps_traslado_pago_mxn / NULLIF(p.monto_pago_mxn, 0))::numeric(6,4) AS ratio_p,
(i.ieps_traslado_mxn / NULLIF(i.total_mxn, 0))::numeric(6,4) AS ratio_i
FROM cfdis p
JOIN cfdis i
ON LOWER(i.uuid) = ANY(string_to_array(LOWER(COALESCE(p.uuid_relacionado, '')), '|'))
AND i.status NOT IN ('Cancelado', '0')
WHERE p.tipo_comprobante = 'P'
AND p.status NOT IN ('Cancelado', '0')
AND COALESCE(p.ieps_traslado_pago_mxn, 0) > 0
AND COALESCE(i.ieps_traslado_mxn, 0) > 0
AND COALESCE(p.monto_pago_mxn, 0) > 0
AND COALESCE(i.total_mxn, 0) > 0
AND ABS(
(p.ieps_traslado_pago_mxn / p.monto_pago_mxn)
- (i.ieps_traslado_mxn / i.total_mxn)
) > 0.05
ORDER BY p.ieps_traslado_pago_mxn DESC
LIMIT 10
`);
console.log(`\n-- H3: ratio_P ratio_I > 5pp (${h3.length}) --`);
for (const r of h3) {
console.log(` P=${r.p_uuid.substring(0, 8)} ratio_P=${r.ratio_p} I=${r.i_uuid.substring(0, 8)} ratio_I=${r.ratio_i} delta=${(Number(r.ratio_p) - Number(r.ratio_i)).toFixed(4)}`);
}
// Resumen: total de P con IEPS > 0
const { rows: [summary] } = await pool.query(`
SELECT COUNT(*) FILTER (WHERE COALESCE(ieps_traslado_pago_mxn, 0) > 0)::int AS p_con_ieps,
COUNT(*) FILTER (WHERE tipo_comprobante = 'P')::int AS p_total
FROM cfdis
WHERE status NOT IN ('Cancelado', '0')
`);
console.log(`\nResumen: ${summary.p_con_ieps} P con IEPS > 0 (de ${summary.p_total} P totales)`);
}
await prisma.$disconnect();
}
main().catch(async e => { console.error(e); await prisma.$disconnect().catch(() => {}); process.exit(1); });