No vídeo de hoje, vou demonstrar em como importar uma pré nota de entrada (SF1 e SD1) via csv ou txt.
Hoje, a dúvida foi feita pelo grande Roberto, onde ele tinha uma dúvida, em como fazer uma importação de csv ou txt para uma pré nota de entrada (SF1 e SD1).
Com isso em mente, fiz um vídeo explicando como fazer a leitura linha a linha e acionar a importação dos dados de forma correta via ExecAuto.
E abaixo o código fonte desenvolvido para exemplificar:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} User Function zVid0013
Função que realiza a importação do CSV como Pré Nota
@type Function
@author Atilio
@since 23/02/2022
/*/
User Function zVid0013()
Local aArea := FWGetArea()
Local cDirIni := GetTempPath()
Local cTipArq := "Arquivos com separações (*.csv)"
Local cTitulo := "Seleção de Arquivos para Processamento"
Local lSalvar := .F.
Local cArqSel := ""
//Se não estiver sendo executado via job
If ! IsBlind()
//Chama a função para buscar arquivos
cArqSel := tFileDialog(;
cTipArq,; // Filtragem de tipos de arquivos que serão selecionados
cTitulo,; // Título da Janela para seleção dos arquivos
,; // Compatibilidade
cDirIni,; // Diretório inicial da busca de arquivos
lSalvar,; // Se for .T., será uma Save Dialog, senão será Open Dialog
; // Se não passar parâmetro, irá pegar apenas 1 arquivo; Se for informado GETF_MULTISELECT será possível pegar mais de 1 arquivo; Se for informado GETF_RETDIRECTORY será possível selecionar o diretório
)
//Se tiver o arquivo selecionado e ele existir
If ! Empty(cArqSel) .And. File(cArqSel)
Processa({|| fImporta(cArqSel) }, "Importando...")
EndIf
EndIf
FWRestArea(aArea)
Return
Static Function fImporta(cArqSel)
Local cDirLog := GetTempPath()
Local cArqLog := "zFat07Im_" + dToS(Date()) + "_" + StrTran(Time(), ':', '-') + ".log"
Local nTotLinhas := 0
Local cLinAtu := ""
Local nLinhaAtu := 0
Local aLinha := {}
Local oArquivo
Local aLinhas
Local aLinhaSD1 := {}
Local cItem := StrTran(Space(TamSX3('D1_ITEM')[01]), ' ', '0')
//Primeira coluna do Excel, será o tipo da linha
Private nPosTip := 1 //SF1 ou SD1
//Posições do Cabeçalho (SF1)
Private nCabTipo := 2 //F1_TIPO
Private nCabForm := 3 //F1_FORMUL
Private nCabDocu := 4 //F1_DOC
Private nCabSeri := 5 //F1_SERIE
Private nCabEmis := 6 //F1_EMISSAO
Private nCabForn := 7 //F1_FORNECE
Private nCabLoja := 8 //F1_LOJA
Private nCabEspe := 9 //F1_ESPECIE
Private nCabCond := 10 //F1_COND
//Posições dos Itens (SD1)
Private nIteProd := 2 //D1_COD
Private nIteQtde := 3 //D1_QUANT
Private nIteVUni := 4 //D1_VUNIT
Private nIteTpES := 5 //D1_TES
//Variáveis do ExecAuto
Private aCabecSF1 := {}
Private aItensSD1 := {}
Private lMSHelpAuto := .T.
Private lAutoErrNoFile := .T.
Private lMsErroAuto := .F.
Private cLog := ""
Private cChaveSF1 := ""
//Abre as tabelas que serão usadas
DbSelectArea('SF1')
SF1->(DbSetOrder(1)) //F1_FILIAL + F1_DOC + F1_SERIE + F1_FORNECE + F1_LOJA + F1_TIPO
SF1->(DbGoTop())
//Definindo o arquivo a ser lido
oArquivo := FWFileReader():New(cArqSel)
//Se o arquivo pode ser aberto
If (oArquivo:Open())
//Se não for fim do arquivo
If ! (oArquivo:EoF())
//Definindo o tamanho da régua
aLinhas := oArquivo:GetAllLines()
nTotLinhas := Len(aLinhas)
ProcRegua(nTotLinhas)
//Método GoTop não funciona (dependendo da versão da LIB), deve fechar e abrir novamente o arquivo
oArquivo:Close()
oArquivo := FWFileReader():New(cArqSel)
oArquivo:Open()
//Iniciando controle de transação
Begin Transaction
//Enquanto tiver linhas
While (oArquivo:HasLine())
//Incrementa na tela a mensagem
nLinhaAtu++
IncProc("Analisando linha " + cValToChar(nLinhaAtu) + " de " + cValToChar(nTotLinhas) + "...")
//Pegando a linha atual e transformando em array
cLinAtu := oArquivo:GetLine()
aLinha := StrTokArr(cLinAtu, ";")
//Se houver posições no array
If Len(aLinha) > 0
//Se for cabeçalho
If Upper(aLinha[nPosTip]) == "SF1"
//Se tiver cabeçalho e itens, chama a rotina para acionar o ExecAuto
fPreNota()
//Zera as variáveis
aCabecSF1 := {}
aItensSD1 := {}
cItem := StrTran(Space(TamSX3('D1_ITEM')[01]), ' ', '0')
cChaveSF1 := ""
//Se tiver o mesmo numero de colunas, adiciona no array da sf1, e monta a chave que será pesquisada no seek
If Len(aLinha) == nCabCond
//Transforma a data
If "/" $ aLinha[nCabEmis]
aLinha[nCabEmis] := cToD(aLinha[nCabEmis])
Else
aLinha[nCabEmis] := sToD(aLinha[nCabEmis])
EndIf
aAdd(aCabecSF1, {"F1_TIPO" , aLinha[nCabTipo] , Nil})
aAdd(aCabecSF1, {"F1_FORMUL" , aLinha[nCabForm] , Nil})
aAdd(aCabecSF1, {"F1_DOC" , aLinha[nCabDocu] , Nil})
aAdd(aCabecSF1, {"F1_SERIE" , aLinha[nCabSeri] , Nil})
aAdd(aCabecSF1, {"F1_EMISSAO" , aLinha[nCabEmis] , Nil})
aAdd(aCabecSF1, {"F1_FORNECE" , aLinha[nCabForn] , Nil})
aAdd(aCabecSF1, {"F1_LOJA" , aLinha[nCabLoja] , Nil})
aAdd(aCabecSF1, {"F1_ESPECIE" , aLinha[nCabEspe] , Nil})
aAdd(aCabecSF1, {"F1_COND" , aLinha[nCabCond] , Nil})
cChaveSF1 := FWxFilial("SF1") +;
PadR(aLinha[nCabDocu], TamSX3("F1_DOC")[1], ' ') +;
PadR(aLinha[nCabSeri], TamSX3("F1_SERIE")[1], ' ') +;
PadR(aLinha[nCabForn], TamSX3("F1_FORNECE")[1], ' ') +;
PadR(aLinha[nCabLoja], TamSX3("F1_LOJA")[1], ' ') +;
PadR(aLinha[nCabTipo], TamSX3("F1_TIPO")[1], ' ')
EndIf
//Se for itens (e tiver todas as posições)
ElseIf Upper(aLinha[nPosTip]) == "SD1" .And. Len(aLinha) == nIteTpES
//Campos numéricos, retira ponto, transforma vírgula em ponto e converte para numérico
aLinha[nIteQtde] := Alltrim(aLinha[nIteQtde])
aLinha[nIteQtde] := StrTran(aLinha[nIteQtde], ".", "")
aLinha[nIteQtde] := StrTran(aLinha[nIteQtde], ",", ".")
aLinha[nIteQtde] := Val(aLinha[nIteQtde])
aLinha[nIteVUni] := Alltrim(aLinha[nIteVUni])
aLinha[nIteVUni] := StrTran(aLinha[nIteVUni], ".", "")
aLinha[nIteVUni] := StrTran(aLinha[nIteVUni], ",", ".")
aLinha[nIteVUni] := Val(aLinha[nIteVUni])
//Adiciona no array de Itens
cItem := Soma1(cItem)
aLinhaSD1 := {}
aAdd(aLinhaSD1, {"D1_ITEM" , cItem , Nil} )
aAdd(aLinhaSD1, {"D1_COD" , aLinha[nIteProd] , Nil} )
aAdd(aLinhaSD1, {"D1_QUANT" , aLinha[nIteQtde] , Nil} )
aAdd(aLinhaSD1, {"D1_VUNIT" , aLinha[nIteVUni] , Nil} )
aAdd(aLinhaSD1, {"D1_TOTAL" , aLinha[nIteQtde] * aLinha[nIteVUni] , Nil} )
aAdd(aLinhaSD1, {"D1_TES" , aLinha[nIteTpES] , Nil} )
aAdd(aItensSD1, aClone(aLinhaSD1))
EndIf
EndIf
EndDo
//Chama novamente a rotina de pré-nota pois pode ser que sobrou um cabec e itens para processar
fPreNota()
End Transaction
//Se tiver log, mostra ele
If ! Empty(cLog)
MemoWrite(cDirLog + cArqLog, cLog)
ShellExecute("OPEN", cArqLog, "", cDirLog, 1)
EndIf
Else
MsgStop("Arquivo não tem conteúdo!", "Atenção")
EndIf
//Fecha o arquivo
oArquivo:Close()
Else
MsgStop("Arquivo não pode ser aberto!", "Atenção")
EndIf
Return
Static Function fPreNota()
Local cPastaErro := ""
Local cNomeErro := ""
Local cTextoErro := ""
Local aLogErro := {}
Local nLinhaErro := 0
//Se tiver cabeçalho e itens
If Len(aCabecSF1) > 0 .And. Len(aItensSD1) > 0
//Se conseguir posicionar na nota, grava no log que já existe
If SF1->(MsSeek(cChaveSF1))
cLog += "- NF já existe na base, chave de pesquisa: " + cChaveSF1 + CRLF
//Aciona o ExecAuto
Else
lMsErroAuto := .F.
MSExecAuto({|x, y, z| MATA140(x, y, z)}, aCabecSF1, aItensSD1, 3)
//Se houve erro, gera o log
If lMsErroAuto
cPastaErro := "\x_logs\"
cNomeErro := "pre_nota_" + dToS(Date()) + "_" + StrTran(Time(), ":", "-") + ".txt"
//Se a pasta de erro não existir, cria ela
If ! ExistDir(cPastaErro)
MakeDir(cPastaErro)
EndIf
//Pegando log do ExecAuto, percorrendo e incrementando o texto
aLogErro := GetAutoGRLog()
For nLinhaErro := 1 To Len(aLogErro)
cTextoErro += aLogErro[nLinhaErro] + CRLF
Next
//Criando o arquivo txt e incrementa o log
MemoWrite(cPastaErro + cNomeErro, cTextoErro)
cLog += "- Falha ao incluir NF, chave de pesquisa: " + cChaveSF1 + ", arquivo de log em '" + cPastaErro + cNomeErro + "' " + CRLF
Else
cLog += "- NF incluida como pré-nota, chave de pesquisa: " + cChaveSF1 + CRLF
EndIf
EndIf
EndIf
Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Como sempre, mais um excelente artigo.
Opa, obrigado pelo comentário e feedback Roberto.
Abraços.
Este artigo foi muito útil para nossa empresa, gostaria de saber se aceita proposta para desenvolver e incluir mais algumas necessidades nesse fonte
Boa tarde Leandro, tudo bem?
Claro, nós atendemos sob demanda, nos mande um email com sua necessidade, segue o link com o nosso contato: https://atiliosistemas.com/contato/
Abraços.
Bom dia Dan, tudo bem?
Achei esse vídeo porque é o fim para os meios que eu preciso rs… porém eu estive pensando em outra coisa, e não sei se já fez algo do tipo.
Tem conhecimento de algum ponto de entrada na MATA103/MATA140 onde eu posso trazer os itens de uma devolução porém todos deletados, para que eu possa desmarcar manualmente? No caso da devolução seria usando o Retornar (devolução de vendas).
Obrigado pelo post!
Boa noite Felipe, tudo joia graças a Deus e você?
Eu nunca precisei fazer um p.e. para esse caso. Tentei procurar e não consegui encontrar.
Caso não encontre, você pode utilizar o ChkExec e adicionar um atalho, por exemplo, um F8 ou F9, ai ao pressionar, ele excluiria tudo da grid para o usuário depois selecionar.
Grande abraço.
Fala Dan! Achei outra forma de fazer isso. O deletar é típico do aHeader, até aí ok.. mas pra validar os valores do aCols quando eu desmarco, precisei passar o MaFisDel ali pois ele não estava considerando pro F1_TOTAL e pra SF3 também.
Segue o que customizei:
User Function DeletaLinha
Local nX
If FwIsInCallStack(“SA103Devol”)
For nX := 1 to Len(aCols)
aCols[nX][Len(aHeader)+1] := .T.
MaFisDel(nX,aCols[nX][Len(aCols[nX])])
Next
EndIf
Return
Grande Felipe, tudo joia?
Opa, obrigado pelo feedback e pelo exemplo enviado.
Um grande abraço.
Boa tarde Daniel,
Estou precisando de uma rotina dessa aqui na minha empresa.
Podemos conversar?
Att,
Milton Silva
Bom dia Milton, tudo joia?
Opa, se tiver alguma dúvida, basta entrar em contato conosco.
Abraços.
Caso eu precise gerar um pre-nota para formulário próprio igual a SIM, esse fonte não funcionaria?
Bom dia Caio, tudo joia?
Faça um teste, no array da SF1, na posição do campo F1_FORMUL, você passa “S” de sim.
Ai valida se irá dar certo a inclusão.
Tenha uma ótima e abençoada sexta feira.
Um forte abraço.