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.
Muito bom Atílio, obrigado por compartilhar algo tão útil em um fonte tão enxuto 🙂
Eu que agradeço pelo comentário jovem.
Grande abraço.
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.
Boa tarde!
Excelente compartilhamento, uma duvida, e a atabela ACC não teria que popular tbm?
Boa noite Rodrigo.
Primeiramente obrigado pelo feedback.
Então tabela ACC é de palavras chaves, ai é possível adaptar a rotina para gravar o nome do arquivo nela também.
Uma dúvida: gostaria de saber se sabem a regra para a pasta “co01\shared” na parte do “co01”. É sempre “co” + [EMPRESA] ou tem alguma regra especifica aí?
Bom dia José, tudo bem?
Conforme documentação no TDN, sempre é “CO” + Grupo de Empresas (existe também parametrização para gravar a data se quiser).
Segue o link: https://tdn.totvs.com/display/public/framework/MV_MULTDIR
Abraços.
Olá Daniel,
Seu fonte é excelente. Agiliza e muito a inclusão de documentos no banco de conhecimento.
Fiz algumas adaptações às minhas necessidades que são, a inclusão do processo de compra (cotações dos fornecedores) em pdf no pedido de compras, iclusão da DANFE em pdf no documento de entrada e inclusão dos comprovantes de pagamento no contas a pagar.
Estou agora estudando uma forma de excluir estes registros das tabelas ACB, ACC e AC9 quando houver a necessidade de excluir um mregstro informado erroneamente, pois de forma manual, só exclui o registro de relacionamento (AC9).
Criei tambem um campo que aparece em browse nas respectivas tabelas para informar visualmente que existe um documento relacionado via banco de conhecimento e assim, os usuários possam verificar o relacionamento sem a necesisdade de abrir o banco para consulta.
Gostaria de disponibilizar o fonte para que assim como eu tive a oportunidade, outros possam ter tambem.
Fala Jean, tudo joia?
Primeiramente obrigado pelas palavras e pelo comentário.
Será uma honra disponibilizar o exemplo aqui no artigo.
Se quiser me mande no WhatsApp ou por eMail, que eu disponibilizo aqui – https://terminaldeinformacao.com/contato/.
Um grande abraço.