Criando Relatório em tReport de forma simples


Muitos amigos que estão começando a desenvolver em ADVPL sempre me perguntam como fazer um relatório simples, porém muito eficiente. Hoje irei publicar um exemplo de relatório enviado pelo amigo Robson Gonçalves.

#Include 'Protheus.ch'
#Include 'Report.ch'

#DEFINE NOME_REL   'xTReport'
#DEFINE TITULO_REL 'Relatório de exemplo - TReport'
#DEFINE DESCRI_REL 'Este relatório é a utilização do TReport, a ideia é exemplificar da maneitra simples.'
#DEFINE ABA_PLAN   'Exemplo - TReport'

//-----------------------------------------------------------------------
// Rotina | xTReport     | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Esta rotina exemplifica a utilização do TReport.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
User Function xTReport()
	Local aSay := {}
	Local aButton := {}
	
	Local nOpcao := 0
	
	Private cCadastro := ABA_PLAN
	
	AAdd(aSay,DESCRI_REL)
	AAdd(aSay,'')
	AAdd(aSay,'Clique em OK para prosseguir....')
	
	AAdd(aButton, { 1,.T.,{|| nOpcao := 1, FechaBatch() }})
	AAdd(aButton, { 2,.T.,{|| FechaBatch()              }})
    
        //A função FormBatch mostrar uma mensagem na tela e as opções disponíveis para o usuário
        //(para saber mais sobre esta função acesse o link http://tdn.totvs.com/pages/viewpage.action?pageId=24346908)
	FormBatch( cCadastro, aSay, aButton )
	
	If nOpcao==1
		xParam()
	Endif
Return

//-----------------------------------------------------------------------
// Rotina | xParam       | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Esta rotina solicita o preenchimento do parâmetros.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xParam()
	Local aPar := {}
	Local aRet := {}
	Local aModelos := {}
	
	Private cOpcRel := ''
	
	AAdd( aModelos, 'Dados em array.' )
	AAdd( aModelos, 'Dados em tabela padrão.' )
	AAdd( aModelos, 'Dados em resultado de query.' )
	
	AAdd(aPar,{3,'Qual modelo quer executar',1,aModelos,99,"",.T.})
	AAdd(aPar,{1,"Tabela de" ,Space(Len(SX5->X5_TABELA)),"","","00","",0,.F.})
	AAdd(aPar,{1,"Tabela até",Space(Len(SX5->X5_TABELA)),"","","00","",0,.T.})
	
	If !ParamBox(aPar,cCadastro,@aRet,,,,,,,,.F.,.F.)
		Return
   Endif
   
   cOpcRel := aModelos[ aRet[1] ] 
   
   If     aRet[1]==1 ; xArray( aRet[2], aRet[3] )
   Elseif aRet[1]==2 ; xPadrao( aRet[2], aRet[3] )
   Elseif aRet[1]==3 ; xQuery( aRet[2], aRet[3] )
   Else              ; MsgInfo('Opção indisponível',cCadastro)
   Endif
Return

//-----------------------------------------------------------------------
// Rotina | xArray       | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Tratamento de impressão dos dados por meio de um Array.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xArray( cPar1, cPar2 )
	Local aCpo := {}
	Local aCab := {}
	Local aDados := {}
	
	Local nI := 0
	
	Local oReport
	
	aCpo := {'X5_TABELA','X5_CHAVE','X5_DESCRI'}
	
	SX3->( dbSetOrder( 2 ) )
	For nI := 1 To Len( aCpo )
		SX3->( dbSeek( aCpo[ nI ] ) )
		AAdd( aCab, RTrim( SX3->X3_TITULO ) )
	Next nI
	
	SX5->( dbSetOrder( 1 ) )
	SX5->( dbSeek( xFilial( "SX5" ) + cPar1 ) )
	While ! SX5->(EOF()) .And. SX5->( X5_FILIAL + X5_TABELA ) <= xFilial("SX5") + cPar2
		SX5->( AAdd( aDados, { X5_TABELA, X5_CHAVE, X5_DESCRI } ) )
		SX5->( dbSkip() )
	End
	
	If Len( aDados ) > 0
		oReport := xDefArray( aDados, aCab )
		oReport:PrintDialog()
	Else
		MsgInfo('Não foi possível localizar os dados, verifique os parâmetros.',cCadastro)
	Endif
Return

//-----------------------------------------------------------------------
// Rotina | xDefArray    | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Definição de impressão dos dados do array.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xDefArray( aCOLS, aHeader )
	Local oReport
	Local oSection 
	Local nLen := Len(aHeader)
	Local nX := 0
	/*
	+-------------------------------------+
	| Método construtor da classe TReport |
	+-------------------------------------+
	New(cReport,cTitle,uParam,bAction,cDescription,lLandscape,uTotalText,lTotalInLine,cPageTText,lPageTInLine,lTPageBreak,nColSpace)
	
	cReport			- Nome do relatório. Exemplo: MATR010
	cTitle			- Título do relatório
	uParam			- Parâmetros do relatório cadastrado no Dicionário de Perguntas (SX1). Também pode ser utilizado bloco de código para parâmetros customizados.
	bAction			- Bloco de código que será executado quando o usuário confirmar a impressão do relatório
	cDescription	- Descrição do relatório
	lLandscape		- Aponta a orientação de página do relatório como paisagem
	uTotalText		- Texto do totalizador do relatório, podendo ser caracter ou bloco de código
	lTotalInLine	- Imprime as células em linha
	cPageTText		- Texto do totalizador da página
	lPageTInLine	- Imprime totalizador da página em linha
	lTPageBreak		- Quebra página após a impressão do totalizador
	nColSpace		- Espaçamento entre as colunas
	
	Retorno	Objeto
	*/
	oReport := TReport():New( NOME_REL, TITULO_REL, , {|oReport| xImprArray( oReport, aCOLS )}, DESCRI_REL + cOpcRel )
	
	DEFINE SECTION oSection OF oReport TITLE ABA_PLAN TOTAL IN COLUMN
	
	For nX := 1 To nLen
		DEFINE CELL NAME "CEL"+Alltrim(Str(nX-1)) OF oSection SIZE 20 TITLE aHeader[nX]
	Next nX
	
	/*
	+---------------------------------------+	
	| Define o espaçamento entre as colunas |
	+---------------------------------------+
	SetColSpace(nColSpace,lPixel)

	nColSpace	- Tamanho do espaçamento
	lPixel		- Aponta se o tamanho será calculado em pixel
	*/
	oSection:SetColSpace(0)
	
	// Quantidade de linhas a serem saltadas antes da impressão da seção
	oSection:nLinesBefore := 2
	
	
	/*
	+--------------------------------------------------------------------------------------------------------------+
	| Define que a impressão poderá ocorrer emu ma ou mais linhas no caso das colunas exederem o tamanho da página |
	+--------------------------------------------------------------------------------------------------------------+
	SetLineBreak(lLineBreak)
	
	lLineBreak - Se verdadeiro, imprime em uma ou mais linhas
	*/
	oSection:SetLineBreak(.T.)
Return( oReport )

//-----------------------------------------------------------------------
// Rotina | xImprArray   | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Impressão dos dos dados do array.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xImprArray( oReport, aCOLS )
	Local oSection := oReport:Section(1) // Retorna objeto da classe TRSection (seção). Tipo Caracter: Título da seção. Tipo Numérico: Índice da seção segundo a ordem de criação dos componentes TRSection.
	Local nX := 0
	Local nY := 0
	
	/*
	+-----------------------------------------------------+
	| Define o limite da régua de progressão do relatório |
	+-----------------------------------------------------+
	SetMeter(nTotal)
	
	nTotal - Limite da régua

	*/
	oReport:SetMeter( Len( aCOLS ) )	
	
	/*
	+---------------------------------------------------------------------+
	| Inicializa as configurações e define a primeira página do relatório |
	+---------------------------------------------------------------------+
	Init()
	
	Não é necessário executar o método Init se for utilizar o método Print, já que estes fazem o controle de inicialização e finalização da impressão.
	*/
	oSection:Init()
	
	For nX := 1 To Len( aCOLS )
		// Retorna se o usuário cancelou a impressão do relatório
		If oReport:Cancel()
			Exit
		EndIf
		
		For nY := 1 To Len(aCOLS[ nX ])
		   If ValType( aCOLS[ nX, nY ] ) == 'D'
		   	// Cell() - Retorna o objeto da classe TRCell (célula) baseado. Tipo Caracter: Nome ou título do objeto. Tipo Numérico: Índice do objeto segundo a ordem de criação dos componentes TRCell.
		   	// SetBlock() - Define o bloco de código que retornará o conteúdo de impressão da célula. Definindo o bloco de código para a célula, esta não utilizara mais o nome mais o alias para retornar o conteúdo de impressão.
		   	oSection:Cell("CEL"+Alltrim(Str(nY-1))):SetBlock( &("{ || '" + Dtoc(aCOLS[ nX, nY ]) + "'}") )
		   Elseif ValType( aCOLS[ nX, nY ] ) == 'N'
		   	oSection:Cell("CEL"+Alltrim(Str(nY-1))):SetBlock( &("{ || '" + TransForm(aCOLS[ nX, nY ],'@E 999,999,999.99') + "'}") )
		   Else
		   	oSection:Cell("CEL"+Alltrim(Str(nY-1))):SetBlock( &("{ || '" + aCOLS[ nX, nY ] + "'}") )
		   Endif
		Next
		
		// Incrementa a régua de progressão do relatório
		oReport:IncMeter()
		
		/*
		+------------------------------------------------+
		| Imprime a linha baseado nas células existentes |
		+------------------------------------------------+
		PrintLine(lEvalPosition,lParamPage,lExcel)
		
		lEvalPosition	- Força a atualização do conteúdo das células 
		lParamPage		- Aponta que é a impressão da página de parâmetros
		lExcel			- Aponta que é geração em planilha

		*/
		oSection:PrintLine()
	Next
	
	/*
	Finaliza a impressão do relatório, imprime os totalizadores, fecha as querys e índices temporários, entre outros tratamentos do componente.
	Não é necessário executar o método Finish se for utilizar o método Print, já que este faz o controle de inicialização e finalização da impressão.
	*/
	oSection:Finish()
Return

//-----------------------------------------------------------------------
// Rotina | xPadrao      | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Tratamento de impressão dos dados por meio de tabela padrão.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xPadrao( cPar1, cPar2 )
	Local aCpo := {}
	Local aCab := {}
	
	Local nI := 0
	
	Local oReport
	
	aCpo := {'X5_TABELA','X5_CHAVE','X5_DESCRI'}
	
	SX3->( dbSetOrder( 2 ) )
	For nI := 1 To Len( aCpo )
		SX3->( dbSeek( aCpo[ nI ] ) )
		AAdd( aCab, RTrim( SX3->X3_TITULO ) )
	Next nI
	
	oReport := xDefPadrao( aCpo, aCab, cPar1, cPar2 )
	oReport:PrintDialog()
Return

//-----------------------------------------------------------------------
// Rotina | xDefPadrao   | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Definição de impressão dos dados da tabela padrão.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xDefPadrao( aCpo, aHeader, cPar1, cPar2 )
	Local oReport
	Local oSection 
	Local nLen := Len(aHeader)
	Local nX := 0
	
	oReport := TReport():New( NOME_REL, TITULO_REL, , {|oReport| xImprPadrao( oReport, aCpo, cPar1, cPar2 )}, DESCRI_REL + cOpcRel )
	
	DEFINE SECTION oSection OF oReport TITLE ABA_PLAN TOTAL IN COLUMN
	
	For nX := 1 To nLen
		DEFINE CELL NAME "CEL"+Alltrim(Str(nX-1)) OF oSection SIZE 20 TITLE aHeader[nX]
	Next nX
	
	oSection:SetColSpace(0)
	oSection:nLinesBefore := 2
	oSection:SetLineBreak()
Return( oReport )

//-----------------------------------------------------------------------
// Rotina | xImprPadrao  | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Impressão dos dos dados da tabela padrão.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xImprPadrao( oReport, aCpo, cPar1, cPar2 )
	Local oSection := oReport:Section(1)
	Local nI := 0
	
	oReport:SetMeter( 0 )	
	oSection:Init()
	
	SX5->( dbSetOrder( 1 ) )
	If SX5->( dbSeek( xFilial( "SX5" ) + cPar1 ) )
		While ! SX5->(EOF()) .And. SX5->( X5_FILIAL + X5_TABELA ) <= xFilial("SX5") + cPar2
			If oReport:Cancel()
				Exit
			EndIf
			
			For nI := 1 To Len( aCpo )
				If ValType( SX5->&( aCpo[ nI ] ) ) == 'D"
					oSection:Cell("CEL"+Alltrim(Str(nI-1))):SetBlock( &("{ || '" + Dtoc( SX5->&( aCpo[ nI ] ) ) + "'}") )
				Elseif ValType( SX5->&( aCpo[ nI ] ) ) == 'N"
					oSection:Cell("CEL"+Alltrim(Str(nI-1))):SetBlock( &("{ || '" + TransForm( SX5->&( aCpo[ nI ] ), '@E 999,999,999.99' ) + "'}") )			
				Else
					oSection:Cell("CEL"+Alltrim(Str(nI-1))):SetBlock( &("{ || '" + SX5->&( aCpo[ nI ] ) + "'}") )
				Endif
			Next nI
	
			oReport:IncMeter()
			oSection:PrintLine()
	
			SX5->( dbSkip() )
		End	
	Else
		oSection:Cell("CEL0"):SetBlock( &("{ || DADOS NÃO LOCALIZADOS, VERIFIQUE OS PARÂMETROS }") )
		oSection:PrintLine()
	Endif
	
	oSection:Finish()
Return

//-----------------------------------------------------------------------
// Rotina | xQuery       | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Tratamento de impressão dos dados por meio de query.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xQuery( cPar1, cPar2 )
	Local aCpo := {}
	Local aCab := {}
	
	Local nI := 0
	
	Local oReport
	
	aCpo := {'X5_TABELA','X5_CHAVE','X5_DESCRI'}
	
	SX3->( dbSetOrder( 2 ) )
	For nI := 1 To Len( aCpo )
		SX3->( dbSeek( aCpo[ nI ] ) )
		AAdd( aCab, RTrim( SX3->X3_TITULO ) )
	Next nI
	
	oReport := xDefQuery( aCpo, aCab, cPar1, cPar2 )
	oReport:PrintDialog()
Return

//-----------------------------------------------------------------------
// Rotina | xDefQuery    | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Definição de impressão dos dados da query.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xDefQuery( aCpo, aHeader, cPar1, cPar2 )
	Local oReport
	Local oSection 
	Local nLen := Len(aHeader)
	Local nX := 0
	
	oReport := TReport():New( NOME_REL, TITULO_REL, , {|oReport| xImprQuery( oReport, aCpo, cPar1, cPar2 )}, DESCRI_REL + cOpcRel )
	
	DEFINE SECTION oSection OF oReport TITLE ABA_PLAN TOTAL IN COLUMN
	
	For nX := 1 To nLen
		DEFINE CELL NAME "CEL"+Alltrim(Str(nX-1)) OF oSection SIZE 20 TITLE aHeader[nX]
	Next nX
	
	oSection:SetColSpace(0)
	oSection:nLinesBefore := 2
	oSection:SetLineBreak()
Return( oReport )

//-----------------------------------------------------------------------
// Rotina | xImprQuery   | Autor | Robson Luiz - Rleg | Data | 04.04.2013
//-----------------------------------------------------------------------
// Descr. | Impressão dos dos dados da query.
//-----------------------------------------------------------------------
// Uso    | Oficina de Programação
//-----------------------------------------------------------------------
Static Function xImprQuery( oReport, aCpo, cPar1, cPar2 )
	Local nI := 0
	
	Local cTRB := ''
	Local cSQL := ''
	
	Local oSection := oReport:Section(1)
	
	oReport:SetMeter( 0 )	
	oSection:Init()
	
	cSQL := "SELECT X5_FILIAL,
	cSQL += "       X5_TABELA, "
	cSQL += "       X5_CHAVE, "
	cSQL += "       X5_DESCRI "
	cSQL += "FROM   "+RetSqlName("SX5")+" SX5 "
	cSQL += "WHERE  X5_FILIAL = "+ValToSql(xFilial("SX5"))+" "
	cSQL += "       AND X5_TABELA BETWEEN "+ValToSql(cPar1)+" AND "+ValToSql(cPar2)+" "
	cSQL += "       AND SX5.D_E_L_E_T_ = ' ' "
	cSQL += "ORDER  BY X5_TABELA, "
	cSQL += "          X5_CHAVE "
	
	cTRB := GetNextAlias()
	
	cSQL := ChangeQuery( cSQL )
	PLSQuery( cSQL, cTRB )
	
	If !(cTRB)->(EOF())
		While ! (cTRB)->(EOF()) .And. (cTRB)->( X5_FILIAL + X5_TABELA ) <= xFilial("SX5") + cPar2
			If oReport:Cancel()
				Exit
			EndIf
			For nI := 1 To Len( aCpo )
				If ValType( (cTRB)->&( aCpo[ nI ] ) ) == 'D"
					oSection:Cell("CEL"+Alltrim(Str(nI-1))):SetBlock( &("{ || '" + Dtoc( (cTRB)->&( aCpo[ nI ] ) ) + "'}") )
				Elseif ValType( SX5->&( aCpo[ nI ] ) ) == 'N"
					oSection:Cell("CEL"+Alltrim(Str(nI-1))):SetBlock( &("{ || '" + TransForm( (cTRB)->&( aCpo[ nI ] ), '@E 999,999,999.99' ) + "'}") )			
				Else
					oSection:Cell("CEL"+Alltrim(Str(nI-1))):SetBlock( &("{ || '" + (cTRB)->&( aCpo[ nI ] ) + "'}") )
				Endif
			Next nI
	
			oReport:IncMeter()
			oSection:PrintLine()
	
			(cTRB)->( dbSkip() )
		End
	Else
		oSection:Cell("CEL0"):SetBlock( &("{ || DADOS NÃO LOCALIZADOS, VERIFIQUE OS PARÂMETROS }") )
		oSection:PrintLine()
	Endif
	oSection:Finish()
	(cTRB)->( dbCloseArea() )
Return