Posibilidades de Jasper Reports, informe tipo calendario

Seguramente usar Jasper Reports para hacer un informe tipo calendario no sea la mejor solución, pero con esto nos podemos hacer una idea de las posibilidades de Jasper Reports. Este informe lo he realizado para un proyecto de Sugar CRM así que las consultas de este informe están escritas para MySQL. A grandes rasgos lo primero que vamos ha hacer es un informe para imprimir un mes, que puede ser utilizado como subinforme para imprimir el informe anual.

El informe mensual va a ser dinámico, le pasaremos como parámetro el mes y el año y nos mostrará el mes, para haceros una idea del resultado este es el preview del informe mensual.

Para conseguir este resultado tenemos que tener en cuenta dos aspectos, por un lado como hacer que imprima columnas horizontales y por otro como obtener los datos de una consulta que devuelva una linea para cada día del mes que queramos y como hacer que coloque el día 1 donde corresponda según el día de la semana.

Vamos a empezar por los aspectos visuales, este es el diseño

En la zona del titulo tenemos un campo que muestra el nombre del mes a partir del número del mes que le pasamos como parámetro y le concatenamos el año que también pasamos como parametro, para eso utilizamos el siguiente código java:

( $P{mes}.equals("1")  ? "ENERO" : ( $P{mes}.equals("2")  ? "FEBRERO" :  ( $P{mes}.equals("3")  ? "MARZO" : ( $P{mes}.equals("4")  ? "ABRIL" : ( $P{mes}.equals("5")  ? "MAYO" : ( $P{mes}.equals("6")  ? "JUNIO" : ( $P{mes}.equals("7")  ? "JULIO" : ( $P{mes}.equals("8")  ? "AGOSTO" : ( $P{mes}.equals("9")  ? "SEPTIEMBRE" : ( $P{mes}.equals("10")  ? "OCTUBRE" : ( $P{mes}.equals("11")  ? "NOVIEMBRE" : ( $P{mes}.equals("12")  ? "DICIEMBRE" : "ERROR" ) ) ) ) ) ) ) ) ) ) ) ) +" "+$P{anno}

En el mismo titulo tenemos la cabecera de los días de la semana, que son del mismo tamaño que las columnas del informe. Para hacer que el informe imprima con columnas seleccionamos el informe en la parte del Report Inspector y las propiedades de la derecha indico que usamos 7 columnas

y que empiece a imprimir de forma horizontal

Ya hemos preparado visualmente el informe pero necesitamos una consulta que nos devuelva los días de la semana y que las primeras lineas de la consulta estén vacías dependiendo del día de la semana que empiece el día 1 del mes que pasemos como parámetro para que el día uno caiga en la posición que corresponda según el día de la semana.

Por ejemplo si el día 1 cae en lunes nuestra consulta devolverá 1,2,3… si cae en martes 0,1,2,3… en miércoles 0,0,1,2,3… y el peor caso sería que cayese en domingo que sería 0,0,0,0,0,0,1,2,3…

Así que he creado una tabla en base de datos con dos columnas una columna para indicar el orden empezando por el número 1 y otra que indica el día del mes con los siguientes valores:
0,0,0,0,0,0,1,2,3,4…..29,30,31

En MySQL podemos obtener el día de la semana en que cae el día con la siguiente consulta

DATE_FORMAT(CONCAT($P{anno},CONCAT('-',CONCAT($P{mes},'-01'))), '%w')

Así si cae en domingo devuelve 0, en lunes 1, en martes 2… si el día uno cae en lunes tengo que empezar a mostrar las lineas de mi tabla a partir de la número 7, ya que empiezo a mostrar directamente número y tengo que quitar todos los campos que tienen como día del mes 0, si el día 1 cae en martes en mi consulta muestro a partir de la línea 6 entonces la primera línea de núestra consulta devuelve 0 y la segunda 1, en el peor caso que el día 1 cae en domingo tendría que mostrar todas las lineas esto es 0,0,0,0,0,0,1,2,3…

Para saber el número de días que tiene un mes, si cojo el día 1 de un mes le sumo un mes y le resto un día tengo el último día del mes.

DATE_FORMAT(CONCAT($P{anno},CONCAT('-',CONCAT($P{mes},'-01'))) + INTERVAL 1 MONTH - INTERVAL 1 DAY,'%e')

Así que la consulta del informe es la siguiente:

select num, orden
from msp_report_auxdias
WHERE orden >= 8 - DATE_FORMAT(CONCAT($P{anno},CONCAT('-',CONCAT($P{mes},'-01'))), '%w')
    and num <= DATE_FORMAT(CONCAT($P{anno},CONCAT('-',CONCAT($P{mes},'-01'))) + INTERVAL 1 MONTH - INTERVAL 1 DAY,'%e') -- mas un mes - un dia
order by orden

Con esto ya tenemos un informe de tipo calendario mensual y podríamos hacer el anual llamando a este como subinforme. También podríamos hacer un subinforme para cada día para mostrar detalles de ese día.

En este ejemplo lo hemos hecho con una base datos MySQL, en otro post pondré el informe calendario usando un xml como datasource para que sea independiente de la base datos y usando un scriptlet para conseguir que imprima cada mes.

Tags: ,

6 Comentarios to “Posibilidades de Jasper Reports, informe tipo calendario”

  1. Hrzio says on :

    Muy buen Post, propongo que para la simplificación de la expresión del mes:
    ( $P{mes}.equals(“1″) ? “ENERO” : ( $P{mes}.equals(“2″) ? “FEBRERO” : ( $P{mes}.equals(“3″) ? “MARZO” : ( $P{mes}.equals(“4″) ? “ABRIL” : ( $P{mes}.equals(“5″) ? “MAYO” : ( $P{mes}.equals(“6″) ? “JUNIO” : ( $P{mes}.equals(“7″) ? “JULIO” : ( $P{mes}.equals(“8″) ? “AGOSTO” : ( $P{mes}.equals(“9″) ? “SEPTIEMBRE” : ( $P{mes}.equals(“10″) ? “OCTUBRE” : ( $P{mes}.equals(“11″) ? “NOVIEMBRE” : ( $P{mes}.equals(“12″) ? “DICIEMBRE” : “ERROR” ) ) ) ) ) ) ) ) ) ) ) ) +” “+$P{anno}

    se use en su lugar:

    Integer.parseInt($P{mes}) >0 && Integer.parseInt($P{mes}) 0 && Integer.parseInt($P{mes}) <13 ? new java.text.DateFormatSymbols(new Locale("es")).getMonths()[Integer.parseInt($P{mes}) -1 ].toUpperCase() : "ERROR"

    Igual son un poco complejas pero me parece que es menos fácil perderte en la expresión en caso de que le quieras dar mantenimiento o usar otro idioma :)

    ¡Saludos!

  2. Hrzio says on :

    Integer.parseInt($P{mes}) >0 && Integer.parseInt($P{mes}) 0 && Integer.parseInt($P{mes}) <13 ? new java.text.DateFormatSymbols(new Locale("es")).getMonths()[Integer.parseInt($P{mes}) -1 ].toUpperCase() : "ERROR"

  3. Hrzio says on :

    Integer.parseInt($P{mes}) >0 && Integer.parseInt($P{mes}) <13 ? new java.text.SimpleDateFormat("MMMM", new Locale("es")).format(new java.text.SimpleDateFormat("M").parse($P{mes})).toUpperCase() : "ERROR"

  4. Angel Moya says on :

    Muchas gracias por el aporte, la próxima vez que tenga que trabajar con meses lo usaré seguro.

    Saludos
    Ángel Moya

  5. Javier Armando says on :

    oyes en tu ultima consulta que haces para obtener los dias consecutivos del mes y año
    select num, orden
    from msp_report_auxdias
    WHERE orden >= 8 – DATE_FORMAT(CONCAT($P{anno},CONCAT(‘-’,CONCAT($P{mes},’-01′))), ‘%w’)
    and num <= DATE_FORMAT(CONCAT($P{anno},CONCAT('-',CONCAT($P{mes},'-01'))) + INTERVAL 1 MONTH – INTERVAL 1 DAY,'%e') — mas un mes – un dia
    order by orden
    donde encuentro la tabla msp_report_auxdias
    o como la creo

  6. Angel Moya says on :

    Hola,

    la tabla msp_report_auxdias, es una tabla auxiliar que creo manualmente con los datos que describo en el post.

    Simplemente sería crear la tabla:
    CREATE TABLE msp_report_auxdias (
    num TINYINT(4) NULL,
    orden TINYINT(4) NULL
    )

    Y luego introducir los datos, sería mas cómodo tener una función que lo crease pero como la tengo puedes meter los datos desde un gestor de bases de datos que te lo permita o con intrucciones insert, que sería:

    INSERT INTO msp_report_auxdias(num, orden) VALUES(0, 1);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(0, 2);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(0, 3);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(0, 4);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(0, 5);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(0, 6);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(1, 7);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(2, 8);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(3, 9);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(4, 10);
    INSERT INTO msp_report_auxdias(num, orden) VALUES(5, 11);
    … y así hasta que la columna num llegue a 31.

Deja un comentario