Cómo se unen
cdr_pnl hace left-join de submit y final, así que registros sin resultado aún emergen como
PENDING. La exposición en vuelo permanece visible en lugar de excluirse silenciosamente.
cdr_submit
La tabla portadora. La parte 1 es el único registro por mensaje de qué se cobró.
Identidad y forma
El dinero, ambos lados
Todo el dinero es un
bigint de diezmilésimas. Divide entre 10 000 para mostrar; nunca guardes un float.
El dinero vive por completo en part_no = 1. Los segmentos posteriores son filas de entrega sin dinero.
Escribir importes en cada segmento multiplicaría ambos lados por el número de segmentos. Cada consulta de dinero
necesita WHERE part_no = 1.
Dos monedas, y sin conversión
cost_currency y price_currency se registran por lado. FireFlo nunca convierte entre ellas.
Un despliegue que compra en una moneda y vende en otra tiene una columna de margen que no puede sumarse
sin hacer la conversión tú mismo.
Las tres columnas de TLV
NULL significa que nada registró la columna; {} significa registrado y no había ninguno. tlvs_sent es
NULL para cada proveedor no-SMPP.
body, y por qué es habitualmente NULL
Registrado solo si smsg.cdr.body es excerpt o full (V1.31.0). NULL en cada fila en caso contrario, y
en cada fila escrita antes de que la columna existiera.
Buscado con ILIKE sobre un índice trigrama (V1.32.0), siempre combinado con un rango de fechas. Ese índice
necesita pg_trgm; si el usuario de migración no puede crear extensiones, la búsqueda aún funciona, más lentamente.
registered_delivery
El octeto SMPP como lo envió el cliente, crudo en lugar de decodificado. Lleva tres peticiones
independientes y solo algunas se ejecutan.
submit_status y vendor_attempt
Desde V1.40.0. Ahora se escribe una fila cdr_submit por cada intento contra un vendor, no solo el
que finalmente tuvo éxito o falló de forma terminal — un nack reintentable también escribe una.
Antes de esta columna, una tormenta de reintentos solo era visible como un conteo de submits inflado
en el vendor, sin registro de lo que realmente dijo en los intentos que fallaron — vea
Colas y reintentos para el presupuesto de reintentos que
estas filas ahora hacen legible.
(gateway_msg_id, part_no, retry_count, vendor_attempt) es la clave natural desde V1.40.0, ampliada
desde (gateway_msg_id, part_no, retry_count) — retry_count por sí solo no cambia entre reintentos
dentro del worker contra un mismo vendor, así que sin vendor_attempt esas filas colisionarían.
cdr_final y cdr_interim
Resultados y progreso, divididos por la razón anterior. También tienen tiempos de vida diferentes:
dlr_state guarda el valor SMPP crudo junto al resultado grueso, porque EXPIRED, REJECTD y
UNDELIV facturan todos como fallos pero significan cosas diferentes.
cdr_rejected
Una fila por rechazo, con reason y (desde V1.27.0) el código de estado del proveedor donde el proveedor fue
quien rechazó.
Una fila rechazada no lleva dinero. price, cost y margin son NULL porque el crédito se
devolvió en el momento del rechazo. Que es lo que permite que las consultas de ingresos sumen esas columnas sin un
filtro de resultado.
usage_daily
Una fila por cuenta, por producto, por día. Diaria en lugar de mensual así que cualquier período es un SUM sobre
días, para siempre, sin una segunda tabla derivada con la que discrepar.
Las columnas facturables para un día terminado son finales; las columnas de entrega se reformulan re-ejecutando el
rollup, que es por lo que es idempotente.
Relacionado
Registros de llamada
Para qué es cada tabla, en prosa.
Tablas de configuración
La otra mitad del esquema.