Como importar arquivos para o Banco de Conhecimento

Hoje vou mostrar como importar arquivos para o Banco de Conhecimento do Protheus.

O Banco de Conhecimento no Protheus, serve para armazenar arquivos relacionados a alguma entidade, por exemplo, clientes, fornecedores, vendedores, etc. Então se você quiser um lugar para centralizar documentos de seus clientes, como sintegra ou outros arquivos .pdf, basta você gravar a informação nas tabelas do Banco de Conhecimento e salvar o arquivo dentro da Protheus Data.

Para fazer o cadastro de novos arquivos no Banco de Conhecimento, geralmente usamos a função MsDocWizard junto com a MsDocument, porém no artigo de hoje irei mostrar como importar vários arquivos, sem precisar usar a função de wizard.

Nessa customização iremos incluir dados na tabela ACB (Objeto no Banco de Conhecimento) e AC9 (Relacionamento da Entidade com o Objeto), usando como base a tabela de clientes SA1 e tabela de fornecedores SA2.

Obs.: Para essa importação funcionar, configure o parâmetro MV_DIRDOC sendo um diretório interno da Protheus Data (por exemplo, \DIRDOC\) e o parâmetro customizado MV_X_DIROR, sendo configurado com o diretório de origem que irá buscar os arquivos (por exemplo, F:\Arquivos\)

Obs. 2: A nomenclatura dos arquivos, deve começar com a letra C (Cliente) ou F (Fornecedor), seguido pelo código + loja

//Bibliotecas
#Include "TOTVS.ch"
#Include "FileIO.ch"

/*/{Protheus.doc} zImpDoc
Função para importar objetos para o Banco de Conhecimento
@author Atilio
@since 02/08/2020
@version 1.0
/*/

User Function zImpDoc()
	//Se a pergunta for confirmada
	If MsgYesNo("Esse procedimento realizara a importacao dos arquivos para o Banco de Conhecimento. Deseja continuar?", "Atencao")
		Processa({|| fRunProc() })
	EndIf
Return

Static Function fRunProc()
	Local cDirDoc := Alltrim(GetMv("MV_DIRDOC"))
	Local cDirOrig := SuperGetMv("MV_X_DIROR", .F., "\\192.168.10.112\totvs\banco de Conhecimento\Importar\")
	Local aDir 
	Local cProxObj
	Local cCodLoja
	Local cTipo                    
	Local cPathBco
	Local nAtual
	Local cArqAtu
	Local cAliasAtu := ""
	
	//Se o ultimo caracter nao for uma \, acrescenta ela, e depois configura o diretorio com a subpasta co01\shared
	If SubStr(cDirDoc, Len(cDirDoc), 1) != '\'
		cDirDoc := cDirDoc + "\"
	EndIf
	cPathBco := cDirDoc + 'co01\shared\'

	//Busca todos os arquivos da origem
	aDir := directory(cDirOrig + "*.*")

	//Define o tamanho da regua do Processa
	ProcRegua(Len(aDir))
	
	//Percorre todos os itens
	For nAtual := 1 To Len(aDir)
		IncProc("Importando objeto (" + cValToChar(nAtual) + " de " + cValToChar(Len(aDir)) + ")...")
		cArqAtu := aDir[nAtual, 1]
		
		//Faz a cópia da origem, para a pasta do banco de conhecimento
		Copy File &(cDirOrig + cArqAtu) To &(cPathBco + cArqAtu)
		
		//Se não conseguiu copiar, mostra um alerta, e volta o laço
		If ! File(cPathBco + cArqAtu)
			MsgAlert("Erro ao importar: " + cPathBco + cArqAtu, "Atencao!")
			Loop
		EndIf
		
		//Pegando o código e loja, a partir da posição 2, com 8 caracteres (XXXXXXYY)
		cCodLoja := SubStr(cArqAtu, 2, 8)
		cAliasAtu := ""
		
		//Se começar com a letra C, é cliente
		If Upper(SubStr(cArqAtu, 1, 1)) == "C"
			DbSelectArea("SA1")
			SA1->(DbSetOrder(1))
			SA1->(DbGoTop())
			cTipo     := "Cliente"
			cAliasAtu := "SA1"
			
		//Senão, se começar com a letra F, é fornecedor
		ElseIf Upper(SubStr(cArqAtu, 1, 1)) == "F"
			DbSelectArea("SA2")
			SA2->(DbSetOrder(1))
			SA2->(DbGoTop())
			cTipo     := "Fornecedor"
			cAliasAtu := "SA2"
			
		//Senão, pula o objeto
		Else
			Loop
		EndIf
		
		//Se conseguir posicionar conforme a última tabela aberta com DbSelectArea
		If (cAliasAtu)->(DbSeek(FWxFilial(cAliasAtu) + cCodLoja))
			
			//Pega o próximo registro da ACB
			DbSelectArea("ACB")
			ACB->(DbSetOrder(1))
			ACB->(DbGoBottom())
			cProxObj := StrZero((Val(ACB->ACB_CODOBJ) + 1), 10)
			ACB->(DbSetOrder(2))
			
			//Se não tiver o arquivo na ACB, irá incluir
			If ! ACB->(DbSeek(FWxFilial('ACB') + cArqAtu))
				Reclock("ACB", .T.)
					ACB->ACB_FILIAL := FWxFilial('ACB')
					ACB->ACB_CODOBJ := cProxObj
					ACB->ACB_OBJETO := cArqAtu
					ACB->ACB_DESCRI := cArqAtu
				ACB->(MsUnlock())
				
				//Se não existir na tabela de vinculos, irá criar
				DbSelectArea("AC9")
				AC9->(DbSetOrder(1))
				If ! AC9->(DbSeek(FWxFilial('AC9') + cProxObj + cCodLoja))
					Reclock("AC9", .T.)
						AC9->AC9_FILIAL := FWxFilial('AC9')
						AC9->AC9_ENTIDA := cAliasAtu
						AC9->AC9_CODENT := cCodLoja
						AC9->AC9_CODOBJ := cProxObj
					AC9->(MsUnlock())
				EndIf
			EndIf
			
			//Exclui o arquivo da origem
			FErase(cDirOrig + cArqAtu)
		
		//Se não conseguir dar um Seek na tabela, mostra mensagem de falha
		Else
			MsgStop("Codigo de " + cTipo + " invalido no arquivo: " + cArqAtu, "Atenção")
		EndIf
	Next
Return

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. George Allan disse:

    Muito bom Atílio, obrigado por compartilhar algo tão útil em um fonte tão enxuto 🙂

  2. Renato Silva disse:

    Bom dia, Dan Atilio.

    Parabéns pelo conteúdo. Eu gostaria de saber se existe alguma possibilidade de armazenar os arquivos em outro lugar, como outro drive da máquina ou da rede, ao invés na estrutura do protheus (system\dirdoc)?

    • Bom dia Renato, tudo bem?
      No caso, por isso as tabelas internas e lógica da MsDocument (Banco de Conhecimento), essa rotina usa o parâmetro e os caminhos padrões.
      Para salvar em um drive de rede ou outra máquina, você teria que adaptar o trecho do copy file, e o mais importante, talvez criar uma tabela customizada e usar no lugar da ACB e AC9.
      Abraços.

Deixe uma resposta