Contexto: simplificar la query de Cargo/Abono (v0.3 propia)
Conexión
connection_200_trivasadb3.py en la raíz del repo (sys.path.append("..") desde
layout_gastos/). Expone engine (SQLAlchemy) y q(sql) (helper que regresa DataFrame).
Servidor: TRIVASADB3 (.200), empresa 0001.
Estado actual: 99.7% de reconciliación (1421/1425 folios, enero 2026)
Universo: folios de Gasto_Registro en enero 2026, empresa 0001, excluyendo orígenes
GASTO_REGISTRO_NOMINA y CONSUMO_INTERNO (no llevan póliza por diseño). Base de
comparación: v01_baseline_enero2026_sin_nomina_consumo.csv (columna IMPORTE =
subtotal sin IVA, ya con conversión de moneda aplicada).
Query que llega a 99.7% (agregada a nivel folio, sin desglose por documento):
WITH grupo_arbol AS (
SELECT Gcc_Cve_Grupo_Cuenta_Contable, Gcc_Padre, Gcc_Cve_Grupo_Cuenta_Contable AS raiz
FROM Grupo_Cuenta_Contable
WHERE Gcc_Padre = '0' OR Gcc_Padre = '' OR Gcc_Padre IS NULL
UNION ALL
SELECT g.Gcc_Cve_Grupo_Cuenta_Contable, g.Gcc_Padre, t.raiz
FROM Grupo_Cuenta_Contable g
JOIN grupo_arbol t ON g.Gcc_Padre = t.Gcc_Cve_Grupo_Cuenta_Contable
)
SELECT
gr.Sc_Cve_Sucursal + '-' + RIGHT('0000000' + CONVERT(varchar, gr.Gr_Folio), 7) AS FOLIO,
SUM(CASE WHEN pd.Pd_Tipo = 1 THEN pd.Pd_Importe ELSE 0 END) AS CARGO,
SUM(CASE
WHEN pd.Pd_Tipo = 2 AND ga.raiz = 'F' THEN pd.Pd_Importe
WHEN pd.Pd_Tipo = 2 AND ga.raiz IS NULL AND LEFT(pd.Cc_Cve_Cuenta_Contable, 1) = '6' THEN pd.Pd_Importe
WHEN pd.Pd_Tipo = 2 AND ga.raiz IS NULL AND LOWER(cc.Cc_Descripcion) LIKE '%gastos a cuenta de costo estandar%' THEN pd.Pd_Importe
ELSE 0
END) AS ABONO
FROM Gasto_Registro gr
JOIN Sucursal s ON gr.Sc_Cve_Sucursal = s.Sc_Cve_Sucursal
JOIN Poliza_Control plc ON plc.Pc_Tabla = 'GASTO_REGISTRO' AND plc.Pc_Documento = gr.Gr_Folio
JOIN Poliza pl ON pl.Pl_Folio = plc.Pl_Folio
JOIN Poliza_Detalle pd ON pd.Pl_Folio = plc.Pl_Folio AND pd.Pd_Referencia = gr.Gr_Folio
LEFT JOIN Cuenta_Contable cc ON cc.Cc_Cve_Cuenta_Contable = pd.Cc_Cve_Cuenta_Contable
LEFT JOIN grupo_arbol ga ON ga.Gcc_Cve_Grupo_Cuenta_Contable = cc.Cc_Grupo_Cuenta_Contable
WHERE s.Em_Cve_Empresa = '0001'
AND gr.Gr_Fecha >= '2026-01-01' AND gr.Gr_Fecha < '2026-02-01'
AND gr.Es_Cve_Estado <> 'CA'
AND pl.Es_Cve_Estado <> 'CA'
AND ISNULL(gr.Gr_Tabla, '') NOT IN ('GASTO_REGISTRO_NOMINA', 'CONSUMO_INTERNO')
GROUP BY gr.Sc_Cve_Sucursal, gr.Gr_FolioComparación: (CARGO - ABONO) - IMPORTE debe ser < $1 de diferencia.
Bugs ya resueltos (NO reintroducir)
Gr_Foliocolisiona entre sucursales → siempre filtrar/joinear conSc_Cve_Sucursalcuando aplique (aquí no hace falta explícito porque el join aPoliza_Controlva fila por fila desdegrya acotado por fecha+empresa).Pd_Referenciacolisiona entre AÑOS (es solo el número de folio, sin año/sucursal — 3,179 referencias distintas colisionan entre 2020-2026 en toda la tabla). Por eso NO se puede hacer unGROUP BY Pd_Referenciaglobal sobrePoliza_Detallesin pasar antes porPoliza_Control(Pc_Documento = gr.Gr_Folio) fila por fila desdegr(que ya trae el filtro de fecha). Simplificar el join sin este cuidado revive el bug.- Comparar contra el TOTAL con IVA en vez del SUBTOTAL:
Poliza_Detallenunca incluye impuestos (las líneas de IVA no tienenPd_Referenciapoblado, se agregan a nivel póliza) — comparar contraGrd_Precio_Neto_Importeen vez deGrd_Precio_Descontado_Importerompe la reconciliación estructuralmente. - Filtro de empresa vía
Sucursal.Em_Cve_Empresa = '0001'—Gasto_Registrono trae empresa directo, hay sucursales de otras empresas (0003,0071;0004,0076) mezcladas en la misma base.
4 folios que NO reconcilian (0.3%) — causa conocida, no perseguir más
0005-0181359,0001-0034998,0001-0034999: reversiones contables —Importenegativo, póliza trae Cargo≈Abono (partida doble de una reversión). Regla conocida: siImporte_folio <= -$1, usar solo el Abono (poner Cargo en 0).0005-0177136: origenGASTO_RECLASIFICACION— no debería usar join a póliza en absoluto; su Cargo/Abono real vive enGasto_Registro_Documento(pares espejo Cargo positivo / Abono negativo, mismo folio, misma cuenta víaTipo_Gasto).
Implementación de referencia (NO copiar tal cual — es mucho más compleja porque
también resuelve atribución por documento vía Gasto_Registro_Control, que aquí
todavía no se necesita)
~/trivasa-bi-dev/layout-gastos-streamlit-claude/scripts/layout_gastos_v0_4_2.py — ver
POLIZA_SQL para la query de referencia completa (con las mismas 4 líneas de fallback
de cuenta) y armar()/reglas de reversión al final de la función para la lógica de
Importe <= -$1.
Objetivo de esta tarea
Simplificar la query de arriba (menos condicionantes en el CASE/WHERE, menos joins
si es posible). Piso aceptable: 80% de reconciliación contra
v01_baseline_enero2026_sin_nomina_consumo.csv — puedes bajar hasta ahí si eso permite
simplificar bastante, no hace falta quedarte cerca de 99%. Está bien perder precisión en
casos raros/documentados (los 4 de arriba), pero no reintroducir los 4 bugs de la sección
anterior. Iterar y medir el % de reconciliación en cada intento antes de aceptar un
cambio; detente en el punto donde menos condicionantes todavía te da >=80%.