diff --git a/README.md b/README.md index 01f7436..eb45520 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -Atenção este repositório já esta em desenvolvimento para a versão NF-e 4.00, para a versão 3.10 utilize a última [release](https://github.com/leotada/PyNFe/releases). +Atualizado para a versão 4.00 NF-e/NFC-e ----------- Visão Geral diff --git a/pynfe/entidades/base.py b/pynfe/entidades/base.py index 9f82806..1704944 100644 --- a/pynfe/entidades/base.py +++ b/pynfe/entidades/base.py @@ -16,6 +16,9 @@ class Entidade(object): self._fonte_dados.adicionar_objeto(self) + def __str__(self): + return self.__class__.__name__ + def __repr__(self): return '<%s %s>'%(self.__class__.__name__, str(self)) diff --git a/pynfe/entidades/notafiscal.py b/pynfe/entidades/notafiscal.py index c2fc6ac..ed001bf 100644 --- a/pynfe/entidades/notafiscal.py +++ b/pynfe/entidades/notafiscal.py @@ -355,6 +355,7 @@ class NotaFiscal(Entidade): self.duplicatas = [] self.observacoes_contribuinte = [] self.processos_referenciados = [] + self.responsavel_tecnico = [] super(NotaFiscal, self).__init__(*args, **kwargs) @@ -386,7 +387,6 @@ class NotaFiscal(Entidade): self.totais_icms_pis += obj.pis_valor self.totais_icms_cofins += obj.cofins_valor self.totais_icms_outras_despesas_acessorias += obj.outras_despesas_acessorias - self.totais_icms_total_nota += obj.valor_total_bruto # - Valor Total do FCP (Fundo de Combate à Pobreza) self.totais_fcp += obj.fcp_valor self.totais_fcp_destino += obj.fcp_destino_valor @@ -396,6 +396,12 @@ class NotaFiscal(Entidade): self.totais_icms_inter_remetente += obj.icms_inter_remetente_valor ## TODO calcular impostos aproximados #self.totais_tributos_aproximado += obj.tributos + + self.totais_icms_total_nota += obj.valor_total_bruto - obj.desconto + \ + obj.icms_desonerado + obj.icms_st_valor + \ + obj.total_frete + obj.total_seguro + \ + obj.outras_despesas_acessorias + obj.ipi_valor_ipi + return obj def adicionar_transporte_volume(self, **kwargs): @@ -417,11 +423,17 @@ class NotaFiscal(Entidade): return obj def adicionar_processo_referenciado(self, **kwargs): - u"""Adiciona uma instancia de Processo Referenciado""" + """Adiciona uma instancia de Processo Referenciado""" obj = NotaFiscalProcessoReferenciado(**kwargs) self.processos_referenciados.append(obj) return obj + def adicionar_responsavel_tecnico(self, **kwargs): + """ Adiciona uma instancia de Responsavel Tecnico """ + obj = NotaFiscalResponsavelTecnico(**kwargs) + self.responsavel_tecnico.append(obj) + return obj + def _codigo_numerico_aleatorio(self): self.codigo_numerico_aleatorio = str(random.randint(0, 99999999)).zfill(8) return self.codigo_numerico_aleatorio @@ -1003,3 +1015,11 @@ class NotaFiscalServico(Entidade): def __str__(self): return ' '.join([str(self.identificador)]) + +class NotaFiscalResponsavelTecnico(Entidade): + # NT 2018/003 + cnpj = str() + contato = str() + email = str() + fone = str() + csrt = str() diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py index e8c7cf0..1cbfe93 100644 --- a/pynfe/processamento/comunicacao.py +++ b/pynfe/processamento/comunicacao.py @@ -83,7 +83,12 @@ class ComunicacaoSefaz(Comunicacao): if ind_sinc == 1: try: # Protocolo com envio OK - inf_prot = prot[0][0] # root protNFe + 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': @@ -168,7 +173,7 @@ class ComunicacaoSefaz(Comunicacao): # url url = self._get_url_an(consulta='DISTRIBUICAO') # Monta XML para envio da requisição - raiz = etree.Element('distDFeInt', versao='1.00', xmlns=NAMESPACE_NFE) + raiz = etree.Element('distDFeInt', versao='1.01', xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) if self.uf: etree.SubElement(raiz, 'cUFAutor').text = CODIGOS_ESTADOS[self.uf.upper()] @@ -176,15 +181,16 @@ class ComunicacaoSefaz(Comunicacao): etree.SubElement(raiz, 'CNPJ').text = cnpj else: etree.SubElement(raiz, 'CPF').text = cpf - distNSU = etree.SubElement(raiz, 'distNSU') - etree.SubElement(distNSU, 'ultNSU').text = str(nsu).zfill(15) - # if chave: - # consChNFe = etree.SubElement(raiz, 'consChNFe') - # etree.SubElement(consChNFe, 'chNFe').text = chave - # Monta XML para envio da requisição + if not chave: + distNSU = etree.SubElement(raiz, 'distNSU') + etree.SubElement(distNSU, 'ultNSU').text = str(nsu).zfill(15) + if chave: + consChNFe = etree.SubElement(raiz, 'consChNFe') + etree.SubElement(consChNFe, 'chNFe').text = chave + #Monta XML para envio da requisição xml = self._construir_xml_soap('NFeDistribuicaoDFe', raiz) - # print(url) - # print(etree.tostring(xml)) + + return self._post(url, xml) def consulta_cadastro(self, modelo, cnpj): @@ -287,7 +293,7 @@ class ComunicacaoSefaz(Comunicacao): 'uf': uf, 'ano': ano, 'cnpj': cnpj, - 'modelo': '55', + 'modelo': '55' if modelo == 'nfe' else '65', # 55=NF-e; 65=NFC-e; 'serie': serie.zfill(3), 'num_ini': str(numero_inicial).zfill(9), 'num_fin': str(numero_final).zfill(9), @@ -353,7 +359,7 @@ class ComunicacaoSefaz(Comunicacao): raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"') # Estados que utilizam outros ambientes else: - lista_svrs = ['AC', 'RJ', 'RN', 'PB', 'SC', 'SE', 'PI'] + lista_svrs = ['AC', 'RJ', 'RN', 'PB', 'SC', 'SE', 'PI', 'DF', 'ES'] lista_svan = ['MA','PA'] if self.uf.upper() in lista_svrs: if self._ambiente == 1: @@ -419,7 +425,7 @@ class ComunicacaoSefaz(Comunicacao): # limpa xml com caracteres bugados para infNFeSupl em NFC-e xml = re.sub( '(.*?)', - lambda x: x.group(0).replace('<', '<').replace('>', '>').replace('amp;', ''), + lambda x: x.group(0).replace('<', '<').replace('>', '>').replace('&', ''), etree.tostring(xml, encoding='unicode').replace('\n', '') ) xml = xml_declaration + xml diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 15afb3a..e216d5e 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -8,6 +8,7 @@ from pynfe.utils.webservices import NFCE import base64 import hashlib from datetime import datetime +import re import pytz @@ -237,6 +238,10 @@ class SerializacaoXML(Serializacao): etree.SubElement(prod, 'uTrib').text = produto_servico.unidade_tributavel etree.SubElement(prod, 'qTrib').text = str(produto_servico.quantidade_tributavel) etree.SubElement(prod, 'vUnTrib').text = '{:.4f}'.format(produto_servico.valor_unitario_tributavel or 0) + + if produto_servico.desconto: + etree.SubElement(prod, 'vDesc').text = '{:.2f}'.format(produto_servico.desconto) + """ Indica se valor do Item (vProd) entra no valor total da NF-e (vProd) 0=Valor do item (vProd) não compõe o valor total da NF-e 1=Valor do item (vProd) compõe o valor total da NF-e (vProd) (v2.0) @@ -257,7 +262,7 @@ class SerializacaoXML(Serializacao): # Lei da transparencia # Tributos aprox por item if produto_servico.valor_tributos_aprox: - etree.SubElement(imposto, 'vTotTrib').text = produto_servico.valor_tributos_aprox + etree.SubElement(imposto, 'vTotTrib').text = str(produto_servico.valor_tributos_aprox) ### ICMS icms = etree.SubElement(imposto, 'ICMS') @@ -293,35 +298,35 @@ class SerializacaoXML(Serializacao): etree.SubElement(icms_item, 'modBC').text = str(produto_servico.icms_modalidade_determinacao_bc) # 00=Tributada integralmente. if produto_servico.icms_modalidade == '00': - etree.SubElement(icms_item, 'vBC').text = str(produto_servico.icms_valor_base_calculo) # Valor da BC do ICMS + etree.SubElement(icms_item, 'vBC').text = str(produto_servico.icms_valor_base_calculo) # Valor da BC do ICMS etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) # Alíquota do imposto - etree.SubElement(icms_item, 'vICMS').text = '{:.2f}'.format(produto_servico.icms_valor or 0) # Valor do ICMS + etree.SubElement(icms_item, 'vICMS').text = '{:.2f}'.format(produto_servico.icms_valor or 0) # Valor do ICMS # 10=Tributada e com cobrança do ICMS por substituição tributária elif produto_servico.icms_modalidade == '10': - etree.SubElement(icms_item, 'vBC').text = str(produto_servico.icms_valor_base_calculo) # Valor da BC do ICMS + etree.SubElement(icms_item, 'vBC').text = str(produto_servico.icms_valor_base_calculo) # Valor da BC do ICMS etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) # Alíquota do imposto - etree.SubElement(icms_item, 'vICMS').text = '{:.2f}'.format(produto_servico.icms_valor or 0) # Valor do ICMS + etree.SubElement(icms_item, 'vICMS').text = '{:.2f}'.format(produto_servico.icms_valor or 0) # Valor do ICMS # Modalidade de determinação da BC do ICMS ST # 0=Preço tabelado ou máximo sugerido; 1=Lista Negativa (valor);2=Lista Positiva (valor);3=Lista Neutra (valor);4=Margem Valor Agregado (%);5=Pauta (valor); - etree.SubElement(icms_item, 'modBCST').text = str(produto_servico.icms_st_modalidade_determinacao_bc) + etree.SubElement(icms_item, 'modBCST').text = str(produto_servico.icms_st_modalidade_determinacao_bc) etree.SubElement(icms_item, 'pMVAST').text = str(produto_servico.icms_st_percentual_adicional) # Percentual da margem de valor Adicionado do ICMS ST etree.SubElement(icms_item, 'pRedBCST').text = str(produto_servico.icms_st_percentual_reducao_bc) # APercentual da Redução de BC do ICMS ST - etree.SubElement(icms_item, 'vBCST ').text = str(produto_servico.icms_st_valor_base_calculo) - etree.SubElement(icms_item, 'pICMSST ').text = str(produto_servico.icms_st_aliquota) - etree.SubElement(icms_item, 'vICMSST ').text = str(produto_servico.icms_st_valor) + etree.SubElement(icms_item, 'vBCST').text = str(produto_servico.icms_st_valor_base_calculo) + etree.SubElement(icms_item, 'pICMSST').text = str(produto_servico.icms_st_aliquota) + etree.SubElement(icms_item, 'vICMSST').text = str(produto_servico.icms_st_valor) # 20=Com redução de base de cálculo elif produto_servico.icms_modalidade == '20': etree.SubElement(icms_item, 'pRedBC').text = '{:.2f}'.format(produto_servico.icms_percentual_reducao_bc or 0) # Percentual da Redução de BC - etree.SubElement(icms_item, 'vBC').text = '{:.2f}'.format(produto_servico.icms_valor_base_calculo or 0) # Valor da BC do ICMS + etree.SubElement(icms_item, 'vBC').text = '{:.2f}'.format(produto_servico.icms_valor_base_calculo or 0) # Valor da BC do ICMS etree.SubElement(icms_item, 'pICMS').text = '{:.2f}'.format(produto_servico.icms_aliquota or 0) # Alíquota do imposto etree.SubElement(icms_item, 'vICMS').text = '{:.2f}'.format(produto_servico.icms_valor or 0) # Valor do ICMS # NT_2016_002 - # Inclusão das regras de validação N17b-20, N23b-20 e N27b-20 que impedem que seja informado zero como percentual de FCP ou FCP ST. + # Inclusão das regras de validação N17b-20, N23b-20 e N27b-20 que impedem que seja informado zero como percentual de FCP ou FCP ST. # Os campos relativos ao Fundo de Combate à Pobreza só devem ser informados se o produto estiver sujeito a incidência do mesmo. - if produto_servico.fcp_valor: + if produto_servico.fcp_valor: etree.SubElement(icms_item, 'vBCFCP').text = '{:.2f}'.format(produto_servico.fcp_base_calculo or 0) # Base de calculo FCP - etree.SubElement(icms_item, 'pFCP').text = '{:.2f}'.format(produto_servico.fcp_percentual or 0) # Percentual FCP - etree.SubElement(icms_item, 'vFCP').text = '{:.2f}'.format(produto_servico.fcp_valor or 0) # Valor Fundo Combate a Pobreza + etree.SubElement(icms_item, 'pFCP').text = '{:.2f}'.format(produto_servico.fcp_percentual or 0) # Percentual FCP + etree.SubElement(icms_item, 'vFCP').text = '{:.2f}'.format(produto_servico.fcp_valor or 0) # Valor Fundo Combate a Pobreza # Impostos não implementados else: raise NotImplementedError @@ -350,7 +355,7 @@ class SerializacaoXML(Serializacao): elif produto_servico.pis_modalidade == '03': pis_item = etree.SubElement(pis, 'PISQtde') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade - etree.SubElement(pis_item, 'qBCProd').text = produto_servico.quantidade_comercial + etree.SubElement(pis_item, 'qBCProd').text = '{:.4f}'.format(produto_servico.quantidade_comercial) etree.SubElement(pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual etree.SubElement(pis_item, 'vPIS').text = '{:.2f}'.format(produto_servico.pis_valor_base_calculo or 0) else: @@ -359,7 +364,7 @@ class SerializacaoXML(Serializacao): etree.SubElement(pis_item, 'vBC').text = '{:.2f}'.format(produto_servico.pis_valor_base_calculo or 0) etree.SubElement(pis_item, 'pPIS').text = '{:.2f}'.format(produto_servico.pis_aliquota_percentual or 0) if produto_servico.pis_modalidade is not '99': - etree.SubElement(pis_item, 'qBCProd').text = produto_servico.quantidade_comercial + etree.SubElement(pis_item, 'qBCProd').text = '{:.4f}'.format(produto_servico.quantidade_comercial) etree.SubElement(pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual etree.SubElement(pis_item, 'vPIS').text = '{:.2f}'.format(produto_servico.pis_valor_base_calculo or 0) @@ -386,9 +391,9 @@ class SerializacaoXML(Serializacao): elif produto_servico.cofins_modalidade == '03': cofins_item = etree.SubElement(cofins, 'COFINSQtde') etree.SubElement(cofins_item, 'CST').text = produto_servico.cofins_modalidade - etree.SubElement(cofins_item, 'qBCProd').text = produto_servico.quantidade_comercial - etree.SubElement(cofins_item, 'vAliqProd').text = produto_servico.cofins_aliquota_percentual - etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor + etree.SubElement(cofins_item, 'qBCProd').text = '{:.4f}'.format(produto_servico.quantidade_comercial) + etree.SubElement(cofins_item, 'vAliqProd').text = '{:.4f}'.format(produto_servico.cofins_aliquota_percentual) + etree.SubElement(cofins_item, 'vCOFINS').text = '{:.2f}'.format(produto_servico.cofins_valor) else: cofins_item = etree.SubElement(cofins, 'COFINSOutr') etree.SubElement(cofins_item, 'CST').text = produto_servico.cofins_modalidade @@ -411,6 +416,18 @@ class SerializacaoXML(Serializacao): else: return raiz + def _serializar_responsavel_tecnico(self, responsavel_tecnico, tag_raiz='infRespTec', retorna_string=True): + raiz = etree.Element(tag_raiz) + etree.SubElement(raiz, 'CNPJ').text = responsavel_tecnico.cnpj + etree.SubElement(raiz, 'xContato').text = responsavel_tecnico.contato + etree.SubElement(raiz, 'email').text = responsavel_tecnico.email + etree.SubElement(raiz, 'fone').text = responsavel_tecnico.fone + + if retorna_string: + return etree.tostring(raiz, encoding="unicode", pretty_print=True) + else: + return raiz + def _serializar_nota_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): raiz = etree.Element(tag_raiz, versao=self._versao) @@ -607,14 +624,14 @@ class SerializacaoXML(Serializacao): etree.SubElement(lacres, 'nLacre').text = lacre.numero_lacre # Pagamento - """ Obrigatório o preenchimento do Grupo Informações de Pagamento para NF-e e NFC-e. + """ Obrigatório o preenchimento do Grupo Informações de Pagamento para NF-e e NFC-e. Para as notas com finalidade de Ajuste ou Devolução o campo Forma de Pagamento deve ser preenchido com 90=Sem Pagamento. """ pag = etree.SubElement(raiz, 'pag') detpag = etree.SubElement(pag, 'detPag') if nota_fiscal.finalidade_emissao == '3' or nota_fiscal.finalidade_emissao == '4': etree.SubElement(detpag, 'tPag').text = '90' etree.SubElement(detpag, 'vPag').text = '{:.2f}'.format(0) - else: + else: etree.SubElement(detpag, 'tPag').text = str(nota_fiscal.tipo_pagamento).zfill(2) etree.SubElement(detpag, 'vPag').text = '{:.2f}'.format(nota_fiscal.totais_icms_total_nota) if nota_fiscal.tipo_pagamento == 3 or nota_fiscal.tipo_pagamento == 4: @@ -638,6 +655,12 @@ class SerializacaoXML(Serializacao): if nota_fiscal.informacoes_complementares_interesse_contribuinte: etree.SubElement(info_ad, 'infCpl').text = nota_fiscal.informacoes_complementares_interesse_contribuinte + # Responsavel Tecnico NT2018/003 + if nota_fiscal.responsavel_tecnico: + raiz.append(self._serializar_responsavel_tecnico( + nota_fiscal.responsavel_tecnico[0], retorna_string=False)) + + if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: @@ -677,7 +700,7 @@ class SerializacaoXML(Serializacao): class SerializacaoQrcode(object): """ Classe que gera e serializa o qrcode de NFC-e no xml """ - def gerar_qrcode(self, token, csc, xml, return_qr=False): + 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} @@ -700,38 +723,56 @@ class SerializacaoQrcode(object): 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] + # 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() + 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) - 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) + #VERSAO_QRCODE =2 + if online: + #versão online + url = '{}|{}|{}|{}'.format(chave,VERSAO_QRCODE, tpamb, 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) + #versão offline + digest = digest.lower() + digest = digest.hex() + + url = '{}|{}|{}|{}|{}|{}|{}'.format( + chave,VERSAO_QRCODE,tpamb,dia,total,digest,token + ) - url_hash = hashlib.sha1(url.encode()+csc.encode()).digest() + url_complementar = url + csc + url_hash = hashlib.sha1(url_complementar.encode()).digest() url_hash = base64.b16encode(url_hash).decode() - url = url + '&cHashQRCode=' + url_hash.upper() + 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”. + # 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'] + 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'] + 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'] + url - # AC, AM, RR, PA, + 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 diff --git a/pynfe/utils/descompactar.py b/pynfe/utils/descompactar.py new file mode 100644 index 0000000..ab4e1ea --- /dev/null +++ b/pynfe/utils/descompactar.py @@ -0,0 +1,30 @@ + +""" + @author: Lucas Resende + + classe que descompacta o gzip recebido pela consulta distribuicao + +""" + +from io import BytesIO +import base64 +import gzip +from lxml import etree + +class DescompactaGzip(object): + @staticmethod + def descompacta(stringZipada): + """ + :paramn stringZipada: String + + :return : Etree + """ + arq = BytesIO() + arq.write(base64.b64decode(stringZipada)) + arq.seek(0) + zip = gzip.GzipFile(fileobj=arq) + texto = zip.read() + arq.close() + zip.close() + descompactado = texto.decode('utf-8') + return etree.fromstring(descompactado) diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py index 7c1db9e..084389d 100644 --- a/pynfe/utils/flags.py +++ b/pynfe/utils/flags.py @@ -12,7 +12,7 @@ NAMESPACE_BETHA = 'http://www.betha.com.br/e-nota-contribuinte-ws' VERSAO_PADRAO = '4.00' -VERSAO_QRCODE = '100' +VERSAO_QRCODE = '2' TIPOS_DOCUMENTO = ( 'CNPJ', @@ -40,7 +40,7 @@ ICMS_TIPOS_TRIBUTACAO = ( ('ST', 'ICMS ST - Grupo de informação do ICMS ST devido para a UF de destino, nas operações interestaduais de produtos que tiveram retenção antecipada de ICMS por ST na UF do remetente. Repasse via Substituto Tributário.') ) -ICMS_ORIGENS = ( +ICMS_ORIGENS = ( (0, 'Nacional, exceto as indicadas nos códigos 3, 4, 5 e 8. '), (1, 'Estrangeira - Importação direta, exceto a indicada no código 6.'), (2, 'Estrangeira - Adquirida no mercado interno, exceto a indicada no código 7.'), @@ -49,7 +49,7 @@ ICMS_ORIGENS = ( (5, 'Nacional, mercadoria ou bem com Conteúdo de Importação inferior ou igual a 40%. '), (6, 'Estrangeira - Importação direta, sem similar nacional, constante em lista da CAMEX e gás natural. '), (7, 'Estrangeira - Adquirida no mercado interno, sem similar nacional, constante em lista da CAMEX e gás natural.'), - (8, 'Nacional, mercadoria ou bem com Conteúdo de Importação superior a 70%.') + (8, 'Nacional, mercadoria ou bem com Conteúdo de Importação superior a 70%.') ) ICMS_MODALIDADES = ( @@ -147,7 +147,7 @@ IPI_TIPOS_CALCULO = ( PIS_TIPOS_TRIBUTACAO = ( ('01', 'PIS 01 - Operação Tributável - Base de cálculo = valor da operação alíquota normal (cumulativo/não cumulativo)'), - ('02', 'PIS 02 - Operação Tributável - Base de cálculo = valor da operação (alíquota diferenciada)'), + ('02', 'PIS 02 - Operação Tributável - Base de cálculo = valor da operação (alíquota diferenciada)'), ('03', 'PIS 03 - Operacao Tributavel - Base de cálculo = quantidade vendida x alíquota por unidade de produto)'), ('04', 'PIS 04 - Operacao Tributavel - Tributacao Monofasica - (Aliquota Zero)'), ('06', 'PIS 06 - Operacao Tributavel - Aliquota Zero'), @@ -184,7 +184,7 @@ PIS_TIPOS_CALCULO = IPI_TIPOS_CALCULO COFINS_TIPOS_TRIBUTACAO = ( ('01', 'COFINS 01 - Operação Tributável - Base de cálculo = valor da operação alíquota normal (cumulativo/não cumulativo)'), - ('02', 'COFINS 02 - Operação Tributável - Base de cálculo = valor da operação (alíquota diferenciada)'), + ('02', 'COFINS 02 - Operação Tributável - Base de cálculo = valor da operação (alíquota diferenciada)'), ('03', 'COFINS 03 - Operacao Tributavel - Base de cálculo = quantidade vendida x alíquota por unidade de produto)'), ('04', 'COFINS 04 - Operacao Tributavel - Tributacao Monofasica - (Aliquota Zero)'), ('06', 'COFINS 06 - Operacao Tributavel - Aliquota Zero'), diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py index 36bd6fc..d030c3d 100644 --- a/pynfe/utils/webservices.py +++ b/pynfe/utils/webservices.py @@ -27,12 +27,12 @@ NFCE = { 'AM': { # csc_homologacao = '0123456789' # token_homologacao = '000001' - 'STATUS': 'nfce.sefaz.am.gov.br/nfce-services-nac/services/NfeStatusServico2', - 'AUTORIZACAO': 'nfce.sefaz.am.gov.br/nfce-services-nac/services/NfeAutorizacao', - 'RECIBO': 'nfce.sefaz.am.gov.br/nfce-services-nac/services/NfeRetAutorizacao', - 'CHAVE': 'nfce.sefaz.am.gov.br/nfce-services-nac/services/NfeConsulta2', - 'INUTILIZACAO': 'nfce.sefaz.am.gov.br/nfce-services-nac/services/NfeInutilizacao2', - 'EVENTOS': 'nfce.sefaz.am.gov.br/nfce-services-nac/services/RecepcaoEvento', + 'STATUS': 'nfe.sefaz.am.gov.br/services2/services/NfeStatusServico4', + 'AUTORIZACAO': 'nfe.sefaz.am.gov.br/services2/services/NfeAutorizacao4', + 'RECIBO': 'nfe.sefaz.am.gov.br/services2/services/NfeRetAutorizacao4', + 'CHAVE': 'nfe.sefaz.am.gov.br/services2/services/NfeConsulta4', + 'INUTILIZACAO': 'nfe.sefaz.am.gov.br/services2/services/NfeInutilizacao4', + 'EVENTOS': 'nfe.sefaz.am.gov.br/services2/services/RecepcaoEvento4', 'QR': 'sefaz.am.gov.br/nfceweb/consultarNFCe.jsp?', 'URL': 'sefaz.am.gov.br/nfceweb/formConsulta.do', 'HTTPS': 'http://sistemas.', @@ -108,7 +108,7 @@ NFCE = { 'QR': 'http://nfce.set.rn.gov.br/consultarNFCe.aspx?', 'HTTPS': '', 'HOMOLOGACAO': '' - + }, 'PB': { 'STATUS': '', @@ -126,10 +126,10 @@ NFCE = { 'CHAVE': '', 'INUTILIZACAO': '', 'EVENTOS': '', - 'QR': 'sefaz.pe.gov.br/nfce-web/consultarNFCe?', + 'QR': 'sefaz.pe.gov.br/nfce/consulta?', 'HTTPS': 'http://nfce.', 'HOMOLOGACAO': 'http://nfcehomolog.', - 'URL': 'sefaz.pe.gov.br/nfce-web/consultarNFCe' + 'URL': 'sefaz.pe.gov.br/nfce/consulta' }, 'AL': { 'STATUS': '', @@ -152,19 +152,23 @@ NFCE = { 'CHAVE': '', 'INUTILIZACAO': '', 'EVENTOS': '', - 'QR': 'sefaz.ba.gov.br/servicos/nfce/modulos/geral/NFCEC_consulta_chave_acesso.aspx?', + 'QR': 'sefaz.ba.gov.br/servicos/nfce/qrcode.aspx?', 'HTTPS': 'http://nfe.', 'HOMOLOGACAO': 'http://hnfe.', - 'URL': 'nfe.sefaz.ba.gov.br/servicos/nfce/default.aspx' - }, + 'URL': 'http://hinternet.sefaz.ba.gov.br/nfce/consulta' + }, 'MG': { - 'STATUS': '', - 'AUTORIZACAO': '', - 'RECIBO': '', - 'CHAVE': '', - 'INUTILIZACAO': '', - 'EVENTOS': '', - 'QR': '' + 'STATUS': 'fazenda.mg.gov.br/nfce/services/NFeStatusServico4', + 'AUTORIZACAO': 'fazenda.mg.gov.br/nfce/services/NFeAutorizacao4', + 'RECIBO': 'fazenda.mg.gov.br/nfce/services/NFeRetAutorizacao4', + 'CHAVE': 'fazenda.mg.gov.br/nfce/services/NFeConsultaProtocolo4', + 'INUTILIZACAO': 'fazenda.mg.gov.br/nfce/services/NFeInutilizacao4', + 'EVENTOS': 'fazenda.mg.gov.br/nfce/services/NFeRecepcaoEvento4', + 'CADASTRO': 'fazenda.mg.gov.br/nfce/services/CadConsultaCadastro4', + 'QR': 'fazenda.mg.gov.br/portalnfce/sistema/qrcode.xhtml?', + 'HTTPS': 'https://nfce.', + 'HOMOLOGACAO': 'https://hnfce.', + 'URL': 'fazenda.mg.gov.br/portalnfce' }, 'ES': { 'STATUS': '', @@ -173,7 +177,10 @@ NFCE = { 'CHAVE': '', 'INUTILIZACAO': '', 'EVENTOS': '', - 'QR': '' + 'QR': 'sefaz.es.gov.br/ConsultaNFCe/qrcode.aspx? ', + 'HTTPS': 'http://nfe.', + 'HOMOLOGACAO': 'http://homologacao.', + 'URL': 'www.sefaz.es.gov.br/nfce/consulta' }, 'RJ': { 'STATUS': '', @@ -182,16 +189,16 @@ NFCE = { 'CHAVE': '', 'INUTILIZACAO': '', 'EVENTOS': '', - 'QR': 'http://www4.fazenda.rj.gov.br/consultaNFCe/QRCode?', + 'QR': 'http://www4.fazenda.rj.gov.br/consultaNFCe/QRCode?', 'URL': 'www.nfce.fazenda.rj.gov.br/consulta' }, - # Os Web Services de homologação da NFC-e 4.00 são: - # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeAutorizacao4.asmx - # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeStatusServico4.asmx - # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeConsultaProtocolo4.asmx - # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeRetAutorizacao4.asmx - # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeRecepcaoEvento4.asmx - # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeInutilizacao4.asmx + # Os Web Services de homologação da NFC-e 4.00 são: + # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeAutorizacao4.asmx + # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeStatusServico4.asmx + # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeConsultaProtocolo4.asmx + # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeRetAutorizacao4.asmx + # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeRecepcaoEvento4.asmx + # https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeInutilizacao4.asmx 'SP': { 'STATUS': 'nfce.fazenda.sp.gov.br/ws/NFeStatusServico4.asmx', 'AUTORIZACAO': 'nfce.fazenda.sp.gov.br/ws/NFeAutorizacao4.asmx', @@ -200,7 +207,7 @@ NFCE = { 'INUTILIZACAO': 'nfce.fazenda.sp.gov.br/ws/NFeInutilizacao4.asmx', 'EVENTOS': 'nfce.fazenda.sp.gov.br/ws/NFeRecepcaoEvento4.asmx', 'QR': 'nfce.fazenda.sp.gov.br/NFCeConsultaPublica/Paginas/ConsultaQRCode.aspx?', - 'URL': 'nfce.fazenda.sp.gov.br/NFCeConsultaPublica/Paginas/ConsultaPublica.aspx', + 'URL': 'nfce.fazenda.sp.gov.br/consulta', 'HTTPS': 'https://', 'HOMOLOGACAO': 'https://homologacao.' }, @@ -213,7 +220,7 @@ NFCE = { 'EVENTOS': 'nfce.sefa.pr.gov.br/nfce/NFeRecepcaoEvento4?wsdl', 'CADASTRO': 'nfce.sefa.pr.gov.br/nfce/CadConsultaCadastro4?wsdl', 'QR': 'http://www.fazenda.pr.gov.br/nfce/qrcode?', - 'URL': 'http://www.fazenda.pr.gov.br', + 'URL': 'http://www.fazenda.pr.gov.br/nfce/consulta', 'HTTPS': 'https://', 'HOMOLOGACAO': 'https://homologacao.' }, @@ -261,8 +268,13 @@ NFCE = { 'EVENTOS': 'sefaz.go.gov.br/nfe/services/NFeRecepcaoEvento4?wsdl', 'QR': 'sefaz.go.gov.br/nfeweb/sites/nfce/danfeNFCe?', 'CADASTRO': 'sefaz.go.gov.br/nfe/services/CadConsultaCadastro4?wsdl', - 'HTTPS': 'http://nfe.', - 'HOMOLOGACAO': 'http://homolog.' + 'HTTPS': 'https://nfe.', + 'HOMOLOGACAO': 'https://homolog.', + 'URL': 'sefaz.go.gov.br/nfeweb/sites/nfce/danfeNFCe' + }, + 'DF': { + 'QR': 'http://www.fazenda.df.gov.br/nfce/qrcode?', + 'URL': 'www.fazenda.df.gov.br/nfce/consulta' }, # RO, AC, RR, PA, AP, TO, MA, PI, RN, PB, AL, SE, BA, ES, RJ, GO, DF 'SVRS': { @@ -290,12 +302,12 @@ NFE = { 'HOMOLOGACAO': 'https://hom' }, 'AM': { - 'STATUS': 'nfe.sefaz.am.gov.br/services2/services/NfeStatusServico2', - 'AUTORIZACAO': 'nfe.sefaz.am.gov.br/services2/services/NfeAutorizacao', - 'RECIBO': 'nfe.sefaz.am.gov.br/services2/services/NfeRetAutorizacao', - 'CHAVE': 'nfe.sefaz.am.gov.br/services2/services/NfeConsulta2', - 'INUTILIZACAO': 'nfe.sefaz.am.gov.br/services2/services/NfeInutilizacao2', - 'EVENTOS': 'nfe.sefaz.am.gov.br/services2/services/RecepcaoEvento', + 'STATUS': 'nfe.sefaz.am.gov.br/services2/services/NfeStatusServico4', + 'AUTORIZACAO': 'nfe.sefaz.am.gov.br/services2/services/NfeAutorizacao4', + 'RECIBO': 'nfe.sefaz.am.gov.br/services2/services/NfeRetAutorizacao4', + 'CHAVE': 'nfe.sefaz.am.gov.br/services2/services/NfeConsulta4', + 'INUTILIZACAO': 'nfe.sefaz.am.gov.br/services2/services/NfeInutilizacao4', + 'EVENTOS': 'nfe.sefaz.am.gov.br/services2/services/RecepcaoEvento4', 'CADASTRO': 'nfe.sefaz.am.gov.br/services2/services/cadconsultacadastro2', 'HTTPS': 'https://', 'HOMOLOGACAO': 'https://hom' @@ -310,7 +322,7 @@ NFE = { 'CHAVE': 'sefaz.ce.gov.br/nfe4/services/NFeConsultaProtocolo4?WSDL', 'INUTILIZACAO': 'sefaz.ce.gov.br/nfe4/services/NFeInutilizacao4?WSDL', 'EVENTOS': 'sefaz.ce.gov.br/nfe4/services/NFeRecepcaoEvento4?WSDL', - 'CADASTRO': 'sefaz.ce.gov.br/nfe2/services/CadConsultaCadastro2?wsdl', + 'CADASTRO': 'nfe.sefaz.ce.gov.br/nfe4/services/CadConsultaCadastro4?wsdl', 'DOWNLOAD': 'sefaz.ce.gov.br/nfe2/services/NfeDownloadNF?wsdl', 'HTTPS': 'https://nfe.', 'HOMOLOGACAO': 'https://nfeh.' @@ -336,23 +348,23 @@ NFE = { 'CADASTRO': 'nfe.sefaz.ba.gov.br/webservices/CadConsultaCadastro4/CadConsultaCadastro4.asmx', 'HTTPS': 'https://', 'HOMOLOGACAO': 'https://h' - }, + }, 'MG': { 'STATUS': 'nfe.fazenda.mg.gov.br/nfe2/services/NFeStatusServico4', 'AUTORIZACAO': 'nfe.fazenda.mg.gov.br/nfe2/services/NFeAutorizacao4', 'RECIBO': 'nfe.fazenda.mg.gov.br/nfe2/services/NFeRetAutorizacao4', 'CHAVE': 'nfe.fazenda.mg.gov.br/nfe2/services/NFeConsulta4', 'INUTILIZACAO': 'nfe.fazenda.mg.gov.br/nfe2/services/NFeInutilizacao4', - 'EVENTOS': 'nfe.fazenda.mg.gov.br/nfe2/services/RecepcaoEvento', + 'EVENTOS': 'nfe.fazenda.mg.gov.br/nfe2/services/NFeRecepcaoEvento4', 'CADASTRO': 'nfe.fazenda.mg.gov.br/nfe2/services/cadconsultacadastro2', 'HTTPS': 'https://', 'HOMOLOGACAO': 'https://h' }, 'SP': { - 'STATUS': 'nfe.fazenda.sp.gov.br/ws/NFeStatusServico4.asmx', + 'STATUS': 'nfe.fazenda.sp.gov.br/ws/nfestatusservico4.asmx', 'AUTORIZACAO': 'nfe.fazenda.sp.gov.br/ws/nfeautorizacao4.asmx', 'RECIBO': 'nfe.fazenda.sp.gov.br/ws/nferetautorizacao4.asmx', - 'CHAVE': 'nfe.fazenda.sp.gov.br/ws/nfeconsulta4.asmx', + 'CHAVE': 'nfe.fazenda.sp.gov.br/ws/nfeconsultaprotocolo4.asmx', 'INUTILIZACAO': 'nfe.fazenda.sp.gov.br/ws/nfeinutilizacao4.asmx', 'EVENTOS': 'nfe.fazenda.sp.gov.br/ws/nferecepcaoevento4.asmx', 'CADASTRO': 'nfe.fazenda.sp.gov.br/ws/cadconsultacadastro4.asmx', @@ -378,31 +390,31 @@ NFE = { 'CHAVE': 'sefazrs.rs.gov.br/ws/NfeConsulta/NfeConsulta4.asmx', 'INUTILIZACAO': 'sefazrs.rs.gov.br/ws/nfeinutilizacao/nfeinutilizacao4.asmx', 'EVENTOS': 'sefazrs.rs.gov.br/ws/recepcaoevento/recepcaoevento4.asmx', - 'CADASTRO': 'https://cad.sefazrs.rs.gov.br/ws/cadconsultacadastro/cadconsultacadastro2.asmx', + 'CADASTRO': 'cad.sefazrs.rs.gov.br/ws/cadconsultacadastro/cadconsultacadastro2.asmx', 'DOWNLOAD': 'sefazrs.rs.gov.br/ws/nfeDownloadNF/nfeDownloadNF.asmx', 'DESTINADAS': 'sefazrs.rs.gov.br/ws/nfeConsultaDest/nfeConsultaDest.asmx', 'HTTPS': 'https://nfe.', 'HOMOLOGACAO': 'https://nfe-homologacao.' }, 'MS': { - 'STATUS': 'nfe.ms.gov.br/ws/NFeStatusServico4', - 'AUTORIZACAO': 'nfe.ms.gov.br/ws/NFeAutorizacao4', - 'RECIBO': 'nfe.ms.gov.br/ws/NFeRetAutorizacao4', - 'CHAVE': 'nfe.ms.gov.br/ws/NFeConsultaProtocolo4', - 'INUTILIZACAO': 'nfe.ms.gov.br/ws/NFeInutilizacao4', - 'EVENTOS': 'nfe.ms.gov.br/ws/NFeRecepcaoEvento4', - 'CADASTRO': 'nfe.fazenda.ms.gov.br/producao/services2/CadConsultaCadastro2', + 'STATUS': 'nfe.sefaz.ms.gov.br/ws/NFeStatusServico4', + 'AUTORIZACAO': 'nfe.sefaz.ms.gov.br/ws/NFeAutorizacao4', + 'RECIBO': 'nfe.sefaz.ms.gov.br/ws/NFeRetAutorizacao4', + 'CHAVE': 'nfe.sefaz.ms.gov.br/ws/NFeConsultaProtocolo4', + 'INUTILIZACAO': 'nfe.sefaz.ms.gov.br/ws/NFeInutilizacao4', + 'EVENTOS': 'nfe.sefaz.ms.gov.br/ws/NFeRecepcaoEvento4', + 'CADASTRO': 'nfe.sefaz.ms.gov.br/ws/CadConsultaCadastro4', 'HTTPS': 'https://', - 'HOMOLOGACAO': 'https://homologacao.' + 'HOMOLOGACAO': 'https://hom.' }, 'MT': { - 'STATUS': 'sefaz.mt.gov.br/nfews/v2/services/NfeStatusServico2?wsdl', - 'AUTORIZACAO': 'sefaz.mt.gov.br/nfews/v2/services/NfeAutorizacao?wsdl', - 'RECIBO': 'sefaz.mt.gov.br/nfews/v2/services/NfeRetAutorizacao?wsdl', - 'CHAVE': 'sefaz.mt.gov.br/nfews/v2/services/NfeConsulta2?wsdl', - 'INUTILIZACAO': 'sefaz.mt.gov.br/nfews/v2/services/NfeInutilizacao2?wsdl', - 'EVENTOS': 'sefaz.mt.gov.br/nfews/v2/services/RecepcaoEvento?wsdl', - 'CADASTRO': 'sefaz.mt.gov.br/nfews/v2/services/CadConsultaCadastro2?wsdl', + 'STATUS': 'sefaz.mt.gov.br/nfews/v2/services/NfeStatusServico4?wsdl', + 'AUTORIZACAO': 'sefaz.mt.gov.br/nfews/v2/services/NfeAutorizacao4?wsdl', + 'RECIBO': 'sefaz.mt.gov.br/nfews/v2/services/NfeRetAutorizacao4?wsdl', + 'CHAVE': 'sefaz.mt.gov.br/nfews/v2/services/NfeConsulta4?wsdl', + 'INUTILIZACAO': 'sefaz.mt.gov.br/nfews/v2/services/NfeInutilizacao4?wsdl', + 'EVENTOS': 'sefaz.mt.gov.br/nfews/v2/services/RecepcaoEvento4?wsdl', + 'CADASTRO': 'sefaz.mt.gov.br/nfews/v2/services/CadConsultaCadastro4?wsdl', 'HTTPS': 'https://nfe.', 'HOMOLOGACAO': 'https://homologacao.' }, @@ -462,7 +474,7 @@ NFE = { # Nfs-e NFSE = { - # + # 'BETHA': { 'AUTORIZACAO':'GerarNfse', 'CANCELAR':'CancelarNfse', @@ -486,4 +498,4 @@ NFSE = { 'HTTPS':'https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl', 'HOMOLOGACAO':'https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl' } -} \ No newline at end of file +} diff --git a/requirements-nfse.txt b/requirements-nfse.txt index a203ffa..582da17 100644 --- a/requirements-nfse.txt +++ b/requirements-nfse.txt @@ -1,3 +1,3 @@ # Opcional para NFS-e suds-jurko -pyxb +pyxb=1.2.4