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.

13 comentarios sobre “Posibilidades de Jasper Reports, informe tipo calendario

  1. Hrzio

    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

    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

    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 Autor del artículo

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

    Saludos
    Ángel Moya

  5. Javier Armando

    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 Autor del artículo

    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.

  7. string

    Disculpa que utilizas para definir los dias de la semana q son static label o que?

  8. Angel Moya Autor del artículo

    Buenas, hace mucho que hice este informe, pero creo que si, las etiquetas de los días de la semana son estáticas.

  9. ismael

    hola men tengo una pregnta stoy buscando hacer un horario de clase con reporte pero n tengo idea como hacerlo no tendras algo q me ayude hacerlo xfavor

  10. MIJAEL EUSEBIO PARIONA TARQUI

    Hola, debo considerar que es un buen tutorial, base para otros tutoriales semejantes; lo que no logro es hacer un reporte semanal de pagos, con totales por semana, tengo campos como pago y fecha, pero eh intentado todo, sin logro alguno, quisiera que me ayuden por favor.

    Se los agradeceria eternamente…!

  11. Edith

    hola, yo hice un calendario para la organizacion de los horarios en una sala de juntas, donde en cada dia ponia los eventos, su horario y el reponsable. utilicé un crosstab y esta consulta (el calendario se construye al vuelo, no se guarda)

    SELECT NUM||evento AS DIAEVENTO,
    TO_CHAR(LDIA)||DIA AS NOMBREDIA,
    to_date(num||’-‘||$P{MES_ANIO}, ‘dd/mm/yyyy hh24:mi:ss’) – to_char(to_date(num||’-‘||$P{MES_ANIO}, ‘dd/mm/yyyy hh24:mi:ss’), ‘d’) as dia_d

    FROM

    (
    SELECT ‘ 1’ AS NUM,(to_char(TO_DATE(’01-‘||$P{MES_ANIO},’dd-mm-yyyy’),’D’)) AS LDIA,(to_char(TO_DATE(’01-‘||$P{MES_ANIO},’dd-mm-yyyy’),’DAY’)) AS dia ,

    ROWTOCOL(‘SELECT »(»|| TO_CHAR(«FECHAHR_INI»,»HH24:MI»)||»-»|| TO_CHAR(«FECHAHR_FIN», »HH24:MI»)||»)»||»EVENTO» ||chr(10)||»Dep: »||DEPENDENCIA||chr(10)||»Resp: »||SOLICITANTE
    FROM SAL_RESERVACIONES
    WHERE
    ESTATUS = »A»
    and id_sala = 1
    and to_char(fechahr_ini,»dd-mm-yyyy»)=»01-‘||$P{MES_ANIO}||»»
    ,chr(10)) AS EVENTO
    FROM DUAL

    union
    SELECT ‘ 2’ AS NUM,(to_char(TO_DATE(’02-‘||$P{MES_ANIO},’dd-mm-yyyy’),’D’)) AS LDIA,(to_char(TO_DATE(’02-‘||$P{MES_ANIO},’dd-mm-yyyy’),’DAY’)) AS DIA ,

    ROWTOCOL(‘SELECT »(»|| TO_CHAR(«FECHAHR_INI»,»HH24:MI»)||»-»|| TO_CHAR(«FECHAHR_FIN», »HH24:MI»)||»)»||»EVENTO» ||chr(10)||»Dep: »||DEPENDENCIA||chr(10)||»Resp: »||SOLICITANTE
    FROM SAL_RESERVACIONES
    WHERE
    ESTATUS = »A»
    and id_sala = 1
    and to_char(fechahr_ini,»dd-mm-yyyy»)=»02-‘||$P{MES_ANIO}||»»
    ,chr(10)) AS EVENTO

    FROM DUAL

    )

    Y EN EL CASO DEL CROSSTAB:
    : es el nombre de cada dia y su lugar en la semana(1domingo , 2lunes, …,etc)
    :es la fecha del primer dia de cada semana (me sirve para agrupar los que coinciden con ese primer dia de semana
    : es el numero del dia y todos los elementos que coindicieron con la misma fecha de evento

    ——————————————————————————-
    | nombredia1 | … |nombrediaN
    ——————————————————————————
    dia_d | DIAEVENTO

  12. Angel Moya Autor del artículo

    Muchas gracias por el aporte, esta entrada tiene casi siete años, y la verdad es que no recuerdo porque lo hice así, de todas formas seguro que a alguien le sirve ese comentario.

  13. Carina

    Tengo una duda, el espacio que queda en blanco después del día 30, quedaron 4 columnas vacías, se podrá mostrar 4 textfield, aunque este nulo, osea que no quede nada vació.
    Porfa ayudenme

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.