Skip to content

Syntage · Invoices (facturación CFDI)

De punta a punta: del webhook de Syntage a su uso en análisis y producto. Incluye dónde vive la lógica de cada transformación.

Camino de terminal_client (dbt-etls) ELIMINADO el 2026-09-11

El cálculo de terminal en dbt-etls (models/terminal_client/, tabla …terminal.client_dbt) ya no existe: se borró el 2026-09-11 junto con el export a Supabase (ver Apagado Terminal → Supabase). El producto de pricing vivo es Terminal v3, que lee de dbt-analytics en solvento-risk-analytics-prod, no de aquí. El consumo vivo y confiable de este proceso es consistency_jobs.invoices (abajo). La vía exacta de la facturación de cara al cliente conviene confirmarla.

¿Llegaste hasta acá desde…?

Usa esta tabla para entrar en sentido inverso (lo que ves → de dónde sale):

Si ves… Eso sale de… La lógica está en…
Montos/totales canonizados en análisis o Metabase solvento-adv-analytics-prod.consistency_jobs.invoices dbt-etls → models/advanced_analytics/invoices.sql
Tarifas de lanes / pricing de flete solvento-risk-analytics-prod.terminal_v3.datarelease_* Terminal v3 (vía dbt-analytics)
❌ terminal.client_dbt (dbt-etls) Eliminado el 2026-09-11 (dataset dropeado) Ya no existe — ver Apagado Terminal → Supabase
Una factura "cruda" / sin deduplicar solvento-data-prod.syntage.invoices (RAW) Ingesta (sin lógica de negocio); ver "Paso a paso"

Resumen

Campo Valor
Origen Webhook de Syntage (evento invoice)
Patrón Event-driven (Cloud Run → Pub/Sub → Dataflow) + transformación dbt
Tabla RAW solvento-data-prod.syntage.invoices
Tabla transformada (viva) solvento-adv-analytics-prod.consistency_jobs.invoices (vía dbt-etls)
terminal.client_dbt ❌ Eliminado el 2026-09-11 junto con el dataset (ver Apagado Terminal → Supabase)
Frecuencia Ingesta streaming · transformación dbt diaria (madrugada)
Criticidad 🔴 Alta — flujo más crítico del ecosistema
Dueño Martin (data eng)

Diagrama de linaje (ingesta → lógica → consumo)

graph LR
    SYN[["📨 Syntage<br/>webhook invoice"]]

    subgraph ing["1 · Ingesta (sin lógica de negocio)"]
        CR["Cloud Run<br/>webhook-syntage-inline-prod"]
        TOP(["Pub/Sub<br/>invoices-webhook-prod"])
        DF["Dataflow<br/>invoices-webhook-prod"]
        RAW[("solvento-data-prod<br/>syntage.invoices · RAW")]
    end

    subgraph logica["2 · Lógica de negocio · dbt-etls"]
        M1["invoices.sql<br/><i>dedup · redondeo · nombres · FX</i>"]
        M2["invoices_360.sql<br/><i>une items + carta porte</i>"]
        M3["❌ final_invoice.sql<br/><i>ELIMINADO 2026-09-11</i>"]
        M4["❌ client_dbt.sql<br/><i>ELIMINADO 2026-09-11</i>"]
        GOLD[("❌ terminal.client_dbt<br/>dataset dropeado")]
    end

    subgraph cons["3 · Consumo"]
        MB["Metabase / Riesgo<br/>(consumo vivo)"]
    end

    SYN -->|HTTP| CR --> TOP --> DF --> RAW
    RAW --> M1 --> M2
    RAW -.->|deprecado| M3 -.-> M4 -.-> GOLD
    M1 --> MB
    M2 -.-> M4

    classDef src fill:#fde68a,stroke:#b45309,color:#000;
    classDef store fill:#bfdbfe,stroke:#1e40af,color:#000;
    classDef logic fill:#dcfce7,stroke:#15803d,color:#000;
    class SYN src;
    class RAW,GOLD store;
    class M1,M2,M3,M4 logic;

Paso a paso

1 · Ingesta (mueve datos, no aplica lógica de negocio)

  1. Syntage emite un webhook por cada factura nueva o actualizada.
  2. Cloud Run webhook-syntage-inline-prod (webhook_syntage) enruta a Pub/Sub según el tipo de evento. Enruta todo Syntage, por eso es tan crítico.
  3. Pub/Sub desacopla: topic invoices-webhook-prod (factura completa), invoices-api-topic (requiere detalle vía API → invoices_items), invoices-dlq (fallidos).
  4. Dataflow invoices-webhook-prod-… (template-invoices) escribe el dato crudo en solvento-data-prod.syntage.invoices. Ojo: la RAW puede tener duplicados; aún no hay lógica de negocio.

2 · Lógica de negocio (dbt — aquí están las reglas) → repo dbt-etls

  1. invoices.sql (models/advanced_analytics/invoices.sql) → solvento-adv-analytics-prod.consistency_jobs.invoices. Deduplica por id, redondea montos (total, subtotal, tax, etc.), canoniza nombres de emisor/receptor (issuer_names, receiver_names) y convierte moneda con analiticas.exchange_rates.
  2. invoices_360.sql une invoices + invoices_items + cp_data + items_partition_map (vista 360 de la factura).
  3. ❌ final_invoice.sql y client_dbt.sql (models/terminal_client/) — eliminados el 2026-09-11 junto con el dataset …terminal. Combinaban la factura con carta porte/mercancías y producían la tabla GOLD del terminal de cliente. Se dejan nombrados solo por el ruido histórico: ya no existen (ver Apagado Terminal → Supabase).

3 · Consumo

  • ❌ terminal.client_dbt en dbt-etls — eliminado el 2026-09-11. La vía actual de la facturación de cara al cliente conviene confirmarla.
  • Metabase / modelos de riesgo leen de consistency_jobs.invoices.

Si falla 🛠️

Impacto: si cae webhook-syntage-inline-prod se afecta todo Syntage. Mitigante: Syntage reintenta los webhooks; recuperar el servicio suele bastar.

Síntoma Dónde mirar Acción
No llegan facturas nuevas Logs Cloud Run webhook-syntage-inline-prod Si fue un deploy → rollback; si es saturación → subir instancias/memoria (Terraform gcp/terraform-gcp-infrastructure)
Llega a RAW pero el frontend no actualiza Run diario de dbt Cloud (proyecto ingeniería) Re-ejecutar el job; revisar qué modelo falló (invoices, invoices_360)
Llega al topic pero la RAW no avanza Dataflow: watermark del job; backlog de la suscripción Transitorios se recuperan solos; relanzar consumiendo la misma suscripción. Si hay duda, escalar
Montos/nombres "raros" en el frontend Lógica en dbt-etls (invoices.sql, invoices_360.sql) Revisar la transformación en el repo, no la ingesta

Escalación: lógica SQL / Metabase → Diego · Airbyte → Gero · resto → Martin.

Enlaces

  • 📊 Estado en vivo: dashboard "Data Processes" (Cloud Monitoring)
  • 📦 Ingesta: webhook_syntage · template-invoices
  • 🧮 Lógica: dbt-etls — modelos en models/advanced_analytics/ (models/terminal_client/ fue eliminado el 2026-09-11)

Última actualización: 2026-06-21 · Si cambia el flujo o un modelo dbt, actualizar esta ficha en el mismo MR.