Ir al contenido
FINORA Academy
SistemaFINORA ERP

FINORA ERP · Referencia

FINORA Reportes: informe técnico

En desarrolloImplementadoAvanzado20 minVerificado el 20 oct. 2026

FINORA Reportes (bundle com.finora.lve.reportes, módulo REPORTES, ADR-LVE-020) es el diseñador y motor de reportes de FINORA ERP. Un reporte es una consulta SQL de solo lectura con parámetros con nombre, más sus columnas y, si se quiere, plantillas Excel. Al publicarlo se convierte en un proceso normal de iDempiere: tiene diálogo de parámetros, acceso por rol, entrada de menú y endpoint REST, sin código nuevo. El modelo es el de Jmix Reports (consulta, parámetros, plantillas; el usuario elige el formato al ejecutar) construido sobre el diccionario de iDempiere.

Pieza del coreQué daQué le falta
Print FormatListados de una tabla o vista, exporta PDF y XLSXUna consulta con joins exige crear una vista en la base de datos
JasperReportsDocumentos de diseño fino (recibo, ARC)Diseñar exige Jaspersoft Studio; el Excel sale «pixelado»
FINORA ReportesConsulta + parámetros + columnas + plantillas desde una ventana—

Jasper sigue siendo la herramienta para los documentos con diseño propio (recibo de pago, comprobantes). FINORA Reportes cubre los listados y resúmenes que un administrador quiere crear y ajustar sin desarrolladores.

Diseñador de reportes (ventana) Menú «Reportes» / proceso FVE_RPT_<código> / REST
│ Publicar │
▼ ▼
FVE_ReportDef ── FVE_ReportParam RunReport (clase genérica)
├──────── FVE_ReportColumn │
└──────── FVE_ReportTemplate (+ adjunto .xlsx) ▼
ReportEngine: valida, enlaza, ejecuta en solo lectura
│ filas en streaming
┌──────────┬─────────┴──────────┬────────────┐
▼ ▼ ▼ ▼
PDF (OpenPDF) XLSX (POI SXSSF) XLSX plantilla CSV
  • Sin motor nuevo. OpenPDF 1.3.39 y Apache POI 5.2.2 ya vienen con iDempiere 13 (los usa org.adempiere.base); el bundle los toma por Require-Bundle.
  • Dominio puro y probado. El lector de la consulta, los tipos, los totales, la huella y los cuatro escritores no dependen de iDempiere y tienen pruebas unitarias que releen cada PDF y cada Excel generado.
  • Un solo recorrido de las filas. Los grupos, subtotales, totales y la huella SHA-256 se calculan mientras las filas pasan hacia el escritor; ninguna fila se guarda en memoria salvo en la plantilla Excel, que necesita el libro completo.

Las cuatro tablas son AccessLevel 6 (System + empresa): una empresa ve los reportes del sistema de solo lectura y los suyos con permiso de escritura.

TablaColumnas clave
FVE_ReportDefValue (código único por empresa, [A-Z][A-Z0-9_]{1,39}), Name, Description, Help, FVE_ReportCategory, FVE_ReportSQL, FVE_Orientation (P/L), FVE_OutputFormats (PDF,XLSX,CSV), FVE_DefaultFormat, FVE_GroupColumn, FVE_FileNamePattern, FVE_MaxRows (50 000, tope 1 000 000), AD_Process_ID
FVE_ReportParamColumnName (el marcador), Name (etiqueta), FVE_ParamType (DATE, INTEGER, NUMBER, TEXT, YESNO, RECORD), AD_Table_ID, IsMandatory, IsRange, DefaultValue, SeqNo
FVE_ReportColumnColumnName (alias del SELECT), Name (encabezado), FVE_ColumnType (TEXT, INTEGER, NUMBER, AMOUNT, DATE, PERCENT), IsSummarized, FVE_Width, IsDisplayed, SeqNo
FVE_ReportTemplateName, FVE_TemplateType (XLSX), IsDefault, FVE_TemplateResource (bundle:<bundle>:<ruta>); sin recurso, el .xlsx adjunto

Los códigos CATALOGO y EJECUTAR están reservados para la API. FVE_OutputFormat (lista) tiene los valores PDF, XLSX (Excel automático), XLSXT (Excel con plantilla) y CSV; un reporte que ofrece XLSX también admite su plantilla.

  • Una sola sentencia SELECT o WITH. Un ; final se acepta; texto después de él, no.
  • Marcadores con nombre :Nombre, uno por parámetro. Un parámetro con rango da :Nombre y :Nombre_To. Los del sistema: :AD_Client_ID, :AD_Org_ID, :AD_User_ID, :AD_Role_ID y :Today.
  • :AD_Client_ID es obligatorio: una consulta que no lo usa no se guarda. Así una empresa nunca ve datos de otra.
  • Parámetro opcional vacío = NULL tipado. El patrón es (:X IS NULL OR col = :X). Las fechas viajan como date, los números como numeric y los textos como varchar, de modo que PostgreSQL resuelve el tipo incluso en :X IS NULL.
  • El lector respeta literales ('…', E'…'), nombres entre comillas dobles, bloques $$…$$, comentarios y el :: de los casts: nada de eso se confunde con un marcador.
  • Un ? suelto se rechaza (el driver lo tomaría por marcador); los operadores JSON tienen funciones equivalentes como jsonb_exists.
  • Las columnas salen de la pestaña Columnas (orden, encabezado, tipo, totales, ancho). Si no hay ninguna, de los metadatos del resultado. Los alias se comparan sin distinguir mayúsculas: PostgreSQL los devuelve en minúscula.
SELECT bp.Name AS cliente, o.DocumentNo AS orden, o.DateOrdered AS fecha, o.GrandTotal AS total
FROM C_Order o JOIN C_BPartner bp ON bp.C_BPartner_ID = o.C_BPartner_ID
WHERE o.AD_Client_ID = :AD_Client_ID AND o.IsSOTrx = 'Y' AND o.DocStatus IN ('CO', 'CL')
AND (:DateOrdered IS NULL OR o.DateOrdered >= :DateOrdered)
AND (:DateOrdered_To IS NULL OR o.DateOrdered::date <= :DateOrdered_To)
AND (:C_BPartner_ID IS NULL OR o.C_BPartner_ID = :C_BPartner_ID)
ORDER BY bp.Name, o.DateOrdered
CapaQué hace
Transacción propiaConexión aparte con SET TRANSACTION READ ONLY: una consulta que intenta escribir falla. Siempre se revierte
Tiempo límiteSET LOCAL statement_timeout con FVE_REPORT_TIMEOUT_S (FVE_Config, 120 s por defecto)
Límite de filasFVE_MaxRows (+1 para detectarlo): más filas es un error claro, no un archivo truncado
Funciones prohibidaspg_sleep, pg_terminate_backend, pg_read_file, lo_import, dblink, set_config, bloqueos advisory…
Aislamiento:AD_Client_ID obligatorio
DiseñoLos botones del diseñador exigen lectura y escritura en la ventana Diseñador de reportes, comprobado en el servidor (también por REST)
EjecuciónCada reporte publicado es un AD_Process: se ejecuta con el acceso de proceso del rol
FormatoCómo sale
PDFOpenPDF, A4 vertical u horizontal: logo (organización, luego LogoReport_ID, luego Logo_ID de la empresa), razón social, RIF (perfil fiscal vigente o AD_OrgInfo.TaxID), título, parámetros usados, tabla con cabecera oscura repetida en cada página, filas alternas, grupos con subtotal, total general, pie «Página X de Y» y el inicio de la huella; la huella completa al final
XLSXPOI en streaming (SXSSF, 200 filas en memoria): mismo encabezado, celdas tipadas (#,##0.00, dd/mm/aaaa), paneles fijos, autofiltro, subtotales y total como SUBTOTAL(9,…) (siguen al filtro y no suman dos veces)
XLSXTLa plantilla del usuario (XSSF): la fila con ${COLUMNA} se repite por registro con su estilo y sus fórmulas por fila; se sustituyen ${param.X}, ${report.name}, ${report.code}, ${report.generated}, ${report.user}, ${report.rows}, ${report.sha256}, ${company.name}, ${company.rif} y ${total.COLUMNA}
CSVUTF-8 con BOM, separador ;, coma decimal, fechas dd/mm/aaaa; sin subtotales; un texto que empieza por = + - @ lleva ' delante (inyección de fórmulas)

La huella SHA-256 se calcula sobre los valores mostrados de todas las filas, independiente del formato y de la escala de los números: el mismo dato da la misma huella en PDF, Excel y CSV.

El nombre del archivo sale de FVE_FileNamePattern con ${code}, ${name}, ${date}, ${time} y ${param.X} (por defecto ${code}_${date}_${time}), reducido a letras sin acentos, dígitos, ., _ y -.

ValueClaseQué hace
FVE_ReportRuncom.finora.lve.reportes.process.RunReportLa clase de todo reporte publicado. Busca la definición por AD_Process_ID (la copia de la empresa con el mismo código gana); toma los parámetros por ColumnName, más FVE_OutputFormat, EMail y FVE_ReportTemplate_ID; deja el archivo en exportFile y lo descarga en la web
FVE_ReportPublishPublishReportCrea o actualiza FVE_RPT_<código> (sistema) o FVE_RPT_<empresa>_<código>, sus parámetros, el acceso del rol que publica y la entrada bajo Reportes
FVE_ReportDetectColumnsDetectColumnsDescribe la consulta sin leer filas y crea las columnas que faltan con el tipo deducido
FVE_ReportTemplateBaseGenerateTemplatePlantilla XLSX base, adjunta a una fila nueva de Plantillas
FVE_ReportPreviewPreviewReportPDF con 50 filas y los parámetros por defecto
FVE_ReportCopyCopyReportCopia la definición, sus parámetros, columnas y plantillas a la empresa
FVE_RPT_Catalogoprocess.api.ReportCatalogAPI: reportes que el rol puede ejecutar
FVE_RPT_Ejecutarprocess.api.ExecuteReportAPI: ejecuta un reporte por código

AD_Process y AD_Menu son diccionario del sistema: al publicar un reporte de empresa se escriben como cliente 0, con EntityType U y el id de la empresa en el nombre, y solo los roles con acceso lo ven. Nunca se toca un proceso que vino en el 2Pack de un módulo.

POST /api/v1/processes/fve_rpt_catalogo
{"FVE_ReportCategory": "Nómina"}
POST /api/v1/processes/fve_rpt_ejecutar
{"FVE_ReportCode": "NOM_RESUMEN_CORRIDA", "FVE_OutputFormat": "XLSX",
"FVE_ReportParams": "{\"HR_Process_ID\": 1000042}"}
  • El catálogo responde un objeto JSON por reporte en logs[] (codigo, nombre, categoria, formatos, formato, parametros con nombre, etiqueta, tipo, obligatorio, rango, defecto, tabla) y el resumen {"reportes": n}. Solo lista lo que el rol puede ejecutar.
  • Ejecutar devuelve el archivo en exportFile (base64) y el resumen {"archivo","formato","filas","sha256"}. Las fechas van como AAAA-MM-DD; el fin de un rango, como Nombre_To; un parámetro omitido toma su valor por defecto. Exige el mismo acceso que el menú.
  • Cada reporte publicado es también un proceso REST: POST /api/v1/processes/fve_rpt_<código> con sus parámetros y FVE_OutputFormat.

Cómo declara un módulo sus reportes del sistema

Sección titulada «Cómo declara un módulo sus reportes del sistema»

Un módulo que trae reportes (Nómina es el primero) depende de REPORTES en tres lugares: Require-Bundle del manifiesto, requiredBundles() de su LvePackActivator (para que sus filas se apliquen después de las tablas de reportes) y requires de tools/apps/modules.json, con "reports": true (el publicador del catálogo rechaza un módulo con reportes que no requiera REPORTES). FINORA Aplicaciones instala la dependencia sola.

En un 2Pack de datos del módulo:

  1. Un AD_Process FVE_RPT_<código> con Classname com.finora.lve.reportes.process.RunReport y un AD_Process_Para por parámetro (mismo ColumnName que el marcador; la referencia la elige el módulo: búsqueda, lista, tabla propia o rango), más FVE_OutputFormat (lista uid("AD_Reference","FVE_OutputFormat"), elemento uid("AD_Element","FVE_OutputFormat"), largo 5) y, si se quiere, EMail.
  2. La fila FVE_ReportDef con AD_Client_ID 0 y AD_Process_ID = ese proceso, con sus filas FVE_ReportParam y FVE_ReportColumn, todas con UUID estables.
  3. Su entrada de menú, donde el módulo quiera; el acceso sigue al módulo del rol.
  4. Una plantilla del sistema va en el propio bundle y se declara con FVE_TemplateResource = bundle:<bundle>:<ruta>.

Una empresa que quiere cambiar un reporte del sistema pulsa Copiar a mi empresa: su copia, con el mismo código, reemplaza al original en el menú del módulo, en la API y en el proceso, sin tocar la fila del sistema.