Browse Source

Merge branch 'master' of https://github.com/leotada/PyNFe

pull/1/head
leotada 11 years ago
parent
commit
62eba54613
  1. 20
      pynfe/entidades/notafiscal.py
  2. 8
      pynfe/processamento/assinatura.py
  3. 89
      pynfe/processamento/comunicacao.py
  4. 168
      pynfe/processamento/serializacao.py
  5. 4
      pynfe/utils/webservices.py
  6. 5
      test.py

20
pynfe/entidades/notafiscal.py

@ -68,8 +68,20 @@ class NotaFiscal(Entidade):
cliente_final = int() cliente_final = int()
# - Indica se a compra foi feita presencialmente, telefone, internet, etc # - Indica se a compra foi feita presencialmente, telefone, internet, etc
"""
0=Não se aplica (por exemplo, Nota Fiscal complementar ou deajuste);
1=Operação presencial;
2=Operação não presencial, pela Internet;
3=Operação não presencial, Teleatendimento;
4=NFC-e em operação com entrega a domicílio;
9=Operação não presencial, outros.
"""
indicador_presencial = int() indicador_presencial = int()
""" nfce suporta apenas operação interna
Identificador de local de destino da operação 1=Operação interna;2=Operação interestadual;3=Operação com exterior.
"""
indicador_destino = int()
# - UF - converter para codigos em CODIGOS_ESTADOS # - UF - converter para codigos em CODIGOS_ESTADOS
uf = str() uf = str()
@ -351,8 +363,8 @@ class NotaFiscal(Entidade):
return obj return obj
def _codigo_numerico_aleatorio(self): def _codigo_numerico_aleatorio(self):
codigo_numerico_aleatorio = str(random.randint(0, 99999999)).zfill(8)
return codigo_numerico_aleatorio
self.codigo_numerico_aleatorio = str(random.randint(0, 99999999)).zfill(8)
return self.codigo_numerico_aleatorio
def _dv_codigo_numerico(self, key): def _dv_codigo_numerico(self, key):
assert len(key) == 43 assert len(key) == 43
@ -371,8 +383,8 @@ class NotaFiscal(Entidade):
remainder = key_sum % 11 remainder = key_sum % 11
if remainder == 0 or remainder == 1: if remainder == 0 or remainder == 1:
return '0' return '0'
dv_codigo_numerico_aleatorio = str(11 - remainder)
return str(dv_codigo_numerico_aleatorio)
self.dv_codigo_numerico_aleatorio = str(11 - remainder)
return str(self.dv_codigo_numerico_aleatorio)
@property @property
# @memoize # @memoize

8
pynfe/processamento/assinatura.py

@ -18,20 +18,21 @@ class Assinatura(object):
self.certificado = certificado self.certificado = certificado
self.senha = senha self.senha = senha
def assinar_nfe(self, xml):
"""Efetua a assinatura da nfe"""
def assinar(self, xml):
"""Efetua a assinatura da nota"""
pass pass
class AssinaturaA1(Assinatura): class AssinaturaA1(Assinatura):
"""Classe responsavel por efetuar a assinatura do certificado """Classe responsavel por efetuar a assinatura do certificado
digital no XML informado. Passar XML como string.""" digital no XML informado. Passar XML como string."""
def assinar_nfe(self, xml):
def assinar(self, xml):
arquivo_cert = CertificadoA1(self.certificado) arquivo_cert = CertificadoA1(self.certificado)
chave, cert = arquivo_cert.separar_arquivo(self.senha) chave, cert = arquivo_cert.separar_arquivo(self.senha)
#root = etree.parse(xml).getroot() # caminho #root = etree.parse(xml).getroot() # caminho
root = etree.fromstring(xml) # string root = etree.fromstring(xml) # string
#root = etree.XML(xml) # string
signer = signxml.xmldsig(root, digest_algorithm="sha1") signer = signxml.xmldsig(root, digest_algorithm="sha1")
signer.sign(method=signxml.methods.enveloped, key=chave, cert=cert, signer.sign(method=signxml.methods.enveloped, key=chave, cert=cert,
algorithm="rsa-sha1", c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315', algorithm="rsa-sha1", c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
@ -44,4 +45,5 @@ class AssinaturaA1(Assinatura):
.attrib['URI'] = '#chaveteste' .attrib['URI'] = '#chaveteste'
result = etree.tostring(root) result = etree.tostring(root)
return result return result

89
pynfe/processamento/comunicacao.py

@ -27,8 +27,27 @@ class ComunicacaoSefaz(Comunicacao):
_versao = VERSAO_PADRAO _versao = VERSAO_PADRAO
_assinatura = AssinaturaA1 _assinatura = AssinaturaA1
def autorizacao(self, nota_fiscal):
pass
def autorizacao(self, modelo, nota_fiscal):
# url do serviço
url = self._get_url(modelo=modelo, consulta='AUTORIZACAO')
# Monta XML do corpo da requisição
raiz = etree.Element('enviNFe')
etree.SubElement(raiz, 'versaoDados').text = self._versao
etree.SubElement(raiz, 'idLote').text = str(1) # numero autoincremental gerado pelo sistema
etree.SubElement(raiz, 'indSinc').text = str(1) # 0 para assincrono, 1 para sincrono
etree.SubElement(raiz, 'NFe').text = nota_fiscal # conjunto de nfe tramistidas (max 50)
import ipdb
#ipdb.set_trace()
print (type(nota_fiscal))
dados = etree.tostring(raiz, encoding="unicode")
print (dados)
print (type(dados))
#print (dados)
# Monta XML para envio da requisição
xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(), dados=dados, url=url)
return xml
#return self._post(url, xml, self._post_header())
def cancelar(self, nota_fiscal): def cancelar(self, nota_fiscal):
pass pass
@ -41,29 +60,19 @@ class ComunicacaoSefaz(Comunicacao):
""" tipo é a string com tipo de serviço que deseja consultar """ tipo é a string com tipo de serviço que deseja consultar
Ex: nfe ou nfce Ex: nfe ou nfce
""" """
if self._ambiente == 1:
ambiente = 'https://'
else:
ambiente = 'https://homologacao.'
if tipo == 'nfe':
# nfe Ex: https://nfe.fazenda.pr.gov.br/nfe/NFeStatusServico3
url = ambiente + NFE[self.uf.upper()]['STATUS']
elif tipo == 'nfce':
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
url = ambiente + NFCE[self.uf.upper()]['STATUS']
else:
# TODO implementar outros tipos de notas como NFS-e
pass
url = self._get_url(tipo=tipo, consulta='STATUS')
# Monta XML do corpo da requisição # Monta XML do corpo da requisição
raiz = etree.Element('consStatServ', versao='3.10', xmlns=NAMESPACE_NFE) raiz = etree.Element('consStatServ', versao='3.10', xmlns=NAMESPACE_NFE)
etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente)
etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()] etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()]
etree.SubElement(raiz, 'xServ').text = 'STATUS' etree.SubElement(raiz, 'xServ').text = 'STATUS'
dados = etree.tostring(raiz, encoding='UTF-8')
dados = etree.tostring(raiz, encoding="UTF-8").decode('utf-8')
# Monta XML para envio da requisição # Monta XML para envio da requisição
xml = self._construir_xml_soap(cabecalho=self._cabecalho_soap(), dados=dados, url=url)
if self.uf.upper() == 'PR':
xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(), dados=dados, url=url)
else:
xml = self._construir_xml_soap(cabecalho=self._cabecalho_soap(), metodo='nfeRecepcao2', tag_metodo='nfeStatusServicoNF2', dados=dados)
# Chama método que efetua a requisição POST no servidor SOAP # Chama método que efetua a requisição POST no servidor SOAP
return self._post(url, xml, self._post_header()) return self._post(url, xml, self._post_header())
@ -71,8 +80,7 @@ class ComunicacaoSefaz(Comunicacao):
#post = '/nfeweb/services/cadconsultacadastro.asmx' #post = '/nfeweb/services/cadconsultacadastro.asmx'
post = '/nfeweb/services/nfeconsulta.asmx' post = '/nfeweb/services/nfeconsulta.asmx'
def inutilizar_faixa_numeracao(self, numero_inicial, numero_final, emitente, certificado,
senha, ano=None, serie='1', justificativa=''):
def inutilizar_faixa_numeracao(self, numero_inicial, numero_final, emitente, certificado, senha, ano=None, serie='1', justificativa=''):
post = '/nfeweb/services/nfestatusservico.asmx' post = '/nfeweb/services/nfestatusservico.asmx'
# Valores default # Valores default
@ -127,6 +135,22 @@ class ComunicacaoSefaz(Comunicacao):
return retorno return retorno
def _get_url(self, modelo, consulta):
if self._ambiente == 1:
ambiente = 'https://'
else:
ambiente = 'https://homologacao.'
if modelo == 'nfe':
# nfe Ex: https://nfe.fazenda.pr.gov.br/nfe/NFeStatusServico3
url = ambiente + NFE[self.uf.upper()][consulta]
elif modelo == 'nfce':
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
url = ambiente + NFCE[self.uf.upper()][consulta]
else:
# TODO implementar outros tipos de notas como NFS-e
pass
return url
def _cabecalho_soap(self): def _cabecalho_soap(self):
u"""Monta o XML do cabeçalho da requisição SOAP""" u"""Monta o XML do cabeçalho da requisição SOAP"""
@ -134,9 +158,24 @@ class ComunicacaoSefaz(Comunicacao):
etree.SubElement(raiz, 'cUF').text = str(41) etree.SubElement(raiz, 'cUF').text = str(41)
etree.SubElement(raiz, 'versaoDados').text = VERSAO_PADRAO etree.SubElement(raiz, 'versaoDados').text = VERSAO_PADRAO
return etree.tostring(raiz, encoding='UTF-8')
return etree.tostring(raiz, encoding="unicode")
def _construir_xml_soap(self, cabecalho, metodo, tag_metodo, dados):
"""Mota o XML para o envio via SOAP"""
raiz = etree.Element('{%s}Envelope'%NAMESPACE_SOAP, nsmap={'soap': NAMESPACE_SOAP})
body = etree.SubElement(raiz, '{%s}Body'%NAMESPACE_SOAP)
met = etree.SubElement(
body, tag_metodo, xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/%s"%metodo,
)
etree.SubElement(met, 'nfeCabecMsg').text = cabecalho
etree.SubElement(met, 'nfeDadosMsg').text = dados
return etree.tostring(raiz, encoding="unicode", xml_declaration=True)
def _construir_xml_soap(self, cabecalho, dados, url):
def _construir_xml_status_pr(self, cabecalho, dados, url):
u"""Mota o XML para o envio via SOAP""" u"""Mota o XML para o envio via SOAP"""
raiz = etree.Element('{%s}Envelope'%NAMESPACE_SOAP, nsmap={'soap': NAMESPACE_SOAP}, xmlns=url) raiz = etree.Element('{%s}Envelope'%NAMESPACE_SOAP, nsmap={'soap': NAMESPACE_SOAP}, xmlns=url)
@ -144,7 +183,7 @@ class ComunicacaoSefaz(Comunicacao):
body = etree.SubElement(raiz, '{%s}Body'%NAMESPACE_SOAP) body = etree.SubElement(raiz, '{%s}Body'%NAMESPACE_SOAP)
etree.SubElement(body, 'nfeDadosMsg').text = dados etree.SubElement(body, 'nfeDadosMsg').text = dados
return etree.tostring(raiz, encoding='UTF-8', xml_declaration=True)
return etree.tostring(raiz, encoding="UTF-8", xml_declaration=True).decode('utf-8')
def _post_header(self): def _post_header(self):
u"""Retorna um dicionário com os atributos para o cabeçalho da requisição HTTP""" u"""Retorna um dicionário com os atributos para o cabeçalho da requisição HTTP"""
@ -155,7 +194,7 @@ class ComunicacaoSefaz(Comunicacao):
u'Accept': u'application/soap+xml; charset=utf-8', u'Accept': u'application/soap+xml; charset=utf-8',
} }
def _post(self, post, xml, header):
def _post(self, url, xml, header):
# Separa arquivos de certificado para chave e certificado (sozinho) # Separa arquivos de certificado para chave e certificado (sozinho)
#caminho_chave, caminho_cert = self.certificado.separar_arquivo(senha=self.certificado_senha) #caminho_chave, caminho_cert = self.certificado.separar_arquivo(senha=self.certificado_senha)
caminho_chave = '/home/junior/Documentos/Certificados/key.pem' caminho_chave = '/home/junior/Documentos/Certificados/key.pem'
@ -167,7 +206,7 @@ class ComunicacaoSefaz(Comunicacao):
#headers = {'content-type': 'text/xml'} #headers = {'content-type': 'text/xml'}
try: try:
r = requests.post(post, s, headers=self._post_header(), cert=cert, verify=False)
r = requests.post(url, s, headers=self._post_header(), cert=cert, verify=False)
print (r.content) print (r.content)
if r == 200: if r == 200:
return r.text return r.text

168
pynfe/processamento/serializacao.py

@ -1,12 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time import time
try:
set
except:
from sets import Set as set
from pynfe.entidades import Emitente, Cliente, Produto, Transportadora, NotaFiscal
from pynfe.excecoes import NenhumObjetoEncontrado, MuitosObjetosEncontrados
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, safe_str, obter_uf_por_codigo, obter_codigo_por_municipio formatar_decimal, safe_str, obter_uf_por_codigo, obter_codigo_por_municipio
@ -62,7 +58,7 @@ class SerializacaoXML(Serializacao):
raiz.append(self._serializar_nota_fiscal(nf, retorna_string=False)) raiz.append(self._serializar_nota_fiscal(nf, retorna_string=False))
if retorna_string: if retorna_string:
return etree.tostring(raiz, pretty_print=True).decode('utf-8')
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else: else:
return raiz return raiz
@ -97,18 +93,19 @@ class SerializacaoXML(Serializacao):
etree.SubElement(endereco, 'fone').text = emitente.endereco_telefone etree.SubElement(endereco, 'fone').text = emitente.endereco_telefone
if retorna_string: if retorna_string:
return etree.tostring(raiz, pretty_print=True)
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else: else:
return raiz return raiz
def _serializar_cliente(self, cliente, tag_raiz='dest', retorna_string=True):
def _serializar_cliente(self, cliente, modelo, tag_raiz='dest', retorna_string=True):
raiz = etree.Element(tag_raiz) raiz = etree.Element(tag_raiz)
# Dados do cliente
# Dados do cliente (distinatario)
etree.SubElement(raiz, cliente.tipo_documento).text = so_numeros(cliente.numero_documento) etree.SubElement(raiz, cliente.tipo_documento).text = so_numeros(cliente.numero_documento)
etree.SubElement(raiz, 'xNome').text = cliente.razao_social etree.SubElement(raiz, 'xNome').text = cliente.razao_social
etree.SubElement(raiz, 'IE').text = cliente.inscricao_estadual
# nfc-e nao possui IE mesmo que seja uma empresa
if modelo == 55:
etree.SubElement(raiz, 'IE').text = cliente.inscricao_estadual
# Endereço # Endereço
endereco = etree.SubElement(raiz, 'enderDest') endereco = etree.SubElement(raiz, 'enderDest')
etree.SubElement(endereco, 'xLgr').text = cliente.endereco_logradouro etree.SubElement(endereco, 'xLgr').text = cliente.endereco_logradouro
@ -125,7 +122,7 @@ class SerializacaoXML(Serializacao):
etree.SubElement(endereco, 'fone').text = cliente.endereco_telefone etree.SubElement(endereco, 'fone').text = cliente.endereco_telefone
if retorna_string: if retorna_string:
return etree.tostring(raiz, pretty_print=True)
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else: else:
return raiz return raiz
@ -146,7 +143,7 @@ class SerializacaoXML(Serializacao):
etree.SubElement(raiz, 'UF').text = transportadora.endereco_uf etree.SubElement(raiz, 'UF').text = transportadora.endereco_uf
if retorna_string: if retorna_string:
return etree.tostring(raiz, pretty_print=True)
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else: else:
return raiz return raiz
@ -168,11 +165,11 @@ class SerializacaoXML(Serializacao):
etree.SubElement(raiz, 'UF').text = entrega_retirada.endereco_uf etree.SubElement(raiz, 'UF').text = entrega_retirada.endereco_uf
if retorna_string: if retorna_string:
return etree.tostring(raiz, pretty_print=True)
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else: else:
return raiz return raiz
def _serializar_produto_servico(self, produto_servico, tag_raiz='det', retorna_string=True):
def _serializar_produto_servico(self, produto_servico, modelo, tag_raiz='det', retorna_string=True):
raiz = etree.Element(tag_raiz) raiz = etree.Element(tag_raiz)
# Produto # Produto
@ -202,22 +199,24 @@ class SerializacaoXML(Serializacao):
etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota)
etree.SubElement(icms_item, 'vICMS').text = str(produto_servico.icms_valor) etree.SubElement(icms_item, 'vICMS').text = str(produto_servico.icms_valor)
pis = etree.SubElement(imposto, 'PIS')
pis_item = etree.SubElement(pis, 'PISAliq')
etree.SubElement(pis_item, 'CST').text = str(produto_servico.pis_situacao_tributaria)
etree.SubElement(pis_item, 'vBC').text = str(produto_servico.pis_valor_base_calculo)
etree.SubElement(pis_item, 'pPIS').text = str(produto_servico.pis_aliquota_percentual)
etree.SubElement(pis_item, 'vPIS').text = str(produto_servico.pis_valor)
cofins = etree.SubElement(imposto, 'COFINS')
cofins_item = etree.SubElement(cofins, 'COFINSAliq')
etree.SubElement(cofins_item, 'CST').text = str(produto_servico.cofins_situacao_tributaria)
etree.SubElement(cofins_item, 'vBC').text = str(produto_servico.cofins_valor_base_calculo)
etree.SubElement(cofins_item, 'pCOFINS').text = str(produto_servico.cofins_aliquota_percentual)
etree.SubElement(cofins_item, 'vCOFINS').text = str(produto_servico.cofins_valor)
# apenas nfe
if modelo == 55:
pis = etree.SubElement(imposto, 'PIS')
pis_item = etree.SubElement(pis, 'PISAliq')
etree.SubElement(pis_item, 'CST').text = str(produto_servico.pis_situacao_tributaria)
etree.SubElement(pis_item, 'vBC').text = str(produto_servico.pis_valor_base_calculo)
etree.SubElement(pis_item, 'pPIS').text = str(produto_servico.pis_aliquota_percentual)
etree.SubElement(pis_item, 'vPIS').text = str(produto_servico.pis_valor)
cofins = etree.SubElement(imposto, 'COFINS')
cofins_item = etree.SubElement(cofins, 'COFINSAliq')
etree.SubElement(cofins_item, 'CST').text = str(produto_servico.cofins_situacao_tributaria)
etree.SubElement(cofins_item, 'vBC').text = str(produto_servico.cofins_valor_base_calculo)
etree.SubElement(cofins_item, 'pCOFINS').text = str(produto_servico.cofins_aliquota_percentual)
etree.SubElement(cofins_item, 'vCOFINS').text = str(produto_servico.cofins_valor)
if retorna_string: if retorna_string:
return etree.tostring(raiz, pretty_print=True)
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else: else:
return raiz return raiz
@ -250,7 +249,17 @@ class SerializacaoXML(Serializacao):
horário de verão serão -01:00, -02:00 e -03:00. Exemplo: "2010-08-19T13:00:15-03:00". horário de verão serão -01:00, -02:00 e -03:00. Exemplo: "2010-08-19T13:00:15-03:00".
""" """
etree.SubElement(ide, 'tpNF').text = str(nota_fiscal.tipo_documento) # 0=entrada 1=saida etree.SubElement(ide, 'tpNF').text = str(nota_fiscal.tipo_documento) # 0=entrada 1=saida
etree.SubElement(ide, 'idDest').text = str(1) # Identificador de local de destino da operação 1=Operação interna;2=Operação interestadual;3=Operação com exterior.
""" nfce suporta apenas operação interna
Identificador de local de destino da operação 1=Operação interna;2=Operação interestadual;3=Operação com exterior.
"""
if nota_fiscal.modelo == 65:
etree.SubElement(ide, 'idDest').text = str(1)
etree.SubElement(ide, 'indPres').text = str(1)
etree.SubElement(ide, 'indFinal').text = str(1)
else:
etree.SubElement(ide, 'idDest').text = str(nota_fiscal.indicador_destino)
etree.SubElement(ide, 'indPres').text = str(nota_fiscal.indicador_presencial)
etree.SubElement(ide, 'indFinal').text = str(nota_fiscal.cliente_final)
etree.SubElement(ide, 'cMunFG').text = nota_fiscal.municipio etree.SubElement(ide, 'cMunFG').text = nota_fiscal.municipio
etree.SubElement(ide, 'tpImp').text = str(nota_fiscal.tipo_impressao_danfe) etree.SubElement(ide, 'tpImp').text = str(nota_fiscal.tipo_impressao_danfe)
etree.SubElement(ide, 'tpEmis').text = str(nota_fiscal.forma_emissao) etree.SubElement(ide, 'tpEmis').text = str(nota_fiscal.forma_emissao)
@ -258,14 +267,16 @@ class SerializacaoXML(Serializacao):
etree.SubElement(ide, 'tpAmb').text = str(self._ambiente) etree.SubElement(ide, 'tpAmb').text = str(self._ambiente)
etree.SubElement(ide, 'finNFe').text = str(nota_fiscal.finalidade_emissao) etree.SubElement(ide, 'finNFe').text = str(nota_fiscal.finalidade_emissao)
etree.SubElement(ide, 'procEmi').text = str(nota_fiscal.processo_emissao) etree.SubElement(ide, 'procEmi').text = str(nota_fiscal.processo_emissao)
etree.SubElement(ide, 'verProc').text = '%s %s'%(self._nome_aplicacao,
nota_fiscal.versao_processo_emissao)
etree.SubElement(ide, 'verProc').text = '%s %s'%(self._nome_aplicacao, nota_fiscal.versao_processo_emissao)
### CONTINGENCIA ###
#etree.SubElement(ide, 'dhCont').text = '' # Data e Hora da entrada em contingência AAAA-MM-DDThh:mm:ssTZD
#etree.SubElement(ide, 'xJust').text = '' # Justificativa da entrada em contingência (min 20, max 256 caracteres)
# Emitente # Emitente
raiz.append(self._serializar_emitente(nota_fiscal.emitente, retorna_string=False)) raiz.append(self._serializar_emitente(nota_fiscal.emitente, retorna_string=False))
# Destinatário # Destinatário
raiz.append(self._serializar_cliente(nota_fiscal.cliente, retorna_string=False))
raiz.append(self._serializar_cliente(nota_fiscal.cliente, modelo=nota_fiscal.modelo, retorna_string=False))
# Retirada # Retirada
if nota_fiscal.retirada: if nota_fiscal.retirada:
@ -285,7 +296,7 @@ class SerializacaoXML(Serializacao):
# Itens # Itens
for num, item in enumerate(nota_fiscal.produtos_e_servicos): for num, item in enumerate(nota_fiscal.produtos_e_servicos):
det = self._serializar_produto_servico(item, retorna_string=False)
det = self._serializar_produto_servico(item, modelo=nota_fiscal.modelo, retorna_string=False)
det.attrib['nItem'] = str(num+1) det.attrib['nItem'] = str(num+1)
raiz.append(det) raiz.append(det)
@ -301,50 +312,55 @@ class SerializacaoXML(Serializacao):
etree.SubElement(icms_total, 'vFrete').text = str(nota_fiscal.totais_icms_total_frete) etree.SubElement(icms_total, 'vFrete').text = str(nota_fiscal.totais_icms_total_frete)
etree.SubElement(icms_total, 'vSeg').text = str(nota_fiscal.totais_icms_total_seguro) etree.SubElement(icms_total, 'vSeg').text = str(nota_fiscal.totais_icms_total_seguro)
etree.SubElement(icms_total, 'vDesc').text = str(nota_fiscal.totais_icms_total_desconto) etree.SubElement(icms_total, 'vDesc').text = str(nota_fiscal.totais_icms_total_desconto)
etree.SubElement(icms_total, 'vII').text = str(nota_fiscal.totais_icms_total_ii)
etree.SubElement(icms_total, 'vIPI').text = str(nota_fiscal.totais_icms_total_ipi)
etree.SubElement(icms_total, 'vPIS').text = str(nota_fiscal.totais_icms_pis)
etree.SubElement(icms_total, 'vCOFINS').text = str(nota_fiscal.totais_icms_cofins)
etree.SubElement(icms_total, 'vOutro').text = str(nota_fiscal.totais_icms_outras_despesas_acessorias) etree.SubElement(icms_total, 'vOutro').text = str(nota_fiscal.totais_icms_outras_despesas_acessorias)
etree.SubElement(icms_total, 'vNF').text = str(nota_fiscal.totais_icms_total_nota) etree.SubElement(icms_total, 'vNF').text = str(nota_fiscal.totais_icms_total_nota)
# Transporte
transp = etree.SubElement(raiz, 'transp')
etree.SubElement(transp, 'modFrete').text = str(nota_fiscal.transporte_modalidade_frete)
# Transportadora
if nota_fiscal.transporte_transportadora:
transp.append(self._serializar_transportadora(
nota_fiscal.transporte_transportadora,
retorna_string=False,
))
# Veículo
veiculo = etree.SubElement(transp, 'veicTransp')
etree.SubElement(veiculo, 'placa').text = nota_fiscal.transporte_veiculo_placa
etree.SubElement(veiculo, 'UF').text = nota_fiscal.transporte_veiculo_uf
etree.SubElement(veiculo, 'RNTC').text = nota_fiscal.transporte_veiculo_rntc
# Reboque
reboque = etree.SubElement(transp, 'reboque')
etree.SubElement(reboque, 'placa').text = nota_fiscal.transporte_reboque_placa
etree.SubElement(reboque, 'UF').text = nota_fiscal.transporte_reboque_uf
etree.SubElement(reboque, 'RNTC').text = nota_fiscal.transporte_reboque_rntc
# Volumes
for volume in nota_fiscal.transporte_volumes:
vol = etree.SubElement(transp, 'vol')
etree.SubElement(vol, 'qVol').text = str(volume.quantidade)
etree.SubElement(vol, 'esp').text = volume.especie
etree.SubElement(vol, 'marca').text = volume.marca
etree.SubElement(vol, 'nVol').text = volume.numeracao
etree.SubElement(vol, 'pesoL').text = str(volume.peso_liquido)
etree.SubElement(vol, 'pesoB').text = str(volume.peso_bruto)
# Lacres
lacres = etree.SubElement(vol, 'lacres')
for lacre in volume.lacres:
etree.SubElement(lacres, 'nLacre').text = lacre.numero_lacre
# Apenas NF-e
if nota_fiscal.modelo == 55:
# Tributos
etree.SubElement(icms_total, 'vIPI').text = str(nota_fiscal.totais_icms_total_ipi)
etree.SubElement(icms_total, 'vPIS').text = str(nota_fiscal.totais_icms_pis)
etree.SubElement(icms_total, 'vCOFINS').text = str(nota_fiscal.totais_icms_cofins)
etree.SubElement(icms_total, 'vII').text = str(nota_fiscal.totais_icms_total_ii)
# Transporte
transp = etree.SubElement(raiz, 'transp')
etree.SubElement(transp, 'modFrete').text = str(nota_fiscal.transporte_modalidade_frete)
# Transportadora
if nota_fiscal.transporte_transportadora:
transp.append(self._serializar_transportadora(
nota_fiscal.transporte_transportadora,
retorna_string=False,
))
# Veículo
veiculo = etree.SubElement(transp, 'veicTransp')
etree.SubElement(veiculo, 'placa').text = nota_fiscal.transporte_veiculo_placa
etree.SubElement(veiculo, 'UF').text = nota_fiscal.transporte_veiculo_uf
etree.SubElement(veiculo, 'RNTC').text = nota_fiscal.transporte_veiculo_rntc
# Reboque
reboque = etree.SubElement(transp, 'reboque')
etree.SubElement(reboque, 'placa').text = nota_fiscal.transporte_reboque_placa
etree.SubElement(reboque, 'UF').text = nota_fiscal.transporte_reboque_uf
etree.SubElement(reboque, 'RNTC').text = nota_fiscal.transporte_reboque_rntc
# Volumes
for volume in nota_fiscal.transporte_volumes:
vol = etree.SubElement(transp, 'vol')
etree.SubElement(vol, 'qVol').text = str(volume.quantidade)
etree.SubElement(vol, 'esp').text = volume.especie
etree.SubElement(vol, 'marca').text = volume.marca
etree.SubElement(vol, 'nVol').text = volume.numeracao
etree.SubElement(vol, 'pesoL').text = str(volume.peso_liquido)
etree.SubElement(vol, 'pesoB').text = str(volume.peso_bruto)
# Lacres
lacres = etree.SubElement(vol, 'lacres')
for lacre in volume.lacres:
etree.SubElement(lacres, 'nLacre').text = lacre.numero_lacre
# Informações adicionais # Informações adicionais
info_ad = etree.SubElement(raiz, 'infAdic') info_ad = etree.SubElement(raiz, 'infAdic')
@ -352,7 +368,7 @@ class SerializacaoXML(Serializacao):
etree.SubElement(info_ad, 'infCpl').text = nota_fiscal.informacoes_complementares_interesse_contribuinte etree.SubElement(info_ad, 'infCpl').text = nota_fiscal.informacoes_complementares_interesse_contribuinte
if retorna_string: if retorna_string:
return etree.tostring(raiz, pretty_print=True)
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
else: else:
return raiz return raiz

4
pynfe/utils/webservices.py

@ -1,4 +1,8 @@
"""
@author: Junior Tada, Leonardo Tada
"""
# Nfc-e # Nfc-e
NFCE = { NFCE = {
'RO': { 'RO': {

5
test.py

@ -8,8 +8,7 @@ from pynfe.entidades.cliente import Cliente
from pynfe.entidades.emitente import Emitente from pynfe.entidades.emitente import Emitente
from pynfe.entidades.notafiscal import NotaFiscal, NotaFiscalProduto from pynfe.entidades.notafiscal import NotaFiscal, NotaFiscalProduto
from pynfe.entidades.fonte_dados import _fonte_dados from pynfe.entidades.fonte_dados import _fonte_dados
from pynfe.processamento.serializacao import SerializacaoPipes, SerializacaoXML
from pynfe.processamento.validacao import Validacao
from pynfe.processamento.serializacao import SerializacaoXML
from pynfe.processamento.assinatura import AssinaturaA1 from pynfe.processamento.assinatura import AssinaturaA1
from pynfe.utils.flags import CODIGO_BRASIL from pynfe.utils.flags import CODIGO_BRASIL
import datetime import datetime
@ -60,7 +59,7 @@ nota_fiscal = NotaFiscal(
codigo_numerico_aleatorio='66998237', codigo_numerico_aleatorio='66998237',
natureza_operacao='VENDA', natureza_operacao='VENDA',
forma_pagamento='1', forma_pagamento='1',
modelo=55,
modelo=65,
serie='1', serie='1',
numero_nf='1', numero_nf='1',
data_emissao=datetime.datetime.now(), data_emissao=datetime.datetime.now(),

Loading…
Cancel
Save