ReportMaker

De BIS Wiki
Ir para navegação Ir para pesquisar

O BISReports é o sistema do BIS para a geração de relatórios do sistema. A função deste serviço é oferecer funções e suporte para que a aplicação possa desenvolver relatórios em PDF de forma rápida e centralizada. Outra função bem clara do BISReports é centralizar a aparência dos relatórios em todo o sistema, oferecendo templates de cabeçalhos, rodapés, e blocos de conteúdos para serem usados pelas relatórios dos plugins/módulos.


Note 64.png
iText
O BISReports funciona em cima da biblioteca [iText]. Verifique o Guia Rápido do iText para uma visão rápida do seu funcionamento e exemplos sucintos de como escrever no diretamente no documento.


BISReport

BISReport é a classe principal do serviço. Esta classe é abstrata e deve ser estendida diretamente pela classe do relatório, ou por alguma classe "intermediária" usada para criar um template específico de relatório.

Os serviços oferecidos por esta classe são:

Conjunto de Fontes

Entre as características que devem ser uniformes em todos os relatórios do sistema estão as "Fontes" usadas para escrever as informações. Por isso a classe pai oferece um conjunto de fontes para ser utilizado nos relatórios. Os conjuntos definem o tipo de letra (fonte), e sua aparência (bold, italic, etc.). Essas fontes são obtidas pelos métodos:

  • getBaseFontPlain() - Retorna a fonte padrão para relatório do sistema.
  • getBaseFontItalic() - Retorna a fonte padrão com o formato itálico ativado.
  • getBaseFontBold() - Retorna a fonte padrão com formato negrito ativado.
  • getBaseFontBoldItalic() - Retorna a fonte padrão com o formato negrito e itálico ativado.


Note 64.png
Fontes Alternativas
Embora nada impeça a criação de novas fontes nos relatórios, ou mesmo fontes específicas para relatórios específicos, deve-se analisar com cuidado a troca da fonte padrão do relatório por alguma personalizada, justamente para não remover o padrão ou dificultar a leitura do relatório.


Cabeçalhos e Rodapés

Outra característica do BISReport é a centralização dos cabeçalhos e rodapés disponíveis para serem utilizados nos relatórios. Há alguns modelos distintos de acordo com as informações que precisam ser exibidas, como títulos e subtítulos, datas de períodos, etc.

Abaixo estão listados os modelos existentes atualmente:

Cabeçalho de Relatório: Modelo 1

Dados exibidos:

  • Nome da Empresa
  • Título do Relatório
  • Data de Geração
Exemplo de Cabeçalho de Relatório: Modelo 1

Rodapé de Página: Modelo 1

Dados exibidos:

  • Número da Página
Exemplo de Rodapé de Página: Modelo 1

Métodos Utilitários

A classe oferece alguns métodos que facilitam a escrita dos relatórios. São funções e blocos de códigos que costumam se repetir em vários momentos/relatórios.

createClippedTextField

Este método cria um template[1] para escrita de um texto e aplica um clip no tamanho desejado.

É usado (ou deve ser usado) durante a escrita de campos de texto que podem ter tamanho variável, e algumas vezes até maior do que o espaço destinado à ele. Utilizando esta técnica o campo será "cortado" no seu limite, evitando que a informação atropele outro conteúdo, ou mesmo desobedeça as margens do papel.

Mais detalhes sobre o funcionamento no javadoc do método.


getWritableWidth & getWritableHeight

Ambos os métodos servem para retornar o espaço livre da folha, retornando respectivamente a largura (eixo X) e a altura (eixo Y). Este método leva em consideração apenas 2 coisas: O tamanho da folha em uso e as margens definidas. Este método não considera cabeçalhos, rodapés ou qualquer outro conteúdo já "impresso" no relatório.

getCoord*

Os métodos getCoord são responsáveis por calcular as coordenadas a partir dos limites "writable" do documento, sendo a origem (0,0) no canto superior esquerdo. Por exemplo, ao solicitar a posição 100 a partir da esquerda, o sistema calculará 100 + a borda da esquerda para achar o valor de x correto para ser usado no PDF. Dessa maneira facilita o posicionamento dos campos no espaço "writable".

Os métodos disponíveis são:

  • getCoordFromTop(c) - Obtém a coordenada Y que representa a distância "c" em relação à borda superior do espaço "writable" do documento.
  • getCoordFromBottom(c) - Obtém a coordenada Y que representa a distância "c" em relação à borda inferior do espaço "writable" do documento.
  • getCoordFromRight(c) - Obtém a coordenada X que representa a distância "c" em relação à borda direita do espaço "writable" do documento.
  • getCoordFromLeft(c) - Obtém a coordenada X que representa a distância "c" em relação à borda esquerda do espaço "writable" do documento.
  • getCoordFromMiddleX(c) - Obtém a coordenada X que representa a distância "c" em relação ao centro da largura "writable" do documento.


Note 64.png
Distância Negativas
Embora não faça muito sentido para a maioria dos métodos citados, os valores "c" podem ser passados negativos. O que fará com que o valor retornado seja no "sentido contrário". Isto é, valores positivos em geral retornam uma posição dentro do espaço "writable" da folha.

O valor negativo faz mais sentido se pensar no método getCoordFromMiddleX(). Se o valor for positivo ele retornará a coordenada que fica à distância "c" do centro da página para a direita. Caso o valor seja negativo, a coordenada ficará a mesma distância "c", só que a esquerda do centro da página.


Além disso, os métodos automaticamente invertem as origens do documento conforme solicitado.

setPageSize*

Os métodos setPageSize já contém alguns tamanhos "padrões" de folhas, e permitem que o tamanho da folha a ser usada no relatório seja definido de forma mais ágil. Inclusive rotacionar o tamanho para trocar do formato Retrato para Paisagem.

setMargins()

Permite que as margens do relatório sejam redefinidas. As margens padrão já são definidas para garantir que de forma geral nenhuma impressora do mercado "corte" informações nas bordas do papel. No entanto ainda é possível tentar ampliar ou reduzir essas margens conforme necessidade.

Os valores definidos como padrão é de 36px.

BISReportBean

O BISReportBean é um objeto que "carrega" todas as configurações necessárias para a geração do relatório. Ao invés de um construtor complexo com inúmeros atributos, optamos por receber este único objeto com todas as configurações necessárias internamente.

O BISReportBean tem alguns atributos usados no relatório, e todos os atributos já são instanciados com valores que definem o relatório, como por exemplo, que a folha é A4 no formato 'Retrato', e algumas margens padrões para impressão.


Stop 256.png
Locale
Embora o relatório seja classe do Core, muitos dados precisam ser tratados de acordo com o Locale do usuário, afinal, relatório é como uma "interface que exibe dados para o usuário", e precisa ser legível à maneira que ele é acostumado a ver a informação: decimais com "," ou ".", datas com "dd/mm/aaaa" ou "mmm dd,aaa", etc..

Ao iniciar o Bean procure sempre passar o Locale do usuário, provavelmente enviando-o junto durante a requisição da interface. Caso o relatório esteja sendo executado de outro "ator", como uma integração de outro sistema, ou uma tarefa agendada é preciso tomar o cuidado de definir o locale que será usado. O locale pode vir de diversos lugares, é preciso analisar cado a caso.

Por fim, se nenhum Locale for especificado o BISReportBean usará como valor padrão o Locale retornado como padrão na JVM.


É sugerido que os relatório sigam o mesmo padrão. Que recebam em seu construtor a mesma classe BISReportBean ou outro Bean específico para o relatório. Neste caso, também é sugerido que o Bean específico para o relatório estenda o BISReportBean. Desta forma um único objeto carregará todas as informações necessárias, tanto para o BISReport quando para a classe de Relatório.

Entre os atributos específicos de cada relatório podem estar o "MO" que o relatório usará para obter os dados no CRUD, ou mesmo a coleção de dados/objeto que ele deverá usar para montar o relatório. Sendo obviamente livre e de definição de cada relatório definir seus atributos e informações necessárias.

Implementando um BISReport

Implementar uma classe de relatório precisa apenas de poucos passos:

  1. Crie uma classe que estenda BISReport;
  2. Crie uma classe de Bean que estenda BISReportBean, preferencialmente com o mesmo nome (exceto pelos sufixos diferentes: Report e ReportBean);
  3. Implemente o método writeReportContent(), que é abstrato em BISReport;

Esses três passos são o suficiente para criar a estrutura para começar a implementar o relatório. A partir deste ponto começa a implementação específica de cada relatório em duas etapas: obtenção/preparação dos dados e escrita no documento.

A obtenção/preparação dos dados significa obter os dados que serão escritos no relatório. Para alguns relatórios esses dados podem ser obtidos pela própria classe do Report, quando já virem dentro do ReportBean da classe.


Note 64.png
Código de Obtenção dos Dados
As classes "Report" fazem parte do CRUD, isto quer dizer que as classes Report podem chamar diretamente os métodos do CRUD do mesmo módulo/plugin.

Também é recomendável que esses dados sejam obtidos diretamente no construtor do relatório. Fazendo com que o construtor lance as exceções necessárias diretamente.


Já a escrita no documento deve ser feita toda dentro do método abstrato herdado de BISReport - writeReportContent(). Chamado da classe pai quando for a hora de gerar o relatório, este método é quem deverá conter toda a lógica de "desenho e escrita no papel". Para saber como "escrever no papel" veja o Guia Rápido do iText.

Executando um Relatório

Uma vez que o relatório foi implementado, gera-lo pode ser descrito em três passos básicos:

  1. instancie a classe do relatório (que estende e implementa os métodos abstratos da BISReport);
  2. chame o método writeReport();
  3. por fim, obtenha o arquivo do PDF através do método getOut();


Obviamente que há passos anteriores aos 3 citados acima, como por exemplo captar e definir eventuais configurações do relatório.

BISListReport

O BISListReport é uma implementação da classe BISReport que tem a finalidade de simplificar os cálculos e a geração dos relatórios do tipo "listagem". Entende-se por relatório de "listagem" os relatórios que simplesmente imprimem dados em formas de linhas. Pode ainda ser usado para impressão de blocos gráficos, multi-linhas, ou qualquer outro cuja exibição seja sequencial no sentido vertical da página.

O BISListReport gera um relatório com a seguinte estrutura:

  • Cabeçalho de Relatório - é um cabeçalho que só é impresso uma vez em cada relatório - no começo da primeira página. Geralmente têm o nome da empresa, a data de geração do relatório e títulos/subtítulos do relatório para identifica-lo.
  • Cabeçalho de Página - é um cabeçalho menor impresso no começo que cada nova página. Na primeira página é impresso logo depois do cabeçalho de relatório. Em geral este cabeçalho só informa os títulos das colunas da listagem.
  • Conteúdo do Relatório - O conteúdo do relatório definido é iterado e colocado sequencialmente até que o espaço da folha acabe.
  • Rodapé de Página - O rodapé de página é colocado no final de cada página criada.

Funcionamento

Para utilizar a BISListReport basta estender a classe, e implementar seus métodos abstratos. No entanto entender seu funcionamento é fundamental para a implementação de um bom relatório. Assim:

  • O BISListReport permite a criação de 1 ou mais relatórios juntos. - Isto é, é possível anexar a informação de "vários" relatórios e permitir que o BISListReport gerencie essas informações e crie relatórios distintos para cada informação, mesmo que concatenados no mesmo arquivo PDF. A ideia desta funcionalidade é que, por exemplo, é possível emitir o relatório de vários clientes de uma única vez - único PDF - sem que a numeração de página torne-se continua, reiniciando a cada novo relatório.
  • O BISListReport monta sequencialmente na vertical os blocos recebidos. - Todos os blocos recebidos são organizados em ordem como em uma lista automaticamente. E, independente do tamanho de cada bloco, o BISListReport verifica seu tamanho e os organiza até que a folha se esgote. Ao esgotar ele cria uma nova página, refaz cabeçalho e rodapé de folha e continua a colocar os blocos até que se esgote novamente. E assim sucessivamente até que se esgotem os blocos.
  • As definições de página, como tamanho, orientação e margens, devem ser definidas logo no construtor - O BISListReport herda as configurações padrões de folha do BISReport, mas essas configurações podem ser redefinidas pela classe filha logo em seu construtor. Depois que o relatório começar a ser escrito alterar essas configurações pode causar mal funcionamento no BISListReport.

Seu procedimento é o seguinte:

  • Passo 1: prepareReportData() - este método é chamado depois que o "documento PDF já foi aberto", isso significa que blocos (templates) já podem ser criados. Lembre-se que "blocos" são em geral as linhas do relatório, mas são chamados de bloco pois podem ser qualquer coisa, ou mesmo uma mesclagem de linhas de dados, pequenos gráficos, uma linha gráfica para separar os dados, etc.
  • Passo 2: getReportBlocksList() - este método é chamado para obter todos os blocos de um relatório de uma única vez. Esses blocos normalmente devem ter sido criados no método anterior.
  • Passo 3: writeReportHeader() / writePageHeader() / writePageFooter() - Esses métodos devem criar um template (PdfTemplate) do Cabeçalho de Relatório, Cabeçalho de Página e Rodapé de Página, respectivamente. A ordem de evocação desse três métodos, bem como a quantidade de vezes que serão chamados, dependerá da necessidade durante o processo de execução, como por exemplo a quantidade de páginas sendo criadas. No entanto é certo afirmar que se todas as chamadas feitas se referem ao relatório obtido na última evocação do método getReportBlocksList().
  • Passo 4: onReportFinished() - Este método é chamado quando o relatório termina, permitindo que o relatório possa realizar algumas finalizações, como a escrita de templates que ficaram pendentes durante o processo de geração.
  • Passo 5: Votar ao Passo 2 - Quando o relatório termina o BISListReport volta par ao passo 2 e solicita novamente o conteúdo do relatório. Caso a classe filha retorna uma nova lista de blocos a BISListReport começará um novo relatório no fim do existente. Recomeçará a contar as páginas da 1 novamente e assim por diante.


Stop 256.png
Loop Infinito
Como a BISListReport interpreta cada retorno do método getReportBlocksList() como um novo relatório, caso a classe filha só gere 1 relatório, mas mantenha o método o "return" sempre retornando o mesmo conjunto de blocos, o sistema ficará fazendo e refazendo o mesmo relatório até o stackoverflow.

Tome cuidado para só retornar o conjunto 1 vez e retornar null na segunda iteração.


Referências

  1. Template no iText é um "pedaço" do documento que é escrito separado e depois posicionado onde desejado. Similar à ideia de escrever em um Post-It e depois cola-lo no seu documento, com a vantagem que não ficará visível onde esse template começa ou termina, ele não gera bordas ou fundos. Pelo menos não automáticamente.