fix(despacho-stats): contar obligaciones y tareas pendientes correctamente

- Obligaciones: las obligaciones activas sin registro en obligacion_periodos
  para el periodo actual ahora se cuentan como pendientes (antes daban 0)
- Tareas: se materializan los periodos antes de contar para que las tareas
  sin registro previo aparezcan como pendientes
- Usa CTEs separadas para obligaciones y tareas evitando producto cartesiano
This commit is contained in:
Horux Dev
2026-05-25 23:40:17 +00:00
parent 929aeec641
commit 441ec20059

View File

@@ -1,5 +1,6 @@
import type { Pool } from 'pg'; import type { Pool } from 'pg';
import { prisma } from '../config/database.js'; import { prisma } from '../config/database.js';
import { materializarPeriodos } from './tareas.service.js';
export interface ContribuyentesStats { export interface ContribuyentesStats {
totalContribuyentes: number; totalContribuyentes: number;
@@ -210,30 +211,62 @@ export async function getMisAsignados(
const inicioMes = `${_año}-${String(_mes).padStart(2, '0')}-01`; const inicioMes = `${_año}-${String(_mes).padStart(2, '0')}-01`;
const finMes = new Date(_año, _mes, 0).toISOString().split('T')[0]; const finMes = new Date(_año, _mes, 0).toISOString().split('T')[0];
// Materializar periodos de tareas antes de contar (evita que tareas sin
// registro en tarea_periodos aparezcan como 0).
await Promise.all(ids.map(id => materializarPeriodos(pool, id).catch(() => {})));
const { rows: stats } = await pool.query( const { rows: stats } = await pool.query(
`WITH obl AS ( `WITH obligaciones_activas AS (
SELECT oc.contribuyente_id, SELECT id, contribuyente_id FROM obligaciones_contribuyente
COUNT(*) FILTER (WHERE op.completada = false AND op.periodo = $1)::int AS pendientes, WHERE contribuyente_id = ANY($4::uuid[]) AND activa = true
COUNT(*) FILTER (WHERE op.completada = false AND op.periodo < $1)::int AS atrasadas, ),
COUNT(*) FILTER (WHERE op.completada = true AND op.periodo = $1)::int AS completadas op_actual AS (
FROM obligaciones_contribuyente oc SELECT obligacion_id, completada FROM obligacion_periodos
LEFT JOIN obligacion_periodos op ON op.obligacion_id = oc.id WHERE obligacion_id IN (SELECT id FROM obligaciones_activas) AND periodo = $1
WHERE oc.contribuyente_id = ANY($4::uuid[]) AND oc.activa = true ),
GROUP BY oc.contribuyente_id op_atrasadas AS (
SELECT obligacion_id, COUNT(*) as atrasadas FROM obligacion_periodos
WHERE obligacion_id IN (SELECT id FROM obligaciones_activas) AND periodo < $1 AND completada = false
GROUP BY obligacion_id
),
obl AS (
SELECT oa.contribuyente_id,
COUNT(*) FILTER (WHERE op_a.completada IS NULL OR op_a.completada = false)::int AS pendientes,
COALESCE(SUM(op_atr.atrasadas), 0)::int AS atrasadas,
COUNT(*) FILTER (WHERE op_a.completada = true)::int AS completadas
FROM obligaciones_activas oa
LEFT JOIN op_actual op_a ON op_a.obligacion_id = oa.id
LEFT JOIN op_atrasadas op_atr ON op_atr.obligacion_id = oa.id
GROUP BY oa.contribuyente_id
),
tareas_activas AS (
SELECT id, contribuyente_id FROM tareas_catalogo
WHERE contribuyente_id = ANY($4::uuid[]) AND active = true
),
tar_actual AS (
SELECT tarea_id, completada FROM tarea_periodos
WHERE tarea_id IN (SELECT id FROM tareas_activas)
AND fecha_limite BETWEEN $2::date AND $3::date
),
tar_atrasadas AS (
SELECT tarea_id, COUNT(*) as atrasadas FROM tarea_periodos
WHERE tarea_id IN (SELECT id FROM tareas_activas)
AND fecha_limite < $2::date AND completada = false
GROUP BY tarea_id
), ),
tar AS ( tar AS (
SELECT tc.contribuyente_id, SELECT ta.contribuyente_id,
COUNT(*) FILTER (WHERE tp.completada = false AND tp.fecha_limite BETWEEN $2::date AND $3::date)::int AS pendientes, COUNT(*) FILTER (WHERE tar_a.completada IS NULL OR tar_a.completada = false)::int AS pendientes,
COUNT(*) FILTER (WHERE tp.completada = false AND tp.fecha_limite < $2::date)::int AS atrasadas, COALESCE(SUM(tar_atr.atrasadas), 0)::int AS atrasadas,
COUNT(*) FILTER (WHERE tp.completada = true AND tp.fecha_limite BETWEEN $2::date AND $3::date)::int AS completadas COUNT(*) FILTER (WHERE tar_a.completada = true)::int AS completadas
FROM tareas_catalogo tc FROM tareas_activas ta
LEFT JOIN tarea_periodos tp ON tp.tarea_id = tc.id LEFT JOIN tar_actual tar_a ON tar_a.tarea_id = ta.id
WHERE tc.contribuyente_id = ANY($4::uuid[]) AND tc.active = true LEFT JOIN tar_atrasadas tar_atr ON tar_atr.tarea_id = ta.id
GROUP BY tc.contribuyente_id GROUP BY ta.contribuyente_id
) )
SELECT SELECT
obl.contribuyente_id AS obl_id, obl.pendientes AS obl_pen, obl.atrasadas AS obl_atr, obl.completadas AS obl_com, obl.contribuyente_id AS obl_id, obl.pendientes AS obl_pen, obl.atrasadas AS obl_atr, obl.completadas AS obl_com,
tar.contribuyente_id AS tar_id, tar.pendientes AS tar_pen, tar.atrasadas AS tar_atr, tar.completadas AS tar_com tar.contribuyente_id AS tar_id, tar.pendientes AS tar_pen, tar.atrasadas AS tar_atr, tar.completadas AS tar_com
FROM obl FROM obl
FULL OUTER JOIN tar ON tar.contribuyente_id = obl.contribuyente_id`, FULL OUTER JOIN tar ON tar.contribuyente_id = obl.contribuyente_id`,
[periodoMes, inicioMes, finMes, ids], [periodoMes, inicioMes, finMes, ids],