Browse Source

NT2015/002 implementada(qrcode), NT2015/003 (Cest) comentada

pull/7/head
Junior Tada 10 years ago
parent
commit
bf2f91e4ad
  1. 5
      pynfe/entidades/produto.py
  2. 4
      pynfe/processamento/comunicacao.py
  3. 53
      pynfe/processamento/danfe.py
  4. 89
      pynfe/processamento/serializacao.py

5
pynfe/entidades/produto.py

@ -29,6 +29,11 @@ class Produto(Entidade):
# - NCM
ncm = str()
# - CEST - Código especificador da substituição tributária
# NT2015/003 http://www.nfe.fazenda.gov.br/portal/exibirArquivo.aspx?conteudo=uXFlhOSgUZc=
# Tabela https://www.confaz.fazenda.gov.br/anexo-i.pdf
cest = str()
# - Unid. Com.
unidade_comercial = str()

4
pynfe/processamento/comunicacao.py

@ -290,7 +290,6 @@ class ComunicacaoSefaz(Comunicacao):
self.url = ambiente + NFE['AN'][consulta]
return self.url
def _get_url(self, modelo, consulta):
""" Retorna a url para comunicação com o webservice """
# estado que implementam webservices proprios
@ -369,7 +368,8 @@ class ComunicacaoSefaz(Comunicacao):
# Abre a conexão HTTPS
try:
xml_declaration='<?xml version="1.0" encoding="utf-8"?>'
xml = etree.tostring(xml, encoding='unicode', pretty_print=False).replace('\n','')
# limpa xml com caracteres bugados para infNFeSupl em NFC-e
xml = etree.tostring(xml, encoding='unicode', pretty_print=False).replace('\n','').replace('&lt;','<').replace('&gt;','>').replace('amp;','')
xml = xml_declaration + xml
# Faz o request com o servidor

53
pynfe/processamento/danfe.py

@ -1,9 +1,5 @@
# -*- coding: utf-8 -*-
import base64
import hashlib
from pynfe.utils.flags import VERSAO_QRCODE
from pynfe.utils.webservices import NFCE
class Danfe(object):
""" Classe abstrata para a geração do Danfe. """
@ -11,53 +7,6 @@ class Danfe(object):
class DanfeNfce(Danfe):
""" Classe para geração de Danfe para Nota Fiscal de Consumidor Eletrônica (NFC-e). """
pass
def gerar_qrcode(self, token, csc, xml, uf, homologacao=False):
""" Classe para gerar url do qrcode da NFC-e """
try:
# 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[0]
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]
# 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
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':
return NFCE[uf.upper()]['QR'] + url
else:
if homologacao:
return NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url
else:
return NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url
except Exception as e:
raise e

89
pynfe/processamento/serializacao.py

@ -5,7 +5,10 @@ from pynfe.entidades import NotaFiscal
from pynfe.utils import etree, so_numeros, obter_municipio_por_codigo, \
obter_pais_por_codigo, obter_municipio_e_codigo, formatar_decimal, \
remover_acentos, obter_uf_por_codigo, obter_codigo_por_municipio
from pynfe.utils.flags import CODIGOS_ESTADOS, VERSAO_PADRAO, NAMESPACE_NFE
from pynfe.utils.flags import CODIGOS_ESTADOS, VERSAO_PADRAO, NAMESPACE_NFE, VERSAO_QRCODE
from pynfe.utils.webservices import NFCE
import base64
import hashlib
class Serializacao(object):
@ -64,12 +67,6 @@ class SerializacaoXML(Serializacao):
for nf in notas_fiscais:
raiz.append(self._serializar_nota_fiscal(nf, retorna_string=False))
# Grupo de informaçoes suplementares NT2015.002
# Somente para NFC-e
# if nf.modelo == 65:
# info = etree.Element('infNFeSupl')
# etree.SubElement(info, 'qrCode').text = ''
# raiz.append(info)
if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=False)
@ -221,12 +218,17 @@ class SerializacaoXML(Serializacao):
etree.SubElement(prod, 'cEAN').text = produto_servico.ean
etree.SubElement(prod, 'xProd').text = produto_servico.descricao
etree.SubElement(prod, 'NCM').text = produto_servico.ncm
# Codificação opcional que detalha alguns NCM. Formato: duas letras maiúsculas e 4 algarismos. Se a mercadoria se enquadrar em mais de uma codificação, informar até 8 codificações principais.
# Codificação opcional que detalha alguns NCM. Formato: duas letras maiúsculas e 4 algarismos.
# Se a mercadoria se enquadrar em mais de uma codificação, informar até 8 codificações principais.
#etree.SubElement(prod, 'NVE').text = ''
etree.SubElement(prod, 'CFOP').text = produto_servico.cfop
etree.SubElement(prod, 'uCom').text = produto_servico.unidade_comercial
etree.SubElement(prod, 'qCom').text = str(produto_servico.quantidade_comercial or 0)
etree.SubElement(prod, 'vUnCom').text = str('{:.2f}').format(produto_servico.valor_unitario_comercial or 0)
""" Código Especificador da Substituição Tributária – CEST, que estabelece a sistemática de uniformização e identificação das mercadorias e bens passíveis de
sujeição aos regimes de substituição tributária e de antecipação de recolhimento do ICMS. """
#if produto_servico.cest:
# etree.SubElement(prod, 'CEST').text = produto_servico.cest
etree.SubElement(prod, 'vProd').text = str('{:.2f}').format(produto_servico.valor_total_bruto or 0)
etree.SubElement(prod, 'cEANTrib').text = produto_servico.ean_tributavel
etree.SubElement(prod, 'uTrib').text = produto_servico.unidade_tributavel
@ -594,6 +596,76 @@ class SerializacaoXML(Serializacao):
return raiz
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):
""" Classe para gerar url do qrcode da NFC-e """
try:
# 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
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)
# 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
except Exception as e:
raise e
class SerializacaoNfse(object):
def __init__(self, autorizador):
"Recebe uma string com o nome do autorizador."
@ -654,6 +726,7 @@ class SerializacaoNfse(object):
else:
raise Exception('Autorizador não suportado para cancelamento!')
class SerializacaoPipes(Serializacao):
"""Serialização utilizada pela SEFAZ-SP para a importação de notas."""

Loading…
Cancel
Save