Transmitir e monitorar NFe via código fonte

No artigo de hoje vamos demonstrar em como transmitir e monitorar uma NFe de saída via comandos em AdvPL ou TLPP.

Recentemente nos perguntaram se seria possível numa customização, acionar a transmissão do documento e monitorá-lo, sem exibir telas aos usuários.

 

Pensando nisso, montamos esse exemplo onde:

  1. É recebido por parâmetro a nota e série da SF2
  2. É feito a busca do ident, ambiente e modalidade
  3. Se conseguiu buscar as informações aciona a SpedNfeTrf para transmitir
  4. Em seguida é acionado a ProcMonitorDoc
  5. Se deu tudo certo, ou algum erro, é definido num array que será retornado

 

Supondo então, que você tenha a nota 000123789 com a série 1, pra acionar a customização iria ficar:

aInfo := u_zTransNfe("000123789", "1")

E abaixo o código completo da zTransNfe:

//Bibliotecas
#Include "TOTVS.ch"

/*/{Protheus.doc} zTransNfe
Função para transmitir a SF2 para a SEFAZ e Monitorar o resultado
@type user function
@author Atilio
@since 13/06/2025
@version version
@param cDocumento, Caractere, Número do Documento que vai ser transmitido
@param cSerie, Caractere, Série do Documento
@return aRetorno, Array, Array com duas posição, primeira se deu certo (.T. ou .F.) e segunda a mensagem (com observações)
@example
    aInfo := u_zTransNfe("000123456", "1")
/*/

User Function zTransNfe(cDocumento, cSerie)
    Local aArea         := FWGetArea()
    //Transmissão e Monitoramento
    Local cModelo		:= "55"
    Local cIdEnt 		:= ""
    Local cError		:= ""
    //Transmissão
	Local cAmbiente		:= ""
	Local cModalidade	:= ""
	Local cVersao		:= ""
	Local lCte			:= .F. //( cModelo == "57" )
	Local lEnd			:= .F.
    //Monitoramento
    Local nVezes        := 0
    Local cURL       	:= PadR(GetNewPar("MV_SPEDURL", "http://"), 250)
    Local aParam        := {}
    Local nTpMonitor 	:= 1
    Local aRetMonit     := {}
    //Retorno da Função
    Local lDeuCerto     := .F.
    Local cMensagem     := ""
    Local aRetorno      := {.F., ""}

    //Posiciona na Nota (que não tenha chave de acesso ainda)
    Dbselectarea('SF2')
    SF2->(DbSetOrder(1)) // F2_FILIAL + F2_DOC + F2_SERIE + F2_CLIENTE + F2_LOJA + F2_FORMUL + F2_TIPO
    If SF2->(MsSeek(FWxFilial('SF2') + cDocumento + cSerie)) .And. Empty(SF2->F2_CHVNFE)
        cIdEnt := getCfgEntidade(@cError)

        //Se encontrou a entidade
        If ! Empty( cIdEnt )

            //Busca o ambiente, modalidade e versão
            cAmbiente := getCfgAmbiente(@cError, cIdEnt, cModelo)
            If ! Empty(cAmbiente)
                cModalidade := getCfgModalidade(@cError, cIdEnt, cModelo)

                If ! Empty(cModalidade) 
                    cVersao	:= getCfgVersao(@cError, cIdEnt, cModelo)
                EndIf
            EndIf

            //Se conseguiu buscar as informações
            If ! Empty(cVersao)
                //Aciona a transmissão da Nota para o Sefaz
                cRetorno := SpedNFeTrf(;
                    "SF2",;         //cAlias
                    SF2->F2_SERIE,; //cSerie
                    SF2->F2_DOC,;   //cNotaIni
                    SF2->F2_DOC,;   //cNotaFim
                    cIdEnt,;        //cIDEnt
                    cAmbiente,;     //cAmbiente
                    cModalidade,;   //cModalidade
                    cVersao,;       //cVersao
                    @lEnd,;         //lEnd
                    lCte,;          //lCte
                    .T.,;           //lAuto
                    Nil,;           //dDataDe
                    Nil;            //dDataAte
                )

                //Se tiver a mensagem de sucesso, tenta acionar o monitoramento
                If "SUCESSO" $ Upper(cRetorno)

                    //Monta o array de parâmetros para monitorar
                    aParam    := Array(5)
                    aParam[1] := SF2->F2_SERIE
                    aParam[2] := SF2->F2_DOC
                    aParam[3] := SF2->F2_DOC
                    aParam[4] := MonthSub(SF2->F2_EMISSAO, 1)
                    aParam[5] := MonthSum(SF2->F2_EMISSAO, 1)

                    //Tenta monitorar 3 vezes
                    While nVezes < 3
                        aRetMonit := procMonitorDoc(;
                            cIdent,;          //cIdEnt
                            cUrl,;            //cUrl
                            aParam,;          //aParam
                            nTpMonitor,;      //nTpMonitor (1=Range de Notas; 2=Lote de Id;3=Tempo)
                            "0" + cModelo,;   //cModelo
                            lCte,;            //lCte
                            @cError;          //cAviso
                        )

                        //Se teve retorno o monitoramento
                        If Len(aRetMonit) > 0

                            //Se começar com 001, deu certo o monitoramento
                            If Left(Alltrim(aRetMonit[1][9]), 3) == '001'
                                lDeuCerto := .T.
                                cMensagem := "Sucesso na transmissão e monitoramento da Nota!"
                                Exit
                            EndIf
                        EndIf

                        //Aguarda 3 segundos antes da próxima tentativa
                        Sleep(3000)
                        nVezes++
                    EndDo

                    //Se mesmo ao acionar o monitoramento, não der certo, atualiza a variável de retorno
                    If ! lDeuCerto
                        cMensagem := "Falha ao tentar acionar o monitoramento! " + cError
                    EndIf

                Else
                    cMensagem := "Falha na transmissão da Nota! " + cRetorno
                EndIf
            Else
                cMensagem := "Falha ao buscar informações (Ambiente, Modalidade e Versão)! " + cError
            EndIf

        Else
            cMensagem := "Falha ao buscar o IdEnt da Empresa! " + cError
        EndIf

    Else
        cMensagem := "Nota e Série não encontradas na SF2!"
    EndIf

    //Define o retorno
    aRetorno[1] := lDeuCerto
    aRetorno[2] := cMensagem

	FWRestArea(aArea)
Return aRetorno

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

Deixe uma resposta

Terminal de Informação