Atualizar moeda do sistema pelo Banco Central do Brasil


Há muito tempo atrás encontrei um código, criado por Caio Graco, pelo fonte que encontra-se comigo, é de 2006, eu o adaptei a minha necessidade. A idéia do fonte é pegar o arquivo txt gerado pelo banco central, baixá-lo, ler linha a linha, pegar o codigo da moeda e seu valor correspondente (valor de compra e venda). Depois que localizar a moeda e o valor correspondente armazenar na SM2. Irei postar parte do código, mostrando a sua simplicidade e eficácia.

/*
+----------------------------------------------------------------------------+
!                         FICHA TECNICA DO PROGRAMA                          !
+----------------------------------------------------------------------------+
!   DADOS DO PROGRAMA                                                        !
+------------------+---------------------------------------------------------+
!Tipo              ! Miscelanea                                              !
+------------------+---------------------------------------------------------+
!Modulo            ! Contabilidade Gerencial e Financeiro                    !
+------------------+---------------------------------------------------------+
!Nome              ! MOEDAS001                                               !
+------------------+---------------------------------------------------------+
!Descricao         ! Atualiza e Projeta Moedas/Cambio                        !
!                  !                                                         !
!                  ! Colocar as linhas abaixo no APPSERVER.INI		     !
!                  ! [ONSTART]                                               !
!                  ! jobs=Moedas                                             !
!                  ! RefreshRate=86400                                       !
!                  !                                                         !
!                  ! [Moedas]                                                !
!                  ! main=u_MOEDAS001                                        !
!                  ! Environment=TESTE                                       !
!                  !                                                         !
!                  ! Fonte retirado da internet e modificado conforme neces- !
!                  ! sidade da empresa                                       !
+------------------+---------------------------------------------------------+
!Autor             ! Caio Graco Bucke Brito                       	     !
+------------------+---------------------------------------------------------+
!Data de Criacao   ! 18/10/2006                                              !
+------------------+---------------------------------------------------------+
*/
#include 'protheus.ch'
#include "topconn.ch"
User Function MOEDAS001(_aMoedas,lAuto,_dDtAtual,lPtax)
	Local 	cHora		:= Time()
	Local 	lFeito		:= .F.
	Private lAuto
	Private dDataRef, dData
	Private nValReal	:= 1.000000
	Private nValUfir	:= 0 
	Private nN	   		:= 0
	Private nS1, nS2, nS3
	Private nI1, nI2, nI3
	Private oDlg
	Private nDiasPro	:= 10
	Private nDiasreg	:= 10
	Private aMoedas		:= {} 
	Private aNMoedas    := {}
	Default lAuto		:= .F.	                 
	Default	lPtax		:= .F.
	Default _dDtAtual   := iif(Empty(_dDtAtual),date(),_dDtAtual)
	Private nValorC		:= 0
	Private nValorV		:= 0

	dData := _dDtAtual
			
	if valType("_aMoedas")<>"U"
		if(!Empty(_aMoedas))
			aMoedas := _aMoedas
		Endif
	Endif
                                   	
	//Testa se esta sendo rodado do menu
	If	Select('SX2') == 0						
		RPCSetType( 3 )						//Não consome licensa de uso
		RpcSetEnv('01','01',,,,GetEnvServer(),{ "SM2","SYE" })
		sleep( 5000 )						//Aguarda 5 segundos para que as jobs IPC subam.
		lAuto := .F.
	EndIf
	
	If	( lAuto )               
		LjMsgRun(OemToAnsi('Atualização On-line de moedas SM2 (Banco Central do Brasil)'),,{|| fAtuaMoeda(lAuto,"SM2")} )
	Else
		//Atualização tabela SM2
		aMoedas := faaMoedas() //pego as informações necessárias das moedas que utilizo
		
		DbSelectArea("SM2")
		SM2->(DbSetorder(1))
		ConOut('Verifica se existe registro na SM2')
		If SM2->(DbSeek(Dtos(dDataBase)))           
			ConOut('Verifica se existe valor na moeda4')                 
			if(SM2->M2_MOEDA4==0)
				ConOut('Iniciando atualização de Moedas SM2... '+Dtoc(dDatabase)+' - '+Time())
				fAtuaMoeda(lAuto,"SM2")                               
				ConOut('Moedas SM2 Atualizadas. '+Dtoc(dDatabase)+' - '+Time())
			Else
				ConOut('Nao eh necessario atualizacao, tabela SM2 ja atualizada!')
			Endif
		Else                                       
			ConOut('Iniciando atualizacao de Moedas SM2... '+Dtoc(dDatabase)+' - '+Time())
			fAtuaMoeda(lAuto,"SM2")                               
			ConOut('Moedas SM2 Atualizadas. '+Dtoc(dDatabase)+' - '+Time())
		Endif		
		RpcClearEnv()		   				//Libera o Ambiente
	EndIf
	
Return

Static Function fAtuaMoeda(lAuto,cAlias)
	Local nPass, cFile, cTexto, nLinhas, cLinha, cdata, cCompra, cVenda, J, K, L 
	Local cEmail  := ""    
	Local cFile   := ""
	Local aLinha  := {}
	Local cMoeda  := ""
	Local nArquivo:= 0
	Local cArqImpor := "\system\moedasbcb.csv"
	Local nHdl
	Local nTamArq
	Local nTamLinha
	Local nLinhas
	Local nPass := IIF(cAlias=="SM2",1,2)    //Se moeda padrao do sistema, basear em um dia util anterior,caso contrario (PTAX) em 2 dias uteis anterior a data informada 
	Local cMesDia   := ""
	Local aFeriados := {}
	
	dDataRef := ( dData - nPass )

    if Dow(dDataRef)==1 //domingo        
    	dDataRef:= dData -3
    Endif
    	
	//no código original, era chumbado todos os feriados
	//estarei usando a tabela DV8 para cadastrar meus feriados e dias bancarios nao trabalhados
	//Feriados Bancário Fixo
	dbSelectArea("DV8")
	DV8->(dbSetOrder(1))
	DV8->(dbGoTop())
	While DV8->(!EOF())	
		cMesDia := Right(DV8->DV8_DIAMES,2)+Left(DV8->DV8_DIAMES,2)
		aadd(aFeriados,cMesDia)
		DV8->(dbSkip())
	End
	DV8->(dbCloseArea())
	                                   
	For i:=1 to len(aFeriados)
		if Dtos(dDataRef) == STR(Year(Date()),4)+aFeriados[i]
			dDataRef:= dDataRef - 1
			
			If	Dow(dDataRef) == 1		//Se for domingo
				cFile := Dtos(dDataRef - 2)+'.csv'
			ElseIf	Dow(dDataRef) == 7  //Se for sabado
				cFile := Dtos(dDataRef - 1)+'.csv'
			Else						//Se for dia normal
				cFile := Dtos(dDataRef)+'.csv'	
			EndIf
		Endif	
	Next     

	if(Empty(cFile))
		If	Dow(dDataRef) == 1		//Se for domingo
			cFile := Dtos(dDataRef - 2)+'.csv'
		ElseIf	Dow(dDataRef) == 7  //Se for sabado
			cFile := Dtos(dDataRef - 1)+'.csv'
		Else						//Se for dia normal
			cFile := Dtos(dDataRef)+'.csv'	
		EndIf
	Endif
				
	//armazena-se o conteudo do arquivo pego no banco central
	cTexto  := HttpGet('http://www4.bcb.gov.br/Download/fechamento/'+cFile)
	
	nArquivo := FCreate( cArqImpor, 0 )  	
	FWrite( nArquivo , cTexto)
	fClose( nArquivo ) 

	If	( !lAuto )
		ConOut('DownLoading from BCB '+cFile+' In '+Dtoc(Date()))
	EndIf

	//+---------------------------------------------------------------------+
	//| Abertura do arquivo texto                                           |
	//+---------------------------------------------------------------------+
	nHdl := fOpen(cArqImpor)

	If nHdl == -1 
		IF FERROR()== 516 
			If	( lAuto )
			    ALERT("Feche a planilha que gerou o arquivo.")
		    ENDIF
		    ConOut("Feche a planilha que gerou o arquivo.")
		EndIF
	EndIf
	
	//+---------------------------------------------------------------------+
	//| Verifica se foi possível abrir o arquivo                            |
	//+---------------------------------------------------------------------+
	If nHdl == -1
		cMsg := "O arquivo de nome "+cArqImpor+" nao pode ser aberto! Verifique os parametros."
		If	( lAuto )
			MsgAlert(cMsg,"Atencao!")
	    ENDIF
	    ConOut(cMsg)
	   	Return
	Endif
	
	//+---------------------------------------------------------------------+
	//| Posiciona no Inicio do Arquivo                                      |
	//+---------------------------------------------------------------------+
	FSEEK(nHdl,0,0)
	
	//+---------------------------------------------------------------------+
	//| Traz o Tamanho do Arquivo TXT                                       |
	//+---------------------------------------------------------------------+
	nTamArq:=FSEEK(nHdl,0,2)
	
	//+---------------------------------------------------------------------+
	//| Posicona novamemte no Inicio                                        |
	//+---------------------------------------------------------------------+
	FSEEK(nHdl,0,0)
	
	//+---------------------------------------------------------------------+
	//| Fecha o Arquivo                                                     |
	//+---------------------------------------------------------------------+
	fClose(nHdl)
	FT_FUse(cArqImpor)  //abre o arquivo 
	FT_FGOTOP()         //posiciona na primeira linha do arquivo      
	nTamLinha := Len(FT_FREADLN()) //Ve o tamanho da linha
	FT_FGOTOP()
	
	//+---------------------------------------------------------------------+
	//| Verifica quantas linhas tem o arquivo                               |
	//+---------------------------------------------------------------------+
	nLinhas := Int(nTamArq/nTamLinha)
	
	ProcRegua(nLinhas)		                                                            

	aDados:={}	      
	nCont := 0
	While !FT_FEOF()// .and. ncont < 16 
	   
	   	IncProc('Validando Linha: ' + Alltrim(Str(nCont)) )
  	
		aTab := {}
		clinha := FT_FREADLN() 
        
        if(At("<!",cLinha)>0)
        	MsgStop("Não foi encontrado no Banco Central o arquivo correspondente ("+cFile+")")
        	Return
        Endif
        
		aLinha  :=  Separa(cLinha,";",.T.)
		cData  	:= aLinha[1]                
		cMoeda  := aLinha[2]                
		cCompra := aLinha[5] 
		cVenda  := aLinha[6] 

		For nW := 1 to len(aMoedas)     
			If	( cMoeda==aMoedas[nW,2] )
				nValor  := "nVal"+aMoedas[nW,1]+Alltrim(aMoedas[nW,3])
	 			&nValor	:= Val(StrTran(cVenda,",","."))
				If(!Empty(aMoedas[nW,4]))
					nValor  := "nVal"+aMoedas[nW,1]+Alltrim(aMoedas[nW,4])		
		 			&nValor	:= Val(StrTran(cCompra,",","."))
	 			Endif

 				nValorV	:= Val(StrTran(cVenda,",","."))
 				nValorC	:= Val(StrTran(cCompra,",","."))
	 			
	 			AADD(aNMoedas,{aMoedas[nW,1],aMoedas[nW,2],aMoedas[nW,3],aMoedas[nW,4]})
			EndIf
		Next    

		FT_FSKIP()
		nCont++
	EndDo
	FT_FUse()
	fClose(nHdl)

	
	if len(aNMoedas) > 0
		GravaDados()
		If	( lAuto )
			LjMsgRun(OemToAnsi("Atualizado Moedas e Cambio!"),,{|| } )
		Endif
	Else
		cAviso:= "Ocorreu um erro ao atualizar Moedas! Arquivo "+cFile+" nao encontrado em "+Dtoc(Date())
		ConOut(cAviso)
		If	( lAuto )
			LjMsgRun(OemToAnsi(cAviso),,{|| } )
		EndIf					
	Endif
Return

Static Function GravaDados()
	Local lGrava                                                                    
	Local cMoFin1
	Local cnMoeda1
	Local nValor1
	Local cMoFin2
	Local cnMoeda2
	Local nValor2
	
	DbSelectArea("SM2")				
	SM2->(DbSetorder(1))
	lGrava := SM2->(DbSeek(Dtos(dData)))  
	Reclock('SM2',!lGrava)
	SM2->M2_DATA	:= dData
	SM2->M2_MOEDA1	:= nValReal		
	cnMoeda:=""

	For nW := 1 to len(aNMoedas)  
		cMoFin1 := Alltrim(Str(Posicione("SYF",1,xFilial("SYF")+aNMoedas[nW,1],"YF_MOEFAT")))
		cnMoeda1 := "SM2->M2_MOEDA"+cMoFin1
		nValor1  := "nVal"+aNMoedas[nW,1]+Alltrim(aNMoedas[nW,3])
		if(cnMoeda1!="SM2->M2_MOEDA0")
			&cnMoeda1 := &nValor1 
		endif                       

		cMoFin2 := Alltrim(Str(Posicione("SYF",1,xFilial("SYF")+aNMoedas[nW,1],"YF_ZZMOEFA")))
		if(cMoFin2!="0")
			cnMoeda2 := "SM2->M2_MOEDA"+cMoFin2
			nValor2  := "nVal"+aNMoedas[nW,1]+Alltrim(aNMoedas[nW,4])
			&cnMoeda2 := &nValor2         
		Endif		
	Next
	SM2->M2_INFORM	:= "S"
	MsUnlock('SM2')
	SM2->(dbCloseArea())
	
	BEGIN TRANSACTION	
	If CtbInUse()
		GrvCTBCTP(dData)
	EndIf	
	END TRANSACTION 	
Return

Static Function GrvCTBCTP(dData,cMoeda)
	Local aSaveArea := GetArea()
	Local cVal
	Local cBloq
	Local nTaxa
	Local nCont    
	Local nQtas := iif( __nQuantas < 5 , 5 , __nQuantas )  
	Local lGrava
	
	/*Grava CTP -> quando estiver usando SIGACTB*/
	
	If ChkFile("CTP") .And. ChkFile("CTO")
		For nCont	:= 1 To nQtas
			cMoeda		:= StrZero(nCont,2)
			cVal		:= Alltrim( Str( nCont ))
			nTaxa		:= CriaVar("CTP_TAXA",.T.)
			cBloq		:= CriaVar("CTP_BLOQ",.T.)
			If ChkFile("CTO")
				dbSelectArea("CTO")
				dbSetOrder(1)
				If dbSeek( xFilial() + cMoeda )
					If ChkFile("CTP")
						dbSelectArea("CTP")
						dbSetOrder(1) 
						lGrava := CTP->(dbSeek( xFilial() + DTOS(dData) + cMoeda ))
						RecLock("CTP",!lGrava)
						Replace CTP_FILIAL		With xFilial()
						Replace CTP_DATA		With dData
						Replace CTP_MOEDA		With cMoeda
						Replace CTP_BLOQ		With cBloq				// Taxa Nao Bloqueada
						
						If Empty(&("SM2->M2_MOEDA"+cVal))
							Replace CTP_TAXA	With nTaxa
						Else	
							Replace CTP_TAXA 	With &("SM2->M2_MOEDA"+cVal)
						EndIf	
						MsUnlock()
						dbCommit()
					EndIf	
				EndIf	
			EndIf	
		Next nCont
	EndIf   
	
	RestArea(aSaveArea)
	
Return                    
   
Static Function faaMoedas()
    Local aMoeSis   := {}
	Local cCampo    := ""
	Local aaMoedas  := {}
	Local cQuery    := ""
	    
	aMoeSis := StrTokArr(GvGetMoedas(),";")
	
	dbSelectArea("SX3")      
 	For i := 1 to len(aMoeSis) 
 		cCampo := "M2_MOEDA"+Substr(Alltrim(aMoeSis[i]),1,1)
		SX3->(dbSetOrder(2))
		SX3->(dbGoTop())
		If SX3->(dbSeek(@cCampo))
			cQuery := "SELECT * FROM " + RetSQLName("SYF") + " WHERE D_E_L_E_T_='' AND YF_FILIAL='"+xFilial("SYF")+"' AND YF_MOEFAT = "+Substr(Alltrim(aMoeSis[i]),1,1)+" ORDER BY YF_MOEDA"
		
			If ( SELECT("TMP") ) > 0
				dbSelectArea("TMP")
				TMP->(dbCloseArea())
			EndIf
			
			TCQUERY cQuery NEW ALIAS "TMP"	                      
			
		    if TMP->(!EOF())	        
		    	While TMP->(!EOF())	        
				    Aadd(aaMoedas, {TMP->YF_MOEDA,TMP->YF_COD_GI,TMP->YF_MOEFAT,TMP->YF_ZZMOEFA} )
				    TMP->(dbSkip())
				EndDo
			Endif		

		Endif
	Next
Return(aaMoedas)