Cruce XML Recibidos vs Comprobante Digital — CONT-3
Página del app Contabilidad de streamlit-reportes (
reportes.frento.com.mx/contabilidad). Renombrada a CONT-3 el 2026-09-03 (antes página 1, sin clave) al agregar CONT-1/CONT-2 — mismo contenido, solo cambia el nombre de archivo/label y la conexión de MPRO (ver abajo).
Qué XML CFDI ya recibidos (cargados por el ELT
trivasa-bi-core/raw_sat_xml/cargar_cfdi_recibidos.py a Postgres
raw_sat.cfdi_recibidos, ver consulta-xmls)
tienen o no un registro ligado en MPRO vía Comprobante_Digital — match por
UUID (Cd_Timbre_UUID).
Fuentes y grano
Grano: un CFDI recibido (uuid).
- XML: Postgres
raw_sat.cfdi_recibidos—uuid,fecha_emision,rfc_emisor,nombre_emisor,tipo_comprobante,total,periodo. - MPRO:
Comprobante_Digital— TRIVASADB en.207(producción real), verget_engine_207()encontabilidad/db.py. Antes de 2026-09-03 usaba.205(no productiva) temporalmente, compartiendo conexión con el reporte de Layout de Gastos aunque son bases distintas por diseño — separado al agregar CONT-1/CONT-2, que sí se queda en.205a propósito.
Match: normalizar ambos UUID a mayúsculas y comparar. Un mismo UUID puede
estar capturado en más de un Cd_Tabla de Comprobante_Digital — solo
importa si existe al menos un match, no cuántos.
Clasificación en 3 buckets (no 2) — decisión 2026-09-02
Excluir sin más los CFDI tipo T del cálculo de conciliación (propuesta
inicial) se descartó: escondía pendientes reales. En vez de eso, el reporte
clasifica cada XML en tres grupos:
| Bucket | Condición | Significado |
|---|---|---|
| Compra/gasto | match en Comprobante_Digital, Cd_Tabla ≠ TRASLADO |
Ya conciliado (COMPRA, GASTO_REGISTRO, CHEQUE, etc.) |
| Traslado | match en Comprobante_Digital, Cd_Tabla = TRASLADO |
Ya conciliado — ver hallazgo abajo |
| Sin match | no aparece en Comprobante_Digital en ningún módulo |
Pendiente real |
Hallazgo: CFDI tipo T = Carta Porte autoemitida por Trivasa
En raw_sat.cfdi_recibidos, tipo_comprobante usa la clasificación
estándar del SAT (I/E/T/P). Confirmado con datos (2026-09-02):
| tipo_comprobante | n | % autoemitido (rfc_emisor = rfc_receptor) |
uso_cfdi |
|---|---|---|---|
| T | 27,006 | 100% | 100% S01 |
| I | 13,416 | 1 caso aislado | — |
| P | 3,925 | 0% | — |
| E | 217 | 0% | — |
Todo CFDI tipo T es una Carta Porte (complemento cartaporte31:CartaPorte)
que Trivasa se autoemite (rfc_emisor = rfc_receptor = TRI970922TL2,
UsoCFDI = S01, Total = $0) por obligación del SAT al mover material
propio entre plantas/sucursales por carretera — no es compra ni gasto, no
tiene efecto fiscal. Ejemplo real inspeccionado: UUID
000BE387-68DB-4889-8B84-DB54E97CD29D, concepto "CEMENTO GRIS 25 KG
FORTALEZA" x400, Importe=$0.00, origen "PLANTA UMAN".
No hay ni hace falta un campo clasificador nuevo — tipo_comprobante='T'
ya es 100% equivalente a "carta porte autoemitida" en este dataset (los
datos lo confirman, no hace falta agregar una columna derivada que metería
ruido/duplicación en raw_sat.cfdi_recibidos).
Del lado de MPRO, estos CFDI matchean contra el módulo más grande de
Comprobante_Digital (Cd_Tabla='TRASLADO', 148,997 filas — el mismo que
alimenta Transferencias sin recepción).
Nota: el campo que "debería" decir el tipo (Cd_Tipo_Comprobante_CFDI,
valores INGRESO/PAGO/NOMINA/EGRESO) viene vacío para todo
Cd_Tabla='TRASLADO' — MPRO no lo etiqueta ahí, solo se infiere por
Cd_Tabla.
Cruce global tipo T (2026-09-02): de 27,006, 24,732 (91.6%) matchean en
TRASLADO, 2,274 (8.4%) no tienen match en ningún lado — confirmado
con búsqueda de texto libre sobre Cd_XML/Cd_Cadena_Original (no solo
Cd_Timbre_UUID) en una muestra, cero coincidencias. Esos 2,274 son
traslados facturados ante el SAT pero sin captura en el módulo TRASLADO
de MPRO — pendientes reales, no ruido, y por eso siguen visibles en el
reporte en vez de filtrarse.
Bug corregido: filtro de periodo vacío mostraba "todo" en vez de "nada"
Primera versión: if f_periodo: ... trataba una selección vacía del
multiselect como "sin filtro" → mostraba el total global (44,564 XML / 90.2%
match) en vez de nada, confuso al cambiar de periodo. Corregido: selección
vacía → st.stop() con aviso "Selecciona al menos un periodo", nunca
"todos" implícito.
Resultado de referencia (2026-09-02, todos los periodos)
44,564 XML recibidos totales, 90.2% con match (40,203) contra
Comprobante_Digital — cifra agregada de compra/gasto + traslado, antes de
separar en los 3 buckets. Enero 2026 aislado: 5,624 XML, 2,028 compra/gasto
+ 3,565 traslado conciliados (99.4% agregado), 20 sin match compra/gasto +
11 sin match traslado.
El Streamlit
Código: contabilidad/pages/3_Cruce_XML_Recibidos_vs_Comprobante_Digital_CONT-3.py.
- Filtros: Periodo (multiselect, default = periodo más reciente, vacío = sin datos, no "todos"), Clasificación (Compra/gasto, Traslado, Sin match).
- Métricas: 4 KPIs — Compra/gasto conciliado, Traslado conciliado, Sin match–traslado, Sin match–compra/gasto (estos últimos son los pendientes reales de proveedor a revisar).
- Tabla:
streamlit-aggrid, columnas incluyentipo_comprobante,clasificacion,modulo_mpro(Cd_Tabla),documento_mpro. - Descarga CSV. Query cacheada 10 min.
Pendiente
- Revisar el caso aislado de tipo
Iautoemitido (fuera de alcance de esta primera versión).