Skip to content

Layout de Gastos por CECO — CONT-1

Página del app Contabilidad de streamlit-reportes (reportes.frento.com.mx/contabilidad). Reemplaza, el 2026-09-03, al reporte "Layout de Gastos — Reconciliación CECO" original (mismo path de página, contenido rediseñado — ver "Rediseño" abajo). Ver también CONT-2, la misma reconciliación + el séptimo origen (GASTO_REGISTRO_NOMINA).

Compara, folio por folio y centro por centro, el reparto operativo del gasto (Gasto_Registro_Control.Grc_Importe) contra lo que realmente quedó contabilizado (Poliza_Detalle) — 6 orígenes de Gasto_Registro: CONTROL_COMBUSTIBLE, ORDEN_COMPRA, VIAJE, GASTO_DIRECTO, GASTO_RECLASIFICACION, CONSUMO_INTERNO. GASTO_REGISTRO_NOMINA en CONT-2 aparte (técnica de emparejamiento distinta, ver ese .md).

Es un reporte de diagnóstico de calidad de dato, no el layout de gastos en sí — Poliza_Detalle sola ya reconcilia al 100% contra el folio (ver Layout de gastos). Este reporte responde una pregunta distinta: ¿el reparto por centro de costo que trae Gasto_Registro_Control coincide con lo que se contabilizó?

Origen completo del trabajo (scripts numerados 01-13, PROGRESS.md, RESUMEN_CASOS.md): conciliacion-master/layout-gastos/ en proyectos-bi — ese es el laboratorio de exploración; este reporte es la promoción de 11_reporte_base_ceco.py/12_reporte_base_ceco_consumo_interno.py a Streamlit, misma lógica.

Rediseño 2026-09-03 — sin máscara de reversión

La versión original de este reporte (promoción de 09_reconciliacion_completa_con_consumo_interno.py) decidía Cargo vs. Abono con una regla de reversión por folio ("si IMPORTE del folio ≤ -$1, usar Abono"), calculada del lado operativo. Existía solo porque la query de póliza (v03_detalle_cuenta_centro_costo.sql, heredada de FlexMonster) colapsaba Pd_Tipo — el dato real, 1=Cargo/2=Abono — en dos columnas sumadas antes de que el código pudiera ver cuál era la línea real.

Esta versión agrupa por Pd_Tipo en vez de colapsarlo — TIPO_MOVIMIENTO sale directo del dato, cero regla, cero máscara. Validado no solo en agregado sino posición por posición dentro de (FOLIO, CECO), contra el diseño viejo: cero diferencias en miles de combinaciones (FOLIO, CENTRO) comparadas. Mismo resultado exacto, mecanismo honesto.

Dos bugs reales encontrados al dejar de colapsar (ninguno cambió el % final, sí la honestidad del mecanismo) — detalle completo en PROGRESS.md del proyecto de origen (entrada 2026-09-03):

  1. Gr_Tabla viene '' (no NULL) para GASTO_DIRECTO — se normaliza en el SQL, no con un .fillna() después del hecho.
  2. Líneas de póliza sin Pd_Centro_Costo real (contrapartida normal de doble entrada — Abono a Proveedores/Provisión/Préstamos, cuentas de balance sin centro) se excluyen a propósito (AND pd.Pd_Centro_Costo <> ''), no por accidente.

Un tercer bug, específico del folio de display: Gr_Folio ya es el folio completo tal cual lo ve el usuario en MPRO ("SS-NNNNNNN", sucursal 2 dígitos + folio 7 dígitos, varchar(10) fijo) — no hacía falta reconstruirlo concatenando Sc_Cve_Sucursal (ese catálogo guarda la sucursal con 4 dígitos, "00"+2, un formato distinto que nunca correspondió al folio de display). El código viejo (y los 13 scripts de la exploración de origen) lo reconstruían sin necesidad — corregido en todos.

Fuentes y grano

Grano del reporte: (FOLIO, CECO, TIPO_GASTO) — 1 fila por combinación, con la línea real de póliza (CUENTA, TIPO_MOVIMIENTO, IMPORTE) que le tocó por posición dentro de (FOLIO, CECO) (rank-pairing — no existe llave real entre Grc_ID y Poliza_Detalle, Poliza_Detalle no guarda Grd_ID). Confirmado que CARGO/ABONO nunca coexisten !=0 en la misma fila, ni siquiera en el residual de GASTO_RECLASIFICACION que mezcla signos en un mismo centro.

  • Lado operativo: Gasto_Registro_Control (Grc_Importe), colapsado por (Tg_Cve_Tipo_Gasto, Cc_Cve_Centro_Costo) — no por Grd_ID (documento). Confirmado con folio real 01-0034885 ("TELEFONIA", 7 recibos/documentos): colapsado por documento da 53 filas, por tipo de gasto da 27, exacto el número de líneas reales de la póliza.
  • Lado contable: Poliza_Detalle, agrupado por (Cc_Cve_Cuenta_Contable, Pd_Centro_Costo, Pd_Tipo) — Pd_Tipo real decide TIPO_MOVIMIENTO, nunca inferido. Para CONSUMO_INTERNO, query aparte (filtra la póliza de gasto real, excluye la memo de inventario).
  • .205 (no productiva), a propósito — toda la exploración de origen se construyó y validó contra esta instancia (ver get_engine_205() en contabilidad/db.py).

Reconciliación — a nivel FOLIO, no fila (2026-09-03)

La pestaña "Reconciliación" compara, por folio, Cargo - Abono (sumado sobre todas sus líneas de CECO x Tipo de Gasto) contra el importe nativo del folio (Gasto_Registro_Documento, la misma cifra que reporta MPRO — no Grc_Importe). Reemplaza la comprobación a nivel fila (que dependía del rank-pairing y heredaba su residual) por una pregunta más simple: "¿el folio completo cierra?", sin importar cómo se repartieron sus líneas entre centros/tipos de gasto. Tolerancia < $1.

Reglas de negocio aplicadas

  1. GASTO_RECLASIFICACION — par espejo Cargo=Abono dentro de la misma póliza. El signo de Grc_Importe por línea (no si el folio completo es negativo) decide si esa línea es Cargo (positivo) o Abono (negativo) — del lado operativo únicamente; del lado póliza no hace falta decidir nada, TIPO_MOVIMIENTO ya viene de Pd_Tipo.
  2. CONSUMO_INTERNO — genera dos pólizas paralelas por folio (memo de inventario 10500/10600 vs. gasto real). Se filtra Poliza.Pl_Comentario (excluir "CUENTAS DE ORDEN"/"CTS ORDEN"/"CUENTA ORDEN") para quedarse con la de gasto real. Confirmado 2026-09-03 con Pd_Tipo real (no asumido, a diferencia de la versión anterior de este reporte): 100% Cargo, 0% Abono con centro real.

Resultado de referencia (enero 2026, empresa 0001)

Origen Filas
CONTROL_COMBUSTIBLE 591
GASTO_DIRECTO 6,531
GASTO_RECLASIFICACION 143
ORDEN_COMPRA 80
VIAJE 346
CONSUMO_INTERNO 3,072
Total 10,763 (4,395 folios)

99.75% de las filas cuadran contra la estimación operativa; Importe reporte MPRO (deduplicado por folio) coincide con el importe nativo agregado del periodo. Detalle completo del residual conocido (<0.06% del universo trimestral, causas identificadas en su mayoría) en PROGRESS.md del proyecto de origen.

El Streamlit

Código: contabilidad/pages/1_Layout_de_Gastos_por_CECO_CONT-1.py + lógica de negocio en contabilidad/layout_gastos_ceco_lib.py + UI compartida con CONT-2 en contabilidad/layout_gastos_ceco_ui.py (patrón del skill trivasa-streamlit-reportes).

  • Filtros: Periodo (rango de fechas, ambas inclusivas), Origen (multiselect, default = todos), Buscar (texto libre sobre folio/póliza/ CECO/cuenta/tipo de gasto).
  • Métricas: Filas, Folios, % cuadra vs. lado operativo, Σ Cargo, Σ Abono, Importe reporte MPRO.
  • Tabs: Datos (con descarga Excel) · Reconciliación (semáforo por origen + tabla de folios que no cuadran) · Documentación.

Pendiente

  • ~~Implementar la rama de capitalización de activo fijo para CONSUMO_INTERNO~~ — resuelto 2026-09-08 (ver conciliacion-master/layout-gastos/PROGRESS.md, entrada de esa fecha). La hipótesis original (parsear Grd_Comentario "U-NNN") era incorrecta: el código corto ya vive tal cual en Gasto_Registro.Gr_Referencia, y Poliza_Configuracion_Detalle.Pcd_Referencia de las configs 0295/ 0414 lo confirma (Pcd_Referencia = Gasto_Registro.Gr_Referencia, no Gr_Folio — ver configuracion-polizas.md, sección "Addendum 2026-09-08"). Gr_Referencia no es único dentro de una póliza (colisiona en ~28% de las pólizas de esta rama) — se resuelve con la misma técnica de rank-pairing que el resto del proyecto, por (Pl_Folio, Referencia). Resultado: CONSUMO_INTERNO sube de 99.37% a 99.84% (enero-marzo 2026), 45/47 folios de activo fijo recuperados. Queda un residual de 2 folios que reparten el gasto en más de un centro de costo (no cubierto por el rank-pairing simple sin CECO en la llave).
  • Aplicar la regla de reversión de folio a CONSUMO_INTERNO si aplica (no investigado si tiene sus propios folios de reversión).
  • Mejorar el filtro de doble póliza de CONSUMO_INTERNO (Pl_Comentario NOT LIKE '%CUENTAS DE ORDEN%', texto libre, frágil) por uno basado en cuenta contable.
  • Decidir qué hacer con las filas residuales del rank-pairing (<0.06%): hoy quedan visibles marcadas TIPO_GASTO/CUENTA = (residual).