Criação de modelos de documentos no SIGA-DOC

Conceitos Básicos

O que é um modelo de documento?

Um modelo de um documento é um arquivo pré-formatado que serve como base para a criação de documentos semelhantes. Ele geralmente inclui elementos de design e formatação, como fontes, estilos, margens e espaçamentos, além de elementos de conteúdo, como cabeçalhos, rodapés, seções e áreas reservadas para inserção de textos e imagens.

Os modelos são muito úteis para garantir a consistência visual e de conteúdo em documentos produzidos em larga escala, como ofícios, formulários, contratos e outros documentos corporativos.

Eles também podem ser usados para economizar tempo e esforço na criação de documentos personalizados, permitindo que os usuários preencham apenas os campos necessários.

Componentes do Modelo

Entrevista: Campos que são preenchidos pelo usuário.

Documento: HTML que representa o documento e será posteriormente convertido em PDF.

Descrição: Resumo do conteúdo do documento que é apresentado ao usuário em listagens.

Ganchos de Execução: Pequenos trechos de código que são executados em determinados pontos do ciclo de vida do documento.

3 Maneiras de Descrever Modelos

Tradicional: Primeira versão que foi disponibilizada.

Tradicional com campos padronizados: Melhorias no que diz respeito aos campos da entrevista.

Simples: Um novo sistema de modelos que pode ser utilizado sem conhecimento de Freemarker ou HTML.

Variáveis

Em computação, uma variável é um local na memória do computador que pode ser usado para armazenar um valor.

Essa memória pode ser alterada durante a execução de um programa de computador.

As variáveis são identificadas por um nome e são usadas para armazenar diferentes tipos de dados, como números, strings (cadeias de caracteres), booleanos e objetos.

Expressões

Em computação, uma expressão é uma combinação de valores, variáveis e operadores que são avaliados para produzir um resultado.

As expressões podem ser simples ou complexas, e podem incluir aritmética, comparação, lógica e outras operações.

Por exemplo, em uma expressão aritmética simples como "2 + 3", os valores "2" e "3" são somados pelo operador "+", produzindo o resultado "5".

Expressões Booleanas

Uma expressão booleana é uma expressão que retorna um valor verdadeiro ou falso. As expressões booleanas são usadas para avaliar condições e tomar decisões em programas de computador.

Por exemplo, a expressão booleana "5 é maior que 3" é verdadeira, enquanto a expressão "2 é igual a 3" é falsa. Essas expressões podem ser escritas em uma linguagem de programação como:

5 > 3 (verdadeiro)

2 == 3 (falso)

Ciclo de Vida do Documento

Temporário: Durante a elaboração.

Finalizado: Já está pronto para assinar.

Assinado: Passa a produzir efeitos.

Arquivado no Corrente: Já concluiu seu trâmite e aguarda a destinação.

Arquivado no Intermediário: É mantido para fins de prova.

Recolhido: Foi incluído no Arquivo Permanente.

Eliminado: Não tem mais utilidade e é descartado.

Por Que Usamos PDF?

Consistência e fidelidade: o padrão PDF (Portable Document Format) é capaz de preservar a formatação e o layout de um documento, independentemente do dispositivo ou software usado para visualizá-lo.

Isso garante a consistência e fidelidade do documento original ao longo do tempo, tornando-o uma escolha ideal para documentos arquivísticos que precisam ser preservados por longos períodos.

Conversão para PDF

O OpenHtmlToPdf é uma biblioteca Java gratuita e de código aberto para converter HTML em PDF.

O OpenHtmlToPdf permite que os desenvolvedores gerem PDFs a partir de conteúdo HTML usando CSS para definir o estilo do documento.

A biblioteca é fácil de usar e suporta uma variedade de recursos, incluindo imagens, tabelas, listas e outras estruturas HTML comuns.

Modelos Simples

Introdução

Tradicionalmente os modelos do Siga-Doc são desenvolvidos utilizando HTML e a linguagem FreeMarker. Embora esta seja uma opção viável e muito flexível, em muitos casos o desenvolvimento dos modelos se torna demasiado complexo.

Surgiu então a necessidade de simplificar os modelos, na esperança de que os próprios usuários, ou pessoas com menos conhecimento de programação, também fossem capazes de produzir modelos. Pelo menos os mais simples.

Markdown e JModel

Em vez de HTML, os modelos simples utilizam Markdown, que é uma linguagem de marcação muito mais simples e concisa, e que é convertida facilmente em HTML. Markdown é utilizado por muitas empresas, como a Wikipedia e o GitHub, que precisam gerar documentos padronizados, sem dar espaço para muitas "invenções", mas mantendo as principais capacidades de formatação que o HTML oferece.

Em vez do FreeMarker foi desenvolvida uma nova ferramenta de processamento de modelos chamada JModel. O JModel tem por objetivo facilitar ao máximo o trabalho de marcar onde entram os campos que devem compor a "entrevista".

Markdown vs HTML

Markdown

  • É fácil de aprender e usar

  • Ótimo para Criar conteúdo simples

  • Ideal para documentação e texto básico Exemplo: # Bem-vindo à minha página

    Esta é uma página simples criada com Markdown.

HTML

  • Mais complexo e detalhado

  • Permite controle mais preciso sobre a apresentação

  • Melhor para desenvolvimento web avançado Exemplo: <!DOCTYPE html> <html> <body> <h1> Bem-vindo à minha página! </h1> <p> Esta é uma página simples criada usando HTML.</p> </body> </html>

StackEdit.io

O StackEdit.io é um editor de texto online gratuito que permite escrever, formatar e publicar documentos na web usando a linguagem de marcação Markdown. Ele possui recursos avançados de edição de texto e integração com diversas plataformas, facilitando a escrita e a publicação do conteúdo.

JModel vs Freemarker

Para demonstrar a diferença entre o JModel e o Freemarker, basta observar como um modelo bem simples em JModel ficaria se fossemos fazer a mesma coisa em Freemarker e HTML.

JModel:

Freemarker: [@interview] [@field var='nome'/] [/@interview] [@document] <p> Olá [@value var='nome'/]! </p> [/@document]

Modelo Básico

O modelo mais simples de todos é composto de um único parágrafo de texto no qual existe a inserção de um campo para perguntar, por exemplo, o nome de uma pessoa. Este modelo pode ser visto abaixo:

Olá, {nome} ! Se, na entrevista, for fornecido o nome "Renato" o documento resultante terá um único parágrafo, que será assim:

Olá, Renato!

Modelo Básico 2

Claro que é possível criar mais parágrafos, e para isso basta pular uma linha no texto. Também se pode introduzir quantos campos quiser. Só com esse conhecimento, já seria possível criar um modelo bem básico, algo do tipo: Eu, {nome}, portador do CPF número {cpf}, venho pedir {pedido}. Alego ao meu favor que {alegacao}.

Exemplo no Siga-Doc

Vamos experimentar cadastrar um modelo bem básico no Siga-Doc para ver o resultado. Com a formatação do Markdown e os campos do JModel já dá para fazer muitas coisas interessantes.

Identificadores

Uma coisa importante a respeito dos campos é que o nome que é utilizado deve sempre começar com uma letra minúscula e ser composto por letras não acentuadas, números e o caracter sublinhado (_).

Este nome é o identificador de uma variável, por isso tem que respeitar estas limitações.

Tipos de Campos

Utilizando o tipo Checkbox

O modo de utilização do tipo checkbox na entrevista é igual ao dos outros tipos. Para que um campo seja mostrado na entrevista como do tipo checkbox, basta colocar kind='checkbox'. No entanto, para visualizar o conteúdo desse campo, é necessário realizar mais um passo. Isso ocorre pois, como padrão, o SIGA evidencia no documento a palavra 'Sim', caso o checkbox esteja marcado e 'Não', se o mesmo estiver desmarcado. Desta forma, para mostrar o conteúdo pode-se valer da ferramenta IF, que será explicada mais a frente, conforme figura abaixo. {var_1 title='Registro de presença' kind='checkbox' document=false} {if var_1=='Sim'} - Registro de presença {/if}

O atributo 'document=false' foi colocado justamente para que não seja mostrado no documento o valor atribuído a variável var_1 ('Sim' para checkbox marcado e 'Não' para o não selecionado}. Com a sequência de comandos das imagens acima, é possível imprimir no documento 'Registro de Presença'.

Utilizando o atributo HINT

Caso deseje colocar uma observação/recomendação abaixo de um campo na entrevista (conforme imagem a seguir) deve-se utilizar o atributo HINT da seguinte forma: {var_1 title=’Celular’ hint=’Colocar o número no padrão (00) 00000-0000’}

Utilizando um tipo inexistente

Às vezes, há necessidade de se colocar um campo na entrevista somente para funcionar como se fosse um título/subtítulo, sem o objetivo de ter um espaço logo abaixo para editar. Para que isso seja possível, é necessário atribuir um tipo inexistente. {var_1 title='Justiça Federal' kind='meu'} {var_2 title='Lotação'}

O tipo 'meu' explicitado na var_1 não existe, sendo assim, esta variável assumirá a seguinte forma na entrevista. Note que abaixo do campo 'Lotação' aparece o editor padrão do SIGA.

Inferindo o Tipo da Variável

O nome da variável pode ser utilizado para inferir o tipo.

Por exemplo, se o nome for "cpf" ou "cpf_servidor" ou "cpfServidor" será automaticamente atribuído o tipo "cpf".

Isto acontece porque, como pode ser visto na tabela acima, para alguns tipos de campo existe um "prefixo".

O tipo também pode ser especificado diretamente, através do parâmetro "tipo". No exemplo abaixo, todos os campos serão do tipo CPF: {cpf} {cpf_servidor} {cpfServidor} {codigo kind='cpf'}

Inferindo o Tipo “Selecao”

Existe um tipo de campo chamado "selecao" que contém uma lista de opções dentre as quais o usuário deve escolher apenas uma. A lista de opções deve ser informada no parâmetro options e precisa estar separada por ";".

Quando o tipo não é informado e nenhum prefixo é reconhecido, se for informado o parâmetro "options" será assumido o tipo "selecao", caso o contrário, será assumido o tipo "texto". {pais options='Brasil;Argentina'} {field var='pais' kind='selecao' options='Brasil;Argentina'}

Um Exemplo com Tipos de Variáveis

No exemplo abaixo, o campo {cpf} será automaticamente reconhecido e permitirá apenas a entrada de um número válido.

O campo {pedido options='férias;licença médica'} apresentará apenas estas duas opções para o usuário selecionar.

Além disso, o campo {alegacao kind='memo'} permitirá que o usuário digite um texto de várias linhas. Eu, {nome}, portador do CPF número {cpf}, venho pedir {pedido options='férias;licença médica'}. Alego ao meu favor que {alegacao kind='memo'}.

Outros Parâmetros dos Campos

O título de um campo na entrevista pode ser especificado através do parâmetro title: Servidor: {nome title='Nome do Servidor'}

O número de linhas e colunas de um campo do tipo memo pode ser especificado conforme o exemplo abaixo: {memoJust columns=80 lines=3}

Por padrão o preenchimento dos campos é opcional, mas se for obrigatório, basta incluir o parâmetro required=true: Nome: {nome required=true}

Caso deseje informar um valor default para o campo, isso pode ser obtido conforme o exemplo abaixo: País: {pais default='Brasil'}

Trechos Opcionais com o Comando IF

Quando precisamos que trechos do modelo sejam apresentados, ou não, dependendo do preenchimento de algum campo anterior, podemos utilizar o comando IF.

No exemplo abaixo, a Unidade Federativa será perguntada apenas se a esfera for "Estadual". Se a esfera for "Federal", nenhuma pergunta posterior será feita. Esfera: {esfera options='Federal;Estadual' refresh='esf'} {if esfera=='Estadual' depend='esf'} Estado: {uf options='RJ;SP'} {/if}

Os Parâmetros Refresh e Depend

Os parâmetros refresh e depend são utilizados para indicar ao sistema que, quando é feita uma alteração no campo que tem o parâmetro refresh, o comando que tem o depend deve ser atualizado.

É importante que o valor informado para o refresh seja o mesmo que foi informado para o depend.

Se não utilizarmos o refresh e o depend a entrevista não será automaticamente alterada para apresentar o campo "Estado" quando o usuário selecionar a esfera "Estadual".

O comando refresh sempre aceita um único valor. Já o depend pode receber uma lista de valores separados por ponto-e-vírgula para indicar que qualquer alteração em um dos campos marcados com refresh causará a atualização do comando. Por exemplo, poderíamos ter um comando assim: {if pais=='Brasil' && esfera=='Estadual' depend='pais;esf'}

Refresh e Depend Automáticos

É importante entender como funciona o refresh e o depend mas, para a maior parte dos casos, podemos contar com o padrão.

Nas versões mais recentes do Siga, o refresh é por padrão o nome da variável. Já o depend é obtido a partir de uma análise que é feita na expressão, buscando identificadores válidos.

O resultado é que, para o exemplo acima, que representa um caso bem simples, podemos usar simplesmente assim: Esfera: {esfera options='Federal;Estadual'} {if esfera=='Estadual'} Estado: {uf options='RJ;SP'} {/if}

Os Comandos {if} e {/if}

O comando {if esfera=='Estadual' depend='esf'} marca o início do trecho que é opcional, e o comando {/if} marca o final. Tudo que está entre estes dois comandos será suprimido caso a expressão esfera=='Estadual' não seja verdadeira.

No exemplo acima estamos comparando o valor da variável esfera com a constante 'Estadual', que está entre aspas simples. Isso é necessário para que o valor da constante não se confunda com o nome de outra variável.

Estamos usando o operador de igualdade, ==, mas muitos outros operadores poderiam ser utilizados como, por exemplo, o de desigualdade: !=. Todas as expressões do FreeMarker estão disponíveis para uso e, inclusive, podem conter operadores lógicos como "e" (&&), "ou" (||) e "não" (!).

Repetição com o Comando FOR

Em algumas situações é necessário repetir um trecho do documento ou da entrevista diversas vezes, por exemplo, se desejarmos colher o nome de várias pessoas.

Uma maneira comum de fazer isso é perguntando primeiro quantas pessoas são e depois usando o comando for para repetir várias vezes o trecho do documento que contém o campo que pergunta o nome. Número de pessoas: {qtd options='1;2;3;4;5' refresh='qtd'} {for qtd depend='qtd'} Nome: {nome} {/for}

O Índice do Comando FOR

Os campos que estiverem dentro de um for terão seus nomes acrescidos de um sufixo que varia de 1 até o número final da repetição.

Por exemplo, se o usuário selecionar o número 3, em um {for 3} os 3 campos de nome gerados ganhariam os nomes: nome1, nome2 e nome3.

Se houver a necessidade de utilizar esse contador em alguma expressão do FreeMarker, ou simplesmente imprimi-lo no documento final, o contador fica disponível na variável automática index. Por exemplo, se desejarmos incluir o número do contador no título do campo que aparece na entrevista, podemos fazer assim: {nome title='Nome '+_index}

Organizando os Campos na Entrevista com o Comando GROUP

Se desejarmos agrupar alguns campos da entrevista, ou se quisermos acrescentar um aviso ao usuário que vai minutar o documento, podemos utilizar o comando group: {group title='Identificação'} Nome: {nome} CPF: {cpf} {/group}

Existe a possibilidade de acrescentar um aviso ao usuário que vai minutar o documento. Esse alerta/informação pode ser de 3 tipos, que deve ser escolhido de acordo com o objetivo da mensagem, variando o fundo do texto digitado, conforme disposto abaixo.

Para utilizar esses atributos, deve-se proceder da forma discriminada abaixo:

{group title='Dados pessoais' warning='Seus dados serão mantidos em sigilo'} Nome: {nome} CPF: {cpf} {/group}

Organizando os Campos da Entrevista em Colunas

Por padrão cada campo ocupará uma linha inteira na página de entrevista. Muitas vezes este tamanho todo é desnecessário. Para criar campos menores, podemos utilizar o parâmetro col.

Para o sistema, uma linha da entrevista contém o equivalente a 12 colunas. Sendo assim, poderíamos criar 2 campos, cada um com a largura de 6 colunas para que eles dividam a linha meio-a-meio: Nome: {nome col=6} Telefone: {tel col=6}

Outras opções podem ser exploradas, por exemplo, o nome poderia ocupar 2/3 da linha e o CPF o terço restante: Nome: {nome col=8} Telefone: {tel col=4}

Variáveis do Contexto

Além de variáveis obtidas da “entrevista”, também podemos acessar metadados do documento ou informações de outros documentos interligados. Para tanto, utilizaremos o comando “print”, assim: {print doc.sigla}

Caso seja necessário fazer referência a lotação, função de confiança e cargo de um servidor, que não seja o subscritor, deve-se utilizar os comandos abaixo, substituindo o campo "nomevariavel" pela nomenclatura da respectiva variável que faz menção ao nome do servidor. É importante destacar que para utilizar as funções abaixo, a variável deve ser do tipo 'pessoa'.

Nome: func.pessoa((.vars['nomevariavel_pessoaSel.id'])?number).descricao Matrícula: func.pessoa((.vars['nomevariavel_pessoaSel.id'])?number).sigla Lotação: func.pessoa((.vars['nomevariavel_pessoaSel.id'])?number).lotacao Função de confiança: func.pessoa((.vars['nomevariavel_pessoaSel.id'])?number).funcaoConfianca.descricao Cargo: func.pessoa((.vars['nomevariavel_pessoaSel.id'])?number).cargo.descricao

Selecionando o Estilo do Documento

Até agora vimos como se faz para criar o texto do documento e não consideramos outros aspectos como brasão, cabeçalho, assinatura, rodapé, etc.

Existem alguns estilos pré-definidos para os documentos e para inserirmos nosso texto dentro de um deles utilizaremos o comando {set}. O que este comando faz é atribuir valores para algumas variáveis que controlam a seleção do estilo e alguns parâmetros para configurar detalhes de formatação.

Selecionando o STYLE

Existem algumas variáveis que são padrão do JModel e é fácil identificá-las pois os nomes são em inglês e elas são escritas em letras todas maiúsculas. A principal variável que precisa ser definida se chama STYLE e é utilizada para escolher o estilo do documento. A tabela completa pode ser vista abaixo.

Selecionando Outros Parâmetros de Estilo

Também existem parâmetros complementares que são específicos do Siga-Doc e podem ser vistos nas tabelas abaixo.

Estilo de Memorando

Um memorando bem simples poderia ser gerado da seguinte forma: {set STYLE='memorando' _fecho='Cordialmente,'} Eu, {nome}, estou de acordo.

Descrição Automática

Com os Modelos Simples, podemos criar descrição automática para os documentos criados. Para isso, basta escrever o conteúdo da descrição entre os comandos {description} e {/description}, como pode ser visto no exemplo abaixo. Além dos campos utilizados no documento, a descrição pode incluir novos campos de entrevista. Eu, {nome}, estou de acordo. {description} Despacho de aprovação de {nome}, matrícula: {matricula} {/description}

Executando Operações em Momentos do Ciclo de Vida com o Comando HOOK

É comum acrescentarmos trechos de código FreeMarker que são executados em determinados momentos do ciclo de vida de um documento. Por exemplo, podemos querer iniciar um procedimento de Workflow quando o documento é assinado, ou validar o preenchimento de algum perfil antes da assinatura. Para isso existe o comando hook. No exemplo abaixo, temos o hook sendo utilizado exatamente para esse fim: {hook 'BEFORE_SIGN'} [#if !doc.getResponsaveisPorPapel("gestor")??] [#assign x = exbl.appException("Não é permitido assinar este documento antes de definir uma pessoa ou lotação com o papel de Gestor para representar o proponente da solicitação de deslocamento") /] [/#if] {/hook} {hook 'AFTER_SIGN'} [#assign criado = func.criarWorkflow('TRF2: Solicitação de Deslocamento', doc, cadastrante, titular, lotaCadastrante, lotaTitular) /] {/hook}

Hook e Etapas do Ciclo de Vida

As etapas do ciclo de vida que são interceptadas pelo hook são as seguintes:

Inserindo os Modelos no Siga-Doc

Existem duas maneiras para inserir Modelos Simples no Siga-Doc.

A primeira consiste em selecionar a opção "FreeMarker" e incluir o modelo diretamente. O Siga-Doc faz uma avaliação do modelo e concluirá que se trata de um modelo simples desde que ele não encontre nenhuma das macros @entrevista, @documento, @descricao ou @markdown.

A segunda opção, portanto, consiste em incluir o Modelo Simples entre as pseudo macros [@markdown] e [/@markdown]. [@entrevista] [@campo var="nome" /] [/@entrevista] [@markdown] Olá {print nome!}! [/@markdown]

Limitações do Markdown e do JModel

Em determinadas situações pode ser necessário criar algum tipo de diagramação não suportada pelo Markdown.

De maneira geral, isso provavelmente significa que estamos querendo criar um documento digital como se ele fosse um daqueles antigos formulários para serem preenchidos a mão. Por favor, não façam isso.

A estética desses documentos é coisa de outra época. Mesmo assim, ainda existem pessoas que acreditam que é assim que fica bonito. Fazer documentos digitais com caixinhas como se eles fossem ser preenchidos manualmente dificulta, complica e é muito contraproducente.

Se, mesmo assim, for detectada a necessidade de usar algum tipo de diagramação não suportada pelo Markdown, a boa notícia é que código HTML pode ser escrito junto com o Markdown, sem problema algum: <p style="color: red"> Olá, {nome}! </p>

Por outro lado, pode ser necessário usar IFs ou FORs ou expressões mais complexas.

Neste caso, é possível aplicar código FreeMarker diretamente no Modelo Simples, conforme pode ser visto ao lado. País: {pais options='Brasil;Argentina'} [#if pais=='Brasil'] Ótimo lugar para se morar! [/#if]

Somando valores

Para somar valores, deve-se atribuir uma variável no início do modelo [#assign nomedavariável = 0 document=false]. Considerando que o valor a ser adicionado esteja dentro de um FOR, é necessário colocar [#assign nomedavariavel = nomedavariavel + .vars['variavel_que_se_deseja_somar'+_index]?replace('.', '')?replace(',', '.')?number] dentro do FOR, onde:

o .vars['variavel_que_se_deseja_somar'+_index]: utilizado para somar o valor que está dentro do FOR e o +_index é justamente para especificar a rodada do FOR que está.

o ?replace('.', '')?replace(',', '.'): utilizado para substituir os ‘.’ e as ‘,’ conforme fórmulas

o ?number: para converter em número, visto que o termo é entendido como string pelo freemarker.

Exemplo: [#assign valortotal = 0 document=false] {qtd_imoveis title='Qual é a quantidade de salas/imóveis?' options='1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20' document=false} {for qtd_imoveis} [#assign valortotal = valortotal + .vars['valor'+_index]?replace('.', '')?replace(',', '.')?number] {/for}

[#assign valortotal = valortotal?string.currency] (A função ?string.currency é utilizada para colocar a formatação de moeda no valor) Para visualizar o valor da variável, é necessário efetuar um print.

Last updated