TReport com sub-secoes e totalizadores

Como criar relatorio TReport hierarquico — secao principal + sub-secao + totalizador automatico. Padrao de relatorio gerencial.

TReport e o framework moderno de relatorios. Sua maior virtude esta em sub-secoes hierarquicas — voce define uma secao principal (clientes) e sub-secoes (titulos do cliente), e o framework cuida da agregacao, totalizacao e quebras automaticas.

Estrutura tipica

Codigo completo

#include "totvs.ch"
#include "totvs.ch"
#include "report.ch"

User Function RelTitCli()
    Local oReport := TReport():New("RELTITCLI", ;
        "Titulos em aberto por Cliente", ;
        "MTRELTIT", ;
        {|oRep| ImprimeRel(oRep)}, ;
        "Lista de titulos a receber agrupado por cliente")

    // Secao 1: Cliente
    Local oSecCli := TRSection():New(oReport, "Cliente", {"SA1"})
    oSecCli:SetTotalInLine(.F.)

    TRCell():New(oSecCli, "A1_COD",   "SA1", "Codigo")
    TRCell():New(oSecCli, "A1_NOME",  "SA1", "Nome")
    TRCell():New(oSecCli, "A1_CGC",   "SA1", "CNPJ", "@R 99.999.999/9999-99")

    // Sub-secao: Titulos do cliente
    Local oSecTit := TRSection():New(oSecCli, "Titulos", {"SE1"})

    TRCell():New(oSecTit, "E1_NUM",     "SE1", "Numero")
    TRCell():New(oSecTit, "E1_PARCELA", "SE1", "Parc")
    TRCell():New(oSecTit, "E1_VENCREAL","SE1", "Vencto")
    TRCell():New(oSecTit, "E1_VALOR",   "SE1", "Valor", "@E 999,999.99", 14)

    // Total automatico
    TRFunction():New(oSecTit:Cell("E1_VALOR"), NIL, "SUM", ;
                     oSecCli, "Subtotal cliente", "@E 999,999.99", NIL, .F.)

    oReport:PrintDialog()
Return

Static Function ImprimeRel(oReport)
    Local oSecCli := oReport:Section(1)
    Local oSecTit := oReport:Section(1):Section(1)

    SA1->(DBSetOrder(1))
    SA1->(DBSeek(xFilial("SA1")))

    oSecCli:Init()

    While !SA1->(Eof()) .And. SA1->A1_FILIAL == xFilial("SA1")

        oSecCli:PrintLine()

        // Filhos: titulos em aberto desse cliente
        SE1->(DBSetOrder(2))  // indice por cliente
        SE1->(DBSeek(xFilial("SE1") + SA1->A1_COD + SA1->A1_LOJA))

        oSecTit:Init()
        While !SE1->(Eof()) .And. ;
              SE1->E1_FILIAL  == xFilial("SE1") .And. ;
              SE1->E1_CLIENTE == SA1->A1_COD    .And. ;
              SE1->E1_LOJA    == SA1->A1_LOJA

            If Empty(SE1->E1_BAIXA)  // so em aberto
                oSecTit:PrintLine()
            EndIf
            SE1->(DBSkip())
        EndDo
        oSecTit:Finish()

        SA1->(DBSkip())
    EndDo

    oSecCli:Finish()
Return

Variantes uteis

1. Quebra de pagina por cliente

oSecCli:SetPageBreak(.T.)

2. Total em pe de pagina (e nao por secao)

TRFunction():New(oSecTit:Cell("E1_VALOR"), NIL, "SUM", ;
                 oReport, "Total geral", "@E 999,999,999.99", NIL, .T.)

3. Cabecalho custom no relatorio

oReport:SetTitle("Titulos por Cliente - " + DToC(dDataBase))
oReport:SetMargins(2, 2, 2, 2)
oReport:SetLandscape()  // paisagem

Exportacao automatica

TReport exporta nativamente em PDF, XLSX, CSV, HTML. O usuario escolhe na tela de impressao. Voce nao escreve nada extra — o framework cuida.

Pegadinhas

Verificacao

  1. Compile a User Function via /advpl-compile
  2. Acesse menu > Atualizacoes > Relatorios
  3. Cadastre rotina em SX2/menu apontando pra U_RelTitCli
  4. Execute e teste PDF + XLSX

Veja também