Este documento describe diferentes tipos de reportes y procedimientos en GeneXus, incluyendo sus características, comandos como For Each y filtros. Explica cómo se pueden crear reportes de forma declarativa e independiente de la base de datos, además de incluir filtros y parámetros. También cubre temas como For Each anidados, diseño de salida y el uso del Report Viewer.
12. Otros comandos If <Cond> ... [Else] ... endif Do while <Cond> ... Enddo Do case Case <Cond> ... [ Case <Cond>] ... Otherwise ... Endcase For &<var>=<Expresion> To <Expresion> [ Step <Integer>] ... Endfor
13.
14.
15.
16.
17.
Hinweis der Redaktion
Reportes: Definen procesos no interactivos de consulta a la base de datos. Los reporte s son listado s que pueden emitirse por impresora, visualiza rse por pantalla , o seleccionar que la salida sea a un archivo. Procedimientos: Definen procesos no interactivos de actualización de la base de datos. Los Procedimientos pueden hacer todo lo que los Rep o rte s hacen y además actualizar la base de datos.
Definición Procedural A diferencia de las transacciones donde las especificaciones se realizan en forma declarativa y GeneXus resuelve en el momento de generar el programa la secuencia de ejecución, en los reportes y procedimientos , las especificaciones son realizadas en forma procedural. Definición sobre la Base de Conocimiento La gran protencia del lenguaje de reportes/procedimientos es que las definiciones se hacen sobre la Base de Conocimiento y no directamente sobre el modelo físico. Esto nos permite utilizar automáticamente todo el conocimiento ya incorporado o generado por GeneXus a partir de las especificaciones realizadas. Por ejemplo, el concepto de tabla extendida, que es posible porque GeneXus conoce las relaciones entre las tablas de la Base de Datos. Otro ejemplo claro, es el caso de los atributos fórmulas, donde aprovechamos que GeneXus sabe como calcular el valor para este atributo. Independencia de la Base de Datos, definición a nivel de atributos La definición de Reportes y Procedimientos se hace a nivel de atributos, en ningún momento decimos qué tablas se deben recorrer ni qué índices se deben utilizar, sino que esto es determinado por GeneXus en base a las especificaciones realizadas. De esta manera logramos una real independencia de la base de datos, ya que cualquier cambio en las tablas será manejado automáticamente por GeneXus .
Toda la definición del acceso a la base de datos y la estructura del reporte o procedimiento , se realizan solo con este comando. Utilizando el comando FOR EACH se define la información que se va a leer de la base de datos, pero la forma de hacerlo se basa en nombrar los atributos a utilizar y NUNCA se especifican nombres de tablas ni nombres de índices. Con este comando se define QUE atributos se necesitan y en qué ORDEN se quiere recuperar la información. Luego GeneXus se encarga de encontrar COMO hacerlo. El acceso a la base de datos queda especificado por los atributos que son utilizados dentro de un grupo FOR EACH - ENDFOR. Para ese conjunto de atributos GeneXus buscará la tabla extendida mínima que los contenga (el concepto de tabla extendida es muy importante en este comando y sugerimos repasar su definición). Order : Lista de atributos que indican el orden de recorrida de la tabla base. Sólo pueden mencionarse atributos almacenados en la tabla base . El Order es opcional, en caso de no especificarse se asume el orden de la clave primaria de la tabla base (si es que el for each no está anidado a otro for each, como veremos luego). Elección del índice : GeneXus eli g e automáticamente el índice a utilizar para satisfacer el orden. En caso de que no exista , crea el índice en forma temporal. Where : Permite e stablece r condiciones de filtro en la recorrida de la información. Se pueden mencionar tanto atributos de la tabla base como de la tabla extendida.
GeneXus infiere la tabla base del for each, por los atributos mencionados en el order, where, defined by y en el cuerpo del for each. Tomemos como ejemplo un reporte con la siguiente definición:
El Msg se ejecuta sólo cuando no se entra en el For Each, es decir, cuando no hay ningún registro correspondiente a la tabla base del for each para el que se cumplan las condiciones de filtro. También se aplica a For Each [Selected] Line, XFor Each y XFor First, los cuales veremos más adelante. Importante: Si se incluyen For Eachs dentro del When None no se infieren Joins ni filtros de ningún tipo con respecto al For each que contiene el When None, ya que son considerados dos For Each paralelos .
Los For Each se pueden definir en forma paralela o anidada. En el ejemplo hemos definido dos for eachs paralelos. El primero recorrerá todas las facturas y el segundo todos los recibos.
Al encontrar for eachs anidados, GeneXus determina la tabla base de cada uno. Para el caso del for each principal, la tabla base queda determinada estudiando los atributos utilizados en el cuerpo del For each (no considerando los for each anidados que pueda contener). Es decir, en base a los atributos que aparezcan en las cláusulas Order, Where, Defined by, y en el propio cuerpo del For each. GeneXus encuentra la tabla extendida mínima que los contiene, y define la tabla base a través de la cual llegaría a todas las demás. Para el caso de los For each anidados, GeneXus se fija si los atributos utilizados dentro del cuerpo del for each están incluidos o no dentro de la tabla extendida previamente determinada, del for each principal. En caso afirmativo, GeneXus determina que la tabla base del for each subordinado será la misma que la del for each principal (Corte de Control). En caso contrario, la tabla base se determina análogamente a como se hace para el for each principal, es decir, se determina como si el for each no estuviera anidado a nadie. De la determinación de las tablas bases, pueden darse 3 casos, que son los enumerados en la transparencia.
GeneXus determina la tabla base de cada for each, y luego intenta determinar atributos en común entre la tabla extendida del for each principal y la tabla base del for each anidado. Si encuentra atributos en común, define que estos atributos actuarán como condiciones de filtro en la recorrida de la tabla anidada. En este ejemplo, la tabla base del primer for each es CLIENTES, y la del segundo, FACTURAS. Ambas tablas están relacionadas por el atributo CliCod . Navegación: For Each CLIENTES (Line: 8) Index: ICLIENTES Order: CliCod Navigation filters: Start from: FirstRecord Loop while: NotEndOfTable CLIENTES ( CliCod ) For Each FACTURAS (Line: 10) Index: IFACTURAS2 Order: CliCod Navigation filters: Start from: CliCod=CliCod Loop while: CliCod=CliCod FACTURAS ( FacNro ) Vertical Formulas: Navigation to evaluate: FacSubTot FACTURAS ( FacNro ) FACTURAS1 ( FacNro )
Producto Cartesiano: Para cada registro de la tabla base del primer For Each se recorre toda la tabla asociada al For Each anidado.
Corte de Control La resolución de este reporte puede hacerse accediendo únicamente a las facturas, recorriendo la tabla ordenada por cliente. En este caso imprimiríamos solo aquellos clientes que tienen facturas. De todas maneras es necesario utilizar dos for eachs, ya que se necesita una instancia de corte, es decir un momento en el que se cambia de cliente y se puede operar en consecuencia, por ejemplo imprimir el total facturado al cliente. Lo interesante del caso es que los dos for eachs tendrán como tabla base la tabla FACTURAS. Para lograr esto se puede utilizar la cláusula DEFINED BY del For each o el comando PRINT IF DETAIL . En el ejemplo podríamos mencionar un atributo de la tabla FACTURAS en el Defined by, con lo que estaríamos diciéndole explícitamente a GeneXus que utili ce dicha tabla. Si utilizamos el comando Print if detail, debemos definirlo en el primer For Each. Se debe definir además en el orden de recorrida del primer for each (cláusula ORDER), los atributos por los que se quiere realizar el corte (en el ejemplo: CliCod ). Este es un requerimiento, debido a que GeneXus no podría saber cuál es el criterio de agrupación que queremos, ya que en una misma tabla pueden ser varios, por ejemplo, podríamos querer realizar el corte de control por Fecha de factura, calculando el total facturado cada día. Debido a esto es que la definición de la cláusula Order es fundamental .
En el lenguaje de reportes y procedimientos existen también los comandos de control usuales. Ellos son: If : De acuerdo a la evaluación de la condición que aparece, se ejecuta uno de los bloques de código (y/o impresión) que siguen al If, si la condición da True, o al Else, en caso de existir esta cláusula, y si la condición da false. Ejemplo: if &opcion=4 call( PAltaCli ) Else Return Endif Do while : Causa la repetición del código que aparece delimitado por el do while y el enddo mientras la condición sea satisfecha. Para forzar una salida del comando, puede utilizarse el comando Exit dentro del mismo. Ejemplo: &i = 1 //se desea imprimir dos veces los datos del cliente 3 do while &i <= 2 For each where CliCod = 3 endfor enddo CliCod CliNom CliDir
En reportes y procedimientos existen un número reducido de reglas. Entre ellas están: Default : Asigna un valor por defecto a una variable. El valor puede ser un literal entre comillas, un número, o una de las funciones: Today(), Date() o SysDate(), debiendo coincidir el tipo de datos del valor, con el tipo de datos de la variable. Default( &<var>, <valor>); Output_file : Determina el nombre de la salida de un reporte o procedimiento, ya sea que ésta sea a archivo, pantalla, o impresora. Está disponible para reportes y procedimientos generados para el Report Viewer (vb, vfp, Java). El Report Viewer se verá unas hojas más adelante. Output_file( “nombre”|<att>|&<var>, “formato”); Cuando la salida es a archivo, por medio de esta regla se puede configurar que se genere un archivo con el “nombre” especificado y con cierto formato, entre los siguientes: “gxr” ( formato nativo), “rtf” (rich text format), “txt” ( text file), “xml”, “pdf”. El nombre puede ser un literal que indique el path del archivo a ser generado. Con la propertie “Report Output” de estos objetos se puede configurar el tipo de salida que tendrá el objeto. El valor por defecto de esta propertie es “Ask user” pero también se puede cambiar a “Only to File”.
El diseño del layout consiste en dos pasos: 1.- Requiere de una estructura de datos en la cual hay que incluir atributos . Dicha estructura es muy similar a la usada en las transacciones, sin embargo, los paréntesis se usan para indicar niveles de For Each ( en vez de niveles de una transacción ) y el asterisco (*) se usa para indicar el orden deseado (y no para indicar la unicidad como en las transacciones). Una vez que se definió correctamente la estructura, se presiona el botón de “Next” para pasar al siguiente paso. 2.- Permite definir otras características del layout. Se permite elegir los fonts para representar los atributos o textos, también se permite definir si los cabezales de los atributos para cada uno de los niveles se despliegan horizontalmente o verticalmente. Presionando el botón de “Finish” se graban las definiciones y se sale del diálogo del Report Wizard. Una vez que todas las opciones del Wizard fueron aceptadas, se genera el layout del reporte, el cuál puede ser modificado como cualquier otro reporte. También es posible editar el Wizard mediante la opción : Edit/Report/Proc. Wizard. El Wizard permite que los niveles tengan o no orden . El atributo que indica el orden no tiene por qué ser el primero del nivel.
Como filtrar la información a recuperar de la base de datos Muchas veces es necesario filtrar la información a incluir en el reporte, por ejemplo, supongamos que el reporte deberá listar sólo aquellos clientes cuyo código esté comprendido en un rango determinado. Para resolver esto, tenemos dos opciones: * El uso de condiciones * El uso de la cláusula where en el FOR EACH La única diferencia entre usar Condi ciones y la cláusula Where, es que la primera es global para todos los FOR EACH que definamos y la segunda se aplica sólo para el FOR EACH donde está definida. La performance es la misma en ambos casos. Debemos escoger una de las dos opciones. La regla PARM() La utilización de atributos en la regla PARM() determina condici ones de filtro por igualdad , global es para todo el reporte o procedimiento. Ejemplo: PARM( CliCod ) . For Each [ CliCod ] [ CliNom ] Endfor El reporte sólo acceder á al cliente cuyo código sea igual al recibido como parámetro.
MT [nlínea]: nlíneas es el número de línea en el que se quiere empezar a imprimir el listado. En caso de no especificarse un valor se asume el valor por defecto que es 0. MB [nlínea]: nlíneas es el número de líneas que se desea dejar como margen inferior. En caso de no especificarse un valor se asume el valor por defecto que es 6. PL [nlínea] : Setea el largo de página. El número de líneas que será impreso es el número especificado menos el margen de abajo (valor por defecto es 6). Ej: PL 66 Setea el largo de página a 66 líneas, aunque sólo 60 líneas serán impresas en el form, con un margen inferior de 6 líneas. CP [nlínea] : Si queda en la página actual un número de líneas mayor o igual al número especificado, continúa imprimiendo en la misma página. De lo contrario, pasa a imprimir en la próxima página (fuerza a un salto de página). Lineno [nlínea] : Define el número de línea donde va a ser impresa la siguiente línea. Si el número de línea actual es mayor al número especificado, entonces, la línea será impresa en la próxima página. Eject : Fuerza a un salto de página. Noskip : Tiene que estar inmediatamente después de un printblock. Si el comando se encuentra entre dos líneas, este comando las imprimirá en la misma línea.
Los listados se pueden salvar a archivos, almacenándose en archivos de extensión *.gxr Para visualizar reportes s alvados anteriormente, se debe invocar al Report Viewer para poder desde éste hacer un File/Open del archivo que contiene el reporte listado anteriormente. El Report Viewer se abre automáticamente cuando se ejecuta cualquier reporte, o se puede ejecutar Standalone , corriendo el utilitario GxRView.