Introducción
Los informes se utilizan para obtener copias impresas de la información almacenada en la base de datos del sistema. Como en otros elementos de Axapta, podemos introducir código en los informes para ampliar su funcionalidad.
Existen distintos ámbitos en los informes donde podemos añadir código:
- Informe propiamente dicho
- Consulta del origen de datos del informe
- Secciones del informe
Dependiendo de la funcionalidad que queramos implementar en el informe, escribiremos el código en un ámbito o en otro. No obstante, normalmente, se siguen las siguientes reglas:
- Codificamos en los métodos del propio informe, cuando queremos controlar la funcionalidad general del mismo.
- Codificamos en los métodos de la consulta del origen de datos, cuando queremos controlar la funcionalidad de los datos que aparecen en el informe.
- Codificamos en las secciones del informe, cuando queremos controlar la funcionalidad de alguna de las secciones o el comportamiento de alguno de los elementos específicos que aparecen en el informe.
Variables del sistema
Tal y como ocurría con los formularios, cuando trabajamos con los informes, algunas variables son declaradas implícitamente por el sistema.
Además de estas variables, es conveniente recordar que en cualquier momento, la variable this nos da acceso al elemento al que pertenece el método que estamos modificando.
A continuación se describen las variables de sistema de los informes y los elementos a los que dan acceso:
Informe
Una variable llamada element de tipo ReportRun referencia al objeto informe al completo.
Tabla
Por cada uno de los orígenes de datos del informe tendremos una variable con el nombre del origen de datos, que nos referencia la tabla asociada a dicho origen de datos. En realidad, en un momento dado esta variable nos da acceso al registro activo.
Suponiendo que tuviéramos un origen de datos que se llamara DatosInforme, tendríamos una variable con ese nombre que haría referencia a la tabla. Esta variable nos permite hacer dos cosas:
1. Llamar a un método definido en la tabla. Por ejemplo:
DatosInforme.insert();
2. Hacer referencia a los campos individuales de la tabla. Por ejemplo:
number = DatosInforme.accountNo;
Consulta
Existen dos variables que nos dan acceso a la consulta de un informe:
Una variable llamada QUERY de tipo Query, que hace referencia a las propiedades y los métodos de la consulta del informe. Esto nos da la posibilidad de ejecutar directamente sus métodos. Por ejemplo:
query.levelNo(1);
Una variable llamada QUERYRUN de tipo QueryRun, que hace referencia a las propiedades y métodos de una instancia en ejecución de la consulta del informe. Esto nos da la posibilidad de ejecutar directamente sus métodos. Por ejemplo:
queryRun.getNo(1);
A pesar de que se existen estas variables, declaradas automáticamente por el sistema, podemos acceder a los elementos que referencian de la forma tradicional, es decir, desde código haciendo uso de los métodos de la clase de sistema ReportRun.
Así, por ejemplo, desde un método del informe podemos acceder a la consulta del siguiente modo:
Ejemplo de acceso a una consulta
Query q;
;
q = this.query();
q.levelNo(1);
Ejemplo de acceso a la instancia en ejecución de una consulta
QueryRun qr;
;
qr = this.queryRun();
qr.getNo(1);
En ambos casos la variable this haría referencia al objeto en ejecución en ese momento, es decir, al informe.
Métodos del informe
Cuando creamos un nuevo informe se crea automáticamente un nodo de métodos.
El nodo contiene lo que se denomina métodos virtuales, que son métodos implementados en MorphX, pero que pueden ser sobrecargados para cambiar el comportamiento por defecto de los formularios. En estos métodos la función llamada super() activa la ejecución del método implementado por MorphX.
Lista de métodos
En un informe podemos encontrar los siguientes métodos de sistema:
Finalize |
- Se ejecuta cuando ya no se necesita la instancia del informe en ejecución. |
Prompt |
- Se ejecuta para solicitar al usuario que elija el medio (papel, pantalla, archivo) y otra información de impresión. |
Init |
- Se ejecuta cuando se crea un informe. |
Run |
- Se ejecuta para poner en funcionamiento el informe. |
Fetch |
- Se ejecuta para recuperar registros de la base de datos. |
Print |
- Se ejecuta para imprimir el informe en el medio de impresión seleccionado. |
Send |
- Se ejecuta para enviar los registros recuperados por la consulta a las distintas secciones del informe. |
SetTarget |
- Se ejecuta por el formulario SysPrintForm cuando cambiamos de medio de impresión. |
GetTarget |
- Se ejecuta por el formulario SysPrintForm cuando cambiamos de medio de impresión. |
PrinterSettings |
- Se ejecuta cuando seleccionamos la opciones de impresión en un menú o a través del formulario SysPrintForm. |
Caption |
- Se ejecuta cuando se pone en marcha el informe y determina el título de la ventana de visualización preliminar del informe. |
CreateProgressForm |
- Se ejecuta cuando se crea una ventana que indica el progreso en la construcción del informe. |
ProgressInfo |
- Se ejecuta cada vez que se va a actualizar la ventana de progreso. |
Métodos principales y su función
A continuación vamos a describir algunos de los métodos más utilizados en los informes, que por su importancia merecen un tratamiento algo más exhaustivo.
Método ClassDeclaration
En éste método se definen las variables globales del informe que son accesibles desde cualquier método del informe o de cualquier sección del mismo. Los métodos de la consulta no tienen acceso a estas variables globales.
Método Init
El método Init se ejecuta cuando abrimos un informe.
La llamada al método super() crea una instancia en ejecución del informe. Es automáticamente activado después de un método new. En el método Init, se inicializan las variables específicas de dicho informe.
Como ejemplo, tenemos el método Init del informe CustRevenue.
Ejemplo de método Init
public void init()
{
super();
custRevenueReport = element.args().caller();
if (!custRevenueReport)
throw error(strfmt("@SYS22338",funcname()));
}
Método Prompt
El método Prompt se ejecuta para solicitar al usuario que elija el medio de impresión. Se muestra un diálogo en pantalla, donde podemos elegir entre las distintas opciones de impresión.
Si el programador no quiere que aparezca este diálogo, el método Prompt puede sobrecargarse, de manera que no realice la llamada a super(). No hay que confundir este método con el método del mismo nombre de una consulta. Como ejemplo, tenemos el método Prompt del informe Cheque.
Ejemplo de método Prompt
boolean prompt()
{
boolean ret;
;
if (chequeCopy)
ret = true;
else
ret = super();
return ret;
}
Método Run
El método Run se ejecuta cuando abrimos un informe, inmediatamente después del método Init, para poner en funcionamiento el informe.
La versión no sobrecargada de este método realiza cinco tareas en la siguiente secuencia:
- Llamar al método Prompt
- Crear un diseño básico para el informe, si aún no existe
- Organizar los campos en el informe
- Llamar al método Fetch
- Llamar al método Print
Antes de la llamada al método super() podríamos hacer algunas tareas habituales, como por ejemplo modificar la consulta del informe. Como ejemplo, tenemos el método Run del informe ForecastSalesActual.
Ejemplo de método Run
public void run()
{
ReportStringControl ctrlBudget;
ReportStringControl ctrlActual;
;
ctrlBudget = element.design().controlName('BudgetInterval');
ctrlBudget.leftValue(ctrlBudgetQty.leftValue());
ctrlActual = element.design().controlName('ActualInterval');
ctrlActual.leftValue(ctrlActualQty.leftValue());
super();
}
Secuencia de ejecución de métodos
En la siguiente figura se muestra la secuencia de ejecución de métodos cuando abrimos un informe:

Figura 12. Secuencia de ejecución de métodos en un informe.
El orden en el que se ejecutan los métodos es el siguiente:
1. Se activa el método Init del informe, para inicializarlo.
2. Se activa el método Run del informe.
3. Se activa el método Prompt del informe, para permitir al usuario interactuar con él.
4. Se activa el método Fetch del informe.
- Se activa el método Print del informe.
Selección del diseño de un informe
Los informes en MorphX pueden tener más de un diseño. Podemos utilizar esto para tener distintas versiones del mismo informe. Por ejemplo, podemos tener un informe con dos diseños, donde el primero imprimiría con orientación vertical y el segundo con orientación horizontal o apaisada.
Cuando imprimimos un informe, el primer diseño es el utilizado por defecto. Sin embargo, en tiempo de ejecución podemos abrir un diseño específico en función de alguna condición. Para ello utilizaremos el método design() de la clase ReporRun.
Como ejemplo, veamos parte del método Init del informe SalesInvoice, correspondiente a las facturas de venta:
Ejemplo
void init()
{
super();
...
switch(SalesParameters::find().prePrintLevelInvoice)
{
case(PrePrintLevel::BlankPaper):
element.design('BlankPaper');
break;
case(PrePrintLevel::SemiPrePrinted):
element.design('SemiPrePrinted');
break;
case(PrePrintLevel::PrePrinted):
element.design('PrePrinted');
break;
}
...
}
Métodos Fetch y Send
La consulta, utilizada para recuperar registros de la base de datos, y el diseño de un informe son dos elementos independientes. Estos dos elementos, sólo interaccionan de manera dinámica mediante los métodos que vamos a definir en este apartado.
La consulta puede hacer referencia al informe utilizando la variable predefinida element. Si lo necesitamos, el informe puede acceder a la consulta, utilizando la variable query.
Los métodos Fetch y Send son una parte central del motor de los informes en MorphX. El método Fetch recoge los registros definidos por la consulta del informe, y el método Send envía los registros recogidos al diseño del informe.
El método Fetch es el principal bucle de un informe. Si los datos que se van a mostrar en el informe deben cumplir restricciones especiales, el programador puede sobrecargar el método Fetch.
La estructura básica del método Fetch es la siguiente:
QueryRun qr = new QueryRun(report);
// Abrir el diálogo prompt
if (qr.prompt()) // el usuario no ha pulsado el botón de cancelar
{
while (qr.next())
{
file = qr.get(file); // Para todos los orígenes de datos
send(file):
}
}
Si sólo queremos imprimir registros que satisfacen condiciones especiales, que sean difíciles de expresar como un rango en la consulta, debemos escribir el código situado arriba, y solo permitir la llamada al método Send si la restricción (expresada como una función con el mismo nombre en el ejemplo de abajo) se satisface.
while (qr.next())
{
file = qr.get(file); // Para todos los orígenes de datos
if (restricción())
send(file);
}
A continuación presentamos un ejemplo del método Fetch del informe Cheque.
Ejemplo de método fetch
boolean fetch()
{
QueryRun query;
;
query = new QueryRun(this);
if (query.prompt() && element.prompt())
{
query.setRecord(tmpCheque);
while (query.next())
{
tmpChequePrintout = query.getNo(1);
this.send(tmpChequePrintout);
}
return true;
}
return false;
}
El método Send es una conexión entre la consulta y la parte visual del informe. El método Send envía los registros recogidos a las secciones del cuerpo (body sections) del informe.
Podemos ver un esquema del flujo de información en los informes en el dibujo siguiente:

Figura 13. Flujo de información en un informe.
En la figura podemos ver cómo los datos se envían desde la tabla a la consulta del formulario mediante el método Fetch, y después como se enlazan esos datos con los controles del diseño del informe mediante el método Send.
Métodos en la consulta
En la Guía del desarrollador de Axapta podemos encontrar la lista completa de métodos de las consultas. En este apartado vamos a ver únicamente los más importantes.
Método ClassDeclaration
En éste método se definen las variables globales de la consulta, que serán accesibles únicamente por sus métodos.
Método Init
El método Init incializa la consulta del informe cuando ésta se ejecuta.
Método Prompt
La ejecución de este método presenta un diálogo en pantalla, donde el usuario podrá determinar los rangos de selección de registros, el orden en que éstos deben presentarse, etc.
La llamada al método super(), abre el formulario definido en la propiedad Form de la consulta. Por defecto, esta propiedad toma el valor SysQueryForm.
Si el programador no quiere que aparezca este diálogo, el método Prompt puede sobrecargarse, de manera que no realice la llamada a super(). Como ejemplo, tenemos el método Prompt del informe Cheque.
Ejemplo de método Prompt
boolean prompt()
{
boolean ret;
;
ret = true; //No muestra la ventana
return ret;
}
Método Run
El método Run se ejecuta cuando ejecutamos la consulta de un informe desde el Arbol de Objetos de la Aplicación.
Métodos en secciones de un informe
Las secciones determinan la apariencia de un informe en MorphX. Estas secciones, pueden ser definidas por una plantilla o directamente en el diseño particular de un informe. Todas las secciones pueden ser repetidas un número determinado de veces, según las necesidades del usuario.
En la tabla siguiente se presentan las diferentes secciones que pueden componer un informe:
Prólogo
(Prolog) |
- Aparece al principio de un informe. Se utiliza para mostrar elementos, como por ejemplo el logotipo, el título del informe, o la fecha actual. El prólogo se imprime antes que el encabezado de página, en la primera página del informe. |
Encabezado de página
(Page Header) |
- Aparece al principio de cualquier página de un informe. |
Encabezado
(Header) |
- Aparece al principio de un nuevo grupo de registros. Se utiliza para mostrar elementos, como por ejemplo el nombre de un grupo. |
Sección
(Section Group) |
- Aparece en la parte central de un informe. Una sección puede contener un encabezado, un cuerpo y un pie.
- Es importante señalar, que la estructura de los orígenes de datos se ve reflejada en la estructura de las secciones. |
Cuerpo
(Body) |
- Aparece en la parte central de un informe. Un cuerpo contiene controles o una sección. Los controles muestran la información de los campos de los orígenes de datos. |
Pie
(Footer) |
- Aparece al final de un grupo de registros. Se utiliza para mostrar, por ejemplo, subtotales. |
Pie de página
(Page Footer) |
- Aparece al final de cada página de un informe. Se utiliza para mostrar, por ejemplo, números de página. |
Epílogo
(Epilog) |
- Aparece al final de un informe. El epílogo se imprime justo después del pie de página de la última página del informe. |
Sección programable
(Programmable Section) |
- Podemos utilizar secciones programables para añadir cualquier tipo de información personalizada a nuestros informes. Para activar una sección programable, lo hacemos mediante la llamada explícita al método execute. |
Por lo tanto, la estructura de un informe sería la siguiente:
[Prolog]
[Page Header]
[Section Group]
[Header]
[Body]
[Footer]
[Section Group]
[Header]
[Body]
[Footer]
…
[Page Footer]
[Epilog]
En cualquier lugar del informe podemos definir Secciones programables. De la misma manera, en cualquier sección del diseño de un informe, podemos crear métodos de tipo display, que nos permitirían producir la información que quisiéramos mostrar en dicho informe.
En el diseño de un informe, debajo de cada sección, existe un método llamado ExecuteSection. Cuando ejecutamos el método super(), dentro de un método de este tipo, se imprime la información de dicho sector. En determinadas situaciones, nos interesa controlar si la información de una sección queremos que se imprima o no, de acuerdo con algún criterio que nosotros mismos definimos. Esto se consigue haciendo que la llamada al método super() se realice dentro de una instrucción condicional.
También podemos utilizar el método ExecuteSection para esconder o mostrar controles de un informe en tiempo de ejecución.
Otra utilidad común de los métodos ExecuteSection es insertar un salto de página. Por ejemplo, para insertar un salto de página entre el prólogo y las páginas siguientes, debemos insertar la instrucción element.newPage() después de la llamada al método super() en el método ExecuteSection del prólogo.
Acceso a los controles desde el código
En algunas ocasiones puede interesarnos modificar alguna propiedad de un control en tiempo de ejecución.
Para poder acceder a los controles de un informe, lo primero que tenemos que hacer es declarar una variable del tipo correspondiente en el método ClassDeclaration:
Ejemplo declaración de controles
public class ReportRun extends ObjectRun
{
ReportSection reportSection;
ReportTextControl textControl;
}
A continuación debemos asignar a esa variable de tipo control el control del informe. Supondremos que tenemos una sección llamada Prolog_1 y dentro de ella un control de tipo texto llamado PrologText1. Realizaríamos la asignación con una instrucción como la siguiente:
Ejemplo de asignación de control a una variable
public void init()
{
reportSection = element.design().sectionName("Prolog_1");
textControl = reportSection.controlName("PrologText1");
}
Hay que destacar que en los controles de los informes no tenemos la propiedad de declaración automática (Autodeclaration), lo que hará, que tengamos de declarar variables para todos los controles del informe a los que queramos acceder en tiempo de ejecución.
Volver |