Andesmar BI · Presentación negocio

Estados de boleto: qué significan y por qué los medimos así

Un recorrido pedagógico para gerencia, operaciones y finanzas: cómo Betterez registra los boletos, por qué no alcanza con un solo campo de estado, y qué columna usar en cada reporte.

Junio 2026 ~1,2 millones de boletos en producción Fuente BI: bi_rebuild.fact_ticket
🔎
La respuesta corta: en nuestra plataforma de datos no existe una sola columna que sea “el estado del boleto según Betterez, listo para KPI”. Betterez guarda el estado en varios lugares distintos y, en muchos casos, no actualiza el campo principal cuando hay una cancelación. Por eso construimos columnas propias — no es un defecto del sistema, es una decisión de diseño para dar números confiables a la gerencia.
1.140.409
boletos pagados netos (is_paid = true) — KPI oficial BI (corte 2026-06-13)
~3.717
boletos que Betterez sigue marcando como “paid” pero ya están cancelados (is_paid=false)
~2.991
cancelaciones parciales (con penalidad retenida por Andesmar)
2–20
boletos de diferencia típica por agencia/mes vs Betterez web
Tres ideas para llevarse de esta presentación
1. Un boleto no es lo mismo que una venta
Una venta (transacción) puede tener varios boletos (ida, vuelta, seguros). Los estados se calculan por boleto, no por venta.
2. Betterez registra los eventos; nosotros los interpretamos
La cancelación queda en refund_details (webhook refund.created), pero el campo status del boleto a veces no se actualiza. El ETL cruza ambas fuentes.
3. Cada pregunta de negocio tiene su columna
Tablero oficial → is_paid. Cruce con Betterez web → is_paid_including_partial_cancel. Cancelados → effective_ticket_status.

Para quién es este documento

Presentación en vivo + referencia standalone para consultar después

💼
Gerencia general
Entender por qué los números del tablero BI y los de Betterez web pueden diferir en pocos boletos, sin que sea un error.
📈
Finanzas
Revenue neto, penalidades retenidas en cancelaciones parciales, montos reembolsados.
🏛
Operaciones / agencias
Ranking por punto de venta, cruce con reportes Betterez, cancelaciones parciales.
🖥
Datos / IT / MSTR
Qué tabla usar, qué columnas modelar, scripts de validación y auditoría OLTP.

Vocabulario de negocio

Términos que aparecen en Betterez, en los reportes y en esta plataforma

Transacción / venta
Operación de compra completa en Betterez. Puede incluir uno o varios boletos, seguros y otros ítems. En nuestra base: tabla sales.
Boleto / pasaje / ticket
Un pasaje individual con número propio (ej. ZK6M6Q). Es la unidad de análisis del tablero BI. En nuestra base: tabla tickets, hecho fact_ticket.
Cancelación
El pasajero devuelve el boleto. Betterez calcula penalidad y monto a reembolsar en 3 pasos (ver § ciclo de vida). Webhook: refund.created con type = cancel.
Cancelación parcial
Cancelación donde Andesmar retiene parte del importe como penalidad. El pasajero recibe menos de lo que pagó. Betterez web sí cuenta ese boleto; el tablero BI neto no.
Cancelación total
Reembolso completo (≥ importe del boleto). Ningún sistema lo cuenta como venta vigente.
Cambio / reemisión
Modificación de fecha, horario o servicio. Puede generar un boleto nuevo y marcar el anterior como changed. Webhook: ticket.updated y a veces refund.created con type = change.
Devolución (refund)
Reembolso distinto de cancelación estándar. Tipo refund en refund_details.
Penalidad / cargo por cancelación
Monto que Andesmar retiene. En Betterez API: campo penalty del cancel set. En BI: cancel_penalty_amount = ticket_amount − reembolso.
OLTP
Capa operacional: copia fiel de lo que Betterez nos envía (PostgreSQL GCP, schema public).
BI / bi_rebuild
Capa analítica curada para reportes y MicroStrategy. Una fila = un boleto con flags de negocio calculados.
ETL
Proceso diario que transforma OLTP → BI. Recalcula estados mirando refund_details, no solo el status crudo.
Grano
Qué representa una fila. En fact_ticket: 1 fila = 1 boleto. En fact_sale: 1 fila = 1 venta.

Qué es Betterez y qué nos manda

La plataforma de ticketing que opera las ventas de Andesmar

Betterez es el sistema donde se venden los pasajes (agencias, web, backoffice). Cada venta, cancelación o cambio genera webhooks (notificaciones automáticas) que nuestra API recibe y guarda íntegros antes de procesarlos. Documentación oficial consultada: Webhooks de tickets, Webhooks de refunds, Guía de cancelaciones.
Eventos Betterez que afectan el estado de un boleto
Acción en BetterezWebhookQué guardamosImpacto en BI
Compra de boleto ticket.created Fila en tickets con status = paid Venta neta
Cancelación ejecutada refund.created (type = cancel) + a veces ticket.updated Fila en refund_details; tickets.status puede quedar en paid Excluido de is_paid
Cambio de boleto ticket.updated + a veces refund.created (type = change) Status changed; boleto nuevo en misma u otra venta No cuenta como venta vigente
Devolución (refund) refund.created (type = refund) Fila en refund_details effective = refunded
Pago pendiente / expirado ticket.updated waiting for payment, payment expired No operable
Punto clave de la documentación Betterez: al cancelar, Betterez ejecuta un flujo de 3 pasos (obtener ítems cancelables → crear “cancel set” con penalidad y montos → ejecutar cancelación). El webhook refund.created incluye campos como penalty, amountToRefund, refunded y type. Esos datos son la fuente de verdad para saber si hubo cancelación parcial; el campo status del ticket no siempre refleja el resultado final.

Ciclo de vida de un boleto

Desde la venta hasta la cancelación o el cambio

Paso 1
Venta
Pasajero paga → ticket.created
status = paid
Estado vigente
Boleto activo
is_paid = true
cancel / change / refund
Postventa
Evento en refund_details
refund.created
Cancelación en Betterez (3 pasos API)
  1. Consultar ítems cancelables — qué boletos se pueden devolver y bajo qué reglas de canal.
  2. Crear cancel set — preview con penalidad, fees y monto a reembolsar por medio de pago.
  3. Ejecutar cancelación — procesa el reembolso, actualiza ítems y emite webhooks.
Cambio de boleto en Betterez
  1. Consultar datos del cambio (trip-change-info).
  2. Buscar inventario disponible para el nuevo viaje.
  3. Crear carrito con el cambio (puede ser “zero pay” si el precio es igual).
Analogía para negocio: imaginen el boleto como un recibo de compra y refund_details como la nota de crédito. A veces el recibo original sigue diciendo “pagado” aunque ya exista la nota de crédito. Nuestro tablero BI lee ambos documentos antes de decidir si el boleto sigue contando como venta.

Tablas involucradas y sus relaciones

Modelo conceptual: qué es cada tabla, qué representa una fila y cómo se conectan

Origen · Betterez
Transacción (transaction)
1 transacción = 1 operación de compra
Contiene el total de la venta, agencia, canal, fecha, estado global (paid, confirmed…). Puede incluir varios boletos y productos ancillaries.
Webhook: transaction.* → guardamos en public.sales
OLTP · public.sales
sales
1 fila = 1 venta / transacción
Copia fiel de la transacción Betterez. Campos clave: transaction_id, sale_date, total, currency, agency_code, status (mapeado: paid→confirmed).
1 venta → N boletos (tickets.sale_id)
OLTP · public.tickets
tickets
1 fila = 1 boleto
Pasaje individual: número, ruta, importe (total), impuestos, fecha de viaje, status crudo de Betterez (paid, cancelled, changed…).
N boletos ← 1 venta · 1 boleto → N refund_details
OLTP · public.refund_details
refund_details
1 fila = 1 evento postventa sobre un boleto
Detalle de cancelación, cambio o devolución. Campos clave: type (cancel/change/refund), refunded, amount, penalty, ticket_number.
Webhook: refund.created · Fuente de verdad para cancelaciones
BI · bi_rebuild.fact_ticket
fact_ticket
1 fila = 1 boleto (hecho principal)
Tabla analítica con estados curados: is_paid, effective_ticket_status, flags de cancel parcial/total, montos de refund, dimensiones (agencia, canal, fecha).
Se alimenta del ETL diario cruzando tickets + refund_details + sales
BI · bi_rebuild.fact_ticket_mstr
fact_ticket_mstr
1 fila = 1 boleto (vista wide MSTR)
Incluye etiquetas de manifiesto (has_nacional, etc.) y columnas básicas de estado. No trae flags finos como is_partial_cancel.
JOIN con fact_ticket por ticket_id si se necesitan ambos
Diagrama de relaciones (conceptual)
Betterez (webhooks) │ ├── transaction ──────────► public.sales ──────────► bi_rebuild.fact_sale │ │ │ │ 1 : N │ ▼ ├── ticket.created/updated ─► public.tickets ──────► bi_rebuild.fact_ticket ◄── ETL diario │ │ ▲ │ │ 1 : N │ └── refund.created ───────────► public.refund_details ─────┘ │ └── type: cancel | change | refund penalty, refunded, amount
Dimensiones conectadas a fact_ticket: dim_agency (punto de venta), dim_channel (web, agencia, backoffice), dim_date / dim_mes_anio (fecha de venta), dim_route, dim_station (origen/destino). Permiten cortar los KPI por agencia, mes, canal, etc.
Principio raw-first: antes de calcular cualquier estado, guardamos el payload completo de Betterez en Google Cloud Storage y en raw_events. Si hay duda sobre un boleto, siempre podemos auditar qué mandó Betterez originalmente.

Tres niveles de lectura del estado

De la vista ejecutiva al detalle de auditoría

Nivel 1 — Semáforo ejecutivo
is_paid vs is_paid_including_partial_cancel
Para gerencia: “¿cuánto vendimos?” vs “¿cuánto muestra Betterez?” La diferencia ≈ cancelaciones parciales.
Nivel 2 — Estado efectivo curado
effective_ticket_status
paid / cancelled / changed / refunded. Para composición del universo de boletos y hojas del tablero MSTR.
Nivel 3 — Granularidad fina
is_partial_cancel, montos, ticket_status
Para finanzas (penalidades), operaciones (auditoría por agencia) y datos (diagnóstico OLTP vs curado).
Prioridad del ETL al calcular effective_ticket_status
1. ¿Hay cancel en refund_details?
effective_ticket_status = 'cancelled'
2. ¿Hay refund en refund_details?
effective_ticket_status = 'refunded'
3. ¿Hay change en refund_details?
effective_ticket_status = 'changed'
4. Si no hay eventos postventa
→ usar tickets.status (paid, changed, waiting for payment…) o unknown
¿Por qué este orden? Porque Betterez registra la cancelación en refund_details de forma más confiable que en tickets.status. Priorizamos el evento postventa sobre el campo que a veces no se actualiza.
1

El camino del dato: de Betterez al reporte

Tres capas, dos saltos

Origen
Betterez
Webhooks / API REST
tickets.status
refunds.type
transaction.status
copia directa
Capa OLTP
public.*
PostgreSQL GCP
copia + logica
de negocio
ETL incremental
Capa BI
bi_rebuild.*
fact_ticket & mstr
Columnas que vienen "directo": son copias de OLTP (ticket_status, refund_type, refund_amount). Llegan intactas, pero pueden estar mal en origen.
Columnas calculadas en el ETL: son las que realmente se usan para KPI (is_paid, effective_ticket_status, is_partial_cancel…). Las arma el ETL mirando refund_details.
2

Columnas que vienen directo de Betterez

Copias del OLTP — útiles para auditoría, no para KPI ejecutivos

Regla pedagógica: estas columnas son el “espejo” de lo que Betterez dejó escrito en OLTP. Sirven para diagnosticar discrepancias, pero no definen el KPI de ventas porque el dato de origen puede estar incompleto.
Columna en BI Tabla OLTP origen Origen en Betterez Uso recomendado
ticket_status public.tickets.status tickets[].status del webhook
Valores: paid cancelled changed waiting for payment payment expired
Solo auditoría
Puede decir “paid” aunque el boleto ya esté cancelado
current_status public.tickets.status Espejo sincronizado puntualmente No usar en KPI
Puede quedar desactualizado
refund_type public.refund_details.type refunds[].typecancel, change, refund Complementario
Agrupado por coma si hay varios eventos
refund_amount public.refund_details Suma de refunded / amount del webhook Métricas de monto
fact_sale.status public.sales.status data.transaction.status (mapeado: paid→confirmed) Nivel venta, no boleto
dim_manifest.manifest_status public.manifest_entries Status del manifiesto (re-fetch API) Dimensión operativa
3

Columnas calculadas en el ETL

No existen en Betterez — las construye nuestro proceso diario con reglas de negocio acordadas

¿Por qué las inventamos? Porque ningún campo único de Betterez responde todas las preguntas de negocio. El tablero oficial necesita excluir cancelados; el ranking de agencias necesita alinear con Betterez web; finanzas necesita separar penalidades. Cada columna calculada responde una pregunta concreta, documentada y auditable.
effective_ticket_status — el estado curado para reportes. El ETL aplica prioridad: cancel en refunds > refund > change > status OLTP.
ValorCuando apareceUso tipico
paid Sin evento cancel/refund/change en refund_details Venta neta standard
cancelled Hay type = cancel en refund_details (aunque ticket_status diga paid) Hoja de cancelados
refunded Hay type = refund en refund_details Hoja de devoluciones
changed type = change en refunds, o ticket_status = changed sin refund Hoja de cambios/reemision
unknown Estado no reconocido Solo auditoria
FlagLogica resumidaPara que sirve
is_paid ticket_status = 'paid' Y sin cancel ni refund en refund_details KPI oficial BI Tablero y manifiesto
is_paid_including_partial_cancel is_paid = true O is_partial_cancel = true Cruce con Betterez web Ranking de agencias
is_partial_cancel Cancel en refunds con reembolso menor que el importe del boleto El cliente pago una penalidad — Betterez lo cuenta, BI neto no
is_full_cancel Cancel y reembolso total (≥ importe boleto) Cancelacion sin costo para el pasajero
is_cancelled ticket_status = 'cancelled' O cancel en refunds Flag compuesto general de cancelacion
is_refunded ticket_status = 'refunded' O refund en refunds Flag compuesto de devolucion
has_refund_record Existe al menos una fila en refund_details Detectar si el boleto tuvo algun evento postventa
ColumnaCalculoCuando tiene valor
refund_amount Suma total reembolsada al pasajero Boletos con cualquier refund/cancel
cancel_penalty_amount ticket_amount - cancel_refund_amount Solo en cancelaciones parciales — es el ingreso retenido por Andesmar
Siempre filtrar por currency al sumar montos. Nunca mezclar ARS con otras monedas en la misma metrica. Aplicar cap de $500.000 ARS para KPIs ejecutivos (evita outliers historicos).
Estas columnas NO se recomiendan para KPI ejecutivos:
ColumnaPor que evitarla
is_final_paid Solo mira ticket_status = 'paid' sin revisar refund_details. Sobrecontabiliza boletos cancelados.
current_status Espejo OLTP de sync puntual. Igual que ticket_status, puede estar desactualizado.
ticket_status (como KPI) Valor crudo Betterez. Betterez no lo actualiza cuando hay cancelacion con penalidad — puede quedar paid cuando el boleto ya esta cancelado.
4

"Directo de Betterez" no significa "confiable"

El campo status de Betterez puede decir "paid" cuando el boleto ya esta cancelado

El problema de raiz: Betterez no actualiza tickets.status de forma confiable cuando hay una cancelacion o devolucion. El evento de cancelacion queda en refund_details pero el status del boleto puede seguir figurando como paid. Por eso el ETL prioriza refund_details sobre el status crudo.
3.715
boletos con ticket_status = 'paid' pero effective_ticket_status = 'cancelled'
2.991
boletos con ticket_status = 'paid' y cancelacion parcial activa
3.717
boletos que ticket_status dice "paid" pero is_paid es false
1.140.409
boletos con is_paid = true (venta neta real) — corte 2026-06-13
Conclusion practica

Si usaras solo ticket_status = 'paid' para contar boletos vendidos, estarias contando ~3.717 boletos de mas que en realidad estan cancelados. El campo is_paid corrige ese problema mirando refund_details. Dicho de otra forma: ticket_status es el dato crudo de Betterez, pero is_paid es la interpretacion correcta de ese dato.

Cancelación parcial: el corazón de la diferencia BI vs Betterez

Cuando el pasajero paga penalidad y Betterez sigue contando el boleto

Tipo de cancelaciónCondiciónBetterez webis_paid (BI neto)is_paid_including_partial_cancel
Sin cancelación No hay evento en refund_details Cuenta true true
Parcial Reembolso < importe del boleto (penalidad retenida) Cuenta false true
Total Reembolso ≥ importe del boleto No cuenta false false
En Betterez API la penalidad se define al crear el cancel set (penalty, penaltyReason). El monto reembolsado llega en refunded / amountToRefund del webhook refund.created.
En nuestro BI calculamos cancel_penalty_amount = ticket_amount − reembolso. Ese ingreso retenido es revenue para Andesmar aunque el boleto ya no sea una “venta vigente” en el sentido neto.
5

Que columna usar segun la pregunta

Guia rapida para reportes, dashboards y reconciliacion

Cuantos boletos vendimos (tablero oficial BI)
is_paid = true
El KPI principal. Excluye cualquier cancelacion o devolucion.
Cuantos muestra Betterez por agencia (ranking)
is_paid_including_partial_cancel = true
Incluye cancelaciones parciales donde el cliente pago penalidad. Betterez los cuenta.
Cuantos boletos se cancelaron en el periodo
effective_ticket_status = 'cancelled'
Incluye cancelaciones totales y parciales. No usar ticket_status = 'cancelled' solo.
Cuantos boletos se cambiaron o remitieron
effective_ticket_status = 'changed'
Cambio de servicio o fecha. Puede o no tener fila en refund_details.
Cuantos tuvieron devolucion tipo refund
effective_ticket_status = 'refunded'
O equivalente: is_refunded = true.
Solo cancelaciones con penalidad retenida
is_partial_cancel = true
El pasajero cobro menos de lo que pago. El ingreso retenido esta en cancel_penalty_amount.
Revenue de boletos vendidos
Mismo filtro que conteo + SUM(ticket_amount)
Siempre filtrar currency = 'ARS'. Cap $500k para KPI ejecutivo.
Auditoria del dato crudo de Betterez
ticket_status
Solo para diagnostico tecnico. No para reportes de negocio.
6

Tabla de verdad: combinaciones frecuentes en produccion

Como se leen los flags juntos en casos reales

ticket_status effective_ticket_status is_paid is_partial_cancel is_full_cancel is_paid_incl_parcial Interpretacion
paid paid true false false true Venta neta standard Ambos sistemas coinciden.
paid cancelled false true false true Cancel parcial Betterez lo cuenta, BI neto no. La diferencia entre ambos sistemas.
paid cancelled false false true false Cancel total Betterez no actualizo el status. Ambos sistemas excluyen.
changed changed false false false false Cambio de boleto Ni el BI ni Betterez lo cuentan como venta vigente.
cancelled cancelled false false false false Cancel explicito OLTP Betterez actualizo el status correctamente.
La fila en amarillo es la clave: cuando ticket_status = 'paid' pero hay una cancelacion parcial en refund_details, Betterez lo cuenta como boleto vigente (cobro penalidad), pero el tablero BI oficial no (is_paid = false). Esto genera diferencias de 2-20 boletos por agencia/mes que son reglas de negocio, no errores.
7

Ejemplo real: agencia L78, abril 2026

Como se traduce la diferencia entre columnas a numeros concretos

Conteo segun cada metodo
is_paid = true 10.933
is_paid_including_partial_cancel 10.935 = Betterez web
is_partial_cancel = true 2
is_full_cancel (con status=paid) 12
Detalle de los 2 boletos con cancelacion parcial
N° boletoImporteReembolsoPenalidad
ZK6M6Q $16.200 $14.580 $1.620
GDTSAT $19.000 $17.099 $1.901
Estos 2 boletos explican la diferencia de 2 unidades entre el conteo BI y el conteo Betterez web. No es un error — son reglas de negocio diferentes.
Lectura para negocio: los 2 boletos que explican la diferencia

En abril 2026, la agencia L78 vendió 10.933 boletos netos según el tablero BI. Betterez web mostraba 10.935. La diferencia son exactamente 2 cancelaciones parciales: pasajeros que devolvieron el boleto pero pagaron penalidad. Betterez los sigue contando; nuestro KPI neto no. No hay error de carga — es la regla acordada para medir venta real vs alinear con el ranking de agencias.

8

Cambios de boleto y sucesores

Cómo enlazamos un boleto changed con su reemplazo

Betterez no siempre deja un vínculo explícito entre boleto viejo y nuevo. En BI usamos tres vías de enlace:
Vía 1: cross-transaction (heurística)
Hay un refund_details.type = change en la venta original y aparece un boleto paid candidato en otra transacción (misma persona y misma ruta, dentro de la ventana de tiempo).
Columna: successor_match_method = 'heuristic_unique'
Vía 2: intra-transaction (misma venta)
El boleto changed y su reemplazo paid quedan en la misma venta (sale_id), con misma ruta. Suele ocurrir sin registro de refund.
Columna: successor_match_method = 'same_transaction'
Vía 3: confirmación por API Betterez
Para casos ambiguos o sin match claro, usamos el campo determinístico changedFromTicketId desde API de Betterez para confirmar el reemplazo correcto.
Columna: successor_match_method = 'api'
Las columnas successor_ticket_number y successor_transaction_id permiten hacer drill-down de cambios en dashboards. Si quedan NULL, ese boleto changed no tiene reemplazo identificado o no tiene reemplazo real (por ejemplo, cambio parcial de tramo).
9

Como modelar esto en MicroStrategy

Que atributos y metricas configurar, y con que tabla

Atributos recomendados
Atributo MSTRColumna
Estado efectivoeffective_ticket_status
Pagado neto BIis_paid
Pagado estilo Betterezis_paid_including_partial_cancel
Cancel parcialis_partial_cancel
Cancel totalis_full_cancel
Status OLTP (auditoria)ticket_status — solo usuarios avanzados
fact_ticket vs fact_ticket_mstr
NecesidadTabla
Estados finos, cancel parcial, montos refund fact_ticket
Etiquetas manifiesto (has_*), vista wide MSTR fact_ticket_mstr
Ambas necesidades JOIN por ticket_id
fact_ticket_mstr solo trae is_paid y effective_ticket_status. Para is_partial_cancel u otros flags finos, usar fact_ticket.
Metricas condicionadas (plantillas)
BOLETOS PAGADOS OFICIAL
Count(ticket_id)
donde is_paid = True
y currency = 'ARS'
BOLETOS PAGADOS BETTEREZ
Count(ticket_id)
donde is_paid_including_partial_cancel = True
y currency = 'ARS'
CANCELADOS
Count(ticket_id)
donde effective_ticket_status = 'cancelled'
REVENUE (SOLO INTERURBANO)
Sum(ticket_amount)
donde is_paid = True
y currency = 'ARS'
y product_type = 'reservation'
?

Preguntas frecuentes (negocio)

Respuestas directas para la reunión y para consultar después

¿Por qué el tablero BI no usa directamente lo que dice Betterez?
Porque Betterez guarda la cancelación en un registro aparte (refund_details) y a veces no actualiza el campo status del boleto. Si contáramos solo “status = paid”, incluiríamos ~3.717 boletos cancelados de más. Construimos reglas propias para dar un número neto confiable.
¿La diferencia de 2 boletos con Betterez web es un error?
En la mayoría de los casos, no. Es la diferencia entre contar venta neta (is_paid) vs contar también cancelaciones parciales con penalidad (is_paid_including_partial_cancel). Son reglas de negocio distintas, no fallos de carga de datos.
¿Qué columna debe ver el gerente general en el tablero principal?
is_paid = true para boletos vendidos netos y el mismo filtro para revenue. Es el KPI oficial acordado con operaciones y manifiesto.
¿Un boleto cancelado con penalidad genera ingreso para Andesmar?
Sí. La penalidad retenida está en cancel_penalty_amount. El pasajero recuperó menos de lo que pagó; la diferencia es ingreso para la empresa aunque el boleto no cuente como venta vigente en el KPI neto.
¿Qué pasa con los boletos cambiados?
El boleto original pasa a changed y no cuenta como venta vigente. Si hay reemplazo, las columnas successor_* enlazan al boleto nuevo con método heuristic_unique, same_transaction o api. Si quedan en NULL, el reemplazo no pudo identificarse o el cambio no generó un boleto sucesor directo.
¿Esto es comparable con el sistema Legacy SAP?
No directamente. Legacy y GCP tienen semánticas distintas de cancelados y montos. Esta plataforma está diseñada sobre Betterez + reglas curadas en bi_rebuild. Para comparaciones históricas, usar los informes de reconciliación específicos.
¿Con qué frecuencia se actualizan estos estados?
El ETL incremental corre diariamente (Cloud Run Job). Los boletos cuyo ticket o refund cambió en los últimos días se recalculan. Los datos en MicroStrategy reflejan la última corrida exitosa del ETL.
10

Checklist antes de publicar un reporte con boletos

Verificacion rapida para evitar los errores mas comunes

  • El conteo de boletos usa is_paid (tablero BI) o is_paid_including_partial_cancel (cruce Betterez) segun el KPI
  • El revenue usa el mismo filtro que el conteo de boletos
  • Hay filtro de currency en todas las metricas de dinero
  • Solo interurbano: product_type = 'reservation' aplicado
  • Los cancelados usan effective_ticket_status = 'cancelled' y no solo ticket_status
  • No se usa is_final_paid ni current_status en KPI ejecutivos
  • Si hay montos ARS: cap de $500.000 aplicado para outliers historicos
  • Los estados finos (cancel parcial, refund) vienen de fact_ticket, no solo de fact_ticket_mstr
  • El cubo MSTR fue refrescado si se deployaron columnas nuevas recientemente

Resumen en una sola tabla

Imprimible / consulta rápida post-presentación

Pregunta Filtro correcto No usar
Boletos vendidos (tablero oficial BI) is_paid = true ticket_status, is_final_paid
Boletos segun Betterez web / agencias is_paid_including_partial_cancel = true Solo effective_ticket_status = 'paid'
Revenue de boletos Mismo que conteo + SUM(ticket_amount) + currency Mezclar monedas sin filtro
Cancelados del periodo effective_ticket_status = 'cancelled' Solo ticket_status = 'cancelled'
Cambios / reemision effective_ticket_status = 'changed'
Penalidades retenidas is_partial_cancel = true + SUM(cancel_penalty_amount)
Auditoria payload crudo ticket_status — (solo diagnostico tecnico)