Modos de Reportes en iDempiere
Este documento pretende mostrar diversas modalidades de reportes que pueden utilizarse en Idempiere y disponer de flexibilidad a la hora de construir resultados complejo.
Dentro de las tecnicas mas conocidas se tiene:
De estas dos técnicas existe una amplia información en la Wiki de idempiere y en los diversos foros de la comunidad.
No entraremos en detalles sobre estas dos modalidades, sin embargo se mostrarán metodos y procedimientos no convencionales utilizando Jaspersoft, Codigo Java, ZK y librerías de Apache poi, que se detallan en los diferentes técnicas, de las cuales se detallan.
Métodos alternativos de avanzada:
Código fuente se puede encontrar en:
- iDempiere (fuente):
https://github.com/idempiere/idempiere - Localizaciones y plugins:
https://github.com/luisamesty/Amerpsoft-iDempiere-lve/tree/release-12
Framework Propio
La técnica o framework propio de iDempiere para la creación de reportes y documentos (como facturas, órdenes de compra, etc.) se llama Application Dictionary Reporting o ADempiere Reporting Engine.
⚙️ Concepto y Componentes
Este motor de reportes no se basa en un lenguaje de scripting como Groovy (usado por JasperReports), sino que utiliza la propia estructura de metadatos del Diccionario de Aplicación (AD) de iDempiere.
Los componentes clave de esta técnica son:
- Report & Process (Proceso y Reporte): Define la lógica de negocio (en Java) para obtener los datos. Esta clase se asocia a una ventana de parámetros (
Report & Process/Proceso y Reporte). - Report View (Vista de Reporte): Es una vista de base de datos (
AD_RV_...) que consolida los datos necesarios para el reporte. Esta vista es crucial, ya que el motor de reportes del AD opera directamente sobre ella. - Print Format (Formato de Impresión): Este es el corazón de la técnica. Permite diseñar el diseño del reporte (campos, etiquetas, agrupaciones, totales) completamente desde la interfaz de usuario de iDempiere, sin tocar código ni archivos externos (XML/JRXML).
En resumen, la técnica propia es la configuración de Print Formats sobre Report Views, controlada por la lógica de un Process en el Diccionario de Aplicación.
Distinción Importante
Cuando se habla de la "técnica propia" de iDempiere, se refiere al diseño a través del Print Format del Diccionario de Aplicación.
📄 Jaspersoft
Resumen de Reportes en iDempiere con Jaspersoft
La integración de Jaspersoft (o JasperReports) en iDempiere es el mecanismo estándar para crear reportes con diseño complejo, visualización avanzada, gráficos, y salida PDF/Excel/HTML profesional. Es el motor utilizado para la mayoría de los documentos transaccionales y reportes financieros avanzados, complementando el motor de reportes propio del Diccionario de Aplicación (AD).
Jaspersoft - Proceso de Integración
El flujo para crear y usar un reporte Jaspersoft en iDempiere involucra dos mundos principales: el diseño externo y la configuración interna de iDempiere.
1. Diseño del Reporte (Entorno Externo)
Se utiliza la herramienta de diseño de JasperReports (típicamente Jaspersoft Studio):
- JRXML: El diseñador crea el archivo
.jrxml, que es el código fuente XML que define el diseño, la colocación de campos, las fuentes, los gráficos y los estilos. - Fuente de Datos: El diseñeador usa una consulta SQL o una Report View (
AD_RV_...) para obtener los datos de iDempiere. La consulta debe ser compatible con la estructura de la base de datos de iDempiere. - Compilación: El archivo
.jrxmlse compila en un archivo binario.jasper(el reporte listo para ser ejecutado) que luego se carga en iDempiere.
2. Configuración en iDempiere (Diccionario de Aplicación - AD)
Para que iDempiere ejecute y muestre el reporte, el archivo .jasper debe registrarse y asociarse a un proceso:
| Componente | Configuración | Propósito |
|---|---|---|
Proceso y Reporte (AD_Process) | Se crea un nuevo proceso (Action = P). | Define la ventana de parámetros del usuario (filtros). |
| Parámetros | Se definen los campos de filtro que se enviarán a Jasper (ej. C_BPartner_ID, DateFrom). | Permite la interactividad con el usuario. |
Formato de Impresión (AD_PrintFormat) | Se asocia el AD_Process con un AD_PrintFormat. | Este es el contenedor donde se adjunta el archivo .jasper. |
| Archivo .jasper | Se carga el archivo compilado (.jasper) en el campo Jasper Report del PrintFormat. | Vincula el diseño externo con la ejecución interna. |
Jaspersoft - Ejecución y Visualización
Cuando el usuario selecciona la opción de menú asociada al proceso:
- iDempiere ejecuta la lógica del proceso (si existe).
- Recoge los parámetros de entrada del usuario.
- Ejecuta la consulta SQL definida en el reporte
.jasper, enviando los parámetros (P_DateFrom,P_OrgID, etc.). - El motor de JasperReports genera la salida (PDF, XLSX, etc.).
- El resultado se muestra en el Visor de Jasper (
ZkJRViewer), el cual se abre en una nueva pestaña (GridTab) de la aplicación iDempiere.
🧩 Jasper Java Class Pojo
Este reporte de ejemplo muestra los elementos de cuenta configurados para un cliente específico dentro del esquema contable.
Se basa en una Clase Java POJO. Lee los datos de la base de datos utilizando una Clase Java DataPopulator.
El archivo: src/org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_Pojo.jrxml no está adjunto a un Proceso AD, sino que se lee directamente desde el sistema de archivos (Filesystem).
Los parámetros se leen desde SvrProcess y se inyectan en el archivo de Jaspersoft.
Configuración del Proceso en el Diccionario de Aplicaciones (AD)
Para que este reporte de Java Class POJO sea ejecutable desde el menú de iDempiere, debes registrarlo como un Proceso y/o Reporte. Y posteriomente añadir una entrada de menu a este proceso.
Crear Proceso
| Campo de la Ventana "Proceso y Reporte" | Valor |
|---|---|
| Nombre (Name) | Amfin Account Elements Jasper Java Class Pojo |
| Valor de Búsqueda (Value) | AmfinAccountElementsJasperJavaClassPo |
| Clase (Classname) | org.amerp.reports.jasper.AccountElements_Tree.AccountElements_Tree_Pojo |
| Tipo de Procedimiento | Java |
| Reporte | (Marcar la casilla) |
Parámetros
| Parámetro | Código / Columna | Explicación Detallada |
|---|---|---|
| Cliente / Grupo empresarial | AD_Client_ID | Este parámetro es fundamental para la seguridad y el alcance de los datos. Limita la ejecución del informe a la información que pertenece exclusivamente a la empresa o al grupo de empresas seleccionado. En un entorno multi-tenant, esto garantiza que solo se procesen los elementos de cuenta de la organización correcta. |
| Esquema Contable | C_AcctSchema_ID | Es el parámetro más crucial para definir la estructura del informe. El esquema contable es la plantilla que determina la forma en que una organización registra sus transacciones. Al seleccionarlo, el reporte sabe qué: • Plan de Cuentas (Chart of Accounts) usar. • Reglas contables (ej. devengo vs. caja). • Moneda base y elementos (cuentas, dimensiones) que deben incluirse en el informe. |
Pantalla Parámetros

Clase Java
File: AccountElements_Tree_Pojo.java
La clase Java es un SvrProcess clásico:
public class AccountElements_Tree_Pojo extends SvrProcess implements ProcessCall, ClientProcess{
Preparación de Parámetros (prepare()):
@Override
protected void prepare() {
ProcessInfoParameter[] para = getParameter();
for (ProcessInfoParameter pp : para) {
String name = pp.getParameterName();
if (name.equals("AD_Client_ID")) {
p_AD_Client_ID = pp.getParameterAsInt();
} else if (name.equals("C_AcctSchema_ID")) {
p_C_AcctSchema_ID = pp.getParameterAsInt();
}
}
// Si no se pasaron como parámetro, obtener del contexto actual de iDempiere
if (p_AD_Client_ID == 0) {
p_AD_Client_ID = Env.getAD_Client_ID(Env.getCtx());
}
// Para C_AcctSchema_ID, si no viene como parámetro, podría requerir lógica para obtener el predeterminado
// o ser un parámetro obligatorio en la ventana del proceso. Aquí lo dejamos como 0 si no se pasa.
}
Generación del Reporte (doIt()):
A continuación, se describen los pasos clave dentro del método doIt() (ejecutar):
- Paso 0: Copiar archivos al directorio temporal en el servidor.
// Lista de recursos a copiar
String[] resourcesToCopy = new String[]{
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_Pojo.jrxml",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree.properties",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_es.properties",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_fr.properties"
// Si hay imágenes o subreports, añádelos aquí
};
for (String resource : resourcesToCopy) {
jasperUtils.copyResourceToTmp(resource, tmpFolder);
}
- Paso 1: Obtener los datos para el informe desde la clase
DataPopulator.
// Lista de recursos a copiar
String[] resourcesToCopy = new String[]{
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_Pojo.jrxml",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree.properties",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_es.properties",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_fr.properties"
// Si hay imágenes o subreports, añádelos aquí
};
for (String resource : resourcesToCopy) {
jasperUtils.copyResourceToTmp(resource, tmpFolder);
}
- Paso 2: Compilar el archivo Jasper.
try (InputStream reportStream = new FileInputStream(jrxmlPath)) {
jasperReport = JasperCompileManager.compileReport(reportStream);
log.info("Archivo .jasper cargado exitosamente.");
} catch (Exception e) {
log.log(Level.SEVERE, "Error al cargar y/o compilar el archivo .jrxml desde: " + jrxmlPath, e);
throw e; // Relanza la excepción para que iDempiere la maneje
}
- Paso 3: Crear
JRBeanCollectionDataSource(Fuente de datos basada en una colección de beans).
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(reportData);
log.info("JRBeanCollectionDataSource creado con " + dataSource.getRecordCount() + " registros.");
- Paso 4: Preparar los Parámetros del informe.
Map<String, Object> parameters = new HashMap<>();
parameters.put("AD_Client_ID", p_AD_Client_ID);
parameters.put("C_AcctSchema_ID",p_C_AcctSchema_ID);
parameters.put(JRParameter.REPORT_RESOURCE_BUNDLE, ResourceBundle.getBundle(
"org.amerp.reports.jasper.AccountElements_Tree.AccountElements_Tree",
Locale.getDefault()
));
- Paso 5: Rellenar el informe (Fill report) y llamar al visor
JRViewer.
try {
jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
log.info("Informe de JasperReports llenado exitosamente.");
} catch (JRException e) {
log.log(Level.SEVERE, "Error al llenar el informe de JasperReports.", e);
throw e; // Relanza la excepción
}
....
try (Connection conn = DB.getConnectionRO()) {
// export to viewer
processInfo = getProcessInfo();
printInfo = new PrintInfo(processInfo);
// view the report
JRViewerProvider viewerLauncher = Service.locator().locate(JRViewerProvider.class).getService();
viewerLauncher.openViewer(jasperPrint, processInfo.getTitle(), printInfo);
}
Ejemplo reporte

📄 Jasper Java Class Standard
Este reporte de ejemplo muestra los elementos de cuenta configurados para un cliente específico dentro del esquema contable.
Se basa en una Clase Java Std. Lee los datos utilizando una Consulta SQL definida dentro del archivo .jrxml.
El archivo: src/org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_Std.jrxml no está adjunto a un Proceso AD, sino que se lee directamente desde el sistema de archivos (Filesystem).
Los parámetros se leen desde SvrProcess y se inyectan en el archivo de Jaspersoft.
Configuración del Proceso en el Diccionario de Aplicaciones (AD)
Para que este reporte de Clase Java Estándar sea ejecutable desde el menú de iDempiere/ADempiere, debes registrarlo como un Proceso y/o Reporte en el Diccionario de Aplicaciones. Y posteriomente añadir una entrada de menu a este proceso.
Crear el Proceso
| Campo de la Ventana "Proceso y Reporte" | Valor |
|---|---|
| Nombre (Name) | Amfin Account Elements Jasper Java Class Standard |
| Valor de Búsqueda (Value) | AmfinAccountElementsJasperJavaClassStd |
| Clase (Classname) | org.amerp.reports.jasper.AccountElements_Tree.AccountElements_Tree_Std |
| Tipo de Procedimiento | Java |
| Reporte | (Marcar la casilla) |
Parámetros
- Cliente / Tenant (
AD_Client_ID): Se refiere a la empresa o grupo de empresas que comparten la misma configuración contable. - Esquema Contable (
C_AcctSchema_ID): Define la estructura contable, incluyendo plan de cuentas, reglas, monedas y otras configuraciones financieras.
El informe puede incluir filtros basados en niveles de cuenta, tipos de cuenta o estado (activo/inactivo), dependiendo del esquema contable seleccionado.
Pantalla Parámetros

Clase Java
File: AccountElements_Tree_Std.java
La clase Java es un SvrProcess clásico:
public class AccountElements_Tree_Std extends SvrProcess implements ProcessCall, ClientProcess {
Preparación de Parámetros (prepare()):
for (ProcessInfoParameter param : pip) {
String name = param.getParameterName();
if (param.getParameter() == null)
;
else if ("AD_Client_ID".equalsIgnoreCase(name))
p_AD_Client_ID = param.getParameterAsInt();
else if ("C_AcctSchema_ID".equalsIgnoreCase(name))
p_C_AcctSchema_ID = param.getParameterAsInt();
else
log.severe("Unknown Parameter: " + name);
}
Generación del Reporte (doIt()):
- Paso 0: Copiar archivos al directorio temporal en el servidor.
// Carpeta temporal
JasperUtils jasperUtils = new JasperUtils();
String tmpFolder = jasperUtils.getTempFolder();
// Lista de recursos a copiar
String[] resourcesToCopy = new String[]{
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_Std.jrxml",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree.properties",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_es.properties",
"org/amerp/reports/jasper/AccountElements_Tree/AccountElements_Tree_fr.properties"
// Si hay imágenes o subreports, añádelos aquí
};
// Copiar físicamente cada recurso al tmpFolder
for (String resource : resourcesToCopy) {
jasperUtils.copyResourceToTmp(resource, tmpFolder);
}
- Paso 1: Obtener Parámetros.
try (InputStream reportStream = new FileInputStream(jrxmlPath)) {
JasperReport jasperReport = JasperCompileManager.compileReport(reportStream);
// Parámetros, conexión, etc.
Map<String, Object> parameters = new HashMap<>();
parameters.put("AD_Client_ID", p_AD_Client_ID);
parameters.put("C_AcctSchema_ID",p_C_AcctSchema_ID);
parameters.put(JRParameter.REPORT_RESOURCE_BUNDLE, ResourceBundle.getBundle(
"org.amerp.reports.jasper.AccountElements_Tree.AccountElements_Tree",
Locale.getDefault()
));
- Paso 2: Compilar, generar y desplegar el archivo Jasper.
try (Connection conn = DB.getConnectionRO()) {
jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
// export to viewer
processInfo = getProcessInfo();
printInfo = new PrintInfo(processInfo);
// view the report
JRViewerProvider viewerLauncher = Service.locator().locate(JRViewerProvider.class).getService();
viewerLauncher.openViewer(jasperPrint, processInfo.getTitle(), printInfo);
}
Ejemplo de reporte

📄 Process Class Xlsx
Este reporte de ejemplo muestra los elementos de cuenta configurados para un cliente específico dentro del esquema contable.
Se basa en una Clase Java que utiliza clases Apache POI XLSX para generar un Archivo XLSX. Lee los datos de la Base de Datos utilizando una Clase Java DataPopulator.
El informe se muestra dentro de una ventana de visualización XLSX, lo que permite a los usuarios explorar fácilmente filas y columnas en detalle. También ofrece la opción de descargar el archivo para verlo en Excel o LibreOffice.
Archivos y Proceso
- Clase principal:
org.amerp.reports.xlsx.AccountElements_Tree_ProcXlsx: Clase principal que implementaProcessCallyClientProcess. Lee los parámetros del Proceso AD definido. - Visor:
src/org/amerp/reports/xlsx/ExcelViewerWindow.java: Visor para el archivo Xlsx. - Nombre Proceso AD: Amfin Account Elements Process Class Xlsx.
Los parámetros se leen del Proceso AD asociado y se inyectan en el archivo de la clase principal.
Configuración del Proceso en el Diccionario de Aplicaciones (AD)
Para que este reporte de Proceso Java Xlsx sea ejecutable desde el menú de iDempiere/ADempiere, debes registrarlo como un Proceso y/o Reporte en el Diccionario de Aplicaciones. Y posteriomente añadir una entrada de menu a este proceso.
Crear el Proceso
| Campo de la Ventana "Proceso y Reporte" | Valor |
|---|---|
| Nombre (Name) | Amfin Account Elements Process Class Xlsx |
| Valor de Búsqueda (Value) | AmfinAccountElementsJavaProcXlsx |
| Clase (Classname) | org.amerp.reports.xlsx.AccountElements_Tree_ProcXlsx |
| Tipo de Procedimiento | Java |
| Reporte | (Marcar la casilla) |
Parámetros
- Cliente / Tenant (
AD_Client_ID): Se refiere a la empresa o grupo de empresas que comparten la misma configuración contable. - Esquema Contable (
C_AcctSchema_ID): Define la estructura contable, incluyendo plan de cuentas, reglas, monedas y otras configuraciones financieras.
El informe puede incluir filtros basados en niveles de cuenta, tipos de cuenta o estado (activo/inactivo), dependiendo del esquema contable seleccionado.
Pantalla Parámetros

Clase Java
File: AccountElements_Tree_ProcXlsx.java
La clase Java es una clásica llamada a Proceso (Process Call).
public class AccountElements_Tree_ProcXlsx implements ProcessCall, ClientProcess {
Iniciar Proceso (startProcess(...)):
- Paso 1: Crea el Xlsx (
crearXlsx(..))
try {
// Aquí generas tu Excel
File xlsxFile = crearXlsx(ctx, pInfo, null);
if (xlsxFile == null)
return false;
final String fullPath = xlsxFile.getAbsolutePath();
pInfo.setSummary("Archivo generado: " + fullPath);
- Paso 2: Previsualizar Xlsx (
previewXlsx(xlsxFile))
if (m_processUI != null && xlsxFile != null) {
previewXlsx(xlsxFile);
}
Crear XLsx (crearXlsx(...)):
En este caso particular, utiliza la librería Apache POI Xlsx.
- Importaciones importantes:
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.*;
import org.amerp.reports.xlsx.util.ExcelUtils;
- Método importante del Visor (
openExcelViewerInNewTab(File xlsxFile)):
Utiliza atributos especiales del visor ZK WebUI para desplegar el archivo Xlsx en una pestaña (TAB) de iDempiere.
private void openExcelViewerInNewTab(File xlsxFile) {
try {
// 🖥️ Obtener el escritorio activo
IDesktop desktop = SessionManager.getAppDesktop();
if (desktop != null) {
ExcelViewerWindow viewer = new ExcelViewerWindow(
xlsxFile,
headers,
maxLen,
4,
50000
); // tu constructor
viewer.setAttribute(Window.MODE_KEY, Window.MODE_EMBEDDED);
viewer.setAttribute(Window.INSERT_POSITION_KEY, Window.INSERT_NEXT);
viewer.setAttribute(WindowContainer.DEFER_SET_SELECTED_TAB, Boolean.TRUE);
desktop.registerWindow(viewer);
desktop.showWindow(viewer);
//AEnv.showCenterScreen(viewer);
}
log.info("✅ Visor Excel abierto en nuevo tab: " + xlsxFile.getAbsolutePath());
} catch (Exception e) {
log.warning( "❌ Error al abrir formulario de visor Excel\n\r"+e.getMessage());
}
}
Ejemplo reporte

