Browse Source

Novos webservices RS

pull/1/head
Junior Tada 11 years ago
parent
commit
e3e3afd0e2
  1. 15
      pynfe/entidades/evento.py
  2. 6
      pynfe/processamento/assinatura.py
  3. 44
      pynfe/processamento/comunicacao.py
  4. 36
      pynfe/processamento/serializacao.py
  5. 42
      pynfe/utils/webservices.py

15
pynfe/entidades/evento.py

@ -26,12 +26,12 @@ class EventoCancelarNota(Evento):
tp_evento = '110111' tp_evento = '110111'
# - Sequencial do evento para o mesmo tipo de evento. Para maioria dos eventos nSeqEvento=1, nos casos em quepossa existir mais de um evento, como é o caso da Carta de Correção, o autor do evento deve numerar de forma sequencial. # - Sequencial do evento para o mesmo tipo de evento. Para maioria dos eventos nSeqEvento=1, nos casos em quepossa existir mais de um evento, como é o caso da Carta de Correção, o autor do evento deve numerar de forma sequencial.
n_seq_evento = '1' n_seq_evento = '1'
# - Versão do detalhe do evento (grupo detEvento – HP17), informação utilizada para a SEFAZ validar o grupo detEvento.
ver_evento = str()
# - Informações do Pedido de Cancelamento
det_evento = str()
# - Versão do Pedido de Cancelamento, deve ser informado com a mesma informação da tag verEvento (HP16)
versao = str()
# # - Versão do detalhe do evento (grupo detEvento – HP17), informação utilizada para a SEFAZ validar o grupo detEvento.
# ver_evento = str()
# # - Informações do Pedido de Cancelamento
# det_evento = str()
# # - Versão do Pedido de Cancelamento, deve ser informado com a mesma informação da tag verEvento (HP16)
# versao = str()
# - descEvento # - descEvento
descricao = 'Cancelamento' descricao = 'Cancelamento'
# - Informar o número do Protocolo de Autorização da NF-e a ser Cancelada. (vide item 5.8). # - Informar o número do Protocolo de Autorização da NF-e a ser Cancelada. (vide item 5.8).
@ -45,8 +45,9 @@ class EventoCancelarNota(Evento):
Gera o valor para o campo id Gera o valor para o campo id
A regra de formação do Id é: ID + tpEvento + chave da NF-e + nSeqEvento A regra de formação do Id é: ID + tpEvento + chave da NF-e + nSeqEvento
""" """
self.id = "ID%(tp_evento)s%(chave)s%(n_seq_evento)s"%{
self.id = "ID%(tp_evento)s%(um)s%(chave)s%(n_seq_evento)s"%{
'tp_evento': self.tp_evento, 'tp_evento': self.tp_evento,
'um': '1',
'chave': self.chave, 'chave': self.chave,
'n_seq_evento': self.n_seq_evento, 'n_seq_evento': self.n_seq_evento,
} }

6
pynfe/processamento/assinatura.py

@ -34,7 +34,8 @@ class AssinaturaA1(Assinatura):
siginfo = etree.SubElement(raiz, 'SignedInfo') siginfo = etree.SubElement(raiz, 'SignedInfo')
etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') 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') etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1')
ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.findall('infNFe')[0].attrib['Id'])
#ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.findall('infNFe')[0].attrib['Id'])
ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.findall('infEvento')[0].attrib['Id'])
trans = etree.SubElement(ref, 'Transforms') 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/2000/09/xmldsig#enveloped-signature')
etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
@ -49,7 +50,8 @@ class AssinaturaA1(Assinatura):
with open('testes.xml', 'w') as arquivo: with open('testes.xml', 'w') as arquivo:
arquivo.write(etree.tostring(xml, encoding="unicode", pretty_print=False)) arquivo.write(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', 'infNFe', 'testes.xml'])
#subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', 'infNFe', 'testes.xml'])
subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', 'infEvento', 'testes.xml'])
xml = etree.parse('funfa.xml').getroot() xml = etree.parse('funfa.xml').getroot()
if retorna_string: if retorna_string:

44
pynfe/processamento/comunicacao.py

@ -78,27 +78,17 @@ class ComunicacaoSefaz(Comunicacao):
return self._post(url, xml) return self._post(url, xml)
def cancelar(self, modelo, xml):
def cancelar(self, modelo, evento):
""" Envia um evento de cancelamento de nota fiscal """ """ Envia um evento de cancelamento de nota fiscal """
# timezone Brasília -03:00
tz = time.strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
# url do serviço # url do serviço
url = self._get_url(modelo=modelo, consulta='EVENTOS') url = self._get_url(modelo=modelo, consulta='EVENTOS')
# Monta XML do corpo da requisição # Monta XML do corpo da requisição
raiz = etree.Element('envEvento')
#etree.SubElement(raiz, 'versao').text = self._versao # Na documentaçao 6.0 está desta forma
etree.SubElement(raiz, 'versaoDados').text = self._versao # Na documentaçao 6.0 está desta forma
raiz = etree.Element('envEvento', versao='1.00', xmlns=NAMESPACE_NFE)
etree.SubElement(raiz, 'idLote').text = str(1) # numero autoincremental gerado pelo sistema etree.SubElement(raiz, 'idLote').text = str(1) # numero autoincremental gerado pelo sistema
evento = etree.SubElement(raiz, 'evento')
etree.SubElement(evento, 'versao').text = '1' # versao do leiaute do evento (cancelamento = 1)
etree.SubElement(raiz, 'infEvento').text = xml # Evento, um lote pode conter até 20 eventos
dados = etree.tostring(raiz, encoding="unicode")
xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='RecepcaoEvento'), metodo='RecepcaoEvento', dados=dados)
xml = str(xml).replace('&amp;','').replace('lt;','<').replace('gt;','>').replace('&','')
return xml
#return self._post(url, xml)
raiz.append(evento)
xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='RecepcaoEvento'), metodo='RecepcaoEvento', dados=raiz)
return self._post(url, xml)
def status_servico(self, modelo): def status_servico(self, modelo):
""" Verifica status do servidor da receita. """ """ Verifica status do servidor da receita. """
@ -178,6 +168,27 @@ class ComunicacaoSefaz(Comunicacao):
return retorno return retorno
def _get_url(self, modelo, consulta): def _get_url(self, modelo, consulta):
# RS utiliza um formato de url diferente dos outros estados
if self.uf.upper() == 'RS':
if modelo == 'nfe':
if consulta == 'CADASTRO':
self.url = 'https://cad.' + NFE[self.uf.upper()][consulta]
else:
# nfe Ex: https://nfe.fazenda.pr.gov.br/nfe/NFeStatusServico3
if self._ambiente == 1:
self.url = 'https://nfe.' + NFE[self.uf.upper()][consulta]
else:
self.url = 'https://nfe-homologacao.' + NFE[self.uf.upper()][consulta]
elif modelo == 'nfce':
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
if self._ambiente == 1:
self.url = 'https://nfce.' + NFCE[self.uf.upper()][consulta]
else:
self.url = 'https://nfce-homologacao.' + NFCE[self.uf.upper()][consulta]
else:
# TODO implementar outros tipos de notas como NFS-e
pass
else:
if self._ambiente == 1: if self._ambiente == 1:
ambiente = 'https://' ambiente = 'https://'
else: else:
@ -197,6 +208,9 @@ class ComunicacaoSefaz(Comunicacao):
u"""Monta o XML do cabeçalho da requisição SOAP""" u"""Monta o XML do cabeçalho da requisição SOAP"""
raiz = etree.Element('nfeCabecMsg', xmlns=NAMESPACE_METODO+metodo) raiz = etree.Element('nfeCabecMsg', xmlns=NAMESPACE_METODO+metodo)
if metodo == 'RecepcaoEvento':
etree.SubElement(raiz, 'versaoDados').text = '1.00'
else:
etree.SubElement(raiz, 'versaoDados').text = VERSAO_PADRAO etree.SubElement(raiz, 'versaoDados').text = VERSAO_PADRAO
etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()] etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()]
return raiz return raiz

36
pynfe/processamento/serializacao.py

@ -488,28 +488,28 @@ class SerializacaoXML(Serializacao):
else: else:
return raiz return raiz
def _serializar_evento(self, evento, tag_raiz='infEvento', retorna_string=False):
def _serializar_evento(self, evento, tag_raiz='evento', retorna_string=False):
# timezone Brasília -03:00 # timezone Brasília -03:00
tz = time.strftime("%z") tz = time.strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:]) tz = "{}:{}".format(tz[:-2], tz[-2:])
raiz = etree.Element(tag_raiz)
etree.SubElement(raiz, 'Id').text = evento.id
etree.SubElement(raiz, 'cOrgao').text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente)
etree.SubElement(raiz, 'CNPJ').text = evento.cnpj
#etree.SubElement(raiz, 'CPF').text = ''
etree.SubElement(raiz, 'chNFe').text = evento.chave
etree.SubElement(raiz, 'dhEvento').text = evento.data_emissao.strftime('%Y-%m-%dT%H:%M:%S') + tz
etree.SubElement(raiz, 'tpEvento').text = evento.tp_evento
etree.SubElement(raiz, 'nSeqEvento').text = evento.n_seq_evento
etree.SubElement(raiz, 'verEvento').text = evento.ver_evento
etree.SubElement(raiz, 'detEvento').text = evento.det_evento
etree.SubElement(raiz, 'versao').text = evento.versao
etree.SubElement(raiz, 'descEvento').text = evento.descricao
etree.SubElement(raiz, 'nPro').text = evento.protocolo
etree.SubElement(raiz, 'xJust').text = evento.justificativa
#import ipdb
#ipdb.set_trace()
raiz = etree.Element(tag_raiz, versao='1.00', xmlns=NAMESPACE_NFE)
e = etree.SubElement(raiz, 'infEvento', Id=evento.identificador)
etree.SubElement(e, 'cOrgao').text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, 'tpAmb').text = str(self._ambiente)
etree.SubElement(e, 'CNPJ').text = evento.cnpj # Empresas somente terão CNPJ
#etree.SubElement(evento, 'CPF').text = ''
etree.SubElement(e, 'chNFe').text = evento.chave
etree.SubElement(e, 'dhEvento').text = evento.data_emissao.strftime('%Y-%m-%dT%H:%M:%S') + tz
etree.SubElement(e, 'tpEvento').text = evento.tp_evento
etree.SubElement(e, 'nSeqEvento').text = evento.n_seq_evento
etree.SubElement(e, 'verEvento').text = '1.00'
det = etree.SubElement(e, 'detEvento', versao='1.00')
etree.SubElement(det, 'descEvento').text = evento.descricao
etree.SubElement(det, 'nProt').text = evento.protocolo
etree.SubElement(det, 'xJust').text = evento.justificativa
if retorna_string: if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=True) return etree.tostring(raiz, encoding="unicode", pretty_print=True)

42
pynfe/utils/webservices.py

@ -182,12 +182,12 @@ NFCE = {
'EVENTOS': '' 'EVENTOS': ''
}, },
'RS': { 'RS': {
'STATUS': '',
'AUTORIZACAO': '',
'RECIBO': '',
'CHAVE': '',
'INUTILIZACAO': '',
'EVENTOS': ''
'STATUS': 'sefazrs.rs.gov.br/ws/NfeStatusServico/NfeStatusServico2.asmx',
'AUTORIZACAO': 'sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao.asmx',
'RECIBO': 'sefazrs.rs.gov.br/ws/NfeRetAutorizacao/NFeRetAutorizacao.asmx',
'CHAVE': 'sefazrs.rs.gov.br/ws/NfeConsulta/NfeConsulta2.asmx',
'INUTILIZACAO': 'sefazrs.rs.gov.br/ws/nfeinutilizacao/nfeinutilizacao2.asmx',
'EVENTOS': 'sefazrs.rs.gov.br/ws/recepcaoevento/recepcaoevento.asmx'
}, },
'MS': { 'MS': {
'STATUS': '', 'STATUS': '',
@ -423,17 +423,27 @@ NFE = {
'EVENTOS': '', 'EVENTOS': '',
'CADASTRO': '' 'CADASTRO': ''
}, },
# 'RS': {
# 'STATUS': 'nfe.sefaz.rs.gov.br/ws/NfeStatusServico/NfeStatusServico2.asmx',
# 'AUTORIZACAO': 'nfe.sefaz.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao.asmx',
# 'RECIBO': 'nfe.sefaz.rs.gov.br/ws/NfeRetAutorizacao/NFeRetAutorizacao.asmx',
# 'CHAVE': 'nfe.sefaz.rs.gov.br/ws/NfeConsulta/NfeConsulta2.asmx',
# 'INUTILIZACAO': 'nfe.sefaz.rs.gov.br/ws/NfeInutilizacao/NfeInutilizacao2.asmx',
# 'EVENTOS': 'nfe.sefaz.rs.gov.br/ws/recepcaoevento/recepcaoevento.asmx',
# 'CADASTRO': 'nfe.sefaz.rs.gov.br/ws/cadconsultacadastro/cadconsultacadastro2.asmx',
# 'DOWNLOAD': 'nfe.sefaz.rs.gov.br/ws/nfeDownloadNF/nfeDownloadNF.asmx',
# 'DESTINADAS': 'nfe.sefaz.rs.gov.br/ws/nfeConsultaDest/nfeConsultaDest.asmx'
# },
'RS': { 'RS': {
'STATUS': 'nfe.sefaz.rs.gov.br/ws/NfeStatusServico/NfeStatusServico2.asmx',
'AUTORIZACAO': 'nfe.sefaz.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao.asmx',
'RECIBO': 'nfe.sefaz.rs.gov.br/ws/NfeRetAutorizacao/NFeRetAutorizacao.asmx',
'CHAVE': 'nfe.sefaz.rs.gov.br/ws/NfeConsulta/NfeConsulta2.asmx',
'INUTILIZACAO': 'nfe.sefaz.rs.gov.br/ws/NfeInutilizacao/NfeInutilizacao2.asmx',
'EVENTOS': 'nfe.sefaz.rs.gov.br/ws/recepcaoevento/recepcaoevento.asmx',
'CADASTRO': 'nfe.sefaz.rs.gov.br/ws/cadconsultacadastro/cadconsultacadastro2.asmx',
'EVENTOS': 'nfe.sefaz.rs.gov.br/ws/recepcaoevento/recepcaoevento.asmx',
'DOWNLOAD': 'nfe.sefaz.rs.gov.br/ws/nfeDownloadNF/nfeDownloadNF.asmx',
'DESTINADAS': 'nfe.sefaz.rs.gov.br/ws/nfeConsultaDest/nfeConsultaDest.asmx'
'STATUS': 'sefazrs.rs.gov.br/ws/NfeStatusServico/NfeStatusServico2.asmx',
'AUTORIZACAO': 'sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao.asmx',
'RECIBO': 'sefazrs.rs.gov.br/ws/NfeRetAutorizacao/NFeRetAutorizacao.asmx',
'CHAVE': 'sefazrs.rs.gov.br/ws/NfeConsulta/NfeConsulta2.asmx',
'INUTILIZACAO': 'sefazrs.rs.gov.br/ws/nfeinutilizacao/nfeinutilizacao2.asmx',
'EVENTOS': 'sefazrs.rs.gov.br/ws/recepcaoevento/recepcaoevento.asmx',
'CADASTRO': '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'
}, },
'MS': { 'MS': {
'STATUS': '', 'STATUS': '',

Loading…
Cancel
Save