Ejemplo n.º 1
0
    def autorizacao(self, modelo, nota_fiscal, id_lote=1, ind_sinc=1):
        """
        Método para realizar autorização da nota de acordo com o modelo
        :param modelo: Modelo
        :param nota_fiscal: XML assinado
        :param id_lote: Id do lote - numero autoincremental gerado pelo sistema
        :param ind_sinc: Indicador de sincrono e assincrono, 0 para assincrono, 1 para sincrono
        :return:  Uma tupla que em caso de sucesso, retorna xml com nfe e protocolo de autorização. Caso contrário,
        envia todo o soap de resposta da Sefaz para decisão do usuário.
        """
        # url do serviço
        url = self._get_url(modelo=modelo, consulta='AUTORIZACAO')

        # Monta XML do corpo da requisição
        raiz = etree.Element('enviNFe', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO)
        etree.SubElement(raiz, 'idLote').text = str(id_lote)  # numero autoincremental gerado pelo sistema
        etree.SubElement(raiz, 'indSinc').text = str(ind_sinc)  # 0 para assincrono, 1 para sincrono
        raiz.append(nota_fiscal)

        # Monta XML para envio da requisição
        xml = self._construir_xml_soap('NFeAutorizacao4', raiz)
        # Faz request no Servidor da Sefaz
        retorno = self._post(url, xml)

        # Em caso de sucesso, retorna xml com nfe e protocolo de autorização.
        # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário.
        if retorno.status_code == 200:
            if ind_sinc == 1:
                # Procuta status no xml
                ns = {'ns': 'http://www.portalfiscal.inf.br/nfe'}  # namespace
                try:
                    prot = etree.fromstring(retorno.text)
                except ValueError:
                    # em SP retorno.text apresenta erro
                    prot = etree.fromstring(retorno.content)
                try:
                    # Protocolo com envio OK
                    inf_prot = prot[1][0][0][6]                             # root protNFe
                    status = inf_prot.xpath("ns:infProt/ns:cStat", namespaces=ns)[0].text
                except IndexError:
                    # Protocolo com algum erro no Envio
                    ret_envi = prot[1][0][0]                             # root retEnvi
                    status = ret_envi.xpath("ns:cStat", namespaces=ns)[0].text
                if status == '100':
                    raiz = etree.Element('nfeProc', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO)
                    raiz.append(nota_fiscal)
                    raiz.append(inf_prot)
                    return 0, raiz
            else:
                # Retorna id do protocolo para posterior consulta em caso de sucesso.
                ns = {'ns': 'http://www.portalfiscal.inf.br/nfe'}    # namespace
                rec = etree.fromstring(retorno.text)
                rec = rec[1][0][0]
                status = rec.xpath("ns:cStat", namespaces=ns)[0].text
                # Lote Recebido com Sucesso!
                if status == '103':
                    nrec = rec.xpath("ns:infRec/ns:nRec", namespaces=ns)[0].text
                    return 0, nrec, nota_fiscal
        return 1, retorno, nota_fiscal
Ejemplo n.º 2
0
    def autorizacao(self, modelo, nota_fiscal, idlote=1, indSinc=1):
        # url do serviço
        url = self._get_url(modelo=modelo, consulta='AUTORIZACAO')
        # Monta XML do corpo da requisição
        raiz = etree.Element('enviNFe', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO)
        etree.SubElement(raiz, 'idLote').text = str(idlote) # numero autoincremental gerado pelo sistema
        etree.SubElement(raiz, 'indSinc').text = str(indSinc) # 0 para assincrono, 1 para sincrono
        raiz.append(nota_fiscal)
        # Monta XML para envio da requisição
        xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='NfeAutorizacao'), metodo='NfeAutorizacao', dados=raiz)
        # Faz request no Servidor da Sefaz
        retorno = self._post(url, xml)

        # Em caso de sucesso, retorna xml com nfe e protocolo de autorização.
        # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário.
        if retorno.status_code == 200:
            if indSinc == 1:
                # Procuta status no xml
                ns = {'ns':'http://www.portalfiscal.inf.br/nfe'}    # namespace
                try:
                    prot = etree.fromstring(retorno.text)
                except ValueError:
                    #em SP retorno.text apresenta erro
                    prot = etree.fromstring(retorno.content)
                try:
                    # Protocolo com envio OK
                    infProt = prot[1][0][0][6]                             # root protNFe
                    status = infProt.xpath("ns:infProt/ns:cStat", namespaces=ns)[0].text
                except IndexError:
                    # Protocolo com algum erro no Envio
                    retEnvi = prot[1][0][0]                             # root retEnvi
                    status = retEnvi.xpath("ns:cStat", namespaces=ns)[0].text
                if status == '100':
                    raiz = etree.Element('nfeProc', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO)
                    raiz.append(nota_fiscal)
                    raiz.append(infProt)
                    return 0, raiz
            else:
                # Retorna id do protocolo para posterior consulta em caso de sucesso.
                ns = {'ns':'http://www.portalfiscal.inf.br/nfe'}    # namespace
                rec = etree.fromstring(retorno.text)
                rec = rec[1][0][0]
                status = rec.xpath("ns:cStat", namespaces=ns)[0].text
                # Lote Recebido com Sucesso!
                if status == '103':
                    nrec = rec.xpath("ns:infRec/ns:nRec", namespaces=ns)[0].text
                    return 0, nrec, nota_fiscal
        return 1, retorno, nota_fiscal
Ejemplo n.º 3
0
    def assinar(self, xml, retorna_string=False):
        # busca tag que tem id(reference_uri), logo nao importa se tem namespace
        reference = xml.find(".//*[@Id]").attrib['Id']

        # retira acentos
        xml_str = remover_acentos(
            etree.tostring(xml, encoding="unicode", pretty_print=False))
        xml = etree.fromstring(xml_str)

        signer = XMLSigner(
            method=signxml.methods.enveloped,
            signature_algorithm="rsa-sha1",
            digest_algorithm='sha1',
            c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')

        ns = {None: signer.namespaces['ds']}
        signer.namespaces = ns

        ref_uri = ('#%s' % reference) if reference else None
        signed_root = signer.sign(xml,
                                  key=self.key,
                                  cert=self.cert,
                                  reference_uri=ref_uri)

        ns = {'ns': NAMESPACE_SIG}
        # coloca o certificado na tag X509Data/X509Certificate
        tagX509Data = signed_root.find('.//ns:X509Data', namespaces=ns)
        etree.SubElement(tagX509Data, 'X509Certificate').text = self.cert
        if retorna_string:
            return etree.tostring(signed_root,
                                  encoding="unicode",
                                  pretty_print=False)
        else:
            return signed_root
Ejemplo n.º 4
0
    def assinar(self, xml, retorna_string=False):
        # busca tag que tem id(reference_uri), logo nao importa se tem namespace
        reference = xml.find(".//*[@Id]").attrib['Id']
        #print('Referencia: ',reference)
        # retira acentos
        xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
        xml = etree.fromstring(xml_str)

        signer = XMLSigner(
            method=signxml.methods.enveloped, signature_algorithm="rsa-sha1",
            digest_algorithm='sha1',
            c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')

        ns = {None: signer.namespaces['ds']}
        signer.namespaces = ns
        #print('Chave......: ',self.key)
        #print('*',200)
        #print('Certificado: ',self.cert)
        ref_uri = ('#%s' % reference) if reference else None
        signed_root = signer.sign(
            xml, key=self.key, cert=self.cert, reference_uri=ref_uri)

        ns = {'ns': NAMESPACE_SIG}
        # coloca o certificado na tag X509Data/X509Certificate
        tagX509Data = signed_root.find('.//ns:X509Data', namespaces=ns)
        etree.SubElement(tagX509Data, 'X509Certificate').text = self.cert
        #print('Assinatura: ',etree.tostring(signed_root, encoding="unicode", pretty_print=False) )
        if retorna_string:
            return etree.tostring(signed_root, encoding="unicode", pretty_print=False)
        else:
            return signed_root
Ejemplo n.º 5
0
    def assinarNfse(self, xml, retorna_string=True):
        "Assina NFS-e"
        try:
            # define variaveis de acordo com autorizador
            if self.autorizador == 'ginfes':
                xpath = './/ns2:InfRps'
                tag = 'InfRps'
            elif self.autorizador == 'betha':
                xpath = './/ns1:InfDeclaracaoPrestacaoServico'
                tag = 'InfDeclaracaoPrestacaoServico'
            else:
                raise Exception('Autorizador não encontrado!')

            xml = etree.fromstring(xml)
            # define namespaces, pega do proprio xml
            namespaces = xml.nsmap
            # No raiz do XML de saida
            raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Tenta achar a tag
            ref = etree.SubElement(siginfo, 'Reference', URI='#' +
                                   xml.xpath(xpath, namespaces=namespaces)[0].attrib['Id'])
            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            rps = xml.xpath(xpath+'/..', namespaces=namespaces)[0]
            rps.append(raiz)

            # Escreve no arquivo depois de remover caracteres especiais e parse string
            with open('nfse.xml', 'w') as arquivo:
                texto = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
                # se for tag do Betha
                if tag == 'InfDeclaracaoPrestacaoServico':
                    texto = texto.replace('ns1:', '').replace(':ns1', '')
                arquivo.write(texto)

            subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado,
                             '--pwd', self.senha, '--crypto', 'openssl', '--output',
                             'nfse.xml', '--id-attr:Id', tag, 'nfse.xml'])

            if retorna_string:
                return open('nfse.xml', 'r').read()
            else:
                return etree.parse('nfse.xml').getroot()
        except Exception as e:
            raise e
Ejemplo n.º 6
0
    def assinarCancelar(self, xml, retorna_string=True):
        """ Método que assina o xml para cancelamento de NFS-e """
        try:
            if self.autorizador == 'ginfes':
                xpath = 'CancelarNfseEnvio'
                tag = 'CancelarNfseEnvio'
                namespaces = {'ns1': 'http://www.ginfes.com.br/servico_cancelar_nfse_envio', 'ns2':'http://www.ginfes.com.br/tipos'}
            elif self.autorizador == 'betha':
                xpath = '/CancelarNfseEnvio/ns1:Pedido'
                tag = 'InfPedidoCancelamento'
                namespaces = {'ns1': 'http://www.betha.com.br/e-nota-contribuinte-ws'}
            else:
                raise Exception('Autorizador não encontrado!')

            xml = etree.fromstring(xml)
            # No raiz do XML de saida
            raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Tenta achar a tag informada no xpath
            if tag == 'InfPedidoCancelamento':
                ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.xpath('.//ns1:'+tag, namespaces=namespaces)[0].attrib['Id'])
            # ginfes não tem id no cancelamento v2
            else:
                ref = etree.SubElement(siginfo, 'Reference', URI='')
            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            if tag == 'InfPedidoCancelamento':
                xml = xml.xpath(xpath, namespaces=namespaces)[0]
            # ginfes só possui a tag root
            else:
               xml.append(raiz)

            # Escreve no arquivo depois de remover caracteres especiais e parse string
            with open('nfse.xml', 'w') as arquivo:
                arquivo.write(remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n','')))

            subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml'])

            if retorna_string:
                return open('funfa.xml', 'r').read()
            else:
                return etree.parse('funfa.xml').getroot()
        except Exception as e:
            raise e
Ejemplo n.º 7
0
    def assinarLote(self, xml, retorna_string=True):
        "Assina nfse e lote"
        try:
            xml = self.assinarNfse(xml, retorna_string=False)
            xpath = './/ns1:LoteRps'
            tag = 'LoteRps'
            # define namespaces, pega do proprio xml
            namespaces = xml.nsmap
            # No raiz do XML de saida
            raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Tenta achar a tag
            ref = etree.SubElement(siginfo, 'Reference', URI='#' +
                                   xml.xpath(xpath, namespaces=namespaces)[0].attrib['Id'])
            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            # posiciona tag Signature antes do LoteRps para assinar
            base = xml.xpath(xpath+'/..', namespaces=namespaces)[0]
            base.insert(0, raiz)

            # Escreve no arquivo depois de remover caracteres especiais
            with open('nfse.xml', 'w') as arquivo:
                texto = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
                arquivo.write(texto)
            # assina lote
            subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado,
                             '--pwd', self.senha, '--crypto', 'openssl', '--output',
                             'nfse.xml', '--id-attr:Id', tag, 'nfse.xml'])

            # Reposiciona tag Signature apos LoteRps
            xml = etree.fromstring(open('nfse.xml', 'r').read())
            namespaces = xml.nsmap
            sig = xml.find('{http://www.w3.org/2000/09/xmldsig#}Signature')
            sig.getparent().remove(sig)
            xml.append(sig)

            if retorna_string:
                return etree.tostring(xml, encoding="unicode", pretty_print=False)
            else:
                return xml
        except Exception as e:
            raise e
Ejemplo n.º 8
0
    def _post_soap(self, classe, ws_metodo, raiz_xml, str_xml=False):
        url, webservice, metodo = self._get_url_webservice_metodo(ws_metodo)
        if not str_xml:
            xml = self._construir_xml_soap(webservice,
                                           self._construir_etree_ds(raiz_xml))
        else:
            etree_ds = self._construir_etree_ds(raiz_xml)
            etree_ds.append(etree.fromstring(str_xml))
            xml = self._construir_xml_soap(webservice, etree_ds)

        retorno = self._post(url,
                             xml,
                             soap_webservice_method=webservice + b'/' + metodo)
        return analisar_retorno(ws_metodo, retorno, classe)
Ejemplo n.º 9
0
def analisar_retorno(webservice, retorno, classe_resposta):

    # retorno.raise_for_status()
    # print(retorno.text)

    match = re.search('<soap:Body>(.*?)</soap:Body>', retorno.text)

    if match:
        resultado = etree.tostring(etree.fromstring(match.group(1))[0])
        # classe_resposta.Validate_simpletypes_ = False
        # resposta = classe_resposta.parseString(resultado)
        resposta = resultado
        # resposta = retorno.text

    return RetornoSoap(webservice, retorno, resposta)
Ejemplo n.º 10
0
    def consulta_nota_assinada(self, xml, modelo, chave_assinatura):
        """
            Este método oferece a consulta da situação da NF-e/NFC-e na Base de Dados do Portal
            da Secretaria de Fazenda Estadual.
        :param xml: XML da nota
        :param modelo: Modelo da nota
        :param chave_assinatura: Tupla (certificado, chave) A3
        :return:
        """

        if type(xml) == str:
            xml = etree.fromstring(xml)

        # url do serviço
        url = self._get_url(modelo=modelo, consulta='CHAVE')

        return self._post(url, xml, chave_assinatura)
Ejemplo n.º 11
0
    def _assinar(self, xml, tag, retorna_string=True):
        """ Método para assinar xml de NFS-e com tags sem ID
            Consulta de Lote e Consulta por RPS
            @param tag - raiz do xml que será assinado
        """
        try:
            xml = etree.fromstring(xml)
            # No raiz do XML de saida
            raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Consulta nao tem id
            ref = etree.SubElement(siginfo, 'Reference', URI='')

            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            xml.append(raiz)

            # Escreve no arquivo depois de remover caracteres especiais e parse string
            with open('nfse.xml', 'w') as arquivo:
                arquivo.write(remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n','')))

            subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml'])
            xml = etree.parse('funfa.xml').getroot()

            if retorna_string:
                return etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n','')
            else:
                return xml
        except Exception as e:
            raise e
Ejemplo n.º 12
0
    def assinarConsulta(self, xml, retorna_string=True):
        try:
            xml = etree.fromstring(xml)
            # No raiz do XML de saida
            tag = 'ns1:ConsultarNfseEnvio'  # tag que será assinada
            raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Consulta nao tem id
            ref = etree.SubElement(siginfo, 'Reference', URI='')

            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            consulta = xml.xpath('/ns1:ConsultarNfseEnvio', namespaces={'ns1': 'http://www.ginfes.com.br/servico_consultar_nfse_envio_v03.xsd', 'ns2':'http://www.ginfes.com.br/tipos_v03.xsd'})[0]
            consulta.append(raiz)

            # Escreve no arquivo depois de remover caracteres especiais e parse string
            with open('nfse.xml', 'w') as arquivo:
                arquivo.write(remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n','')))

            subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml'])
            xml = etree.parse('funfa.xml').getroot()

            if retorna_string:
                return etree.tostring(xml, encoding="unicode", pretty_print=False)
            else:
                return xml
        except Exception as e:
            raise e
Ejemplo n.º 13
0
    def assinarLote(self, xml, retorna_string=True):
        "Assina nfse e lote"
        try:
            xml = self.assinarNfse(xml, retorna_string=False)
            xpath = './/ns1:LoteRps'
            tag = 'LoteRps'
            # define namespaces, pega do proprio xml
            namespaces = xml.nsmap
            # No raiz do XML de saida
            raiz = etree.Element('Signature',
                                 xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(
                siginfo,
                'CanonicalizationMethod',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                siginfo,
                'SignatureMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Tenta achar a tag
            ref = etree.SubElement(
                siginfo,
                'Reference',
                URI='#' +
                xml.xpath(xpath, namespaces=namespaces)[0].attrib['Id'])
            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm=
                'http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                ref,
                'DigestMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            # posiciona tag Signature antes do LoteRps para assinar
            base = xml.xpath(xpath + '/..', namespaces=namespaces)[0]
            base.insert(0, raiz)

            # Escreve no arquivo depois de remover caracteres especiais
            with open('nfse.xml', 'w') as arquivo:
                texto = remover_acentos(
                    etree.tostring(xml, encoding="unicode",
                                   pretty_print=False))
                arquivo.write(texto)
            # assina lote
            subprocess.check_call([
                'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd',
                self.senha, '--crypto', 'openssl', '--output', 'nfse.xml',
                '--id-attr:Id', tag, 'nfse.xml'
            ])

            # Reposiciona tag Signature apos LoteRps
            xml = etree.fromstring(open('nfse.xml', 'r').read())
            namespaces = xml.nsmap
            sig = xml.find('{http://www.w3.org/2000/09/xmldsig#}Signature')
            sig.getparent().remove(sig)
            xml.append(sig)

            if retorna_string:
                return etree.tostring(xml,
                                      encoding="unicode",
                                      pretty_print=False)
            else:
                return xml
        except Exception as e:
            raise e
Ejemplo n.º 14
0
    def gerar_qrcode(self, token, csc, xml, return_qr=False, online=True):
        """ Classe para gerar url do qrcode da NFC-e """
        # Procura atributos no xml
        ns = {'ns':NAMESPACE_NFE}
        sig = {'sig':NAMESPACE_SIG}
        # Tag Raiz NFe Ex: <NFe>
        nfe = xml
        chave = nfe[0].attrib['Id'].replace('NFe','')
        data = nfe.xpath('ns:infNFe/ns:ide/ns:dhEmi/text()', namespaces=ns)[0].encode()
        tpamb = nfe.xpath('ns:infNFe/ns:ide/ns:tpAmb/text()', namespaces=ns)[0]
        cuf = nfe.xpath('ns:infNFe/ns:ide/ns:cUF/text()', namespaces=ns)[0]
        uf = [key for key, value in CODIGOS_ESTADOS.items() if value == cuf][0]

        # tenta encontrar a tag cpf
        try:
            cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CPF/text()', namespaces=ns)[0]
        except IndexError:
            # em caso de erro tenta procurar a tag cnpj
            try:
                cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CNPJ/text()', namespaces=ns)[0]
            except IndexError:
                cpf = None
        total = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vNF/text()', namespaces=ns)[0]
        # icms = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vICMS/text()', namespaces=ns)[0]
        digest = nfe.xpath('sig:Signature/sig:SignedInfo/sig:Reference/sig:DigestValue/text()', namespaces=sig)[0].encode()

        lista_dia = re.findall("-\d{2}", str(data))
        dia = str(lista_dia[1])
        dia = dia[1:]
        replacements = {'0': ''}
        token = re.sub('([0])', lambda m: replacements[m.group()], token)

        #VERSAO_QRCODE =2
        if online:
            #versão online
            url = '{}|{}|{}|{}'.format(chave,VERSAO_QRCODE, tpamb, token)
        else:
            #versão offline
            digest = digest.lower()
            digest = digest.hex()

            url = '{}|{}|{}|{}|{}|{}|{}'.format(
                chave,VERSAO_QRCODE,tpamb,dia,total,digest,token
                )

        url_complementar = url + csc
        url_hash = hashlib.sha1(url_complementar.encode()).digest()
        url_hash = base64.b16encode(url_hash).decode()

        url = 'p={}|{}'.format(url, url_hash)

        # url_chave - Texto com a URL de consulta por chave de acesso a ser impressa no DANFE NFC-e.
        # Informar a URL da “Consulta por chave de acesso da NFC-e”.
        # A mesma URL que deve estar informada no DANFE NFC-e para consulta por chave de acesso
        lista_uf_padrao = ['PR', 'CE', 'RS', 'RJ', 'RO', 'DF']
        if uf.upper() in lista_uf_padrao:
            qrcode = NFCE[uf.upper()]['QR'] + url
            url_chave = NFCE[uf.upper()]['URL']
        elif uf.upper() == 'SP':
            if tpamb == '1':
                qrcode = NFCE[uf.upper()]['HTTPS'] + 'www.' + NFCE[uf.upper()]['QR'] + url
                url_chave = NFCE[uf.upper()]['HTTPS'] + 'www.' + NFCE[uf.upper()]['URL']
            else:
                qrcode = NFCE[uf.upper()]['HTTPS'] + 'www.homologacao.' + NFCE[uf.upper()]['QR'] + url
                url_chave = NFCE[uf.upper()]['HTTPS'] + 'www.homologacao.' + NFCE[uf.upper()]['URL']
        # BA tem comportamento distindo para qrcode e url
        elif uf.upper() == 'BA':
            if tpamb == '1':
                qrcode = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url
            else:
                qrcode = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url
            url_chave = url_chave = NFCE[uf.upper()]['URL']
        # AC, AM, RR, PA,
        else:
            if tpamb == '1':
                qrcode = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url
                url_chave = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['URL']
            else:
                qrcode = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url
                url_chave = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['URL']
        # adicionta tag infNFeSupl com qrcode
        info = etree.Element('infNFeSupl')
        etree.SubElement(info, 'qrCode').text = '<![CDATA['+ qrcode.strip() + ']]>'
        etree.SubElement(info, 'urlChave').text = url_chave
        nfe.insert(1, info)
        # correção da tag qrCode, retira caracteres pois e CDATA
        tnfe = etree.tostring(nfe, encoding='unicode')
        etree.tostring(nfe.find(".//qrCode"), encoding='unicode') \
            .replace('\n','').replace('&lt;','<').replace('&gt;','>').replace('amp;','')
        nfe = etree.fromstring(tnfe)
        # retorna nfe com o qrcode incluido NT2015/002 e qrcode
        if return_qr:
            return nfe, qrcode.strip()
        # retorna apenas nfe com o qrcode incluido NT2015/002
        else:
            return nfe
Ejemplo n.º 15
0
    def autorizacao(self, manifesto, id_lote=1, ind_sinc=1):
        """
        Método para realizar autorização do manifesto
        :param manifesto: XML assinado
        :param id_lote: Id do lote - numero autoincremental gerado pelo sistema
        :param ind_sinc: Indicador de sincrono e assincrono, 0 para assincrono, 1 para sincrono
        :return:  Uma tupla que em caso de sucesso, retorna xml com manifesto e protocolo de autorização.
        Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário.
        """
        # url do serviço
        if ind_sinc == 0:
            url = self._get_url(consulta='RECEPCAO')
        elif ind_sinc == 1:
            url = self._get_url(consulta='RECEPCAO_SINC')
        else:
            raise f'ind_sinc deve ser 0=assincrono ou 1=sincrono'

        # Monta XML do corpo da requisição
        raiz = etree.Element('enviMDFe',
                             xmlns=NAMESPACE_MDFE,
                             versao=VERSAO_MDFE)
        etree.SubElement(raiz, 'idLote').text = str(
            id_lote)  # numero autoincremental gerado pelo sistema
        #etree.SubElement(raiz, 'indSinc').text = str(ind_sinc)  # 0 para assincrono, 1 para sincrono
        raiz.append(manifesto)

        # Monta XML para envio da requisição
        if ind_sinc == 0:
            xml = self._construir_xml_soap('MDFeRecepcao', raiz)
        elif ind_sinc == 1:
            xml = self._construir_xml_soap('MDFeRecepcaoSinc', raiz)

        # Faz request no Servidor da Sefaz
        retorno = self._post(url, xml)

        # Em caso de sucesso, retorna xml com o mdfe e protocolo de autorização.
        # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário.
        if retorno.status_code == 200:
            # namespace
            ns = {'ns': NAMESPACE_MDFE}
            # Procuta status no xml
            try:
                prot = etree.fromstring(retorno.text)
            except ValueError:
                # em SP retorno.text apresenta erro
                prot = etree.fromstring(retorno.content)

            if ind_sinc == 1:
                try:
                    # Protocolo com envio OK
                    inf_prot = prot[1][0]
                    lote_status = inf_prot.xpath("ns:retEnviMDFe/ns:cStat",
                                                 namespaces=ns)[0].text

                    # Lote processado
                    if lote_status == self._edoc_situacao_lote_processado:
                        prot_mdfe = inf_prot.xpath(
                            "ns:retEnviMDFe/ns:protMDFe", namespaces=ns)[0]
                        status = prot_mdfe.xpath('ns:infProt/ns:cStat',
                                                 namespaces=ns)[0].text

                        # autorizado uso do MDF-e
                        # retorna xml final (protMDFe + MDFe)
                        if status in self._edoc_situacao_ja_enviado:  # if status == '100':
                            raiz = etree.Element('mdfeProc',
                                                 xmlns=NAMESPACE_MDFE,
                                                 versao=VERSAO_MDFE)
                            raiz.append(manifesto)
                            raiz.append(prot_mdfe)
                            return 0, raiz
                except IndexError:
                    # Protocolo com algum erro no Envio
                    return 1, retorno, manifesto
            else:
                # Retorna id do protocolo para posterior consulta em caso de sucesso.
                rec = prot[1][0]
                status = rec.xpath("ns:retEnviMDFe/ns:cStat",
                                   namespaces=ns)[0].text
                # Lote Recebido com Sucesso!
                if status == self._edoc_situacao_arquivo_recebido_com_sucesso:
                    nrec = rec.xpath("ns:retEnviMDFe/ns:infRec/ns:nRec",
                                     namespaces=ns)[0].text
                    return 0, nrec, manifesto
        return 1, retorno, manifesto
Ejemplo n.º 16
0
    def gerar_qrcode(self, token, csc, xml, return_qr=False):
        """ Classe para gerar url do qrcode da NFC-e """
        # Procura atributos no xml
        ns = {'ns':'http://www.portalfiscal.inf.br/nfe'}
        sig = {'sig':'http://www.w3.org/2000/09/xmldsig#'}
        # Tag Raiz NFe Ex: <NFe>
        nfe = xml
        chave = nfe[0].attrib['Id'].replace('NFe','')
        data = nfe.xpath('ns:infNFe/ns:ide/ns:dhEmi/text()', namespaces=ns)[0].encode()
        tpamb = nfe.xpath('ns:infNFe/ns:ide/ns:tpAmb/text()', namespaces=ns)[0]
        cuf = nfe.xpath('ns:infNFe/ns:ide/ns:cUF/text()', namespaces=ns)[0]
        uf = [key for key, value in CODIGOS_ESTADOS.items() if value == cuf][0]

        # tenta encontrar a tag cpf
        try:
            cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CPF/text()', namespaces=ns)[0]
        except IndexError:
            # em caso de erro tenta procurar a tag cnpj
            try:
                cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CNPJ/text()', namespaces=ns)[0]
            except IndexError:
                cpf = None
        total = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vNF/text()', namespaces=ns)[0]
        icms = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vICMS/text()', namespaces=ns)[0]
        digest = nfe.xpath('sig:Signature/sig:SignedInfo/sig:Reference/sig:DigestValue/text()', namespaces=sig)[0].encode()

        data = base64.b16encode(data).decode()
        digest = base64.b16encode(digest).decode()

        if cpf is None:
            url = 'chNFe={}&nVersao={}&tpAmb={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format(
                   chave, VERSAO_QRCODE, tpamb, data.lower(), total, icms, digest.lower(), token)
        else:
            url = 'chNFe={}&nVersao={}&tpAmb={}&cDest={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format(
                   chave, VERSAO_QRCODE, tpamb, cpf, data.lower(), total, icms, digest.lower(), token)

        url_hash = hashlib.sha1(url.encode()+csc.encode()).digest()
        url_hash = base64.b16encode(url_hash).decode()

        url = url + '&cHashQRCode=' + url_hash.upper()

        if uf.upper() == 'PR':
            qrcode = NFCE[uf.upper()]['QR'] + url
        else:
            if tpamb == '1':
                qrcode = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url
            else:
                qrcode = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url

        # adicionta tag infNFeSupl com qrcode
        info = etree.Element('infNFeSupl')
        etree.SubElement(info, 'qrCode').text = '<![CDATA['+ qrcode.strip() + ']]>'
        nfe.insert(1, info)
        # correção da tag qrCode, retira caracteres pois e CDATA
        tnfe = etree.tostring(nfe, encoding='unicode')
        etree.tostring(nfe.find(".//qrCode"), encoding='unicode') \
            .replace('\n','').replace('&lt;','<').replace('&gt;','>').replace('amp;','')
        nfe = etree.fromstring(tnfe)
        # retorna nfe com o qrcode incluido NT2015/002 e qrcode
        if return_qr:
            return nfe, qrcode.strip()
        # retorna apenas nfe com o qrcode incluido NT2015/002
        else:
            return nfe
Ejemplo n.º 17
0
    def gerar_qrcode(self, token, csc, xml, return_qr=False):
        """ Classe para gerar url do qrcode da NFC-e """
        # Procura atributos no xml
        ns = {'ns':'http://www.portalfiscal.inf.br/nfe'}
        sig = {'sig':'http://www.w3.org/2000/09/xmldsig#'}
        # Tag Raiz NFe Ex: <NFe>
        nfe = xml
        chave = nfe[0].attrib['Id'].replace('NFe','')
        data = nfe.xpath('ns:infNFe/ns:ide/ns:dhEmi/text()', namespaces=ns)[0].encode()
        tpamb = nfe.xpath('ns:infNFe/ns:ide/ns:tpAmb/text()', namespaces=ns)[0]
        cuf = nfe.xpath('ns:infNFe/ns:ide/ns:cUF/text()', namespaces=ns)[0]
        uf = [key for key, value in CODIGOS_ESTADOS.items() if value == cuf][0]

        # tenta encontrar a tag cpf
        try:
            cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CPF/text()', namespaces=ns)[0]
        except IndexError:
            # em caso de erro tenta procurar a tag cnpj
            try:
                cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CNPJ/text()', namespaces=ns)[0]
            except IndexError:
                cpf = None
        total = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vNF/text()', namespaces=ns)[0]
        icms = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vICMS/text()', namespaces=ns)[0]
        digest = nfe.xpath('sig:Signature/sig:SignedInfo/sig:Reference/sig:DigestValue/text()', namespaces=sig)[0].encode()

        data = base64.b16encode(data).decode()
        digest = base64.b16encode(digest).decode()

        if cpf is None:
            url = 'chNFe={}&nVersao={}&tpAmb={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format(
                   chave, VERSAO_QRCODE, tpamb, data.lower(), total, icms, digest.lower(), token)
        else:
            url = 'chNFe={}&nVersao={}&tpAmb={}&cDest={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format(
                   chave, VERSAO_QRCODE, tpamb, cpf, data.lower(), total, icms, digest.lower(), token)

        url_hash = hashlib.sha1(url.encode()+csc.encode()).digest()
        url_hash = base64.b16encode(url_hash).decode()

        url = url + '&cHashQRCode=' + url_hash.upper()

        # url_chave - Texto com a URL de consulta por chave de acesso a ser impressa no DANFE NFC-e.
        # Informar a URL da “Consulta por chave de acesso da NFC-e”. 
        # A mesma URL que deve estar informada no DANFE NFC-e para consulta por chave de acesso
        lista_uf_padrao = ['PR', 'CE', 'RS', 'RJ', 'RO']
        if uf.upper() in lista_uf_padrao:
            qrcode = NFCE[uf.upper()]['QR'] + url
            url_chave = NFCE[uf.upper()]['URL']
        elif uf.upper() == 'SP':
            if tpamb == '1':
                qrcode = NFCE[uf.upper()]['HTTPS'] + 'www.' + NFCE[uf.upper()]['QR'] + url
                url_chave = NFCE[uf.upper()]['HTTPS'] + 'www.' + NFCE[uf.upper()]['URL'] + url
            else:
                qrcode = NFCE[uf.upper()]['HTTPS'] + 'www.homologacao.' + NFCE[uf.upper()]['QR'] + url
                url_chave = NFCE[uf.upper()]['HTTPS'] + 'www.homologacao.' + NFCE[uf.upper()]['URL'] + url
        # AC, AM, RR, PA, 
        else:
            if tpamb == '1':
                qrcode = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url
                url_chave = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['URL'] + url
            else:
                qrcode = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url
                url_chave = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['URL'] + url
        # adicionta tag infNFeSupl com qrcode
        info = etree.Element('infNFeSupl')
        etree.SubElement(info, 'qrCode').text = '<![CDATA['+ qrcode.strip() + ']]>'
        etree.SubElement(info, 'urlChave').text = url_chave
        nfe.insert(1, info)
        # correção da tag qrCode, retira caracteres pois e CDATA
        tnfe = etree.tostring(nfe, encoding='unicode')
        etree.tostring(nfe.find(".//qrCode"), encoding='unicode') \
            .replace('\n','').replace('&lt;','<').replace('&gt;','>').replace('amp;','')
        nfe = etree.fromstring(tnfe)
        # retorna nfe com o qrcode incluido NT2015/002 e qrcode
        if return_qr:
            return nfe, qrcode.strip()
        # retorna apenas nfe com o qrcode incluido NT2015/002
        else:
            return nfe
Ejemplo n.º 18
0
    def assinarNfse(self, xml, retorna_string=True):
        "Assina NFS-e"
        try:
            # define variaveis de acordo com autorizador
            if self.autorizador == 'ginfes':
                xpath = './/ns2:InfRps'
                tag = 'InfRps'
            elif self.autorizador == 'betha':
                xpath = './/ns1:InfDeclaracaoPrestacaoServico'
                tag = 'InfDeclaracaoPrestacaoServico'
            else:
                raise Exception('Autorizador não encontrado!')

            xml = etree.fromstring(xml)
            # define namespaces, pega do proprio xml
            namespaces = xml.nsmap
            # No raiz do XML de saida
            raiz = etree.Element('Signature',
                                 xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(
                siginfo,
                'CanonicalizationMethod',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                siginfo,
                'SignatureMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Tenta achar a tag
            ref = etree.SubElement(
                siginfo,
                'Reference',
                URI='#' +
                xml.xpath(xpath, namespaces=namespaces)[0].attrib['Id'])
            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm=
                'http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                ref,
                'DigestMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            rps = xml.xpath(xpath + '/..', namespaces=namespaces)[0]
            rps.append(raiz)

            # Escreve no arquivo depois de remover caracteres especiais e parse string
            with open('nfse.xml', 'w') as arquivo:
                texto = remover_acentos(
                    etree.tostring(xml, encoding="unicode",
                                   pretty_print=False))
                # se for tag do Betha
                if tag == 'InfDeclaracaoPrestacaoServico':
                    texto = texto.replace('ns1:', '').replace(':ns1', '')
                arquivo.write(texto)

            subprocess.check_call([
                'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd',
                self.senha, '--crypto', 'openssl', '--output', 'nfse.xml',
                '--id-attr:Id', tag, 'nfse.xml'
            ])

            if retorna_string:
                return open('nfse.xml', 'r').read()
            else:
                return etree.parse('nfse.xml').getroot()
        except Exception as e:
            raise e
Ejemplo n.º 19
0
    def _assinar(self, xml, tag, retorna_string=True):
        """ Método para assinar xml de NFS-e com tags sem ID
            Consulta de Lote e Consulta por RPS
            @param tag - raiz do xml que será assinado
        """
        try:
            xml = etree.fromstring(xml)
            # No raiz do XML de saida
            raiz = etree.Element('Signature',
                                 xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(
                siginfo,
                'CanonicalizationMethod',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                siginfo,
                'SignatureMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Consulta nao tem id
            ref = etree.SubElement(siginfo, 'Reference', URI='')

            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm=
                'http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                ref,
                'DigestMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            xml.append(raiz)

            # Escreve no arquivo depois de remover caracteres especiais e parse string
            with open('nfse.xml', 'w') as arquivo:
                arquivo.write(
                    remover_acentos(
                        etree.tostring(xml,
                                       encoding="unicode",
                                       pretty_print=False).replace('\n', '')))

            subprocess.check_call([
                'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd',
                self.senha, '--crypto', 'openssl', '--output', 'funfa.xml',
                '--id-attr:Id', tag, 'nfse.xml'
            ])
            xml = etree.parse('funfa.xml').getroot()

            if retorna_string:
                return etree.tostring(xml,
                                      encoding="unicode",
                                      pretty_print=False).replace('\n', '')
            else:
                return xml
        except Exception as e:
            raise e
Ejemplo n.º 20
0
    def assinarConsulta(self, xml, retorna_string=True):
        try:
            xml = etree.fromstring(xml)
            # No raiz do XML de saida
            tag = 'ns1:ConsultarNfseEnvio'  # tag que será assinada
            raiz = etree.Element('Signature',
                                 xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(
                siginfo,
                'CanonicalizationMethod',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                siginfo,
                'SignatureMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Consulta nao tem id
            ref = etree.SubElement(siginfo, 'Reference', URI='')

            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm=
                'http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                ref,
                'DigestMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            consulta = xml.xpath(
                '/ns1:ConsultarNfseEnvio',
                namespaces={
                    'ns1':
                    'http://www.ginfes.com.br/servico_consultar_nfse_envio_v03.xsd',
                    'ns2': 'http://www.ginfes.com.br/tipos_v03.xsd'
                })[0]
            consulta.append(raiz)

            # Escreve no arquivo depois de remover caracteres especiais e parse string
            with open('nfse.xml', 'w') as arquivo:
                arquivo.write(
                    remover_acentos(
                        etree.tostring(xml,
                                       encoding="unicode",
                                       pretty_print=False).replace('\n', '')))

            subprocess.check_call([
                'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd',
                self.senha, '--crypto', 'openssl', '--output', 'funfa.xml',
                '--id-attr:Id', tag, 'nfse.xml'
            ])
            xml = etree.parse('funfa.xml').getroot()

            if retorna_string:
                return etree.tostring(xml,
                                      encoding="unicode",
                                      pretty_print=False)
            else:
                return xml
        except Exception as e:
            raise e
Ejemplo n.º 21
0
    def assinarCancelar(self, xml, retorna_string=True):
        """ Método que assina o xml para cancelamento de NFS-e """
        try:
            if self.autorizador == 'ginfes':
                xpath = 'CancelarNfseEnvio'
                tag = 'CancelarNfseEnvio'
                namespaces = {
                    'ns1':
                    'http://www.ginfes.com.br/servico_cancelar_nfse_envio',
                    'ns2': 'http://www.ginfes.com.br/tipos'
                }
            elif self.autorizador == 'betha':
                xpath = '/CancelarNfseEnvio/ns1:Pedido'
                tag = 'InfPedidoCancelamento'
                namespaces = {
                    'ns1': 'http://www.betha.com.br/e-nota-contribuinte-ws'
                }
            else:
                raise Exception('Autorizador não encontrado!')

            xml = etree.fromstring(xml)
            # No raiz do XML de saida
            raiz = etree.Element('Signature',
                                 xmlns='http://www.w3.org/2000/09/xmldsig#')
            siginfo = etree.SubElement(raiz, 'SignedInfo')
            etree.SubElement(
                siginfo,
                'CanonicalizationMethod',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                siginfo,
                'SignatureMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
            # Tenta achar a tag informada no xpath
            if tag == 'InfPedidoCancelamento':
                ref = etree.SubElement(
                    siginfo,
                    'Reference',
                    URI='#' + xml.xpath('.//ns1:' + tag,
                                        namespaces=namespaces)[0].attrib['Id'])
            # ginfes não tem id no cancelamento v2
            else:
                ref = etree.SubElement(siginfo, 'Reference', URI='')
            trans = etree.SubElement(ref, 'Transforms')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm=
                'http://www.w3.org/2000/09/xmldsig#enveloped-signature')
            etree.SubElement(
                trans,
                'Transform',
                Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
            etree.SubElement(
                ref,
                'DigestMethod',
                Algorithm='http://www.w3.org/2000/09/xmldsig#sha1')
            etree.SubElement(ref, 'DigestValue')
            etree.SubElement(raiz, 'SignatureValue')
            keyinfo = etree.SubElement(raiz, 'KeyInfo')
            etree.SubElement(keyinfo, 'X509Data')

            if tag == 'InfPedidoCancelamento':
                xml = xml.xpath(xpath, namespaces=namespaces)[0]
            # ginfes só possui a tag root
            else:
                xml.append(raiz)

            # Escreve no arquivo depois de remover caracteres especiais e parse string
            with open('nfse.xml', 'w') as arquivo:
                arquivo.write(
                    remover_acentos(
                        etree.tostring(xml,
                                       encoding="unicode",
                                       pretty_print=False).replace('\n', '')))

            subprocess.check_call([
                'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd',
                self.senha, '--crypto', 'openssl', '--output', 'funfa.xml',
                '--id-attr:Id', tag, 'nfse.xml'
            ])

            if retorna_string:
                return open('funfa.xml', 'r').read()
            else:
                return etree.parse('funfa.xml').getroot()
        except Exception as e:
            raise e
Ejemplo n.º 22
0
    def autorizacao(self, modelo, nota_fiscal, id_lote=1, ind_sinc=1):
        """
        Método para realizar autorização da nota de acordo com o modelo
        :param modelo: Modelo
        :param nota_fiscal: XML assinado
        :param id_lote: Id do lote - numero autoincremental gerado pelo sistema
        :param ind_sinc: Indicador de sincrono e assincrono, 0 para assincrono, 1 para sincrono
        :return:  Uma tupla que em caso de sucesso, retorna xml com nfe e protocolo de autorização. Caso contrário,
        envia todo o soap de resposta da Sefaz para decisão do usuário.
        """
        # url do serviço
        url = self._get_url(modelo=modelo, consulta='AUTORIZACAO')

        # Monta XML do corpo da requisição
        raiz = etree.Element('enviNFe',
                             xmlns=NAMESPACE_NFE,
                             versao=VERSAO_PADRAO)
        etree.SubElement(raiz, 'idLote').text = str(
            id_lote)  # numero autoincremental gerado pelo sistema
        etree.SubElement(raiz, 'indSinc').text = str(
            ind_sinc)  # 0 para assincrono, 1 para sincrono
        raiz.append(nota_fiscal)

        # Monta XML para envio da requisição
        xml = self._construir_xml_soap('NFeAutorizacao4', raiz)
        # Faz request no Servidor da Sefaz
        retorno = self._post(url, xml)

        # Em caso de sucesso, retorna xml com nfe e protocolo de autorização.
        # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário.
        if retorno.status_code == 200:
            # namespace
            ns = {'ns': NAMESPACE_NFE}
            # Procuta status no xml
            try:
                prot = etree.fromstring(retorno.text)
            except ValueError:
                # em SP retorno.text apresenta erro
                prot = etree.fromstring(retorno.content)
            if ind_sinc == 1:
                try:
                    # Protocolo com envio OK
                    try:
                        inf_prot = prot[0][0]  # root protNFe
                    except IndexError:
                        # Estados como GO vem com a tag header
                        inf_prot = prot[1][0]

                    lote_status = inf_prot.xpath("ns:retEnviNFe/ns:cStat",
                                                 namespaces=ns)[0].text
                    # Lote processado
                    if lote_status == '104':
                        prot_nfe = inf_prot.xpath("ns:retEnviNFe/ns:protNFe",
                                                  namespaces=ns)[0]
                        status = prot_nfe.xpath('ns:infProt/ns:cStat',
                                                namespaces=ns)[0].text
                        # autorizado usa da NF-e
                        # retorna xml final (protNFe+NFe)
                        if status == '100':
                            raiz = etree.Element('nfeProc',
                                                 xmlns=NAMESPACE_NFE,
                                                 versao=VERSAO_PADRAO)
                            raiz.append(nota_fiscal)
                            raiz.append(prot_nfe)
                            return 0, raiz

                        # denegado o uso da NF-e
                        # 110 = Uso Denegado
                        # 301 = Uso Denegado: Irregularidade fiscal do emitente
                        # 302 = Uso Denegado: Irregularidade fiscal do destinatário
                        # 303 = Uso Denegado: Destinatário não habilitado a operar na UF
                        elif status in ["110", "301", "302", "303"]:
                            raiz = etree.Element('nfeProc',
                                                 xmlns=NAMESPACE_NFE,
                                                 versao=VERSAO_PADRAO)
                            raiz.append(nota_fiscal)
                            raiz.append(prot_nfe)
                            return 2, raiz
                except IndexError:
                    # Protocolo com algum erro no Envio
                    return 1, retorno, nota_fiscal
            else:
                # Retorna id do protocolo para posterior consulta em caso de sucesso.
                rec = prot[0][0]
                status = rec.xpath("ns:retEnviNFe/ns:cStat",
                                   namespaces=ns)[0].text
                # Lote Recebido com Sucesso!
                if status == '103':
                    nrec = rec.xpath("ns:retEnviNFe/ns:infRec/ns:nRec",
                                     namespaces=ns)[0].text
                    return 0, nrec, nota_fiscal
        return 1, retorno, nota_fiscal