From 441ec20059b38814f4b33926f8246bca89c3a39a Mon Sep 17 00:00:00 2001 From: Horux Dev Date: Mon, 25 May 2026 23:40:17 +0000 Subject: [PATCH] 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 --- .../src/services/despacho-stats.service.ts | 71 ++++++++++++++----- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/apps/api/src/services/despacho-stats.service.ts b/apps/api/src/services/despacho-stats.service.ts index 8fbd5c7..58bc6ee 100644 --- a/apps/api/src/services/despacho-stats.service.ts +++ b/apps/api/src/services/despacho-stats.service.ts @@ -1,5 +1,6 @@ import type { Pool } from 'pg'; import { prisma } from '../config/database.js'; +import { materializarPeriodos } from './tareas.service.js'; export interface ContribuyentesStats { totalContribuyentes: number; @@ -210,30 +211,62 @@ export async function getMisAsignados( const inicioMes = `${_año}-${String(_mes).padStart(2, '0')}-01`; 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( - `WITH obl AS ( - SELECT oc.contribuyente_id, - COUNT(*) FILTER (WHERE op.completada = false AND op.periodo = $1)::int AS pendientes, - 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 - FROM obligaciones_contribuyente oc - LEFT JOIN obligacion_periodos op ON op.obligacion_id = oc.id - WHERE oc.contribuyente_id = ANY($4::uuid[]) AND oc.activa = true - GROUP BY oc.contribuyente_id + `WITH obligaciones_activas AS ( + SELECT id, contribuyente_id FROM obligaciones_contribuyente + WHERE contribuyente_id = ANY($4::uuid[]) AND activa = true + ), + op_actual AS ( + SELECT obligacion_id, completada FROM obligacion_periodos + WHERE obligacion_id IN (SELECT id FROM obligaciones_activas) AND periodo = $1 + ), + 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 ( - SELECT tc.contribuyente_id, - COUNT(*) FILTER (WHERE tp.completada = false AND tp.fecha_limite BETWEEN $2::date AND $3::date)::int AS pendientes, - COUNT(*) FILTER (WHERE tp.completada = false AND tp.fecha_limite < $2::date)::int AS atrasadas, - COUNT(*) FILTER (WHERE tp.completada = true AND tp.fecha_limite BETWEEN $2::date AND $3::date)::int AS completadas - FROM tareas_catalogo tc - LEFT JOIN tarea_periodos tp ON tp.tarea_id = tc.id - WHERE tc.contribuyente_id = ANY($4::uuid[]) AND tc.active = true - GROUP BY tc.contribuyente_id + SELECT ta.contribuyente_id, + COUNT(*) FILTER (WHERE tar_a.completada IS NULL OR tar_a.completada = false)::int AS pendientes, + COALESCE(SUM(tar_atr.atrasadas), 0)::int AS atrasadas, + COUNT(*) FILTER (WHERE tar_a.completada = true)::int AS completadas + FROM tareas_activas ta + LEFT JOIN tar_actual tar_a ON tar_a.tarea_id = ta.id + LEFT JOIN tar_atrasadas tar_atr ON tar_atr.tarea_id = ta.id + GROUP BY ta.contribuyente_id ) SELECT - 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 + 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 FROM obl FULL OUTER JOIN tar ON tar.contribuyente_id = obl.contribuyente_id`, [periodoMes, inicioMes, finMes, ids],