Tela em MVC com 3 tabelas temporárias

Hoje iremos demonstrar um exemplo de uma tela em MVC usando 3 tabelas temporárias.

Esse exemplo foi gentilmente disponibilizado por Fabrício Antunes ( LinkedIn ). No caso, a lógica por trás da rotina é exibir a Conciliação x Contabilidade x Financeiro.

Esse fonte inclusive esta bem completo, ao abrir ele, será exibido uma pergunta que irá filtrar os dados.

Tela de parâmetros

Após confirmar, será aberto um browse com os dados já populados na temporária.

Browse com os registros

Ao clicar no botão Detalhes, será exibido uma tela com dados de 3 tabelas temporárias.

Tela de manipulação com as 3 temporárias

E se clicar no botão Relatório, será aberto um TReport listando os dados.

Relatório com os dados

Abaixo o código fonte completo:

//Bibliotecas
#Include "TOTVS.CH"
#Include "FWMVCDef.CH"

/*/{Protheus.doc} User Function MCON00X
Funcao de conciliacao financeiro
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

User Function MCON00X()
	Local aArea        :=  FWGetArea()
    Local aCposCab     :=  {}
    Local aCposGrd1    :=  {}
	Local aCposGrd2	   :=  {}
	Local aPergs       :=  {}
    Local aTitulos
    Local nX
	Local cSpace       := Space(17)
	Local lAborta      := .F.
    Private cTableCab, cTableGr1, cTableGr2
	Private oBrowse    :=  Nil	
    Private aRotina    :=  MenuDef()
    Private aBrows, aGrd1, aGrd2    //Varias com estrutura de colunas para ser utilizado no browser, no fields e nos grids
    Private cAlisCab   := GetNextAlias()
    Private cAlisGr1   := GetNextAlias()
    Private cAlisGr2   := GetNextAlias()
    Private cfilqry
	Private aSelFil  :=  {}
	Private oGrd1
    Private oGrd2
    Private oCabec

	// Perguntas de parametros para Funcao
	aAdd(aPergs, {1, "Da Conta", '           ',  "@!", ".T.", "CT1", ".T.", 80,  .T.})
	aAdd(aPergs, {1, "Registro de",   sTod('        '),  "", ".T.", "", ".T.", 80,  .T.})
	aAdd(aPergs, {1, "Registros ate",  sTod('        '),  "", ".T.", "", ".T.", 80,  .T.})
	aAdd(aPergs ,{3, "Seleciona Filiais",1,{"Sim","Nao"},50,"",.T.}) 
	aAdd(aPergs ,{3, "Somente Divergentes",2,{"Sim","Nao"},50,"",.T.}) 
	aAdd(aPergs ,{3, "Somente Div. Sld Final",2,{"Sim","Nao"},50,"",.T.}) 
	aAdd(aPergs, {1, "Do Item", cSpace,  "@!", ".T.", "CTD", ".T.", 80,  .F.})
	aAdd(aPergs, {1, "Ate o Item", 'ZZZZZZZZZZZZZZZZZ',  "@!", ".T.", "CTD", ".T.", 80,  .F.})

	If ParamBox(aPergs, "Informe os parâmetros para definicao dos filtros da rotina")
		
		///----------------------------------------------------------
		//Cria tabela para browser que sera usada no filds do MVC
		//----------------------------------------------------------
		aAdd(aCposCab,{"ID","C",6,00})
		aAdd(aCposCab,{"ITEM_TAB","C",10,00})
		aAdd(aCposCab,{"DESC_ITEM","C",30,00})
		aAdd(aCposCab,{"FIN_SLA","N",15,2})
		aAdd(aCposCab,{"FIN_DEB","N",15,2})
		aAdd(aCposCab,{"FIN_CRE","N",15,2})
		aAdd(aCposCab,{"FIN_SLF","N",15,2})
		aAdd(aCposCab,{"CTB_SLA","N",15,2})
		aAdd(aCposCab,{"CTB_DEB","N",15,2})
		aAdd(aCposCab,{"CTB_CRE","N",15,2})
		aAdd(aCposCab,{"CTB_SLF","N",15,2})
		aAdd(aCposCab,{"DEF_TAB","C",1,0})
		aAdd(aCposCab,{"DIF_VAL","N",15,2})
		
		//Array com nome dos campos para Browser
		aTitulos := {'ID Rotina', "Codigo", "Nome", "Fin. Sl. Ant.","Fin. Debito","Fin. Credito","Fin. Sl. Fin.","Ctb. Sl. Ant." ,"Ctb. Debito","Ctb. Credito" ,"Ctb. Sl. Fin.", "Div.", "Diferença" }

		//Funcao para gerar as colunas do Browser
		aBrows  :=  gerCpBrow(aCposCab,aTitulos)
		If oCabec <> Nil
			oCabec:Delete()
			oCabec  :=  Nil
		Endif
		oCabec := FWTemporaryTable():New(cAlisCab)
		oCabec:SetFields(aCposCab)
		oCabec:AddIndex("1", {"ID"})
		oCabec:AddIndex("2", {"ITEM_TAB"})
		oCabec:Create()
		
		//Obtenho o nome "verdadeiro" da tabela no BD (criada como tempor ria)
		cTableCab  :=  oCabec:GetRealName()



		//----------------------------------------------------------
		//Cria tabela grid 1 para ser usado  do MVC
		//----------------------------------------------------------

		If oGrd1 <> Nil
			oGrd1:Delete()
			oGrd1  :=  Nil
		Endif

		oGrd1  :=  FWTemporaryTable():New(cAlisGr1)
		
		aAdd(aCposGrd1,{"ID"        ,"C",06,0})
		aAdd(aCposGrd1,{"ITEM"      ,"C",03,0})
		aAdd(aCposGrd1,{"DATS"      ,"C",10,0})
		aAdd(aCposGrd1,{"DOC"       ,"C",09,0})
		aAdd(aCposGrd1,{"HIST"      ,"C",50,0})
		aAdd(aCposGrd1,{"FIN_DEB"   ,"N",18,2})
		aAdd(aCposGrd1,{"FIN_CRED"  ,"N",18,2})
		aAdd(aCposGrd1,{"SALDO"     ,"N",18,2})

		aTitulos := {'ID Rotina',  "Item","Data", "Documento", "Historico","Fin. Debito","Fin. Credito", "Saldo" }
		aGrd1 := gerCpBrow(aCposGrd1,aTitulos)


		oGrd1:SetFields(aCposGrd1)
		oGrd1:AddIndex("1", {"ID"})
		oGrd1:AddIndex("2", {"DATS"})
		oGrd1:AddIndex("3", {"DOC"})
		oGrd1:Create()
		//Obtenho o nome "verdadeiro" da tabela no BD (criada como tempor ria)
		cTableGr1  :=  oGrd1:GetRealName()


		//----------------------------------------------------------
		//Cria tabela grid 2 para ser usado  do MVC
		//----------------------------------------------------------

		If oGrd2 <> Nil
			oGrd2:Delete()
			oGrd2  :=  Nil
		Endif

		oGrd2  :=  FWTemporaryTable():New(cAlisGr2)

		aAdd(aCposGrd2,{"ID"        ,"C",06,0})
		aAdd(aCposGrd2,{"ITEM"      ,"C",03,0})
		aAdd(aCposGrd2,{"DATS"      ,"C",10,0})
		aAdd(aCposGrd2,{"LOTE"      ,"C",09,0})
		aAdd(aCposGrd2,{"HIST"      ,"C",50,0})
		aAdd(aCposGrd2,{"FIN_DEB"   ,"N",18,2})
		aAdd(aCposGrd2,{"FIN_CRED"  ,"N",18,2})
		aAdd(aCposGrd2,{"SALDO"     ,"N",18,2})

		aTitulos := {'ID Rotina', "Item","Data", "Lote", "Historico","Fin. Debito","Fin. Credito", "Saldo" }
		aGrd2 := gerCpBrow(aCposGrd2,aTitulos)


		oGrd2:SetFields(aCposGrd2)
		oGrd2:AddIndex("1", {"ID"})
		oGrd2:AddIndex("2", {"DATS"})
		oGrd2:AddIndex("3", {"LOTE"})
		oGrd2:Create()
		//Obtenho o nome "verdadeiro" da tabela no BD (criada como tempor ria)
		cTableGr2  :=  oGrd2:GetRealName()

		//----------------------------------------------------------
		//Preenchimento dos dados nas tabelas
		//----------------------------------------------------------
		If MV_PAR04 == 1 .And. Len( aSelFil ) <= 0
			aSelFil  :=  AdmGetFil()
			If Len( aSelFil ) <= 0
				lAborta := .T.
			Else
				cfilqry  :=  "("
				For nX  :=  1 to len(aSelFil)
					cfilqry += "'"+aSelFil[nX]+"',"
				Next
				cfilqry  :=  substr(cfilqry,1,len(cfilqry)-1) + ")"
			EndIf
		EndIf

		If ! lAborta
			MsgRun("Carregando dados de movimentação financeira...",,{||CursorWait(),GrvFin(MV_PAR01),CursorArrow()})

			
			dbSelectArea(cAlisGr1)
			dbSelectArea(cAlisGr2)

			//----------------------------------------------------------
			//Montagem do browser
			//----------------------------------------------------------
			oBrowse :=  FwMBrowse():New()
			oBrowse:SetDescription("Concilicao Financeira") 
			oBrowse:SetAlias(cAlisCab) 
			oBrowse:SetWalkThru(.F.)
			oBrowse:SetAmbiente(.T.) 
			oBrowse:SetTemporary(.T.)
			oBrowse:SetFields(aBrows)
			oBrowse:AddLegend( "DIF_VAL == 0", "GREEN", "Correto" )
			oBrowse:AddLegend( "DIF_VAL <> 0", "RED",   "Incorreto" )
			oBrowse:Activate()
		EndIf

		//--------------------------------
		//Exclui tabelas temporarias
		//--------------------------------
		If oCabec <> Nil
			oCabec:Delete()
			oCabec  :=  Nil
		Endif

		If oGrd1 <> Nil
			oGrd1:Delete()
			oGrd1  :=  Nil
		Endif

		If oGrd2 <> Nil
			oGrd2:Delete()
			oGrd2  :=  Nil
		Endif
	EndIF
	FWRestArea(aArea)
Return

/*/{Protheus.doc} MenuDef
Menu da rotina
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function MenuDef()
    Local aRot  :=  {}
    
    ADD OPTION aRot TITLE 'Detalhes'    ACTION 'VIEWDEF.MCON001'OPERATION 4 ACCESS 0 
	ADD OPTION aRot TITLE 'Relatorio'   ACTION 'U_MCON01A()'    OPERATION 4 ACCESS 0 

Return(Aclone(aRot))

/*/{Protheus.doc} ModelDef
Modelo de dados MVC para edicao da tabela temporaria
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function ModelDef()
	Local oModel   :=  Nil
	Local osCabec  :=  FWFormModelStruct():New()
	Local osGrd1   :=  FWFormModelStruct():New()
	Local osGrd2   :=  FWFormModelStruct():New()
	Local nX
	Local bPre     :=  {|oModel, cAction, cIDField, xValue| validPre(oModel, cAction, cIDField, xValue)}
	Local bPos     :=  {|oModel| fieldValidPos(oModel)}
	Local bLoad    :=  {|oModel, lCopy| loadField(oModel, lCopy)}
	Local bLoaGr1  :=  {|oModel, lCopy| loadGrd(oModel, lCopy,"GR1")}
	Local bLoaGr2  :=  {|oModel, lCopy| loadGrd(oModel, lCopy,"GR2")}

	For nX := 1 to Len(aBrows)
		aBrows[nX,6]=.F.
	Next
	osCabec:AddTable(cAlisCab, {"ID"}, "Concilicao Financeira")

	For nX := 1 to Len(aGrd1)
		aadd(aGrd1[nX],.F.)
	Next

	For nX := 1 to Len(aGrd2)
	 	aadd(aGrd2[nX],.F.)
	Next

    /*----------------------------------------------------------------------
    Estrutura do array para montagem dos campos usados na funcao MntStrut
        1 - Descricao
        2 - Nome do Campo
        3 - Tipo do campo
        4 - Tamanho do campo
        5 - Decimal
        6 - Se campo e editavel
    ------------------------------------------------------------------------*/

    MntStrut(@osCabec,cAlisCab,aBrows)  
    MntStrut(@osGrd1,cAlisGr1,aGrd1)  
    MntStrut(@osGrd2,cAlisGr2,aGrd2)  

    osCabec:AddTable(cAlisCab,, "Concilicao Financeira"	,{|| oCabec:GetRealName()})
	osGrd1:AddTable(cAlisGr1,, "Concilicao Financeira"	,{|| oGrd1:GetRealName()})
	osGrd2:AddTable(cAlisGr2,, "Contabilidade"			,{|| oGrd2:GetRealName()})	

    oModel  :=  FWFormModel():New( 'mdMCON001',,,{|oModel| commit()},{|oModel| cancel()})   

    
	oModel:AddFields( 'ID_M_FLD', , osCabec,bPre,bPos,bLoad)
	oModel:AddGrid( 'ID_M_GRD1', 'ID_M_FLD', osGrd1, /*bLinePre*/, /*{|oModelZA2| ValLinha(oModelZA2)}*/, /*bPreVal*/,/*{|oModel| ValLinha(oModel)}*/, bLoaGr1/*bLoad1*/)
    oModel:AddGrid( 'ID_M_GRD2', 'ID_M_FLD', osGrd2, /*bLinePre*/, /*{|oModelZA2| ValLinha(oModelZA2)}*/, /*bPreVal*/,/*{|oModel| ValLinha(oModel)}*/, bLoaGr2/* bLoad2*/)

	oModel:SetRelation( 'ID_M_GRD1', {{'ID','ID'}}, (cAlisGr1)->(IndexKey(1)))
    oModel:SetRelation( 'ID_M_GRD2', {{'ID','ID'}}, (cAlisGr2)->(IndexKey(1)))

	oModel:GetModel( 'ID_M_GRD1' ):SetUniqueLine( { 'ITEM'} )
	oModel:GetModel( 'ID_M_GRD2' ):SetUniqueLine( { 'ITEM'} )
	oModel:SetPrimaryKey({ 'ID' })

	oModel:AddCalc( 'TOTAL', 'ID_M_FLD', 'ID_M_GRD1',  'SALDO'	, '_nVlrOcor', 'SUM' , ,,'Total Saldo',/*{ |oModel| AGL300H( oModel)} */  )
	oModel:AddCalc( 'TOTAL2', 'ID_M_FLD', 'ID_M_GRD2', 'SALDO'	, '_nVlrOco2', 'SUM' , ,,'Total Saldo',/*{ |oModel| AGL300H( oModel)} */  )

	oModel:SetDescription( 'Conciliacao Financeiro' )
	oModel:GetModel( 'ID_M_GRD1' ):SetDescription( 'Contabilidade' )
    oModel:GetModel( 'ID_M_GRD1' ):SetDescription( 'Financeiro' )
	
Return oModel

/*/{Protheus.doc} fieldValidPos
Funcao de validacao pos carregamento dos dados
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function fieldValidPos(oModel)
	Local lRet  :=  .T.

    oModel:GetModel():SetErrorMessage('mdMCON001', "ID" , 'mdMCON001' , 'ID' , "ITEM")      
Return lRet

/*/{Protheus.doc} validPre
Funcao de validação dos dados de carregamento
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function validPre(oModel, cAction, cIDField, xValue)
	Local lRet  :=  .T.

	oModel:GetModel():SetErrorMessage('mdMCON001', "ID" , 'mdMCON001' , 'ID' , "ITEM")
Return lRet

/*/{Protheus.doc} loadField
Funcao de carregamento dos dados para o Fields
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function loadField(oModel, lCopy)
	Local aLoad  :=  {}
	Local nI as numeric
	Local aLine as array
	Local xValue as variant

	aLine  :=  {}

	For nI  :=  1 to Len(aBrows)
		If aBrows[nI][3] == "C"
			xValue  :=  (cAlisCab)->&(aBrows[nI,2])
		Elseif aBrows[nI][3] == "D"
			xValue  :=  StoD((cAlisCab)->&(aBrows[nI,2]))
		Elseif aBrows[nI][3] == "N"
			xValue  :=  (cAlisCab)->&(aBrows[nI,2])
		Else
			xValue  :=  .F.
		Endif

		aAdd(aLine, xValue)
	Next
	

	aAdd(aLoad, aLine) //dados
	aAdd(aLoad, 1) //recno
Return aLoad

/*/{Protheus.doc} Commit
Funcao de valicao do comit da tela
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function Commit()
Return .T.

/*/{Protheus.doc} Cancel
Funcao de valicao do cancelamento do tela
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function Cancel()
Return .T.

/*/{Protheus.doc} ViewDef
Visao de dados MVC para montagem da tela da  tabela temporaria
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function ViewDef()
	Local oModel  :=  FWLoadModel("MCON001")
	Local osCabec  :=  FWFormViewStruct():New()
	Local osGrd1  :=  FWFormViewStruct():New()
	Local osGrd2  :=  FWFormViewStruct():New()
	Local oView  :=  Nil
	Local nX
	Local aDadCab  := {}
	Local aDadGr1  := {}
	Local aDadGr2  := {}

    /*----------------------------------------------------------------------
    Estrutura do array para montagem dos campos usados na funcao MntView
        1 - Nome do Campo
        2 - Ordem
        3 - Titulo do campo
        4 - Tipo do campo
        5 - Picture
        6 - Se campo e editavel
    ------------------------------------------------------------------------*/
  
	For nX := 1 to Len(aBrows)
		IF aBrows[nX,3] = "C"
            cPict := "@!"
		ElseIF aBrows[nX,3] = "N"
            cPict := "@E 9,999,999.99"
		Else
            cPict := ""
		EnDIF
        aADD(aDadCab,{aBrows[nX,2],StrZero(nX,2),aBrows[nX,1],aBrows[nX,3],cPict,.F.})
	Next

	For nX := 1 to Len(aGrd1)
		IF aGrd1[nX,3] = "C"
            cPict := "@!"
		ElseIF aGrd1[nX,3] = "N"
            cPict := "@E 9,999,999.99"
		Else
            cPict := ""
		EnDIF
        aADD(aDadGr1,{aGrd1[nX,2],StrZero(nX,2),aGrd1[nX,1],aGrd1[nX,3],cPict,.F.})
	Next

	For nX := 1 to Len(aGrd2)
	 	IF aGrd2[nX,3] = "C"
             cPict := "@!"
	 	ElseIF aGrd2[nX,3] = "N"
             cPict := "@E 9,999,999.99"
	 	Else
             cPict := ""
	 	EnDIF
        aADD(aDadGr2,{aGrd2[nX,2],StrZero(nX,2),aGrd2[nX,1],aGrd2[nX,3],cPict,.F.})
	Next

    MntView(@osCabec,aDadCab)
    MntView(@osGrd1,aDadGr1)
    MntView(@osGrd2,aDadGr2)

    oView  :=  FWFormView():New()
    oView:SetModel(oModel)

    oView:AddField("ID_V_FLD", osCabec, "ID_M_FLD")
    oView:AddGrid("ID_V_GRD1", osGrd1, "ID_M_GRD1")
    oView:AddGrid("ID_V_GRD2", osGrd2, "ID_M_GRD2")     

    oView:CreateHorizontalBox("SUPERIOR",30)
    oView:CreateHorizontalBox("INFERIOR",70)
    oView:CreateVerticalBox('ESQUERDA', 50 , 'INFERIOR')
	oView:CreateVerticalBox("DIREITA",  50 , 'INFERIOR')
    
    oView:SetOwnerView( 'ID_V_FLD'   , 'SUPERIOR' )
	oView:SetOwnerView( 'ID_V_GRD1'   , 'ESQUERDA' )
	oView:SetOwnerView( 'ID_V_GRD2'   , 'DIREITA' )


    //Colocando título do formulário
    oView:EnableTitleView('ID_V_FLD', 'Conciliacao Financeiro' )  
    oView:EnableTitleView('ID_V_GRD1', 'Contabilidade' )  
    oView:EnableTitleView('ID_V_GRD2', 'Financeiro' )       
    oView:SetCloseOnOk({||.T.})
Return oView

/*/{Protheus.doc} gerCpBrow
Funcao para montar array com colunas para browse
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function gerCpBrow(aCampos,aTitulos)
	Local nX
	Local aBrows := {}

	For nX := 1 to Len(aCampos)
		aAdd(aBrows,{aTitulos[nX], aCampos[nX,1] ,aCampos[nX,2] ,aCampos[nX,3] ,aCampos[nX,4]})
	Next
Return aBrows

/*/{Protheus.doc} MntStrut
Funcao para montar estrutura de dados para ModelDef
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function MntStrut(oObj,cAlias, aCampos)
	Local nX
	Default aCampos := {}

	For nX := 1 to Len(aCampos)
		oObj:AddField(;
			aCampos[nX,1],;                                                                              	// [01]  C   Titulo do campo
			aCampos[nX,1],;                                                                                  // [02]  C   ToolTip do campo
			aCampos[nX,2],;                                                                                  // [03]  C   Id do Field
			aCampos[nX,3],;                                                                                  // [04]  C   Tipo do campo
			aCampos[nX,4],;                                                                                  // [05]  N   Tamanho do campo
			aCampos[nX,5],;                                                                                  // [06]  N   Decimal do campo
			Nil,;                                                                                            // [07]  B   Code-block de validação do campo
			Nil,;                                                                                            // [08]  B   Code-block de validação When do campo
			{},;                                                                                             // [09]  A   Lista de valores permitido do campo
			.F.,;                                                                                            // [10]  L   Indica se o campo tem preenchimento obrigatório
			FwBuildFeature( STRUCT_FEATURE_INIPAD, "Iif(!INCLUI,('"+cAlias+"')->"+aCampos[nX,2]+",'')" ),;   // [11]  B   Code-block de inicializacao do campo
			.T.,;                                                                                            // [12]  L   Indica se trata-se de um campo chave
			aCampos[nX,6],;                                                                                  // [13]  L   Indica se o campo pode receber valor em uma operação de update.
			.F.;                                                                                             // [14]  L   Indica se o campo é virtual
		)

		IF aCampos[nX,6]
			oObj:SetProperty(aCampos[nX,2], MODEL_FIELD_WHEN, { || .T.})
			oObj:SetProperty(aCampos[nX,2], MODEL_FIELD_NOUPD,.F.)
		EndIF
	Next
Return

/*/{Protheus.doc} MntView
Funcao para montar estrutura de dados para ViewDef
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function MntView(oObj,aCampos)
	Local nX

	For nX := 1 to Len(aCampos)
		//Adicionando campos da estrutura
		oObj:AddField(;
			aCampos[nX,1],;                  // [01]  C   Nome do Campo
			aCampos[nX,2],;                  // [02]  C   Ordem
			aCampos[nX,3],;                  // [03]  C   Titulo do campo
			aCampos[nX,3],;                  // [04]  C   Descricao do campo
			Nil,;                            // [05]  A   Array com Help
			aCampos[nX,4],;                  // [06]  C   Tipo do campo
			aCampos[nX,5],;                  // [07]  C   Picture
			Nil,;                            // [08]  B   Bloco de PictTre Var
			Nil,;                            // [09]  C   Consulta F3
			aCampos[nX,6],;                  // [10]  L   Indica se o campo é alteravel
			Nil,;                            // [11]  C   Pasta do campo
			Nil,;                            // [12]  C   Agrupamento do campo
			Nil,;                            // [13]  A   Lista de valores permitido do campo (Combo)
			Nil,;                            // [14]  N   Tamanho maximo da maior opção do combo
			Nil,;                            // [15]  C   Inicializador de Browse
			Nil,;                            // [16]  L   Indica se o campo é virtual
			Nil,;                            // [17]  C   Picture Variavel
			Nil;                             // [18]  L   Indica pulo de linha após o campo
		)
	Next

Return

/*/{Protheus.doc} GrvFin
Funcao que ira criar e popular a tabela temporaria
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static function GrvFin(cContab)
	Local aArea := FWGetArea()
	Local aTam := TamSX3("E1_CLIENTE")
	Local aCampos  :=  {}
	Local _oFINR5501
	Private cSE5KeyAnt	 :=  ""

	aAdd(aCampos,{"CODIGO" ,"C",aTam[1],aTam[2]})
	aAdd(aCampos,{"SALDOA"  ,"N",18,2})
	aAdd(aCampos,{"VALORD"  ,"N",18,2})
	aAdd(aCampos,{"VALORC"  ,"N",18,2})

	_oFINR5501  :=  FWTemporaryTable():New( "cNomeArq" )
	_oFINR5501:SetFields(aCampos)
	_oFINR5501:AddIndex("1", {"CODIGO"})
	//------------------
	//Criação da tabela temporaria
	//------------------
	_oFINR5501:Create()

	//------------------
	//Localiza e grava titulos a receber dentro dos parametros
	//------------------

	cQuery  :=  "SELECT TOP 100 * FROM " + RetSqlName("SE2") + " E2 (NOLOCK) WHERE"
	cQuery += " E2.D_E_L_E_T_ <> '*'"

	dbUseArea(.T., "TOPCONN", TCGenQry(,,cQuery), 'TRBSE2', .F., .T.)
	dbselectarea("TRBSE2")
	While !TRBSE2->(Eof())

		//------------------
		//Le registros com data anterior a data inicial (para compor
		//os saldos anteriores) ate a data final.
		//------------------

		If TRBSE2->E2_TIPO $ MVABATIM
			dbSelectArea("TRBSE2")
			TRBSE2->(dbSkip( ))
			Loop
		Endif


		//------------------
		//Grava debito no arquivo de trabalho
		//------------------
		_dEmissao  :=  stod(TRBSE2->E2_EMIS1)
		aMOVI  :=  {10,20,30}

		If( cNomeArq->(dbseek(TRBSE2->E2_FORNECE)))
			Reclock( "cNomeArq", .F. )
			cNomeArq->SALDOA   += aMOVI[1]
			cNomeArq->VALORD   += aMOVI[2]
			cNomeArq->VALORC   += aMOVI[3]
			cNomeArq->( MsUnlock() )

		Else
			Reclock( "cNomeArq", .T. )
			cNomeArq->CODIGO   :=  TRBSE2->E2_FORNECE
			cNomeArq->SALDOA    :=  aMOVI[1]
			cNomeArq->VALORD    :=  aMOVI[2]
			cNomeArq->VALORC    :=  aMOVI[3]
			cNomeArq->( MsUnlock() )
		Endif


		dbSelectArea("TRBSE2")
		TRBSE2->(dbSkip())

	Enddo

	dbselectarea("cNomeArq")
	cNomeArq->(dbgotop())
	cCodigo		 :=  ""
	nSaldoAtu	 :=  0
	nTotDeb		 :=  0
	nTotCrd		 :=  0

	While cNomeArq->(!Eof())

		cCodigo		 :=  cNomeArq->CODIGO
		cLoja  :=  ""
		nSaldoAtu	 :=  0
		nTotDeb		 :=  0
		nTotCrd		 :=  0
		lNoSkip  :=  .f.
		nSaldoAtu	+= cNomeArq->SALDOA
		nTotDeb   += ABS(cNomeArq->VALORD)
		nTotCrd   += ABS(cNomeArq->VALORC)

		cNomeArq->(dbSkip())
		//cAlisCab := oGrd1:GetRealName()

		If cNomeArq->(Eof()) .or. cNomeArq->CODIGO <> cCodigo
			//------------------
			//Grava debito no arquivo de trabalho
			//------------------
			dbSelectArea(cAlisCab)
			(cAlisCab)->(dbSetOrder(2))
			Reclock((cAlisCab),.t.)
			Replace ID  	    With cCodigo
			Replace ITEM_TAB  	With cCodigo
			IF SA1->(dbseek(xfilial("SA1")+cCodigo))
				Replace DESC_ITEM  	With SA1->A1_NOME
			ElseIf SA2->(dbseek(xfilial("SA2")+cCodigo))
				Replace DESC_ITEM  	With SA2->A2_NOME
			Endif
			Replace FIN_SLA  With nSaldoAtu
			Replace FIN_DEB  With nTotDeb
			Replace FIN_CRE  With nTotCrd
			Replace FIN_SLF  With FIN_SLA + FIN_DEB - FIN_CRE
			MsUnlock()

////grid 1
			dbSelectArea(cAlisGr1)
			(cAlisGr1)->(dbSetOrder(2))
			Reclock((cAlisGr1),.t.)
			Replace ID  	    With cCodigo
			Replace ITEM  	With cCodigo
			Replace FIN_DEB  With nTotDeb
			MsUnlock()
///grid 2

			// dbSelectArea(cAlisGr2)
			// (cAlisGr2)->(dbSetOrder(2))
			// Reclock((cAlisGr2),.t.)
			// Replace ID  	    With cCodigo
			// Replace ITEM 	With cCodigo
			// Replace FIN_DEB  With nTotDeb
			// MsUnlock()
		Endif
	EndDo
	
	FWRestArea(aArea)
Return

/*/{Protheus.doc} User Function MCON01A
Funcao para gerar um relatorio com os dados
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

User Function MCON01A()
	Private oReport
	Private oSecCabc
	Private oSecFinan
	Private oSecCont


	oReport  :=  ReportDef()
	oReport:PrintDialog()
Return

/*/{Protheus.doc} ReportDef
Funcao que monta as definições do relatório TReport
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function ReportDef()
	oReport  :=  TReport():New("MCON001","Conciliacao Financeiro Contabil",,{|oReport| PrintReport(oReport)},"Conciliacao Financeiro Contabil")
	oReport:SetLandscape(.T.) //Paisagem
	oReport:lDisableOrientation  :=  .T.
	oReport:HideParamPage()//desabilita a impressão da pagina de parâmetros  

	oSecCabc  :=  TRSection():New(oReport,"SINTETICO",)
	TRCell():New( oSecCabc ,"ITEM_TAB"			,"" ,"Codigo" 			,"@!"/*Picture*/				,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"DESC_ITEM"			,"" ,"Nome"				,"@!"/*Picture*/				,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"FIN_SLA"			,"" ,"Fin. Sl. Ant."	,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"FIN_DEB"			,"" ,"Fin. Debito"		,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"FIN_CRE"			,"" ,"Fin. Credito"		,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"FIN_SLF"			,"" ,"Fin. Sl. Fin."	,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"CTB_SLA"			,"" ,"Ctb. Sl. Ant."	,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"CTB_DEB"			,"" ,"Ctb. Debito"		,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"CTB_CRE"			,"" ,"Ctb. Credito"		,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"CTB_SLF"			,"" ,"Ctb. Sl. Fin."	,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"DEF_TAB"			,"" ,"Div."				,"@!"/*Picture*/				,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New( oSecCabc ,"DIF_VAL"			,"" ,"Diferença"		,"@E 99,999,999.99"/*Picture*/	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)

	oSecFinan  :=  TRSection():New(oReport,"FINANCEIRO","TRB")
	TRCell():New(oSecFinan	,"DATS"			,"" ,"Data"	        ,X3Picture("E1_EMISSAO"),   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecFinan	,"DOC"			,"" ,"Documento"	,X3Picture("E1_MUM")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecFinan	,"HIST"			,"" ,"Historico"	,X3Picture("E1_HIST")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecFinan	,"FIN_DEB"		,"" ,"Fin. Debit."	,X3Picture("E1_VALOR")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecFinan	,"FIN_CRED"		,"" ,"Fin. Cred."	,X3Picture("E1_VALOR")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecFinan	,"SALDO"		,"" ,"Saldo"	    ,X3Picture("E1_VALOR")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	oSecFinan:SetLinesBefore(2)

	oSecCont  :=  TRSection():New(oReport,"CONTABIL","TRB")
	TRCell():New(oSecCont	,"DATS"			,"" ,"Data"	        ,X3Picture("E1_EMISSAO"),   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecCont	,"LOTE"			,"" ,"Lote"			,X3Picture("E1_MUM")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecCont	,"HIST"			,"" ,"Historico"	,X3Picture("E1_HIST")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecCont	,"FIN_DEB"		,"" ,"Fin. Debit."	,X3Picture("E1_VALOR")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecCont	,"FIN_CRED"		,"" ,"Fin. Cred."	,X3Picture("E1_VALOR")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	TRCell():New(oSecCont	,"SALDO"		,"" ,"Saldo"	    ,X3Picture("E1_VALOR")	,   /*nSize*/,/*lPixel*/,/*bBlock*/,"LEFT"/*cAlign*/,/*lLineBreak*/,"LEFT"/*cHeaderAlign*/,/*lCellBreak*/,/*nColSpace*/,.T./*lAutoSize*/,/*nClrBack*/,/*nClrFore*/,/*lBold*/)
	oSecCont:SetLinesBefore(2)
Return(oReport)

/*/{Protheus.doc} PrintReport
Função que faz a impressão do relatório TReport
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function PrintReport(oReport)
	oSecCabc:Init()
	oSecCabc:Cell("ITEM_TAB"):SetValue((cAlisCab)->ITEM_TAB)
	oSecCabc:Cell("DESC_ITEM"):SetValue((cAlisCab)->DESC_ITEM)
	oSecCabc:Cell("FIN_SLA"):SetValue((cAlisCab)->FIN_SLA)
	oSecCabc:Cell("FIN_DEB"):SetValue((cAlisCab)->FIN_DEB)
	oSecCabc:Cell("FIN_CRE"):SetValue((cAlisCab)->FIN_CRE)
	oSecCabc:Cell("FIN_SLF"):SetValue((cAlisCab)->FIN_SLF)
	oSecCabc:Cell("CTB_SLA"):SetValue((cAlisCab)->CTB_SLA)
	oSecCabc:Cell("CTB_DEB"):SetValue((cAlisCab)->CTB_DEB)
	oSecCabc:Cell("CTB_CRE"):SetValue((cAlisCab)->CTB_CRE)
	oSecCabc:Cell("CTB_SLF"):SetValue((cAlisCab)->CTB_SLF)
	oSecCabc:Cell("DEF_TAB"):SetValue((cAlisCab)->DEF_TAB)
	oSecCabc:Cell("DIF_VAL"):SetValue((cAlisCab)->DIF_VAL)
	oSecCabc:PrintLine()
	oSecCabc:Finish()


	oReport:Say(oReport:Row()+20, 10, " --------------------DADOS FINANCEIROS--------------------")
	oSecFinan:Init()
	(cAlisGr1)->(dbSetOrder(1))
	(cAlisGr1)->(dbGoTop())
	IF (cAlisGr1)->(dbSeek((cAlisCab)->ID))
		While !(cAlisGr1)->(Eof()) .AND. (cAlisGr1)->ID = (cAlisCab)->ID

			If oReport:Cancel()
				Exit
			EndIf

			oSecFinan:Cell("DATS"):SetValue((cAlisGr1)->DATS)
			oSecFinan:Cell("DOC"):SetValue((cAlisGr1)->DOC)
			oSecFinan:Cell("HIST"):SetValue((cAlisGr1)->HIST)
			oSecFinan:Cell("FIN_DEB"):SetValue((cAlisGr1)->FIN_DEB)
			oSecFinan:Cell("FIN_CRED"):SetValue((cAlisGr1)->FIN_CRED)
			oSecFinan:Cell("SALDO"):SetValue((cAlisGr1)->SALDO)

			
			oSecFinan:PrintLine()
			(cAlisGr1)->(dbSkip())
		EndDo
	EndIF
	oSecFinan:Finish()

	oReport:Say(oReport:Row()+20, 10, " --------------------DADOS CONTABILIDADE--------------------")

	oSecCont:Init()
	(cAlisGr2)->(dbSetOrder(1))
	(cAlisGr2)->(dbGoTop())
	IF (cAlisGr2)->(dbSeek((cAlisCab)->ID))
		While !(cAlisGr2)->(Eof()) .AND. (cAlisGr2)->ID = (cAlisCab)->ID

			If oReport:Cancel()
				Exit
			EndIf

			oSecCont:Cell("DATS"):SetValue((cAlisGr2)->DATS)
			oSecCont:Cell("LOTE"):SetValue((cAlisGr2)->LOTE)
			oSecCont:Cell("HIST"):SetValue((cAlisGr2)->HIST)
			oSecCont:Cell("FIN_DEB"):SetValue((cAlisGr2)->FIN_DEB)
			oSecCont:Cell("FIN_CRED"):SetValue((cAlisGr2)->FIN_CRED)
			oSecCont:Cell("SALDO"):SetValue((cAlisGr2)->SALDO)

			
			oSecCont:PrintLine()
			(cAlisGr2)->(dbSkip())
		EndDo
	EndIf
	oSecCont:Finish()

	oReport:StartPage()
	oReport:EndPage()
Return

/*/{Protheus.doc} loadGrd
Função responsável pela carga dos modelos em MVC
@type  Function
@author Fabricio Antunes
@since 22/09/2021
/*/

Static Function loadGrd(oSub,lCopy,cIdSub)
	Local cAliasTab	 :=  ""
	Local nI		 :=  0
	Local nRec		 := 1
	Local aFldSub	 :=  {}
	Local aRet 		 :=  {}
	Local aAux		 :=  {}

	aFldSub  :=  oSub:GetStruct():GetFields()

	If ( cIdSub == "GR1" ) 
		cAliasTab  :=  oGrd1:GetAlias()
	ElseIf ( cIdSub == "GR2" )
		cAliasTab  :=  oGrd2:GetAlias()
	EndIf

	(cAliasTab)->(dbSetOrder(1))
	(cAliasTab)->(dbGoTop())
	IF (cAliasTab)->(dbSeek((cAlisCab)->ID))
		While !(cAliasTab)->(Eof()) .AND. (cAliasTab)->ID = (cAlisCab)->ID
					
			For nI  :=  1 to Len(aFldSub)

				If ( (cAliasTab)->(FieldPos(aFldSub[nI,3])) > 0 )
					aAdd(aAux,(cAliasTab)->&(aFldSub[nI,3]))
				Else
					aAdd(aAux,GTPCastType(,aFldSub[nI,4]))
				EndIf

			Next nI
			
			aAdd(aRet,{nRec,aClone(aAux)})
			aAux  :=  {}
			nRec++
			
			(cAliasTab)->(DbSkip())
			
		EndDo
	EndIF
Return(aRet)

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

4 Responses

  1. Paulo Roberto Soares disse:

    Ola bom dia, poderia complementar o exmplo pois VIEWDEF.MCON001 no menu não abre a tela de detalhes, aterando o mesmo para VIEWDEF.MCON00X tenho o seguinte erro
    ERROR: argumento #0 , parâmetro oObj erro, previsto O->U

  2. Pedro Ferreira disse:

    Bom dia, obrigado pelo exemplo, funcionou perfeitamente aqui! Tive somente uma dúvida com relação ao porque do uso do “GTPCastType” na Static Function loadGrd. Não encontrei documentação sobre isso. Trata-se de uma função reservada da TOTVS? Obrigado!

    • Boa tarde Pedro.
      Essa função ela faz a conversão de tipo de dado, então nesse exemplo, se ele não encontrar o campo, irá formatar o valor nulo conforme o tipo do campo (se o campo for caractere ou memo, volta espaço vazio, se for numérico, volta 0, se for data volta a database e se for lógico volta .f.).

Deixe uma resposta