Browse Source

black - python code formater

pull/262/head
Gabriela Cavalcante da Silva 6 years ago
parent
commit
8c311d4caf
  1. 165
      docs/conf.py
  2. 76
      nfe.py
  3. 1024
      pytrustnfe/Servidores.py
  4. 8
      pytrustnfe/__init__.py
  5. 12
      pytrustnfe/certificado.py
  6. 12
      pytrustnfe/client.py
  7. 4
      pytrustnfe/exceptions.py
  8. 165
      pytrustnfe/nfe/__init__.py
  9. 20
      pytrustnfe/nfe/assinatura.py
  10. 358
      pytrustnfe/nfe/danfce.py
  11. 1066
      pytrustnfe/nfe/danfe.py
  12. 36
      pytrustnfe/nfe/patch.py
  13. 43
      pytrustnfe/nfse/aparecida/__init__.py
  14. 23
      pytrustnfe/nfse/assinatura.py
  15. 76
      pytrustnfe/nfse/betha/__init__.py
  16. 51
      pytrustnfe/nfse/bh/__init__.py
  17. 21
      pytrustnfe/nfse/bh/assinatura.py
  18. 53
      pytrustnfe/nfse/carioca/__init__.py
  19. 69
      pytrustnfe/nfse/dsf/__init__.py
  20. 96
      pytrustnfe/nfse/floripa/__init__.py
  21. 59
      pytrustnfe/nfse/ginfes/__init__.py
  22. 38
      pytrustnfe/nfse/imperial/__init__.py
  23. 47
      pytrustnfe/nfse/mga/__init__.py
  24. 17
      pytrustnfe/nfse/mga/assinatura.py
  25. 68
      pytrustnfe/nfse/paulistana/__init__.py
  26. 64
      pytrustnfe/nfse/simpliss/__init__.py
  27. 34
      pytrustnfe/nfse/susesu/__init__.py
  28. 262
      pytrustnfe/urls.py
  29. 60
      pytrustnfe/utils.py
  30. 20
      pytrustnfe/xml/__init__.py
  31. 27
      pytrustnfe/xml/filters.py
  32. 4
      pytrustnfe/xml/validate.py
  33. 4
      requirements-dev.txt
  34. 96
      setup.py
  35. 71
      tests/test_assinatura.py
  36. 110
      tests/test_certificado.py
  37. 6
      tests/test_danfe.py
  38. 13
      tests/test_ginfes.py
  39. 143
      tests/test_nfse_paulistana.py
  40. 37
      tests/test_servidores.py
  41. 134
      tests/test_utils.py
  42. 17
      tests/test_xml.py
  43. 33
      tests/test_xml_serializacao.py

165
docs/conf.py

@ -19,89 +19,89 @@ import shlex
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.coverage',
"sphinx.ext.autodoc",
"sphinx.ext.coverage",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
source_suffix = ".rst"
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# General information about the project.
project = u'PyTrustNFe'
copyright = u'2015, Danimar Ribeiro'
author = u'Danimar Ribeiro'
project = u"PyTrustNFe"
copyright = u"2015, Danimar Ribeiro"
author = u"Danimar Ribeiro"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
version = "1.0"
# The full version, including alpha/beta/rc tags.
release = '1.0'
release = "1.0"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'pt_BR'
language = "pt_BR"
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ["_build"]
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
@ -111,156 +111,155 @@ todo_include_todos = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'nature'
html_theme = "nature"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'PyTrustNFedoc'
htmlhelp_basename = "PyTrustNFedoc"
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'PyTrustNFe.tex', u'PyTrustNFe Documentation',
u'Danimar Ribeiro', 'manual'),
(
master_doc,
"PyTrustNFe.tex",
u"PyTrustNFe Documentation",
u"Danimar Ribeiro",
"manual",
),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'pytrustnfe', u'PyTrustNFe Documentation',
[author], 1)
]
man_pages = [(master_doc, "pytrustnfe", u"PyTrustNFe Documentation", [author], 1)]
# If true, show URL addresses after external links.
#man_show_urls = False
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@ -269,19 +268,25 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'PyTrustNFe', u'PyTrustNFe Documentation',
author, 'PyTrustNFe', 'One line description of project.',
'Miscellaneous'),
(
master_doc,
"PyTrustNFe",
u"PyTrustNFe Documentation",
author,
"PyTrustNFe",
"One line description of project.",
"Miscellaneous",
),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
# texinfo_no_detailmenu = False

76
nfe.py

@ -0,0 +1,76 @@
import xml.dom.minidom
import os
import mock
from pytrustnfe.nfse.natal import recepcionar_lote_rps
from pytrustnfe.certificado import Certificado
from pytrustnfe.nfse.assinatura import Assinatura
rps_list = [
{
"numero": "E2143992638620191226",
"serie": "UNICA",
"tipo_rps": "1",
"data_emissao": "2020-01-279",
"natureza_operacao": "1",
"regime_tributacao": "1",
"optante_simples": "1",
"incentivador_cultural": "2",
"servico": {
"valor_servico": "1.00",
"iss_retido": "2",
"base_calculo": "0.00",
"codigo_servico": "01.07",
"cnae_servico": "6209100",
"descricao": "Sistema SGP|1.0000|220.00|220.00#",
"codigo_municipio": "2408102",
},
"prestador": {
"cnpj": "23809070000190",
"inscricao_municipal": "2143992",
"razao_social": "TSMX SERVICOS DE TI EIRELI",
"fantasia": "TSMX",
"endereco": "AV AMINTAS BARROS",
"numero": "3700",
"complemento": "SALA 1907 BLOCO A",
"bairro": "Lagoa Nova",
"codigo_municipio": "2408102",
"uf": "RN",
"cep": "59075810",
"telefone": "4132095554",
"email": "SUPORTE@CONTABILIZEI.COM.BR",
},
"tomador": {
"cpf_cnpj": "01812418000166",
"razao_social": "LEONIR NETO",
"endereco": "RUA IRMÃO GROBEIRO",
"numero": "14",
"bairro": "CRUZEIRO",
"cidade": "3159506",
"uf": "MG",
"cep": "35225000",
"email": "leonirneto@uol.com.br",
"orgao_gerador": {"codigo_municipio"},
},
}
]
nfse = {
"numero_lote": "1",
"cnpj_prestador": "23809070000190",
"inscricao_municipal": "2143992",
"lista_rps": rps_list,
}
caminho = os.path.dirname(__file__)
pfx_source = open(os.path.join(caminho, "tests/teste.pfx"), "rb").read()
pfx = Certificado(pfx_source, "123456")
retorno = recepcionar_lote_rps(pfx, nfse=nfse, ambiente="homologacao")
# dom = xml.dom.minidom.parseString(retorno['received_xml'])
# received_xml = dom.toprettyxml()
# print(received_xml)
dom = xml.dom.minidom.parseString(retorno.get("sent_xml"))
sent_xml = dom.toprettyxml()
print(sent_xml)

1024
pytrustnfe/Servidores.py
File diff suppressed because it is too large
View File

8
pytrustnfe/__init__.py

@ -6,16 +6,14 @@ import requests
class HttpClient(object):
def __init__(self, url):
self.url = url
def _headers(self, action):
return {
'Content-type':
'text/xml; charset=utf-8;',
'Accept': 'application/soap+xml; charset=utf-8',
'SOAPAction': action
"Content-type": "text/xml; charset=utf-8;",
"Accept": "application/soap+xml; charset=utf-8",
"SOAPAction": action,
}
def post_soap(self, xml_soap, action):

12
pytrustnfe/certificado.py

@ -13,7 +13,7 @@ class Certificado(object):
def save_pfx(self):
pfx_temp = tempfile.mkstemp()[1]
arq_temp = open(pfx_temp, 'wb')
arq_temp = open(pfx_temp, "wb")
arq_temp.write(self.pfx)
arq_temp.close()
return pfx_temp
@ -22,11 +22,9 @@ class Certificado(object):
def extract_cert_and_key_from_pfx(pfx, password):
pfx = crypto.load_pkcs12(pfx, password)
# PEM formatted private key
key = crypto.dump_privatekey(crypto.FILETYPE_PEM,
pfx.get_privatekey())
key = crypto.dump_privatekey(crypto.FILETYPE_PEM, pfx.get_privatekey())
# PEM formatted certificate
cert = crypto.dump_certificate(crypto.FILETYPE_PEM,
pfx.get_certificate())
cert = crypto.dump_certificate(crypto.FILETYPE_PEM, pfx.get_certificate())
return cert.decode(), key.decode()
@ -34,11 +32,11 @@ def save_cert_key(cert, key):
cert_temp = tempfile.mkstemp()[1]
key_temp = tempfile.mkstemp()[1]
arq_temp = open(cert_temp, 'w')
arq_temp = open(cert_temp, "w")
arq_temp.write(cert)
arq_temp.close()
arq_temp = open(key_temp, 'w')
arq_temp = open(key_temp, "w")
arq_temp.write(key)
arq_temp.close()

12
pytrustnfe/client.py

@ -8,26 +8,22 @@ import suds_requests
def get_authenticated_client(base_url, cert, key):
cache_location = '/tmp/suds'
cache_location = "/tmp/suds"
cache = suds.cache.DocumentCache(location=cache_location)
session = requests.Session()
session.cert = (cert, key)
return suds.client.Client(
base_url,
cache=cache,
transport=suds_requests.RequestsTransport(session)
base_url, cache=cache, transport=suds_requests.RequestsTransport(session)
)
def get_client(base_url):
cache_location = '/tmp/suds'
cache_location = "/tmp/suds"
cache = suds.cache.DocumentCache(location=cache_location)
session = requests.Session()
return suds.client.Client(
base_url,
cache=cache,
transport=suds_requests.RequestsTransport(session)
base_url, cache=cache, transport=suds_requests.RequestsTransport(session)
)

4
pytrustnfe/exceptions.py

@ -7,6 +7,6 @@ class NFeValidationException(ValueError):
"""Exceção para erro na validação do esquema da NFe"""
def __init__(self, message, *args, **kwargs):
self.erros = kwargs['erros']
self.sent_xml = kwargs['sent_xml']
self.erros = kwargs["erros"]
self.sent_xml = kwargs["sent_xml"]
super(NFeValidationException, self).__init__(message, *args, **kwargs)

165
pytrustnfe/nfe/__init__.py

@ -22,44 +22,48 @@ 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:]
chave_nfe = gerar_chave(chave_nfe, "NFe")
item["infNFe"]["Id"] = chave_nfe
item["infNFe"]["ide"]["cDV"] = chave_nfe[len(chave_nfe) - 1 :]
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)
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'
modelo = modelo.text if modelo is not None else "55"
if sign:
signer = Assinatura(certificado.pfx, certificado.password)
if method == 'NfeInutilizacao':
xml_send = signer.assina_xml(xmlElem_send, kwargs['obj']['id'])
if method == 'NfeAutorizacao':
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'])
elif method == 'RecepcaoEvento':
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['eventos'][0]['Id'])
elif method == 'RecepcaoEventoManifesto':
xml_send = signer.assina_xml(
xmlElem_send, kwargs['manifesto']['identificador'])
xmlElem_send, kwargs["manifesto"]["identificador"]
)
else:
xml_send = etree.tostring(xmlElem_send, encoding=str)
@ -67,8 +71,7 @@ def _render(certificado, method, sign, **kwargs):
def _get_session(certificado):
cert, key = extract_cert_and_key_from_pfx(
certificado.pfx, certificado.password)
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key)
session = Session()
@ -80,19 +83,23 @@ def _get_session(certificado):
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]
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'])
method, kwargs["estado"], kwargs["modelo"], kwargs["ambiente"]
)
session = _get_session(certificado)
patch = has_patch(kwargs['estado'], method)
patch = has_patch(kwargs["estado"], method)
if patch:
return patch(session, xml_send, kwargs['ambiente'])
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)
@ -104,140 +111,138 @@ def _send_zeep(first_operation, client, xml_send):
namespaceNFe = xml.find(".//{http://www.portalfiscal.inf.br/nfe}NFe")
if namespaceNFe is not None:
namespaceNFe.set('xmlns', 'http://www.portalfiscal.inf.br/nfe')
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]
"sent_xml": xml_send,
"received_xml": response,
"object": obj.Body.getchildren()[0],
}
def xml_autorizar_nfe(certificado, **kwargs):
_generate_nfe_id(**kwargs)
return _render(certificado, 'NfeAutorizacao', True, **kwargs)
return _render(certificado, "NfeAutorizacao", True, **kwargs)
def autorizar_nfe(certificado, **kwargs): # Assinar
if "xml" not in kwargs:
kwargs['xml'] = xml_autorizar_nfe(certificado, **kwargs)
return _send(certificado, 'NfeAutorizacao', **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)
return _render(certificado, "NfeRetAutorizacao", False, **kwargs)
def retorno_autorizar_nfe(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_retorno_autorizar_nfe(certificado, **kwargs)
return _send(certificado, 'NfeRetAutorizacao', **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)
return _render(certificado, "RecepcaoEvento", True, **kwargs)
def recepcao_evento_cancelamento(certificado, **kwargs): # Assinar
if "xml" not in kwargs:
kwargs['xml'] = xml_recepcao_evento_cancelamento(certificado, **kwargs)
return _send(certificado, 'RecepcaoEvento', **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)
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)
kwargs["xml"] = xml_inutilizar_nfe(certificado, **kwargs)
return _send(certificado, "NfeInutilizacao", **kwargs)
def xml_consultar_protocolo_nfe(certificado, **kwargs):
return _render(certificado, 'NfeConsultaProtocolo', False, **kwargs)
return _render(certificado, "NfeConsultaProtocolo", False, **kwargs)
def consultar_protocolo_nfe(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_consultar_protocolo_nfe(certificado, **kwargs)
return _send(certificado, 'NfeConsultaProtocolo', **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)
return _render(certificado, "NfeStatusServico", False, **kwargs)
def nfe_status_servico(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_nfe_status_servico(certificado, **kwargs)
return _send(certificado, 'NfeStatusServico', **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)
return _render(certificado, "NfeConsultaCadastro", False, **kwargs)
def consulta_cadastro(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_consulta_cadastro(certificado, **kwargs)
kwargs['modelo'] = '55'
return _send(certificado, 'NfeConsultaCadastro', **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)
return _render(certificado, "RecepcaoEvento", True, **kwargs)
def recepcao_evento_carta_correcao(certificado, **kwargs): # Assinar
if "xml" not in kwargs:
kwargs['xml'] = xml_recepcao_evento_carta_correcao(
certificado, **kwargs)
return _send(certificado, 'RecepcaoEvento', **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)
return _render(certificado, "RecepcaoEvento", True, **kwargs)
def recepcao_evento_manifesto(certificado, **kwargs): # Assinar
if "xml" not in kwargs:
kwargs['xml'] = xml_recepcao_evento_manifesto(certificado, **kwargs)
return _send(certificado, 'RecepcaoEvento', **kwargs)
kwargs["xml"] = xml_recepcao_evento_manifesto(certificado, **kwargs)
return _send(certificado, "RecepcaoEvento", **kwargs)
def xml_consulta_distribuicao_nfe(certificado, **kwargs): # Assinar
return _render(certificado, 'NFeDistribuicaoDFe', False, **kwargs)
return _render(certificado, "NFeDistribuicaoDFe", False, **kwargs)
def consulta_distribuicao_nfe(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_consulta_distribuicao_nfe(certificado, **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)
return _render(certificado, "NFeDistribuicaoDFe", False, **kwargs)
def download_nfe(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_download_nfe(certificado, **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'])
"NFeDistribuicaoDFe", kwargs["estado"], kwargs["modelo"], kwargs["ambiente"]
)
cert, key = extract_cert_and_key_from_pfx(
certificado.pfx, certificado.password)
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key)
session = Session()
@ -246,16 +251,20 @@ def _send_v310(certificado, **kwargs):
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>')
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 = 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
"sent_xml": xml_send,
"received_xml": response,
"object": obj.Body.nfeDistDFeInteresseResponse.nfeDistDFeInteresseResult,
}

20
pytrustnfe/nfe/assinatura.py

@ -9,7 +9,6 @@ from signxml import XMLSigner
class Assinatura(object):
def __init__(self, arquivo, senha):
self.arquivo = arquivo
self.senha = senha
@ -22,22 +21,25 @@ class Assinatura(object):
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')
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']
ns[None] = signer.namespaces["ds"]
signer.namespaces = ns
ref_uri = ('#%s' % reference) if reference else None
ref_uri = ("#%s" % reference) if reference else None
signed_root = signer.sign(
xml_element, key=key.encode(), cert=cert.encode(),
reference_uri=ref_uri)
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(
".//{http://www.w3.org/2000/09/xmldsig#}Signature")
".//{http://www.w3.org/2000/09/xmldsig#}Signature"
)
if element_signed is not None and signature is not None:
parent = element_signed.getparent()

358
pytrustnfe/nfe/danfce.py

@ -19,25 +19,34 @@ 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:])
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:])
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 = cDateUTC[0:10].split("-")
cDt.reverse()
return '/'.join(cDt), cDateUTC[11:16]
return "/".join(cDt), cDateUTC[11:16]
def format_number(cNumber, precision=0, group_sep='.', decimal_sep=','):
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 (
("{:,." + str(precision) + "f}")
.format(number)
.replace(",", "X")
.replace(".", ",")
.replace("X", ".")
)
return ""
@ -46,7 +55,7 @@ def tagtext(oNode=None, cTag=None):
xpath = ".//{http://www.portalfiscal.inf.br/nfe}%s" % (cTag)
cText = oNode.find(xpath).text
except:
cText = ''
cText = ""
return cText
@ -58,24 +67,19 @@ def get_image(path, width=1 * cm):
def format_telefone(telefone):
telefone = re.sub('[^0-9]', '', telefone)
telefone = re.sub("[^0-9]", "", telefone)
if len(telefone) == 10:
telefone = '(%s) %s-%s' % (telefone[0:2],
telefone[2:6],
telefone[6:])
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:])
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):
self.current_font_size = 7
self.current_font_name = 'NimbusSanL-Regu'
self.current_font_name = "NimbusSanL-Regu"
self.max_height = 840
self.min_height = 1
@ -85,8 +89,8 @@ class danfce(object):
self.oPDF_IO = BytesIO()
self.canvas = canvas.Canvas(self.oPDF_IO, pagesize=(7.2 * cm, 30 * cm))
self.canvas.setTitle('DANFCE')
self.canvas.setLineWidth(.5)
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
@ -99,52 +103,69 @@ class danfce(object):
elem_emit = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}emit")
# Razão Social emitente
nomeEmpresa = tagtext(oNode=elem_emit, cTag='xFant')
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'))
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'):
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.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')
7,
"NimbusSanL-Bold",
)
self.drawTitle("Consumidor Eletrônica", 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.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):
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']]
rows = [["Cód", "Descrição", "Qtde", "Un", "Unit.", "Total"]]
colWidths = (25, 90, 15, 15, 25, 25)
rowHeights = [7]
@ -153,17 +174,14 @@ class danfce(object):
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')
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)
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]
@ -174,54 +192,57 @@ class danfce(object):
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"),
]))
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)
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)
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_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):
@ -236,13 +257,13 @@ class danfce(object):
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,
"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)
@ -252,26 +273,30 @@ class danfce(object):
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']:
["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)])
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")
]))
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
@ -281,27 +306,27 @@ class danfce(object):
# 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_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_prot_nfe = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}protNFe")
el_infAdic = oXML.find(
".//{http://www.portalfiscal.inf.br/nfe}infAdic")
el_infAdic = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infAdic")
url_chave = tagtext(oNode=el_NFeSupl, cTag='urlChave')
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)
frase_chave_acesso = (
"Consulte pela Chave de Acesso em:<br />\
%s<br />%s"
% (url_chave, access_key)
)
qrcode = tagtext(oNode=el_NFeSupl, cTag='qrCode')
qrcode = tagtext(oNode=el_NFeSupl, cTag="qrCode")
cnpj = tagtext(oNode=el_dest, cTag='CNPJ')
cpf = tagtext(oNode=el_dest, cTag='CPF')
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)
@ -312,45 +337,53 @@ class danfce(object):
cnpj_cpf = u"CONSUMIDOR NÃO IDENTIFICADO"
nNFC = tagtext(oNode=el_ide, cTag="nNF")
serie = tagtext(oNode=el_ide, cTag='serie')
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)
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'):
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')
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 = 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)
numProtocolo,
dataAutorizacao,
)
self._drawCenteredParagraph(text)
self.draw_qr_code(qrcode)
infAdFisco = tagtext(oNode=el_infAdic, cTag='infAdFisco')
infAdFisco = tagtext(oNode=el_infAdic, cTag="infAdFisco")
self._drawCenteredParagraph(infAdFisco)
infCpl = tagtext(oNode=el_infAdic, cTag='infCpl')
infCpl = tagtext(oNode=el_infAdic, cTag="infCpl")
self._drawCenteredParagraph(infCpl)
def _drawCenteredParagraph(self, text):
style = ParagraphStyle(
name='Normal',
fontName='NimbusSanL-Regu',
name="Normal",
fontName="NimbusSanL-Regu",
fontSize=7,
alignment=TA_CENTER,
leading=7,
@ -359,27 +392,28 @@ class danfce(object):
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)
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.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'):
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.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.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):
@ -396,8 +430,7 @@ class danfce(object):
def nfce_generate(self):
for oXML in self.list_xml:
oXML_cobr = oXML.find(
".//{http://www.portalfiscal.inf.br/nfe}cobr")
oXML_cobr = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}cobr")
self.NrPages = 1
self.Page = 1
@ -413,17 +446,17 @@ class danfce(object):
list_cod_prod = []
nPg = 0
for nId, item in enumerate(el_det):
el_prod = item.find(
".//{http://www.portalfiscal.inf.br/nfe}prod")
el_prod = item.find(".//{http://www.portalfiscal.inf.br/nfe}prod")
infAdProd = item.find(
".//{http://www.portalfiscal.inf.br/nfe}infAdProd")
".//{http://www.portalfiscal.inf.br/nfe}infAdProd"
)
list_ = wrap(tagtext(oNode=el_prod, cTag='xProd'), 56)
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_cProd = wrap(tagtext(oNode=el_prod, cTag="cProd"), 14)
list_cod_prod.append(list_cProd)
# Nr linhas necessárias p/ descrição item
@ -440,14 +473,19 @@ class danfce(object):
oPaginator[nPg][1] = nId + 1
oPaginator[nPg][2] += nLin_Itens
self.NrPages = len(oPaginator) # Calculando nr. páginas
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.produtos(
oXML=oXML,
el_det=el_det,
oPaginator=oPaginator[0],
list_desc=list_desc,
list_cod_prod=list_cod_prod,
)
self.drawLine()
@ -461,9 +499,13 @@ class danfce(object):
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.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)

1066
pytrustnfe/nfe/danfe.py
File diff suppressed because it is too large
View File

36
pytrustnfe/nfe/patch.py

@ -3,37 +3,43 @@ from pytrustnfe.xml import sanitize_response
def nfeInutilizacaoCE(session, xml_send, ambiente):
soap = '<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope"><Body>\
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>'
>'
+ xml_send
+ "</nfeDadosMsg></Body></Envelope>"
)
headers = {
'SOAPAction': "",
'Content-Type': 'application/soap+xml; charset="utf-8"'
"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)
"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)
"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]
"sent_xml": xml_send,
"received_xml": response,
"object": obj.Body.getchildren()[0],
}
methods = {
'NfeInutilizacaoCE': nfeInutilizacaoCE
}
methods = {"NfeInutilizacaoCE": nfeInutilizacaoCE}
def has_patch(cod_estado, metodo):
uf = SIGLA_ESTADO[cod_estado]
method = metodo+uf
method = metodo + uf
if method in methods:
return methods[method]
return None

43
pytrustnfe/nfse/aparecida/__init__.py

@ -13,24 +13,23 @@ 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)
path = os.path.join(os.path.dirname(__file__), "templates")
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs)
reference = ''
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'
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'
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 = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key)
disable_warnings()
@ -41,41 +40,37 @@ def _send(certificado, method, **kwargs):
client = Client(base_url, transport=transport)
xml_send = kwargs['xml']
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
}
return {"sent_xml": xml_send, "received_xml": response, "object": obj}
def xml_recepcionar_lote_rps(certificado, **kwargs):
return _render(certificado, 'recepcionarLoteRps', **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)
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)
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)
kwargs["xml"] = xml_consultar_lote_rps(certificado, **kwargs)
return _send(certificado, "consultarLoteRps", **kwargs)
def xml_cancelar_nfse(certificado, **kwargs):
return _render(certificado, 'cancelarNfse', **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)
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs)
return _send(certificado, "cancelarNfse", **kwargs)

23
pytrustnfe/nfse/assinatura.py

@ -8,11 +8,10 @@ import os.path
consts = xmlsec.constants
NAMESPACE_SIG = 'http://www.w3.org/2000/09/xmldsig#'
NAMESPACE_SIG = "http://www.w3.org/2000/09/xmldsig#"
class Assinatura(object):
def __init__(self, cert_pem, private_key, password):
self.cert_pem = cert_pem
self.private_key = private_key
@ -20,22 +19,27 @@ class Assinatura(object):
def _checar_certificado(self):
if not os.path.isfile(self.private_key):
raise Exception('Caminho do certificado não existe.')
raise Exception("Caminho do certificado não existe.")
def assina_xml(self, xml, reference):
self._checar_certificado()
template = etree.fromstring(xml)
key = xmlsec.Key.from_file(
self.private_key, format=xmlsec.constants.KeyDataFormatPem,
password=self.password)
self.private_key,
format=xmlsec.constants.KeyDataFormatPem,
password=self.password,
)
signature_node = xmlsec.template.create(
template, c14n_method=consts.TransformInclC14N,
sign_method=consts.TransformRsaSha1)
template,
c14n_method=consts.TransformInclC14N,
sign_method=consts.TransformRsaSha1,
)
template.append(signature_node)
ref = xmlsec.template.add_reference(
signature_node, consts.TransformSha1, uri='')
signature_node, consts.TransformSha1, uri=""
)
xmlsec.template.add_transform(ref, consts.TransformEnveloped)
xmlsec.template.add_transform(ref, consts.TransformInclC14N)
@ -46,8 +50,7 @@ class Assinatura(object):
ctx = xmlsec.SignatureContext()
ctx.key = key
ctx.key.load_cert_from_file(
self.cert_pem, consts.KeyDataFormatPem)
ctx.key.load_cert_from_file(self.cert_pem, consts.KeyDataFormatPem)
ctx.sign(signature_node)
return etree.tostring(template, encoding=str)

76
pytrustnfe/nfse/betha/__init__.py

@ -15,99 +15,97 @@ from pytrustnfe.nfse.assinatura import Assinatura
def sign_tag(certificado, **kwargs):
pkcs12 = crypto.load_pkcs12(certificado.pfx, certificado.password)
key = pkcs12.get_privatekey()
if 'nfse' in kwargs:
for item in kwargs['nfse']['lista_rps']:
signed = crypto.sign(key, item['assinatura'], 'SHA1')
item['assinatura'] = b64encode(signed)
if 'cancelamento' in kwargs:
signed = crypto.sign(key, kwargs['cancelamento']['assinatura'], 'SHA1')
kwargs['cancelamento']['assinatura'] = b64encode(signed)
if "nfse" in kwargs:
for item in kwargs["nfse"]["lista_rps"]:
signed = crypto.sign(key, item["assinatura"], "SHA1")
item["assinatura"] = b64encode(signed)
if "cancelamento" in kwargs:
signed = crypto.sign(key, kwargs["cancelamento"]["assinatura"], "SHA1")
kwargs["cancelamento"]["assinatura"] = b64encode(signed)
def _send(certificado, method, **kwargs):
path = os.path.join(os.path.dirname(__file__), 'templates')
if method in ('GerarNfse', 'RecepcionarLoteRps',
'RecepcionarLoteRpsSincrono',
'CancelarNfse', 'SubstituirNfse'):
path = os.path.join(os.path.dirname(__file__), "templates")
if method in (
"GerarNfse",
"RecepcionarLoteRps",
"RecepcionarLoteRpsSincrono",
"CancelarNfse",
"SubstituirNfse",
):
sign_tag(certificado, **kwargs)
if kwargs['ambiente'] == 'producao':
url = \
'http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl'
if kwargs["ambiente"] == "producao":
url = "http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl"
else:
url = 'http://e-gov.betha.com.br/e-nota-contribuinte-ws/nfseWS?wsdl'
url = "http://e-gov.betha.com.br/e-nota-contribuinte-ws/nfseWS?wsdl"
xml_send = render_xml(path, '%s.xml' % method, False, **kwargs)
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs)
cert, key = extract_cert_and_key_from_pfx(
certificado.pfx, certificado.password)
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key)
client = get_authenticated_client(url, cert, key)
pfx_path = certificado.save_pfx()
signer = Assinatura(pfx_path, certificado.password)
xml_send = signer.assina_xml(xml_send, '')
xml_send = signer.assina_xml(xml_send, "")
try:
response = getattr(client.service, method)(1, xml_send)
except suds.WebFault as e:
return {
'sent_xml': xml_send,
'received_xml': e.fault.faultstring,
'object': None
"sent_xml": xml_send,
"received_xml": e.fault.faultstring,
"object": None,
}
response, obj = sanitize_response(response)
return {
'sent_xml': xml_send,
'received_xml': response,
'object': obj
}
return {"sent_xml": xml_send, "received_xml": response, "object": obj}
def gerar_nfse(certificado, **kwargs):
return _send(certificado, 'GerarNfse', **kwargs)
return _send(certificado, "GerarNfse", **kwargs)
def envio_lote_rps_assincrono(certificado, **kwargs):
return _send(certificado, 'RecepcionarLoteRps', **kwargs)
return _send(certificado, "RecepcionarLoteRps", **kwargs)
def envio_lote_rps(certificado, **kwargs):
return _send(certificado, 'RecepcionarLoteRpsSincrono', **kwargs)
return _send(certificado, "RecepcionarLoteRpsSincrono", **kwargs)
def cancelar_nfse(certificado, **kwargs):
return _send(certificado, 'CancelarNfse', **kwargs)
return _send(certificado, "CancelarNfse", **kwargs)
def substituir_nfse(certificado, **kwargs):
return _send(certificado, 'SubstituirNfse', **kwargs)
return _send(certificado, "SubstituirNfse", **kwargs)
def consulta_situacao_lote_rps(certificado, **kwargs):
return _send(certificado, 'ConsultaSituacaoLoteRPS', **kwargs)
return _send(certificado, "ConsultaSituacaoLoteRPS", **kwargs)
def consulta_nfse_por_rps(certificado, **kwargs):
return _send(certificado, 'ConsultaNfsePorRps', **kwargs)
return _send(certificado, "ConsultaNfsePorRps", **kwargs)
def consultar_lote_rps(certificado, **kwargs):
return _send(certificado, 'ConsultarLoteRps', **kwargs)
return _send(certificado, "ConsultarLoteRps", **kwargs)
def consulta_nfse_servico_prestado(certificado, **kwargs):
return _send(certificado, 'ConsultarNfseServicoPrestado', **kwargs)
return _send(certificado, "ConsultarNfseServicoPrestado", **kwargs)
def consultar_nfse_servico_tomado(certificado, **kwargs):
return _send(certificado, 'ConsultarNfseServicoTomado', **kwargs)
return _send(certificado, "ConsultarNfseServicoTomado", **kwargs)
def consulta_nfse_faixe(certificado, **kwargs):
return _send(certificado, 'ConsultarNfseFaixa', **kwargs)
return _send(certificado, "ConsultarNfseFaixa", **kwargs)
def consulta_cnpj(certificado, **kwargs):
return _send(certificado, 'ConsultaCNPJ', **kwargs)
return _send(certificado, "ConsultaCNPJ", **kwargs)

51
pytrustnfe/nfse/bh/__init__.py

@ -13,38 +13,37 @@ 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)
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']
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')
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'
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'
base_url = "https://bhisshomologa.pbh.gov.br/bhiss-ws/nfse?wsdl"
xml_send = kwargs["xml"].decode('utf-8')
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 = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key)
session = Session()
@ -57,28 +56,24 @@ def _send(certificado, method, **kwargs):
response = client.service[method](xml_cabecalho, xml_send)
response, obj = sanitize_response(response)
return {
'sent_xml': xml_send,
'received_xml': response,
'object': obj
}
return {"sent_xml": xml_send, "received_xml": response, "object": obj}
def xml_gerar_nfse(certificado, **kwargs):
return _render(certificado, 'GerarNfse', **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)
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs)
return _send(certificado, "GerarNfse", **kwargs)
def xml_cancelar_nfse(certificado, **kwargs):
return _render(certificado, 'CancelarNfse', **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)
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs)
return _send(certificado, "CancelarNfse", **kwargs)

21
pytrustnfe/nfse/bh/assinatura.py

@ -9,7 +9,6 @@ from signxml import XMLSigner
class Assinatura(object):
def __init__(self, arquivo, senha):
self.arquivo = arquivo
self.senha = senha
@ -22,21 +21,25 @@ class Assinatura(object):
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')
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']
ns[None] = signer.namespaces["ds"]
signer.namespaces = ns
ref_uri = ('#%s' % reference) if reference else None
ref_uri = ("#%s" % reference) if reference else None
signed_root = signer.sign(
xml_element, key=key.encode(), cert=cert.encode(),
reference_uri=ref_uri)
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()
signature = (
signed_root.find(".//*[@URI='#%s']" % reference).getparent().getparent()
)
if element_signed is not None and signature is not None:
parent = element_signed.getparent()

53
pytrustnfe/nfse/carioca/__init__.py

@ -10,30 +10,29 @@ 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)
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']
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')
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'
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
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)
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)
@ -41,34 +40,30 @@ def _send(certificado, method, **kwargs):
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
"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
}
return {"sent_xml": str(xml_send), "received_xml": str(response), "object": obj}
def xml_gerar_nfse(certificado, **kwargs):
return _render(certificado, 'GerarNfse', **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)
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs)
return _send(certificado, "GerarNfse", **kwargs)
def xml_cancelar_nfse(certificado, **kwargs):
return _render(certificado, 'CancelarNfse', **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)
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs)
return _send(certificado, "CancelarNfse", **kwargs)

69
pytrustnfe/nfse/dsf/__init__.py

@ -12,11 +12,11 @@ from pytrustnfe.client import get_client
def _render(certificado, method, **kwargs):
path = os.path.join(os.path.dirname(__file__), 'templates')
path = os.path.join(os.path.dirname(__file__), "templates")
if method == "testeEnviar":
xml_send = render_xml(path, 'enviar.xml', True, **kwargs)
xml_send = render_xml(path, "enviar.xml", True, **kwargs)
else:
xml_send = render_xml(path, '%s.xml' % method, False, **kwargs)
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs)
if type(xml_send) != str:
xml_send = etree.tostring(xml_send)
@ -26,59 +26,56 @@ def _render(certificado, method, **kwargs):
def _get_url(**kwargs):
try:
cod_cidade = kwargs['nfse']['cidade']
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',
"2715": "http://www.issdigitalbel.com.br/WsNFe2/LoteRps.jws?wsdl",
# Sorocaba - SP
'7145': 'http://issdigital.sorocaba.sp.gov.br/WsNFe2/LoteRps.jws?wsdl',
"7145": "http://issdigital.sorocaba.sp.gov.br/WsNFe2/LoteRps.jws?wsdl",
# Teresina - PI
'1219': 'http://www.issdigitalthe.com.br/WsNFe2/LoteRps.jws?wsdl',
"1219": "http://www.issdigitalthe.com.br/WsNFe2/LoteRps.jws?wsdl",
# Campinas - SP
'6291': 'http://issdigital.campinas.sp.gov.br/WsNFe2/LoteRps.jws?wsdl',
"6291": "http://issdigital.campinas.sp.gov.br/WsNFe2/LoteRps.jws?wsdl",
# Uberlandia - MG
'5403': 'http://udigital.uberlandia.mg.gov.br/WsNFe2/LoteRps.jws?wsdl',
"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',
"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',
"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))
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')
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 = 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, '')
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
"sent_xml": xml_send,
"received_xml": e.fault.faultstring,
"object": None,
}
except Exception as e:
if response:
@ -86,46 +83,42 @@ def _send(certificado, method, **kwargs):
else:
raise e
return {
'sent_xml': xml_send,
'received_xml': response,
'object': obj
}
return {"sent_xml": xml_send, "received_xml": response, "object": obj}
def xml_enviar(certificado, **kwargs):
return _render(certificado, 'enviar', **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)
kwargs["xml"] = xml_enviar(certificado, **kwargs)
return _send(certificado, "enviar", **kwargs)
def xml_teste_enviar(certificado, **kwargs):
return _render(certificado, 'testeEnviar', **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)
kwargs["xml"] = xml_teste_enviar(certificado, **kwargs)
return _send(certificado, "testeEnviar", **kwargs)
def cancelar(certificado, ** kwargs):
return _send(certificado, 'cancelar', **kwargs)
def cancelar(certificado, **kwargs):
return _send(certificado, "cancelar", **kwargs)
def consulta_lote(**kwargs):
return _send(False, 'consultarLote', **kwargs)
return _send(False, "consultarLote", **kwargs)
def xml_consultar_nfse_rps(certificado, **kwargs):
return _render(certificado, 'consultarNFSeRps', **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)
kwargs["xml"] = xml_consultar_nfse_rps(certificado, **kwargs)
return _send(certificado, "consultarNFSeRps", **kwargs)

96
pytrustnfe/nfse/floripa/__init__.py

@ -11,47 +11,48 @@ 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'
"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",
},
'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)
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 = 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, '')
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'
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'
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'))
auth = base64.b64encode(secret.encode("utf-8"))
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic %s" % auth.decode('utf-8').replace('\n', '')
"Authorization": "Basic %s" % auth.decode("utf-8").replace("\n", ""),
}
m.update(kwargs["password"].encode('utf-8'))
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"])
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()
@ -60,57 +61,66 @@ def _get_oauth_token(**kwargs):
def _send(certificado, method, **kwargs):
url = URLS[kwargs['ambiente']][method]
xml_send = kwargs['xml']
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"]})
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']}
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,
"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)
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)
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)
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)
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"])
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"])
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']}
headers = {
"Accept": "application/json",
"Authorization": "Bearer %s" % kwargs["access_token"],
}
r = requests.get(url, headers=headers)
if r.status_code == 200:
return r.text

59
pytrustnfe/nfse/ginfes/__init__.py

@ -14,12 +14,12 @@ 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)
path = os.path.join(os.path.dirname(__file__), "templates")
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs)
reference = ''
if method == 'RecepcionarLoteRpsV3':
reference = 'rps%s' % kwargs['nfse']['lista_rps'][0]['numero']
reference = ""
if method == "RecepcionarLoteRpsV3":
reference = "rps%s" % kwargs["nfse"]["lista_rps"][0]["numero"]
signer = Assinatura(certificado.pfx, certificado.password)
xml_send = signer.assina_xml(xml_send, reference)
@ -27,17 +27,16 @@ def _render(certificado, method, **kwargs):
def _send(certificado, method, **kwargs):
base_url = ''
if kwargs['ambiente'] == 'producao':
base_url = 'https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl'
base_url = ""
if kwargs["ambiente"] == "producao":
base_url = "https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl"
else:
base_url = 'https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl'
base_url = "https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl"
cert, key = extract_cert_and_key_from_pfx(
certificado.pfx, certificado.password)
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key)
header = '<ns2:cabecalho xmlns:ns2="http://www.ginfes.com.br/cabecalho_v03.xsd" versao="3"><versaoDados>3</versaoDados></ns2:cabecalho>' #noqa
header = '<ns2:cabecalho xmlns:ns2="http://www.ginfes.com.br/cabecalho_v03.xsd" versao="3"><versaoDados>3</versaoDados></ns2:cabecalho>' # noqa
disable_warnings()
session = Session()
@ -47,60 +46,56 @@ def _send(certificado, method, **kwargs):
client = Client(base_url, transport=transport)
xml_send = kwargs['xml']
xml_send = kwargs["xml"]
response = client.service[method](header, xml_send)
response, obj = sanitize_response(response)
return {
'sent_xml': xml_send,
'received_xml': response,
'object': obj
}
return {"sent_xml": xml_send, "received_xml": response, "object": obj}
def xml_recepcionar_lote_rps(certificado, **kwargs):
return _render(certificado, 'RecepcionarLoteRpsV3', **kwargs)
return _render(certificado, "RecepcionarLoteRpsV3", **kwargs)
def recepcionar_lote_rps(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_recepcionar_lote_rps(certificado, **kwargs)
return _send(certificado, 'RecepcionarLoteRpsV3', **kwargs)
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs)
return _send(certificado, "RecepcionarLoteRpsV3", **kwargs)
def xml_consultar_situacao_lote(certificado, **kwargs):
return _render(certificado, 'ConsultarSituacaoLoteRpsV3', **kwargs)
return _render(certificado, "ConsultarSituacaoLoteRpsV3", **kwargs)
def consultar_situacao_lote(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_consultar_situacao_lote(certificado, **kwargs)
return _send(certificado, 'ConsultarSituacaoLoteRpsV3', **kwargs)
kwargs["xml"] = xml_consultar_situacao_lote(certificado, **kwargs)
return _send(certificado, "ConsultarSituacaoLoteRpsV3", **kwargs)
def consultar_nfse_por_rps(certificado, **kwargs):
return _send(certificado, 'ConsultarNfsePorRpsV3', **kwargs)
return _send(certificado, "ConsultarNfsePorRpsV3", **kwargs)
def xml_consultar_lote_rps(certificado, **kwargs):
return _render(certificado, 'ConsultarLoteRpsV3', **kwargs)
return _render(certificado, "ConsultarLoteRpsV3", **kwargs)
def consultar_lote_rps(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_consultar_lote_rps(certificado, **kwargs)
return _send(certificado, 'ConsultarLoteRpsV3', **kwargs)
kwargs["xml"] = xml_consultar_lote_rps(certificado, **kwargs)
return _send(certificado, "ConsultarLoteRpsV3", **kwargs)
def consultar_nfse(certificado, **kwargs):
return _send(certificado, 'ConsultarNfseV3', **kwargs)
return _send(certificado, "ConsultarNfseV3", **kwargs)
def xml_cancelar_nfse(certificado, **kwargs):
return _render(certificado, 'CancelarNfseV3', **kwargs)
return _render(certificado, "CancelarNfseV3", **kwargs)
def cancelar_nfse(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_cancelar_nfse(certificado, **kwargs)
return _send(certificado, 'CancelarNfseV3', **kwargs)
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs)
return _send(certificado, "CancelarNfseV3", **kwargs)

38
pytrustnfe/nfse/imperial/__init__.py

@ -12,49 +12,47 @@ from pytrustnfe.xml import render_xml, sanitize_response
def _render(certificado, method, **kwargs):
path = os.path.join(os.path.dirname(__file__), 'templates')
xml_send = render_xml(path, '%s.xml' % method, True, **kwargs)
path = os.path.join(os.path.dirname(__file__), "templates")
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs)
return etree.tostring(xml_send)
def _send(certificado, method, **kwargs):
base_url = ''
if kwargs['ambiente'] == 'producao':
base_url = 'https://petropolis.sigiss.com.br/petropolis/ws/sigiss_ws.php' # noqa
base_url = ""
if kwargs["ambiente"] == "producao":
base_url = (
"https://petropolis.sigiss.com.br/petropolis/ws/sigiss_ws.php" # noqa
)
else:
raise Exception('Não existe ambiente de homologação!')
raise Exception("Não existe ambiente de homologação!")
xml_send = kwargs["xml"].decode('utf-8')
xml_send = kwargs["xml"].decode("utf-8")
headers = {
'SOAPAction': "urn:sigiss_ws#%s" % method,
'Content-Type': 'text/xml; charset="utf-8"'
"SOAPAction": "urn:sigiss_ws#%s" % method,
"Content-Type": 'text/xml; charset="utf-8"',
}
r = requests.post(base_url, data=xml_send, headers=headers)
response, obj = sanitize_response(r.text.strip())
return {
'sent_xml': xml_send,
'received_xml': response,
'object': obj.Body
}
return {"sent_xml": xml_send, "received_xml": response, "object": obj.Body}
def xml_gerar_nota(certificado, **kwargs):
return _render(certificado, 'GerarNota', **kwargs)
return _render(certificado, "GerarNota", **kwargs)
def gerar_nota(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_gerar_nota(certificado, **kwargs)
return _send(certificado, 'GerarNota', **kwargs)
kwargs["xml"] = xml_gerar_nota(certificado, **kwargs)
return _send(certificado, "GerarNota", **kwargs)
def xml_cancelar_nota(certificado, **kwargs):
return _render(certificado, 'CancelarNota', **kwargs)
return _render(certificado, "CancelarNota", **kwargs)
def cancelar_nota(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_cancelar_nota(certificado, **kwargs)
return _send(certificado, 'CancelarNota', **kwargs)
kwargs["xml"] = xml_cancelar_nota(certificado, **kwargs)
return _send(certificado, "CancelarNota", **kwargs)

47
pytrustnfe/nfse/mga/__init__.py

@ -12,31 +12,30 @@ 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)
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']
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')
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'
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'
base_url = "https://isseteste.maringa.pr.gov.br/ws/?wsdl"
xml_send = kwargs["xml"].decode('utf-8')
xml_send = kwargs["xml"].decode("utf-8")
cert, key = extract_cert_and_key_from_pfx(
certificado.pfx, certificado.password)
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key)
session = Session()
@ -48,28 +47,24 @@ def _send(certificado, method, **kwargs):
response = client.service[method](xml_send)
response, obj = sanitize_response(response)
return {
'sent_xml': str(xml_send),
'received_xml': str(response),
'object': obj
}
return {"sent_xml": str(xml_send), "received_xml": str(response), "object": obj}
def xml_gerar_nfse(certificado, **kwargs):
return _render(certificado, 'GerarNfse', **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)
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs)
return _send(certificado, "GerarNfse", **kwargs)
def xml_cancelar_nfse(certificado, **kwargs):
return _render(certificado, 'CancelarNfse', **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)
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs)
return _send(certificado, "CancelarNfse", **kwargs)

17
pytrustnfe/nfse/mga/assinatura.py

@ -9,7 +9,6 @@ from signxml import XMLSigner
class Assinatura(object):
def __init__(self, arquivo, senha):
self.arquivo = arquivo
self.senha = senha
@ -22,22 +21,26 @@ class Assinatura(object):
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')
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']
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())
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")
".//{http://www.w3.org/2000/09/xmldsig#}Signature"
)
if element_signed is not None and signature is not None:
parent = xml_element.getchildren()[0]

68
pytrustnfe/nfse/paulistana/__init__.py

@ -15,96 +15,94 @@ from pytrustnfe.nfse.assinatura import Assinatura
def sign_tag(certificado, **kwargs):
pkcs12 = crypto.load_pkcs12(certificado.pfx, certificado.password)
key = pkcs12.get_privatekey()
if 'nfse' in kwargs:
for item in kwargs['nfse']['lista_rps']:
signed = crypto.sign(key, item['assinatura'], 'SHA1')
item['assinatura'] = b64encode(signed).decode()
if 'cancelamento' in kwargs:
signed = crypto.sign(key, kwargs['cancelamento']['assinatura'], 'SHA1')
kwargs['cancelamento']['assinatura'] = b64encode(signed).decode()
if "nfse" in kwargs:
for item in kwargs["nfse"]["lista_rps"]:
signed = crypto.sign(key, item["assinatura"], "SHA1")
item["assinatura"] = b64encode(signed).decode()
if "cancelamento" in kwargs:
signed = crypto.sign(key, kwargs["cancelamento"]["assinatura"], "SHA1")
kwargs["cancelamento"]["assinatura"] = b64encode(signed).decode()
def _send(certificado, method, **kwargs):
# A little hack to test
path = os.path.join(os.path.dirname(__file__), 'templates')
if method == 'TesteEnvioLoteRPS' or method == 'EnvioLoteRPS' \
or method == 'CancelamentoNFe':
path = os.path.join(os.path.dirname(__file__), "templates")
if (
method == "TesteEnvioLoteRPS"
or method == "EnvioLoteRPS"
or method == "CancelamentoNFe"
):
sign_tag(certificado, **kwargs)
if method == 'TesteEnvioLoteRPS':
xml_send = render_xml(path, 'EnvioLoteRPS.xml', False, **kwargs)
if method == "TesteEnvioLoteRPS":
xml_send = render_xml(path, "EnvioLoteRPS.xml", False, **kwargs)
else:
xml_send = render_xml(path, '%s.xml' % method, False, **kwargs)
base_url = 'https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl'
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs)
base_url = "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl"
cert, key = extract_cert_and_key_from_pfx(
certificado.pfx, certificado.password)
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)
signer = Assinatura(cert, key, certificado.password)
xml_send = signer.assina_xml(xml_send, '')
xml_send = signer.assina_xml(xml_send, "")
try:
response = getattr(client.service, method)(1, xml_send)
except suds.WebFault as e:
return {
'sent_xml': xml_send,
'received_xml': e.fault.faultstring,
'object': None
"sent_xml": xml_send,
"received_xml": e.fault.faultstring,
"object": None,
}
response, obj = sanitize_response(response)
return {
'sent_xml': xml_send,
'received_xml': response,
'object': obj
}
return {"sent_xml": xml_send, "received_xml": response, "object": obj}
def envio_rps(certificado, **kwargs):
return _send(certificado, 'EnvioRPS', **kwargs)
return _send(certificado, "EnvioRPS", **kwargs)
# Testado pois usa o mesmo xml que o teste_envio_lote_rps
def envio_lote_rps(certificado, **kwargs):
return _send(certificado, 'EnvioLoteRPS', **kwargs)
return _send(certificado, "EnvioLoteRPS", **kwargs)
# Testado
def teste_envio_lote_rps(certificado, **kwargs):
return _send(certificado, 'TesteEnvioLoteRPS', **kwargs)
return _send(certificado, "TesteEnvioLoteRPS", **kwargs)
def cancelamento_nfe(certificado, **kwargs):
return _send(certificado, 'CancelamentoNFe', **kwargs)
return _send(certificado, "CancelamentoNFe", **kwargs)
# Testado
def consulta_nfe(certificado, **kwargs):
return _send(certificado, 'ConsultaNFe', **kwargs)
return _send(certificado, "ConsultaNFe", **kwargs)
# Testado
def consulta_nfe_recebidas(certificado, **kwargs):
return _send(certificado, 'ConsultaNFeRecebidas', **kwargs)
return _send(certificado, "ConsultaNFeRecebidas", **kwargs)
# Testado
def consulta_nfe_emitidas(certificado, **kwargs):
return _send(certificado, 'ConsultaNFeEmitidas', **kwargs)
return _send(certificado, "ConsultaNFeEmitidas", **kwargs)
# Testado
def consulta_lote(certificado, **kwargs):
return _send(certificado, 'ConsultaLote', **kwargs)
return _send(certificado, "ConsultaLote", **kwargs)
# Testado
def consulta_informacoes_lote(certificado, **kwargs):
return _send(certificado, 'ConsultaInformacoesLote', **kwargs)
return _send(certificado, "ConsultaInformacoesLote", **kwargs)
# Testado
def consulta_cnpj(certificado, **kwargs):
return _send(certificado, 'ConsultaCNPJ', **kwargs)
return _send(certificado, "ConsultaCNPJ", **kwargs)

64
pytrustnfe/nfse/simpliss/__init__.py

@ -15,16 +15,16 @@ from pytrustnfe.xml import render_xml, sanitize_response
def _render_xml(certificado, method, **kwargs):
path = os.path.join(os.path.dirname(__file__), 'templates')
xml_send = render_xml(path, '%s.xml' % method, True, **kwargs)
path = os.path.join(os.path.dirname(__file__), "templates")
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs)
xml_send = etree.tostring(xml_send)
return xml_send
def _validate(method, xml):
path = os.path.join(os.path.dirname(__file__), 'templates')
schema = os.path.join(path, '%s.xsd' % method)
path = os.path.join(os.path.dirname(__file__), "templates")
schema = os.path.join(path, "%s.xsd" % method)
nfe = etree.fromstring(xml)
esquema = etree.XMLSchema(etree.parse(schema))
@ -34,86 +34,82 @@ def _validate(method, xml):
def _send(method, **kwargs):
if kwargs['ambiente'] == 'producao':
base_url = 'http://sistemas.pmp.sp.gov.br/semfi/simpliss/ws_nfse/nfseservice.svc' # noqa
if kwargs["ambiente"] == "producao":
base_url = "http://sistemas.pmp.sp.gov.br/semfi/simpliss/ws_nfse/nfseservice.svc" # noqa
else:
base_url = 'http://wshomologacao.simplissweb.com.br/nfseservice.svc' # noqa
base_url = "http://wshomologacao.simplissweb.com.br/nfseservice.svc" # noqa
base_url = 'http://wshomologacao.simplissweb.com.br/nfseservice.svc'
base_url = "http://wshomologacao.simplissweb.com.br/nfseservice.svc"
xml_send = kwargs["xml"]
path = os.path.join(os.path.dirname(__file__), 'templates')
soap = render_xml(path, 'SoapRequest.xml', False, soap_body=xml_send)
path = os.path.join(os.path.dirname(__file__), "templates")
soap = render_xml(path, "SoapRequest.xml", False, soap_body=xml_send)
act = 'http://www.sistema.com.br/Sistema.Ws.Nfse/INfseService/%s' % method
act = "http://www.sistema.com.br/Sistema.Ws.Nfse/INfseService/%s" % method
client = HttpClient(base_url)
response = client.post_soap(soap, act)
response, obj = sanitize_response(response)
return {
'sent_xml': xml_send,
'received_xml': response,
'object': obj
}
return {"sent_xml": xml_send, "received_xml": response, "object": obj}
def xml_recepcionar_lote_rps(certificado, **kwargs):
return _render_xml(certificado, 'RecepcionarLoteRps', **kwargs)
return _render_xml(certificado, "RecepcionarLoteRps", **kwargs)
def recepcionar_lote_rps(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_recepcionar_lote_rps(certificado, **kwargs)
return _send('RecepcionarLoteRps', **kwargs)
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs)
return _send("RecepcionarLoteRps", **kwargs)
def xml_consultar_situacao_lote(certificado, **kwargs):
return _render_xml(certificado, 'ConsultarSituacaoLoteRps', **kwargs)
return _render_xml(certificado, "ConsultarSituacaoLoteRps", **kwargs)
def consultar_situacao_lote(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_consultar_situacao_lote(certificado, **kwargs)
return _send('ConsultarSituacaoLoteRps', **kwargs)
kwargs["xml"] = xml_consultar_situacao_lote(certificado, **kwargs)
return _send("ConsultarSituacaoLoteRps", **kwargs)
def consultar_nfse_por_rps(certificado, **kwargs):
return _send('ConsultarNfsePorRps', **kwargs)
return _send("ConsultarNfsePorRps", **kwargs)
def xml_consultar_lote_rps(certificado, **kwargs):
return _render_xml(certificado, 'ConsultarLoteRps', **kwargs)
return _render_xml(certificado, "ConsultarLoteRps", **kwargs)
def consultar_lote_rps(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_consultar_lote_rps(certificado, **kwargs)
return _send('ConsultarLoteRps', **kwargs)
kwargs["xml"] = xml_consultar_lote_rps(certificado, **kwargs)
return _send("ConsultarLoteRps", **kwargs)
def xml_consultar_nfse(certificado, **kwargs):
return _render_xml(certificado, 'ConsultarNfse', **kwargs)
return _render_xml(certificado, "ConsultarNfse", **kwargs)
def consultar_nfse(certificado, **kwargs):
return _send('ConsultarNfse', **kwargs)
return _send("ConsultarNfse", **kwargs)
def xml_cancelar_nfse(certificado, **kwargs):
return _render_xml(certificado, 'CancelarNfse', **kwargs)
return _render_xml(certificado, "CancelarNfse", **kwargs)
def cancelar_nfse(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_cancelar_nfse(certificado, **kwargs)
return _send('CancelarNfse', **kwargs)
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs)
return _send("CancelarNfse", **kwargs)
def xml_gerar_nfse(certificado, **kwargs):
return _render_xml(certificado, 'GerarNfse', **kwargs)
return _render_xml(certificado, "GerarNfse", **kwargs)
def gerar_nfse(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_recepcionar_lote_rps(certificado, **kwargs)
return _send('GerarNfse', **kwargs)
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs)
return _send("GerarNfse", **kwargs)

34
pytrustnfe/nfse/susesu/__init__.py

@ -9,49 +9,49 @@ from pytrustnfe.client import get_client
def _render_xml(method, **kwargs):
path = os.path.join(os.path.dirname(__file__), 'templates')
xml_send = render_xml(path, '%s.xml' % method, False, **kwargs)
path = os.path.join(os.path.dirname(__file__), "templates")
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs)
return xml_send
def _send(method, **kwargs):
if kwargs['ambiente'] == 'producao':
base_url = 'http://www.susesu.com.br/wsnfd/serviconfd.asmx?WSDL'
if kwargs["ambiente"] == "producao":
base_url = "http://www.susesu.com.br/wsnfd/serviconfd.asmx?WSDL"
else:
base_url = 'http://pira.comunix.net:5002/gestaopublica/wsnfd/ServicoNfd.asmx?WSDL' # noqa
base_url = "http://pira.comunix.net:5002/gestaopublica/wsnfd/ServicoNfd.asmx?WSDL" # noqa
client = get_client(base_url)
try:
xml_send = kwargs["xml"]
result = getattr(client.service, method)(__inject={'msg': xml_send})
result = getattr(client.service, method)(__inject={"msg": xml_send})
except Exception as e:
return {
'sent_xml': xml_send,
'received_xml': e.fault.faultstring,
"sent_xml": xml_send,
"received_xml": e.fault.faultstring,
}
result = str(result)
result = unicodedata.normalize('NFKD', result).encode('ascii', 'ignore')
result = unicodedata.normalize("NFKD", result).encode("ascii", "ignore")
return {
'sent_xml': xml_send,
'received_xml': result,
"sent_xml": xml_send,
"received_xml": result,
}
def xml_enviar_nota(**kwargs):
return _render_xml('EnviarNota', **kwargs)
return _render_xml("EnviarNota", **kwargs)
def enviar_nota(**kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_enviar_nota(**kwargs)
return _send('EnviarNota', **kwargs)
kwargs["xml"] = xml_enviar_nota(**kwargs)
return _send("EnviarNota", **kwargs)
def xml_enviar_nota_retorna_url(**kwargs):
return _render_xml('EnviarNotaRetornaurlNota', **kwargs)
return _render_xml("EnviarNotaRetornaurlNota", **kwargs)
def enviar_nota_retorna_url(**kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_enviar_nota_retorna_url(**kwargs)
return _send('EnviarNotaRetornaurlNota', **kwargs)
kwargs["xml"] = xml_enviar_nota_retorna_url(**kwargs)
return _send("EnviarNotaRetornaurlNota", **kwargs)

262
pytrustnfe/urls.py

@ -1,146 +1,146 @@
AC = '12'
AL = '27'
AM = '13'
AP = '16'
BA = '29'
CE = '23'
DF = '53'
ES = '32'
GO = '52'
MA = '21'
MG = '31'
MS = '50'
MT = '51'
PA = '15'
PB = '25'
PE = '26'
PI = '22'
PR = '41'
RJ = '33'
RN = '24'
RO = '11'
RR = '14'
RS = '43'
SC = '42'
SE = '28'
SP = '35'
TO = '17'
AC = "12"
AL = "27"
AM = "13"
AP = "16"
BA = "29"
CE = "23"
DF = "53"
ES = "32"
GO = "52"
MA = "21"
MG = "31"
MS = "50"
MT = "51"
PA = "15"
PB = "25"
PE = "26"
PI = "22"
PR = "41"
RJ = "33"
RN = "24"
RO = "11"
RR = "14"
RS = "43"
SC = "42"
SE = "28"
SP = "35"
TO = "17"
PRODUCAO = '1'
HOMOLOGACAO = '2'
PRODUCAO = "1"
HOMOLOGACAO = "2"
URLS = {
PRODUCAO: {
AC: 'http://www.sefaznet.ac.gov.br/nfce/qrcode?',
AL: 'http://nfce.sefaz.al.gov.br/QRCode/consultarNFCe.jsp?',
AM: 'http://sistemas.sefaz.am.gov.br/nfceweb/consultarNFCe.jsp?',
AP: 'https://www.sefaz.ap.gov.br/nfce/nfcep.php?',
BA: 'http://nfe.sefaz.ba.gov.br/servicos/nfce/qrcode.aspx?',
DF: 'http://www.fazenda.df.gov.br/nfce/qrcode?',
GO: 'http://nfe.sefaz.go.gov.br/nfeweb/sites/nfce/danfeNFCe?',
MA: 'http://nfce.sefaz.ma.gov.br/portal/consultarNFCe.jsp?',
MG: 'https://nfce.fazenda.mg.gov.br/portalnfce/sistema/qrcode.xhtml?',
MS: 'http://www.dfe.ms.gov.br/nfce/qrcode?',
MT: 'http://www.sefaz.mt.gov.br/nfce/consultanfce?',
PA: 'https://appnfc.sefa.pa.gov.br/portal/view/consultas/nfce/nfceForm.seam?', # noqa
PB: 'http://www.receita.pb.gov.br/nfce?',
PE: 'http://nfce.sefaz.pe.gov.br/nfce/consulta?',
PI: 'http://www.sefaz.pi.gov.br/nfce/qrcode?',
PR: 'http://www.fazenda.pr.gov.br/nfce/consulta?',
RJ: 'http://www4.fazenda.rj.gov.br/consultaNFCe/QRCode?',
RN: 'http://nfce.set.rn.gov.br/consultarNFCe.aspx?',
RO: 'http://www.nfce.sefin.ro.gov.br/consultanfce/consulta.jsp?',
RR: 'https://www.sefaz.rr.gov.br/nfce/servlet/qrcode?',
RS: 'https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx?',
SE: 'http://www.nfce.se.gov.br/nfce/qrcode?',
SP: 'https://www.nfce.fazenda.sp.gov.br/qrcode?',
TO: 'http://www.sefaz.to.gov.br/nfce/qrcode?',
AC: "http://www.sefaznet.ac.gov.br/nfce/qrcode?",
AL: "http://nfce.sefaz.al.gov.br/QRCode/consultarNFCe.jsp?",
AM: "http://sistemas.sefaz.am.gov.br/nfceweb/consultarNFCe.jsp?",
AP: "https://www.sefaz.ap.gov.br/nfce/nfcep.php?",
BA: "http://nfe.sefaz.ba.gov.br/servicos/nfce/qrcode.aspx?",
DF: "http://www.fazenda.df.gov.br/nfce/qrcode?",
GO: "http://nfe.sefaz.go.gov.br/nfeweb/sites/nfce/danfeNFCe?",
MA: "http://nfce.sefaz.ma.gov.br/portal/consultarNFCe.jsp?",
MG: "https://nfce.fazenda.mg.gov.br/portalnfce/sistema/qrcode.xhtml?",
MS: "http://www.dfe.ms.gov.br/nfce/qrcode?",
MT: "http://www.sefaz.mt.gov.br/nfce/consultanfce?",
PA: "https://appnfc.sefa.pa.gov.br/portal/view/consultas/nfce/nfceForm.seam?", # noqa
PB: "http://www.receita.pb.gov.br/nfce?",
PE: "http://nfce.sefaz.pe.gov.br/nfce/consulta?",
PI: "http://www.sefaz.pi.gov.br/nfce/qrcode?",
PR: "http://www.fazenda.pr.gov.br/nfce/consulta?",
RJ: "http://www4.fazenda.rj.gov.br/consultaNFCe/QRCode?",
RN: "http://nfce.set.rn.gov.br/consultarNFCe.aspx?",
RO: "http://www.nfce.sefin.ro.gov.br/consultanfce/consulta.jsp?",
RR: "https://www.sefaz.rr.gov.br/nfce/servlet/qrcode?",
RS: "https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx?",
SE: "http://www.nfce.se.gov.br/nfce/qrcode?",
SP: "https://www.nfce.fazenda.sp.gov.br/qrcode?",
TO: "http://www.sefaz.to.gov.br/nfce/qrcode?",
},
HOMOLOGACAO: {
AC: 'http://www.hml.sefaznet.ac.gov.br/nfce/qrcode?',
AL: 'http://nfce.sefaz.al.gov.br/QRCode/consultarNFCe.jsp?',
AM: 'http://homnfce.sefaz.am.gov.br/nfceweb/consultarNFCe.jsp?',
AP: 'https://www.sefaz.ap.gov.br/nfcehml/nfce.php?',
BA: 'http://hnfe.sefaz.ba.gov.br/servicos/nfce/qrcode.aspx?',
DF: 'http://www.fazenda.df.gov.br/nfce/qrcode?',
GO: 'http://homolog.sefaz.go.gov.br/nfeweb/sites/nfce/danfeNFCe?',
MA: 'http://homologacao.sefaz.ma.gov.br/portal/consultarNFCe.jsp?',
MS: 'http://www.dfe.ms.gov.br/nfce/qrcode?',
MG: 'https://nfce.fazenda.mg.gov.br/portalnfce/sistema/qrcode.xhtml?',
MT: 'http://homologacao.sefaz.mt.gov.br/nfce/consultanfce?',
PA: 'https://appnfc.sefa.pa.gov.br/portal-homologacao/view/consultas/nfce/nfceForm.seam?', # noqa
PB: 'http://www.receita.pb.gov.br/nfcehom?',
PE: 'http://nfcehomolog.sefaz.pe.gov.br/nfce/consulta?',
PI: 'http://www.sefaz.pi.gov.br/nfce/qrcode?',
PR: 'http://www.fazenda.pr.gov.br/nfce/consulta?',
RJ: 'http://www4.fazenda.rj.gov.br/consultaNFCe/QRCode?',
RN: 'http://hom.nfce.set.rn.gov.br/consultarNFCe.aspx?',
RO: 'http://200.174.88.103:8080/nfce/servlet/qrcode?',
RR: 'https://www.sefaz.rr.gov.br/nfce/servlet/qrcode?',
RS: 'https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx?',
SE: 'http://www.hom.nfe.se.gov.br/nfce/qrcode?',
SP: 'https://www.homologacao.nfce.fazenda.sp.gov.br/qrcode?',
TO: 'http://homologacao.sefaz.to.gov.br/nfce/qrcode?',
}
AC: "http://www.hml.sefaznet.ac.gov.br/nfce/qrcode?",
AL: "http://nfce.sefaz.al.gov.br/QRCode/consultarNFCe.jsp?",
AM: "http://homnfce.sefaz.am.gov.br/nfceweb/consultarNFCe.jsp?",
AP: "https://www.sefaz.ap.gov.br/nfcehml/nfce.php?",
BA: "http://hnfe.sefaz.ba.gov.br/servicos/nfce/qrcode.aspx?",
DF: "http://www.fazenda.df.gov.br/nfce/qrcode?",
GO: "http://homolog.sefaz.go.gov.br/nfeweb/sites/nfce/danfeNFCe?",
MA: "http://homologacao.sefaz.ma.gov.br/portal/consultarNFCe.jsp?",
MS: "http://www.dfe.ms.gov.br/nfce/qrcode?",
MG: "https://nfce.fazenda.mg.gov.br/portalnfce/sistema/qrcode.xhtml?",
MT: "http://homologacao.sefaz.mt.gov.br/nfce/consultanfce?",
PA: "https://appnfc.sefa.pa.gov.br/portal-homologacao/view/consultas/nfce/nfceForm.seam?", # noqa
PB: "http://www.receita.pb.gov.br/nfcehom?",
PE: "http://nfcehomolog.sefaz.pe.gov.br/nfce/consulta?",
PI: "http://www.sefaz.pi.gov.br/nfce/qrcode?",
PR: "http://www.fazenda.pr.gov.br/nfce/consulta?",
RJ: "http://www4.fazenda.rj.gov.br/consultaNFCe/QRCode?",
RN: "http://hom.nfce.set.rn.gov.br/consultarNFCe.aspx?",
RO: "http://200.174.88.103:8080/nfce/servlet/qrcode?",
RR: "https://www.sefaz.rr.gov.br/nfce/servlet/qrcode?",
RS: "https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx?",
SE: "http://www.hom.nfe.se.gov.br/nfce/qrcode?",
SP: "https://www.homologacao.nfce.fazenda.sp.gov.br/qrcode?",
TO: "http://homologacao.sefaz.to.gov.br/nfce/qrcode?",
},
}
URLS_EXIBICAO = {
PRODUCAO: {
AC: 'www.sefaznet.ac.gov.br/nfce/consulta',
AL: 'www.sefaz.al.gov.br/nfce/consulta',
AM: 'www.sefaz.am.gov.br/nfce/consulta',
AP: 'www.sefaz.ap.gov.br/nfce/consulta',
BA: 'http://www.sefaz.ba.gov.br/nfce/consulta',
CE: 'www.sefaz.ce.gov.br/nfce/consulta',
DF: 'www.fazenda.df.gov.br/nfce/consulta',
ES: 'www.sefaz.es.gov.br/nfce/consulta',
GO: 'www.sefaz.go.gov.br/nfce/consulta',
MA: 'www.sefaz.ma.gov.br/nfce/consulta',
MS: 'www.dfe.ms.gov.br/nfce/consulta',
MT: 'www.sefaz.mt.gov.br/nfce/consulta',
MG: 'http://nfce.fazenda.mg.gov.br/portalnfce',
PA: 'www.sefa.pa.gov.br/nfce/consulta',
PB: 'www.receita.pb.gov.br/nfce/consulta',
PE: 'nfce.sefaz.pe.gov.br/nfce/consulta',
PI: 'www.sefaz.pi.gov.br/nfce/consulta',
PR: 'http://www.fazenda.pr.gov.br/nfce/consulta',
RJ: 'www.fazenda.rj.gov.br/nfce/consulta',
RN: 'www.set.rn.gov.br/nfce/consulta',
RO: 'www.sefin.ro.gov.br/nfce/consulta',
RR: 'www.sefaz.rr.gov.br/nfce/consulta',
RS: 'www.sefaz.rs.gov.br/nfce/consulta',
SE: 'http://www.nfce.se.gov.br/nfce/consulta',
SP: 'https://www.nfce.fazenda.sp.gov.br/consulta',
TO: 'www.sefaz.to.gov.br/nfce/consulta',
AC: "www.sefaznet.ac.gov.br/nfce/consulta",
AL: "www.sefaz.al.gov.br/nfce/consulta",
AM: "www.sefaz.am.gov.br/nfce/consulta",
AP: "www.sefaz.ap.gov.br/nfce/consulta",
BA: "http://www.sefaz.ba.gov.br/nfce/consulta",
CE: "www.sefaz.ce.gov.br/nfce/consulta",
DF: "www.fazenda.df.gov.br/nfce/consulta",
ES: "www.sefaz.es.gov.br/nfce/consulta",
GO: "www.sefaz.go.gov.br/nfce/consulta",
MA: "www.sefaz.ma.gov.br/nfce/consulta",
MS: "www.dfe.ms.gov.br/nfce/consulta",
MT: "www.sefaz.mt.gov.br/nfce/consulta",
MG: "http://nfce.fazenda.mg.gov.br/portalnfce",
PA: "www.sefa.pa.gov.br/nfce/consulta",
PB: "www.receita.pb.gov.br/nfce/consulta",
PE: "nfce.sefaz.pe.gov.br/nfce/consulta",
PI: "www.sefaz.pi.gov.br/nfce/consulta",
PR: "http://www.fazenda.pr.gov.br/nfce/consulta",
RJ: "www.fazenda.rj.gov.br/nfce/consulta",
RN: "www.set.rn.gov.br/nfce/consulta",
RO: "www.sefin.ro.gov.br/nfce/consulta",
RR: "www.sefaz.rr.gov.br/nfce/consulta",
RS: "www.sefaz.rs.gov.br/nfce/consulta",
SE: "http://www.nfce.se.gov.br/nfce/consulta",
SP: "https://www.nfce.fazenda.sp.gov.br/consulta",
TO: "www.sefaz.to.gov.br/nfce/consulta",
},
HOMOLOGACAO: {
AC: 'www.sefaznet.ac.gov.br/nfce/consulta',
AL: 'www.sefaz.al.gov.br/nfce/consulta',
AM: 'www.sefaz.am.gov.br/nfce/consulta',
AP: 'www.sefaz.ap.gov.br/nfce/consulta',
BA: 'http://hinternet.sefaz.ba.gov.br/nfce/consulta',
CE: 'www.sefaz.ce.gov.br/nfce/consulta',
DF: 'www.fazenda.df.gov.br/nfce/consulta',
ES: 'www.sefaz.es.gov.br/nfce/consulta',
GO: 'www.sefaz.go.gov.br/nfce/consulta',
MA: 'www.sefaz.ma.gov.br/nfce/consulta',
MS: 'www.dfe.ms.gov.br/nfce/consulta',
MT: 'www.sefaz.mt.gov.br/nfce/consulta',
MG: 'http://hnfce.fazenda.mg.gov.br/portalnfce',
PA: 'www.sefa.pa.gov.br/nfce/consulta',
PB: 'www.receita.pb.gov.br/nfcehom',
PE: 'nfce.sefaz.pe.gov.br/nfce/consulta',
PI: 'www.sefaz.pi.gov.br/nfce/consulta',
PR: 'http://www.fazenda.pr.gov.br/nfce/consulta',
RJ: 'www.fazenda.rj.gov.br/nfce/consulta',
RN: 'www.set.rn.gov.br/nfce/consulta',
RO: 'www.sefin.ro.gov.br/nfce/consulta',
RR: 'www.sefaz.rr.gov.br/nfce/consulta',
RS: 'www.sefaz.rs.gov.br/nfce/consulta',
SE: 'http://www.hom.nfe.se.gov.br/nfce/consulta',
SP: 'https://www.homologacao.nfce.fazenda.sp.gov.br/consulta',
TO: 'www.sefaz.to.gov.br/nfce/consulta',
}
AC: "www.sefaznet.ac.gov.br/nfce/consulta",
AL: "www.sefaz.al.gov.br/nfce/consulta",
AM: "www.sefaz.am.gov.br/nfce/consulta",
AP: "www.sefaz.ap.gov.br/nfce/consulta",
BA: "http://hinternet.sefaz.ba.gov.br/nfce/consulta",
CE: "www.sefaz.ce.gov.br/nfce/consulta",
DF: "www.fazenda.df.gov.br/nfce/consulta",
ES: "www.sefaz.es.gov.br/nfce/consulta",
GO: "www.sefaz.go.gov.br/nfce/consulta",
MA: "www.sefaz.ma.gov.br/nfce/consulta",
MS: "www.dfe.ms.gov.br/nfce/consulta",
MT: "www.sefaz.mt.gov.br/nfce/consulta",
MG: "http://hnfce.fazenda.mg.gov.br/portalnfce",
PA: "www.sefa.pa.gov.br/nfce/consulta",
PB: "www.receita.pb.gov.br/nfcehom",
PE: "nfce.sefaz.pe.gov.br/nfce/consulta",
PI: "www.sefaz.pi.gov.br/nfce/consulta",
PR: "http://www.fazenda.pr.gov.br/nfce/consulta",
RJ: "www.fazenda.rj.gov.br/nfce/consulta",
RN: "www.set.rn.gov.br/nfce/consulta",
RO: "www.sefin.ro.gov.br/nfce/consulta",
RR: "www.sefaz.rr.gov.br/nfce/consulta",
RS: "www.sefaz.rs.gov.br/nfce/consulta",
SE: "http://www.hom.nfe.se.gov.br/nfce/consulta",
SP: "https://www.homologacao.nfce.fazenda.sp.gov.br/consulta",
TO: "www.sefaz.to.gov.br/nfce/consulta",
},
}

60
pytrustnfe/utils.py

@ -9,26 +9,25 @@ import lxml.etree as ET
class ChaveNFe(object):
def __init__(self, **kwargs):
self.cnpj = kwargs.pop('cnpj', '')
self.estado = kwargs.pop('estado', '')
self.emissao = kwargs.pop('emissao', '')
self.modelo = kwargs.pop('modelo', '')
self.serie = kwargs.pop('serie', '')
self.numero = kwargs.pop('numero', '')
self.tipo = kwargs.pop('tipo', '')
self.codigo = kwargs.pop('codigo', '')
self.cnpj = kwargs.pop("cnpj", "")
self.estado = kwargs.pop("estado", "")
self.emissao = kwargs.pop("emissao", "")
self.modelo = kwargs.pop("modelo", "")
self.serie = kwargs.pop("serie", "")
self.numero = kwargs.pop("numero", "")
self.tipo = kwargs.pop("tipo", "")
self.codigo = kwargs.pop("codigo", "")
def validar(self):
assert self.cnpj != '', 'CNPJ necessário para criar chave NF-e'
assert self.estado != '', 'Estado necessário para criar chave NF-e'
assert self.emissao != '', 'Emissão necessário para criar chave NF-e'
assert self.modelo != '', 'Modelo necessário para criar chave NF-e'
assert self.serie != '', 'Série necessária para criar chave NF-e'
assert self.numero != '', 'Número necessário para criar chave NF-e'
assert self.tipo != '', 'Tipo necessário para criar chave NF-e'
assert self.codigo != '', 'Código necessário para criar chave NF-e'
assert self.cnpj != "", "CNPJ necessário para criar chave NF-e"
assert self.estado != "", "Estado necessário para criar chave NF-e"
assert self.emissao != "", "Emissão necessário para criar chave NF-e"
assert self.modelo != "", "Modelo necessário para criar chave NF-e"
assert self.serie != "", "Série necessária para criar chave NF-e"
assert self.numero != "", "Número necessário para criar chave NF-e"
assert self.tipo != "", "Tipo necessário para criar chave NF-e"
assert self.codigo != "", "Código necessário para criar chave NF-e"
def date_tostring(data):
@ -45,11 +44,16 @@ def gerar_chave(obj_chave, prefix=None):
assert isinstance(obj_chave, ChaveNFe), "Objeto deve ser do tipo ChaveNFe"
obj_chave.validar()
chave_parcial = "%s%s%s%s%s%s%d%s" % (
obj_chave.estado, obj_chave.emissao,
obj_chave.cnpj, obj_chave.modelo,
obj_chave.serie.zfill(3), str(obj_chave.numero).zfill(9),
obj_chave.tipo, obj_chave.codigo)
chave_parcial = re.sub('[^0-9]', '', chave_parcial)
obj_chave.estado,
obj_chave.emissao,
obj_chave.cnpj,
obj_chave.modelo,
obj_chave.serie.zfill(3),
str(obj_chave.numero).zfill(9),
obj_chave.tipo,
obj_chave.codigo,
)
chave_parcial = re.sub("[^0-9]", "", chave_parcial)
soma = 0
contador = 2
for c in reversed(chave_parcial):
@ -75,16 +79,16 @@ def _find_node(xml, node):
def gerar_nfeproc(envio, recibo):
NSMAP = {None: 'http://www.portalfiscal.inf.br/nfe'}
NSMAP = {None: "http://www.portalfiscal.inf.br/nfe"}
root = ET.Element("nfeProc", versao="4.00", nsmap=NSMAP)
parser = ET.XMLParser(encoding='utf-8')
docEnvio = ET.fromstring(envio.encode('utf-8'), parser=parser)
docRecibo = ET.fromstring(recibo.encode('utf-8'), parser=parser)
parser = ET.XMLParser(encoding="utf-8")
docEnvio = ET.fromstring(envio.encode("utf-8"), parser=parser)
docRecibo = ET.fromstring(recibo.encode("utf-8"), parser=parser)
nfe = _find_node(docEnvio, "NFe")
protocolo = _find_node(docRecibo, "protNFe")
if nfe is None or protocolo is None:
return b''
return b""
root.append(nfe)
root.append(protocolo)
return ET.tostring(root)
@ -96,6 +100,6 @@ def gerar_nfeproc_cancel(nfe_proc, cancelamento):
ev_cancelamento = _find_node(docCancel, "retEvento")
if ev_cancelamento is None:
return b''
return b""
docEnvio.append(ev_cancelamento)
return ET.tostring(docEnvio)

20
pytrustnfe/xml/__init__.py

@ -17,8 +17,7 @@ def recursively_empty(e):
def render_xml(path, template_name, remove_empty, **nfe):
nfe = recursively_normalize(nfe)
env = Environment(
loader=FileSystemLoader(path), extensions=['jinja2.ext.with_'])
env = Environment(loader=FileSystemLoader(path), extensions=["jinja2.ext.with_"])
env.filters["normalize"] = filters.strip_line_feed
env.filters["normalize_str"] = filters.normalize_str
env.filters["format_percent"] = filters.format_percent
@ -27,9 +26,10 @@ def render_xml(path, template_name, remove_empty, **nfe):
env.filters["comma"] = filters.format_with_comma
template = env.get_template(template_name)
xml = template.render(**nfe).replace('\n', '')
parser = etree.XMLParser(remove_blank_text=True, remove_comments=True,
strip_cdata=False)
xml = template.render(**nfe).replace("\n", "")
parser = etree.XMLParser(
remove_blank_text=True, remove_comments=True, strip_cdata=False
)
root = etree.fromstring(xml, parser=parser)
for element in root.iter("*"): # remove espaços em branco
if element.text is not None and not element.text.strip():
@ -45,15 +45,15 @@ def render_xml(path, template_name, remove_empty, **nfe):
def sanitize_response(response):
parser = etree.XMLParser(encoding='utf-8')
tree = etree.fromstring(response.encode('UTF-8'), parser=parser)
parser = etree.XMLParser(encoding="utf-8")
tree = etree.fromstring(response.encode("UTF-8"), parser=parser)
# Remove namespaces inuteis na resposta
for elem in tree.getiterator():
if not hasattr(elem.tag, 'find'):
if not hasattr(elem.tag, "find"):
continue
i = elem.tag.find('}')
i = elem.tag.find("}")
if i >= 0:
elem.tag = elem.tag[i + 1:]
elem.tag = elem.tag[i + 1 :]
objectify.deannotate(tree, cleanup_namespaces=True)
return response, objectify.fromstring(etree.tostring(tree))

27
pytrustnfe/xml/filters.py

@ -14,23 +14,24 @@ def normalize_str(string):
"""
if string:
if not isinstance(string, str):
string = str(string, 'utf-8', 'replace')
string = str(string, "utf-8", "replace")
string = string.encode('utf-8')
return normalize(
'NFKD', string.decode('utf-8')).encode('ASCII', 'ignore').decode()
return ''
string = string.encode("utf-8")
return (
normalize("NFKD", string.decode("utf-8")).encode("ASCII", "ignore").decode()
)
return ""
def strip_line_feed(string):
if string:
if not isinstance(string, str):
string = str(string, 'utf-8', 'replace')
string = str(string, "utf-8", "replace")
remap = {
ord('\t'): ' ',
ord('\n'): ' ',
ord('\f'): ' ',
ord('\r'): None, # Delete
ord("\t"): " ",
ord("\n"): " ",
ord("\f"): " ",
ord("\r"): None, # Delete
}
return string.translate(remap).strip()
return string
@ -45,7 +46,7 @@ def format_datetime(value):
"""
Format datetime
"""
dt_format = '%Y-%m-%dT%H:%M:%I'
dt_format = "%Y-%m-%dT%H:%M:%I"
if isinstance(value, datetime):
return value.strftime(dt_format)
return value
@ -55,7 +56,7 @@ def format_date(value):
"""
Format date
"""
dt_format = '%Y-%m-%d'
dt_format = "%Y-%m-%d"
if isinstance(value, date):
return value.strftime(dt_format)
return value
@ -63,5 +64,5 @@ def format_date(value):
def format_with_comma(value):
if isinstance(value, float):
return ('%.2f' % value).replace('.', ',')
return ("%.2f" % value).replace(".", ",")
return value

4
pytrustnfe/xml/validate.py

@ -7,8 +7,8 @@ import os
from lxml import etree
PATH = os.path.dirname(os.path.abspath(__file__))
SCHEMA = os.path.join(PATH, 'schemas/enviNFe_v4.00.xsd')
SCHEMA_DFE = os.path.join(PATH, 'schemas/distDFeInt_v1.01.xsd')
SCHEMA = os.path.join(PATH, "schemas/enviNFe_v4.00.xsd")
SCHEMA_DFE = os.path.join(PATH, "schemas/distDFeInt_v1.01.xsd")
def valida_nfe(xml_nfe, schema=SCHEMA):

4
requirements-dev.txt

@ -0,0 +1,4 @@
pytest==5.3.4
pytest-cov==2.8.1
black==19.10b0
flake8==3.7.9

96
setup.py

@ -9,56 +9,56 @@ setup(
name="PyTrustNFe3",
version=VERSION,
author="Danimar Ribeiro",
author_email='danimaribeiro@gmail.com',
keywords=['nfe', 'mdf-e'],
author_email="danimaribeiro@gmail.com",
keywords=["nfe", "mdf-e"],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Plugins',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU Lesser General Public License v2 or \
later (LGPLv2+)',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.4',
'Topic :: Software Development :: Libraries :: Python Modules',
"Development Status :: 5 - Production/Stable",
"Environment :: Plugins",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v2 or \
later (LGPLv2+)",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.4",
"Topic :: Software Development :: Libraries :: Python Modules",
],
packages=find_packages(exclude=['*test*']),
package_data={'pytrustnfe': [
'nfe/templates/*xml',
'nfe/fonts/*ttf',
'nfse/paulistana/templates/*xml',
'nfse/dsf/templates/*xml',
'nfse/ginfes/templates/*xml',
'nfse/simpliss/templates/*xml',
'nfse/betha/templates/*xml',
'nfse/susesu/templates/*xml',
'nfse/imperial/templates/*xml',
'nfse/floripa/templates/*xml',
'nfse/carioca/templates/*xml',
'nfse/bh/templates/*xml',
'nfse/mga/templates/*xml',
'nfse/aparecida/templates/*xml',
'xml/schemas/*xsd',
]},
url='https://github.com/danimaribeiro/PyTrustNFe',
license='LGPL-v2.1+',
description='PyTrustNFe é uma biblioteca para envio de NF-e',
long_description=open('README.md', 'r').read(),
long_description_content_type='text/markdown',
packages=find_packages(exclude=["*test*"]),
package_data={
"pytrustnfe": [
"nfe/templates/*xml",
"nfe/fonts/*ttf",
"nfse/paulistana/templates/*xml",
"nfse/dsf/templates/*xml",
"nfse/ginfes/templates/*xml",
"nfse/simpliss/templates/*xml",
"nfse/betha/templates/*xml",
"nfse/susesu/templates/*xml",
"nfse/imperial/templates/*xml",
"nfse/floripa/templates/*xml",
"nfse/carioca/templates/*xml",
"nfse/bh/templates/*xml",
"nfse/mga/templates/*xml",
"nfse/aparecida/templates/*xml",
"xml/schemas/*xsd",
]
},
url="https://github.com/danimaribeiro/PyTrustNFe",
license="LGPL-v2.1+",
description="PyTrustNFe é uma biblioteca para envio de NF-e",
long_description=open("README.md", "r").read(),
long_description_content_type="text/markdown",
install_requires=[
'Jinja2 >= 2.8',
'pyOpenSSL >= 16.0.0, < 18',
'signxml >= 2.4.0',
'lxml >= 3.5.0, < 5',
'suds-jurko >= 0.6',
'suds-jurko-requests >= 1.2',
'reportlab',
'pytz',
'zeep',
],
tests_require=[
'pytest',
"Jinja2 >= 2.8",
"pyOpenSSL >= 16.0.0, < 18",
"signxml >= 2.4.0",
"lxml >= 3.5.0, < 5",
"suds-jurko >= 0.6",
"suds-jurko-requests >= 1.2",
"reportlab",
"pytz",
"zeep",
],
tests_require=["pytest",],
)

71
tests/test_assinatura.py

@ -1,9 +1,9 @@
# coding=utf-8
'''
"""
Created on Jun 14, 2015
@author: danimar
'''
"""
import os
import os.path
import unittest
@ -11,18 +11,22 @@ from lxml import etree
from pytrustnfe.nfe.assinatura import Assinatura
XML_ASSINAR = '<Envelope xmlns="urn:envelope">' \
' <Data Id="NFe43150602261542000143550010000000761792265342">'\
' Hello, World!' \
' </Data>' \
'</Envelope>'
XML_ASSINAR = (
'<Envelope xmlns="urn:envelope">'
' <Data Id="NFe43150602261542000143550010000000761792265342">'
" Hello, World!"
" </Data>"
"</Envelope>"
)
XML_ERRADO = '<Envelope xmlns="urn:envelope">' \
' <Data Id="NFe">' \
' Hello, World!' \
' </Data>' \
'</Envelope>'
XML_ERRADO = (
'<Envelope xmlns="urn:envelope">'
' <Data Id="NFe">'
" Hello, World!"
" </Data>"
"</Envelope>"
)
class test_assinatura(unittest.TestCase):
@ -30,26 +34,35 @@ 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'), 'rb').read()
signer = Assinatura(pfx, '123')
self.assertRaises(Exception, signer.assina_xml, signer,
etree.fromstring(XML_ASSINAR),
'NFe43150602261542000143550010000000761792265342')
pfx = open(os.path.join(self.caminho, "teste.pfx"), "rb").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'), 'rb').read()
signer = Assinatura(pfx, '123456')
self.assertRaises(Exception, signer.assina_xml, signer,
etree.fromstring(XML_ERRADO),
'NFe43150602261542000143550010000000761792265342')
pfx = open(os.path.join(self.caminho, "teste.pfx"), "rb").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'), 'rb').read()
signer = Assinatura(pfx, '123456')
pfx = open(os.path.join(self.caminho, "teste.pfx"), "rb").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')
"NFe43150602261542000143550010000000761792265342",
)
xml_assinado = open(
os.path.join(self.caminho, "xml_valido_assinado.xml"), "r"
).read()
self.assertEqual(xml_assinado, xml, "Xml assinado é inválido")

110
tests/test_certificado.py

@ -1,9 +1,9 @@
# coding=utf-8
'''
"""
Created on Jun 14, 2015
@author: danimar
'''
"""
import unittest
import os
import os.path
@ -11,37 +11,41 @@ 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'
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'
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):
@ -49,34 +53,34 @@ 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'), 'rb').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')
dir_pfx = open(os.path.join(self.caminho, "teste.pfx"), "rb").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'), 'rb').read()
pfx = Certificado(pfx_source, '123')
pfx_source = open(os.path.join(self.caminho, "teste.pfx"), "rb").read()
pfx = Certificado(pfx_source, "123")
path = pfx.save_pfx()
saved = open(path, 'rb').read()
self.assertEqual(pfx_source, saved,
'Arquivo pfx salvo não bate com arquivo lido')
saved = open(path, "rb").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'), 'rb').read()
cert, key = extract_cert_and_key_from_pfx(dir_pfx, '123456')
dir_pfx = open(os.path.join(self.caminho, "teste.pfx"), "rb").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')
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')
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')
dir_pfx = os.path.join(self.caminho, "teste.pfx")
self.assertRaises(Exception, extract_cert_and_key_from_pfx, dir_pfx, "123")

6
tests/test_danfe.py

@ -12,8 +12,8 @@ class test_danfe(unittest.TestCase):
caminho = os.path.dirname(__file__)
def test_can_generate_danfe(self):
path = os.path.join(os.path.dirname(__file__), 'XMLs')
xml_string = open(os.path.join(path, 'NFe00000857.xml'), "r").read()
path = os.path.join(os.path.dirname(__file__), "XMLs")
xml_string = open(os.path.join(path, "NFe00000857.xml"), "r").read()
# xml_string = open('/home/danimar/Downloads/NFe (5).xml', "r").read()
xml_element = etree.fromstring(xml_string)
@ -22,5 +22,5 @@ class test_danfe(unittest.TestCase):
# Para testar localmente o Danfe
# with open('/home/danimar/danfe.pdf', 'w') as oFile:
with tempfile.TemporaryFile(mode='wb') as oFile:
with tempfile.TemporaryFile(mode="wb") as oFile:
oDanfe.writeto_pdf(oFile)

13
tests/test_ginfes.py

@ -13,12 +13,11 @@ class test_nfse_ginfes(unittest.TestCase):
@unittest.skip
def test_consulta_situacao_lote(self):
pfx_source = open('/home/danimar/Downloads/machado.pfx', 'rb').read()
pfx = Certificado(pfx_source, '123456789')
pfx_source = open("/home/danimar/Downloads/machado.pfx", "rb").read()
pfx = Certificado(pfx_source, "123456789")
dados = {'ambiente': 'homologacao'}
retorno = consultar_situacao_lote(
pfx, consulta=dados, ambiente='homologacao')
dados = {"ambiente": "homologacao"}
retorno = consultar_situacao_lote(pfx, consulta=dados, ambiente="homologacao")
self.assertNotEqual(retorno['received_xml'], '')
self.assertEqual(retorno['object'].Cabecalho.Sucesso, True)
self.assertNotEqual(retorno["received_xml"], "")
self.assertEqual(retorno["object"].Cabecalho.Sucesso, True)

143
tests/test_nfse_paulistana.py

@ -17,127 +17,126 @@ class test_nfse_paulistana(unittest.TestCase):
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'
"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",
},
'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'
"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
"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'), 'rb').read()
pfx = Certificado(pfx_source, '123456')
pfx_source = open(os.path.join(self.caminho, "teste.pfx"), "rb").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()
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:
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)
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'), 'rb').read()
pfx = Certificado(pfx_source, '123456')
pfx_source = open(os.path.join(self.caminho, "teste.pfx"), "rb").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()
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:
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.service.EnvioLoteRPS.return_value = "<xml></xml>"
retorno = envio_lote_rps(pfx, nfse=nfse)
self.assertEqual(retorno['sent_xml'], xml_sent)
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',
"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'), 'rb').read()
pfx = Certificado(pfx_source, '123456')
pfx_source = open(os.path.join(self.caminho, "teste.pfx"), "rb").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()
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:
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)
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'), 'rb').read()
pfx = Certificado(pfx_source, '123456')
pfx_source = open(os.path.join(self.caminho, "teste.pfx"), "rb").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()
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:
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)
self.assertEqual(retorno["received_xml"], xml_return)
self.assertEqual(retorno["object"].Cabecalho.Sucesso, False)
self.assertEqual(retorno["object"].Erro.ChaveNFe.NumeroNFe, 446)

37
tests/test_servidores.py

@ -1,47 +1,46 @@
# 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/NFeAutorizacao4/NFeAutoriza\
cao4.asmx?wsdl'
url_ba = "https://nfe.sefaz.ba.gov.br/webservices/NFeAutorizacao4/NFeAutoriza\
cao4.asmx?wsdl"
url_sp = 'https://nfe.fazenda.sp.gov.br/ws/nfeautorizacao4.asmx?wsdl'
url_sp = "https://nfe.fazenda.sp.gov.br/ws/nfeautorizacao4.asmx?wsdl"
url_qrcode_homologacao_sp = 'https://homologacao.nfce.fazenda.sp.gov.br/NFCEConsultaPublica/Paginas/ConstultaQRCode.aspx'
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/NFeAutorizacao4.asmx?wsdl'
url_sc = "https://nfe.svrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao4.asmx?wsdl"
url_rs = 'https://nfe.sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao4.asmx?wsdl'
url_rs = "https://nfe.sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao4.asmx?wsdl"
url_cad_rs = 'https://cad.sefazrs.rs.gov.br/ws/cadconsultacadastro/cadconsultacadastro4.asmx?wsdl'
url_cad_rs = "https://cad.sefazrs.rs.gov.br/ws/cadconsultacadastro/cadconsultacadastro4.asmx?wsdl"
url_cad_sc = 'https://cad.svrs.rs.gov.br/ws/cadconsultacadastro/cadconsulta\
cadastro4.asmx?wsdl'
url_cad_sc = "https://cad.svrs.rs.gov.br/ws/cadconsultacadastro/cadconsulta\
cadastro4.asmx?wsdl"
class test_servidores(unittest.TestCase):
def test_localizar_url(self):
url = localizar_url('NfeAutorizacao', '29', ambiente=1)
url = localizar_url("NfeAutorizacao", "29", ambiente=1)
self.assertEqual(url, url_ba)
url = localizar_url('NfeAutorizacao', '35', ambiente=1)
url = localizar_url("NfeAutorizacao", "35", ambiente=1)
self.assertEqual(url, url_sp)
url = localizar_url('NfeAutorizacao', '42', ambiente=1)
url = localizar_url("NfeAutorizacao", "42", ambiente=1)
self.assertEqual(url, url_sc)
url = localizar_url('NfeAutorizacao', '43', ambiente=1)
url = localizar_url("NfeAutorizacao", "43", ambiente=1)
self.assertEqual(url, url_rs)
url = localizar_url('NfeConsultaCadastro', '43', ambiente=2)
url = localizar_url("NfeConsultaCadastro", "43", ambiente=2)
self.assertEqual(url, url_cad_rs)
url = localizar_url('NfeConsultaCadastro', '42', ambiente=2)
url = localizar_url("NfeConsultaCadastro", "42", ambiente=2)
self.assertEqual(url, url_cad_sc)
def test_localizar_qrcode(self):
url = localizar_qrcode('35')
url = localizar_qrcode("35")
self.assertEqual(url, url_qrcode_homologacao_sp)

134
tests/test_utils.py

@ -1,48 +1,52 @@
# 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 date_tostring, datetime_tostring, gerar_chave
from pytrustnfe.utils import ChaveNFe
class test_utils(unittest.TestCase):
kwargs = {
'cnpj': '33009911002506', 'estado': '52', 'emissao': '0604',
'modelo': '55', 'serie': '012', 'numero': 780,
'tipo': 0, 'codigo': '26730161'
"cnpj": "33009911002506",
"estado": "52",
"emissao": "0604",
"modelo": "55",
"serie": "012",
"numero": 780,
"tipo": 0,
"codigo": "26730161",
}
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.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.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")
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")
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")
@ -50,64 +54,80 @@ class test_utils(unittest.TestCase):
def test_chave_nfe(self):
chave = ChaveNFe(**self.kwargs)
with self.assertRaises(AssertionError) as cm:
chave.cnpj = ''
chave.cnpj = ""
chave.validar()
chave.cnpj = '1234567891011'
self.assertEqual('CNPJ necessário para criar chave NF-e',
str(cm.exception),
'Validação da chave nf-e incorreta')
chave.cnpj = "1234567891011"
self.assertEqual(
"CNPJ necessário para criar chave NF-e",
str(cm.exception),
"Validação da chave nf-e incorreta",
)
with self.assertRaises(AssertionError) as cm:
chave.estado = ''
chave.estado = ""
chave.validar()
chave.estado = '42'
self.assertEqual('Estado necessário para criar chave NF-e',
str(cm.exception),
'Validação da chave nf-e incorreta')
chave.estado = "42"
self.assertEqual(
"Estado necessário para criar chave NF-e",
str(cm.exception),
"Validação da chave nf-e incorreta",
)
with self.assertRaises(AssertionError) as cm:
chave.emissao = ''
chave.emissao = ""
chave.validar()
chave.emissao = '0'
self.assertEqual('Emissão necessário para criar chave NF-e',
str(cm.exception),
'Validação da chave nf-e incorreta')
chave.emissao = "0"
self.assertEqual(
"Emissão necessário para criar chave NF-e",
str(cm.exception),
"Validação da chave nf-e incorreta",
)
with self.assertRaises(AssertionError) as cm:
chave.modelo = ''
chave.modelo = ""
chave.validar()
chave.modelo = '55'
self.assertEqual('Modelo necessário para criar chave NF-e',
str(cm.exception),
'Validação da chave nf-e incorreta')
chave.modelo = "55"
self.assertEqual(
"Modelo necessário para criar chave NF-e",
str(cm.exception),
"Validação da chave nf-e incorreta",
)
with self.assertRaises(AssertionError) as cm:
chave.serie = ''
chave.serie = ""
chave.validar()
chave.serie = '012'
self.assertEqual('Série necessária para criar chave NF-e',
str(cm.exception),
'Validação da chave nf-e incorreta')
chave.serie = "012"
self.assertEqual(
"Série necessária para criar chave NF-e",
str(cm.exception),
"Validação da chave nf-e incorreta",
)
with self.assertRaises(AssertionError) as cm:
chave.numero = ''
chave.numero = ""
chave.validar()
chave.numero = '000000780'
self.assertEqual('Número necessário para criar chave NF-e',
str(cm.exception),
'Validação da chave nf-e incorreta')
chave.numero = "000000780"
self.assertEqual(
"Número necessário para criar chave NF-e",
str(cm.exception),
"Validação da chave nf-e incorreta",
)
with self.assertRaises(AssertionError) as cm:
chave.tipo = ''
chave.tipo = ""
chave.validar()
chave.tipo = '42'
self.assertEqual('Tipo necessário para criar chave NF-e',
str(cm.exception),
'Validação da chave nf-e incorreta')
chave.tipo = "42"
self.assertEqual(
"Tipo necessário para criar chave NF-e",
str(cm.exception),
"Validação da chave nf-e incorreta",
)
with self.assertRaises(AssertionError) as cm:
chave.codigo = ''
chave.codigo = ""
chave.validar()
self.assertEqual('Código necessário para criar chave NF-e',
str(cm.exception),
'Validação da chave nf-e incorreta')
self.assertEqual(
"Código necessário para criar chave NF-e",
str(cm.exception),
"Validação da chave nf-e incorreta",
)

17
tests/test_xml.py

@ -1,9 +1,9 @@
# coding=utf-8
'''
"""
Created on Jun 14, 2015
@author: danimar
'''
"""
import unittest
from datetime import datetime
from pytrustnfe.xml.filters import normalize_str
@ -14,17 +14,16 @@ from pytrustnfe.xml.filters import format_datetime
class test_xmlfilters(unittest.TestCase):
def test_xmlfilters(self):
word = normalize_str('ação café pó pá veêm')
self.assertEqual(word, 'acao cafe po pa veem')
word = normalize_str("ação café pó pá veêm")
self.assertEqual(word, "acao cafe po pa veem")
self.assertEqual(1.5, format_percent(150))
self.assertEqual('aa', format_date('aa'))
self.assertEqual('aa', format_datetime('aa'))
self.assertEqual("aa", format_date("aa"))
self.assertEqual("aa", format_datetime("aa"))
dt = datetime(2016, 9, 17, 12, 12, 12)
self.assertEqual('2016-09-17', format_date(dt.date()))
self.assertEqual('2016-09-17T12:12:12', format_datetime(dt))
self.assertEqual("2016-09-17", format_date(dt.date()))
self.assertEqual("2016-09-17T12:12:12", format_datetime(dt))
word = strip_line_feed("olá\ncomo vai\r senhor ")
self.assertEqual(word, "olá como vai senhor")

33
tests/test_xml_serializacao.py

@ -8,29 +8,30 @@ 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')
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()
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')
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, encoding=str)
result = open(os.path.join(path, 'jinja_remove_empty.xml'), 'r').read()
self.assertEqual(xml + '\n', result)
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()
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')
self.assertEqual(obj.tpAmb, "oi")
self.assertEqual(obj.CNPJ, "ola")
self.assertEqual(obj.indNFe, "")
self.assertEqual(obj.indEmi, "comovai")
Loading…
Cancel
Save