Saltar al contenido principal
Reporter es el motor de reportes de codigo abierto de Lerian que permite a los equipos generar reportes dinamicos basados en datos a traves de plantillas de texto plano simples (archivos .tpl). Las plantillas se renderizan en multiples formatos de salida manteniendo la estructura del documento que usted define. El codigo fuente esta disponible publicamente en GitHub.
Formato de plantillaFormato de salida
.tpl estructurado como CSVArchivo CSV
.tpl estructurado como XMLArchivo XML
.tpl estructurado como HTMLArchivo HTML o PDF
.tpl estructurado como TXTArchivo TXT

Por que usar Reporter?


En lugar de escribir consultas SQL complejas, usted referencia dominios, tablas y campos a traves de marcadores de posicion intuitivos. Esto hace que la creacion de reportes sea mas rapida, flexible y facil de mantener.

Como funciona


Flujo de trabajo

Reporter sigue un flujo de trabajo simple y eficiente que convierte sus plantillas en reportes listos para produccion:
  1. Envie plantillas con filtros y parametros opcionales
  2. Reporter obtiene los datos de las bases de datos configuradas (PostgreSQL, MongoDB)
  3. Se aplica la logica de la plantilla (bucles, condiciones, calculos)
  4. Se genera la salida final en el formato solicitado
Flujo de trabajo de Reporter mostrando el proceso desde la plantilla hasta el reporte renderizado

Arquitectura

Reporter esta construido sobre una arquitectura en capas que mantiene las responsabilidades claras y soporta el crecimiento:
  • Capa de datos: Se conecta a bases de datos a traves de fuentes de datos configuradas. Soporta PostgreSQL y MongoDB, con consultas multi-esquema para PostgreSQL.
  • Capa de logica de negocio: Gestiona el analisis de plantillas, la resolucion de marcadores de posicion y el renderizado.
  • Capa de almacenamiento: Almacena plantillas y reportes generados utilizando almacenamiento de objetos compatible con S3 (AWS S3, MinIO o SeaweedFS).
  • Capa de presentacion: Retorna la salida formateada a traves de APIs RESTful.
Capas de arquitectura de Reporter mostrando la estructura de componentes

Que puede hacer


  • Consultas dinamicas con marcadores de posicion: Referencie cualquier punto de datos a traves de rutas directas — sin necesidad de SQL.
  • Soporte multi-esquema: Consulte tablas en multiples esquemas de PostgreSQL desde una sola plantilla utilizando sintaxis de esquema explicita.
  • Logica de bucles y condiciones: Construya contenido dinamico con bucles for, condicionales if/elif/else y bloques con alcance definido.
  • Operaciones matematicas y agregacion: Realice calculos con sum_by, avg_by, count_by, min_by, max_by, calc y aggregate_balance.
  • Seguimiento de contadores: Rastree y muestre contadores nombrados a lo largo de las iteraciones de la plantilla con counter y counter_show.
  • Filtros de transformacion de datos: Transforme valores en linea con where, sum, count, replace, slice, strip_zeros y percent_of.
  • Procesamiento asincrono: Los reportes pesados se manejan de forma asincrona a traves de una cola de mensajes.
  • Almacenamiento compatible con S3: Las plantillas y reportes se almacenan en cualquier servicio compatible con S3 (AWS S3, MinIO, SeaweedFS).
  • Multiples formatos de salida: Genere salida en CSV, XML, HTML, TXT o PDF desde un unico motor de plantillas.

Modelo de plantilla


Reporter utiliza plantillas que reflejan la estructura del documento final. Los archivos deben tener la extension .tpl independientemente del formato de contenido interno.
Aunque el contenido del archivo debe seguir el formato de salida, asegurese de guardarlo con la extension .tpl. Esto es necesario para que la plantilla funcione correctamente.

Configuracion de su entorno


Las referencias a bases de datos deben renombrarse en el archivo .env del proyecto para evitar conflictos cuando las tablas comparten nombres entre bases de datos. Ejemplo de nomenclatura:
  • midaz_onboarding (PostgreSQL)
  • midaz_onboarding_metadata (MongoDB)

Uso de marcadores de posicion


La estructura de los marcadores de posicion sigue una sintaxis basada en rutas:
{{ base.table_or_collection.field_or_document }}
Esto funciona tanto para bases de datos SQL (tablas y campos) como para MongoDB (colecciones y documentos).

Marcadores de posicion multi-esquema

Cuando su fuente de datos PostgreSQL tiene multiples esquemas, use la sintaxis de esquema explicita para evitar ambiguedades:
{{ base:schema.table.field }}
Por ejemplo:
{{ external_db:sales.orders.total }}
{{ external_db:inventory.items.quantity }}
Si un nombre de tabla existe en un solo esquema, la sintaxis anterior {{ base.table.field }} aun funciona — Reporter descubre automaticamente el esquema correcto. Si una tabla existe en multiples esquemas, Reporter utiliza por defecto el esquema public. Si la tabla no esta en public, Reporter retorna un error con sugerencias:
ambiguous table reference: 'db.orders' exists in multiple schemas: [sales, shipping]
Please use explicit schema syntax:
  {{ db:sales.orders }}
  {{ db:shipping.orders }}

Construccion de plantillas


Bloques comunes

  • Bucle
{% for <item> in <list> %}
  ...
{% endfor %}
  • Bucle con esquema explicito
{% for order in external_db:sales.orders %}
  {{ order.id }} - {{ order.total }}
{% endfor %}
  • Condicion simple
{% if value_a == value_b %}
  ...
{% endif %}
  • Alcance temporal
{% with <object> as <alias> %}
  ...
{% endwith %}
  • Formato de valores
{{ field_name | floatformat:2 }}   --> renders 123.45

Bloques condicionales

BloqueDescripcionEjemplo
IfEjecuta el bloque si la condicion es verdadera{% if condition %}...{% endif %}
If-elseEjecuta un bloque si es verdadero, otro si es falso{% if condition %}...{% else %}...{% endif %}
If-else-ifPermite multiples verificaciones{% if a %}...{% elif b %}...{% else %}...{% endif %}
EqualVerifica si dos valores son iguales{% if a == b %}
Not equalVerifica si dos valores son diferentes{% if a != b %}
Greater thanVerifica si a es mayor que b{% if a > b %}
Less thanVerifica si a es menor que b{% if a < b %}
Greater than or equalVerifica si a es mayor o igual que b{% if a >= b %}
Less than or equalVerifica si a es menor o igual que b{% if a <= b %}
AndRetorna verdadero si ambas condiciones son verdaderas{% if a and b %}
OrRetorna verdadero si al menos una es verdadera{% if a or b %}
NotInvierte el resultado booleano{% if not a %}

Referencia de tags


Tags de agregacion

sum_by — Suma valores numericos de un campo en todos los elementos de una coleccion.
{% sum_by <collection> by <field> %}
{% sum_by <collection> by <field> if <condition> %}
Ejemplo:
<Sum>
  {% sum_by transaction.operation by "amount" if accountAlias != "@external/BRL" %}
</Sum>
count_by — Cuenta el numero de elementos en una coleccion.
{% count_by <collection> %}
{% count_by <collection> if <condition> %}
Ejemplo:
<Count>
  {% count_by transaction.operation if accountAlias != "@external/BRL" %}
</Count>
avg_by — Calcula el promedio de valores numericos en un campo.
{% avg_by <collection> by <field> %}
{% avg_by <collection> by <field> if <condition> %}
min_by — Encuentra el valor numerico minimo en un campo.
{% min_by <collection> by <field> %}
{% min_by <collection> by <field> if <condition> %}
max_by — Encuentra el valor numerico maximo en un campo.
{% max_by <collection> by <field> %}
{% max_by <collection> by <field> if <condition> %}
Todos los tags de agregacion utilizan precision decimal para evitar errores de redondeo de punto flotante. Los campos faltantes o no numericos se omiten. Retorna 0 si ningun elemento coincide.

Tag de fecha y hora

date_time — Muestra la fecha y hora actual formateada segun la cadena de formato proporcionada. La hora se genera en UTC.
{% date_time "<format>" %}
Codigos de formato:
CodigoSignificadoEjemplo
YYYYAno de 4 digitos2025
MMMes de 2 digitos01-12
ddDia de 2 digitos01-31
HHHora de 2 digitos (24h)00-23
mmMinuto de 2 digitos00-59
ssSegundo de 2 digitos00-59
Ejemplos:
{% date_time "YYYY-MM-dd" %}           --> 2025-02-06
{% date_time "dd/MM/YYYY HH:mm:ss" %} --> 06/02/2025 14:30:45

Tag aritmetico

calc — Evalua expresiones matematicas con soporte para variables del contexto de la plantilla.
{% calc <expression> %}
Operadores soportados:
OperadorDescripcionPrecedencia
**ExponenciacionMas alta (derecha a izquierda)
* /Multiplicacion, divisionMedia
+ -Suma, restaMas baja
( )ParentesisAnula la precedencia
Ejemplos:
{% calc 100 + 50 %}                                --> 150
{% calc balance.available * 0.5 %}                 --> calculated value
{% calc (balance.available + 1.2) * balance.on_hold - balance.available / 2 %}
Las variables que no pueden resolverse toman el valor predeterminado 0. La division por cero produce un error.

Tag de agregacion financiera

aggregate_balance — Agrupa elementos por un campo, selecciona la entrada mas reciente por cuenta dentro de cada grupo y suma los saldos. Util para reportes regulatorios que requieren el ultimo saldo por cuenta agrupado por categoria.
{% aggregate_balance <collection> by "<balance_field>" group_by "<group_field>" order_by "<date_field>" [if <condition>] as <result_var> %}
El resultado se almacena en una variable sobre la que puede iterar:
{% aggregate_balance accounts by "balance" group_by "cosif_code" order_by "created_at" as balances %}
{% for b in balances %}
  {{ b.group_value }}: {{ b.balance }} ({{ b.count }} accounts)
{% endfor %}
Cada elemento del resultado contiene:
CampoTipoDescripcion
group_valuestringEl valor del campo group_by
balancedecimalSuma de los ultimos saldos por cuenta en el grupo
countintegerNumero de cuentas en el grupo
Tamano maximo de la coleccion: 100,000 elementos. Los resultados se ordenan por group_value.

Tags de contadores

counter — Incrementa un contador nombrado en 1. No produce salida. Los contadores tienen alcance por renderizado.
{% counter "<counter_name>" %}
counter_show — Muestra la suma de uno o mas contadores nombrados.
{% counter_show "<name1>" %}
{% counter_show "<name1>" "<name2>" "<name3>" %}
Ejemplo:
{% for tx in ledger.transactions %}
  {% counter tx.type %}
{% endfor %}
Total credits: {% counter_show "credit" %}
Total debits: {% counter_show "debit" %}
Combined: {% counter_show "credit" "debit" %}

Referencia de filtros


percent_of

Calcula el porcentaje de un valor en relacion con un total. Retorna una cadena formateada con 2 decimales.
{{ value | percent_of: total }}
Ejemplo: si category.amount = "6.00" y total.expenses = "20.00":
{{ category.amount | percent_of: total.expenses }}  --> 30.00%

strip_zeros

Elimina los ceros finales de un valor numerico sin redondear.
{{ number | strip_zeros }}
Ejemplos:
{{ "100.50000" | strip_zeros }}  --> 100.5
{{ "100.00" | strip_zeros }}     --> 100
{{ "99.990" | strip_zeros }}     --> 99.99

slice

Extrae una subcadena usando indices de inicio y fin (basados en 0).
{{ string | slice:"start:end" }}
Ejemplos:
{{ "hello" | slice:"0:3" }}  --> hel
{{ "12345" | slice:"1:4" }}  --> 234

replace

Reemplaza todas las ocurrencias de una cadena de busqueda con una cadena de reemplazo. Formato: "busqueda:reemplazo".
{{ string | replace:"search:replacement" }}
Ejemplos:
{{ "01310-100" | replace:"-:" }}      --> 01310100   (elimina guiones)
{{ "1234.56" | replace:".:," }}       --> 1234,56    (punto a coma)
{{ "12.345.678/0001-99" | replace:".:" }}  --> 12345678/0001-99

where

Filtra un arreglo de objetos por igualdad de campo. Soporta campos anidados mediante notacion de punto.
{{ array | where:"field:value" }}
Ejemplos:
{{ holders | where:"state:SP" }}
{{ holders | where:"address.state:SP" }}
Uso dentro de bucles:
{% for holder in holders|where:"state:SP" %}
  {{ holder.name }}
{% endfor %}

sum (filtro)

Suma valores numericos de un campo en todos los elementos de un arreglo. Utiliza precision decimal.
{{ array | sum:"field" }}
Ejemplos:
{{ operations | sum:"amount" }}
{{ items | sum:"price.value" }}

count (filtro)

Cuenta los elementos de un arreglo donde un campo coincide con un valor. Soporta campos anidados.
{{ array | count:"field:value" }}
Ejemplos:
{{ operations | count:"nat_oper:6" }}
{{ holders | count:"address.state:SP" }}

contains

Verifica si un valor esta parcialmente incluido en otro. Util cuando los datos incluyen prefijos o sufijos dinamicos.
{% if contains(source_field, target_field) %}
Ejemplo:
  • Origen: 0#@external/BRL
  • Destino: @external/BRL
Retorna true porque @external/BRL existe dentro del valor de origen.

Resumen de operadores y filtros


NombreTipoDescripcion
sum_byTagSuma valores por campo con filtro opcional
count_byTagCuenta elementos con filtro opcional
avg_byTagCalcula el promedio por campo
min_byTagEncuentra el valor minimo
max_byTagEncuentra el valor maximo
date_timeTagFormatea la fecha/hora actual
calcTagEvalua expresiones aritmeticas
aggregate_balanceTagAgregacion de saldos financieros agrupados
counterTagIncrementa un contador nombrado
counter_showTagMuestra el valor del contador
percent_ofFiltroCalcula porcentaje
strip_zerosFiltroElimina ceros finales
sliceFiltroExtrae subcadena
replaceFiltroReemplazo de cadenas
whereFiltroFiltra arreglo por valor de campo
sumFiltroSuma valores de campo del arreglo
countFiltroCuenta elementos coincidentes
containsFuncionCoincidencia parcial de cadenas
floatformatFiltroFormatea decimales

Filtrado avanzado


Al generar un reporte, puede pasar filtros en el cuerpo de la solicitud para acotar los datos. Los filtros siguen una estructura de fuente de datos > tabla > campo: Esquema unico (predeterminado):
{
  "templateId": "00000000-0000-0000-0000-000000000000",
  "filters": {
    "midaz_onboarding": {
      "account": {
        "id": { "eq": ["123", "456"] },
        "createdAt": { "between": ["2023-01-01", "2023-01-31"] },
        "status": { "in": ["active", "pending"] }
      }
    }
  }
}
Multi-esquema (clave explicita esquema.tabla):
{
  "templateId": "00000000-0000-0000-0000-000000000000",
  "filters": {
    "external_db": {
      "sales.orders": {
        "total": { "gt": [100] },
        "created_at": { "gte": ["2025-01-01"] }
      },
      "finance.invoices": {
        "status": { "eq": ["paid"] }
      }
    }
  }
}
Operadores soportados:
OperadorDescripcionEjemplo
eqIgual a{ "eq": ["active", "pending"] }
gtMayor que{ "gt": [100] }
gteMayor o igual que{ "gte": ["2025-06-01"] }
ltMenor que{ "lt": [1000] }
lteMenor o igual que{ "lte": ["2025-06-30"] }
betweenEl valor esta dentro de un rango{ "between": [100, 1000] }
inEl valor esta dentro de una lista{ "in": ["active", "pending"] }
ninEl valor no esta dentro de una lista{ "nin": ["deleted", "archived"] }

Necesita inspiracion?


Consulte la pagina de Ejemplos de plantillas para explorar lo que puede hacer y comenzar a disenar su propia plantilla.

Autenticación y autorización


Reporter no requiere autenticación por defecto, pero se desarrolla con integración nativa al Access Manager. Cuando está habilitado, Access Manager proporciona control de acceso basado en roles (RBAC) para plantillas, reportes y fuentes de datos — ofreciendo control granular sobre quién puede ver, crear o gestionar recursos de reportes.
Access Manager es una funcionalidad opcional disponible en el modelo Enterprise. Para detalles sobre cómo habilitarlo, consulta la documentación de Access Manager.

Próximos pasos