Compare commits
merge into: felipe:master
felipe:feature/betha
felipe:feature/cte
felipe:feature/nfe-4.0
felipe:feature/nfe-mde
felipe:feature/nota-dsf
felipe:fix-endereco
felipe:fix-invalid-token-bug
felipe:fix-url-df
felipe:fix/warning
felipe:iss-net
felipe:master
felipe:master3
felipe:merge-master3
pull from: felipe:iss-net
felipe:feature/betha
felipe:feature/cte
felipe:feature/nfe-4.0
felipe:feature/nfe-mde
felipe:feature/nota-dsf
felipe:fix-endereco
felipe:fix-invalid-token-bug
felipe:fix-url-df
felipe:fix/warning
felipe:iss-net
felipe:master
felipe:master3
felipe:merge-master3
205 Commits
172 changed files with 14259 additions and 10094 deletions
-
6.flake8
-
8.gitignore
-
10.travis.yml
-
125README.md
-
7cidades/dsf.md
-
165docs/conf.py
-
1222pytrustnfe/Servidores.py
-
8pytrustnfe/__init__.py
-
23pytrustnfe/certificado.py
-
36pytrustnfe/client.py
-
4pytrustnfe/exceptions.py
-
501pytrustnfe/nfe/__init__.py
-
29pytrustnfe/nfe/assinatura.py
-
34pytrustnfe/nfe/comunicacao.py
-
529pytrustnfe/nfe/danfce.py
-
1268pytrustnfe/nfe/danfe.py
-
BINpytrustnfe/nfe/fonts/NimbusSanL Bold.ttf
-
BINpytrustnfe/nfe/fonts/NimbusSanL Regular.ttf
-
45pytrustnfe/nfe/patch.py
-
33pytrustnfe/nfe/templates/NFeDistribuicaoDFe.xml
-
279pytrustnfe/nfe/templates/NfeAutorizacao.xml
-
5pytrustnfe/nfe/templates/NfeConsultaProtocolo.xml
-
2pytrustnfe/nfe/templates/NfeInutilizacao.xml
-
2pytrustnfe/nfe/templates/NfeRetAutorizacao.xml
-
4pytrustnfe/nfe/templates/NfeStatusServico.xml
-
6pytrustnfe/nfe/templates/RecepcaoEvento.xml
-
21pytrustnfe/nfe/templates/RecepcaoEventoCarta.xml
-
31pytrustnfe/nfe/templates/RecepcaoEventoEPEC.xml
-
2pytrustnfe/nfe/templates/RecepcaoEventoManifesto.xml
-
76pytrustnfe/nfse/aparecida/__init__.py
-
91pytrustnfe/nfse/aparecida/templates/Rps.xml
-
15pytrustnfe/nfse/aparecida/templates/cancelarNfse.xml
-
7pytrustnfe/nfse/aparecida/templates/consultarLoteRps.xml
-
13pytrustnfe/nfse/aparecida/templates/recepcionarLoteRps.xml
-
99pytrustnfe/nfse/assinatura.py
-
78pytrustnfe/nfse/betha/__init__.py
-
79pytrustnfe/nfse/bh/__init__.py
-
47pytrustnfe/nfse/bh/assinatura.py
-
13pytrustnfe/nfse/bh/templates/CancelarNfse.xml
-
11pytrustnfe/nfse/bh/templates/GerarNfse.xml
-
91pytrustnfe/nfse/bh/templates/Rps.xml
-
69pytrustnfe/nfse/carioca/__init__.py
-
13pytrustnfe/nfse/carioca/templates/CancelarNfse.xml
-
3pytrustnfe/nfse/carioca/templates/GerarNfse.xml
-
91pytrustnfe/nfse/carioca/templates/Rps.xml
-
124pytrustnfe/nfse/dsf/__init__.py
-
18pytrustnfe/nfse/dsf/templates/cancelar.xml
-
11pytrustnfe/nfse/dsf/templates/consulta_notas.xml
-
10pytrustnfe/nfse/dsf/templates/consultarLote.xml
-
22pytrustnfe/nfse/dsf/templates/consultarNFSeRps.xml
-
100pytrustnfe/nfse/dsf/templates/enviar.xml
-
12pytrustnfe/nfse/dsf/templates/soap_header.xml
-
128pytrustnfe/nfse/floripa/__init__.py
-
7pytrustnfe/nfse/floripa/templates/cancelar_nota.xml
-
41pytrustnfe/nfse/floripa/templates/processar_nota.xml
-
86pytrustnfe/nfse/ginfes/__init__.py
-
74pytrustnfe/nfse/imperial/__init__.py
-
17pytrustnfe/nfse/imperial/templates/CANCELANOTAELETRONICA.xml
-
9pytrustnfe/nfse/imperial/templates/CONSULTANOTASPROTOCOLO.xml
-
9pytrustnfe/nfse/imperial/templates/CONSULTAPROTOCOLO.xml
-
14pytrustnfe/nfse/imperial/templates/CancelarNota.xml
-
43pytrustnfe/nfse/imperial/templates/GerarNota.xml
-
81pytrustnfe/nfse/imperial/templates/PROCESSARPS.xml
-
5pytrustnfe/nfse/imperial/templates/SoapRequest.xml
-
81pytrustnfe/nfse/issnet/__init__.py
-
13pytrustnfe/nfse/issnet/templates/CancelarNfse.xml
-
7pytrustnfe/nfse/issnet/templates/ConsultarLoteRps.xml
-
13pytrustnfe/nfse/issnet/templates/RecepcionarLoteRps.xml
-
91pytrustnfe/nfse/issnet/templates/Rps.xml
-
70pytrustnfe/nfse/mga/__init__.py
-
48pytrustnfe/nfse/mga/assinatura.py
-
15pytrustnfe/nfse/mga/templates/CancelarNfse.xml
-
3pytrustnfe/nfse/mga/templates/GerarNfse.xml
-
81pytrustnfe/nfse/mga/templates/Rps.xml
-
116pytrustnfe/nfse/natal/__init__.py
-
8pytrustnfe/nfse/natal/templates/EnvelopeSoap.xml
-
111pytrustnfe/nfse/natal/templates/Exemplo_LoteRPS.xml
-
112pytrustnfe/nfse/natal/templates/Rps.xml
-
3pytrustnfe/nfse/natal/templates/cabecalho.xml
-
15pytrustnfe/nfse/natal/templates/cancelarNfse.xml
-
7pytrustnfe/nfse/natal/templates/consultarLoteRps.xml
-
11pytrustnfe/nfse/natal/templates/recepcionarLoteRps.xml
-
73pytrustnfe/nfse/paulistana/__init__.py
-
23pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml
-
62pytrustnfe/nfse/paulistana/templates/EnvioRPS.xml
-
66pytrustnfe/nfse/simpliss/__init__.py
-
36pytrustnfe/nfse/susesu/__init__.py
-
9pytrustnfe/nfse/susesu/templates/EnviarNota.xml
-
1pytrustnfe/test/XMLs/paulistana_resultado.xml
-
34pytrustnfe/test/test_add_qr_code.py
-
57pytrustnfe/test/test_assinatura.py
-
82pytrustnfe/test/test_certificado.py
-
20pytrustnfe/test/test_comunicacao.py
-
19pytrustnfe/test/test_consulta_cadastro.py
-
143pytrustnfe/test/test_nfse_paulistana.py
-
48pytrustnfe/test/test_servidores.py
-
119pytrustnfe/test/test_utils.py
-
37pytrustnfe/test/test_xml_serializacao.py
-
189pytrustnfe/test/xml_com_qrcode.xml
-
190pytrustnfe/test/xml_sem_qrcode.xml
@ -0,0 +1,6 @@ |
|||
[flake8] |
|||
ignore = E203, E266, E501, W503, F403, E402, E265, E231 |
|||
max-line-length = 79 |
|||
max-complexity = 18 |
|||
select = B,C,E,F,W,T4,B9 |
|||
exclude = .git,__pycache__,api/specs/,migrations/ |
|||
@ -0,0 +1,7 @@ |
|||
* Belém - PA |
|||
* Sorocaba - SP |
|||
* Teresina - PI |
|||
* Campinas - SP |
|||
* Uberlandia - MG |
|||
* São Luis - MA |
|||
* Campo Grande - MS |
|||
1222
pytrustnfe/Servidores.py
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,243 +1,378 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
|
|||
import os |
|||
import hashlib |
|||
import os |
|||
import requests |
|||
from lxml import etree |
|||
from .comunicacao import executar_consulta |
|||
from .patch import has_patch |
|||
from .assinatura import Assinatura |
|||
from pytrustnfe.xml import render_xml |
|||
from pytrustnfe.utils import CabecalhoSoap |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.utils import gerar_chave, ChaveNFe |
|||
from pytrustnfe.Servidores import localizar_url, localizar_qrcode |
|||
from pytrustnfe.xml.validate import valida_nfe |
|||
from pytrustnfe.exceptions import NFeValidationException |
|||
|
|||
|
|||
def _build_header(method, **kwargs): |
|||
action = { |
|||
'NfeAutorizacao': ('NfeAutorizacao', '3.10'), |
|||
'NfeRetAutorizacao': ('NfeRetAutorizacao', '3.10'), |
|||
'NfeConsultaCadastro': ('CadConsultaCadastro2', '2.00'), |
|||
'NfeInutilizacao': ('NfeInutilizacao2', '3.10'), |
|||
'RecepcaoEventoCancelamento': ('RecepcaoEvento', '1.00'), |
|||
'RecepcaoEventoCarta': ('RecepcaoEvento', '1.00'), |
|||
'NFeDistribuicaoDFe': ('NFeDistribuicaoDFe/nfeDistDFeInteresse', |
|||
'1.00'), |
|||
'RecepcaoEventoManifesto': ('RecepcaoEvento', '1.00'), |
|||
} |
|||
vals = {'estado': kwargs['estado'], |
|||
'soap_action': action[method][0], |
|||
'versao': action[method][1]} |
|||
return CabecalhoSoap(**vals) |
|||
from pytrustnfe.Servidores import localizar_url |
|||
from pytrustnfe.urls import url_qrcode, url_qrcode_exibicao |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from requests.packages.urllib3.exceptions import InsecureRequestWarning |
|||
# Zeep |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
|
|||
|
|||
def _generate_nfe_id(**kwargs): |
|||
for item in kwargs['NFes']: |
|||
for item in kwargs["NFes"]: |
|||
vals = { |
|||
'cnpj': item['infNFe']['emit']['cnpj_cpf'], |
|||
'estado': item['infNFe']['ide']['cUF'], |
|||
'emissao': '%s%s' % (item['infNFe']['ide']['dhEmi'][2:4], |
|||
item['infNFe']['ide']['dhEmi'][5:7]), |
|||
'modelo': item['infNFe']['ide']['mod'], |
|||
'serie': item['infNFe']['ide']['serie'], |
|||
'numero': item['infNFe']['ide']['nNF'], |
|||
'tipo': item['infNFe']['ide']['tpEmis'], |
|||
'codigo': item['infNFe']['ide']['cNF'], |
|||
"cnpj": item["infNFe"]["emit"]["cnpj_cpf"], |
|||
"estado": item["infNFe"]["ide"]["cUF"], |
|||
"emissao": "%s%s" |
|||
% ( |
|||
item["infNFe"]["ide"]["dhEmi"][2:4], |
|||
item["infNFe"]["ide"]["dhEmi"][5:7], |
|||
), |
|||
"modelo": item["infNFe"]["ide"]["mod"], |
|||
"serie": item["infNFe"]["ide"]["serie"], |
|||
"numero": item["infNFe"]["ide"]["nNF"], |
|||
"tipo": item["infNFe"]["ide"]["tpEmis"], |
|||
"codigo": item["infNFe"]["ide"]["cNF"], |
|||
} |
|||
chave_nfe = ChaveNFe(**vals) |
|||
chave_nfe = gerar_chave(chave_nfe, 'NFe') |
|||
item['infNFe']['Id'] = chave_nfe |
|||
item['infNFe']['ide']['cDV'] = chave_nfe[len(chave_nfe) - 1:] |
|||
|
|||
|
|||
def _add_required_node(elemTree): |
|||
ns = elemTree.nsmap |
|||
if None in ns: |
|||
ns['ns'] = ns[None] |
|||
ns.pop(None) |
|||
|
|||
prods = elemTree.findall('ns:NFe/ns:infNFe/ns:det/ns:prod', namespaces=ns) |
|||
for prod in prods: |
|||
element = prod.find('ns:cEAN', namespaces=ns) |
|||
if element is None: |
|||
cEan = etree.Element('cEAN') |
|||
prod.insert(1, cEan) |
|||
element = prod.find('ns:cEANTrib', namespaces=ns) |
|||
if element is None: |
|||
cEANTrib = etree.Element('cEANTrib') |
|||
vProd = prod.find('ns:vProd', namespaces=ns) |
|||
prod.insert(prod.index(vProd) + 1, cEANTrib) |
|||
return elemTree |
|||
|
|||
|
|||
def _add_qrCode(xml, **kwargs): |
|||
xml = etree.fromstring(xml) |
|||
inf_nfe = kwargs['NFes'][0]['infNFe'] |
|||
nfe = xml.find(".//{http://www.portalfiscal.inf.br/nfe}NFe") |
|||
infnfesupl = etree.Element('infNFeSupl') |
|||
qrcode = etree.Element('qrCode') |
|||
chave_nfe = inf_nfe['Id'][3:] |
|||
dh_emissao = inf_nfe['ide']['dhEmi'].encode('hex') |
|||
versao = '100' |
|||
ambiente = kwargs['ambiente'] |
|||
valor_total = inf_nfe['total']['vNF'] |
|||
dest_cpf = 'Inexistente' |
|||
dest = nfe.find(".//{http://www.portalfiscal.inf.br/nfe}dest") |
|||
if dest: |
|||
dest_parent = dest.getparent() |
|||
dest_parent.remove(dest) |
|||
if inf_nfe.get('dest', False): |
|||
if inf_nfe['dest'].get('CPF', False): |
|||
dest_cpf = inf_nfe['dest']['CPF'] |
|||
dest = etree.Element('dest') |
|||
cpf = etree.Element('CPF') |
|||
cpf.text = dest_cpf |
|||
dest.append(cpf) |
|||
dest_parent.append(dest) |
|||
icms_total = inf_nfe['total']['vICMS'] |
|||
dig_val = xml.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}DigestValue")\ |
|||
.text.encode('hex') |
|||
cid_token = kwargs['NFes'][0]['infNFe']['codigo_seguranca']['cid_token'] |
|||
csc = kwargs['NFes'][0]['infNFe']['codigo_seguranca']['csc'] |
|||
|
|||
c_hash_QR_code = "chNFe={0}&nVersao={1}&tpAmb={2}&cDest={3}&dhEmi={4}&vNF\ |
|||
={5}&vICMS={6}&digVal={7}&cIdToken={8}{9}".\ |
|||
format(chave_nfe, versao, ambiente, dest_cpf, dh_emissao, |
|||
valor_total, icms_total, dig_val, cid_token, csc) |
|||
c_hash_QR_code = hashlib.sha1(c_hash_QR_code).hexdigest() |
|||
|
|||
QR_code_url = "?chNFe={0}&nVersao={1}&tpAmb={2}&{3}dhEmi={4}&vNF={5}&vICMS\ |
|||
={6}&digVal={7}&cIdToken={8}&cHashQRCode={9}".\ |
|||
format(chave_nfe, versao, ambiente, |
|||
'cDest={}&'.format(dest_cpf) if dest_cpf != 'Inexistente' |
|||
else '', dh_emissao, valor_total, icms_total, dig_val, |
|||
cid_token, c_hash_QR_code) |
|||
qr_code_server = localizar_qrcode(kwargs['estado'], ambiente) |
|||
qrcode_text = qr_code_server + QR_code_url |
|||
qrcode.text = etree.CDATA(qrcode_text) |
|||
infnfesupl.append(qrcode) |
|||
nfe.insert(1, infnfesupl) |
|||
return etree.tostring(xml) |
|||
chave_nfe = gerar_chave(chave_nfe, "NFe") |
|||
item["infNFe"]["Id"] = chave_nfe |
|||
item["infNFe"]["ide"]["cDV"] = chave_nfe[len(chave_nfe) - 1 :] |
|||
|
|||
|
|||
def _send(certificado, method, sign, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), 'templates') |
|||
xmlElem_send = render_xml(path, '%s.xml' % method, True, **kwargs) |
|||
def _render(certificado, method, sign, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xmlElem_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
modelo = xmlElem_send.find(".//{http://www.portalfiscal.inf.br/nfe}mod") |
|||
modelo = modelo.text if modelo is not None else '55' |
|||
if modelo == '65': |
|||
pagamento = etree.Element('pag') |
|||
tipo_pagamento = etree.Element('tPag') |
|||
valor = etree.Element('vPag') |
|||
valor_pago = kwargs['NFes'][0]['infNFe']['total']['vNF'] |
|||
metodo_pagamento = kwargs['NFes'][0]['infNFe']['pagamento'] |
|||
tipo_pagamento.text, valor.text = metodo_pagamento, valor_pago |
|||
pagamento.append(tipo_pagamento) |
|||
pagamento.append(valor) |
|||
transp = xmlElem_send.find( |
|||
".//{http://www.portalfiscal.inf.br/nfe}transp") |
|||
transp.addnext(pagamento) |
|||
modelo = modelo.text if modelo is not None else "55" |
|||
|
|||
if sign: |
|||
# Caso for autorização temos que adicionar algumas tags tipo |
|||
# cEan, cEANTrib porque o governo sempre complica e não segue padrão |
|||
if method == 'NfeAutorizacao': |
|||
xmlElem_send = _add_required_node(xmlElem_send) |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
if method == 'NfeInutilizacao': |
|||
xml_send = signer.assina_xml(xmlElem_send, kwargs['obj']['id']) |
|||
if method == 'NfeAutorizacao': |
|||
xml_send = signer.assina_xml( |
|||
xmlElem_send, kwargs['NFes'][0]['infNFe']['Id']) |
|||
if 'validate' in kwargs: |
|||
erros = valida_nfe(xml_send) |
|||
if erros: |
|||
raise NFeValidationException('Erro ao validar NFe', |
|||
erros=erros, |
|||
sent_xml=xml_send) |
|||
elif method == 'RecepcaoEventoCancelamento': |
|||
xml_send = signer.assina_xml( |
|||
xmlElem_send, kwargs['eventos'][0]['Id']) |
|||
|
|||
if method == 'RecepcaoEventoCarta': |
|||
if method == "NfeInutilizacao": |
|||
xml_send = signer.assina_xml(xmlElem_send, kwargs["obj"]["id"]) |
|||
if method == "NfeAutorizacao": |
|||
xml_send = signer.assina_xml( |
|||
xmlElem_send, kwargs['Id']) |
|||
elif method == 'RecepcaoEventoManifesto': |
|||
xmlElem_send, kwargs["NFes"][0]["infNFe"]["Id"] |
|||
) |
|||
elif method == "RecepcaoEvento": |
|||
xml_send = signer.assina_xml(xmlElem_send, kwargs["eventos"][0]["Id"]) |
|||
elif method == "RecepcaoEventoManifesto": |
|||
xml_send = signer.assina_xml( |
|||
xmlElem_send, kwargs['manifesto']['identificador']) |
|||
|
|||
if modelo == '65': |
|||
xml_send = _add_qrCode(xml_send, **kwargs) |
|||
xmlElem_send, kwargs["manifesto"]["identificador"] |
|||
) |
|||
|
|||
else: |
|||
xml_send = etree.tostring(xmlElem_send) |
|||
xml_send = etree.tostring(xmlElem_send, encoding=str) |
|||
return xml_send |
|||
|
|||
|
|||
def gerar_qrcode(id_csc: int, csc: str, xml_send: str, cert = False) -> str: |
|||
xml = etree.fromstring(xml_send) |
|||
signature = xml.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}Signature") |
|||
id = xml.find( |
|||
".//{http://www.portalfiscal.inf.br/nfe}infNFe").get('Id') |
|||
if id is None: |
|||
raise Exception("XML Invalido - Sem o ID") |
|||
|
|||
chave = id.replace('NFe', '') |
|||
emit_uf = chave[:2] |
|||
|
|||
tp_amb = xml.find(".//{http://www.portalfiscal.inf.br/nfe}tpAmb") |
|||
if tp_amb is None: |
|||
raise Exception("XML Invalido - Sem o tipo de ambiente") |
|||
|
|||
dh_emi = xml.find(".//{http://www.portalfiscal.inf.br/nfe}dhEmi") |
|||
if dh_emi is None: |
|||
raise Exception("XML Invalido - Sem data de Emissao") |
|||
dh_emi = dh_emi.text.split("-")[2].split("T")[0] |
|||
|
|||
tp_emis = xml.find(".//{http://www.portalfiscal.inf.br/nfe}tpEmis") |
|||
if tp_emis is None: |
|||
raise Exception("XML Invalido - Sem tipo de emissao") |
|||
|
|||
v_nf = xml.find(".//{http://www.portalfiscal.inf.br/nfe}vNF") |
|||
if v_nf is None: |
|||
raise Exception("XML Invalido - Sem o valor da NFe") |
|||
|
|||
url_qrcode_str = url_qrcode( |
|||
estado=emit_uf, |
|||
ambiente=tp_amb.text) |
|||
url_qrcode_exibicao_str = url_qrcode_exibicao( |
|||
estado=emit_uf, |
|||
ambiente=tp_amb.text) |
|||
|
|||
if tp_emis != 1: |
|||
if signature is None: |
|||
if cert is not False: |
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xmlElem_send, id) |
|||
else: |
|||
raise Exception("XML Invalido - Sem assinatura e não " |
|||
"foi enviado o certificado nos parametros") |
|||
digest_value = xml.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}DigestValue") |
|||
c_hash_qr_code = \ |
|||
"{ch_acesso}|{versao}|{tp_amb}|{dh_emi}|" \ |
|||
"{v_nf}|{dig_val}|{id_csc}|{csc}".format( |
|||
ch_acesso=chave, |
|||
versao=2, |
|||
tp_amb=tp_amb.text, |
|||
dh_emi=dh_emi, |
|||
v_nf=float(v_nf.text), |
|||
dig_val=digest_value.text, |
|||
id_csc=int(id_csc), |
|||
csc=csc |
|||
) |
|||
c_hash_qr_code = hashlib.sha1(c_hash_qr_code.encode()). \ |
|||
hexdigest() |
|||
qr_code_url = 'p={ch_acesso}|{versao}|{tp_amb}|{dh_emi}|" \ |
|||
"{v_nf}|{dig_val}|{id_csc}|{hash}'.format( |
|||
ch_acesso=chave, |
|||
versao=2, |
|||
tp_amb=tp_amb.text, |
|||
dh_emi=dh_emi, |
|||
v_nf=float(v_nf.text), |
|||
dig_val=digest_value.text, |
|||
id_csc=int(id_csc), |
|||
hash=c_hash_qr_code |
|||
) |
|||
qrcode = url_qrcode_str + qr_code_url |
|||
url_consulta = url_qrcode_exibicao_str |
|||
|
|||
qrCode = xml.find( |
|||
'.//{http://www.portalfiscal.inf.br/nfe}qrCode').text = \ |
|||
qrcode |
|||
urlChave = xml.find( |
|||
'.//{http://www.portalfiscal.inf.br/nfe}urlChave').text = \ |
|||
url_consulta |
|||
else: |
|||
c_hash_qr_code = \ |
|||
"{ch_acesso}|{versao}|{tp_amb}|{id_csc}|{csc}".format( |
|||
ch_acesso=chave, |
|||
versao=2, |
|||
tp_amb=tp_amb.text, |
|||
id_csc=int(id_csc), |
|||
csc=csc |
|||
) |
|||
c_hash_qr_code = hashlib.sha1(c_hash_qr_code.encode()).hexdigest() |
|||
|
|||
qr_code_url = "p={ch_acesso}|{versao}|{tp_amb}|{id_csc}|" \ |
|||
"{hash}".\ |
|||
format( |
|||
ch_acesso=chave, |
|||
versao=2, |
|||
tp_amb=tp_amb.text, |
|||
id_csc=int(id_csc), |
|||
hash=c_hash_qr_code |
|||
) |
|||
qrcode = url_qrcode_str + qr_code_url |
|||
url_consulta = url_qrcode_exibicao_str |
|||
qrCode = xml.find( |
|||
'.//{http://www.portalfiscal.inf.br/nfe}qrCode').text = \ |
|||
qrcode |
|||
urlChave = xml.find( |
|||
'.//{http://www.portalfiscal.inf.br/nfe}urlChave').text = \ |
|||
url_consulta |
|||
return etree.tostring(xml) |
|||
|
|||
url = localizar_url(method, kwargs['estado'], modelo, |
|||
kwargs['ambiente']) |
|||
cabecalho = _build_header(method, **kwargs) |
|||
def _get_session(certificado): |
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
return session |
|||
|
|||
|
|||
def _get_client(base_url, transport): |
|||
client = Client(base_url, transport=transport) |
|||
port = next(iter(client.wsdl.port_types)) |
|||
first_operation = [ |
|||
x |
|||
for x in iter(client.wsdl.port_types[port].operations) |
|||
if "zip" not in x.lower() |
|||
][0] |
|||
return first_operation, client |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
xml_send = kwargs["xml"] |
|||
base_url = localizar_url( |
|||
method, kwargs["estado"], kwargs["modelo"], kwargs["ambiente"] |
|||
) |
|||
session = _get_session(certificado) |
|||
patch = has_patch(kwargs["estado"], method) |
|||
if patch: |
|||
return patch(session, xml_send, kwargs["ambiente"]) |
|||
transport = Transport(session=session) |
|||
first_op, client = _get_client(base_url, transport) |
|||
return _send_zeep(first_op, client, xml_send) |
|||
|
|||
|
|||
def _send_zeep(first_operation, client, xml_send): |
|||
parser = etree.XMLParser(strip_cdata=False) |
|||
xml = etree.fromstring(xml_send, parser=parser) |
|||
|
|||
namespaceNFe = xml.find(".//{http://www.portalfiscal.inf.br/nfe}NFe") |
|||
if namespaceNFe is not None: |
|||
namespaceNFe.set("xmlns", "http://www.portalfiscal.inf.br/nfe") |
|||
|
|||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) |
|||
with client.settings(raw_response=True): |
|||
response = client.service[first_operation](xml) |
|||
response, obj = sanitize_response(response.text) |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": response, |
|||
"object": obj.Body.getchildren()[0], |
|||
} |
|||
|
|||
send_raw = False |
|||
if method == 'NFeDistribuicaoDFe': |
|||
send_raw = True |
|||
|
|||
response, obj = executar_consulta(certificado, url, cabecalho, xml_send, |
|||
send_raw=send_raw) |
|||
return { |
|||
'sent_xml': xml_send, |
|||
'received_xml': response, |
|||
'object': obj |
|||
} |
|||
def xml_autorizar_nfe(certificado, **kwargs): |
|||
_generate_nfe_id(**kwargs) |
|||
return _render(certificado, "NfeAutorizacao", True, **kwargs) |
|||
|
|||
|
|||
def autorizar_nfe(certificado, **kwargs): # Assinar |
|||
_generate_nfe_id(**kwargs) |
|||
return _send(certificado, 'NfeAutorizacao', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_autorizar_nfe(certificado, **kwargs) |
|||
return _send(certificado, "NfeAutorizacao", **kwargs) |
|||
|
|||
|
|||
def xml_retorno_autorizar_nfe(certificado, **kwargs): |
|||
return _render(certificado, "NfeRetAutorizacao", False, **kwargs) |
|||
|
|||
|
|||
def retorno_autorizar_nfe(certificado, **kwargs): |
|||
return _send(certificado, 'NfeRetAutorizacao', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_retorno_autorizar_nfe(certificado, **kwargs) |
|||
return _send(certificado, "NfeRetAutorizacao", **kwargs) |
|||
|
|||
|
|||
def xml_recepcao_evento_cancelamento(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "RecepcaoEvento", True, **kwargs) |
|||
|
|||
|
|||
def recepcao_evento_cancelamento(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'RecepcaoEventoCancelamento', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcao_evento_cancelamento(certificado, **kwargs) |
|||
return _send(certificado, "RecepcaoEvento", **kwargs) |
|||
|
|||
|
|||
def xml_inutilizar_nfe(certificado, **kwargs): |
|||
return _render(certificado, "NfeInutilizacao", True, **kwargs) |
|||
|
|||
|
|||
def inutilizar_nfe(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_inutilizar_nfe(certificado, **kwargs) |
|||
return _send(certificado, "NfeInutilizacao", **kwargs) |
|||
|
|||
def inutilizar_nfe(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'NfeInutilizacao', True, **kwargs) |
|||
|
|||
def xml_consultar_protocolo_nfe(certificado, **kwargs): |
|||
return _render(certificado, "NfeConsultaProtocolo", False, **kwargs) |
|||
|
|||
|
|||
def consultar_protocolo_nfe(certificado, **kwargs): |
|||
return _send(certificado, 'NfeConsultaProtocolo', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_protocolo_nfe(certificado, **kwargs) |
|||
return _send(certificado, "NfeConsultaProtocolo", **kwargs) |
|||
|
|||
|
|||
def xml_nfe_status_servico(certificado, **kwargs): |
|||
return _render(certificado, "NfeStatusServico", False, **kwargs) |
|||
|
|||
|
|||
def nfe_status_servico(certificado, **kwargs): |
|||
return _send(certificado, 'NfeStatusServico', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_nfe_status_servico(certificado, **kwargs) |
|||
return _send(certificado, "NfeStatusServico", **kwargs) |
|||
|
|||
|
|||
def xml_consulta_cadastro(certificado, **kwargs): |
|||
return _render(certificado, "NfeConsultaCadastro", False, **kwargs) |
|||
|
|||
|
|||
def consulta_cadastro(certificado, **kwargs): |
|||
return _send(certificado, 'NfeConsultaCadastro', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consulta_cadastro(certificado, **kwargs) |
|||
kwargs["modelo"] = "55" |
|||
return _send(certificado, "NfeConsultaCadastro", **kwargs) |
|||
|
|||
|
|||
def xml_recepcao_evento_carta_correcao(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "RecepcaoEvento", True, **kwargs) |
|||
|
|||
|
|||
def recepcao_evento_carta_correcao(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'RecepcaoEventoCarta', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcao_evento_carta_correcao(certificado, **kwargs) |
|||
return _send(certificado, "RecepcaoEvento", **kwargs) |
|||
|
|||
|
|||
def xml_recepcao_evento_manifesto(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "RecepcaoEvento", True, **kwargs) |
|||
|
|||
|
|||
def recepcao_evento_manifesto(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'RecepcaoEventoManifesto', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcao_evento_manifesto(certificado, **kwargs) |
|||
return _send(certificado, "RecepcaoEvento", **kwargs) |
|||
|
|||
|
|||
def recepcao_evento_epec(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'RecepcaoEventoEPEC', True, **kwargs) |
|||
def xml_consulta_distribuicao_nfe(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "NFeDistribuicaoDFe", False, **kwargs) |
|||
|
|||
|
|||
def consulta_distribuicao_nfe(certificado, **kwargs): |
|||
return _send(certificado, 'NFeDistribuicaoDFe', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consulta_distribuicao_nfe(certificado, **kwargs) |
|||
return _send_v310(certificado, **kwargs) |
|||
|
|||
|
|||
def xml_download_nfe(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "NFeDistribuicaoDFe", False, **kwargs) |
|||
|
|||
|
|||
def download_nfe(certificado, **kwargs): |
|||
return _send(certificado, 'NFeDistribuicaoDFe', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_download_nfe(certificado, **kwargs) |
|||
return _send_v310(certificado, **kwargs) |
|||
|
|||
|
|||
def _send_v310(certificado, **kwargs): |
|||
xml_send = kwargs["xml"] |
|||
base_url = localizar_url( |
|||
"NFeDistribuicaoDFe", kwargs["estado"], kwargs["modelo"], kwargs["ambiente"] |
|||
) |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
xml = etree.fromstring(xml_send) |
|||
xml_um = etree.fromstring( |
|||
'<nfeCabecMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/"><cUF>AN</cUF><versaoDados>1.00</versaoDados></nfeCabecMsg>' |
|||
) |
|||
client = Client(base_url, transport=transport) |
|||
|
|||
port = next(iter(client.wsdl.port_types)) |
|||
first_operation = next(iter(client.wsdl.port_types[port].operations)) |
|||
with client.settings(raw_response=True): |
|||
response = client.service[first_operation]( |
|||
nfeDadosMsg=xml, _soapheaders=[xml_um] |
|||
) |
|||
response, obj = sanitize_response(response.text) |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": response, |
|||
"object": obj.Body.nfeDistDFeInteresseResponse.nfeDistDFeInteresseResult, |
|||
} |
|||
@ -1,34 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
|
|||
from pytrustnfe.client import HttpClient |
|||
from pytrustnfe.certificado import save_cert_key, extract_cert_and_key_from_pfx |
|||
|
|||
from ..xml import sanitize_response |
|||
|
|||
|
|||
def _soap_xml(body, cabecalho): |
|||
xml = '<?xml version="1.0" encoding="utf-8"?>' |
|||
xml += '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header>' |
|||
xml += '<nfeCabecMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/' + cabecalho.soap_action + '">' |
|||
xml += '<cUF>' + cabecalho.estado + '</cUF><versaoDados>' + cabecalho.versao + '</versaoDados></nfeCabecMsg></soap:Header><soap:Body>' |
|||
xml += '<nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/' + cabecalho.soap_action + '">' |
|||
xml += body |
|||
xml += '</nfeDadosMsg></soap:Body></soap:Envelope>' |
|||
return xml.rstrip('\n') |
|||
|
|||
|
|||
def executar_consulta(certificado, url, cabecalho, xmlEnviar, send_raw=False): |
|||
cert, key = extract_cert_and_key_from_pfx( |
|||
certificado.pfx, certificado.password) |
|||
cert_path, key_path = save_cert_key(cert, key) |
|||
client = HttpClient(url, cert_path, key_path) |
|||
|
|||
xml_enviar = _soap_xml(xmlEnviar, cabecalho) |
|||
if send_raw: |
|||
xml = '<?xml version="1.0" encoding="utf-8"?>' + xmlEnviar.rstrip('\n') |
|||
xml_enviar = xml |
|||
xml_retorno = client.post_soap(xml_enviar, cabecalho) |
|||
return sanitize_response(xml_retorno) |
|||
@ -0,0 +1,529 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2017 Johny Chen Jy, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
import re |
|||
from textwrap import wrap |
|||
from io import BytesIO |
|||
from reportlab.pdfbase import pdfmetrics |
|||
from reportlab.pdfbase.ttfonts import TTFont |
|||
from reportlab.lib import utils |
|||
from reportlab.pdfgen import canvas |
|||
from reportlab.lib.units import cm, mm |
|||
from reportlab.graphics.barcode import qr |
|||
from reportlab.graphics import renderPDF |
|||
from reportlab.graphics.shapes import Drawing |
|||
from reportlab.platypus import Table, TableStyle, Paragraph, Image |
|||
from reportlab.lib.enums import TA_CENTER |
|||
from reportlab.lib.styles import ParagraphStyle |
|||
|
|||
|
|||
def format_cnpj_cpf(value): |
|||
if len(value) < 12: # CPF |
|||
cValue = "%s.%s.%s-%s" % (value[:-8], value[-8:-5], value[-5:-2], value[-2:]) |
|||
else: |
|||
cValue = "%s.%s.%s/%s-%s" % ( |
|||
value[:-12], |
|||
value[-12:-9], |
|||
value[-9:-6], |
|||
value[-6:-2], |
|||
value[-2:], |
|||
) |
|||
return cValue |
|||
|
|||
|
|||
def getdateUTC(cDateUTC): |
|||
cDt = cDateUTC[0:10].split("-") |
|||
cDt.reverse() |
|||
return "/".join(cDt), cDateUTC[11:16] |
|||
|
|||
|
|||
def format_number(cNumber, precision=0, group_sep=".", decimal_sep=","): |
|||
if cNumber: |
|||
number = float(cNumber) |
|||
return ( |
|||
("{:,." + str(precision) + "f}") |
|||
.format(number) |
|||
.replace(",", "X") |
|||
.replace(".", ",") |
|||
.replace("X", ".") |
|||
) |
|||
return "" |
|||
|
|||
|
|||
def tagtext(oNode=None, cTag=None): |
|||
try: |
|||
xpath = ".//{http://www.portalfiscal.inf.br/nfe}%s" % (cTag) |
|||
cText = oNode.find(xpath).text |
|||
except: |
|||
cText = "" |
|||
return cText |
|||
|
|||
|
|||
def get_image(path, width=1 * cm): |
|||
img = utils.ImageReader(path) |
|||
iw, ih = img.getSize() |
|||
aspect = ih / float(iw) |
|||
return Image(path, width=width, height=(width * aspect)) |
|||
|
|||
|
|||
def format_telefone(telefone): |
|||
telefone = re.sub("[^0-9]", "", telefone) |
|||
if len(telefone) == 10: |
|||
telefone = "(%s) %s-%s" % (telefone[0:2], telefone[2:6], telefone[6:]) |
|||
elif len(telefone) == 11: |
|||
telefone = "(%s) %s-%s" % (telefone[0:2], telefone[2:7], telefone[7:]) |
|||
return telefone |
|||
|
|||
|
|||
class danfce(object): |
|||
def __init__(self, list_xml, logo=None, timezone=None): |
|||
dir_fonts = os.path.dirname(os.path.realpath(__file__)) |
|||
pdfmetrics.registerFont( |
|||
TTFont( |
|||
'NimbusSanL-Bold', |
|||
os.path.join(dir_fonts,'fonts/NimbusSanL Bold.ttf'))) |
|||
pdfmetrics.registerFont( |
|||
TTFont( |
|||
'NimbusSanL-Regu', |
|||
os.path.join(dir_fonts, 'fonts/NimbusSanL Regular.ttf'))) |
|||
self.current_font_size = 7 |
|||
self.current_font_name = "NimbusSanL-Regu" |
|||
|
|||
self.max_height = 840 |
|||
self.min_height = 1 |
|||
self.min_width = 5 |
|||
self.max_width = 200 |
|||
self.current_height = 840 |
|||
|
|||
self.oPDF_IO = BytesIO() |
|||
self.canvas = canvas.Canvas(self.oPDF_IO, pagesize=(7.2 * cm, 30 * cm)) |
|||
self.canvas.setTitle("DANFCE") |
|||
self.canvas.setLineWidth(0.5) |
|||
self.canvas.setFont(self.current_font_name, self.current_font_size) |
|||
|
|||
self.list_xml = list_xml |
|||
self.logo = logo |
|||
|
|||
self.nfce_generate() |
|||
|
|||
def ide_emit(self, oXML=None): |
|||
|
|||
elem_emit = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}emit") |
|||
|
|||
# Razão Social emitente |
|||
nomeEmpresa = tagtext(oNode=elem_emit, cTag="xFant") |
|||
self.drawTitle(nomeEmpresa, 10) |
|||
|
|||
if self.logo: |
|||
img = get_image(self.logo, width=10 * mm) |
|||
img.drawOn(self.canvas, 5, 830) |
|||
|
|||
cEnd = tagtext(oNode=elem_emit, cTag="xNome") + "<br />" |
|||
cEnd += "CNPJ: %s " % (format_cnpj_cpf(tagtext(oNode=elem_emit, cTag="CNPJ"))) |
|||
cEnd += "IE: %s" % (tagtext(oNode=elem_emit, cTag="IE")) + "<br />" |
|||
cEnd += ( |
|||
tagtext(oNode=elem_emit, cTag="xLgr") |
|||
+ ", " |
|||
+ tagtext(oNode=elem_emit, cTag="nro") |
|||
+ " - " |
|||
) |
|||
cEnd += ( |
|||
tagtext(oNode=elem_emit, cTag="xBairro") |
|||
+ "<br />" |
|||
+ tagtext(oNode=elem_emit, cTag="xMun") |
|||
+ " - " |
|||
) |
|||
cEnd += ( |
|||
tagtext(oNode=elem_emit, cTag="UF") |
|||
+ " - " |
|||
+ tagtext(oNode=elem_emit, cTag="CEP") |
|||
+ "<br />" |
|||
) |
|||
cEnd += "Fone: " + format_telefone(tagtext(oNode=elem_emit, cTag="fone")) |
|||
|
|||
self._drawCenteredParagraph(cEnd) |
|||
self.drawLine() |
|||
|
|||
def danfce_information(self, oXML=None): |
|||
el_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide") |
|||
tipo_emissao = tagtext(oNode=el_ide, cTag="tpEmis") |
|||
if tipo_emissao in ("5", "9"): |
|||
self.current_height -= 5 |
|||
self.drawTitle("EMITIDA EM CONTINGÊNCIA", 9, "NimbusSanL-Bold") |
|||
self.drawTitle("Pendente de autorização", 7, "NimbusSanL-Bold") |
|||
self.drawLine() |
|||
else: |
|||
self.drawTitle( |
|||
"DANFE NFC-e - Documento Auxiliar da Nota Fiscal de", |
|||
7, |
|||
"NimbusSanL-Bold", |
|||
) |
|||
|
|||
self.drawTitle("Consumidor Eletrônica", 7, "NimbusSanL-Bold") |
|||
|
|||
self.drawString("NFC-e não permite aproveitamento de crédito de ICMS", True) |
|||
self.drawLine() |
|||
|
|||
def produtos( |
|||
self, |
|||
oXML=None, |
|||
el_det=None, |
|||
oPaginator=None, |
|||
list_desc=None, |
|||
list_cod_prod=None, |
|||
): |
|||
|
|||
rows = [["Cód", "Descrição", "Qtde", "Un", "Unit.", "Total"]] |
|||
colWidths = (25, 90, 15, 15, 25, 25) |
|||
rowHeights = [7] |
|||
|
|||
for id in range(oPaginator[0], oPaginator[1]): |
|||
|
|||
item = el_det[id] |
|||
el_prod = item.find(".//{http://www.portalfiscal.inf.br/nfe}prod") |
|||
|
|||
cod = tagtext(oNode=el_prod, cTag="cProd") |
|||
descricao = tagtext(oNode=el_prod, cTag="xProd") |
|||
descricao = (descricao[:20] + "..") if len(descricao) > 20 else descricao |
|||
Un = tagtext(oNode=el_prod, cTag="uCom") |
|||
Un = (Un[:2]) if len(Un) > 2 else Un |
|||
qtde = format_number(tagtext(oNode=el_prod, cTag="qCom"), precision=2) |
|||
vl_unit = format_number(tagtext(oNode=el_prod, cTag="vUnCom"), precision=2) |
|||
vl_total = format_number(tagtext(oNode=el_prod, cTag="vProd"), precision=2) |
|||
|
|||
new_row = [cod, descricao, qtde, Un, vl_unit, vl_total] |
|||
|
|||
rows.append(new_row) |
|||
rowHeights.append(self.current_font_size + 2) |
|||
|
|||
self._draw_product_table(rows, colWidths, rowHeights) |
|||
|
|||
def _draw_product_table(self, rows, colWidths, rowHeights): |
|||
table = Table(rows, colWidths, tuple(rowHeights)) |
|||
table.setStyle( |
|||
TableStyle( |
|||
[ |
|||
("FONTSIZE", (0, 0), (-1, -1), 7), |
|||
("FONT", (0, 1), (-1, -1), "NimbusSanL-Regu"), |
|||
("FONT", (0, 0), (-1, 0), "NimbusSanL-Bold"), |
|||
("ALIGN", (0, 0), (-1, 0), "LEFT"), |
|||
("ALIGN", (1, 0), (-1, 0), "LEFT"), |
|||
("ALIGN", (2, 0), (-1, 0), "CENTER"), |
|||
("ALIGN", (3, 0), (-1, 0), "CENTER"), |
|||
("ALIGN", (0, 1), (-1, -1), "LEFT"), |
|||
("ALIGN", (1, 1), (-1, -1), "LEFT"), |
|||
("ALIGN", (2, 1), (-1, -1), "CENTER"), |
|||
("ALIGN", (3, 1), (-1, -1), "CENTER"), |
|||
] |
|||
) |
|||
) |
|||
|
|||
w, h = table.wrapOn(self.canvas, 200, 450) |
|||
table.drawOn(self.canvas, 0, self.current_height - (h * 1.2)) |
|||
self.current_height -= h * 1.1 |
|||
|
|||
def totais(self, oXML=None): |
|||
# Impostos |
|||
el_total = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}total") |
|||
|
|||
total_tributo = format_number( |
|||
tagtext(oNode=el_total, cTag="vTotTrib"), precision=2 |
|||
) |
|||
valor_total = format_number(tagtext(oNode=el_total, cTag="vProd"), precision=2) |
|||
desconto = format_number(tagtext(oNode=el_total, cTag="vDesc"), precision=2) |
|||
valor_a_pagar = format_number(tagtext(oNode=el_total, cTag="vNF"), precision=2) |
|||
el_pag = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}pag") |
|||
troco = tagtext(oNode=el_pag, cTag="vTroco") |
|||
|
|||
payment_method_list = { |
|||
"01": "Dinheiro", |
|||
"02": "Cheque", |
|||
"03": "Cartão de Crédito", |
|||
"04": "Cartão de Débito", |
|||
"05": "Crédito Loja", |
|||
"10": "Vale Alimentação", |
|||
"11": "Vale Refeição", |
|||
"12": "Vale Presente", |
|||
"13": "Vale Combustível", |
|||
"14": "Duplicata Mercantil", |
|||
"15": "Boleto Bancario", |
|||
"90": "Sem Pagamento", |
|||
"99": "Outros", |
|||
} |
|||
quant_produtos = len(oXML.findall(".//{http://www.portalfiscal.inf.br/nfe}det")) |
|||
|
|||
payment_methods = [] |
|||
for pagId, item in enumerate(el_pag): |
|||
payment = [] |
|||
tipo_pagamento = tagtext(oNode=item, cTag="tPag") |
|||
val = format_number(tagtext(oNode=item, cTag="vPag"), precision=2) |
|||
|
|||
method = payment_method_list.get(tipo_pagamento) |
|||
|
|||
payment.append(method) |
|||
payment.append(val) |
|||
payment_methods.append(payment) |
|||
|
|||
values = { |
|||
"quantidade_itens": quant_produtos, |
|||
"total_tributo": total_tributo, |
|||
"valor_total": valor_total, |
|||
"desconto": desconto, |
|||
"valor_a_pagar": valor_a_pagar, |
|||
"formas_de_pagamento": payment_methods, |
|||
"troco": troco, |
|||
} |
|||
|
|||
self.draw_totals_table(values) |
|||
|
|||
self.drawLine() |
|||
|
|||
def draw_totals_table(self, values): |
|||
rowHeights = [7, 7, 7, 7, 7] |
|||
data = [ |
|||
["QTD.TOTAL DE ITENS", values["quantidade_itens"]], |
|||
["VALOR TOTAL R$", values["valor_total"]], |
|||
["DESCONTO R$", values["desconto"]], |
|||
["VALOR A PAGAR R$", values["valor_a_pagar"]], |
|||
["FORMA DE PAGAMENTO", "VALOR PAGO R$"], |
|||
] |
|||
|
|||
for item in values["formas_de_pagamento"]: |
|||
data.append([item[0], item[1]]) |
|||
rowHeights.append(7) |
|||
data.append(["TROCO", format_number(values["troco"], precision=2)]) |
|||
rowHeights.append(7) |
|||
|
|||
table2 = Table(data, colWidths=(150, 50), rowHeights=tuple(rowHeights)) |
|||
table2.setStyle( |
|||
TableStyle( |
|||
[ |
|||
("FONTSIZE", (0, 0), (-1, -1), 7), |
|||
("FONT", (0, 0), (1, -1), "NimbusSanL-Regu"), |
|||
("FONT", (0, 4), (1, 4), "NimbusSanL-Bold"), |
|||
("ALIGN", (1, 0), (1, -1), "RIGHT"), |
|||
] |
|||
) |
|||
) |
|||
w, h = table2.wrapOn(self.canvas, 200, 450) |
|||
table2.drawOn(self.canvas, 0, self.current_height - (h * 1.1)) |
|||
self.current_height -= h |
|||
|
|||
def inf_authentication(self, oXML=None): |
|||
el_infNFe = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infNFe") |
|||
# n nfce, serie e data de solicitacao |
|||
el_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide") |
|||
|
|||
el_NFeSupl = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infNFeSupl") |
|||
|
|||
el_dest = el_infNFe.find(".//{http://www.portalfiscal.inf.br/nfe}dest") |
|||
# chave, n protocolo, data autorizacao |
|||
el_prot_nfe = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}protNFe") |
|||
|
|||
el_infAdic = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infAdic") |
|||
|
|||
url_chave = tagtext(oNode=el_NFeSupl, cTag="urlChave") |
|||
access_key = tagtext(oNode=el_prot_nfe, cTag="chNFe") |
|||
|
|||
frase_chave_acesso = ( |
|||
"Consulte pela Chave de Acesso em:<br />\ |
|||
%s<br />%s" |
|||
% (url_chave, access_key) |
|||
) |
|||
|
|||
qrcode = tagtext(oNode=el_NFeSupl, cTag="qrCode") |
|||
|
|||
cnpj = tagtext(oNode=el_dest, cTag="CNPJ") |
|||
cpf = tagtext(oNode=el_dest, cTag="CPF") |
|||
if cnpj: |
|||
cnpj_cpf = format_cnpj_cpf(cnpj) |
|||
cnpj_cpf = "CONSUMIDOR CNPJ: %s" % (cnpj) |
|||
elif cpf: |
|||
cnpj_cpf = format_cnpj_cpf(cpf) |
|||
cnpj_cpf = "CONSUMIDOR CPF: %s" % (cpf) |
|||
else: |
|||
cnpj_cpf = u"CONSUMIDOR NÃO IDENTIFICADO" |
|||
|
|||
nNFC = tagtext(oNode=el_ide, cTag="nNF") |
|||
serie = tagtext(oNode=el_ide, cTag="serie") |
|||
|
|||
dataSolicitacao = getdateUTC(tagtext(oNode=el_ide, cTag="dhEmi")) |
|||
dataSolicitacao = dataSolicitacao[0] + " " + dataSolicitacao[1] |
|||
|
|||
text = u"%s <br />%s <br />NFC-e nº%s Série %s %s<br />" % ( |
|||
frase_chave_acesso, |
|||
cnpj_cpf, |
|||
nNFC, |
|||
serie, |
|||
dataSolicitacao, |
|||
) |
|||
|
|||
self._drawCenteredParagraph(text) |
|||
|
|||
tipo_emissao = tagtext(oNode=el_ide, cTag="tpEmis") |
|||
if tipo_emissao in ("5", "9"): |
|||
self.current_height -= 8 |
|||
self.drawTitle("EMITIDA EM CONTINGÊNCIA", 9, "NimbusSanL-Bold") |
|||
self.drawTitle( |
|||
"Pendente de autorização - Via Consumidor", 7, "NimbusSanL-Bold" |
|||
) |
|||
else: |
|||
numProtocolo = tagtext(oNode=el_prot_nfe, cTag="nProt") |
|||
|
|||
dataAutorizacao = getdateUTC(tagtext(oNode=el_prot_nfe, cTag="dhRecbto")) |
|||
dataAutorizacao = dataAutorizacao[0] + " " + dataAutorizacao[1] |
|||
|
|||
text = "Protocolo de autorização: %s<br />Data de autorização %s<br />" % ( |
|||
numProtocolo, |
|||
dataAutorizacao, |
|||
) |
|||
self._drawCenteredParagraph(text) |
|||
|
|||
self.draw_qr_code(qrcode) |
|||
|
|||
infAdFisco = tagtext(oNode=el_infAdic, cTag="infAdFisco") |
|||
self._drawCenteredParagraph(infAdFisco) |
|||
|
|||
infCpl = tagtext(oNode=el_infAdic, cTag="infCpl") |
|||
self._drawCenteredParagraph(infCpl) |
|||
|
|||
def _drawCenteredParagraph(self, text): |
|||
|
|||
style = ParagraphStyle( |
|||
name="Normal", |
|||
fontName="NimbusSanL-Regu", |
|||
fontSize=7, |
|||
alignment=TA_CENTER, |
|||
leading=7, |
|||
) |
|||
|
|||
paragraph = Paragraph(text, style=style) |
|||
w, h = paragraph.wrapOn(self.canvas, 180, 300) |
|||
paragraph.drawOn(self.canvas, 10, self.current_height - h) |
|||
self.current_height -= h * 1.1 |
|||
|
|||
def drawString(self, string, centered=False): |
|||
if centered: |
|||
self.canvas.drawCentredString( |
|||
self.max_width / 2, self.current_height, string |
|||
) |
|||
self.current_height -= self.current_font_size |
|||
else: |
|||
self.canvas.drawString(self.min_width, self.current_height, string) |
|||
self.current_height -= self.current_font_size |
|||
|
|||
def drawTitle(self, string, size, font="NimbusSanL-Regu"): |
|||
self.canvas.setFont(font, size) |
|||
self.canvas.drawCentredString(self.max_width / 2, self.current_height, string) |
|||
self.current_height -= self.current_font_size |
|||
self.canvas.setFont(self.current_font_name, self.current_font_size) |
|||
|
|||
def drawLine(self): |
|||
self.canvas.line( |
|||
self.min_width, self.current_height, self.max_width, self.current_height |
|||
) |
|||
self.current_height -= self.current_font_size |
|||
|
|||
def draw_qr_code(self, string): |
|||
qr_code = qr.QrCodeWidget(string) |
|||
drawing = Drawing(23 * mm, 23 * mm) |
|||
drawing.add(qr_code) |
|||
renderPDF.draw(drawing, self.canvas, 20 * mm, self.current_height - 85) |
|||
self.current_height -= 85 |
|||
|
|||
def newpage(self): |
|||
self.current_height = self.max_height |
|||
self.Page += 1 |
|||
self.canvas.showPage() |
|||
|
|||
def nfce_generate(self): |
|||
for oXML in self.list_xml: |
|||
oXML_cobr = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}cobr") |
|||
|
|||
self.NrPages = 1 |
|||
self.Page = 1 |
|||
|
|||
# Calculando total linhas usadas para descrições dos itens |
|||
# Com bloco fatura, apenas 29 linhas para itens na primeira folha |
|||
nNr_Lin_Pg_1 = 34 if oXML_cobr is None else 30 |
|||
# [ rec_ini , rec_fim , lines , limit_lines ] |
|||
oPaginator = [[0, 0, 0, nNr_Lin_Pg_1]] |
|||
el_det = oXML.findall(".//{http://www.portalfiscal.inf.br/nfe}det") |
|||
if el_det is not None: |
|||
list_desc = [] |
|||
list_cod_prod = [] |
|||
nPg = 0 |
|||
for nId, item in enumerate(el_det): |
|||
el_prod = item.find(".//{http://www.portalfiscal.inf.br/nfe}prod") |
|||
infAdProd = item.find( |
|||
".//{http://www.portalfiscal.inf.br/nfe}infAdProd" |
|||
) |
|||
|
|||
list_ = wrap(tagtext(oNode=el_prod, cTag="xProd"), 56) |
|||
if infAdProd is not None: |
|||
list_.extend(wrap(infAdProd.text, 56)) |
|||
list_desc.append(list_) |
|||
|
|||
list_cProd = wrap(tagtext(oNode=el_prod, cTag="cProd"), 14) |
|||
list_cod_prod.append(list_cProd) |
|||
|
|||
# Nr linhas necessárias p/ descrição item |
|||
nLin_Itens = len(list_) |
|||
|
|||
if (oPaginator[nPg][2] + nLin_Itens) >= oPaginator[nPg][3]: |
|||
oPaginator.append([0, 0, 0, 77]) |
|||
nPg += 1 |
|||
oPaginator[nPg][0] = nId |
|||
oPaginator[nPg][1] = nId + 1 |
|||
oPaginator[nPg][2] = nLin_Itens |
|||
else: |
|||
# adiciona-se 1 pelo funcionamento de xrange |
|||
oPaginator[nPg][1] = nId + 1 |
|||
oPaginator[nPg][2] += nLin_Itens |
|||
|
|||
self.NrPages = len(oPaginator) # Calculando nr. páginas |
|||
|
|||
self.ide_emit(oXML=oXML) |
|||
# self.destinatario(oXML=oXML) |
|||
self.danfce_information(oXML=oXML) |
|||
|
|||
self.produtos( |
|||
oXML=oXML, |
|||
el_det=el_det, |
|||
oPaginator=oPaginator[0], |
|||
list_desc=list_desc, |
|||
list_cod_prod=list_cod_prod, |
|||
) |
|||
|
|||
self.drawLine() |
|||
|
|||
self.totais(oXML=oXML) |
|||
|
|||
self.inf_authentication(oXML=oXML) |
|||
|
|||
# Gera o restante das páginas do XML |
|||
for oPag in oPaginator[1:]: |
|||
if oPag: |
|||
self.newpage() |
|||
self.ide_emit(oXML=oXML) |
|||
# self.destinatario(oXML=oXML) |
|||
self.produtos( |
|||
oXML=oXML, |
|||
el_det=el_det, |
|||
oPaginator=oPag, |
|||
list_desc=list_desc, |
|||
list_cod_prod=list_cod_prod, |
|||
) |
|||
self.totais(oXML=oXML) |
|||
self.inf_authentication(oXML=oXML) |
|||
|
|||
self.newpage() |
|||
|
|||
self.canvas.save() |
|||
|
|||
def writeto_pdf(self, fileObj): |
|||
pdf_out = self.oPDF_IO.getvalue() |
|||
self.oPDF_IO.close() |
|||
fileObj.write(pdf_out) |
|||
1268
pytrustnfe/nfe/danfe.py
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,45 @@ |
|||
from ..Servidores import SIGLA_ESTADO |
|||
from pytrustnfe.xml import sanitize_response |
|||
|
|||
|
|||
def nfeInutilizacaoCE(session, xml_send, ambiente): |
|||
soap = ( |
|||
'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope"><Body>\ |
|||
<nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NFeInutilizacao4"\ |
|||
>' |
|||
+ xml_send |
|||
+ "</nfeDadosMsg></Body></Envelope>" |
|||
) |
|||
headers = { |
|||
"SOAPAction": "", |
|||
"Content-Type": 'application/soap+xml; charset="utf-8"', |
|||
} |
|||
if ambiente == 1: |
|||
response = session.post( |
|||
"https://nfe.sefaz.ce.gov.br/nfe4/services/NFeInutilizacao4", |
|||
data=soap, |
|||
headers=headers, |
|||
) |
|||
else: |
|||
response = session.post( |
|||
"https://nfeh.sefaz.ce.gov.br/nfe4/services/NFeInutilizacao4", |
|||
data=soap, |
|||
headers=headers, |
|||
) |
|||
response, obj = sanitize_response(response.text) |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": response, |
|||
"object": obj.Body.getchildren()[0], |
|||
} |
|||
|
|||
|
|||
methods = {"NfeInutilizacaoCE": nfeInutilizacaoCE} |
|||
|
|||
|
|||
def has_patch(cod_estado, metodo): |
|||
uf = SIGLA_ESTADO[cod_estado] |
|||
method = metodo + uf |
|||
if method in methods: |
|||
return methods[method] |
|||
return None |
|||
@ -1,19 +1,14 @@ |
|||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<Body> |
|||
<nfeDistDFeInteresse xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NFeDistribuicaoDFe"> |
|||
<nfeDadosMsg> |
|||
<distDFeInt xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.01"> |
|||
<tpAmb>{{ ambiente }}</tpAmb> |
|||
<cUFAutor>{{ estado }}</cUFAutor> |
|||
<CNPJ>{{ cnpj_cpf }}</CNPJ> |
|||
<distNSU> |
|||
<ultNSU>{{ ultimo_nsu }}</ultNSU> |
|||
</distNSU> |
|||
<consChNFe> |
|||
<chNFe>{{ chave_nfe }}</chNFe> |
|||
</consChNFe> |
|||
</distDFeInt> |
|||
</nfeDadosMsg> |
|||
</nfeDistDFeInteresse> |
|||
</Body> |
|||
</Envelope> |
|||
<distDFeInt xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.01"> |
|||
<tpAmb>{{ ambiente }}</tpAmb> |
|||
<cUFAutor>{{ estado }}</cUFAutor> |
|||
<CNPJ>{{ cnpj_cpf }}</CNPJ> |
|||
<distNSU> |
|||
<ultNSU>{{ ultimo_nsu }}</ultNSU> |
|||
</distNSU> |
|||
<consChNFe> |
|||
<chNFe>{{ chave_nfe }}</chNFe> |
|||
</consChNFe> |
|||
<consNSU> |
|||
<NSU>{{ nsu }}</NSU> |
|||
</consNSU> |
|||
</distDFeInt> |
|||
@ -1,6 +1,5 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<consSitNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.01"> |
|||
<consSitNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00"> |
|||
<tpAmb>{{ obj.ambiente }}</tpAmb> |
|||
<xServ>CONSULTAR</xServ> |
|||
<chNFe>{{ obj.chave_nfe }}</chNFe> |
|||
</consSitNFe> |
|||
</consSitNFe> |
|||
@ -1,4 +1,4 @@ |
|||
<consReciNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> |
|||
<consReciNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00"> |
|||
<tpAmb>{{ obj.ambiente }}</tpAmb> |
|||
<nRec>{{ obj.numero_recibo }}</nRec> |
|||
</consReciNFe> |
|||
@ -1,6 +1,6 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<consStatServ xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> |
|||
<consStatServ xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00"> |
|||
<tpAmb>{{ obj.ambiente }}</tpAmb> |
|||
<cUF>{{ obj.estado }}</cUF> |
|||
<xServ>STATUS</xServ> |
|||
</consStatServ> |
|||
</consStatServ> |
|||
@ -1,21 +0,0 @@ |
|||
<envEvento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"> |
|||
<idLote>{{ idLote }}</idLote> |
|||
<evento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"> |
|||
<infEvento Id="{{ Id }}"> |
|||
<cOrgao>{{ cOrgao }}</cOrgao> |
|||
<tpAmb>{{ tpAmb }}</tpAmb> |
|||
<CNPJ>{{ CNPJ }}</CNPJ> |
|||
<CPF>{{ CPF }}</CPF> |
|||
<chNFe>{{ chNFe }}</chNFe> |
|||
<dhEvento>{{ dhEvento }}</dhEvento> |
|||
<tpEvento>{{ tpEvento }}</tpEvento> |
|||
<nSeqEvento>{{ nSeqEvento }}</nSeqEvento> |
|||
<verEvento>1.00</verEvento> |
|||
<detEvento versao="1.00"> |
|||
<descEvento>Carta de Correção</descEvento> |
|||
<xCorrecao>{{ xCorrecao|normalize|escape }}</xCorrecao> |
|||
<xCondUso>A Carta de Correção é disciplinada pelo § 1º-A do art. 7º do Convênio S/N, de 15 de dezembro de 1970 e pode ser utilizada para regularização de erro ocorrido na emissão de documento fiscal, desde que o erro não esteja relacionado com: I - as variáveis que determinam o valor do imposto tais como: base de cálculo, alíquota, diferença de preço, quantidade, valor da operação ou da prestação; II - a correção de dados cadastrais que implique mudança do remetente ou do destinatário; III - a data de emissão ou de saída.</xCondUso> |
|||
</detEvento> |
|||
</infEvento> |
|||
</evento> |
|||
</envEvento> |
|||
@ -1,31 +0,0 @@ |
|||
<envEvento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"> |
|||
<idLote>00106151340701</idLote> |
|||
<evento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"> |
|||
<infEvento Id="ID1101403514081014278500019055001001061513407959995201"> |
|||
<cOrgao>91</cOrgao> |
|||
<tpAmb>2</tpAmb> |
|||
<CNPJ>10142785000190</CNPJ> |
|||
<chNFe>35140810142785000190550010010615134079599952</chNFe> |
|||
<dhEvento>2014-08-07T04:52:51-03:00</dhEvento> |
|||
<tpEvento>110140</tpEvento> |
|||
<nSeqEvento>1</nSeqEvento> |
|||
<verEvento>1.00</verEvento> |
|||
<detEvento versao="1.00"> |
|||
<descEvento>EPEC</descEvento> |
|||
<cOrgaoAutor>35</cOrgaoAutor> |
|||
<tpAutor>1</tpAutor> |
|||
<verAplic>1.26</verAplic> |
|||
<dhEmi>2014-08-07T00:00:00-03:00</dhEmi> |
|||
<tpNF>1</tpNF> |
|||
<IE>495171423115</IE> |
|||
<dest> |
|||
<UF>SP</UF> |
|||
<CPF>00000000191</CPF> |
|||
<vNF>86.00</vNF> |
|||
<vICMS>6.02</vICMS> |
|||
<vST>0</vST> |
|||
</dest> |
|||
</detEvento> |
|||
</infEvento> |
|||
</evento> |
|||
</envEvento> |
|||
@ -0,0 +1,76 @@ |
|||
# © 2019 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
from requests.packages.urllib3 import disable_warnings |
|||
|
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
return xml_send |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://aparecida.siltecnologia.com.br/tbw/services/Abrasf10?wsdl" |
|||
else: |
|||
base_url = "https://aparecida.siltecnologia.com.br/tbwhomologacao/services/Abrasf10?wsdl" |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
disable_warnings() |
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(base_url, transport=transport) |
|||
|
|||
xml_send = kwargs["xml"] |
|||
response = client.service[method](xml_send) |
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_recepcionar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "recepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def recepcionar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "recepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_consultar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "consultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def consultar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "consultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "cancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "cancelarNfse", **kwargs) |
|||
@ -0,0 +1,91 @@ |
|||
<Rps> |
|||
<InfRps Id="rps{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<RpsSubstituido> |
|||
<Numero>{{ rps.numero_substituido }}</Numero> |
|||
<Serie>{{ rps.serie_substituido }}</Serie> |
|||
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
|||
</RpsSubstituido> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
</Rps> |
|||
@ -0,0 +1,15 @@ |
|||
<CancelarNfseEnvio xmlns="http://nfse.abrasf.org.br"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="1"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>{{ cancelamento.codigo_cancelamento }}</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,7 @@ |
|||
<ConsultarLoteRpsEnvio xmlns="http://nfse.abrasf.org.br"> |
|||
<Prestador> |
|||
<Cnpj>{{ consulta.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ consulta.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
</ConsultarLoteRpsEnvio> |
|||
@ -0,0 +1,13 @@ |
|||
<EnviarLoteRpsEnvio> |
|||
<LoteRps Id="lote{{ nfse.numero_lote }}"> |
|||
<NumeroLote>{{ nfse.numero_lote }}</NumeroLote> |
|||
<Cnpj>{{ nfse.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ nfse.inscricao_municipal }}</InscricaoMunicipal> |
|||
<QuantidadeRps>{{ nfse.lista_rps|length }}</QuantidadeRps> |
|||
<ListaRps> |
|||
{% for rps in nfse.lista_rps -%} |
|||
{% include 'Rps.xml' %} |
|||
{% endfor %} |
|||
</ListaRps> |
|||
</LoteRps> |
|||
</EnviarLoteRpsEnvio> |
|||
@ -0,0 +1,79 @@ |
|||
# © 2018 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from lxml import etree |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
|
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.nfse.bh.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
ref_lote = "" |
|||
if method == "GerarNfse": |
|||
reference = "rps:%s" % kwargs["rps"]["numero"] |
|||
ref_lote = "lote%s" % kwargs["rps"]["numero_lote"] |
|||
elif method == "CancelarNfse": |
|||
reference = "pedidoCancelamento_%s" % kwargs["cancelamento"]["numero_nfse"] |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
if ref_lote: |
|||
xml_send = signer.assina_xml(etree.fromstring(xml_send), ref_lote) |
|||
return xml_send.encode("utf-8") |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://bhissdigital.pbh.gov.br/bhiss-ws/nfse?wsdl" |
|||
else: |
|||
base_url = "https://bhisshomologa.pbh.gov.br/bhiss-ws/nfse?wsdl" |
|||
|
|||
xml_send = kwargs["xml"].decode("utf-8") |
|||
xml_cabecalho = '<?xml version="1.0" encoding="UTF-8"?>\ |
|||
<cabecalho xmlns="http://www.abrasf.org.br/nfse.xsd" versao="1.00">\ |
|||
<versaoDados>1.00</versaoDados></cabecalho>' |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(base_url, transport=transport) |
|||
|
|||
response = client.service[method](xml_cabecalho, xml_send) |
|||
|
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_gerar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def gerar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "CancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "CancelarNfse", **kwargs) |
|||
@ -0,0 +1,47 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import signxml |
|||
from lxml import etree |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
|||
from signxml import XMLSigner |
|||
|
|||
|
|||
class Assinatura(object): |
|||
def __init__(self, arquivo, senha): |
|||
self.arquivo = arquivo |
|||
self.senha = senha |
|||
|
|||
def assina_xml(self, xml_element, reference): |
|||
cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) |
|||
|
|||
for element in xml_element.iter("*"): |
|||
if element.text is not None and not element.text.strip(): |
|||
element.text = None |
|||
|
|||
signer = XMLSigner( |
|||
method=signxml.methods.enveloped, |
|||
signature_algorithm="rsa-sha1", |
|||
digest_algorithm="sha1", |
|||
c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315", |
|||
) |
|||
|
|||
ns = {} |
|||
ns[None] = signer.namespaces["ds"] |
|||
signer.namespaces = ns |
|||
|
|||
ref_uri = ("#%s" % reference) if reference else None |
|||
signed_root = signer.sign( |
|||
xml_element, key=key.encode(), cert=cert.encode(), reference_uri=ref_uri |
|||
) |
|||
if reference: |
|||
element_signed = signed_root.find(".//*[@Id='%s']" % reference) |
|||
signature = ( |
|||
signed_root.find(".//*[@URI='#%s']" % reference).getparent().getparent() |
|||
) |
|||
|
|||
if element_signed is not None and signature is not None: |
|||
parent = element_signed.getparent() |
|||
parent.append(signature) |
|||
return etree.tostring(signed_root, encoding=str) |
|||
@ -0,0 +1,13 @@ |
|||
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<Pedido xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<InfPedidoCancelamento Id="pedidoCancelamento_{{ cancelamento.numero_nfse }}"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>2</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,11 @@ |
|||
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<LoteRps Id="lote{{ rps.numero_lote }}" versao="1.00"> |
|||
<NumeroLote>{{ rps.numero_lote }}</NumeroLote> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
<QuantidadeRps>1</QuantidadeRps> |
|||
<ListaRps xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
{% include 'Rps.xml' %} |
|||
</ListaRps> |
|||
</LoteRps> |
|||
</GerarNfseEnvio> |
|||
@ -0,0 +1,91 @@ |
|||
<Rps> |
|||
<InfRps xmlns="http://www.abrasf.org.br/nfse.xsd" Id="rps:{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<RpsSubstituido> |
|||
<Numero>{{ rps.numero_substituido }}</Numero> |
|||
<Serie>{{ rps.serie_substituido }}</Serie> |
|||
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
|||
</RpsSubstituido> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
</Rps> |
|||
@ -0,0 +1,69 @@ |
|||
# © 2018 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
import suds |
|||
from pytrustnfe.client import get_authenticated_client |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
if method == "GerarNfse": |
|||
reference = "r%s" % kwargs["rps"]["numero"] |
|||
elif method == "CancelarNfse": |
|||
reference = "Cancelamento_NF%s" % kwargs["cancelamento"]["numero_nfse"] |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
return xml_send.encode("utf-8") |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl" |
|||
else: |
|||
base_url = "https://homologacao.notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl" # noqa |
|||
|
|||
xml_send = kwargs["xml"].decode("utf-8") |
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
client = get_authenticated_client(base_url, cert, key) |
|||
|
|||
try: |
|||
response = getattr(client.service, method)(xml_send) |
|||
except suds.WebFault as e: |
|||
return { |
|||
"sent_xml": str(xml_send), |
|||
"received_xml": str(e.fault.faultstring), |
|||
"object": None, |
|||
} |
|||
|
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": str(xml_send), "received_xml": str(response), "object": obj} |
|||
|
|||
|
|||
def xml_gerar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def gerar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "CancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "CancelarNfse", **kwargs) |
|||
@ -0,0 +1,13 @@ |
|||
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="Cancelamento_NF{{ cancelamento.numero_nfse }}"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>1</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,3 @@ |
|||
<GerarNfseEnvio xmlns="http://notacarioca.rio.gov.br/WSNacional/XSD/1/nfse_pcrj_v01.xsd"> |
|||
{% include 'Rps.xml' %} |
|||
</GerarNfseEnvio> |
|||
@ -0,0 +1,91 @@ |
|||
<Rps> |
|||
<InfRps xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd" Id="r{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<RpsSubstituido> |
|||
<Numero>{{ rps.numero_substituido }}</Numero> |
|||
<Serie>{{ rps.serie_substituido }}</Serie> |
|||
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
|||
</RpsSubstituido> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
</Rps> |
|||
@ -0,0 +1,124 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
# © 2017 Fábio Luna, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
import suds |
|||
from lxml import etree |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfse.assinatura import Assinatura |
|||
from pytrustnfe.client import get_client |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
if method == "testeEnviar": |
|||
xml_send = render_xml(path, "enviar.xml", True, **kwargs) |
|||
else: |
|||
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs) |
|||
|
|||
if type(xml_send) != str: |
|||
xml_send = etree.tostring(xml_send) |
|||
return xml_send.decode() |
|||
|
|||
|
|||
def _get_url(**kwargs): |
|||
|
|||
try: |
|||
cod_cidade = kwargs["nfse"]["cidade"] |
|||
except (KeyError, TypeError): |
|||
raise KeyError("Código de cidade inválido!") |
|||
|
|||
urls = { |
|||
# Belém - PA |
|||
"2715": "http://www.issdigitalbel.com.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Sorocaba - SP |
|||
"7145": "http://issdigital.sorocaba.sp.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Teresina - PI |
|||
"1219": "http://www.issdigitalthe.com.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Campinas - SP |
|||
"6291": "http://issdigital.campinas.sp.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Uberlandia - MG |
|||
"5403": "http://udigital.uberlandia.mg.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# São Luis - MA |
|||
"0921": "http://sistemas.semfaz.saoluis.ma.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Campo Grande - MS |
|||
"2729": "http://issdigital.pmcg.ms.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
} |
|||
|
|||
try: |
|||
return urls[str(cod_cidade)] |
|||
except KeyError: |
|||
raise KeyError("DSF não emite notas da cidade {}!".format(cod_cidade)) |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
url = _get_url(**kwargs) |
|||
|
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
|
|||
xml_send = _render(path, method, **kwargs) |
|||
client = get_client(url) |
|||
response = False |
|||
|
|||
if certificado: |
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
signer = Assinatura(cert, key, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, "") |
|||
|
|||
try: |
|||
response = getattr(client.service, method)(xml_send) |
|||
response, obj = sanitize_response(response.encode()) |
|||
except suds.WebFault as e: |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": e.fault.faultstring, |
|||
"object": None, |
|||
} |
|||
except Exception as e: |
|||
if response: |
|||
raise Exception(response) |
|||
else: |
|||
raise e |
|||
|
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_enviar(certificado, **kwargs): |
|||
return _render(certificado, "enviar", **kwargs) |
|||
|
|||
|
|||
def enviar(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_enviar(certificado, **kwargs) |
|||
return _send(certificado, "enviar", **kwargs) |
|||
|
|||
|
|||
def xml_teste_enviar(certificado, **kwargs): |
|||
return _render(certificado, "testeEnviar", **kwargs) |
|||
|
|||
|
|||
def teste_enviar(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_teste_enviar(certificado, **kwargs) |
|||
return _send(certificado, "testeEnviar", **kwargs) |
|||
|
|||
|
|||
def cancelar(certificado, **kwargs): |
|||
return _send(certificado, "cancelar", **kwargs) |
|||
|
|||
|
|||
def consulta_lote(**kwargs): |
|||
return _send(False, "consultarLote", **kwargs) |
|||
|
|||
|
|||
def xml_consultar_nfse_rps(certificado, **kwargs): |
|||
return _render(certificado, "consultarNFSeRps", **kwargs) |
|||
|
|||
|
|||
def consultar_nfse_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_nfse_rps(certificado, **kwargs) |
|||
return _send(certificado, "consultarNFSeRps", **kwargs) |
|||
@ -0,0 +1,18 @@ |
|||
<ns1:ReqCancelamentoNFSe xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
|||
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqCancelamentoNFSe.xsd"> |
|||
<Cabecalho> |
|||
<CodCidade>{{ cancelamento.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ cancelamento.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<transacao>true</transacao> |
|||
<Versao>1</Versao> |
|||
</Cabecalho> |
|||
<Lote Id="lote:1ABCDZ"> |
|||
<Nota Id="nota:{{ cancelamento.nota_id }}"> |
|||
<InscricaoMunicipalPrestador>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipalPrestador> |
|||
<NumeroNota>{{ cancelamento.nota_id }}</NumeroNota> |
|||
<CodigoVerificacao>{{ cancelamento.assinatura }}</CodigoVerificacao> |
|||
<MotivoCancelamento>{{ cancelamento.motivo }}</MotivoCancelamento> |
|||
</Nota> |
|||
</Lote> |
|||
</ns1:ReqCancelamentoNFSe> |
|||
@ -0,0 +1,11 @@ |
|||
<ns1:ReqConsultaNotas xmlns:ns1="http://localhost:8080/WsNFe2/lote" xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaNotas.xsd"> |
|||
<Cabecalho Id="Consulta:notas"> |
|||
<CodCidade>{{ consulta.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ consulta.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<InscricaoMunicipalPrestador>{{ consulta.inscricao_municipal }}</InscricaoMunicipalPrestador> |
|||
<dtInicio>{{ consulta.data_inicio }}</dtInicio> |
|||
<dtFim>{{ consulta.data_final }}</dtFim> |
|||
<NotaInicial>{{ consulta.nota_inicial }}</NotaInicial> |
|||
<Versao>1</Versao> |
|||
</Cabecalho> |
|||
</ns1:ReqConsultaNotas> |
|||
@ -0,0 +1,10 @@ |
|||
<ns1:ReqConsultaLote xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
|||
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaLote.xsd"> |
|||
<Cabecalho> |
|||
<CodCidade>{{ consulta.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ consulta.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<Versao>1</Versao> |
|||
<NumeroLote>{{ consulta.lote }}</NumeroLote> |
|||
</Cabecalho> |
|||
</ns1:ReqConsultaLote> |
|||
@ -0,0 +1,22 @@ |
|||
<ns1:ReqConsultaNFSeRPS |
|||
xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
|||
xmlns:tipos="http://localhost:8080/WsNFe2/tp" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaNFSeRPS.xsd"> |
|||
<Cabecalho> |
|||
<CodCidade>{{ nfse.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ nfse.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<transacao>true</transacao> |
|||
<Versao>1</Versao> |
|||
</Cabecalho> |
|||
<Lote Id="lote:{{ nfse.lote }}"> |
|||
{% for rps in nfse.lista_rps -%} |
|||
<RPSConsulta> |
|||
<RPS Id="rps:{{ rps.numero }}"> |
|||
<InscricaoMunicipalPrestador>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipalPrestador> |
|||
<NumeroRPS>{{ rps.numero }}</NumeroRPS> |
|||
<SeriePrestacao>{{ rps.serie_prestacao }}</SeriePrestacao> |
|||
</RPS> |
|||
</RPSConsulta> |
|||
{% endfor %} |
|||
</Lote> |
|||
</ns1:ReqConsultaNFSeRPS> |
|||
@ -0,0 +1,100 @@ |
|||
<ns1:ReqEnvioLoteRPS xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
|||
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqEnvioLoteRPS.xsd"> |
|||
<Cabecalho> |
|||
<CodCidade>{{ nfse.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ nfse.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<RazaoSocialRemetente>{{ nfse.remetente }}</RazaoSocialRemetente> |
|||
<transacao>{{ nfse.transacao }}</transacao> |
|||
<dtInicio>{{ nfse.data_inicio|format_date }}</dtInicio> |
|||
<dtFim>{{ nfse.data_fim|format_date }}</dtFim> |
|||
<QtdRPS>{{ nfse.total_rps }}</QtdRPS> |
|||
<ValorTotalServicos>{{ nfse.total_servicos }}</ValorTotalServicos> |
|||
<ValorTotalDeducoes>{{ nfse.total_deducoes }}</ValorTotalDeducoes> |
|||
<Versao>1</Versao> |
|||
<MetodoEnvio>WS</MetodoEnvio> |
|||
</Cabecalho> |
|||
<Lote Id="{{ nfse.lote_id }}"> |
|||
{% for rps in nfse.lista_rps -%} |
|||
<RPS Id="{{ rps.numero }}"> |
|||
<Assinatura>{{ rps.assinatura }}</Assinatura> |
|||
<InscricaoMunicipalPrestador>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipalPrestador> |
|||
<RazaoSocialPrestador>{{ rps.prestador.razao_social }}</RazaoSocialPrestador> |
|||
<TipoRPS>RPS</TipoRPS> |
|||
<SerieRPS>{{ rps.serie }}</SerieRPS> |
|||
<NumeroRPS>{{ rps.numero }}</NumeroRPS> |
|||
<DataEmissaoRPS>{{ rps.data_emissao|format_datetime }}</DataEmissaoRPS> |
|||
<SituacaoRPS>{{ rps.situacao }}</SituacaoRPS> |
|||
<SerieRPSSubstituido></SerieRPSSubstituido> |
|||
<NumeroRPSSubstituido>0</NumeroRPSSubstituido> |
|||
<NumeroNFSeSubstituida>0</NumeroNFSeSubstituida> |
|||
<DataEmissaoNFSeSubstituida>1900-01-01</DataEmissaoNFSeSubstituida> |
|||
<SeriePrestacao>{{ rps.serie_prestacao }}</SeriePrestacao> |
|||
<InscricaoMunicipalTomador>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipalTomador> |
|||
<CPFCNPJTomador>{{ rps.tomador.cpf_cnpj }}</CPFCNPJTomador> |
|||
<RazaoSocialTomador>{{ rps.tomador.razao_social }}</RazaoSocialTomador> |
|||
<TipoLogradouroTomador>{{ rps.tomador.tipo_logradouro }}</TipoLogradouroTomador> |
|||
<LogradouroTomador>{{ rps.tomador.logradouro }}</LogradouroTomador> |
|||
<NumeroEnderecoTomador>{{ rps.tomador.numero }}</NumeroEnderecoTomador> |
|||
<TipoBairroTomador>{{ rps.tomador.tipo_bairro }}</TipoBairroTomador> |
|||
<BairroTomador>{{ rps.tomador.bairro }}</BairroTomador> |
|||
<CidadeTomador>{{ rps.tomador.cidade }}</CidadeTomador> |
|||
<CidadeTomadorDescricao>{{ rps.tomador.cidade_descricao }}</CidadeTomadorDescricao> |
|||
<CEPTomador>{{ rps.tomador.cep }}</CEPTomador> |
|||
<EmailTomador>{{ rps.tomador.email }}</EmailTomador> |
|||
<CodigoAtividade>{{ rps.codigo_atividade }}</CodigoAtividade> |
|||
<AliquotaAtividade>{{ rps.aliquota_atividade }}</AliquotaAtividade> |
|||
<TipoRecolhimento>{{ rps.tipo_recolhimento }}</TipoRecolhimento> |
|||
<MunicipioPrestacao>{{ rps.municipio_prestacao }}</MunicipioPrestacao> |
|||
<MunicipioPrestacaoDescricao>{{ rps.municipio_prestacao_descricao }}</MunicipioPrestacaoDescricao> |
|||
<Operacao>{{ rps.operacao }}</Operacao> |
|||
<Tributacao>{{ rps.tributacao }}</Tributacao> |
|||
<ValorPIS>{{ rps.valor_pis }}</ValorPIS> |
|||
<ValorCOFINS>{{ rps.valor_cofins }}</ValorCOFINS> |
|||
<ValorINSS>{{ rps.valor_inss }}</ValorINSS> |
|||
<ValorIR>{{ rps.valor_ir }}</ValorIR> |
|||
<ValorCSLL>{{ rps.valor_csll }}</ValorCSLL> |
|||
<AliquotaPIS>{{ rps.aliquota_pis }}</AliquotaPIS> |
|||
<AliquotaCOFINS>{{ rps.aliquota_cofins }}</AliquotaCOFINS> |
|||
<AliquotaINSS>{{ rps.aliquota_inss }}</AliquotaINSS> |
|||
<AliquotaIR>{{ rps.aliquota_ir }}</AliquotaIR> |
|||
<AliquotaCSLL>{{ rps.aliquota_csll }}</AliquotaCSLL> |
|||
<DescricaoRPS>{{ rps.descricao }}</DescricaoRPS> |
|||
<DDDPrestador>{{ rps.prestador.ddd }}</DDDPrestador> |
|||
<TelefonePrestador>{{ rps.prestador.telefone }}</TelefonePrestador> |
|||
<DDDTomador>{{ rps.tomador.ddd }}</DDDTomador> |
|||
<TelefoneTomador>{{ rps.tomador.telefone }}</TelefoneTomador> |
|||
<MotCancelamento>{{ rps.motivo_cancelamento }}</MotCancelamento> |
|||
{% if rps.deducoes|count > 0 %} |
|||
<Deducoes> |
|||
{% for deducao in rps.deducoes -%} |
|||
<Deducao> |
|||
<DeducaoPor>{{ deducao.por }}</DeducaoPor> |
|||
<TipoDeducao>{{ deducao.tipo }}</TipoDeducao> |
|||
<CPFCNPJReferencia>{{ deducao.cnpj_referencia }}</CPFCNPJReferencia> |
|||
<NumeroNFReferencia>{{ deducao.nf_referencia }}</NumeroNFReferencia> |
|||
<ValorTotalReferencia>{{ deducao.valor_referencia }}</ValorTotalReferencia> |
|||
<PercentualDeduzir>{{ deducao.percentual_deduzir }}</PercentualDeduzir> |
|||
<ValorDeduzir>{{ deducao.valor_deduzir }}</ValorDeduzir> |
|||
</Deducao> |
|||
{% endfor %} |
|||
</Deducoes> |
|||
{% endif %} |
|||
{% if rps.deducoes|count == 0 %} |
|||
<Deducoes /> |
|||
{% endif %} |
|||
<Itens> |
|||
{% for item in rps.itens -%} |
|||
<Item> |
|||
<DiscriminacaoServico>{{ item.descricao }}</DiscriminacaoServico> |
|||
<Quantidade>{{ item.quantidade }}</Quantidade> |
|||
<ValorUnitario>{{ item.valor_unitario }}</ValorUnitario> |
|||
<ValorTotal>{{ item.valor_total }}</ValorTotal> |
|||
<Tributavel>S</Tributavel> |
|||
</Item> |
|||
{% endfor %} |
|||
</Itens> |
|||
</RPS> |
|||
{% endfor %} |
|||
</Lote> |
|||
</ns1:ReqEnvioLoteRPS> |
|||
@ -0,0 +1,12 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" |
|||
xmlns:dsf="http://dsfnet.com.br"> |
|||
<soapenv:Body> |
|||
<dsf:enviar soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> |
|||
<mensagemXml xsi:type="xsd:string"><![CDATA[ |
|||
{% block content %}{% endblock %} |
|||
]]></mensagemXml> |
|||
</dsf:enviar> |
|||
</soapenv:Body> |
|||
</soapenv:Envelope> |
|||
@ -0,0 +1,128 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2017 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
import hashlib |
|||
import base64 |
|||
import requests |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfse.assinatura import Assinatura |
|||
|
|||
URLS = { |
|||
"producao": { |
|||
"processar_nota": "https://nfps-e.pmf.sc.gov.br/api/v1/processamento/notas/processa", |
|||
"cancelar_nota": "https://nfps-e.pmf.sc.gov.br/api/v1/cancelamento/notas/cancela", |
|||
}, |
|||
"homologacao": { |
|||
"processar_nota": "https://nfps-e-hml.pmf.sc.gov.br/api/v1/processamento/notas/processa", |
|||
"cancelar_nota": "https://nfps-e-hml.pmf.sc.gov.br/api/v1/cancelamento/notas/cancela", |
|||
}, |
|||
} |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs) |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
signer = Assinatura(cert, key, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, "") |
|||
return xml_send |
|||
|
|||
|
|||
def _get_oauth_token(**kwargs): |
|||
if kwargs["ambiente"] == "producao": |
|||
url = "https://nfps-e.pmf.sc.gov.br/api/v1/autenticacao/oauth/token" |
|||
else: |
|||
url = "https://nfps-e-hml.pmf.sc.gov.br/api/v1/autenticacao/oauth/token" |
|||
|
|||
m = hashlib.md5() |
|||
secret = "%s:%s" % (kwargs["client_id"], kwargs["secret_id"]) |
|||
auth = base64.b64encode(secret.encode("utf-8")) |
|||
headers = { |
|||
"Content-Type": "application/x-www-form-urlencoded", |
|||
"Authorization": "Basic %s" % auth.decode("utf-8").replace("\n", ""), |
|||
} |
|||
m.update(kwargs["password"].encode("utf-8")) |
|||
password = m.hexdigest().upper() |
|||
|
|||
dados = ( |
|||
"grant_type=password&username=%s&password=%s&client_id=%s&client_secret=%s" |
|||
% (kwargs["username"], password, kwargs["client_id"], kwargs["secret_id"]) |
|||
) |
|||
r = requests.post(url, data=dados, headers=headers) |
|||
if r.status_code == 200: |
|||
return r.json() |
|||
else: |
|||
return r.json() |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
url = URLS[kwargs["ambiente"]][method] |
|||
xml_send = kwargs["xml"] |
|||
|
|||
token = _get_oauth_token(**kwargs) |
|||
if "access_token" not in token: |
|||
raise Exception( |
|||
"%s - %s: %s" % (token["status"], token["error"], token["message"]) |
|||
) |
|||
kwargs.update({"numero": 1, "access_token": token["access_token"]}) |
|||
|
|||
headers = { |
|||
"Accept": "application/xml;charset=UTF-8", |
|||
"Content-Type": "application/xml", |
|||
"Authorization": "Bearer %s" % kwargs["access_token"], |
|||
} |
|||
r = requests.post(url, headers=headers, data=xml_send) |
|||
|
|||
response, obj = sanitize_response(r.text.strip()) |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": response.encode("utf-8"), |
|||
"object": obj, |
|||
"status_code": r.status_code, |
|||
} |
|||
|
|||
|
|||
def xml_processar_nota(certificado, **kwargs): |
|||
return _render(certificado, "processar_nota", **kwargs) |
|||
|
|||
|
|||
def processar_nota(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_processar_nota(certificado, **kwargs) |
|||
return _send(certificado, "processar_nota", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nota(certificado, **kwargs): |
|||
return _render(certificado, "cancelar_nota", **kwargs) |
|||
|
|||
|
|||
def cancelar_nota(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nota(certificado, **kwargs) |
|||
return _send(certificado, "cancelar_nota", **kwargs) |
|||
|
|||
|
|||
def consultar_nota(certificado, **kwargs): |
|||
if kwargs["ambiente"] == "producao": |
|||
url = "https://nfps-e.pmf.sc.gov.br/api/v1/consultas/notas/numero/%s" % ( |
|||
kwargs["numero"] |
|||
) |
|||
else: |
|||
url = "https://nfps-e-hml.pmf.sc.gov.br/api/v1/consultas/notas/numero/%s" % ( |
|||
kwargs["numero"] |
|||
) |
|||
|
|||
headers = { |
|||
"Accept": "application/json", |
|||
"Authorization": "Bearer %s" % kwargs["access_token"], |
|||
} |
|||
r = requests.get(url, headers=headers) |
|||
if r.status_code == 200: |
|||
return r.text |
|||
else: |
|||
return r.text |
|||
@ -0,0 +1,7 @@ |
|||
<?xml version="1.0"?> |
|||
<xmlCancelamentoNfpse> |
|||
<motivoCancelamento>{{ cancelamento.motivo }}</motivoCancelamento> |
|||
<nuAedf>{{ cancelamento.aedf }}</nuAedf> |
|||
<nuNotaFiscal>{{ cancelamento.numero }}</nuNotaFiscal> |
|||
<codigoVerificacao>{{ cancelamento.codigo_verificacao }}</codigoVerificacao> |
|||
</xmlCancelamentoNfpse> |
|||
@ -0,0 +1,41 @@ |
|||
<?xml version="1.0"?> |
|||
<xmlProcessamentoNfpse> |
|||
<bairroTomador>{{ rps.tomador.bairro|normalize|escape }}</bairroTomador> |
|||
<baseCalculo>{{ rps.base_calculo }}</baseCalculo> |
|||
<baseCalculoSubstituicao>0.0</baseCalculoSubstituicao> |
|||
<cfps>{{ rps.cfps }}</cfps> |
|||
<codigoMunicipioTomador>{{ rps.tomador.cidade }}</codigoMunicipioTomador> |
|||
<codigoPostalTomador>{{ rps.tomador.cep }}</codigoPostalTomador> |
|||
<complementoEnderecoTomador>{{ rps.tomador.complemento|normalize|escape }}</complementoEnderecoTomador> |
|||
<dadosAdicionais>{{ rps.observacoes|normalize|escape }}</dadosAdicionais> |
|||
<dataEmissao>{{ rps.data_emissao }}</dataEmissao> |
|||
<emailTomador>{{ rps.tomador.email }}</emailTomador> |
|||
<identificacao>{{ rps.numero }}</identificacao> |
|||
<identificacaoTomador>{{ rps.tomador.cnpj_cpf }}</identificacaoTomador> |
|||
<inscricaoMunicipalTomador>{{ rps.tomador.inscricao_municipal }}</inscricaoMunicipalTomador> |
|||
<itensServico> |
|||
{% for item in rps.itens_servico -%} |
|||
<itemServico> |
|||
<aliquota>{{ item.aliquota }}</aliquota> |
|||
<baseCalculo>{{ item.base_calculo }}</baseCalculo> |
|||
<cst>{{ item.cst_servico }}</cst> |
|||
<descricaoServico>{{ item.name|normalize|escape }}</descricaoServico> |
|||
<idCNAE>{{ item.cnae }}</idCNAE> |
|||
<quantidade>{{ item.quantidade }}</quantidade> |
|||
<valorTotal>{{ item.valor_total }}</valorTotal> |
|||
<valorUnitario>{{ item.valor_unitario }}</valorUnitario> |
|||
</itemServico> |
|||
{% endfor %} |
|||
</itensServico> |
|||
<logradouroTomador>{{ rps.tomador.logradouro|normalize|escape }}</logradouroTomador> |
|||
<nomeMunicipioTomador></nomeMunicipioTomador> |
|||
<numeroAEDF>{{ rps.aedf }}</numeroAEDF> |
|||
<numeroEnderecoTomador>{{ rps.tomador.numero }}</numeroEnderecoTomador> |
|||
<paisTomador>1058</paisTomador> |
|||
<razaoSocialTomador>{{ rps.tomador.razao_social|normalize|escape }}</razaoSocialTomador> |
|||
<telefoneTomador>{{ rps.tomador.telefone }}</telefoneTomador> |
|||
<ufTomador>{{ rps.tomador.uf }}</ufTomador> |
|||
<valorISSQN>{{rps.valor_issqn }}</valorISSQN> |
|||
<valorISSQNSubstituicao>0.0</valorISSQNSubstituicao> |
|||
<valorTotalServicos>{{ rps.valor_total }}</valorTotalServicos> |
|||
</xmlProcessamentoNfpse> |
|||
@ -1,17 +0,0 @@ |
|||
<ws_nfe.CANCELANOTAELETRONICA xmlns="NFe"> |
|||
<Sdt_cancelanfe> |
|||
<Login> |
|||
<CodigoUsuario>{{ cancelamento.codigo_usuario }}</CodigoUsuario> |
|||
<CodigoContribuinte>{{ cancelamento.codigo_contribuinte }}</CodigoContribuinte> |
|||
</Login> |
|||
<Nota> |
|||
<SerieNota>{{ cancelamento.serie_nota }}</SerieNota> |
|||
<NumeroNota>{{ cancelamento.numero_nota }}</NumeroNota> |
|||
<SerieRPS>{{ cancelamento.serie_rps }}</SerieRPS> |
|||
<NumeroRps>{{ cancelamento.numero_rps }}</NumeroRps> |
|||
<ValorNota>{{ cancelamento.valor }}</ValorNota> |
|||
<MotivoCancelamento>{{ cancelamento.motivo }}</MotivoCancelamento> |
|||
<PodeCancelarGuia>{{ cancelamento.cancelar_guia }}</PodeCancelarGuia> |
|||
</Nota> |
|||
</Sdt_cancelanfe> |
|||
</ws_nfe.CANCELANOTAELETRONICA> |
|||
@ -1,9 +0,0 @@ |
|||
<ws_nfe.CONSULTANOTASPROTOCOLO xmlns="NFe"> |
|||
<Sdt_consultanotasprotocoloin> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
<Login> |
|||
<CodigoUsuario>{{ consulta.codigo_usuario }}</CodigoUsuario> |
|||
<CodigoContribuinte>{{ consulta.codigo_contribuinte }}</CodigoContribuinte> |
|||
</Login> |
|||
</Sdt_consultanotasprotocoloin> |
|||
</ws_nfe.CONSULTANOTASPROTOCOLO> |
|||
@ -1,9 +0,0 @@ |
|||
<ws_nfe.CONSULTAPROTOCOLO xmlns="NFe"> |
|||
<Sdt_consultaprotocoloin> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
<Login> |
|||
<CodigoUsuario>{{ consulta.codigo_usuario }}</CodigoUsuario> |
|||
<CodigoContribuinte>{{ consulta.codigo_contribuinte }}</CodigoContribuinte> |
|||
</Login> |
|||
</Sdt_consultaprotocoloin> |
|||
</ws_nfe.CONSULTAPROTOCOLO> |
|||
@ -0,0 +1,14 @@ |
|||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<Body> |
|||
<CancelarNota xmlns="urn:sigiss_ws"> |
|||
<DadosCancelaNota> |
|||
<ccm>{{ cancelamento.ccm }}</ccm> |
|||
<cnpj>{{ cancelamento.cnpj }}</cnpj> |
|||
<senha>{{ cancelamento.senha }}</senha> |
|||
<nota>{{ cancelamento.nota }}</nota> |
|||
<motivo>{{ cancelamento.motivo }}</motivo> |
|||
<email>{{ cancelamento.email }}</email> |
|||
</DadosCancelaNota> |
|||
</CancelarNota> |
|||
</Body> |
|||
</Envelope> |
|||
@ -0,0 +1,43 @@ |
|||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<Body> |
|||
<GerarNota xmlns="urn:sigiss_ws"> |
|||
<DescricaoRps> |
|||
<ccm>{{ nfse.ccm }}</ccm> |
|||
<cnpj>{{ nfse.cnpj }}</cnpj> |
|||
<senha>{{ nfse.senha }}</senha> |
|||
<crc>{{ nfse.crc }}</crc> |
|||
<crc_estado>{{ nfse.crc_estado }}</crc_estado> |
|||
<aliquota_simples>{{ nfse.aliquota_simples }}</aliquota_simples> |
|||
<id_sis_legado>{{ nfse.id_sis_legado }}</id_sis_legado> |
|||
<servico>{{ nfse.servico }}</servico> |
|||
<situacao>{{ nfse.situacao }}</situacao> |
|||
<valor>{{ nfse.valor }}</valor> |
|||
<base>{{ nfse.base }}</base> |
|||
<descricaoNF>{{ nfse.descricaoNF }}</descricaoNF> |
|||
<tomador_tipo>{{ nfse.tomador_tipo }}</tomador_tipo> |
|||
<tomador_cnpj>{{ nfse.tomador_cnpj }}</tomador_cnpj> |
|||
<tomador_email>{{ nfse.tomador_email }}</tomador_email> |
|||
<tomador_ie>{{ nfse.tomador_ie }}</tomador_ie> |
|||
<tomador_razao>{{ nfse.tomador_razao }}</tomador_razao> |
|||
<tomador_fantasia>{{ nfse.tomador_fantasia }}</tomador_fantasia> |
|||
<tomador_endereco>{{ nfse.tomador_endereco }}</tomador_endereco> |
|||
<tomador_numero>{{ nfse.tomador_endereco }}</tomador_numero> |
|||
<tomador_complemento>{{ nfse.tomador_complemento }}</tomador_complemento> |
|||
<tomador_bairro>{{ nfse.tomador_bairro }}</tomador_bairro> |
|||
<tomador_CEP>{{ nfse.tomador_CEP }}</tomador_CEP> |
|||
<tomador_cod_cidade>{{ nfse.tomador_cod_cidade }}</tomador_cod_cidade> |
|||
<tomador_fone>{{ nfse.tomador_fone }}</tomador_fone> |
|||
<tomador_ramal>{{ nfse.tomador_ramal }}</tomador_ramal> |
|||
<tomador_fax>{{ nfse.tomador_fax }}</tomador_fax> |
|||
<outro_municipio>{{ nfse.outro_municipio }}</outro_municipio> |
|||
<cod_outro_municipio>{{ nfse.cod_outro_municipio }}</cod_outro_municipio> |
|||
<retencao_iss>{{ nfse.retencao_iss }}</retencao_iss> |
|||
<pis>{{ nfse.pis }}</pis> |
|||
<cofins>{{ nfse.cofins }}</cofins> |
|||
<inss>{{ nfse.inss }}</inss> |
|||
<irrf>{{ nfse.irrf }}</irrf> |
|||
<csll>{{ nfse.csll }}</csll> |
|||
</DescricaoRps> |
|||
</GerarNota> |
|||
</Body> |
|||
</Envelope> |
|||
@ -1,81 +0,0 @@ |
|||
<ws_nfe.PROCESSARPS xmlns="NFe"> |
|||
<Sdt_processarpsin> |
|||
<Login> |
|||
<CodigoUsuario>{{ nfse.codigo_usuario }}</CodigoUsuario> |
|||
<CodigoContribuinte>{{ nfse.codigo_contribuinte }}</CodigoContribuinte> |
|||
</Login> |
|||
<SDTRPS> |
|||
<Ano>{{ nfse.ano }}</Ano> |
|||
<Mes>{{ nfse.mes }}</Mes> |
|||
<CPFCNPJ>{{ nfse.cnpj_prestador }}</CPFCNPJ> |
|||
<DTIni>{{ nfse.data_emissao }}</DTIni> |
|||
<DTFin>{{ nfse.data_emissao }}</DTFin> |
|||
<TipoTrib>{{ nfse.tipo_tributacao }}</TipoTrib> |
|||
<DtAdeSN>{{ nfse.data_adesao_simples }}</DtAdeSN> |
|||
<AlqIssSN_IP>{{ nfse.aliquota_simples_isencao|comma }}</AlqIssSN_IP> |
|||
<Versao>2.00</Versao> |
|||
{% for rps in nfse.lista_rps -%} |
|||
<Reg20> |
|||
<!-- Optional --> |
|||
<Reg20Item> |
|||
<TipoNFS>{{ rps.tipo_nfse }}</TipoNFS> |
|||
<NumRps>{{ rps.numero }}</NumRps> |
|||
<SerRps>{{ rps.serie }}</SerRps> |
|||
<DtEmi>{{ rps.data_emissao }}</DtEmi> |
|||
<RetFonte>{{ rps.iss_retido }}</RetFonte> |
|||
<CodSrv>{{ rps.codigo_servico }}</CodSrv> |
|||
<DiscrSrv>{{ rps.descricao}}</DiscrSrv> |
|||
<VlNFS>{{ rps.valor_liquido_nfse|comma }}</VlNFS> |
|||
<VlDed>{{ rps.valor_deducao|comma }}</VlDed> |
|||
<DiscrDed>{{ rps.discriminacao_deducao }}</DiscrDed> |
|||
<VlBasCalc>{{ rps.base_calculo|comma }}</VlBasCalc> |
|||
<AlqIss>{{ rps.aliquota_issqn|comma }}</AlqIss> |
|||
<VlIss>{{ rps.valor_iss|comma }}</VlIss> |
|||
<VlIssRet>{{ rps.valor_iss_retido|comma }}</VlIssRet> |
|||
<CpfCnpTom>{{ rps.tomador.cnpj_cpf }}</CpfCnpTom> |
|||
<RazSocTom>{{ rps.tomador.razao_social }}</RazSocTom> |
|||
<TipoLogtom>{{ rps.tomador.tipo_logradouro }}</TipoLogtom> |
|||
<LogTom>{{ rps.tomador.logradouro }}</LogTom> |
|||
<NumEndTom>{{ rps.tomador.numero }}</NumEndTom> |
|||
<ComplEndTom>{{ rps.tomador.complemento }}</ComplEndTom> |
|||
<BairroTom>{{ rps.tomador.bairro }}</BairroTom> |
|||
<MunTom>{{ rps.tomador.municipio }}</MunTom> |
|||
<SiglaUFTom>{{ rps.tomador.uf }}</SiglaUFTom> |
|||
<CepTom>{{ rps.tomador.cep }}</CepTom> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
{% if rps.local_prestacao == 'prestador' %} |
|||
<TipoLogLocPre>{{ rps.prestador.tipo_logradouro }}</TipoLogLocPre> |
|||
<LogLocPre>{{ rps.prestador.logradouro }}</LogLocPre> |
|||
<NumEndLocPre>{{ rps.prestador.numero }}</NumEndLocPre> |
|||
<ComplEndLocPre>{{ rps.prestador.complemento }}</ComplEndLocPre> |
|||
<BairroLocPre>{{ rps.prestador.bairro }}</BairroLocPre> |
|||
<MunLocPre>{{ rps.prestador.municipio }}</MunLocPre> |
|||
<SiglaUFLocpre>{{ rps.prestador.uf }}</SiglaUFLocpre> |
|||
<CepLocPre>{{ rps.prestador.cep }}</CepLocPre> |
|||
{% endif %} |
|||
<Email1>{{ rps.tomador.email }}</Email1> |
|||
{% for imposto in rps.impostos -%} |
|||
<Reg30> |
|||
<Reg30Item> |
|||
<TributoSigla>{{ imposto.sigla }}</TributoSigla> |
|||
<TributoAliquota>{{ imposto.aliquota|comma }}</TributoAliquota> |
|||
<TributoValor>{{ imposto.valor|comma }}</TributoValor> |
|||
</Reg30Item> |
|||
</Reg30> |
|||
{% endfor %} |
|||
</Reg20Item> |
|||
</Reg20> |
|||
{% endfor %} |
|||
<Reg90> |
|||
<QtdRegNormal>{{ nfse.lista_rps|length }}</QtdRegNormal> |
|||
<ValorNFS>{{ nfse.lista_rps|sum(attribute='valor_liquido_nfse')|comma }}</ValorNFS> |
|||
<ValorISS>{{ nfse.lista_rps|sum(attribute='valor_iss')|comma }}</ValorISS> |
|||
<ValorDed>{{ nfse.lista_rps|sum(attribute='valor_deducao')|comma }}</ValorDed> |
|||
<ValorIssRetTom>{{ nfse.lista_rps|sum(attribute='valor_iss_retido')|comma }}</ValorIssRetTom> |
|||
<QtdReg30>{{ nfse.quantidade_impostos }}</QtdReg30> |
|||
<ValorTributos>{{ nfse.valor_tributos|comma }}</ValorTributos> |
|||
</Reg90> |
|||
</SDTRPS> |
|||
</Sdt_processarpsin> |
|||
</ws_nfe.PROCESSARPS> |
|||
@ -1,5 +0,0 @@ |
|||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<Body> |
|||
{{ soap_body }} |
|||
</Body> |
|||
</Envelope> |
|||
@ -1,3 +1,80 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# © 2020 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
from requests.packages.urllib3 import disable_warnings |
|||
|
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
if method == "RecepcionarLoteRps": |
|||
reference = "rps%s" % kwargs["nfse"]["lista_rps"][0]["numero"] |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
return xml_send |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://www.issnetonline.com.br/webserviceabrasf/duquedecaxias/servicos.asmx?wsdl" |
|||
else: |
|||
raise Exception('Não existe ambiente de homologação para este município!') |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
disable_warnings() |
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(base_url, transport=transport) |
|||
|
|||
xml_send = kwargs["xml"] |
|||
response = client.service[method](xml_send) |
|||
|
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_recepcionar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "RecepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def recepcionar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "RecepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_consultar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "ConsultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def consultar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "ConsultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "CancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "CancelarNfse", **kwargs) |
|||
@ -0,0 +1,13 @@ |
|||
<CancelarNfseEnvio xmlns="http://www.issnetonline.com.br/webserviceabrasf/vsd/servico_cancelar_nfse_envio.xsd"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>{{ cancelamento.codigo_cancelamento }}</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,7 @@ |
|||
<ConsultarLoteRpsEnvio xmlns="http://www.issnetonline.com.br/webserviceabrasf/vsd/servico_consultar_lote_rps_envio.xsd" xmlns:tipos="http://www.issnetonline.com.br/webserviceabrasf/vsd/tipos_complexos.xsd"> |
|||
<Prestador> |
|||
<tipos:CpfCnpj><tipos:Cnpj>{{ consulta.cnpj_prestador }}</tipos:Cnpj></tipos:CpfCnpj> |
|||
<tipos:InscricaoMunicipal>{{ consulta.inscricao_municipal }}</tipos:InscricaoMunicipal> |
|||
</Prestador> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
</ConsultarLoteRpsEnvio> |
|||
@ -0,0 +1,13 @@ |
|||
<EnviarLoteRpsEnvio xmlns="http://www.issnetonline.com.br/webserviceabrasf/vsd/servico_enviar_lote_rps_envio.xsd" xmlns:tipos="http://www.issnetonline.com.br/webserviceabrasf/vsd/tipos_complexos.xsd"> |
|||
<LoteRps Id="lote{{ nfse.numero_lote }}"> |
|||
<tipos:NumeroLote>{{ nfse.numero_lote }}</tipos:NumeroLote> |
|||
<tipos:CpfCnpj><tipos:Cnpj>{{ nfse.cnpj_prestador }}</tipos:Cnpj></tipos:CpfCnpj> |
|||
<tipos:InscricaoMunicipal>{{ nfse.inscricao_municipal }}</tipos:InscricaoMunicipal> |
|||
<tipos:QuantidadeRps>{{ nfse.lista_rps|length }}</tipos:QuantidadeRps> |
|||
<ListaRps xmlns="http://www.issnetonline.com.br/webserviceabrasf/vsd/tipos_complexos.xsd"> |
|||
{% for rps in nfse.lista_rps -%} |
|||
{% include 'Rps.xml' %} |
|||
{% endfor %} |
|||
</ListaRps> |
|||
</LoteRps> |
|||
</EnviarLoteRpsEnvio> |
|||
@ -0,0 +1,91 @@ |
|||
<Rps> |
|||
<InfRps Id="rps{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<RpsSubstituido> |
|||
<Numero>{{ rps.numero_substituido }}</Numero> |
|||
<Serie>{{ rps.serie_substituido }}</Serie> |
|||
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
|||
</RpsSubstituido> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<CpfCnpj><Cnpj>{{ rps.prestador.cnpj }}</Cnpj></CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
</Rps> |
|||
@ -0,0 +1,70 @@ |
|||
# © 2018 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
|
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.nfse.mga.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
if method == "GerarNfse": |
|||
reference = "rps:%s" % kwargs["rps"]["numero"] |
|||
elif method == "CancelarNfse": |
|||
reference = "Cancelamento_NF%s" % kwargs["cancelamento"]["numero_nfse"] |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
return xml_send.encode("utf-8") |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://isse.maringa.pr.gov.br/ws/?wsdl" |
|||
else: |
|||
base_url = "https://isseteste.maringa.pr.gov.br/ws/?wsdl" |
|||
|
|||
xml_send = kwargs["xml"].decode("utf-8") |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(base_url, transport=transport) |
|||
response = client.service[method](xml_send) |
|||
|
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": str(xml_send), "received_xml": str(response), "object": obj} |
|||
|
|||
|
|||
def xml_gerar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def gerar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "CancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "CancelarNfse", **kwargs) |
|||
@ -0,0 +1,48 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import signxml |
|||
from lxml import etree |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
|||
from signxml import XMLSigner |
|||
|
|||
|
|||
class Assinatura(object): |
|||
def __init__(self, arquivo, senha): |
|||
self.arquivo = arquivo |
|||
self.senha = senha |
|||
|
|||
def assina_xml(self, xml_element, reference): |
|||
cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) |
|||
|
|||
for element in xml_element.iter("*"): |
|||
if element.text is not None and not element.text.strip(): |
|||
element.text = None |
|||
|
|||
signer = XMLSigner( |
|||
method=signxml.methods.enveloped, |
|||
signature_algorithm=u"rsa-sha1", |
|||
digest_algorithm=u"sha1", |
|||
c14n_algorithm=u"http://www.w3.org/TR/2001/REC-xml-c14n-20010315", |
|||
) |
|||
|
|||
ns = {} |
|||
ns[None] = signer.namespaces["ds"] |
|||
signer.namespaces = ns |
|||
element_to_be_signed = xml_element.getchildren()[0].getchildren()[0] |
|||
|
|||
signed_root = signer.sign( |
|||
element_to_be_signed, key=key.encode(), cert=cert.encode() |
|||
) |
|||
if reference: |
|||
element_signed = xml_element.find(".//*[@Id='%s']" % reference) |
|||
|
|||
signature = signed_root.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}Signature" |
|||
) |
|||
|
|||
if element_signed is not None and signature is not None: |
|||
parent = xml_element.getchildren()[0] |
|||
parent.append(signature) |
|||
return etree.tostring(xml_element, encoding=str) |
|||
@ -0,0 +1,15 @@ |
|||
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="Cancelamento_NF{{ cancelamento.numero_nfse }}"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>1</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,3 @@ |
|||
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
{% include 'Rps.xml' %} |
|||
</GerarNfseEnvio> |
|||
@ -0,0 +1,81 @@ |
|||
<Rps> |
|||
<InfDeclaracaoPrestacaoServico> |
|||
<Rps Id="rps:{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<Status>{{ rps.status }}</Status> |
|||
</Rps> |
|||
<Competencia>{{ rps.data_emissao }}</Competencia> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
<CodigoPais>{{ rps.codigo_pais }}</CodigoPais> |
|||
<ExigibilidadeISS>{{ rps.exigibilidade_iss}}</ExigibilidadeISS> |
|||
</Servico> |
|||
<Prestador> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<CodigoPais>{{ rps.tomador.codigo_pais }}</CodigoPais> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivoFiscal>{{ rps.incentivador_cultural }}</IncentivoFiscal> |
|||
</InfDeclaracaoPrestacaoServico> |
|||
</Rps> |
|||
@ -0,0 +1,116 @@ |
|||
# © 2019 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from OpenSSL import crypto |
|||
from base64 import b64encode |
|||
|
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
from requests.packages.urllib3 import disable_warnings |
|||
|
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
from lxml import etree |
|||
|
|||
|
|||
def sign_rps(path, certificado, **kwargs): |
|||
if "nfse" in kwargs: |
|||
lote = "" |
|||
for item in kwargs["nfse"]["lista_rps"]: |
|||
data = {"rps": item} |
|||
xml_rps = render_xml(path, "Rps.xml", True, **data) |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
lote += signer.assina_xml( |
|||
xml_rps, f"rps:{item.get('numero')}{item.get('serie')}", getchildren=True |
|||
) |
|||
return lote |
|||
return "" |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
parser = etree.XMLParser( |
|||
remove_blank_text=True, remove_comments=True, strip_cdata=False |
|||
) |
|||
|
|||
lote = "" |
|||
referencia = "" |
|||
if method == "RecepcionarLoteRps": |
|||
referencia = "lote" |
|||
lote = sign_rps(path, certificado, **kwargs) |
|||
|
|||
kwargs["lote"] = lote |
|||
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs) |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
|
|||
xml_send = signer.assina_xml(etree.fromstring( |
|||
xml_send, parser=parser), f"{referencia}", getchildren=True) |
|||
return xml_send |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://wsnfsev1.natal.rn.gov.br:8444" |
|||
else: |
|||
base_url = "https://wsnfsev1homologacao.natal.rn.gov.br:8443/axis2/services/NfseWSServiceV1?wsdl" |
|||
|
|||
base_url = "https://wsnfsev1homologacao.natal.rn.gov.br:8443/axis2/services/NfseWSServiceV1?wsdl" |
|||
cert, key = extract_cert_and_key_from_pfx( |
|||
certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
disable_warnings() |
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(wsdl=base_url, transport=transport) |
|||
xml_send = {} |
|||
xml_send = { |
|||
"nfseDadosMsg": kwargs["xml"], |
|||
"nfseCabecMsg": """<?xml version="1.0"?> |
|||
<cabecalho xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" versao="1" xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<versaoDados>1</versaoDados> |
|||
</cabecalho>""", |
|||
} |
|||
|
|||
response = client.service[method](**xml_send) |
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_recepcionar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "RecepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def recepcionar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "RecepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_consultar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "ConsultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def consultar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "ConsultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "cancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "cancelarNfse", **kwargs) |
|||
@ -0,0 +1,8 @@ |
|||
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<soap:Body> |
|||
<RecepcionarLoteRpsRequest xmlns="http://nfse.abrasf.org.br"> |
|||
<nfseCabecMsg><![CDATA[{% include 'cabecalho.xml' %}]]></nfseCabecMsg> |
|||
<nfseDadosMsg><![CDATA[{% include 'RecepcionarLoteRps.xml' %}]]></nfseDadosMsg> |
|||
</RecepcionarLoteRpsRequest> |
|||
</soap:Body> |
|||
</soap:Envelope> |
|||
@ -0,0 +1,111 @@ |
|||
<EnviarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<LoteRps Id="lote"> |
|||
<NumeroLote>1</NumeroLote> |
|||
<Cnpj>27596568000505</Cnpj> |
|||
<InscricaoMunicipal>1000047</InscricaoMunicipal> |
|||
<QuantidadeRps>1</QuantidadeRps> |
|||
<ListaRps> |
|||
<Rps> |
|||
<InfRps Id="rps:1ABCDZ"> |
|||
<IdentificacaoRps> |
|||
<Numero>1</Numero> |
|||
<Serie>ABCDH</Serie> |
|||
<Tipo>1</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>2010-06-16T21:00:00</DataEmissao> |
|||
<NaturezaOperacao>1</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>6</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>1</OptanteSimplesNacional> |
|||
<IncentivadorCultural>2</IncentivadorCultural> |
|||
<Status>1</Status> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>1000</ValorServicos> |
|||
<ValorPis>10</ValorPis> |
|||
<ValorCofins>10</ValorCofins> |
|||
<ValorInss>10</ValorInss> |
|||
<ValorIr>10</ValorIr> |
|||
<ValorCsll>10</ValorCsll> |
|||
<IssRetido>1</IssRetido> |
|||
<ValorIss>50</ValorIss> |
|||
<OutrasRetencoes>10</OutrasRetencoes> |
|||
<BaseCalculo>1000</BaseCalculo> |
|||
<Aliquota>0.05</Aliquota> |
|||
</Valores> |
|||
<ItemListaServico>11.01</ItemListaServico> |
|||
<CodigoCnae>4520005</CodigoCnae> |
|||
<Discriminacao>Teste.</Discriminacao> |
|||
<CodigoMunicipio>3106200</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>27596568000505</Cnpj> |
|||
<InscricaoMunicipal>1000047</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
<Cnpj>24533572000102</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>1000039</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>INSCRICAO DE TESTE SIATU - DAGUA -PAULINOS</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>DA BAHIA</Endereco> |
|||
<Numero>200</Numero> |
|||
<Complemento>ANDAR 14</Complemento> |
|||
<Bairro>CENTRO</Bairro> |
|||
<CodigoMunicipio>2408102</CodigoMunicipio> |
|||
<Uf>RN</Uf> |
|||
<Cep>30160010</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Email>marcelo@teste.com.br</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
<ConstrucaoCivil> |
|||
<CodigoObra>1234</CodigoObra> |
|||
<Art>1234</Art> |
|||
</ConstrucaoCivil> |
|||
</InfRps> |
|||
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> |
|||
<SignedInfo> |
|||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" /> |
|||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> |
|||
<Reference URI="#rps:1ABCDZ"> |
|||
<Transforms> |
|||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> |
|||
</Transforms> |
|||
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> |
|||
<DigestValue>mMyQLAm4psxx52kaD8Jlta3ouPM=</DigestValue> |
|||
</Reference> |
|||
</SignedInfo> |
|||
<SignatureValue>qBKfaNz6RbsYUxCOrjGZ9zrdgiGL7QSBxjlhYRlKDNlDERlDWvM8gi28yus8FoUb0v2CTKKIBz0tzfqxgk60rke4YCMkTzdWfpm7ofMIhYC9VHqbWdInC20znOKygJy5hyIx6JBoyXbejnw/0KF+2E1P1ZehqXJWZqY+KPaIGAY=</SignatureValue> |
|||
<KeyInfo> |
|||
<X509Data> |
|||
<X509Certificate>MIIE7DCCA9SgAwIBAgIQZMlLC9ZEsHWsnvJNdMI2yzANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDEsMCoGA1UECxMjU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgLSBTUkYxGDAWBgNVBAMTD0FDIFBST0RFTUdFIFNSRjAeFw0wNzEwMzEwMDAwMDBaFw0xMDEwMzAyMzU5NTlaMIGQMQswCQYDVQQGEwJCUjETMBEGA1UEChQKSUNQLUJyYXNpbDEqMCgGA1UECxQhU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwtU1JGMRIwEAYDVQQLFAlTUkYgZS1DUEYxLDAqBgNVBAMTI0VER0FSIERPIENBUk1PIEZFUlJFSVJBOjQzMjYwMTUyNjg3MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6M+9XT5KLQN3IH8mAr+S6vxiochY/EwF8EhtNoxPTYl+zr0Dh+eZsRG31bN410nr2OrwncrRorMK8Ngq+j3FnNF0nIMigaaa5NAEfIk3Yy4kuqrTUZBpqUJvCqc3mkF3C3XD0MTmtbVTWCvYIk+qn3t5ShHyMnQcuah5Q0ItSbQIDAQABo4IB6TCCAeUwgZUGA1UdEQSBjTCBiqA9BgVgTAEDAaA0BDIyMTAzMTk2NDQzMjYwMTUyNjg3MDAwMDAwMDAwMDAwMDAwMDBNLTI4ODQwODVTU1BNR6AXBgVgTAEDBqAOBAwwMDAwMDAwMDAwMDCgHgYFYEwBAwWgFQQTMDAwMDAwMDAwMDAwMDAwMDAwMIEQZWRnYXJAcGJoLmdvdi5icjAJBgNVHRMEAjAAMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly9pY3AtYnJhc2lsLmNlcnRpc2lnbi5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL0FDUFJPREVNR0VTUkYvTGF0ZXN0Q1JMLmNybDAfBgNVHSMEGDAWgBTdO9vtjZcRRUMBQ020Ev0O7niacDAOBgNVHQ8BAf8EBAMCBeAwVQYDVR0gBE4wTDBKBgZgTAECAxQwQDA+BggrBgEFBQcCARYyaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNvbS5ici9yZXBvc2l0b3Jpby9kcGMwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMCMDgGCCsGAQUFBwEBBCwwKjAoBggrBgEFBQcwAYYcaHR0cDovL29jc3AuY2VydGlzaWduLmNvbS5icjANBgkqhkiG9w0BAQUFAAOCAQEAYFcjZj4lGVEREHBaHtcRletWS6/mvpkxmodwj3ele5yXsxuqSZd7ebHbKewXx7gkyaWFkFAxFanQhls2tYKjg6haqt2b0AO1FsitVIHkMcxRwkU9G+1ec8yfdxymra2VdXazkxuvqKABgxkqKnaFdHjje7cjWDgwparymH64mTlHkSQz59GutJW0xfwBHcMGx0/9/iIug6pfMQivWf0NMVpFNzxO5ZNPEuOeBhVDxQr4+KB+4B9xDai/3J6f42UNbSy+z3xuB0K8/7V7BsFUYOYFSNnBrXhvbvXtZOtteX65V0r1+RJJX5OK+PAPhZ57T1LEmHMggdo5kli3Nr1KFQ==</X509Certificate> |
|||
</X509Data> |
|||
</KeyInfo> |
|||
</Signature> |
|||
</Rps> |
|||
</ListaRps> |
|||
</LoteRps> |
|||
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="Ass_lote"> |
|||
<SignedInfo> |
|||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" /> |
|||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> |
|||
<Reference URI="#lote"> |
|||
<Transforms> |
|||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> |
|||
</Transforms> |
|||
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> |
|||
<DigestValue>n42EhtzDSnZ071g+44ZMBCc74UQ=</DigestValue> |
|||
</Reference> |
|||
</SignedInfo> |
|||
<SignatureValue>pQyeXnJ2S9KyUJ1BE3k3PZuDpk7WkD2nMPLoELSLJeNBe9TwmLhImsIUS4inAUreuTsjfrs2BUmChN6jPA0/1cSR0GbblLsHFN+IwPE2dnPN/u0vIOmsan4MuW1OnlH6KexmDHRj/uFwjoXfSJ0JJE1u9bYdbsp5LGlFuc//CCQ=</SignatureValue> |
|||
<KeyInfo> |
|||
<X509Data> |
|||
<X509Certificate>MIIE7DCCA9SgAwIBAgIQZMlLC9ZEsHWsnvJNdMI2yzANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDEsMCoGA1UECxMjU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgLSBTUkYxGDAWBgNVBAMTD0FDIFBST0RFTUdFIFNSRjAeFw0wNzEwMzEwMDAwMDBaFw0xMDEwMzAyMzU5NTlaMIGQMQswCQYDVQQGEwJCUjETMBEGA1UEChQKSUNQLUJyYXNpbDEqMCgGA1UECxQhU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwtU1JGMRIwEAYDVQQLFAlTUkYgZS1DUEYxLDAqBgNVBAMTI0VER0FSIERPIENBUk1PIEZFUlJFSVJBOjQzMjYwMTUyNjg3MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6M+9XT5KLQN3IH8mAr+S6vxiochY/EwF8EhtNoxPTYl+zr0Dh+eZsRG31bN410nr2OrwncrRorMK8Ngq+j3FnNF0nIMigaaa5NAEfIk3Yy4kuqrTUZBpqUJvCqc3mkF3C3XD0MTmtbVTWCvYIk+qn3t5ShHyMnQcuah5Q0ItSbQIDAQABo4IB6TCCAeUwgZUGA1UdEQSBjTCBiqA9BgVgTAEDAaA0BDIyMTAzMTk2NDQzMjYwMTUyNjg3MDAwMDAwMDAwMDAwMDAwMDBNLTI4ODQwODVTU1BNR6AXBgVgTAEDBqAOBAwwMDAwMDAwMDAwMDCgHgYFYEwBAwWgFQQTMDAwMDAwMDAwMDAwMDAwMDAwMIEQZWRnYXJAcGJoLmdvdi5icjAJBgNVHRMEAjAAMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly9pY3AtYnJhc2lsLmNlcnRpc2lnbi5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL0FDUFJPREVNR0VTUkYvTGF0ZXN0Q1JMLmNybDAfBgNVHSMEGDAWgBTdO9vtjZcRRUMBQ020Ev0O7niacDAOBgNVHQ8BAf8EBAMCBeAwVQYDVR0gBE4wTDBKBgZgTAECAxQwQDA+BggrBgEFBQcCARYyaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNvbS5ici9yZXBvc2l0b3Jpby9kcGMwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMCMDgGCCsGAQUFBwEBBCwwKjAoBggrBgEFBQcwAYYcaHR0cDovL29jc3AuY2VydGlzaWduLmNvbS5icjANBgkqhkiG9w0BAQUFAAOCAQEAYFcjZj4lGVEREHBaHtcRletWS6/mvpkxmodwj3ele5yXsxuqSZd7ebHbKewXx7gkyaWFkFAxFanQhls2tYKjg6haqt2b0AO1FsitVIHkMcxRwkU9G+1ec8yfdxymra2VdXazkxuvqKABgxkqKnaFdHjje7cjWDgwparymH64mTlHkSQz59GutJW0xfwBHcMGx0/9/iIug6pfMQivWf0NMVpFNzxO5ZNPEuOeBhVDxQr4+KB+4B9xDai/3J6f42UNbSy+z3xuB0K8/7V7BsFUYOYFSNnBrXhvbvXtZOtteX65V0r1+RJJX5OK+PAPhZ57T1LEmHMggdo5kli3Nr1KFQ==</X509Certificate> |
|||
</X509Data> |
|||
</KeyInfo> |
|||
</Signature> |
|||
</EnviarLoteRpsEnvio> |
|||
@ -0,0 +1,112 @@ |
|||
<Rps> |
|||
<InfRps Id="rps:{{ rps.numero }}{{ rps.serie }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.servico.valor_servico }}</ValorServicos> |
|||
<ValorPis>{{ rps.servico.pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.servico.cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.servico.inss }}</ValorInss> |
|||
<ValorIr>{{ rps.servico.ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.servico.csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.servico.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.servico.iss }}</ValorIss> |
|||
<OutrasRetencoes>{{ rps.servico.retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.servico.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.servico.aliquota }}</Aliquota> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.servico.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.servico.cnae_servico }}</CodigoCnae> |
|||
<Discriminacao>{{ rps.servico.discriminacao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.servico.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
<RazaoSocial>{{ rps.prestador.razaosocial }}</RazaoSocial> |
|||
<NomeFantasia>{{ rps.prestador.fantasia }}</NomeFantasia> |
|||
<Endereco> |
|||
<Endereco>{{ rps.prestador.endereco }}</Endereco> |
|||
<Numero>{{ rps.prestador.numero }}</Numero> |
|||
<Complemento>{{ rps.prestador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.prestador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.prestador.codigomunicipal }}</CodigoMunicipio> |
|||
<Uf>{{ rps.prestador.uf }}</Uf> |
|||
<Cep>{{ rps.prestador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
{% if rps.prestador.telefone is defined -%} |
|||
<Telefone>{{ rps.prestador.telefone }}</Telefone> |
|||
{% endif %} |
|||
{% if rps.prestador.email is defined -%} |
|||
<Email>{{ rps.prestador.email }}</Email> |
|||
{% endif %} |
|||
</Contato> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cpf_cnpj|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cpf_cnpj }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cpf_cnpj|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cpf_cnpj }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
{% if rps.tomador.inscricao_municipal is defined -%} |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
{% endif %} |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.endereco }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.codigo_municipio }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
{% if rps.tomador.telefone is defined -%} |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
{% endif %} |
|||
{% if rps.tomador.email is defined -%} |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
{% endif %} |
|||
</Contato> |
|||
{% if rps.tomador.orgao_gerador is defined -%} |
|||
<OrgaoGerador> |
|||
<CodigoMunicipio>{{ rps.tomador.orgao_gerador.codigo_municipio }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.orgao_gerador.uf }}</Uf> |
|||
</OrgaoGerador> |
|||
{% endif %} |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
<Signature Id="placeholder"></Signature> |
|||
</Rps> |
|||
@ -0,0 +1,3 @@ |
|||
<cabecalho versao="2.01" xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<versaoDados>2.01</versaoDados> |
|||
</cabecalho> |
|||
@ -0,0 +1,15 @@ |
|||
<CancelarNfseEnvio xmlns="http://nfse.abrasf.org.br"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="1"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>{{ cancelamento.codigo_cancelamento }}</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,7 @@ |
|||
<ConsultarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<Prestador> |
|||
<Cnpj>{{ consulta.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ consulta.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
</ConsultarLoteRpsEnvio> |
|||
@ -0,0 +1,11 @@ |
|||
<EnviarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<LoteRps Id="lote"> |
|||
<NumeroLote>{{ nfse.numero_lote }}</NumeroLote> |
|||
<Cnpj>{{ nfse.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ nfse.inscricao_municipal }}</InscricaoMunicipal> |
|||
<QuantidadeRps>{{ nfse.lista_rps|length }}</QuantidadeRps> |
|||
<ListaRps> |
|||
{{lote}} |
|||
</ListaRps> |
|||
</LoteRps> |
|||
</EnviarLoteRpsEnvio> |
|||
@ -1 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?><RetornoEnvioLoteRPS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.prefeitura.sp.gov.br/nfe"><Cabecalho Versao="1" xmlns=""><Sucesso>true</Sucesso><InformacoesLote><NumeroLote>2654364</NumeroLote><InscricaoPrestador>51212</InscricaoPrestador><CPFCNPJRemetente><CNPJ>21332900163</CNPJ></CPFCNPJRemetente><DataEnvioLote>2016-08-29T10:52:15</DataEnvioLote><QtdNotasProcessadas>1</QtdNotasProcessadas><TempoProcessamento>0</TempoProcessamento><ValorTotalServicos>1.35</ValorTotalServicos></InformacoesLote></Cabecalho><ChaveNFeRPS xmlns=""><ChaveNFe><InscricaoPrestador>52382</InscricaoPrestador><NumeroNFe>446</NumeroNFe><CodigoVerificacao>APR9MJR</CodigoVerificacao></ChaveNFe><ChaveRPS><InscricaoPrestador>51282</InscricaoPrestador><SerieRPS>1</SerieRPS><NumeroRPS>6</NumeroRPS></ChaveRPS></ChaveNFeRPS></RetornoEnvioLoteRPS> |
|||
@ -1,34 +0,0 @@ |
|||
# -*- coding: utf-8-*- |
|||
# © 2016 Alessandro Fernandes Martini |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import unittest |
|||
# from lxml import etree |
|||
from pytrustnfe.nfe import _add_qrCode |
|||
|
|||
|
|||
class TestAddQRCode(unittest.TestCase): |
|||
def setUp(self): |
|||
self.xml_sem_qrcode = open('pytrustnfe/test/xml_sem_qrcode.xml', 'r') |
|||
self.xml_com_qrcode = open('pytrustnfe/test/xml_com_qrcode.xml', 'r') |
|||
dhEmi = '2016-11-09T16:03:25-00:00' |
|||
chave_nfe = u'NFe35161121332917000163650010000000011448875034' |
|||
ambiente = 2 |
|||
valor_total = '324.00' |
|||
icms_total = '61.56' |
|||
cid_token = '000001' |
|||
csc = '123456789' |
|||
estado = '35' |
|||
total = {'vNF': valor_total, 'vICMS': icms_total} |
|||
infnfe = {'ide': {'dhEmi': dhEmi}, 'Id': chave_nfe, 'total': total, |
|||
'codigo_seguranca': {'cid_token': cid_token, 'csc': csc}} |
|||
infnfe = {'infNFe': infnfe} |
|||
self.kwargs = {} |
|||
self.kwargs['ambiente'] = ambiente |
|||
self.kwargs['estado'] = estado |
|||
self.kwargs['NFes'] = [infnfe] |
|||
|
|||
def test_add_qrCode(self): |
|||
xml_init = self.xml_sem_qrcode.read() |
|||
xml_end = _add_qrCode(xml_init, **self.kwargs) |
|||
self.assertEqual(xml_end, self.xml_com_qrcode.read()) |
|||
@ -1,57 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 14, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import os |
|||
import os.path |
|||
import unittest |
|||
from lxml import etree |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
|
|||
|
|||
XML_ASSINAR = '<?xml version="1.0" encoding="UTF-8"?>' \ |
|||
'<Envelope xmlns="urn:envelope">' \ |
|||
' <Data Id="NFe43150602261542000143550010000000761792265342">'\ |
|||
' Hello, World!' \ |
|||
' </Data>' \ |
|||
'</Envelope>' |
|||
|
|||
|
|||
XML_ERRADO = '<?xml version="1.0" encoding="UTF-8"?>' \ |
|||
'<Envelope xmlns="urn:envelope">' \ |
|||
' <Data Id="NFe">' \ |
|||
' Hello, World!' \ |
|||
' </Data>' \ |
|||
'</Envelope>' |
|||
|
|||
|
|||
class test_assinatura(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def test_assinar_xml_senha_invalida(self): |
|||
pfx = open(os.path.join(self.caminho, 'teste.pfx')).read() |
|||
signer = Assinatura(pfx, '123') |
|||
self.assertRaises(Exception, signer.assina_xml, signer, |
|||
etree.fromstring(XML_ASSINAR), |
|||
'NFe43150602261542000143550010000000761792265342') |
|||
|
|||
def test_assinar_xml_invalido(self): |
|||
pfx = open(os.path.join(self.caminho, 'teste.pfx')).read() |
|||
signer = Assinatura(pfx, '123456') |
|||
self.assertRaises(Exception, signer.assina_xml, signer, |
|||
etree.fromstring(XML_ERRADO), |
|||
'NFe43150602261542000143550010000000761792265342') |
|||
|
|||
def test_assinar_xml_valido(self): |
|||
pfx = open(os.path.join(self.caminho, 'teste.pfx')).read() |
|||
signer = Assinatura(pfx, '123456') |
|||
xml = signer.assina_xml( |
|||
etree.fromstring(XML_ASSINAR), |
|||
'NFe43150602261542000143550010000000761792265342') |
|||
xml_assinado = open(os.path.join(self.caminho, |
|||
'xml_valido_assinado.xml'), |
|||
'r').read() |
|||
self.assertEqual(xml_assinado, xml, 'Xml assinado é inválido') |
|||
@ -1,82 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 14, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import unittest |
|||
import os |
|||
import os.path |
|||
from pytrustnfe.certificado import Certificado |
|||
from pytrustnfe.certificado import save_cert_key |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
|||
|
|||
CHAVE = '-----BEGIN PRIVATE KEY-----\n' \ |
|||
'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJONRp6l1y2ojgv8\n' \ |
|||
'tP3AOLW0vjWQqiPseBLM7YAxbzz5R7LYlWHC0ZJ4uIvd4Cvc6AuoNJoeuhzFcwHx\n' \ |
|||
'PL0TcFuW+5up1ktUohwaJ+/zKrMODCKt0gvif302yqasMnwLh9mGZQIkLkHPOX8p\n' \ |
|||
'ZQDC4dlqwOyYDi0f+bRd5C7aWx3RAgMBAAECgYADqASP+dwTLZIXifOSNikxl4D/\n' \ |
|||
'Is6UhU+UZ6+a9Z6kDClSrTtGaOV4k7U/AgiEDb1STKDBEPHbtKjc63Vt2gV2teem\n' \ |
|||
'ohU0Giv+gD42uuwy2DM31OfYrpR46mzOK9JrpQc78b36ealL3AWJ1gyBbbcOWbAb\n' \ |
|||
'KmP742V7pcD07EEp4QJBAM/e7M8VdLgOyaQzH9KHekU6fJlI4vy1UwgRUwx3/1W6\n' \ |
|||
'zlBYo1qXfc7NSVG8ZaSrJwW4rPn393u31CpXv+oc/OMCQQC1txS6nxM9+p/641HX\n' \ |
|||
'CHXiWJRn0Wv7rT1FyF2dHO+OQOkCCnHCsGDMf3bacTNb7iyaPbXEDac8od5uF/3h\n' \ |
|||
'aUy7AkBDPGoAeYItXqseL2Mlp6iG5+oRcp/o+YWH4IKqT84JHslI98KutL1+vKvw\n'\ |
|||
'gi2mW63djeR1Xh1wqP85SvTKduHdAkAIJLlIF8Lr/yRWQQO06EsoJqIX+Pmm4L+j\n'\ |
|||
'NfSECvztWhlXHxK0D+V2pKu15GbR0t2q1+Micx4wiGyIcIjPJkHrAkAvlbXGFcGT\n'\ |
|||
'pk9bQ8nl7EYqlvVn1TejzTLfBhBYOse/xT/NI4Kwjkan9R+EJ1cOc9EE8gm1W3jv\n'\ |
|||
'fMw/Bh2wC5kj\n'\ |
|||
'-----END PRIVATE KEY-----\n' |
|||
|
|||
CERTIFICADO = '-----BEGIN CERTIFICATE-----\n'\ |
|||
'MIICMTCCAZqgAwIBAgIQfYOsIEVuAJ1FwwcTrY0t1DANBgkqhkiG9w0BAQUFADBX\n'\ |
|||
'MVUwUwYDVQQDHkwAewA1ADkARgAxAEUANAA2ADEALQBEAEQARQA1AC0ANABEADIA\n'\ |
|||
'RgAtAEEAMAAxAEEALQA4ADMAMwAyADIAQQA5AEUAQgA4ADMAOAB9MB4XDTE1MDYx\n'\ |
|||
'NTA1NDc1N1oXDTE2MDYxNDExNDc1N1owVzFVMFMGA1UEAx5MAHsANQA5AEYAMQBF\n'\ |
|||
'ADQANgAxAC0ARABEAEUANQAtADQARAAyAEYALQBBADAAMQBBAC0AOAAzADMAMgAy\n'\ |
|||
'AEEAOQBFAEIAOAAzADgAfTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAk41G\n'\ |
|||
'nqXXLaiOC/y0/cA4tbS+NZCqI+x4EsztgDFvPPlHstiVYcLRkni4i93gK9zoC6g0\n'\ |
|||
'mh66HMVzAfE8vRNwW5b7m6nWS1SiHBon7/Mqsw4MIq3SC+J/fTbKpqwyfAuH2YZl\n'\ |
|||
'AiQuQc85fyllAMLh2WrA7JgOLR/5tF3kLtpbHdECAwEAATANBgkqhkiG9w0BAQUF\n'\ |
|||
'AAOBgQArdh+RyT6VxKGsXk1zhHsgwXfToe6GpTF4W8PHI1+T0WIsNForDhvst6nm\n'\ |
|||
'QtgAhuZM9rxpOJuNKc+pM29EixpAiZZiRMCSWEItNyEVdUIi+YnKBcAHd88TwO86\n'\ |
|||
'd126MWQ2O8cu5W1VoDp7hYBYKOnLbYi11/StO+0rzK+oPYAvIw==\n'\ |
|||
'-----END CERTIFICATE-----\n' |
|||
|
|||
|
|||
class test_assinatura(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def test_preparar_pfx(self): |
|||
dir_pfx = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
cert, key = extract_cert_and_key_from_pfx(dir_pfx, '123456') |
|||
self.assertEqual(key, CHAVE, 'Chave gerada inválida') |
|||
self.assertEqual(cert, CERTIFICADO, 'Certificado inválido') |
|||
|
|||
def test_save_pfx(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123') |
|||
path = pfx.save_pfx() |
|||
saved = open(path, 'r').read() |
|||
self.assertEqual(pfx_source, saved, |
|||
'Arquivo pfx salvo não bate com arquivo lido') |
|||
|
|||
def test_save_cert_and_key(self): |
|||
dir_pfx = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
cert, key = extract_cert_and_key_from_pfx(dir_pfx, '123456') |
|||
cert_path, key_path = save_cert_key(cert, key) |
|||
cert_saved = open(cert_path, 'r').read() |
|||
key_saved = open(key_path, 'r').read() |
|||
self.assertEqual( |
|||
cert, cert_saved, 'Certificado não corresponde ao original') |
|||
self.assertEqual(key, key_saved, 'Chave não corresponde ao original') |
|||
|
|||
def test_pfx_nao_existe(self): |
|||
self.assertRaises(Exception, extract_cert_and_key_from_pfx, |
|||
'file.pfx', '123456') |
|||
|
|||
def test_pfx_senha_invalida(self): |
|||
dir_pfx = os.path.join(self.caminho, 'teste.pfx') |
|||
self.assertRaises(Exception, extract_cert_and_key_from_pfx, |
|||
dir_pfx, '123') |
|||
@ -1,20 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 16, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import unittest |
|||
import os.path |
|||
|
|||
|
|||
XML_RETORNO = '<retEnviNFe><cStat>103</cStat>' \ |
|||
'<cUF>42</cUF></retEnviNFe>' |
|||
|
|||
|
|||
class test_comunicacao(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def test_envio_nfe(self): |
|||
pass |
|||
@ -1,19 +0,0 @@ |
|||
# coding=utf-8 |
|||
|
|||
import mock |
|||
import os.path |
|||
import unittest |
|||
from pytrustnfe.certificado import Certificado |
|||
from pytrustnfe.nfe import consulta_cadastro |
|||
|
|||
|
|||
class test_consulta_cadastro(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def test_conta_de_cadastro(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
|
|||
obj = {'cnpj': '12345678901234', 'estado': '42'} |
|||
consulta_cadastro(pfx, obj=obj, ambiente=1, estado='42') |
|||
@ -1,143 +0,0 @@ |
|||
# coding=utf-8 |
|||
|
|||
import mock |
|||
import os.path |
|||
import unittest |
|||
from pytrustnfe.certificado import Certificado |
|||
from pytrustnfe.nfse.paulistana import envio_lote_rps |
|||
from pytrustnfe.nfse.paulistana import cancelamento_nfe |
|||
from pytrustnfe.nfse.assinatura import Assinatura |
|||
from pytrustnfe.nfse.paulistana import sign_tag |
|||
|
|||
|
|||
class test_nfse_paulistana(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def _get_nfse(self): |
|||
rps = [ |
|||
{ |
|||
'assinatura': '123', |
|||
'serie': '1', |
|||
'numero': '1', |
|||
'data_emissao': '2016-08-29', |
|||
'codigo_atividade': '07498', |
|||
'total_servicos': '2.00', |
|||
'total_deducoes': '3.00', |
|||
'prestador': { |
|||
'inscricao_municipal': '123456' |
|||
}, |
|||
'tomador': { |
|||
'tipo_cpfcnpj': '1', |
|||
'cpf_cnpj': '12345678923256', |
|||
'inscricao_municipal': '123456', |
|||
'razao_social': 'Trustcode', |
|||
'tipo_logradouro': '1', |
|||
'logradouro': 'Vinicius de Moraes, 42', |
|||
'numero': '42', |
|||
'bairro': 'Corrego', |
|||
'cidade': 'Floripa', |
|||
'uf': 'SC', |
|||
'cep': '88037240', |
|||
}, |
|||
'codigo_atividade': '07498', |
|||
'aliquota_atividade': '5.00', |
|||
'descricao': 'Venda de servico' |
|||
} |
|||
] |
|||
nfse = { |
|||
'cpf_cnpj': '12345678901234', |
|||
'data_inicio': '2016-08-29', |
|||
'data_fim': '2016-08-29', |
|||
'lista_rps': rps |
|||
} |
|||
return nfse |
|||
|
|||
def test_envio_nfse(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
|
|||
nfse = self._get_nfse() |
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_return = open(os.path.join( |
|||
path, 'paulistana_resultado.xml'), 'r').read() |
|||
|
|||
with mock.patch('pytrustnfe.nfse.paulistana.get_authenticated_client') as client: |
|||
retorno = mock.MagicMock() |
|||
client.return_value = retorno |
|||
retorno.service.EnvioLoteRPS.return_value = xml_return |
|||
|
|||
retorno = envio_lote_rps(pfx, nfse=nfse) |
|||
|
|||
self.assertEqual(retorno['received_xml'], xml_return) |
|||
self.assertEqual(retorno['object'].Cabecalho.Sucesso, True) |
|||
self.assertEqual( |
|||
retorno['object'].ChaveNFeRPS.ChaveNFe.NumeroNFe, 446) |
|||
self.assertEqual( |
|||
retorno['object'].ChaveNFeRPS.ChaveRPS.NumeroRPS, 6) |
|||
|
|||
def test_nfse_signature(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
|
|||
nfse = self._get_nfse() |
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_sent = open(os.path.join( |
|||
path, 'paulistana_signature.xml'), 'r').read() |
|||
|
|||
with mock.patch('pytrustnfe.nfse.paulistana.get_authenticated_client') as client: |
|||
retorno = mock.MagicMock() |
|||
client.return_value = retorno |
|||
retorno.service.EnvioLoteRPS.return_value = '<xml></xml>' |
|||
|
|||
retorno = envio_lote_rps(pfx, nfse=nfse) |
|||
self.assertEqual(retorno['sent_xml'], xml_sent) |
|||
|
|||
def _get_cancelamento(self): |
|||
return { |
|||
'cnpj_remetente': '123', |
|||
'assinatura': 'assinatura', |
|||
'numero_nfse': '456', |
|||
'inscricao_municipal': '654', |
|||
'codigo_verificacao': '789', |
|||
} |
|||
|
|||
def test_cancelamento_nfse_ok(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
cancelamento = self._get_cancelamento() |
|||
|
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_return = open(os.path.join( |
|||
path, 'paulistana_canc_ok.xml'), 'r').read() |
|||
|
|||
with mock.patch('pytrustnfe.nfse.paulistana.get_authenticated_client') as client: |
|||
retorno = mock.MagicMock() |
|||
client.return_value = retorno |
|||
retorno.service.CancelamentoNFe.return_value = xml_return |
|||
|
|||
retorno = cancelamento_nfe(pfx, cancelamento=cancelamento) |
|||
|
|||
self.assertEqual(retorno['received_xml'], xml_return) |
|||
self.assertEqual(retorno['object'].Cabecalho.Sucesso, True) |
|||
|
|||
def test_cancelamento_nfse_com_erro(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
cancelamento = self._get_cancelamento() |
|||
|
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_return = open(os.path.join( |
|||
path, 'paulistana_canc_errado.xml'), 'r').read() |
|||
|
|||
with mock.patch('pytrustnfe.nfse.paulistana.get_authenticated_client') as client: |
|||
retorno = mock.MagicMock() |
|||
client.return_value = retorno |
|||
retorno.service.CancelamentoNFe.return_value = xml_return |
|||
|
|||
retorno = cancelamento_nfe(pfx, cancelamento=cancelamento) |
|||
|
|||
self.assertEqual(retorno['received_xml'], xml_return) |
|||
self.assertEqual(retorno['object'].Cabecalho.Sucesso, False) |
|||
self.assertEqual( |
|||
retorno['object'].Erro.ChaveNFe.NumeroNFe, 446) |
|||
@ -1,48 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 14, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import unittest |
|||
from pytrustnfe.Servidores import localizar_url, localizar_qrcode |
|||
|
|||
url_ba = 'https://nfe.sefaz.ba.gov.br/webservices/NfeAutorizacao/NfeAutoriza\ |
|||
cao.asmx' |
|||
|
|||
url_sp = 'https://nfe.fazenda.sp.gov.br/ws/nfeautorizacao.asmx' |
|||
|
|||
url_qrcode_homologacao_sp = 'https://homologacao.nfce.fazenda.sp.gov.br/NFCEConsultaPublica/Paginas/ConstultaQRCode.aspx' |
|||
|
|||
url_sc = 'https://nfe.svrs.rs.gov.br/ws/NfeAutorizacao/NfeAutorizacao.asmx' |
|||
|
|||
url_rs = 'https://nfe.sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao.asmx' |
|||
|
|||
url_cad_rs = 'https://cad.sefazrs.rs.gov.br/ws/cadconsultacadastro/cadcon\ |
|||
sultacadastro2.asmx' |
|||
|
|||
url_cad_sc = 'https://cad.svrs.rs.gov.br/ws/CadConsultaCadastro/CadConsult\ |
|||
aCadastro2.asmx' |
|||
|
|||
|
|||
class test_servidores(unittest.TestCase): |
|||
|
|||
def test_localizar_url(self): |
|||
url = localizar_url('NfeAutorizacao', '29', ambiente=1) |
|||
self.assertEqual(url, url_ba) |
|||
url = localizar_url('NfeAutorizacao', '35', ambiente=1) |
|||
self.assertEqual(url, url_sp) |
|||
url = localizar_url('NfeAutorizacao', '42', ambiente=1) |
|||
self.assertEqual(url, url_sc) |
|||
url = localizar_url('NfeAutorizacao', '43', ambiente=1) |
|||
self.assertEqual(url, url_rs) |
|||
|
|||
url = localizar_url('NfeConsultaCadastro', '43', ambiente=2) |
|||
self.assertEqual(url, url_cad_rs) |
|||
|
|||
url = localizar_url('NfeConsultaCadastro', '42', ambiente=2) |
|||
self.assertEqual(url, url_cad_sc) |
|||
|
|||
def test_localizar_qrcode(self): |
|||
url = localizar_qrcode('35') |
|||
self.assertEqual(url, url_qrcode_homologacao_sp) |
|||
@ -1,119 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 16, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import unittest |
|||
import datetime |
|||
from pytrustnfe.utils import date_tostring, datetime_tostring, \ |
|||
gerar_chave |
|||
from pytrustnfe.utils import ChaveNFe, CabecalhoSoap |
|||
|
|||
|
|||
class test_utils(unittest.TestCase): |
|||
kwargs = { |
|||
'cnpj': '33009911002506', 'estado': '52', 'emissao': '0604', |
|||
'modelo': '55', 'serie': '012', 'numero': 780, |
|||
'tipo': 0, 'codigo': '26730161' |
|||
} |
|||
|
|||
def test_cabecalho_soap(self): |
|||
head = CabecalhoSoap(versao=1, estado='SC', soap_action='Autorizacao') |
|||
self.assertEqual(head.versao, 1) |
|||
self.assertEqual(head.estado, 'SC') |
|||
self.assertEqual(head.soap_action, 'Autorizacao') |
|||
|
|||
def test_date_tostring(self): |
|||
hoje = datetime.date.today() |
|||
data = date_tostring(hoje) |
|||
self.assertEqual(data, hoje.strftime("%d-%m-%y"), |
|||
"Não convertido corretamente") |
|||
self.assertRaises(Exception, date_tostring, "Not a date") |
|||
|
|||
def test_datetime_tostring(self): |
|||
hoje = datetime.datetime.now() |
|||
data = datetime_tostring(hoje) |
|||
self.assertEqual(data, hoje.strftime("%d-%m-%y %H:%M:%S"), |
|||
"Não convertido corretamente") |
|||
self.assertRaises(Exception, datetime_tostring, "Not a date") |
|||
|
|||
def test_geracao_chave(self): |
|||
chave = ChaveNFe(**self.kwargs) |
|||
str_chave = gerar_chave(chave) |
|||
chave_correta = '52060433009911002506550120000007800267301615' |
|||
self.assertEqual(str_chave, chave_correta, |
|||
"Geração de chave nf-e incorreta") |
|||
|
|||
str_chave = gerar_chave(chave, prefix='NFe') |
|||
chave_correta = 'NFe52060433009911002506550120000007800267301615' |
|||
self.assertEqual(str_chave, chave_correta, |
|||
"Geração de chave nf-e com prefixo incorreta") |
|||
|
|||
self.assertRaises(Exception, gerar_chave, "Not a ChaveNFe object") |
|||
self.assertRaises(Exception, gerar_chave, "Not a ChaveNFe object") |
|||
|
|||
def test_chave_nfe(self): |
|||
chave = ChaveNFe(**self.kwargs) |
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.cnpj = '' |
|||
chave.validar() |
|||
chave.cnpj = '1234567891011' |
|||
self.assertEqual('CNPJ necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.estado = '' |
|||
chave.validar() |
|||
chave.estado = '42' |
|||
self.assertEqual('Estado necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.emissao = '' |
|||
chave.validar() |
|||
chave.emissao = '0' |
|||
self.assertEqual('Emissão necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.modelo = '' |
|||
chave.validar() |
|||
chave.modelo = '55' |
|||
self.assertEqual('Modelo necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.serie = '' |
|||
chave.validar() |
|||
chave.serie = '012' |
|||
self.assertEqual('Série necessária para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.numero = '' |
|||
chave.validar() |
|||
chave.numero = '000000780' |
|||
self.assertEqual('Número necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.tipo = '' |
|||
chave.validar() |
|||
chave.tipo = '42' |
|||
self.assertEqual('Tipo necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.codigo = '' |
|||
chave.validar() |
|||
self.assertEqual('Código necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
@ -1,37 +0,0 @@ |
|||
# coding=utf-8 |
|||
|
|||
import os.path |
|||
import unittest |
|||
from lxml import etree |
|||
from pytrustnfe.xml import render_xml |
|||
from pytrustnfe.xml import sanitize_response |
|||
|
|||
|
|||
class test_xml_serializacao(unittest.TestCase): |
|||
|
|||
def test_serializacao_default(self): |
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml = render_xml(path, 'jinja_template.xml', False, tag1='oi', |
|||
tag2='ola', tag3='comovai') |
|||
|
|||
result = open(os.path.join(path, 'jinja_result.xml'), 'r').read() |
|||
self.assertEqual(xml + '\n', result) |
|||
|
|||
def test_serializacao_remove_empty(self): |
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xmlElem = render_xml(path, 'jinja_template.xml', True, tag1='oi', |
|||
tag2='ola', tag3='comovai') |
|||
xml = etree.tostring(xmlElem) |
|||
result = open(os.path.join(path, 'jinja_remove_empty.xml'), 'r').read() |
|||
self.assertEqual(xml + '\n', result) |
|||
|
|||
def test_sanitize_response(self): |
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_to_clear = open(os.path.join(path, 'jinja_result.xml'), 'r').read() |
|||
xml, obj = sanitize_response(xml_to_clear) |
|||
|
|||
self.assertEqual(xml, xml_to_clear) |
|||
self.assertEqual(obj.tpAmb, 'oi') |
|||
self.assertEqual(obj.CNPJ, 'ola') |
|||
self.assertEqual(obj.indNFe, '') |
|||
self.assertEqual(obj.indEmi, 'comovai') |
|||
@ -1,189 +0,0 @@ |
|||
<enviNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> |
|||
<idLote>103</idLote> |
|||
<indSinc>1</indSinc> |
|||
<NFe xmlns="http://www.portalfiscal.inf.br/nfe"> |
|||
<infNFe versao="3.10" Id="NFe35161121332917000163650010000000011448875034"> |
|||
<ide> |
|||
<cUF>35</cUF> |
|||
<cNF>44887503</cNF> |
|||
<natOp>Venda POS</natOp> |
|||
<indPag>0</indPag> |
|||
<mod>65</mod> |
|||
<serie>1</serie> |
|||
<nNF>1</nNF> |
|||
<dhEmi>2016-11-09T16:03:58-00:00</dhEmi> |
|||
<tpNF>1</tpNF> |
|||
<idDest>1</idDest> |
|||
<cMunFG>3550308</cMunFG> |
|||
<tpImp>4</tpImp> |
|||
<tpEmis>1</tpEmis> |
|||
<cDV>4</cDV> |
|||
<tpAmb>2</tpAmb> |
|||
<finNFe>1</finNFe> |
|||
<indFinal>1</indFinal> |
|||
<indPres>1</indPres> |
|||
<procEmi>0</procEmi> |
|||
<verProc>Odoo Brasil 10</verProc> |
|||
</ide> |
|||
<emit> |
|||
<CNPJ>21332917000163</CNPJ> |
|||
<xNome>LEL AMBIENTAL LTDA - EPP</xNome> |
|||
<xFant>Zell Ambiental</xFant> |
|||
<enderEmit> |
|||
<xLgr>Rua Padre João</xLgr> |
|||
<nro>444</nro> |
|||
<xBairro>Penha de França</xBairro> |
|||
<cMun>3550308</cMun> |
|||
<xMun>São Paulo</xMun> |
|||
<UF>SP</UF> |
|||
<CEP>03637000</CEP> |
|||
<cPais>1058</cPais> |
|||
<xPais>Brasil</xPais> |
|||
<fone>3425323750</fone> |
|||
</enderEmit> |
|||
<IE>244694180116</IE> |
|||
<CRT>3</CRT> |
|||
</emit> |
|||
<det nItem="1"> |
|||
<prod> |
|||
<cProd>MISC</cProd> |
|||
<cEAN/> |
|||
<xProd>NOTA FISCAL EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL</xProd> |
|||
<NCM>28431000</NCM> |
|||
<CEST>2806300</CEST> |
|||
<CFOP>5101</CFOP> |
|||
<uCom>Unit(s</uCom> |
|||
<qCom>18.0</qCom> |
|||
<vUnCom>18.00</vUnCom> |
|||
<vProd>324.00</vProd> |
|||
<cEANTrib/> |
|||
<uTrib>Unit(s</uTrib> |
|||
<qTrib>18.0</qTrib> |
|||
<vUnTrib>18.00</vUnTrib> |
|||
<indTot>1</indTot> |
|||
</prod> |
|||
<imposto> |
|||
<vTotTrib>0.00</vTotTrib> |
|||
<ICMS> |
|||
<ICMS00> |
|||
<orig>0</orig> |
|||
<CST>00</CST> |
|||
<modBC>3</modBC> |
|||
<vBC>324.00</vBC> |
|||
<pICMS>19.00</pICMS> |
|||
<vICMS>61.56</vICMS> |
|||
</ICMS00> |
|||
</ICMS> |
|||
<PIS> |
|||
<PISAliq> |
|||
<CST>01</CST> |
|||
<vBC>324.00</vBC> |
|||
<pPIS>0.00</pPIS> |
|||
<vPIS>2.11</vPIS> |
|||
</PISAliq> |
|||
</PIS> |
|||
<COFINS> |
|||
<COFINSAliq> |
|||
<CST>01</CST> |
|||
<vBC>324.00</vBC> |
|||
<pCOFINS>0.00</pCOFINS> |
|||
<vCOFINS>9.72</vCOFINS> |
|||
</COFINSAliq> |
|||
</COFINS> |
|||
</imposto> |
|||
</det> |
|||
<total> |
|||
<ICMSTot> |
|||
<vBC>324.00</vBC> |
|||
<vICMS>61.56</vICMS> |
|||
<vICMSDeson>0.00</vICMSDeson> |
|||
<vBCST>0.00</vBCST> |
|||
<vST>0.00</vST> |
|||
<vProd>324.00</vProd> |
|||
<vFrete>0.00</vFrete> |
|||
<vSeg>0.00</vSeg> |
|||
<vDesc>0.00</vDesc> |
|||
<vII>0.00</vII> |
|||
<vIPI>0.00</vIPI> |
|||
<vPIS>2.11</vPIS> |
|||
<vCOFINS>9.72</vCOFINS> |
|||
<vOutro>0.00</vOutro> |
|||
<vNF>324.00</vNF> |
|||
<vTotTrib>0.00</vTotTrib> |
|||
</ICMSTot> |
|||
</total> |
|||
<transp> |
|||
<modFrete>9</modFrete> |
|||
</transp> |
|||
<pag> |
|||
<tPag>01</tPag> |
|||
<vPag>324.00</vPag> |
|||
</pag> |
|||
</infNFe> |
|||
<infNFeSupl><qrCode><![CDATA[https://homologacao.nfce.fazenda.sp.gov.br/NFCEConsultaPublica/Paginas/ConstultaQRCode.aspx?chNFe=35161121332917000163650010000000011448875034&nVersao=100&tpAmb=2&dhEmi=323031362d31312d30395431363a30333a32352d30303a3030&vNF=324.00&vICMS=61.56&digVal=66664a5a2b30346a6d484e33754c7830386875796b7942733272343d&cIdToken=000001&cHashQRCode=6d674f77ece8067d1255c5ca33fc2acaab3a0e8e]]></qrCode></infNFeSupl><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> |
|||
<SignedInfo> |
|||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> |
|||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> |
|||
<Reference URI="#NFe35161121332917000163650010000000011448875034"> |
|||
<Transforms> |
|||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> |
|||
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> |
|||
</Transforms> |
|||
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> |
|||
<DigestValue>ffJZ+04jmHN3uLx08huykyBs2r4=</DigestValue> |
|||
</Reference> |
|||
</SignedInfo> |
|||
<SignatureValue>u42y8bBqNM336yc7r0+5YWiePmCerKu3cFcp2J+lmQzIK6snba7txyeBtwVos8jQxrYLsnfWtKb5P6FxmhDeqAB41o2aoSIcnxc0yxdFn2ZDTquwU+AurH6E4hGclz8D/5qapv2+g3y+VpXMZFNNCqZSm2vJpvXBmPEY/7oO2cPB13N7WDhDRmI9H4kRDsPuxeeJetr2Bf1ThGJ0EUA4DXC7My0kl/Bw0rYwoPDhoqhxinr9Wocw1UyQ1vprLF0JVHXOtSq39Uqfqmj5QUDwUvvh4YL9bFZ8lvZZ0CZDmILaFGvr1XH3CwJ2Ws3RLlb12Arj5OT4vS8ZKhJtr/dpfA==</SignatureValue> |
|||
<KeyInfo> |
|||
<X509Data> |
|||
<X509Certificate>MIIIPzCCBiegAwIBAgIQYdesnYUNG8VPne0qhTeKOzANBgkqhkiG9w0BAQsFADB4 |
|||
MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE2MDQGA1UECxMtU2Vj |
|||
cmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgZG8gQnJhc2lsIC0gUkZCMRwwGgYD |
|||
VQQDExNBQyBDZXJ0aXNpZ24gUkZCIEc0MB4XDTE2MDUxMDAwMDAwMFoXDTE3MDUw |
|||
OTIzNTk1OVowgekxCzAJBgNVBAYTAkJSMRMwEQYDVQQKFApJQ1AtQnJhc2lsMQsw |
|||
CQYDVQQIEwJTUDESMBAGA1UEBxQJU2FvIFBhdWxvMTYwNAYDVQQLFC1TZWNyZXRh |
|||
cmlhIGRhIFJlY2VpdGEgRmVkZXJhbCBkbyBCcmFzaWwgLSBSRkIxFjAUBgNVBAsU |
|||
DVJGQiBlLUNOUEogQTExJDAiBgNVBAsUG0F1dGVudGljYWRvIHBvciBBUiBTdW5z |
|||
aGluZTEuMCwGA1UEAxMlTEVaIEFNQklFTlRBTCBMVERBIEVQUDoyMTMzMjkxNzAw |
|||
MDE2MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANEG6j0uXIvvHlMz |
|||
0IGzuY/vuFQncIoSE+cBUk0uq6J3dtmGAg4oaVWCHUfHbX9s2Ag1jIG+PFAo2dlt |
|||
sbLSEji74XhD+IpM/9aHm3ke8kb05ay+bYRuUjTNSwUbslT1+amAmIu7m1yPBi6u |
|||
v3+/Lj2I0g7VeBBAjv/TiBG0VRCURXvKrwWrv2Lpybo/yDnENGtRqQHihqeYFKin |
|||
nDzBsMbv4ripbi3XiAgcy/bF6NFgVMqxrNnGvSiSUhDRkmceVFIysRXUMke02Qo1 |
|||
Q5Ik1j1goUIHP44QOruXCMiT0yOK8u0qNAXR0yzSaWcBR2aJCeWgFg7sNbB50Qcx |
|||
c+2GKUECAwEAAaOCA1EwggNNMIG2BgNVHREEga4wgaugPQYFYEwBAwSgNAQyMTYw |
|||
NjE5ODYzNDEzNzgyODg2NTAwMDAwMDAwMDAwMDAwMDAwMDQwMDAwMzczU1NQU1Cg |
|||
IgYFYEwBAwKgGQQXTEVPTkFSRE8gREUgTElNQSBTQU5UT1OgGQYFYEwBAwOgEAQO |
|||
MjEzMzI5MTcwMDAxNjOgFwYFYEwBAwegDgQMMDAwMDAwMDAwMDAwgRJ3YWduZXJA |
|||
emVsbC5jb20uYnIwCQYDVR0TBAIwADAfBgNVHSMEGDAWgBQukerWbeWyWYLcOIUp |
|||
djQWVjzQPjAOBgNVHQ8BAf8EBAMCBeAwfwYDVR0gBHgwdjB0BgZgTAECAQwwajBo |
|||
BggrBgEFBQcCARZcaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNvbS5ici9y |
|||
ZXBvc2l0b3Jpby9kcGMvQUNfQ2VydGlzaWduX1JGQi9EUENfQUNfQ2VydGlzaWdu |
|||
X1JGQi5wZGYwggEWBgNVHR8EggENMIIBCTBXoFWgU4ZRaHR0cDovL2ljcC1icmFz |
|||
aWwuY2VydGlzaWduLmNvbS5ici9yZXBvc2l0b3Jpby9sY3IvQUNDZXJ0aXNpZ25S |
|||
RkJHNC9MYXRlc3RDUkwuY3JsMFagVKBShlBodHRwOi8vaWNwLWJyYXNpbC5vdXRy |
|||
YWxjci5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL0FDQ2VydGlzaWduUkZCRzQvTGF0 |
|||
ZXN0Q1JMLmNybDBWoFSgUoZQaHR0cDovL3JlcG9zaXRvcmlvLmljcGJyYXNpbC5n |
|||
b3YuYnIvbGNyL0NlcnRpc2lnbi9BQ0NlcnRpc2lnblJGQkc0L0xhdGVzdENSTC5j |
|||
cmwwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMIGbBggrBgEFBQcBAQSB |
|||
jjCBizBfBggrBgEFBQcwAoZTaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNv |
|||
bS5ici9yZXBvc2l0b3Jpby9jZXJ0aWZpY2Fkb3MvQUNfQ2VydGlzaWduX1JGQl9H |
|||
NC5wN2MwKAYIKwYBBQUHMAGGHGh0dHA6Ly9vY3NwLmNlcnRpc2lnbi5jb20uYnIw |
|||
DQYJKoZIhvcNAQELBQADggIBAFIUBrNIyC4kBap/7hCW63tQhA/WNnWDNYpKM5wN |
|||
zwApVV2bqFMJURzO/7AUrHu7uZS1p/Ubo+w2dFjmnmj5DniQkY85Sd6HNa1fukJY |
|||
PK13wcUMVHMjeevIAcxnYraNdN4BIz1Svl6A8leGFgIEuDUll7Td+R7+aA8N5JYQ |
|||
dFFIe2VxvJNbWP/WA49oI8U2wkoPTfOZtfrgKf2msHm3FnTfnmyOPhIf8L31iFt6 |
|||
MbKuFjOGIaWu+Z/gRDqj/EbFcEMUrDbeIYqz2724ZGBOJrkjHO7DBqXXoN9pzCTO |
|||
RB5+gILMEnMS7zFsCuLOtLVohxgYUzg8p4Fy3nsHEzb/7IDVOnKLfjh/c5GSTvOa |
|||
JT6qznYV2yav7NyuUSNUv+5bCIBNk45+qrQ8DwpsLBsFa+RLfCwvYVK95ad/xVgJ |
|||
QosPJuzW3t0fU/FWbc00sZWV6lgBPyWhdF8EodaRIWC+EOC2wJbODyw+vdX8pUxT |
|||
TUJKV2iAP8206gR2h07o2CZgXckJGJQ5MnBUbS78AaITXZ5JlPaS7ZdU9zWY3kD+ |
|||
j5YERs0+UweijKi5eHZioGRZRDZ2uksh1wrgeLFLWuiSNaPFYVVrQ/ZGo+E5uVNl |
|||
8FuoR6P9TZjx1/A4XjqLQ9yPoPWgIWe14Vh/76dVcgz3ElWMbmPCDoc/wX+FoHX1 |
|||
Fbux |
|||
</X509Certificate> |
|||
</X509Data> |
|||
</KeyInfo> |
|||
</Signature> |
|||
</NFe> |
|||
</enviNFe> |
|||
@ -1,190 +0,0 @@ |
|||
<?xml version="1.0"?> |
|||
<enviNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> |
|||
<idLote>103</idLote> |
|||
<indSinc>1</indSinc> |
|||
<NFe xmlns="http://www.portalfiscal.inf.br/nfe"> |
|||
<infNFe versao="3.10" Id="NFe35161121332917000163650010000000011448875034"> |
|||
<ide> |
|||
<cUF>35</cUF> |
|||
<cNF>44887503</cNF> |
|||
<natOp>Venda POS</natOp> |
|||
<indPag>0</indPag> |
|||
<mod>65</mod> |
|||
<serie>1</serie> |
|||
<nNF>1</nNF> |
|||
<dhEmi>2016-11-09T16:03:58-00:00</dhEmi> |
|||
<tpNF>1</tpNF> |
|||
<idDest>1</idDest> |
|||
<cMunFG>3550308</cMunFG> |
|||
<tpImp>4</tpImp> |
|||
<tpEmis>1</tpEmis> |
|||
<cDV>4</cDV> |
|||
<tpAmb>2</tpAmb> |
|||
<finNFe>1</finNFe> |
|||
<indFinal>1</indFinal> |
|||
<indPres>1</indPres> |
|||
<procEmi>0</procEmi> |
|||
<verProc>Odoo Brasil 10</verProc> |
|||
</ide> |
|||
<emit> |
|||
<CNPJ>21332917000163</CNPJ> |
|||
<xNome>LEL AMBIENTAL LTDA - EPP</xNome> |
|||
<xFant>Zell Ambiental</xFant> |
|||
<enderEmit> |
|||
<xLgr>Rua Padre João</xLgr> |
|||
<nro>444</nro> |
|||
<xBairro>Penha de França</xBairro> |
|||
<cMun>3550308</cMun> |
|||
<xMun>São Paulo</xMun> |
|||
<UF>SP</UF> |
|||
<CEP>03637000</CEP> |
|||
<cPais>1058</cPais> |
|||
<xPais>Brasil</xPais> |
|||
<fone>3425323750</fone> |
|||
</enderEmit> |
|||
<IE>244694180116</IE> |
|||
<CRT>3</CRT> |
|||
</emit> |
|||
<det nItem="1"> |
|||
<prod> |
|||
<cProd>MISC</cProd> |
|||
<cEAN/> |
|||
<xProd>NOTA FISCAL EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL</xProd> |
|||
<NCM>28431000</NCM> |
|||
<CEST>2806300</CEST> |
|||
<CFOP>5101</CFOP> |
|||
<uCom>Unit(s</uCom> |
|||
<qCom>18.0</qCom> |
|||
<vUnCom>18.00</vUnCom> |
|||
<vProd>324.00</vProd> |
|||
<cEANTrib/> |
|||
<uTrib>Unit(s</uTrib> |
|||
<qTrib>18.0</qTrib> |
|||
<vUnTrib>18.00</vUnTrib> |
|||
<indTot>1</indTot> |
|||
</prod> |
|||
<imposto> |
|||
<vTotTrib>0.00</vTotTrib> |
|||
<ICMS> |
|||
<ICMS00> |
|||
<orig>0</orig> |
|||
<CST>00</CST> |
|||
<modBC>3</modBC> |
|||
<vBC>324.00</vBC> |
|||
<pICMS>19.00</pICMS> |
|||
<vICMS>61.56</vICMS> |
|||
</ICMS00> |
|||
</ICMS> |
|||
<PIS> |
|||
<PISAliq> |
|||
<CST>01</CST> |
|||
<vBC>324.00</vBC> |
|||
<pPIS>0.00</pPIS> |
|||
<vPIS>2.11</vPIS> |
|||
</PISAliq> |
|||
</PIS> |
|||
<COFINS> |
|||
<COFINSAliq> |
|||
<CST>01</CST> |
|||
<vBC>324.00</vBC> |
|||
<pCOFINS>0.00</pCOFINS> |
|||
<vCOFINS>9.72</vCOFINS> |
|||
</COFINSAliq> |
|||
</COFINS> |
|||
</imposto> |
|||
</det> |
|||
<total> |
|||
<ICMSTot> |
|||
<vBC>324.00</vBC> |
|||
<vICMS>61.56</vICMS> |
|||
<vICMSDeson>0.00</vICMSDeson> |
|||
<vBCST>0.00</vBCST> |
|||
<vST>0.00</vST> |
|||
<vProd>324.00</vProd> |
|||
<vFrete>0.00</vFrete> |
|||
<vSeg>0.00</vSeg> |
|||
<vDesc>0.00</vDesc> |
|||
<vII>0.00</vII> |
|||
<vIPI>0.00</vIPI> |
|||
<vPIS>2.11</vPIS> |
|||
<vCOFINS>9.72</vCOFINS> |
|||
<vOutro>0.00</vOutro> |
|||
<vNF>324.00</vNF> |
|||
<vTotTrib>0.00</vTotTrib> |
|||
</ICMSTot> |
|||
</total> |
|||
<transp> |
|||
<modFrete>9</modFrete> |
|||
</transp> |
|||
<pag> |
|||
<tPag>01</tPag> |
|||
<vPag>324.00</vPag> |
|||
</pag> |
|||
</infNFe> |
|||
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> |
|||
<SignedInfo> |
|||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> |
|||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> |
|||
<Reference URI="#NFe35161121332917000163650010000000011448875034"> |
|||
<Transforms> |
|||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> |
|||
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> |
|||
</Transforms> |
|||
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> |
|||
<DigestValue>ffJZ+04jmHN3uLx08huykyBs2r4=</DigestValue> |
|||
</Reference> |
|||
</SignedInfo> |
|||
<SignatureValue>u42y8bBqNM336yc7r0+5YWiePmCerKu3cFcp2J+lmQzIK6snba7txyeBtwVos8jQxrYLsnfWtKb5P6FxmhDeqAB41o2aoSIcnxc0yxdFn2ZDTquwU+AurH6E4hGclz8D/5qapv2+g3y+VpXMZFNNCqZSm2vJpvXBmPEY/7oO2cPB13N7WDhDRmI9H4kRDsPuxeeJetr2Bf1ThGJ0EUA4DXC7My0kl/Bw0rYwoPDhoqhxinr9Wocw1UyQ1vprLF0JVHXOtSq39Uqfqmj5QUDwUvvh4YL9bFZ8lvZZ0CZDmILaFGvr1XH3CwJ2Ws3RLlb12Arj5OT4vS8ZKhJtr/dpfA==</SignatureValue> |
|||
<KeyInfo> |
|||
<X509Data> |
|||
<X509Certificate>MIIIPzCCBiegAwIBAgIQYdesnYUNG8VPne0qhTeKOzANBgkqhkiG9w0BAQsFADB4 |
|||
MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE2MDQGA1UECxMtU2Vj |
|||
cmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgZG8gQnJhc2lsIC0gUkZCMRwwGgYD |
|||
VQQDExNBQyBDZXJ0aXNpZ24gUkZCIEc0MB4XDTE2MDUxMDAwMDAwMFoXDTE3MDUw |
|||
OTIzNTk1OVowgekxCzAJBgNVBAYTAkJSMRMwEQYDVQQKFApJQ1AtQnJhc2lsMQsw |
|||
CQYDVQQIEwJTUDESMBAGA1UEBxQJU2FvIFBhdWxvMTYwNAYDVQQLFC1TZWNyZXRh |
|||
cmlhIGRhIFJlY2VpdGEgRmVkZXJhbCBkbyBCcmFzaWwgLSBSRkIxFjAUBgNVBAsU |
|||
DVJGQiBlLUNOUEogQTExJDAiBgNVBAsUG0F1dGVudGljYWRvIHBvciBBUiBTdW5z |
|||
aGluZTEuMCwGA1UEAxMlTEVaIEFNQklFTlRBTCBMVERBIEVQUDoyMTMzMjkxNzAw |
|||
MDE2MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANEG6j0uXIvvHlMz |
|||
0IGzuY/vuFQncIoSE+cBUk0uq6J3dtmGAg4oaVWCHUfHbX9s2Ag1jIG+PFAo2dlt |
|||
sbLSEji74XhD+IpM/9aHm3ke8kb05ay+bYRuUjTNSwUbslT1+amAmIu7m1yPBi6u |
|||
v3+/Lj2I0g7VeBBAjv/TiBG0VRCURXvKrwWrv2Lpybo/yDnENGtRqQHihqeYFKin |
|||
nDzBsMbv4ripbi3XiAgcy/bF6NFgVMqxrNnGvSiSUhDRkmceVFIysRXUMke02Qo1 |
|||
Q5Ik1j1goUIHP44QOruXCMiT0yOK8u0qNAXR0yzSaWcBR2aJCeWgFg7sNbB50Qcx |
|||
c+2GKUECAwEAAaOCA1EwggNNMIG2BgNVHREEga4wgaugPQYFYEwBAwSgNAQyMTYw |
|||
NjE5ODYzNDEzNzgyODg2NTAwMDAwMDAwMDAwMDAwMDAwMDQwMDAwMzczU1NQU1Cg |
|||
IgYFYEwBAwKgGQQXTEVPTkFSRE8gREUgTElNQSBTQU5UT1OgGQYFYEwBAwOgEAQO |
|||
MjEzMzI5MTcwMDAxNjOgFwYFYEwBAwegDgQMMDAwMDAwMDAwMDAwgRJ3YWduZXJA |
|||
emVsbC5jb20uYnIwCQYDVR0TBAIwADAfBgNVHSMEGDAWgBQukerWbeWyWYLcOIUp |
|||
djQWVjzQPjAOBgNVHQ8BAf8EBAMCBeAwfwYDVR0gBHgwdjB0BgZgTAECAQwwajBo |
|||
BggrBgEFBQcCARZcaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNvbS5ici9y |
|||
ZXBvc2l0b3Jpby9kcGMvQUNfQ2VydGlzaWduX1JGQi9EUENfQUNfQ2VydGlzaWdu |
|||
X1JGQi5wZGYwggEWBgNVHR8EggENMIIBCTBXoFWgU4ZRaHR0cDovL2ljcC1icmFz |
|||
aWwuY2VydGlzaWduLmNvbS5ici9yZXBvc2l0b3Jpby9sY3IvQUNDZXJ0aXNpZ25S |
|||
RkJHNC9MYXRlc3RDUkwuY3JsMFagVKBShlBodHRwOi8vaWNwLWJyYXNpbC5vdXRy |
|||
YWxjci5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL0FDQ2VydGlzaWduUkZCRzQvTGF0 |
|||
ZXN0Q1JMLmNybDBWoFSgUoZQaHR0cDovL3JlcG9zaXRvcmlvLmljcGJyYXNpbC5n |
|||
b3YuYnIvbGNyL0NlcnRpc2lnbi9BQ0NlcnRpc2lnblJGQkc0L0xhdGVzdENSTC5j |
|||
cmwwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMIGbBggrBgEFBQcBAQSB |
|||
jjCBizBfBggrBgEFBQcwAoZTaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNv |
|||
bS5ici9yZXBvc2l0b3Jpby9jZXJ0aWZpY2Fkb3MvQUNfQ2VydGlzaWduX1JGQl9H |
|||
NC5wN2MwKAYIKwYBBQUHMAGGHGh0dHA6Ly9vY3NwLmNlcnRpc2lnbi5jb20uYnIw |
|||
DQYJKoZIhvcNAQELBQADggIBAFIUBrNIyC4kBap/7hCW63tQhA/WNnWDNYpKM5wN |
|||
zwApVV2bqFMJURzO/7AUrHu7uZS1p/Ubo+w2dFjmnmj5DniQkY85Sd6HNa1fukJY |
|||
PK13wcUMVHMjeevIAcxnYraNdN4BIz1Svl6A8leGFgIEuDUll7Td+R7+aA8N5JYQ |
|||
dFFIe2VxvJNbWP/WA49oI8U2wkoPTfOZtfrgKf2msHm3FnTfnmyOPhIf8L31iFt6 |
|||
MbKuFjOGIaWu+Z/gRDqj/EbFcEMUrDbeIYqz2724ZGBOJrkjHO7DBqXXoN9pzCTO |
|||
RB5+gILMEnMS7zFsCuLOtLVohxgYUzg8p4Fy3nsHEzb/7IDVOnKLfjh/c5GSTvOa |
|||
JT6qznYV2yav7NyuUSNUv+5bCIBNk45+qrQ8DwpsLBsFa+RLfCwvYVK95ad/xVgJ |
|||
QosPJuzW3t0fU/FWbc00sZWV6lgBPyWhdF8EodaRIWC+EOC2wJbODyw+vdX8pUxT |
|||
TUJKV2iAP8206gR2h07o2CZgXckJGJQ5MnBUbS78AaITXZ5JlPaS7ZdU9zWY3kD+ |
|||
j5YERs0+UweijKi5eHZioGRZRDZ2uksh1wrgeLFLWuiSNaPFYVVrQ/ZGo+E5uVNl |
|||
8FuoR6P9TZjx1/A4XjqLQ9yPoPWgIWe14Vh/76dVcgz3ElWMbmPCDoc/wX+FoHX1 |
|||
Fbux |
|||
</X509Certificate> |
|||
</X509Data> |
|||
</KeyInfo> |
|||
</Signature> |
|||
</NFe> |
|||
</enviNFe> |
|||
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue