Página 1 de 4

Classe e função pra carregar XML

Enviado: 25 Jul 2016 18:14
por JoséQuintas
Prefiro meu jeito de trabalhar com XML.
Está do jeito que eu uso, mas precisa melhorar algumas coisas, até mesmo os nomes usados.
Qualquer dia uso também pra gerar XML, e não só pra importar.
Dá até pra fazer assim:

Código: Selecionar todos

oFileList := Directory( "*.xml" )
FOR EACH oFile IN oFileList
   oDoc := XmlToDoc( MemoRead( oFile[ 1 ] ) )
   ? oDoc:cNumDoc, oDoc:DataEmissao, oDoc:Emitente:Nome, oDoc:Destinatario:Nome, oDoc:Totais:ValNot
NEXT

Classe e função pra carregar XML

Enviado: 25 Jul 2016 18:17
por JoséQuintas
A classe com o documento, que pode ser NFE, CTE, CCE. Só variáveis.

Código: Selecionar todos

#include "hbclass.ch"

CREATE CLASS NfeCadastroClass

   VAR  Nome                INIT ""
   VAR  Cnpj                INIT ""
   VAR  InscricaoEstadual   INIT ""
   VAR  InscricaoMunicipal  INIT ""
   VAR  CNAE                INIT ""
   VAR  Endereco            INIT ""
   VAR  Numero              INIT ""
   VAR  Compl               INIT ""
   VAR  Bairro              INIT ""
   VAR  Cidade              INIT ""
   VAR  CidadeIbge          INIT ""
   VAR  Uf                  INIT ""
   VAR  Cep                 INIT ""
   VAR  Pais                INIT ""
   VAR  PaisBACEN           INIT ""
   VAR  Telefone            INIT ""

   END CLASS

CREATE CLASS NfeEnderecoEntregaClass

   VAR  Cnpj        INIT ""
   VAR  Endereco    INIT ""
   VAR  Numero      INIT ""
   VAR  Compl       INIT ""
   VAR  Bairro      INIT ""
   VAR  Cidade      INIT ""
   VAR  CidadeIbge  INIT ""
   VAR  Uf          INIT ""

   END CLASS

CREATE CLASS NfeVolumesClass // From NfeTransporteClass

   VAR  Qtde         INIT 0
   VAR  Especie      INIT ""
   VAR  Marca        INIT ""
   VAR  PesoLiquido  INIT 0
   VAR  PesoBruto    INIT 0
   VAR  Lacres       INIT ""

   END CLASS

CREATE CLASS NfeTransporteClass

   VAR  Nome              INIT ""
   VAR  Cnpj              INIT ""
   VAR  InscricaoEstadual INIT ""
   VAR  Endereco          INIT ""
   VAR  Cidade            INIT ""
   VAR  CidadeIbge        INIT ""
   VAR  Uf                INIT ""
   VAR  Placa             INIT ""
   VAR  PlacaUf           INIT ""
   VAR  Volumes
   METHOD Init()

   END CLASS

METHOD Init() CLASS NfeTransporteClass

   ::Volumes := NfeVolumesClass():New()

   RETURN SELF

CREATE CLASS NfeTotaisClass

   VAR  IcmBas INIT 0
   VAR  IcmVal INIT 0
   VAR  SubBas INIT 0
   VAR  SubVal INIT 0
   VAR  IpiVal INIT 0
   VAR  IIVal  INIT 0
   VAR  IssVal INIT 0
   VAR  PisVal INIT 0
   VAR  CofVal INIT 0
   VAR  ValPro INIT 0
   VAR  ValSeg INIT 0
   VAR  ValFre INIT 0
   VAR  ValOut INIT 0
   VAR  ValNot INIT 0

   END CLASS

CREATE CLASS NfeIIClass

   VAR  Base     INIT 0
   VAR  Aliquota INIT 0
   VAR  Valor    INIT 0

   END CLASS

CREATE CLASS NfeIpiClass

   VAR  Base     INIT 0
   VAR  Aliquota INIT 0
   VAR  Valor    INIT 0

   END CLASS

CREATE CLASS NfeIssClass

   VAR  Base     INIT 0
   VAR  Aliquota INIT 0
   VAR  Valor    INIT 0

   END CLASS

CREATE CLASS NfeIcmsClass

   VAR  Cst      INIT ""
   VAR  Base     INIT 0
   VAR  Reducao  INIT 0
   VAR  Aliquota INIT 0
   VAR  Valor    INIT 0

   END CLASS

CREATE CLASS NfeIcmsStClass

   VAR  Base      INIT 0
   VAR  IVA       INIT 0
   VAR  Reducao   INIT 0
   VAR  Aliquota  INIT 0
   VAR  Valor     INIT 0

   END CLASS

CREATE CLASS NfePisClass

   VAR  Cst      INIT ""
   VAR  Base     INIT 0
   VAR  Aliquota INIT 0
   VAR  Valor    INIT 0

   END CLASS

CREATE CLASS NfeCofinsClass

   VAR  Cst      INIT ""
   VAR  Base     INIT 0
   VAR  Aliquota INIT 0
   VAR  Valor    INIT 0

   END CLASS

CREATE CLASS NfeProdutoClass

   VAR  Codigo        INIT ""
   VAR  Nome          INIT ""
   VAR  CfOp          INIT ""
   VAR  NCM           INIT ""
   VAR  GTIN          INIT ""
   VAR  Anp           INIT ""
   VAR  Unidade       INIT ""
   VAR  Qtde          INIT 0
   VAR  ValorUnitario INIT 0
   VAR  ValorTotal    INIT 0
   VAR  Icms
   VAR  IcmsSt
   VAR  Iss
   VAR  Ipi
   VAR  Pis
   VAR  Cofins
   VAR  II
   METHOD Init()

   END CLASS

METHOD Init() CLASS NfeProdutoClass

   ::Icms   := NfeIcmsClass():New()
   ::IcmsSt := NfeIcmsStClass():New()
   ::Iss    := NfeIssClass():New()
   ::II     := NfeIIClass():New()
   ::Ipi    := NfeIpiClass():New()
   ::Pis    := NfePisClass():New()
   ::Cofins := NfeCofinsClass():New()

   RETURN SELF

CREATE CLASS NfeDuplicataClass

   VAR  Vencimento INIT Ctod("" )
   VAR  Valor      INIT 0

   END CLASS

CREATE CLASS DocSpedClass

   VAR  ChaveAcesso             INIT ""
   VAR  cTipoDoc                INIT "" // 2014.11.20
   VAR  cEvento                 INIT "" // 2014.11.20
   VAR  Protocolo               INIT ""
   VAR  cNumDoc                 INIT ""
   VAR  DataEmissao             INIT Ctod( "" )
   VAR  DataSaida               INIT Ctod( "" )
   VAR  cAmbiente               INIT ""
   VAR  NaturezaOperacao        INIT ""
   VAR  Emitente             // --- init
   VAR  Destinatario         // --- init
   VAR  Remetente            // --- init // CTE
   VAR  EnderecoEntrega      // --- init
   VAR  Produto                 INIT {}
   VAR  Transporte           // --- init
   VAR  Duplicata               INIT {}
   VAR  Totais               // --- init
   VAR  ExportacaoUfEmbarque    INIT ""
   VAR  ExportacaoLocalEmbarque INIT ""
   VAR  InfAdicionais           INIT ""
   VAR  cAssinatura             INIT ""
   VAR  cSequencia              INIT "01" // Carta Correção
   VAR  Valor                   INIT 0  // CTE
   VAR  cERRO                   INIT "" // Texto do erro
   VAR  PesoCarga               INIT 0  // Cte
   VAR  ValorCarga              INIT 0  // Cte
   VAR  Status                  INIT ""
   METHOD Init()

   END CLASS

METHOD Init() CLASS DocSpedClass

   ::Emitente        := NfeCadastroClass():New()
   ::Destinatario    := NfeCadastroClass():New()
   ::Remetente       := NfeCadastroClass():New()
   ::EnderecoEntrega := NfeEnderecoEntregaClass():New()
   ::Transporte      := NfeTransporteClass():New()
   ::Totais          := NfeTotaisClass():New()

   RETURN SELF

Classe e função pra carregar XML

Enviado: 25 Jul 2016 18:21
por JoséQuintas
É tudo usando a XmlNode() que já postei por aqui, e tem na SefazClass.

XmlToDoc() decide como pegar os dados, conforme o tipo de xml, e desvia pra função correspondente.

Código: Selecionar todos

FUNCTION XmlToDoc( cXmlInput )

   LOCAL oDoc

   IF .NOT. ["] $ cXmlInput  // Petrobras usa aspas simples
      cXmlInput := StrTran( cXmlInput, ['], ["] )
   ENDIF
   oDoc := DocSpedClass():New()
   DO CASE
   CASE "<nfeProc"      $ cXmlInput
      oDoc:cTipoDoc := "55"
      oDoc:cEvento  := "110100"
      XmlToDocNfeEmi( cXmlInput, @oDoc )
   CASE "<cteProc" $ cXmlInput
      oDoc:cTipoDoc := "57"
      oDoc:cEvento  := "110100"
      XmlToDocCteEmi( cXmlInput, @oDoc )
   CASE "<mdfeProc" $ cXmlInput
      oDoc:cTipoDoc := "58"
      oDoc:cEvento  := "110100"
      XmlToDocMDFEEmi( cXmlInput, @oDoc )
   CASE "<procEventoNFe" $ cXmlInput .AND. "<descEvento>Cancelamento" $ cXmlInput
      oDoc:cTipoDoc := "55"
      oDoc:cEvento  := "110111"
      XmlToDocNfeCancel( cXmlInput, @oDoc )
   CASE "<procCancNFe" $ cXmlInput .AND. "<xServ>CANCELAR" $ cXmlInput
      oDoc:cTipoDoc := "55"
      oDoc:cEvento  := "110111"
      XmlToDocNFECancel( cXmlInput, @oDoc )
   CASE "<procEventoCTe" $ cXmlInput .AND. "<descEvento>Cancelamento" $ cXmlInput
      oDoc:cTipoDoc := "57"
      oDoc:cEvento  := "110111"
      XmlToDocCTeCancel( cXmlInput, @oDoc )
   CASE "<procEventoNFe" $ cXmlInput .AND. "<descEvento>Carta de Correcao" $ cXmlInput
      oDoc:cTipoDoc := "55"
      oDoc:cEvento  := "110110"
      XmlToDocNfeCCe( cXmlInput, @oDoc )
   CASE "<procEventoMDFe" $ cXmlInput .AND. "<descEvento>Cancelamento" $ cXmlInput
      oDoc:cTipoDoc := "58"
      oDoc:cEvento  := "110111"
      XmlToDocMDFECancel( cXmlInput, @oDoc )
   CASE "<procEventoMDFe" $ cXmlInput .AND. "<descEvento>Encerramento" $ cXmlInput
      oDoc:cTipoDoc := "58"
      oDoc:cEvento  := "110112"
      XmlToDocMDFEEnc( cXmlInput, @oDoc )
   CASE "<infMDFe" $ cXmlInput
      oDoc:cTipoDoc := "58"
      oDoc:cEvento  := "000000"
      XmlToDocMDFEEmi( cXmlInput, @oDoc )
   CASE "<infCte" $ cXmlInput
      oDoc:cTipoDoc := "57"
      oDoc:cEvento  := "000000"
      XmlToDocCteEmi( cXmlInput, @oDoc )
   CASE "<infNFe" $ cXmlInput
      oDoc:cTipoDoc := "55"
      oDoc:cEvento  := "000000"
      XmlToDocNfeEmi( cXmlInput, @oDoc )
   //CASE "<infEvento" $ cXmlInput
   //   // pode ser pra qualquer documento
   //   oDoc:cTipoDoc := "XX"
   //   oDoc:cEvento  := "XX"
   OTHERWISE
      oDoc:cErro := "Documento não identificado"
   ENDCASE
   IF Empty( oDoc:Destinatario:Cnpj ) .AND. Empty( oDoc:Destinatario:Nome )
      oDoc:Destinatario := oDoc:Emitente
   ENDIF
   oDoc:ChaveAcesso := SoNumeros( oDoc:ChaveAcesso )
   DO CASE
   CASE Len( oDoc:cErro ) != 0
   CASE Len( oDoc:ChaveAcesso ) != 44
      oDoc:cErro := "Tamanho da chave de acesso inválido"
   CASE Right( oDoc:ChaveAcesso, 1 ) != CalculaDigito( Substr( oDoc:ChaveAcesso, 1, 43 ), "11" )
      oDoc:cErro := "Dígito da chave de acesso inválido"
   CASE Substr( oDoc:ChaveAcesso, 5, 2 ) < "01" .OR. Substr( oDoc:ChaveAcesso, 5, 2 ) > "12"
      oDoc:cErro := "Mes da chave inválido"
   CASE .NOT. ValidCnpjCpf( Substr( oDoc:ChaveAcesso, 7, 14 ) )
      oDoc:cErro := "CNPJ inválido na chave de acesso"
   CASE Val( oDoc:Protocolo ) == 0
      oDoc:cErro := "Sem protocolo"
   CASE Empty( oDoc:cAssinatura )
      oDoc:cErro := "Sem assinatura"
   CASE oDoc:cAmbiente != "1"
      oDoc:cErro := "Não é ambiente de produção"
   CASE oDoc:cTipoDoc != Substr( oDoc:ChaveAcesso, 21, 2 )
      oDoc:cErro := "Tipo de documento " + Substr( oDoc:ChaveAcesso, 21, 2 )
   CASE oDoc:cEvento = "110100" .AND. Empty( oDoc:cNumDoc )
      oDoc:cErro := "Número de documento vazio"
   ENDCASE
   IF Len( oDoc:cErro ) != 0
      oDoc:cTipoDoc := "XX"
      oDoc:cEvento  := "XXXXXX"
   ENDIF

   RETURN oDoc

Classe e função pra carregar XML

Enviado: 25 Jul 2016 18:24
por JoséQuintas
E a que lê o XML de nota emitida.
Dá-lhe ler um "node" de cada vez, com XmlNode()
O resultado é a nota inteira numa variável, que pode ser usada pra importar o XML, cadastrar cliente, cadastrar produtos, etc.

Código: Selecionar todos

FUNCTION XmlToDocNfeEmi( cXmlInput, oNfe )

   LOCAL nCont
   LOCAL cBlocoInfNfeComTag, cBlocoChave, cBlocoIde, cBlocoInfAdic
   LOCAL cBlocoEmit, cBlocoEndereco, cBlocoDest, cBlocoTransporte, cBlocoTransp, cBlocoVeiculo, cBlocoVol, cBlocoTotal
   LOCAL cBlocoDetalhe, cBlocoItem, cBlocoProd,  cBlocoIpi, cBlocoIcms, cBlocoPis, cBlocoCofins
   LOCAL cBlocoComb, cBlocoCobranca, cBlocoDup

   cBlocoInfNfeComTag := XmlNode( cXmlInput, "infNFe", .T. )

   cBlocoChave := XmlElement( cBlocoInfNfeComTag, "Id" )
   cBlocoChave := Substr( cBlocoChave, 4 )
   cBlocoChave := AllTrim( cBlocoChave )
   IF Len( cBlocoChave ) <> 44
      oNfe:cErro := "Chave de Acesso Inválida"
      RETURN NIL
   ENDIF
   oNfe:ChaveAcesso := cBlocoChave
   oNfe:cAssinatura := XmlNode( cXmlInput, "Signature" )
   cBlocoIde := XmlNode( cXmlInput, "ide" )
      oNfe:cNumDoc := XmlNode( cBlocoIde, "nNF" )
      IF Len( Trim( oNfe:cNumDoc ) ) = 0
         oNfe:cErro := "Sem número de documento"
         RETURN NIL
      ENDIF
      oNfe:cNumDoc := StrZero( Val( oNfe:cNumDoc ), 9 )
      IF .NOT. Empty( XmlDate( XmlNode( cBlocoIde, "dhEmi" ) ) )
         oNfe:DataEmissao := XmlDate( XmlNode( cBlocoIde, "dhEmi" ) )
         oNfe:DataSaida   := XmlDate( XmlNode( cBlocoIde, "dhSaiEnt" ) )
      ELSE
         oNfe:DataEmissao := XmlDate( XmlNode( cBlocoIde, "dEmi" ) )
         oNfe:DataSaida   := XmlDate( XmlNode( cBlocoIde, "dSaiEnt" ) )
      ENDIF
      IF Empty( oNfe:DataSaida )
         oNfe:DataSaida := oNfe:DataEmissao
      ENDIF
      oNfe:cAmbiente := XmlNode( cBlocoIde, "tpAmb" )

   cBlocoInfAdic := XmlNode( cXmlInput, "InfAdic" )
      oNfe:InfAdicionais := XmlNode( cBlocoInfAdic, "InfCpl" )

   cBlocoEmit := XmlNode( cXmlInput, "emit" )
      oNfe:Emitente:Cnpj              := Transform( Substr( oNfe:ChaveAcesso, 7, 14 ), "@R 99.999.999/9999-99" )
      oNfe:Emitente:Nome              := Upper( XmlNode( cBlocoEmit, "xNome" ) )
      oNfe:Emitente:InscricaoEstadual := XmlNode( cBlocoEmit, "IE" )
      cBlocoEndereco := XmlNode( cBlocoEmit, "enderEmit" )
         oNfe:Emitente:Endereco   := Upper( XmlNode( cBlocoEndereco, "xLgr" ) )
         oNfe:Emitente:Numero     := XmlNode( cBlocoEndereco, "nro" )
         oNfe:Emitente:Compl      := XmlNode( cBlocoEndereco, "xCpl" )
         oNfe:Emitente:Bairro     := Upper( XmlNode( cBlocoEndereco, "xBairro" ) )
         oNfe:Emitente:CidadeIbge := XmlNode( cBlocoEndereco, "cMun" )
         oNfe:Emitente:Cidade     := Upper( XmlNode( cBlocoEndereco, "xMun" ) )
         oNfe:Emitente:Uf         := Upper( XmlNode( cBlocoEndereco, "UF" ) )
         oNfe:Emitente:Cep        := Transform( XmlNode( cBlocoEndereco, "CEP" ), "@R 99999-999" )
         oNfe:Emitente:Telefone   := XmlNode( cBlocoEndereco, "fone" )

      cBlocoDest := XmlNode( cXmlInput, "dest" )
      oNfe:Destinatario:Cnpj := Trim( XmlNode( cBlocoDest, "CNPJ" ) )
      IF Len( Trim( oNfe:Destinatario:Cnpj ) ) = 0
         oNfe:Destinatario:Cnpj := XmlNode( cBlocoDest, "CPF" )
         oNfe:Destinatario:Cnpj := Transform( oNfe:Destinatario:Cnpj, "@R 999.999.999-99" )
      ELSE
         oNfe:Destinatario:Cnpj := Transform( oNfe:Destinatario:Cnpj, "@R 99.999.999/9999-99" )
      ENDIF
      oNfe:Destinatario:Nome := Upper( XmlNode( cBlocoDest, "xNome" ) )
      oNfe:Destinatario:InscricaoEstadual := XmlNode( cBlocoDest, "IE" )
      cBlocoEndereco := XmlNode( cBlocoDest, "enderDest" )
         oNfe:Destinatario:Endereco   := Upper( XmlNode( cBlocoEndereco, "xLgr" ) )
         oNfe:Destinatario:Numero     := XmlNode( cBlocoEndereco, "nro" )
         oNfe:Destinatario:Compl      := XmlNode( cBlocoEndereco, "xCpl" )
         oNfe:Destinatario:Bairro     := Upper( XmlNode( cBlocoEndereco, "xBairro" ) )
         oNfe:Destinatario:CidadeIbge := XmlNode( cBlocoEndereco, "cMun" )
         oNfe:Destinatario:Cidade     := Upper( XmlNode( cBlocoEndereco, "xMun" ) )
         oNfe:Destinatario:Uf         := Upper( XmlNode( cBlocoEndereco, "UF" ) )
         oNfe:Destinatario:Cep        := Transform( XmlNode( cBlocoEndereco, "CEP" ), "@R 99999-999" )
         oNfe:Destinatario:Telefone   := XmlNode( cBlocoEndereco, "fone" )

   cBlocoTransporte := XmlNode( cXmlInput, "transp" )
      cBlocoTransp := XmlNode( cBlocoTransporte, "transporta" )
         oNfe:Transporte:Cnpj              := Transform( XmlNode( cBlocoTransp, "CNPJ" ), "@R 99.999.999/9999-99" )
         oNfe:Transporte:Nome              := Upper( XmlNode( cBlocoTransp, "xNome" ) )
         oNfe:Transporte:InscricaoEstadual := XmlNode( cBlocoTransp, "IE" )
         oNfe:Transporte:Endereco          := Upper( XmlNode( cBlocoTransp, "xEnder" ) )
         oNfe:Transporte:Cidade            := Upper( XmlNode( cBlocoTransp, "xMun" ) )
         oNfe:Transporte:Uf                := Upper( XmlNode( cBlocoTransp, "UF" ) )
      cBlocoVol := XmlNode( cBlocoTransporte, "vol" )
         oNfe:Transporte:Volumes:Qtde        := Val( XmlNode( cBlocoVol, "qVol" ) )
         oNfe:Transporte:Volumes:Especie     := Upper( XmlNode( cBlocoVol, "esp" ) )
         oNfe:Transporte:Volumes:Marca       := Upper( XmlNode( cBlocoVol, "marca" ) )
         oNfe:Transporte:Volumes:PesoLiquido := Val( XmlNode( cBlocoVol, "pesoL" ) )
         oNfe:Transporte:Volumes:PesoBruto   := Val( XmlNode( cBlocoVol, "pesoB" ) )
      cBlocoVeiculo := XmlNode( cBlocoTransporte, "veicTransp" )
      oNfe:Transporte:PlacaUf := Upper( XmlNode( cBlocoVeiculo, "UF" ) )
      oNfe:Transporte:Placa   := Upper( XmlNode( cBlocoVeiculo, "placa" ) )

   cBlocoTotal := XmlNode( cXmlInput, "total" )
      oNfe:Totais:IpiVal := Val( XmlNode( cBlocoTotal, "vIPI" ) )
      oNfe:Totais:IIVal  := Val( XmlNode( cBlocoTotal, "vII" ) )
      oNfe:Totais:IcmBas := Val( XmlNode( cBlocoTotal, "vBC" ) )
      oNfe:Totais:IcmVal := Val( XmlNode( cBlocoTotal, "vICMS" ) )
      oNfe:Totais:SubBas := Val( XmlNode( cBlocoTotal, "vBCST" ) )
      oNfe:Totais:SubVal := Val( XmlNode( cBlocoTotal, "vST" ) )
      oNfe:Totais:PisVal := Val( XmlNode( cBlocoTotal, "vPIS" ) )
      oNfe:Totais:CofVal := Val( XmlNode( cBlocoTotal, "vCOFINS" ) )
      oNfe:Totais:ValPro := Val( XmlNode( cBlocoTotal, "vProd" ) )
      oNfe:Totais:ValSeg := Val( XmlNode( cBlocoTotal, "vSeg" ) )
      oNfe:Totais:ValFre := Val( XmlNode( cBlocoTotal, "vFrete" ) )
      oNfe:Totais:ValOut := Val( XmlNode( cBlocoTotal, "vOutro" ) )
      oNfe:Totais:ValNot := Val( XmlNode( cBlocoTotal, "vNF" ) )

   cBlocoDetalhe := ""
   IF "<det" $ cXmlInput
      cBlocoDetalhe := Substr( cXmlInput, At( "<det", cXmlInput ) - 1 )
   ENDIF
   FOR nCont = 1 TO 1000
      cBlocoItem := XmlNode( cBlocoDetalhe, [det nItem="] + LTrim( Str( nCont ) ) + ["])
      IF Len( Trim( cBlocoItem ) ) = 0 // Se acabaram os itens
         EXIT
      ENDIF
      AAdd( oNFE:Produto, NFEProdutoClass():New() )
      cBlocoProd := XmlNode( cBlocoItem, "prod" )
         oNfe:Produto[ nCont ]:Codigo          := XmlNode( cBlocoProd, "cProd" )
         oNfe:Produto[ nCont ]:Nome            := Upper( XmlNode( cBlocoProd, "xProd" ) )
         oNfe:Produto[ nCont ]:CFOP            := Transform( XmlNode( cBlocoProd, "CFOP" ), "@R 9.9999" )
         oNfe:Produto[ nCont ]:NCM             := XmlNode( cBlocoProd, "NCM" )
         oNfe:Produto[ nCont ]:GTIN            := XmlNode( cBlocoProd, "cEAN" )
         oNfe:Produto[ nCont ]:Unidade         := Upper( XmlNode( cBlocoProd, "uCom" ) )
         oNfe:Produto[ nCont ]:Qtde            := Val( XmlNode( cBlocoProd, "qCom" ) )
         oNfe:Produto[ nCont ]:ValorUnitario   := Val( XmlNode( cBlocoProd, "vUnCom" ) )
         oNfe:Produto[ nCont ]:ValorTotal      := Val( XmlNode( cBlocoProd, "vProd" ) )
      cBlocoIpi := XmlNode( cBlocoItem, "IPI" )
         oNfe:Produto[ nCont ]:Ipi:Base        := Val( XmlNode( cBlocoIpi, "vBC" ) )
         oNfe:Produto[ nCont ]:Ipi:Aliquota    := Val( XmlNode( cBlocoIpi, "pIPI" ) )
         oNfe:Produto[ nCont ]:Ipi:Valor       := Val( XmlNode( cBlocoIpi, "vIPI" ) )
      cBlocoIcms := XmlNode( cBlocoItem, "ICMS" )
         oNfe:Produto[ nCont ]:Icms:Cst        := XmlNode( cBlocoIcms, "orig" ) + XmlNode( cBlocoIcms, "CST" )
         oNfe:Produto[ nCont ]:Icms:Base       := Val( XmlNode( cBlocoIcms, "vBC" ) )
         oNfe:Produto[ nCont ]:Icms:Reducao    := Val( XmlNode( cBlocoIcms, "vRedBC" ) )
         oNfe:Produto[ nCont ]:Icms:Aliquota   := Val( XmlNode( cBlocoIcms, "pICMS" ) )
         oNfe:Produto[ nCont ]:Icms:Valor      := Val( XmlNode( cBlocoIcms, "vICMS" ) )
         oNfe:Produto[ nCont ]:IcmsSt:Base     := Val( XmlNode( cBlocoIcms, "vBCST" ) )
         oNfe:Produto[ nCont ]:IcmsSt:Iva      := Val( XmlNode( cBlocoIcms, "pMVAST" ) )
         oNfe:Produto[ nCont ]:IcmsSt:Reducao  := Val( XmlNode( cBlocoIcms, "pRedBCST" ) )
         oNfe:Produto[ nCont ]:IcmsSt:Aliquota := Val( XmlNode( cBlocoIcms, "pICMSST" ) )
         oNfe:Produto[ nCont ]:IcmsSt:Valor    := Val( XmlNode( cBlocoIcms, "vICMSST" ) )
      cBlocoPis := XmlNode( cBlocoItem, "PIS" )
         oNfe:Produto[ nCont ]:Pis:Cst         := XmlNode( cBlocoPis, "CST" )
         oNfe:Produto[ nCont ]:Pis:Base        := Val( XmlNode( cBlocoPis, "vBC" ) )
         oNfe:Produto[ nCont ]:Pis:Aliquota    := Val( XmlNode( cBlocoPis, "pPIS" ) )
         oNfe:Produto[ nCont ]:Pis:Valor       := Val( XmlNode( cBlocoPis, "vPIS" ) )
      cBlocoCofins := XmlNode( cBlocoItem, "COFINS" )
         oNfe:Produto[ nCont ]:Cofins:Cst      := XmlNode( cBlocoCofins, "CST" )
         oNfe:Produto[ nCont ]:Cofins:Base     := Val( XmlNode( cBlocoCofins, "vBC" ) )
         oNfe:Produto[ nCont ]:Cofins:Aliquota := Val( XmlNode( cBlocoCofins, "pCOFINS" ) )
         oNfe:Produto[ nCont ]:Cofins:Valor    := Val( XmlNode( cBlocoCofins, "vCOFINS" ) )
      cBlocoComb := XmlNode( cBlocoItem, "comb" )
         oNfe:Produto[ nCont ]:Anp             := XmlNode( cBlocoComb, "cProdANP" )
      cBlocoDetalhe := Substr( cBlocoDetalhe, At( "</det", cBlocoDetalhe ) + 4 )
   NEXT

   cBlocoCobranca := XmlNode( cXmlInput, "cobr" )
   FOR nCont = 1 TO 500
      cBlocoDup := XmlNode( cBlocoCobranca, "dup" )
      IF Len( Trim( cBlocoDup ) ) = 0
         EXIT
      ENDIF
      AAdd( oNfe:Duplicata, NFEDuplicataClass():New() )
      oNfe:Duplicata[ nCont ]:Vencimento := XmlDate( XmlNode( cBlocoDup, "dVenc" ) )
      oNfe:Duplicata[ nCont ]:Valor      := Val( XmlNode( cBlocoDup, "vDup" ) )
      cBlocoCobranca := Substr( cBlocoCobranca, At( "</dup>", cBlocoCobranca ) + 3 )
   NEXT
   oNfe:Protocolo := XmlNode( cXmlInput, "nProt" )
   oNFE:Status    := XmlNode( cXmlInput, "cStat" )

   RETURN NIL

Classe e função pra carregar XML

Enviado: 25 Jul 2016 18:33
por JoséQuintas
Depois é só acessar a variável.

Código: Selecionar todos

? oDoc:Emitente:Nome
IF .NOT. Encontra( oDoc:Destinatario:Cnpj, "clientes", "porcnpj" )
   SELECT clientes
   APPEND BLANK
   REPLACE ;
      clientes->Nome WITH oDoc:Destinatario:Nome, ;
      clientes->Cnpj  WITH oDoc:Destinatario:Cnpj
ENDIF
  
FOR EACH oProduto IN ( oDoc:Produto )
   IF .NOT. Encontra( oProduto:Codigo, "produtos", "porcodigo" )
      SELECT produtos
      APPEND BLANK
      REPLACE ;
      produtos->Codigo WITH oProduto:Codigo, ;
      produtos->Nome WITH oProduto:Nome
   ENDIF
   IF .NOT. Encontra( oProduto:cNumDoc + oProduto:Codigo, "estoque", "docprod" )
      SELECT estoque
      APPEND BLANK
      REPLACE ;
         estoque->Produto WITH oProduto:Codigo, ;
        estoque->Qtde WITH oProduto:Qtde, ;
      estoque->ValorUnitario WITH oProduto:ValorUnitario, ;
   estoque->ValorTotal WITH oProduto:ValorTotal
NEXT

IF .NOT. Encontra( oDoc:cNumDoc, "notas", "numnf" )
   SELECT notas
   APPEND BLANK
   REPLACE ;
      notas->Numero WITH oDoc:cNumDoc, ;
      notas->DatEmi WITH oDoc:DataEmissao, ;
      notas->Valor  WITH oDoc:ValNot
ENDIF

Classe e função pra carregar XML

Enviado: 25 Jul 2016 18:42
por JoséQuintas
Tudo no bom e tradicional modo Clipper, exceto que depois alterei pros dados da nota ficarem numa classe.
Uso desde os tempos do Clipper a leitura do XML assim.

Pensei em utilizar a classe pro caminho inverso:
O aplicativo alimentar as variáveis, e gerar o XML a partir dessa nota.
Também poderia acrescentar validações extras, pra confirmar se tem preenchimento inválido.

Comentário:
<produto>sssss</produto>

Sö usar At() pra encontrar aonde tem <produto> e </produto> e pegar o que está entre eles, usando Substr().
Nada extraordinário, ou classes de XML que só complicam.

E com o tempo, ir melhorando conforme o que for acontecendo.
Qualquer um consegue fazer.
Mas a mania de achar que XML é de coisa outro planeta, acabam recorrendo a classes complicadas pra trabalhar com XML, geralmente classes que são muito mais complicadas que o próprio XML.
XML é um texto, e todo mundo sabe trabalhar com textos.

Classe e função pra carregar XML

Enviado: 30 Jul 2016 14:30
por gilbertosilverio
Ola Jose Quintas,

Baseado neste teu exemplo, tentei ler um arquivo de retorno em xml, mais o retorno e nulo.

Por favor, o que estou fazendo errado ao tentar ler este xml.

Código: Selecionar todos

<retConsCad versao="2.00">
<infCons>
 <verAplic>SP_NFE_PL_008i2</verAplic>
 <cStat>111</cStat>
 <xMotivo>Consulta cadastro com uma ocorrência</xMotivo>
 <UF>SP</UF>
 <CNPJ>47160031000173</CNPJ>
 <dhCons>2016-07-30T10:36:04-03:00</dhCons>
 <cUF>35</cUF>
<infCad>
 <IE>635063157119</IE>
 <CNPJ>47160031000173</CNPJ>
 <UF>SP</UF>
 <cSit>1</cSit>
 <indCredNFe>1</indCredNFe>
 <indCredCTe>4</indCredCTe>
 <xNome>DROGARIA TEM LTDA - EPP</xNome>
 <xRegApur>NORMAL - REGIME PERIÓDICO DE APURAÇÃO</xRegApur>
 <CNAE>4771701</CNAE>
 <dIniAtiv>1975-07-01</dIniAtiv>
 <dUltSit>1975-07-01</dUltSit>
<ender>
 <xLgr>RUA CRISTIANO ANGELI</xLgr>
 <nro>30</nro>
 <xBairro>ASSUNCAO</xBairro>
 <cMun>3548708</cMun>
 <xMun>SAO BERNARDO DO CAMPO</xMun>
 <CEP>09810555</CEP>
 </ender>
 </infCad>
 </infCons>
 </retConsCad>

Código: Selecionar todos

FUNCTION LER_CONSULTA_CADASTRO()
   LOCAL aIE, aCnpj, aUF, acSit, aNome, aRegime, aEndereco, aNumero, aBairro, aCidadeIbge, aCidade, aCep
   PRIVATE cBloco_infCad, cBlocoEndere, cBloco_infCons
   PRIVATE cXmlInput:=[D:\Cnpj_47160031000173-ret-cons-cad.xml]

   cBloco_infCons := XmlNode( cXmlInput, "infCons", .t. )

   cBloco_infCad  := XmlNode( cBloco_infCons , "infCad", .t. )
      aIE         := Upper( XmlNode( cBloco_infCad,     "IE"   ) )
      aCnpj       := Transform( XmlNode( cBloco_infCad, "CNPJ" ), "@R 99.999.999/9999-99" )
      aUF         := Upper( XmlNode( cBloco_infCad,     "UF"   ) )
      acSit       := Upper( XmlNode( cBloco_infCad,     "cSit" ) )
      aNome       := Upper( XmlNode( cBloco_infCad,     "xNome" ) )
      aRegime     := Upper( XmlNode( cBloco_infCad,     "xRegApur" ) )

      cBlocoEndereco   := XmlNode( cBloco_infCad,         "ender"   ) // pesquisa o

         aEndereco     := Upper( XmlNode( cBlocoEndereco, "xLgr"    ) )
         aNumero       := XmlNode( cBlocoEndereco,        "nro"     )
         aBairro       := Upper( XmlNode( cBlocoEndereco, "xBairro" ) )
         aCidadeIbge   := XmlNode( cBlocoEndereco,        "cMun"    )
         aCidade       := Upper( XmlNode( cBlocoEndereco, "xMun"    ) )
         aCep          := Transform( XmlNode( cBlocoEndereco, "CEP" ), "@R 99999-999" )

   HWG_MSGINFO( aIE+CRLF+aCNPJ+CRLF+ aUF+CRLF+ aNOME+CRLF+ aENDERECO+CRLF+ aCEP ,[Olha o que voltou])

RETURN NIL

Grato.

Classe e função pra carregar XML

Enviado: 30 Jul 2016 16:22
por gilbertosilverio
Ola Jose,

Esquece, ja achei meu erro, esqueci de abrir o arquivo como MEMOREAD()...

Muito pratico este teu exemplo.

Grato.

Classe e função pra carregar XML

Enviado: 30 Jul 2016 17:36
por JoséQuintas
Deixei como parte do projeto.
Fazem anos que penso em mexer nesses nomes internos, mas sempre deixo pra depois... rs

https://github.com/JoseQuintas/sefazclass

Isso que postei está em ze_SpedXmlClass.prg

Uso pra importar XMLs de fornecedores.

Em um determinado cliente, uso pra importar TODOS os XMLs, até os próprios.
O dono não quer abrir mão do aplicativo de notas que fez, então importo toda informação dos XMLs pra gerar arquivos pro governo.

Classe e função pra carregar XML

Enviado: 30 Jul 2016 19:58
por fladimir
Legal José, parabéns... Talvez essa ideia pode ser usada pelo Toledo ou outros colegas q estão trabalhando em baixar o XML sem o certificado e ler o HTML e montar o XML correto?

Classe e função pra carregar XML

Enviado: 30 Jul 2016 22:42
por JoséQuintas
Há pouco tempo vi na hbnfe que a impressão da Danfe usa algo assim, mas usando variáveis HASH.

E tem um componente de NFE, acho que é o flexdocs, que tem uma classe nesse estilo pra gerar o XML, que alguns usam por acharem mais fácil desse jeito. (a classe com as informações da NFE).

O que comentei em outro tópico foi sobre isso: pegar essa classe, ou uma nova, e utilizá-la pra tudo.
É apenas uma classe com variáves da NFE, com toda informação, então:
- Daria pra preencher o conteúdo, e gerar TXT ou XML ou ACBR ou outro
- Daria pra usar pra emitir o Danfe
- Daria pra juntar todas as validações que nós temos, e aplicar na informação da classe: validar NCM, CFOP, CST, regras fiscais, regras da NFE, regras do governo, etc. etc. etc. ficando padrão pra todo mundo, e pra qualquer aplicativo, o que permitirá mais colaboração nessas checagens.
- Daria pra usar ANTES de emitir a nota, pra toda validação

Seria facilidade pra todos, porque não dependeria de formato de base de dados, ou outra coisa.
E muitas vezes a gente não tem tempo de conferir tudo isso, então mais gente usando acabaria nos ajudando, de uma forma ou de outra.
É só uma idéia, pelo menos por enquanto.

Classe e função pra carregar XML

Enviado: 06 Set 2016 19:47
por NiltonGM
José,

Na linha 70 do XmlToDoc() não poderia ficar assim?
CASE Len( oDoc:cErro ) != 0
oDoc:cTipoDoc := "XX"
oDoc:cEvento := "XXXXXX"
CASE Len( oDoc:ChaveAcesso ) != 44
...
e eliminar o if após o END CASE na linha 90
IF Len( oDoc:cErro ) != 0
oDoc:cTipoDoc := "XX"
oDoc:cEvento := "XXXXXX"
ENDIF
Ou tem algum problema q não estou enxergando?
Tentei adaptar suas funções mas estavam faltando as funções:
XMLNODE(), XMLELEMENT() e XMLDATE(), a xmlNode achei num post seu no forum mas ademais não achei, onde vc postou pois elas não fazem parte de alguma biblioteca do Harbour.
Por favor aguardo sua ajuda pois estou no meio de uma aplicação e preciso ler XML de NFes e achei suas rotinas muito boas.
Obrigado.

Classe e função pra carregar XML

Enviado: 06 Set 2016 23:10
por JoséQuintas
As outras rotinas podem preencher o oDoc:cErro com outro erro específico.
Se remover a linha em questão, o texto pode acabar sendo removido e trocado por outro.

A rotina atualizada, com as outras funções, está em SefazClass.

https://github.com/JoseQuintas/sefazclass

Classe e função pra carregar XML

Enviado: 07 Set 2016 21:29
por lugab
Pessoal, help.

Aproveito o tema desse tópico do Quintas, pra tirar essa dúvida:

Que programa externo (ou até mesmo um fonte interno) eu devo usar para exibir um arquivo XML (uma nfe)
na tela do meu programa clipper compilado com xHarbour + Hwgui + Gtwvw ?

Tenho visto aqui no forum só contribuições para recuperar os campos dos XML

Grato

Classe e função pra carregar XML

Enviado: 08 Set 2016 11:07
por NiltonGM
Obrigado Zeh, valeu mesmo, vou adaptar as minhas rotinas.