10. Gerando Relatórios

10. Gerando Relatórios

Talvez uma das primeiras aplicações do COBOL no ambiente de negócios tenha sido a geração de relatórios a partir de informações armazenadas em cartões perfurados, fitas e/ou discos magnéticos. A cultura da “informação no papel” vem mudando significativamente nos últimos anos, mas certamente você ainda encontrará milhares de programas na sua empresa que geram relatórios da maneira tradicional.

Hoje boa parte dos relatórios do ambiente corporativo se transformou em XMLs, CSVs e outros formatos similares que podem ser importados para o desktop de trabalho do usuário e tratados nos aplicativos de sua preferência.

A forma como esses formatos são gerados pelo COBOL não é muito diferente da maneira como geramos relatórios tradicionais, aqueles que têm cabeçalho, linhas de detalhe, sumários e rodapés…

Neste capítulo veremos como construir um programa simples para geração de relatórios a partir de arquivos sequenciais em disco. Na verdade, o que faremos é um programa que lê o arquivo de duplicatas válidas que geramos no programa CRP0207 e emite um relatório de contas a receber.

Especificando o relatório

O layout do arquivo de entrada para nosso relatório é o mesmo que usamos para o arquivo de saída do programa CRP0207, e que podemos rever abaixo:

      *----------------------------------------------------------------*
      * DUPLICATAS VALIDAS
      *----------------------------------------------------------------*
       FD CRA0207V.
       01 CRA0207V-REGISTRO.
           03 CRA0207V-NR-FATURA        PIC  9(006).
           03 CRA0207V-NR-DUPLICATA     PIC  9(002).
           03 CRA0207V-CD-CLIENTE       PIC  X(006).
           03 CRA0207V-DT-EMISSAO       PIC  9(008).
           03 CRA0207V-DT-VENCIMENTO    PIC  9(008).
           03 CRA0207V-VL-FATURA        PIC S9(013)V9(002).
           03 CRA0207V-CD-CATEGORIA     PIC  X(003).
           03 CRA0207V-ST-DUPLICATA     PIC  X(003).

Nosso primeiro relatório mostrará uma lista simples dessas duplicatas, sem nenhuma ordenação especial. Uma linha com o número de duplicatas listadas e o somatório dos valores da fatura aparecerá num rodapé que vamos imprimir no final.

A figura abaixo mostra o layout do relatório que queremos gerar:

Cobol: Layout de relatório
Figura 29. Esboço do relatório que vamos emitir

Pelo layout podemos ter uma ideia de alguns recursos novos que veremos no nosso programa: obtenção de data e hora do sistema, criação de máscaras para exibição de datas e valores monetários, alinhamento de colunas etc.

A grande maioria dos relatórios possui uma ou mais linhas de cabeçalho, que aparecem no início de cada página e normalmente seguem um padrão adotado pela empresa. Repare que as três primeiras linhas do nosso relatório mostram o nome da empresa, nome do sistema, nome do relatório (CRL0208), título do relatório, data e hora de emissão e número de página. Logo depois dessas linhas vemos os nomes das colunas. Essa linha também faz parte do cabeçalho.

Depois do cabeçalho temos as linhas de detalhe, que receberão as informações que serão lidas no arquivo de entrada. Todas as informações que aparecem no layout já existem no arquivo de entrada.

No final da última página do relatório teremos um rodapé onde mostraremos a quantidade de duplicatas impressas e o somatório dos valores de todas as duplicatas listadas.

Tradicionalmente os relatórios eram gerados com 80 ou 132 caracteres por linha, e entre 60 e 66 linhas por página. Isso correspondia aos principais modelos de formulários contínuos disponíveis nas empresas e à fonte monoespaçada que existia nas impressoras matriciais. Hoje essas limitações praticamente não existem e as impressoras possuem milhares de recursos para comprimir e ajustar as fontes para o tamanho de papel desejado. Mas o formato tradicional ainda é o mais usado em sistemas legados.

Iniciando a construção do programa

No COBOL um relatório nada mais é que um arquivo sequencial, onde cada linha de cabeçalho, detalhe ou rodapé é um registro. Os comandos para abertura e fechamento de arquivo e gravação de registros são praticamente os mesmos que usamos nos programas anteriores: OPEN, WRITE e CLOSE, sendo que o WRITE tem algumas opções adicionais.

Muitos anos atrás era comum que o programa enviasse o relatório diretamente para a impressora. Hoje, porém, os relatórios são primeiramente salvos em disco (em arquivos texto) que depois são direcionados por servidores de impressão e/ou outros aplicativos similares para o dispositivo físico (impressora e papel).

Se todo relatório é um arquivo, então precisamos declará-lo na ENVIRONMENT. O trecho abaixo mostra o programa da IDENTIFICATION DIVISION (padrão) até a INPUT-OUTPUT SECTION, onde declaramos tanto o arquivo de entrada quanto o relatório.

      *================================================================*
       IDENTIFICATION DIVISION.
      *----------------------------------------------------------------*
       PROGRAM-ID.    CRP0208.
       AUTHOR.        PAULO ANDRE DIAS.
       DATE-WRITTEN.  07/01/2017.
       REMARKS.
      *----------------------------------------------------------------*
      * SISTEMA:      CR - CONTAS A RECEBER
      * JOB:          02 - GERACAO DE FLUXO DE CAIXA
      * PROGRAMA:     08 - LISTA DUPLICATAS VALIDAS
      *
      * OBJETIVO:     LER O ARQUIVO DE DUPLICATAS VALIDAS E GERAR UMA
      *               LISTA SIMPLES PARA CONFERENCIA                 
      *                   
      * VERSOES:      DATA    DESCRICAO
      *               ------  ---------------------------------------
      *               XXXXXX  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      *
      *----------------------------------------------------------------*

      *================================================================*
       ENVIRONMENT DIVISION.
      *----------------------------------------------------------------*
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
           DECIMAL-POINT IS COMMA.

       INPUT-OUTPUT SECTION.
       FILE-CONTROL.

      * DUPLICATAS VALIDAS
           COPY CRS0207V.

      * LISTA DE DUPLICATAS PARA CONFERENCIA
           SELECT CRL0208 ASSIGN TO "$DAT/CRL0208.TXT"
                ORGANIZATION IS LINE SEQUENTIAL.

A declaração do relatório, neste caso, não usa nenhum book; o comando SELECT é codificado diretamente no programa e o mesmo acontecerá com o detalhamento do arquivo, mais a frente, na FILE SECTION.

Repare que a cláusula ASSIGN TO está associando o nome interno CRL0208 a um nome externo “$DAT/CRL0208.TXT”. Isso significa que o programa vai gerar o relatório como um arquivo texto em disco. Depois de gerado, poderemos direcioná-lo para qualquer servidor ou aplicativo de impressão se quisermos efetivamente vê-lo no papel.

O relatório é organizado como LINE SEQUENTIAL (como os arquivos anteriores) porque queremos que cada linha termine com um line feed (no Linux) ou carriage return + line feed (no Windows). Isso fará com que o arquivo possa ser carregado num editor de texto simples.

Nos programas anteriores, quando detalhamos nossos arquivos sequenciais na FILE SECTION, tivemos que declarar todos os campos que faziam parte dos registros daqueles arquivos. Quando trabalhamos com relatórios, porém, o detalhamento do arquivo indica apenas um tamanho fixo para as linhas do relatório (80 ou 132) e isso tem um motivo.

Relatórios possuem cabeçalhos, rodapés, linhas de separação e até linhas de detalhes com muitos valores fixos. Nosso layout, por exemplo, tem nome da empresa, nome de sistema e alguns labels como “Data”, “Hora” e “Pagina”. É muito mais prático criar esses labels como constantes na WORKING-STORAGE (usando a cláusula VALUE) do que preenchê-los com o comando MOVE cada vez que uma linha tiver que ser gravada no relatório. Esse conceito ficará mais claro ao longo do programa. Por ora vamos apenas “detalhar” nosso relatório informando que cada uma de suas linhas terá o tamanho fixo de 80 caracteres:

      *================================================================*
       DATA DIVISION.
      *----------------------------------------------------------------*
       FILE SECTION.

      * DUPLICATAS VALIDAS
           COPY CRF0207V.

      * LISTA DE DUPLICATAS PARA CONFERENCIA
       FD CRL0208.
       01 CRL0208-REGISTRO PIC X(080).

Como todo arquivo, o nome que indicamos na FD precisa ser igual ao nome que usamos na ENVIRONMENT: no caso, CRL0208. Usamos também a mesma convenção de usar o nome do arquivo como prefixo para o nome do registro, que definimos como nível 01. Como não criaremos itens elementares nesse registro, especificamos a picture no próprio nível 01, indicando que o registro é um campo alfanumérico com 80 posições.

Definindo variáveis de apoio

Pelo que vimos até aqui já sabemos que nosso programa precisará de algumas variáveis de trabalho para apoiar a geração do relatório. A primeira delas é o file status do arquivo de entrada:

      *================================================================*
       WORKING-STORAGE SECTION.
      *----------------------------------------------------------------*
       01 WT-FILE-STATUS.
           03 WT-ST-CRA0207V           PIC  X(002) VALUE SPACES.

Relatórios tradicionalmente não usam file status, mesmo que nesse caso estejamos gerando nosso relatório como um arquivo texto em disco.

Vimos que nosso relatório terá um rodapé que mostrará a quantidade de registros lidos/listados. Para isso teremos que criar uma variável de trabalho para contar esses registros. Além disso, o layout nos mostra que todas as páginas serão numeradas, e por isso precisamos também de uma variável para contar as páginas impressas.

      *================================================================*
       WORKING-STORAGE SECTION.
      *----------------------------------------------------------------*
       01 WT-FILE-STATUS.
           03 WT-ST-CRA0207V           PIC  X(002) VALUE SPACES.

       01 WT-CONTADORES.
           03 WT-CT-LIDOS              PIC  9(006) VALUE ZEROS.
           03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.

Cada página terá cinco linhas de cabeçalho, contando com a linha tracejada para separação. A última página terá também um rodapé com 4 linhas (duas linhas separadoras e duas linhas com labels e totais). Se vamos adotar a convenção de 60 linhas por página, então precisamos garantir que cada página receba apenas 51 linhas de detalhe: 5 linhas de cabeçalho mais 51 linhas de detalhe mais 4 linhas de rodapé totalizam 60 linhas numa página).

Para contar a quantidade de linhas impressas precisaremos de mais uma variável de trabalho:

      *================================================================*
       WORKING-STORAGE SECTION.
      *----------------------------------------------------------------*
       01 WT-FILE-STATUS.
           03 WT-ST-CRA0207V           PIC  X(002) VALUE SPACES.

       01 WT-CONTADORES.
           03 WT-CT-LIDOS              PIC  9(006) VALUE ZEROS.
           03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
           03 WT-CT-LINHAS             PIC  9(002) VALUE 99.

E porque iniciamos essa variável com 99? O cabeçalho será impresso numa nova página toda vez que esse contador ultrapassar o limite de 60 linhas. Logo, para garantir que o cabeçalho apareça também na primeira página, precisamos garantir que esse contador já comece “estourado”. Poderíamos usar qualquer valor superior a 60 para iniciar essa variável.

O rodapé do nosso relatório mostrará também o somatório dos valores das duplicatas listadas. Precisamos então de uma variável para acumular esses valores, e vamos criá-la num item de grupo separado apenas para destacar que trata-se de um acumulador:

      *================================================================*
       WORKING-STORAGE SECTION.
      *----------------------------------------------------------------*
       01 WT-FILE-STATUS.
           03 WT-ST-CRA0207V           PIC  X(002) VALUE SPACES.

       01 WT-CONTADORES.
           03 WT-CT-LIDOS              PIC  9(006) VALUE ZEROS.
           03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
           03 WT-CT-LINHAS             PIC  9(002) VALUE 60.

       01 WT-ACUMULADORES.
           03 WT-AC-DUPLICATAS         PIC S9(013)V9(002) VALUE ZEROS.

Sabemos que as datas de emissão e vencimento do arquivo de entrada estão no formato AAAAMMDD. Queremos mostra-las em nosso relatório no formato padrão e editado: DD/MM/AA. Para isso usaremos uma subrotina que transforma uma data AAAAMMD em DD/MM/AAAA. Na nossa empresa fictícia essa subrotina se chama XXREDT4. Por isso vamos criar variáveis para guardar seu nome (e assim chamá-la dinamicamente na PROCEDURE)  e seu código de retorno (para validarmos se sua chamada foi bem sucedida).

      *================================================================*
       WORKING-STORAGE SECTION.
      *----------------------------------------------------------------*
       01 WT-FILE-STATUS.
           03 WT-ST-CRA0207V           PIC  X(002) VALUE SPACES.

       01 WT-CONTADORES.
           03 WT-CT-LIDOS              PIC  9(006) VALUE ZEROS.
           03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
           03 WT-CT-LINHAS             PIC  9(002) VALUE 60.

       01 WT-ACUMULADORES.
           03 WT-AC-DUPLICATAS         PIC S9(013)V9(002) VALUE ZEROS.

       01 WT-AUXILIARES.
           03 WT-NM-EDT4               PIC X(008) VALUE "XXREDT4".
           03 WT-RC-EDT4               PIC 9(002) VALUE ZEROS. 

Agora só faltam mais duas variáveis de apoio: uma para recebermos a data corrente do sistema e outra para a hora corrente do sistema. Usaremos essas variáveis para completar as informações do cabeçalho de nosso relatório:

     *================================================================*
       WORKING-STORAGE SECTION.
     *----------------------------------------------------------------*
       01 WT-FILE-STATUS.
           03 WT-ST-CRA0207V           PIC  X(002) VALUE SPACES.

       01 WT-CONTADORES.
           03 WT-CT-LIDOS              PIC  9(006) VALUE ZEROS.
           03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
           03 WT-CT-LINHAS             PIC  9(002) VALUE 60.

       01 WT-ACUMULADORES.
           03 WT-AC-DUPLICATAS         PIC S9(013)V9(002) VALUE ZEROS.

       01 WT-AUXILIARES.
           03 WT-NM-FDAT               PIC X(008) VALUE "XXRFDAT".
           03 WT-RC-FDAT               PIC 9(002) VALUE ZEROS.
           03 WT-DT-SISTEMA.
              05 ANO                   PIC 9(002) VALUE ZEROS.
              05 MES                   PIC 9(002) VALUE ZEROS.
              05 DIA                   PIC 9(002) VALUE ZEROS.
           03 WT-HR-SISTEMA.
              05 HORA                  PIC 9(002) VALUE ZEROS.
              05 MINUTO                PIC 9(002) VALUE ZEROS.
              05 SEGUNDO               PIC 9(002) VALUE ZEROS.

Com isso temos todas as variáveis de trabalho que precisaremos na PROCEDURE. Agora podemos codificar o layout do relatório.

Codificando o layout do relatório

Linhas de cabeçalho e separação, linhas de detalhe e rodapés também são codificados na WORKING-STORAGE SECTION. Valores fixos (como os labels que contêm nome da empresa e nome do sistema) nunca serão mencionados diretamente na PROCEDURE DIVISION e por isso sempre usaremos FILLERs para declará-los. Apenas as variáveis que serão preenchidas durante o processamento receberão algum nome. Seguindo a convenção que estamos adotando nesse livro, toda variável de trabalho relacionada a relatórios terão o prefixo WR- em seus nomes.

Vamos analisar detalhadamente a primeira linha de cabeçalho, pois as técnicas que veremos aqui serão as mesmas que usaremos nas demais linhas de nosso layout.

A primeira linha do cabeçalho mostrará a string “DATA: 99/99/99” alinhada à direita. Sabemos que cada linha de nosso relatório terá no máximo 80 caracteres. A string “DATA: 99/99/99” tem 14. Logo, para que ela termine exatamente na posição 80, precisamos fazer com que antes dela exista um ou mais campos com exatamente 66 caracteres (80 menos 14).

Cobol: Layout de linha de relatório
Figura 30. Montagem da primeira linha

O campo que vem antes dessa string é o nome da empresa (EMPRESA XYZ). Portanto, basta colocarmos o nome da empresa num FILLER de 66 posições e logo em seguida declararmos a string “DATA: “.

       01 WR-CAB1.
           03 FILLER                   PIC X(066) VALUE
              "EMPRESA XYZ".
           03 FILLER                   PIC X(006) VALUE
              "DATA: ".

Agora precisamos inserir a variável que receberá a data de impressão (a data corrente do sistema). Para isso criaremos um item de grupo que será formado por dia, mês e ano, com uma barra de separação entre eles:

       01 WR-CAB1.
           03 FILLER                   PIC X(066) VALUE
              "EMPRESA XYZ".
           03 FILLER                   PIC X(006) VALUE
              "DATA: ".
           03 WR-CAB-DATA.
              05 DIA                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE "/".
              05 MES                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE "/".
              05 ANO                   PIC 9(002) VALUE ZEROS.

Como teremos que fazer referência a essa variável na PROCEDURE, precisamos dar um nome para ela. Escolhemos WR-CAB-DATA pois isso deixará claro que se trata de uma variável para relatório (WR) existente num cabeçalho (CAB). Seus itens elementares receberam simplesmente os nomes DIA, MES e ANO.

Talvez você tenha notado que também usamos os nomes DIA, MES e ANO quando criamos a variável de trabalho que receberá a data do sistema. Isso não foi por acaso. Mais adiante veremos um novo formato do comando MOVE que facilita a movimentação de itens de grupo.

Entre os itens elementares DIA, MES e ANO colocamos dois FILLERs para posicionar as barras.

A segunda linha do cabeçalho segue a mesma lógica:

Cobol: Layout de linha de relatório
Figura 31. Montagem da segunda linha

A única diferença é que teremos um campo para receber a hora da impressão (hora corrente do sistema):

       01 WR-CAB2.
           03 FILLER                   PIC X(066) VALUE
              "CONTAS A RECEBER".
           03 FILLER                   PIC X(006) VALUE
              "HORA: ".
           03 WR-CAB-HORA.
              05 HOR                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE ":".
              05 MINUTO                PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE ":".
              05 SEGUNDO               PIC 9(002) VALUE ZEROS.

A terceira linha do cabeçalho é um pouco diferente porque tem um título que precisa ser centralizado. O título (DUPLICATAS VÁLIDAS) tem 18 caracteres. Logo, para centralizá-lo, precisamos colocar 31 caracteres de cada lado: (80 – 18) / 2.

Cobol: Layout de linha de relatório
Figura 32. Montagem da terceira linha do cabeçalho

O nome do relatório, portanto, ficará num FILLER com 31 caracteres:

       01 WR-CAB3.
           03 FILLER                   PIC X(031) VALUE 
              "CRL0208".

O layout mostra que a palavra “PAGINA: “ precisa estar alinhada com as palavras “DATA:” e “HORA:” das linhas de cima. Logo, para completar os 66 caracteres criamos o título do relatório com um FILLER de 35:

       01 WR-CAB3.
           03 FILLER                   PIC X(031) VALUE
              "CRL0208".
           03 FILLER                   PIC X(035) VALUE
              "DUPLICATAS VÁLIDAS".

E completamos com o label “PÁGINA: “ e a variável que exibirá o número das páginas:

01 WR-CAB3.
   03 FILLER                   PIC X(031) VALUE
      "CRL0208".
   03 FILLER                   PIC X(035) VALUE
      "DUPLICATAS VÁLIDAS".
   03 FILLER                   PIC X(011) VALUE
      "PAGINA: ".
   03 WR-CAB-PAGINA            PIC ZZ9 VALUE ZEROS.

Agora repare na picture que usamos para a variável WR-CAB-PAGINA. Ela é chamada de “picture de edição” e é usada quando precisamos criar máscaras para campos que serão exibidos na tela ou impressos em relatórios. O símbolo “Z” numa picture indica que um zero nessa posição deve ser substituído por um espaço em branco; PIC ZZ9 estabelece um campo numérico editado de três dígitos com supressão de zeros à esquerda.

Variáveis com pictures de edição são usadas apenas para exibição (usage display) e não podem participar de operações aritméticas. Por isso tivemos que criar uma variável auxiliar na WORKING-STORAGE, chamada WT-CT-PAGINA. A cada impressão de um novo cabeçalho nós incrementaremos essa variável auxiliar e em seguida a movimentaremos para WR-CAB-PAGINA.

A próxima linha do nosso cabeçalho é apenas uma linha separadora, preenchida com hífens.  Ela também será utilizada na impressão do rodapé, por isso lhe daremos um nome diferente: WR-SEP1. A cláusula VALUE ALL permite que se preencha toda a variável com um único caracter.

       01 WR-SEP1 PIC X(080) VALUE ALL “-“.

Como todas as linhas do nosso relatório são itens de grupo, faremos a mesma coisa com o separador apenas para manter a coerência visual:

       01 WR-SEP1.
           03 FILLER PIC X(080) VALUE ALL “-“.

A quarta linha do cabeçalho contém os nomes das colunas. Para simplificar, vamos alinhá-las à esquerda dos campos, com exceção da coluna valor, que alinharemos à direita:

Cobol: Layout de linha de relatório
Figura 33. Montagem da quarta linha do cabeçalho e da linha detalhe
        01 WR-CAB4.
           03  FILLER                  PIC X(012) VALUE "DUPLICATA".
           03  FILLER                  PIC X(010) VALUE "CLIENTE".
           03  FILLER                  PIC X(013) VALUE "EMISSAO".
           03  FILLER                  PIC X(018) VALUE "VENCIMENTO".
           03  FILLER                  PIC X(008) VALUE "VALOR".
           03  FILLER                  PIC X(003) VALUE "CAT".

Para a linha de detalhe usaremos o prefixo WR-DET- no nome das variáveis. Também usaremos FILLERs para criar os espaços entre os campos:

        01 WR-DET1.
           03  WR-DET-NR-FATURA        PIC 9(006) VALUE ZEROS.
           03  FILLER                  PIC X(001) VALUE "/".
           03  WR-DET-NR-DUPLICATA     PIC 9(002) VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-CD-CLIENTE       PIC X(006) VALUE SPACES.
           03  FILLER                  PIC X(004) VALUE SPACES.
           03  WR-DET-DT-EMISSAO       PIC 99/99/9999 VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-DT-VENCIMENTO    PIC 99/99/9999 VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-VL-FATURA        PIC ZZZ.ZZ9,99 VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-CD-CATEGORIA     PIC X(003) VALUE SPACES.

É muito comum utilizarmos a picture de edição 99/99/9999 para datas. Isso é o ideal quando queremos mover uma data armazenada em campo numérico que esteja no formato DDMMAAAA. Mas no nosso exemplo, as datas estão no formato invertido (AAAAMMDD). Logo, se a linha detalhe ficar do jeito que está nossas datas aparecerão assim: 20/16/1025 ou 20/15/1102…

Por isso, mais adiante na PROCEDURE, usaremos uma subrotina que converte formatos de datas. Ela recebe uma variável numérica que tenha uma data no formato AAAAMMDD e gera uma variável alfanumérica que com a mesma data no formato DD/MM/AAAA. As datas na linha de detalhe, portanto, precisam adotar esse formato:

        01 WR-DET1.
           03  WR-DET-NR-FATURA        PIC 9(006) VALUE ZEROS.
           03  FILLER                  PIC X(001) VALUE "/".
           03  WR-DET-NR-DUPLICATA     PIC 9(002) VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-CD-CLIENTE       PIC X(006) VALUE SPACES.
           03  FILLER                  PIC X(004) VALUE SPACES.
           03  WR-DET-DT-EMISSAO       PIC X(010) VALUE SPACES.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-DT-VENCIMENTO    PIC X(010) VALUE SPACES.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-VL-FATURA        PIC ZZZ.ZZ9,99 VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-CD-CATEGORIA     PIC X(003) VALUE SPACES.

Repare agora a picture de edição da variável valor. Esse é um formato muito comum quando queremos exibir valores monetários. A picture da variável CRA0207V-VL-FATURA é S9(013)V9(002), já a variável WR-DET-VL-FATURA está com formato ZZZ.ZZ9,99, com apenas seis dígitos na parte inteira. Se quiséssemos que WR-DET-VL-FATURA tivesse o mesmo tamanho de CRA0207V-VL-FATURA, teríamos que criar a variável assim:

           03  WR-DET-VL-FATURA PIC Z.ZZZ.ZZZ.ZZZ.ZZ9,99 VALUE ZEROS.

No contexto desse exemplo, porém, não temos valores de duplicatas superiores a R$ 999.999,99, logo optamos por usar uma picture menor. O símbolo Z, como já vimos, faz com que o COBOL substitua zeros não significativos por um espaço em branco.

Para terminar a definição do relatório só faltam as linhas do rodapé, que aparecerão na última página e que mostrarão a quantidade de registros listados e o somatório do valor das duplicatas:

Cobol: Layout de linha de relatório
Figura 34. Montagem das linhas de rodapé

As técnicas que usamos aqui para calcular o tamanho dos FILLERs são as mesmas que mostramos na definição das linhas anteriores:

        01 WR-ROD1.
           03  FILLER                  PIC X(054) VALUE SPACES.
           03  FILLER                  PIC X(020) VALUE
               "DUPLICATAS LISTADAS:".
           03  WR-ROD-CT-LIDOS         PIC ZZ.ZZ9 VALUE ZEROS.

       01 WR-ROD2.
           03  FILLER                  PIC X(054) VALUE SPACES.
           03  FILLER                  PIC X(014) VALUE
               "VALOR TOTAL: ".
           03  WR-ROD-AC-DUPLICATAS    PIC Z.ZZZ.ZZ9,99 VALUE ZEROS.

Agora sim estamos prontos para codificar a PROCEDURE que é onde o relatório será realmente impresso. Antes disso, vamos ver como ficou nossa WORKING-STORAGE completa:

      *================================================================*
       WORKING-STORAGE SECTION.
      *----------------------------------------------------------------*
       01 WT-FILE-STATUS.
           03 WT-ST-CRA0207V           PIC  X(002) VALUE SPACES.

       01 WT-CONTADORES.
           03 WT-CT-LIDOS              PIC  9(006) VALUE ZEROS.
           03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
           03 WT-CT-LINHAS             PIC  9(002) VALUE 60.

       01 WT-ACUMULADORES.
           03 WT-AC-DUPLICATAS         PIC S9(013)V9(002) VALUE ZEROS.

       01 WT-AUXILIARES.
           03 WT-NM-EDT4               PIC X(008) VALUE "XXREDT4".
           03 WT-RC-EDT4               PIC 9(002) VALUE ZEROS.
           03 WT-DT-SISTEMA.
              05 ANO                   PIC 9(002) VALUE ZEROS.
              05 MES                   PIC 9(002) VALUE ZEROS.
              05 DIA                   PIC 9(002) VALUE ZEROS.
           03 WT-HR-SISTEMA.
              05 HORA                  PIC 9(002) VALUE ZEROS.
              05 MINUTO                PIC 9(002) VALUE ZEROS.
              05 SEGUNDO               PIC 9(002) VALUE ZEROS.

       01 WR-CAB1.
           03 FILLER                   PIC X(066) VALUE
              "EMPRESA XYZ".
           03 FILLER                   PIC X(006) VALUE
              "DATA: ".
           03 WR-CAB-DATA.
              05 DIA                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE "/".
              05 MES                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE "/".
              05 ANO                   PIC 9(002) VALUE ZEROS.

       01 WR-CAB2.
           03 FILLER                   PIC X(066) VALUE
              "CONTAS A RECEBER".
           03 FILLER                   PIC X(006) VALUE
              "HORA: ".
           03 WR-CAB-HORA.
              05 HORA                  PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE ":".
              05 MINUTO                PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE ":".
              05 SEGUNDO               PIC 9(002) VALUE ZEROS.

       01 WR-CAB3.
           03 FILLER                   PIC X(031) VALUE
              "CRL0208".
           03 FILLER                   PIC X(035) VALUE
              "DUPLICATAS VALIDAS".
           03 FILLER                   PIC X(011) VALUE
              "PAGINA: ".
           03 WR-CAB-PAGINA            PIC ZZ9 VALUE
              ZEROS.

       01 WR-SEP1.
           03  FILLER                  PIC X(080) VALUE ALL "-".

       01 WR-CAB4.
           03  FILLER                  PIC X(012) VALUE "DUPLICATA".
           03  FILLER                  PIC X(010) VALUE "CLIENTE".
           03  FILLER                  PIC X(013) VALUE "EMISSAO".
           03  FILLER                  PIC X(018) VALUE "VENCIMENTO".
           03  FILLER                  PIC X(008) VALUE "VALOR".
           03  FILLER                  PIC X(009) VALUE "CATEGORIA".

       01 WR-DET1.
           03  WR-DET-NR-FATURA        PIC 9(006) VALUE ZEROS.
           03  FILLER                  PIC X(001) VALUE "/".
           03  WR-DET-NR-DUPLICATA     PIC 9(002) VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-CD-CLIENTE       PIC X(006) VALUE SPACES.
           03  FILLER                  PIC X(004) VALUE SPACES.
           03  WR-DET-DT-EMISSAO       PIC X(010) VALUE SPACES.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-DT-VENCIMENTO    PIC X(010) VALUE SPACES.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-VL-FATURA        PIC ZZZ.ZZ9,99 VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-CD-CATEGORIA     PIC X(003) VALUE SPACES.

       01 WR-ROD1.
           03  FILLER                  PIC X(054) VALUE SPACES.
           03  FILLER                  PIC X(020) VALUE
               "DUPLICATAS LISTADAS:".
           03  WR-ROD-CT-LIDOS         PIC ZZ.ZZ9 VALUE ZEROS.

       01 WR-ROD2.
           03  FILLER                  PIC X(054) VALUE SPACES.
           03  FILLER                  PIC X(014) VALUE
               "VALOR TOTAL: ".
           03  WR-ROD-AC-DUPLICATAS    PIC Z.ZZZ.ZZ9,99 VALUE ZEROS.

Codificando o programa

Nossa PROCEDURE será dividida em quatro parágrafos, como mostramos na figura abaixo:

Cobol: Exemplo de diagrama estruturado de programa
Figura 35. Diagrama estruturado do programa CRP0208

No parágrafo INICIA colocaremos a abertura dos arquivos e a primeira leitura do arquivo de entrada.

No parágrafo IMPRIME-RELATORIO ficará a impressão da linha de detalhe. Esse parágrafo será executado para todos os registros do arquivo de entrada. Cada vez que o contador de linhas ultrapassar o limite de 60 linhas por página o programa chamará o parágrafo para impressão de cabeçalho.

Depois que todas as linhas forem impressas, o parágrafo IMPRIME-RODAPE será chamado para imprimir os totais. Pode ser que o parágrafo de impressão de cabeçalhos também tenha que ser chamado aqui, caso o contador de linhas também ultrapasse o limite de linhas por página.

O parágrafo TERMINA, terá os comandos para fechamento de arquivo e retirada da subrotina de memória.

O início da PROCEDURE portanto só precisa chamar os quatro parágrafos principais e encerrar o programa:

      *================================================================*
       PROCEDURE DIVISION.
      *----------------------------------------------------------------*
       0-PRINCIPAL.

           PERFORM 1-INICIA
           PERFORM 2-IMPRIME-RELATORIO UNTIL WT-ST-CRA0207V NOT = "00"
           PERFORM 3-IMPRIME-RODAPE
           PERFORM 4-TERMINA
           STOP RUN.

      *----------------------------------------------------------------*
      * ABRE ARQUIVOS E LE PRIMEIRO REGISTRO DO ARQUIVO DE ENTRADA
      *----------------------------------------------------------------*
       1-INICIA.

           OPEN INPUT CRA0207V
           OPEN OUTPUT CRL0208
           READ CRA0207V.

A primeira coisa que faremos no parágrafo de impressão do relatório é testar o contador de linhas. Se ele estiver com um valor maior que 60 chamaremos o parágrafo que imprime cabeçalho:

      *----------------------------------------------------------------*
      * LISTA TODOS OS REGISTROS DO ARQUIVO DE ENTRADA
      *----------------------------------------------------------------*
       2-IMPRIME-RELATORIO.

           IF WT-CT-LINHAS > 60
               PERFORM X1-IMPRIME-CABECALHO
           END-IF

Você se lembra que quando criamos a variável WT-CT-LINHA nós estabelecemos para ela um valor inicial igual a 99. Isso fará com que o programa entre nesse IF antes que a primeira linha seja impressa, garantindo que o cabeçalho aparecerá na primeira página do relatório.

Logo em seguida usaremos o comando MOVE, já conhecido, para preencher todos os campos da linha de detalhe. As únicas exceções são os campos data de emissão e data de vencimento, pois para eles precisaremos chamar a subrotina XXREDT4 que vai transformar uma data numérica AAAAMMDD numa data alfanumérica DD/MM/AAAA. Os parâmetros serão passados “by reference” (por default), o que permitirá à subrotina ler e alterar diretamente as variáveis que estamos passando:

      *----------------------------------------------------------------*
      * LISTA TODOS OS REGISTROS DO ARQUIVO DE ENTRADA
      *----------------------------------------------------------------*
       2-IMPRESSAO-RELATORIO.

           IF WT-CT-LINHAS > 57
               PERFORM X1-IMPRESSAO-CABECALHO
           END-IF

           MOVE CRA0207V-NR-FATURA TO WR-DET-NR-FATURA
           MOVE CRA0207V-NR-DUPLICATA TO WR-DET-NR-DUPLICATA
           MOVE CRA0207V-CD-CLIENTE TO WR-DET-CD-CLIENTE

           CALL WT-NM-EDT4 USING CRA0207V-DT-EMISSAO
                                 WR-DET-DT-EMISSAO
                                 WT-RC-EDT4

           CALL WT-NM-EDT4 USING CRA0207V-DT-VENCIMENTO
                                 WR-DET-DT-VENCIMENTO
                                 WT-RC-EDT4

           MOVE CRA0207V-VL-FATURA TO WR-DET-VL-FATURA
           MOVE CRA0207V-CD-CATEGORIA TO WR-DET-CD-CATEGORIA

O comando que usaremos para “imprimir” a linha de detalhe é praticamente o mesmo que usamos para gravar registros em arquivos de saída, em programas anteriores: WRITE. Podemos codificá-lo assim:

           MOVE WR-DET TO CRL0208-REGISTRO
           WRITE CRL0208-REGISTRO

No entanto, usaremos a opção FROM para eliminar esse MOVE:

           WRITE CRL0208-REGISTRO FROM WR-DET

Algumas vezes precisamos imprimir alguma coisa saltando uma determinada quantidade de linhas. Na prática, o COBOL insere um conjunto de caracteres LF (ou LF+CR, no caso do Windows) que faz com a linha seja impressa depois de “x” linhas em branco. Seria o caso do exemplo abaixo:

           WRITE CRL0208-REGISTRO FROM WR-DET AFTER 5 LINES

Mas no nosso caso queremos apenas uma linha embaixo da outra, o que seria equivalente a “AFTER 1 LINE”. Como essa é a opção default não vamos nos preocupar em codificá-la.

Agora que já imprimimos a linha de detalhe, vamos incrementar os contadores de registros lidos e linhas impressas e acumular o valor da duplicata. O último comando do parágrafo será a leitura do próximo registro do arquivo de entrada:

      *----------------------------------------------------------------*
      * LISTA TODOS OS REGISTROS DO ARQUIVO DE ENTRADA
      *----------------------------------------------------------------*
       2-IMPRESSAO-RELATORIO.

           IF WT-CT-LINHAS > 57
               PERFORM X1-IMPRESSAO-CABECALHO
           END-IF

           MOVE CRA0207V-NR-FATURA TO WR-DET-NR-FATURA
           MOVE CRA0207V-NR-DUPLICATA TO WR-DET-NR-DUPLICATA
           MOVE CRA0207V-CD-CLIENTE TO WR-DET-CD-CLIENTE

           CALL WT-NM-EDT4 USING CRA0207V-DT-EMISSAO
                                 WR-DET-DT-EMISSAO
                                 WT-RC-EDT4

           CALL WT-NM-EDT4 USING CRA0207V-DT-VENCIMENTO
                                 WR-DET-DT-VENCIMENTO
                                 WT-RC-EDT4

           MOVE CRA0207V-VL-FATURA TO WR-DET-VL-FATURA
           MOVE CRA0207V-CD-CATEGORIA TO WR-DET-CD-CATEGORIA

           WRITE CRL0208-REGISTRO FROM WR-DET1
           ADD 1 TO WT-CT-LINHAS
           ADD 1 TO WT-CT-LIDOS
           ADD CRA0207V-VL-FATURA TO WT-AC-DUPLICATAS

           READ CRA0207V.

Isso é tudo o que precisamos para imprimir o relatório. Agora construiremos o terceiro parágrafo, responsável pela impressão do rodapé. Lembre-se que uma das boas práticas de programação estruturada é criar os parágrafos na mesma ordem em que eles aparecem nos comandos PERFORM. Logo, depois de codificar o parágrafo 2- é hora de codificar o 3-:

      *----------------------------------------------------------------*
      * IMPRIME RODAPE'
      *----------------------------------------------------------------*
       3-IMPRIME-RODAPE.

           IF WT-CT-LINHAS > 60
               PERFORM X1-IMPRIME-CABECALHO
           END-IF

           MOVE WT-CT-LIDOS TO WR-ROD-CT-LIDOS
           MOVE WT-AC-DUPLICATAS TO WR-ROD-AC-DUPLICATAS

           WRITE CRL0208-REGISTRO FROM WR-SEP1
           WRITE CRL0208-REGISTRO FROM WR-ROD1
           WRITE CRL0208-REGISTRO FROM WR-ROD2
           WRITE CRL0208-REGISTRO FROM WR-SEP1.

Repare que ele também testa o contador de linhas impressas e chama o parágrafo de impressão de cabeçalhos caso esse contador esteja maior que o limite de linhas por página.

Os únicos campos que precisamos movimentar aqui é o contador e o acumulador. Os comandos WRITE para impressão são iguais aos que já vimos. A diferença é que precisamos imprimir a linha WR-SEP1 duas vezes para garantir que o rodapé terá duas linhas tracejadas, como previsto pelo layout.

Logo em seguida, codificamos o parágrafo para término do programa, muito semelhante ao que fizemos nos exemplos anteriores…

      *----------------------------------------------------------------*
      * FECHA ARQUIVOS E EXIBE OS CONTADORES DE REGISTROS LIDOS E IM-
      * PRESSOS        
      *----------------------------------------------------------------*
       4-TERMINO.

           CANCEL WT-NM-EDT4

           CLOSE CRA0207V CRL0208.

E finalmente o último parágrafo, onde o cabeçalho será impresso:

      *----------------------------------------------------------------*
      * IMPRIME CABECALHO
      *----------------------------------------------------------------*
       X1-IMPRESSAO-CABECALHO.

           ACCEPT WT-DT-SISTEMA FROM DATE
           ACCEPT WT-HR-SISTEMA FROM TIME
           ADD 1 TO WT-CT-PAGINA

           MOVE CORR WT-DT-SISTEMA TO WR-CAB-DATA
           MOVE CORR WT-HR-SISTEMA TO WR-CAB-HORA
           MOVE WT-CT-PAGINA TO WR-CAB-PAGINA

           WRITE CRL0208-REGISTRO FROM WR-CAB1 AFTER PAGE
           WRITE CRL0208-REGISTRO FROM WR-CAB2
           WRITE CRL0208-REGISTRO FROM WR-CAB3
           WRITE CRL0208-REGISTRO FROM WR-SEP1
           WRITE CRL0208-REGISTRO FROM WR-CAB4
           WRITE CRL0208-REGISTRO FROM WR-SEP1

           MOVE 6 TO WT-CT-LINHAS.

Usamos um comando novo para obter a data e a hora do sistema: ACCEPT. Existem dezenas de formatos diferentes para o comando ACCEPT, pois ele pode ser usado tanto para recuperar informações do sistema operacional (como data e hora corrente) quanto para obter argumentos passados ao programa pela linha de comando, ou informações fornecidas pelo usuário via teclado, ou mesmo telas inteiras…

Por enquanto, nos interessa apenas saber que ACCEPT WT-DT-SISTEMA FROM DATE, preenche a variável (WT-DT-SISTEMA) com a data do sistema, que vem no formato AAMMDD. O comando ACCEPT WT-HR-SISTEMA FROM TIME preenche a variável informada com a hora corrente do sistema, que vem no formato HHMMSS.

Depois de somar 1 ao contador de páginas, usamos mais um comando novo: MOVE CORR. Você se lembra que criamos na WORKING a variável WT-DT-SISTEMA para armazenar a data do sistema, e que ela tinha a seguinte estrutura:

          03 WT-DT-SISTEMA.
              05 ANO                   PIC 9(002) VALUE ZEROS.
              05 MES                   PIC 9(002) VALUE ZEROS.
              05 DIA                   PIC 9(002) VALUE ZEROS.

E lembra também que criamos uma variável para mostrar a data no cabeçalho usando itens elementares que tinham o mesmo nome:

          03 WR-CAB-DATA.
              05 DIA                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE "/".
              05 MES                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE "/".
              05 ANO                   PIC 9(002) VALUE ZEROS.

O que o comando “MOVE CORR item-grupo-1 TO item-grupo-2” faz é copiar apenas os valores dos itens elementares que tenham nomes iguais, tanto em item-grupo-1 quanto em item-grupo-2. E esses itens elementares não precisam estar na mesma ordem. Logo, na prática ele inverteu a data do sistema e a colocou num formato legível no cabeçalho. Usamos o mesmo recurso para movimentar a hora corrente do sistema.

Cobol: Itens elementares com nomes duplicados

Outro detalhe importante: repare que usamos a opção AFTER PAGE para imprimir a primeira linha do cabeçalho. Isso insere um caracter especial que força a impressora a fazer a avançar uma página antes de continuar a impressão; a mesma função do page break que inserimos nos editores de texto.

Depois que o cabeçalho é impresso, precisamos reiniciar o contador de linhas por página. Nós movemos 6 para esse contador porque, nesse momento, é essa a quantidade de linhas que foram impressas na nova página.

E está pronto. Depois de compilar, linkeditar e executar (apontando naturalmente para um arquivo CRA0207V que exista) o resultado será esse:

EMPRESA XYZ                                                       DATA: 09/01/17

CONTAS A RECEBER                                                  HORA: 15:17:30

CRL0208                        DUPLICATAS VALIDAS                 PAGINA:      1

--------------------------------------------------------------------------------
DUPLICATA   CLIENTE   EMISSAO      VENCIMENTO        VALOR   CATEGORIA
--------------------------------------------------------------------------------
001324/01   000015    25/10/2016   25/11/2016       123,45   SLA
001325/01   000010    25/10/2016   25/11/2016     2.319,00   SLA
001326/01   000009    25/10/2016   25/11/2016       590,00   SLA
001326/02   000009    25/10/2016   25/11/2016       590,00   SLA
001326/03   000009    25/10/2016   25/11/2016       590,00   SLA
001326/04   000009    25/10/2016   25/11/2016       590,00   SLA
001326/05   000009    25/10/2016   25/11/2016       590,00   SLA
001327/01   000010    25/10/2016   25/11/2016     4.850,00   SLA
001328/01   000011    25/10/2016   25/11/2016     1.810,15   SLA
001329/01   000008    25/10/2016   25/11/2016     5.650,00   SLA
001330/01   000005    25/10/2016   25/11/2016        45,00   SLA
001331/01   000004    25/10/2016   25/11/2016     2.100,00   SLA
001332/01   000003    25/10/2016   25/11/2016       510,00   SLA
001333/01   000003    25/10/2016   25/11/2016     2.740,00   SLA
001333/02   000003    25/10/2016   25/11/2016     2.740,00   SLA
--------------------------------------------------------------------------------
                                                      DUPLICATAS LISTADAS:    15
                                                      VALOR TOTAL:     25.837,60
--------------------------------------------------------------------------------

O programa completo

O trecho abaixo mostra a PROCEDURE DIVISION completa do programa que acabamos de construir:

      *================================================================*
       PROCEDURE DIVISION.
      *----------------------------------------------------------------*
       0-PRINCIPAL.

           PERFORM 1-INICIA
           PERFORM 2-IMPRIME-RELATORIO UNTIL WT-ST-CRA0207V NOT = "00"
           PERFORM 3-IMPRIME-RODAPE
           PERFORM 4-TERMINA
           STOP RUN.

      *----------------------------------------------------------------*
      * ABRE ARQUIVOS E LE PRIMEIRO REGISTRO DO ARQUIVO DE ENTRADA
      *----------------------------------------------------------------*
       1-INICIA.

           OPEN INPUT CRA0207V
           OPEN OUTPUT CRL0208
           READ CRA0207V.

      *----------------------------------------------------------------*
      * LISTA TODOS OS REGISTROS DO ARQUIVO DE ENTRADA
      *----------------------------------------------------------------*
       2-IMPRIME-RELATORIO.

           IF WT-CT-LINHAS > 60
               PERFORM X1-IMPRIME-CABECALHO
           END-IF

           MOVE CRA0207V-NR-FATURA TO WR-DET-NR-FATURA
           MOVE CRA0207V-NR-DUPLICATA TO WR-DET-NR-DUPLICATA
           MOVE CRA0207V-CD-CLIENTE TO WR-DET-CD-CLIENTE

           CALL WT-NM-EDT4 USING CRA0207V-DT-EMISSAO
                                 WR-DET-DT-EMISSAO
                                 WT-RC-EDT4

           CALL WT-NM-EDT4 USING CRA0207V-DT-VENCIMENTO
                                 WR-DET-DT-VENCIMENTO
                                 WT-RC-EDT4

           MOVE CRA0207V-VL-FATURA TO WR-DET-VL-FATURA
           MOVE CRA0207V-CD-CATEGORIA TO WR-DET-CD-CATEGORIA
           WRITE CRL0208-REGISTRO FROM WR-DET1

           ADD 1 TO WT-CT-LINHAS
           ADD 1 TO WT-CT-LIDOS
           ADD CRA0207V-VL-FATURA TO WT-AC-DUPLICATAS

           READ CRA0207V.

      *----------------------------------------------------------------*
      * IMPRIME RODAPE'
      *----------------------------------------------------------------*
       3-IMPRIME-RODAPE.

           IF WT-CT-LINHAS > 57
               PERFORM X1-IMPRESSAO-CABECALHO
           END-IF

           MOVE WT-CT-LIDOS TO WR-ROD-CT-LIDOS
           MOVE WT-AC-DUPLICATAS TO WR-ROD-AC-DUPLICATAS

           WRITE CRL0208-REGISTRO FROM WR-SEP1
           WRITE CRL0208-REGISTRO FROM WR-ROD1
           WRITE CRL0208-REGISTRO FROM WR-ROD2
           WRITE CRL0208-REGISTRO FROM WR-SEP1.

      *----------------------------------------------------------------*
      * FECHA ARQUIVOS E EXIBE OS CONTADORES DE REGISTROS LIDOS E IM-
      * PRESSOS        
      *----------------------------------------------------------------*
       4-TERMINA.

           CANCEL WT-NM-EDT4

           CLOSE CRA0207V CRL0208.

      *----------------------------------------------------------------*
      * IMPRIME CABECALHO
      *----------------------------------------------------------------*
       X1-IMPRIME-CABECALHO.

           ACCEPT WT-DT-SISTEMA FROM DATE
           ACCEPT WT-HR-SISTEMA FROM TIME
           ADD 1 TO WT-CT-PAGINA

           MOVE CORR WT-DT-SISTEMA TO WR-CAB-DATA
           MOVE CORR WT-HR-SISTEMA TO WR-CAB-HORA
           MOVE WT-CT-PAGINA TO WR-CAB-PAGINA

           WRITE CRL0208-REGISTRO FROM WR-CAB1 AFTER PAGE
           WRITE CRL0208-REGISTRO FROM WR-CAB2
           WRITE CRL0208-REGISTRO FROM WR-CAB3
           WRITE CRL0208-REGISTRO FROM WR-SEP1
           WRITE CRL0208-REGISTRO FROM WR-CAB4
           WRITE CRL0208-REGISTRO FROM WR-SEP1

           MOVE 6 TO WT-CT-LINHAS.

Anterior Conteúdo Próxima