Skip to content

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), ver get_engine_207() en contabilidad/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 .205 a 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 incluyen tipo_comprobante, clasificacion, modulo_mpro (Cd_Tabla), documento_mpro.
  • Descarga CSV. Query cacheada 10 min.

Pendiente

  • Revisar el caso aislado de tipo I autoemitido (fuera de alcance de esta primera versión).