Layout de Gastos — segunda exploración (2026-08-04)

Esta página documenta una segunda exploración, independiente, del mismo requerimiento de Layout de Gastos (Ismael Valdez, Contabilidad — auditoría Bates y Asociados). No es una continuación ni un reemplazo de la exploración original — es una segunda pasada, en otro repo, sobre el mismo problema:

Exploración 1Exploración 2 (esta página)
Cuándo~junio-julio 20262026-08-04 (sesión de un día)
Repo/carpetatrivasa-bi-dev/layout-gastos-streamlit-claude/docs/ (00 a 18)trivasa-bi-dev/layout_gastos/docs/
Documentada enindex.md, Modelo de datos, Atribución de Cargo/Abono, Versionesesta página
MétodoIteración incremental con app Streamlit, corrigiendo un problema a la vez hasta v0.5.1Re-validación pieza por pieza (Cargo/Abono, UUID, CXP) contra datos reales, consultando la exploración 1 solo como referencia — sin reusar su código
Resultadov1.1, +0.89% de brecha de reconciliación, cubre prácticamente todo el layout de una sola vez (docs/03_hito_v1.md)Cargo/Abono y UUID cerrados por separado con % propios (ver tabla abajo); CXP e Impuestos cerrados con reconciliación 100%/99.9%, incluido un caso especial (CONTROL_COMBUSTIBLE) que la exploración 1 no cubrió; queda abierta la granularidad de Cargo/Abono como riesgo bloqueante para la query maestra que una todas las piezas (ver más abajo)

⚠️ Los números de versión colisionan entre las dos exploraciones. Ambas usan etiquetas como v0.2 o v0.3, pero significan cosas distintas en cada una (la v0.2 de la exploración 1 es Python con emparejamiento por valor; la v0.2 de esta exploración es una query SQL de Cargo/Abono a nivel folio). Al citar una versión, siempre hay que decir de cuál exploración viene — nunca “v0.2” a secas.

Qué se validó en esta exploración (2026-08-04)

Todo corre contra TRIVASADB3 (.200), empresa 0001, en su mayoría sobre enero-junio 2026. El detalle completo de cada pieza vive en el .md técnico correspondiente, copiado tal cual en sources/trivasa/layout-gastos/ (ver el índice de esa carpeta) — esta tabla es el resumen, no la fuente de verdad.

Pieza (etiqueta de esta exploración)Qué resuelveResultadoDoc técnico
v0.2Cargo/Abono a nivel folio, 3 queries según el caso (general / GASTO_RECLASIFICACION / reversión)99.96% (9,158/9,162), enero-junio 2026 contra .207sources/trivasa/layout-gastos/v02_cierre.md
v0.3 (experimental, no producción)Simplificar la query de v0.2 (menos joins/CASE) — encargo con piso de 80% aceptado a cambio de menos complejidad99.6% con la variante ganadora (sin CTE recursivo ni join a Cuenta_Contable); no reemplazó a v0.2/v1.0 en producciónsources/trivasa/layout-gastos/contexto_v03_simplificar.md, v03_simplificacion_resultados.md
v1.0 (la que consume FlexMonster)Detalle por cuenta contable y centro de costo — 1 fila por (folio, cuenta, centro de costo), sin decidir qué “cuenta” como gasto real99.96% (9,158/9,162), mismo universo que v0.2. Granularidad no re-verificada en esta sesión — ver riesgo abierto más abajosources/trivasa/layout-gastos/v1_0_cierre.md
v2.1UUID de CFDI por folio (Comprobante_Digital)91.9% con 1 comprobante, 6.8% sin XML esperado (por diseño: reclasificaciones/reversiones), 1.2% “Varios” realsources/trivasa/layout-gastos/v2_1_cierre.md
v3.0 — CXP completo (general + combustible unificados)CXP (Cuenta por Pagar), caso general y CONTROL_COMBUSTIBLE en una sola query (UNION ALL + columna GRANULARIDAD_CXP explícita para distinguir la semántica de cada rama — ver aprendizajes abajo). Reemplaza a v2.2 de esta misma exploración, que solo cubría el caso general1 fila/folio; 100% enero 2026, 99.9% enero-junio 2026sources/trivasa/layout-gastos/v3_0_cxp_completo_cierre.md, control_combustible_hallazgo.md
v5.0 — Impuestos (Subtotal 0/16/Exenta + 13 retenciones)Bloque de tasas/retenciones de Gasto_Registro_Impuesto + Impuesto, con CTE de 2 niveles (documento → folio)1 fila/folio; 100% enero 2026sources/trivasa/layout-gastos/v5_0_impuestos_cierre.md

Hallazgos que la exploración 1 no tenía documentados

Encontrados al re-validar con datos propios, no reusando el código de la exploración 1:

  • Join de folio sin CONVERT: Gr_Folio ya es el string completo 'SS-FFFFFFF' (sucursal + folio), no un número que haya que reconstruir — el join contra Poliza_Control.Pc_Documento / Poliza_Detalle.Pd_Referencia es comparación de texto directa. Confirmado contra POLIZA_REDIRDOC.asp real de MPRO.
  • Gasto_Registro.Gr_Genera_Cxp = 'NO' como filtro/pista de negocio, no como ausencia de obligación de pago: marca folios que MPRO no liga 1-a-1 a una CXP individual (combustible consolidado semanal, algunos casos de reclasificación) — no significa que el folio no tenga cuenta por pagar real. Ver sources/trivasa/layout-gastos/control_combustible_hallazgo.md.
  • Comparar CXP en moneda original, sin convertir: Gasto_Registro_Documento y Cuenta_X_Pagar guardan el importe en la misma moneda del documento (Mn_Cve_Moneda) — comparar Grd_Precio_Neto_Importe contra Cxp_Precio_Neto_Importe directo, sin multiplicar por tipo de cambio, es lo que calza exacto (verificado con un folio real en USD). Cxp_Tipo_Cambio solo sirve para mostrar el equivalente en MXN, no para validar.
  • Mecanismo real de CXP para CONTROL_COMBUSTIBLE: no sigue el link estándar Cxp_Tabla = 'Gasto_Registro:' + Gr_Folio — MPRO consolida varios folios en una sola CXP semanal por proveedor, capturada con Cxp_Tabla = 'Cuenta_X_Pagar' (auto-referenciada) y ligada por texto libre (Cxp_Referencia = Grd_Referencia, mismo proveedor). Puede haber más de una fila de CXP por referencia (~13% de los casos) — hay que agregar con SUM, nunca tomar una sola fila. Detalle completo, con la corrección de fan-out del 2026-08-04, en sources/trivasa/layout-gastos/control_combustible_hallazgo.md.
  • No hay configuración de retención por proveedor ni por tipo de gasto — investigado y descartado con datos reales: Pv_Grupo_Impuesto es demasiado genérico y Tg_Tipo tampoco correlaciona limpio con qué retenciones aplican. La retención se decide manualmente al capturar cada renglón de Gasto_Registro_Impuesto, no hay tabla de reglas que derivarla automáticamente.
  • La identidad “Subtotal 0% + 16% + Exenta = subtotal del documento” es falsa para pagos financieros con retención de ISR (intereses, dividendos, arrendamiento financiero) — el IVA excluye el componente inflacionario por diseño fiscal mexicano, no por dato faltante. La validación correcta a nivel folio es SUM(Gri_Importe) = Grd_Impuesto_Importe, no la suma de subtotales por tasa.
  • Un folio puede tener varios Grd_ID (Z_Grd_Multiple = 'SI') con montos independientes entre sí — cualquier query que agregue directo a nivel folio, sin pasar primero por una agregación a nivel documento, produce fan-out al cruzar contra la baseline de folios. El patrón ya causó bugs de este tipo dos veces (combustible, impuestos); la mitigación aplicada en v5.0 y adoptada como práctica general es un assert de unicidad de folio inmediatamente después de leer cualquier resultado de SQL en los scripts de validación.
  • UNION ALL sobre JOIN condicional con CASE en el ON, cuando dos poblaciones tienen lógica de match distinta (CXP general por documento vs. combustible por referencia consolidada) — mezclar ambas en un solo JOIN con CASE fue la causa raíz del bug de fan-out original de CXP; separarlas en dos SELECT unidos con UNION ALL lo elimina de raíz porque cada rama solo lleva su propia lógica de match.
  • Columnas con el mismo nombre pero semántica distinta entre ramas de un UNION son una trampa para cualquier consumidor externo (FlexMonster/Excel no distinguen el origen de la fila) — se resuelve con una columna explícita de metadata (GRANULARIDAD_CXP: 'documento' vs. 'referencia_consolidada' en v3.0) en vez de solo dejarlo como comentario en el SQL.

Riesgo abierto: granularidad de Cargo/Abono para la query maestra

v03_detalle_cuenta_centro_costo.sql (Cargo/Abono por cuenta contable y centro de costo, v1.0 de esta exploración) no ha sido re-verificado en cuanto a granularidad desde que se cerraron CXP e Impuestos — y es casi seguro que devuelve N filas por folio (una por cuenta contable/centro de costo), no 1, porque el layout pide columnas Cuenta Registro/Nombre Cuenta Registro/Cargo/Abono que son inherentemente multi-línea contable: un folio con Cargo en una cuenta y Abono en otra son 2 líneas, no 1.

Esto bloquea la construcción de cualquier query maestra que una v3.0 (CXP) + v5.0 (Impuestos) + Cargo/Abono + UUID, porque esas tres primeras piezas sí son 1 fila/folio. Si Cargo/Abono resulta ser N filas/folio, hay dos caminos de diseño, sin decidir todavía:

  1. Repetir el valor de CXP/Impuestos/UUID en cada línea de cuenta contable del folio — fácil de implementar, pero un consumidor que sume por accidente sobre esa columna duplica el monto (mismo tipo de trampa que GRANULARIDAD_CXP ya resolvió en v3.0, y que habría que resolver aquí con el mismo patrón de columna de metadata).
  2. Separar el layout en dos niveles de output: un extracto a nivel folio (CXP, Impuestos, UUID, cada fila única) y un extracto a nivel línea contable (Cargo/Abono), dejando que el consumidor final (FlexMonster/Excel) los combine con su propia lógica de pivote, en vez de forzar todo a una sola tabla plana.

El primer paso concreto para resolver esto es un COUNT(*) agrupado por folio contra v03_detalle_cuenta_centro_costo.sql en enero 2026, para ver la distribución real (cuántos folios tienen 1 línea vs. 2+) antes de decidir entre las dos opciones.

Roadmap de columnas pendientes (layout completo, 60 columnas)

Fuente: Requerimiento_de_Reportes_de_Contabilidad_auditoria_V2.docx (mismo requerimiento original de Ismael Valdez). Resumen de sources/trivasa/layout-gastos/roadmap_layout_completo.md — ese archivo es la copia literal de la versión más completa a la fecha en que se copió (2026-08-04); si el trabajo avanza después, esta página y el roadmap original en el repo de trabajo pueden ir por delante de esa copia.

Ya resuelto y validado (ver tabla de arriba): Operacion (ID), Subtotal Neto, Total, UUID, Cuenta Registro/Nombre Cuenta Registro/Cargo/Abono (pendiente de confirmar granularidad, ver riesgo abierto arriba), Monto Cobrado (validación de CXP, aún no expuesta como columna final), Subtotal 0%/Subtotal 16%/Subtotal exento y las ~13 columnas de retenciones específicas (ISR RESICO, IVA sobre arrendamiento, IMSS patrón, etc.) vía v5.0.

Fácil — mismo join ya validado, solo falta traer más columnas:

  • Fecha, Moneda — ya están en Gasto_Registro/Gasto_Registro_Documento.
  • Clave/RFC/Nombre del proveedor — un JOIN Proveedor adicional.
  • Fecha/Tipo/Número/Concepto de póliza — ya se llega a Poliza en v1.0.
  • Columnas XML * y Fecha Factura/Tipo de comprobante — ya se llega a Comprobante_Digital en v2.1.
  • Cobrado en Efectivo, Cobrado con Cheque o Transferencia, Banco, Cuenta bancaria, Fecha de cheque, No. Cheque o No. Transf. — vía Pago_CXP/Cheque, identificado en el reporte de producción (aaron_query/ContabilidadRepository.txt, ver más abajo) pero todavía no explorado con datos propios.

Territorio nuevo, sin explorar:

  • Descuento, Descuento Global — sin origen identificado todavía.
  • FACTURA_REF, Concepto gasto, Clave Uso bien o servicio, Descripcion Uso bien o servicio — origen todavía sin identificar.
  • Pago_CXP/Cheque (Cobrado en Efectivo/Cobrado con Cheque o Transferencia, Banco, Cuenta bancaria, etc.) — sin explorar con datos propios (ver bloque “fácil” arriba, ya identificado en el reporte de referencia del programador).

Pendiente inmediato: verificar la granularidad de Cargo/Abono (COUNT(*) GROUP BY FOLIO contra v03_detalle_cuenta_centro_costo.sql, enero 2026) — desbloquea la decisión de diseño de la query maestra descrita en el riesgo abierto de arriba; según el resultado, construir esa query maestra uniendo v3.0 + v5.0 + Cargo/Abono + UUID; actualizar sources/trivasa/layout-gastos/roadmap_layout_completo.md (o su equivalente vigente en el repo de trabajo) para reflejar que CXP e Impuestos ya cerraron; y explorar, en este orden, el bloque “fácil” (Fecha/Moneda/Proveedor/Póliza/XML, sin riesgo), Pago_CXP/Cheque, y por último Descuento/Descuento Global y el resto de “origen no identificado”.

Reporte de referencia del programador (aaron_query/)

trivasa-bi-dev/layout_gastos/aaron_query/ guarda, solo como referencia, el reporte de producción existente entregado por el programador externo: ContabilidadRepository.txt (repositorio C#/Dapper con la query completa de 60 columnas) y QueryAuditoria2.0.sql (la misma query en SQL puro). Es la fuente de la que sale la lista de columnas del roadmap y de varios de los bugs ya documentados en Modelo de datos (el filtro Es_Cve_Estado = 'AP' y el uso de Poliza_Detalle_Comprobante para ligar UUID, ambos vistos primero en esta implementación externa) — se consulta para saber qué columnas espera Contabilidad y qué caminos ya se intentaron, no se ejecuta ni se copia tal cual. Confirma el patrón de Subtotal 0%/16%/Exenta usado en v5.0, pero no resuelve Descuento/Descuento Global ni las retenciones individuales — también las deja hardcodeadas en 0 ahí, así que esas columnas siguen siendo territorio nuevo sin importar cuál de las dos implementaciones se consulte.

Véase también

  • Layout de Gastos — panorama general del reporte y de la exploración 1.
  • Modelo de datos — tablas de origen de la exploración 1; varios hallazgos de esta página (moneda original, Gr_Folio como texto) son consistentes con lo documentado ahí, solo que llegados por un camino de validación distinto.
  • Atribución de Cargo/Abono por documento — el mecanismo de emparejamiento por valor de la exploración 1; esta exploración no lo re-implementó (se quedó a nivel folio en v0.2/v1.0), lo usó como referencia para la regla de Abono.
  • Versiones y cuándo usar cada una — tabla de versiones v0.1-v0.5.1 de la exploración 1; no confundir con la tabla de esta página.
  • Workflow de exploración de datos — incluye la convención de salida de scripts de validación (helpers_output.py) que usan los scripts de esta exploración, documentada como parte del workflow general.