Sugestão para atualizar campo memo no Protheus de um arquivo txt


Algumas pessoas estavam me perguntando como atualizar o campo memo no Protheus já que este trabalha com a tabela SYP (Descrição dos campos memos)? Tabelas como a do cadastro de produto é uma das tabelas que usam campos mesmo, no caso tem os campos “Descrição LI”, “Descrição em inglês” e “Descrição em português”. O processo de atualização é bem simples, vamos exemplificar usando o cadastro padrão de produtos (SB1). Irei definir um layout do arquivo texto, irei pedir ao meu usuário que crie um arquivo texto contendo as seguintes colunas: Código do produto; código da tabela SYP, descrição. O código do produto deverá ser o mesmo existente na tabela de produtos O código da tabela SYP, deverá ser o mesmo conteúdo existente no campo correspondente ao campo memo, irei trabalhar com os campos B1_DESC_GI e B1_VM_GI  (Descrição da LI), este campo tem o seguinte inicializador padrão: E_MSMM(SB1->B1_DESC_GI,48) A cada 48 caracteres do meu texto, ou a cada quebra de linha será uma linha na minha tabela SYP. E teremos também no meu layout a descrição que quero incluir, pode ser uma coluna só onde você fará a quebra dos 48 caracteres ou peça ao usuário para criar várias colunas que corresponda à quantidade de linha na tabela SYP.  

Produto;Número LI;Desc1;Desc2;Desc3;Desc4
3915008;069418;PARADA DE EMERGENCIA FANT.; texto segunda linha; texto terceira linha; texto quarta linha com xxxxxxxxxxxxxxxxxxxxxxxx
3729745;069725;BARRA INFERIOR DEPEN F201 MAQ; texto segunda linha; texto terceira linha; texto quarta linha com xxxxxxxxxxxxxxxxxxxxxxxx
3729740;069726;BARRA INFERIOR DEPENADEIRA F20; texto segunda linha; texto terceira linha; texto quarta linha com xxxxxxxxxxxxxxxxxxxxxxxx
A codificação abaixo é apenas uma sugestão, se tiverem outras sugestões fiquem a vontade para compartilhar. Vamos ao que interessa:
#INCLUDE "PROTHEUS.CH"
#INCLUDE "TOPCONN.CH"
User Function MCOM009()
	Local cTitulo	:= "Ajustar descrição da LI do cadastro de Produtos"
	Local nOpcao 	:= 0
	Local aButtons 	:= {}
	Local aSays    	:= {}
	Private cArea		:= GetArea()
	Private cPerg 	:= Padr("MCOM009",10)
	Private oProcess
	
	ajustaSx1(cPerg)
	pergunte(cPerg, .F.)

	AADD(aSays,OemToAnsi("Ajustar descrição da LI do cadastro de Produtos vindos de um arquivo CSV."))
	AADD(aSays,"")	
	AADD(aSays,OemToAnsi("Clique no botão PARAM para informar o arquivo que será importado."))
	AADD(aSays,"")	
	AADD(aSays,OemToAnsi("Após isso, clique no botão OK."))
	
	AADD(aButtons, { 1,.T.,{|o| nOpcao:= 1,o:oWnd:End()} } )
	AADD(aButtons, { 2,.T.,{|o| nOpcao:= 2,o:oWnd:End()} } )
	AADD(aButtons, { 5,.T.,{||   pergunte(cPerg,.T.)  } } )
	
	FormBatch( cTitulo, aSays, aButtons,,200,530 )

	if nOpcao = 1
	   	oProcess := MsNewProcess():New( { || MCOM009I(MV_PAR01) } , cTitulo , "Aguarde..." , .F. )
   		oProcess:Activate()		
	endif
    
	RestArea(cArea)

Return
 
Static Function MCOM009I(cArquivo)
	Local cLinha     := ""
	Local cTexto     := ""
	Local nI         := 0
	Local nHdl 
	Local nTamArq
	Local nTamLinha
	Local nLinhas
	Local aDados 	 := {}		
	Local nCont
	Local cLinhas
	Local cAviso     := ""
	Local aStrutSC1  := {}
	Local nItem	     := 0
	Local nTotal     := 0
	Local lPrim      := .T.
	Local nPrim		 := 1
	Local alin		 := {}
	Local cErro		 := ""
	Local cProduto   := ""
	Local cChave	 := ""
	Local cDesc1	 := ""
	Local cDesc2	 := ""
	Local cDesc3	 := ""
	Local cDesc4	 := ""
	Local aDescYP	 := {}
	Local cTipo	 	 := ""
	Local nColunas	 := 0
	Local nDesc1, nDesc2, nDesc3, nDesc4 := 0
								
	if (Upper(Right(Alltrim(cArquivo),4)) != ".CSV" )
		MsgStop("Apenas arquivos com extensão CSV são aceitos!"+CRLF+"Verifique o arquivo informado!","Atenção")		
		Return
	EndIf     

	if !File(cArquivo)
		MsgStop("O arquivo "+Alltrim(cArquivo)+" não existe, favor informar um arquivo existente!","Atenção")		
		Return
	EndIf     
                	
	nHdl := fOpen(cArquivo)

	If nHdl == -1 
		IF FERROR()== 516 
		    ALERT("Feche a planilha que gerou o arquivo.")
		EndIF
	EndIf
	
	//+---------------------------------------------------------------------+
	//| Verifica se foi possível abrir o arquivo                            |
	//+---------------------------------------------------------------------+
	If nHdl == -1
		MsgAlert("O arquivo de nome "+Alltrim(cArquivo)+" nao pode ser aberto! Verifique os parametros.","Atencao!")
	   	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(cArquivo)  //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 := nTamArq/nTamLinha
	
	oProcess:SetRegua1(nLinhas)

	aDados:={}	      
	nCont := 0
	While !FT_FEOF()// .and. ncont < 16 oProcess:IncRegua1('Validando Linha: ' + Alltrim(Str(nCont))) clinha := FT_FREADLN() if !empty(cLinha) AADD(aDados,Separa(cLinha,";",.T.)) //Armazena no array aDados todas as linhas do TXT endif FT_FSKIP() nCont++ EndDo FT_FUse() fClose(nHdl) aStrutSC1 := dbStruct() oProcess:SetRegua1(len(aDados)) cErro := "" dbSelectArea("SB1") SB1->(dbSetOrder(1))
	
	For nI := 1 to len(aDados)
		aColunas := {}
				
		cProduto	:= aDados[nI,1]
		cChave	 	:= iif( !Empty(aDados[nI,2]) , aDados[nI,2] , fUltimo() )
		cTipo	 	:= iif( !Empty(aDados[nI,2]) , "A" , "N" )
		
		nColunas := 0
		For y := 1 to len(aDados[nI])
			nColunas += 1
		Next
		
		cDesc1	 	:= iif(nColunas>=3, aDados[nI,3], "")
		
		If Empty(cDesc1)
			MsgStop("É obrigatório ter pelo menos a primeira descrição!")
			Return			
		Endif
		
		cDesc2	 	:= iif(nColunas>=4, aDados[nI,4], "")
		cDesc3	 	:= iif(nColunas>=5, aDados[nI,5], "")
		cDesc4	 	:= iif(nColunas>=6, aDados[nI,6], "")	

		SB1->(dbGoTop())
		if SB1->(!dbSeek(xFilial("SB1")+cProduto))
			
			cErro += Alltrim(cProduto)+CRLF
			
			oProcess:IncRegua1("Produto "+Alltrim(cProduto)+" não existe...")
			
		Else			                                           
			
			oProcess:IncRegua1("Atualizando produto " + Alltrim(cProduto))
			
			//Verifica se a chave existe, se existir deve excluir todos os registros que contem a chave
			dbSelectArea("SYP")
			SYP->(DbSetOrder(1))
			SYP->(DbGoTop())
			If(SYP->(DbSeek(xFilial("SYP") + cChave, .T.)))
				
				oProcess:SetRegua2( SYP->(RecCount()) )
				
				While SYP->(!Eof()) ;
					.And. ( Alltrim(SYP->YP_CHAVE) == Alltrim(cChave))  ;
					.And. ( Alltrim(SYP->YP_CAMPO) == "B1_DESC_GI") ;
					.And. ( SYP->YP_FILIAL == xFilial("SYP"))
					
					oProcess:IncRegua2("Excluindo sequencia " + SYP->YP_SEQ + "...")
					
			   		RecLock("SYP",.F.)
				  	SYP->(dbDelete())
				  	SYP->(MsUnlock())									 

					SYP->(DbSkip())
					
				End While
			Endif
			SYP->(DbCloseArea())
				
			//Inserir os registros na tabela SYP
			aDescYP := {}
			if !Empty(cDesc1)
				aadd(aDescYP,{cChave,cDesc1})
			Endif
			if !Empty(cDesc2)
				aadd(aDescYP,{cChave,cDesc2})
			Endif
			if !Empty(cDesc3)
				aadd(aDescYP,{cChave,cDesc3})
			Endif
			if !Empty(cDesc4)
				aadd(aDescYP,{cChave,cDesc4})
			Endif
						
			oProcess:SetRegua2( len(aDescYP) * 2)
			
			dbSelectArea("SYP")
			For i := 1 to len(aDescYP)
				Begin Transaction
					RecLock("SYP",.T.)
					SYP->YP_FILIAL := xFilial("SYP")
					SYP->YP_CHAVE  := aDescYP[i,1]
					SYP->YP_SEQ    := StrZero(i,3)
					SYP->YP_TEXTO  := aDescYP[i,2]
					SYP->YP_CAMPO  := "B1_DESC_GI"
					SYP->(MsUnlock())
					DbCommit()

					oProcess:IncRegua2("Incluindo Descrição LI - Registro " + StrZero(nI,4) + "...")
					
				End Transaction
			Next
			
			if cTipo=="N"
				RecLock("SB1",.F.)
				SB1->B1_DESC_GI := cChave
				SB1->(MsUnlock())
			Endif
					
		Endif 
			 
		Sleep(100)
		dbSelectArea("SB1")  
	Next nI
	
			
	if !Empty(cErro)
		
		Aviso("ATENÇÃO", "Alguns produtos não puderam ser importados por não existirem na tabela padrão de produtos."+CRLF+cErro,{"OK"},3)

	Endif
	
	if(mv_par02==1)
		fRename(Upper(Alltrim(cArquivo)),Upper(Alltrim(cArquivo))+".processado")
	Endif

	oProcess:IncRegua1("Atualização finalizada...")
	oProcess:IncRegua2("")

Return
 
Static Function fUltimo()
	local cUltimo := ""
	Local cQuery  := ""
	cQuery := " SELECT MAX(YP_CHAVE) ULTIMO "
	cQuery += " FROM " + RetSqlName("SYP")
	cQuery += " WHERE YP_FILIAL = '"+XFILIAL("SYP")+"' "
	cQuery += " AND D_E_L_E_T_ = ' ' "
	
	If ( SELECT("TMPSYP") ) > 0
		dbSelectArea("TMPSYP")
		TMPSYP->(dbCloseArea())
	EndIf
	TCQUERY cQuery NEW ALIAS "TMPSYP"	
	IF TMPSYP->(!Eof())
		cUltimo := StrZero(Val(TMPSYP->ULTIMO)+1,6)	
	Endif                            
	TMPSYP->(dbCloseArea())	
Return(cUltimo)
 
static function ajustaSx1(cPerg)
	PutSx1(cPerg, "01", "Arquivo ?","","", "mv_ch1", "C",99, 0, 0, "G", "","DIR","","","mv_par01","","","","","","","","","","","","","","","","",{"Informe o arquivo para importar,","obrigatóriamente deve ser .CSV","",""},{"","","",""},{"","",""},"")
	PutSx1(cPerg, "02", "Renomear?","","", "mv_ch2", "N", 1, 0, 2, "C", "",   "","","","mv_par02","Sim","Si","Yes","","Nao","No","No")
Return
importartxtparacampomemo importartxtparacampomemo2