Browse Source

Inicio implantação de NFS-e

pull/3/head
Junior Tada 10 years ago
parent
commit
847935f611
  1. 1
      pynfe/entidades/__init__.py
  2. 26
      pynfe/entidades/notafiscal.py
  3. 21
      pynfe/entidades/servico.py
  4. 1
      pynfe/processamento/__init__.py
  5. 38
      pynfe/processamento/assinatura.py
  6. 95
      pynfe/processamento/serializacao.py
  7. 2
      pynfe/utils/flags.py
  8. 30
      pynfe/utils/webservices.py

1
pynfe/entidades/__init__.py

@ -7,4 +7,5 @@ from .lotes import LoteNotaFiscal
from .fonte_dados import _fonte_dados from .fonte_dados import _fonte_dados
from .certificado import CertificadoA1 from .certificado import CertificadoA1
from .evento import EventoCancelarNota from .evento import EventoCancelarNota
from .servico import Servico

26
pynfe/entidades/notafiscal.py

@ -905,3 +905,29 @@ class NotaFiscalEntregaRetirada(Entidade):
# - Telefone # - Telefone
endereco_telefone = str() endereco_telefone = str()
class NotaFiscalServico(Entidade):
# Empresa que implementa o webservice
autorizador = str() # betha
# id do rps
identificador = str()
# tag competencia
data_emissao = None
# Serviço executado pelo prestador
servico = None
# Emitente da NFS-e
emitente = None
# Cliente para quem a NFS-e será emitida
cliente = None
# Optante Simples Nacional
simples = int() # 1-Sim; 2-Não
# Incentivo Fiscal
incentivo = int() # 1-Sim; 2-Não
def __init__(self, *args, **kwargs):
super(NotaFiscalServico, self).__init__(*args, **kwargs)
def __str__(self):
return ' '.join([str(self.identificador)])

21
pynfe/entidades/servico.py

@ -0,0 +1,21 @@
"""
@author: Junior Tada, Leonardo Tada
"""
from .base import Entidade
from decimal import Decimal
class Servico(Entidade):
valor_servico = Decimal()
iss_retido = Decimal()
""" http://www1.receita.fazenda.gov.br/sistemas/nfse/tabelas-de-codigos.htm
Lista com códigos dos serviços
"""
item_lista = str()
discriminacao = str()
exigibilidade = int()
codigo_municipio = str()
def __str__(self):
return self.discriminacao

1
pynfe/processamento/__init__.py

@ -1,4 +1,5 @@
from .serializacao import SerializacaoXML from .serializacao import SerializacaoXML
from .serializacao import SerializacaoNfse
from .validacao import Validacao from .validacao import Validacao
from .assinatura import AssinaturaA1 from .assinatura import AssinaturaA1
from .comunicacao import ComunicacaoSefaz from .comunicacao import ComunicacaoSefaz

38
pynfe/processamento/assinatura.py

@ -62,4 +62,42 @@ class AssinaturaA1(Assinatura):
return xml return xml
except Exception as e: except Exception as e:
raise e raise e
def assinarNfse(self, xml, retorna_string=False):
try:
# No raiz do XML de saida
tag = 'InfDeclaracaoPrestacaoServico'; # 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')
# Tenta achar a tag infNFe
ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.xpath('Rps/InfDeclaracaoPrestacaoServico')[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('Rps')[0]
rps.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)))
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

95
pynfe/processamento/serializacao.py

@ -6,7 +6,7 @@ from pynfe.entidades import NotaFiscal
from pynfe.utils import etree, so_numeros, obter_municipio_por_codigo, \ from pynfe.utils import etree, so_numeros, obter_municipio_por_codigo, \
obter_pais_por_codigo, obter_municipio_e_codigo, \ obter_pais_por_codigo, obter_municipio_e_codigo, \
formatar_decimal, remover_acentos, obter_uf_por_codigo, obter_codigo_por_municipio 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, NAMESPACE_BETHA
class Serializacao(object): class Serializacao(object):
"""Classe abstrata responsavel por fornecer as funcionalidades basicas para """Classe abstrata responsavel por fornecer as funcionalidades basicas para
@ -576,6 +576,99 @@ class SerializacaoXML(Serializacao):
else: else:
return raiz return raiz
class SerializacaoNfse(Serializacao):
def exportar(self):
pass
def importar(self):
pass
def _serializar_emitente(self, emitente, tag_raiz='Prestador', retorna_string=True):
raiz = etree.Element(tag_raiz)
documento = etree.SubElement(raiz, 'CpfCnpj')
etree.SubElement(documento, 'Cnpj').text = emitente.cnpj
etree.SubElement(raiz, 'InscricaoMunicipal').text = emitente.inscricao_municipal
if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else:
return raiz
def _serializar_cliente(self, cliente, tag_raiz='Tomador', retorna_string=True):
raiz = etree.Element(tag_raiz)
identificacao = etree.SubElement(raiz, 'IdentificacaoTomador')
documento = etree.SubElement(identificacao, 'CpfCnpj')
etree.SubElement(documento, cliente.tipo_documento).text = cliente.numero_documento # Apenas Cnpj ??
etree.SubElement(identificacao, 'InscricaoMunicipal').text = cliente.inscricao_municipal # obrigatório??
etree.SubElement(raiz, 'RazaoSocial').text = cliente.razao_social
endereco = etree.SubElement(raiz, 'Endereco')
etree.SubElement(endereco, 'Endereco').text = cliente.endereco_logradouro
etree.SubElement(endereco, 'Numero').text = cliente.endereco_numero
if cliente.endereco_complemento:
etree.SubElement(endereco, 'Complemento').text = cliente.endereco_complemento
etree.SubElement(endereco, 'Bairro').text = cliente.endereco_bairro
etree.SubElement(endereco, 'CodigoMunicipio').text = obter_codigo_por_municipio(
cliente.endereco_municipio, cliente.endereco_uf)
etree.SubElement(endereco, 'Uf').text = cliente.endereco_uf
etree.SubElement(endereco, 'CodigoPais').text = cliente.endereco_pais
etree.SubElement(endereco, 'Cep').text = so_numeros(cliente.endereco_cep)
contato = etree.SubElement(raiz, 'Contato')
etree.SubElement(contato, 'Telefone').text = cliente.endereco_telefone
etree.SubElement(contato, 'Email').text = cliente.email
if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else:
return raiz
def _serializar_servico(self, servico, tag_raiz='Servico', retorna_string=True):
raiz = etree.Element(tag_raiz)
valores = etree.SubElement(raiz, 'Valores')
etree.SubElement(valores, 'ValorServicos').text = str('{:.2f}').format(servico.valor_servico)
etree.SubElement(raiz, 'IssRetido').text = str('{:.2f}').format(servico.iss_retido)
#etree.SubElement(raiz, 'ResponsavelRetencao').text = ''
etree.SubElement(raiz, 'ItemListaServico').text = servico.item_lista
#etree.SubElement(raiz, 'CodigoCnae').text = ''
#etree.SubElement(raiz, 'CodigoTributacaoMunicipio').text = ''
etree.SubElement(raiz, 'Discriminacao').text = servico.discriminacao
etree.SubElement(raiz, 'CodigoMunicipio').text = servico.codigo_municipio
#etree.SubElement(raiz, 'CodigoPais').text = ''
etree.SubElement(raiz, 'ExigibilidadeISS').text = str(servico.exigibilidade)
etree.SubElement(raiz, 'MunicipioIncidencia').text = servico.codigo_municipio
#etree.SubElement(raiz, 'NumeroProcesso').text = ''
if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else:
return raiz
def _serializar_gerar(self, nfse, tag_raiz='GerarNfseEnvio', retorna_string=False):
if nfse.autorizador == 'betha':
raiz = etree.Element(tag_raiz, xmlns=NAMESPACE_BETHA)
# TODO - implementar outros sistemas autorizadores
else:
raiz = etree.Element(tag_raiz)
rps = etree.SubElement(raiz, 'Rps')
info = etree.SubElement(rps, 'InfDeclaracaoPrestacaoServico', Id=nfse.identificador)
etree.SubElement(info, 'Competencia').text = nfse.data_emissao.strftime('%Y-%m-%d')
# Servico
info.append(self._serializar_servico(nfse.servico, retorna_string=False))
# Emitente/Prestador
info.append(self._serializar_emitente(nfse.emitente, retorna_string=False))
# Cliente/Tomador
info.append(self._serializar_cliente(nfse.cliente, retorna_string=False))
etree.SubElement(info, 'OptanteSimplesNacional').text = str(nfse.simples) # 1-Sim; 2-Não
etree.SubElement(info, 'IncentivoFiscal').text = str(nfse.incentivo) # 1-Sim; 2-Não
if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else:
return raiz
class SerializacaoPipes(Serializacao): class SerializacaoPipes(Serializacao):
"""Serialização utilizada pela SEFAZ-SP para a importação de notas.""" """Serialização utilizada pela SEFAZ-SP para a importação de notas."""

2
pynfe/utils/flags.py

@ -7,6 +7,8 @@ NAMESPACE_XSI = 'http://www.w3.org/2001/XMLSchema-instance'
NAMESPACE_XSD = 'http://www.w3.org/2001/XMLSchema' NAMESPACE_XSD = 'http://www.w3.org/2001/XMLSchema'
NAMESPACE_METODO = 'http://www.portalfiscal.inf.br/nfe/wsdl/' NAMESPACE_METODO = 'http://www.portalfiscal.inf.br/nfe/wsdl/'
NAMESPACE_BETHA = 'http://www.betha.com.br/e-nota-contribuinte-ws'
VERSAO_PADRAO = '3.10' VERSAO_PADRAO = '3.10'
VERSAO_QRCODE = '100' VERSAO_QRCODE = '100'

30
pynfe/utils/webservices.py

@ -420,4 +420,34 @@ NFE = {
'HTTPS': 'https://nfe.', 'HTTPS': 'https://nfe.',
'HOMOLOGACAO': 'https://nfe-homologacao.' 'HOMOLOGACAO': 'https://nfe-homologacao.'
}, },
}
# Nfs-e
NFSE = {
#
'BETHA': {
'STATUS':'',
'AUTORIZACAO':'GerarNfse',
'CANCELAR':'CancelarNfse',
'CONSULTA_RPS':'ConsultarNfsePorRps',
'CONSULTA_FAIXA':'ConsultarNfseFaixa',
'CONSULTA_SERVICO':'ConsultarNfseServicoPrestado',
'CONSULTA_SERVICO_TOMADO':'ConsultarNfseServicoTomado',
'SUBSTITUIR':'SubstituirNfse',
'HTTPS':'http://e-gov.betha.com.br/e-nota-contribuinte-ws/nfseWS?wsdl',
'HOMOLOGACAO':'http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl'
},
#
'GINFES':{
'STATUS':'',
'AUTORIZACAO':'GerarNfse',
'CANCELAR':'CancelarNfse',
'CONSULTA_RPS':'ConsultarNfsePorRps',
'CONSULTA_FAIXA':'ConsultarNfseFaixa',
'CONSULTA_SERVICO':'ConsultarNfseServicoPrestado',
'CONSULTA_SERVICO_TOMADO':'ConsultarNfseServicoTomado',
'SUBSTITUIR':'SubstituirNfse',
'HTTPS':'https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl',
'HOMOLOGACAO':'https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl'
}
} }
Loading…
Cancel
Save