No artigo de hoje vamos demonstrar em como atualizar a tabela SYD, com os dados de NCMs.
A lógica aqui é a seguinte:
- O primeiro passo, é exibido uma pergunta se deseja confirmar
- É feito o download do JSON com as nomenclaturas automaticamente no link https://portalunico.siscomex.gov.br/classif/api/publico/nomenclatura/download/json?perfil=PUBLICO
- Através da classe JSONObject é convertido o texto para uma variável em AdvPL
- A chave Nomenclaturas é atribuída em outra variável (jNomenclat) e é feito um laço de repetição em todas as nomenclaturas (incrementando uma régua de progresso)
- Se a nomenclatura tiver 8 caracteres (sem os pontos) e não existir na SYD, irá acionar o execauto de inclusão (o nome do execauto é MVC_EICA130)
- No final é exibido uma mensagem de log com os sucessos ou falhas (as falhas é gravado um log na pasta \x_logs\ dentro da Protheus Data)
Abaixo o código fonte desenvolvido, conforme a lógica descrita acima.
//Bibliotecas #Include "TOTVS.ch" /*/{Protheus.doc} User Function zImpSYD Função para atualizar a tabela de NCM no Protheus @type Function @author Atilio @since 12/11/2022 @obs A atualização é baseada no JSON disponível para download em: https://www.gov.br/receitafederal/pt-br/assuntos/aduana-e-comercio-exterior/classificacao-fiscal-de-mercadorias/download-ncm-nomenclatura-comum-do-mercosul /*/ User Function zImpSYD() Local aArea := FWGetArea() //Se a pergunta for confirmada If FWAlertYesNo("Deseja atualizar a tabela de NCMs no Protheus?", "Continua") Processa({|| fImporta() }, 'NCMs...') EndIf FWRestArea(aArea) Return Static Function fImporta() Local cLinkDown := "https://portalunico.siscomex.gov.br/classif/api/publico/nomenclatura/download/json?perfil=PUBLICO;charset=iso-8859-1" //Dica do charset enviada por João Local cTxtJson := "" Local cError := "" Local jImport Local jNomenclat Local jNCMAtu Local nNCMAtu := 0 Local cCodigo := "" Local cDescric := "" Local aDados := {} Local cLog := "" Local nLinhaErro := 0 Local nTamDescri := TamSX3("YD_DESC_P")[01] //Variáveis para log do ExecAuto Private lMSHelpAuto := .T. Private lAutoErrNoFile := .T. Private lMsErroAuto := .F. //Baixa o JSON disponível cTxtJson := HttpGet(cLinkDown) //cTxtJson := FWNoAccent(cTxtJson) //Dica do João, será tratado direto na variável cDescric //Se houver conteúdo If ! Empty(cTxtJson) jImport := JsonObject():New() cError := jImport:FromJson(cTxtJson) DbSelectArea("SYD") SYD->(DbSetOrder(1)) // YD_FILIAL + YD_TEC + YD_EX_NCM + YD_EX_NBM + YD_DESTAQU //Se não tiver erro no parse If Empty(cError) jNomenclat := jImport:GetJsonObject('Nomenclaturas') //Percorre os NCM nTotal := Len(jNomenclat) ProcRegua(nTotal) For nNCMAtu := 1 To nTotal IncProc("Processando registro " + cValToChar(nNCMAtu) + " de " + cValToChar(nTotal) + "...") //Pegando o NCM atual, o código e a descrição jNCMAtu := jNomenclat[nNCMAtu] cCodigo := jNCMAtu:GetJsonObject("Codigo") cDescric := jNCMAtu:GetJsonObject("Descricao") //Remove caracteres especiais da descrição cDescric := FWNoAccent(DecodeUTF8(cDescric, "cp1252")) //Dica do João para tratar a acentuação cDescric := StrTran(cDescric, "-", "") cDescric := StrTran(cDescric, "<i>", "") cDescric := StrTran(cDescric, "</i>", "") cDescric := Alltrim(cDescric) cDescric := Upper(cDescric) //Dica do João, para gravar tudo em caixa alta padronizado cDescric := Left(cDescric, nTamDescri) //Dica do Renato, para gravar somente conforme o tamanho do campo no Dicionário //Removendo os pontos do código cCodigo := Alltrim(cCodigo) cCodigo := StrTran(cCodigo, ".", "") cCodigo := StrTran(cCodigo, "-", "") //Se o código tiver 8 caracteres e não conseguir posicionar no registro If Len(cCodigo) == 8 .And. ! SYD->(MsSeek(FWxFilial("SYD") + cCodigo)) aDados := {} aAdd(aDados, {"YD_TEC", cCodigo, Nil}) aAdd(aDados, {"YD_DESC_P", cDescric, Nil}) aAdd(aDados, {"YD_UNID", "UN", Nil}) //Aciona a inclusão do registro lMsErroAuto := .F. MSExecAuto({|x, y| MVC_EICA130(x, y)}, aDados, 3) //Se houve erro, gera o log If lMsErroAuto cPastaErro := '\x_logs\' cNomeErro := 'erro_syd_cod_' + cCodigo + "_" + 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 cTextoErro := "" cTextoErro += "Codigo: " + cCodigo + CRLF cTextoErro += "Descricao: " + cDescric + CRLF cTextoErro += "--" + CRLF + CRLF 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 registro, codigo [' + cCodigo + '], veja o arquivo de log em ' + cPastaErro + cNomeErro + CRLF Else cLog += '+ Sucesso no Execauto no codigo ' + cCodigo + ';' + CRLF EndIf EndIf Next //Se tiver log, mostra ele If ! Empty(cLog) cDirTmp := GetTempPath() cArqLog := 'importacao_' + dToS(Date()) + '_' + StrTran(Time(), ':', '-') + '.log' MemoWrite(cDirTmp + cArqLog, cLog) ShellExecute('OPEN', cArqLog, '', cDirTmp, 1) EndIf Else FWAlertError("Houve uma falha na conversão do JSON: " + CRLF + cError, "Erro no Parse") EndIf EndIf Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Efetuei alguns ajustes neste fonte devido a atender minhas necessidades, mas acredito que outros poderam ter o mesmo problema.
Na linha 55 foi necessario alterar o link para este link Local cLinkDown := “https://portalunico.siscomex.gov.br/classif/api/publico/nomenclatura/download/json?perfil=PUBLICO;charset=iso-8859-1”, por causa da codificação em que os acentos estão retornando para o advpl.
Na linha 44 comentei esta parte //cTxtJson := FWNoAccent(cTxtJson), devido não estar retirado as informações de acentos corretamente.
Desta forma foi necessario incluir uma linha logo abaixo da linha 73 foi incluido a tratativa da descrição das NCMS cDescric := FWNoAccent(decodeUTF8(cDescric, “cp1252”)), devido a codificação em que os registros são retornados.
Já na linha 84, incrementei desta forma para ficar um padrão na gravação dos dados, aAdd(aDados, {“YD_DESC_P”, UPPER(cDescric), Nil})
Bom dia João, tudo joia?
Opa, ficamos felizes que nosso singelo exemplo tenha lhe ajudado.
E ficamos honrados pela melhoria que foi elaborada por você e gentilmente disponibilizada.
Um grande abraço.
Boa noite! Além de seguir as orientações do João, precisei limitar o tamanho da variável cDescric devido ao campo YD_DESC_P, que suporta apenas 40 caracteres.
//Limita a descrição para 40 caraceteres
cDescric := SubStr(cDescric, 1, 40)
Bom dia Renato, tudo joia?
Opa, obrigado pela contribuição, atualizamos o exemplo, linhas 37 e 77.
Um grande abraço.
Atílio, boa tarde! Muito obrigado pelo retorno. Você já pegou o tamanho na sx3, ficou muito bom. Abraço.
Bom dia Renato, tudo joia?
Opa, nós que agradecemos pelo comentário e feedback.
Um grande abraço.
Muito bom!! Está de parabéns, coisas simples e banais que a totvs poderia implementar.
Bom dia Rodrigo, tudo joia?
Obrigado pelo comentário e carinho, é muita bondade e generosidade sua.
Um grande abraço.
Boa tarde pessoal, não sou DEV e por isso, apenas compilei o cod. fonte acima. Porém, não funcionou. Não cadastrou os NCM’s na Tabela SYD.
Bom dia Marcos, tudo joia?
Faça esse procedimento:
1. Baixe o zMiniForm disponível nesse link: https://terminaldeinformacao.com/2018/02/13/funcao-para-executar-formulas-protheus-12/
2. Compile ele na sua base usando o VSCode
3. Coloque ele no menu, conforme esse tutorial: https://terminaldeinformacao.com/2023/05/31/como-adicionar-uma-rotina-em-um-menu-do-protheus/
4. Abra o zMiniForm e execute a fórmula: u_zImpSYD()
Tenha uma ótima e abençoada terça feira.
Um grande abraço.