diff --git a/.travis.yml b/.travis.yml index c3e7bbd8..383a0163 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: python python: -- "3.6" +- "3.8" install: - pip install --upgrade pip - pip install -r requirements.txt diff --git a/pytrustnfe/certificado.py b/pytrustnfe/certificado.py index d6aab080..b2b424bf 100644 --- a/pytrustnfe/certificado.py +++ b/pytrustnfe/certificado.py @@ -4,13 +4,24 @@ import tempfile from OpenSSL import crypto +#import datetime +from datetime import datetime +#temp +import ssl class Certificado(object): def __init__(self, pfx, password): self.pfx = pfx self.password = password + pfx = crypto.load_pkcs12(pfx, password).get_certificate() + cert_date = int(str(pfx.get_notAfter(),'UTF-8').strip('Z')) + now = datetime.now() + date = int(now.strftime("%Y%m%d%H%M%S")) + if cert_date < date: + print("WARNING: Certificado expirado") + def save_pfx(self): pfx_temp = tempfile.mkstemp()[1] arq_temp = open(pfx_temp, "wb") @@ -20,7 +31,11 @@ def save_pfx(self): def extract_cert_and_key_from_pfx(pfx, password): - pfx = crypto.load_pkcs12(pfx, password) + try: + pfx = crypto.load_pkcs12(pfx, password) + except: + print("ERROR: Falha ao ler certiticado. Verifique a senha") + exit() # PEM formatted private key key = crypto.dump_privatekey(crypto.FILETYPE_PEM, pfx.get_privatekey()) # PEM formatted certificate diff --git a/pytrustnfe/client.py b/pytrustnfe/client.py index 2d481a23..43359cc5 100644 --- a/pytrustnfe/client.py +++ b/pytrustnfe/client.py @@ -12,7 +12,13 @@ def get_authenticated_client(base_url, cert, key): cache = suds.cache.DocumentCache(location=cache_location) session = requests.Session() - session.cert = (cert, key) + session.cert = (cert, key) + + # Testa sessao https + r = requests.get(base_url, cert=(cert, key)) + if r.status_code == 403: + print("ERROR: Falha na conexão utilizando o certificado digital e senha infomados. Verifique a validade do certificado") + exit() return suds.client.Client( base_url, cache=cache, transport=suds_requests.RequestsTransport(session) ) diff --git a/requirements.txt b/requirements.txt index 7f8336f8..99bda095 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,14 @@ -lxml >= 3.5.0, < 5 +lxml >= 4.2.1, < 5 coveralls Jinja2 signxml urllib3 >= 1.22 -suds-jurko >= 0.6 -suds-jurko-requests >= 1.2 +suds-community +suds-requests4 defusedxml >= 0.7.1, < 1 eight >= 0.3.0, < 1 -cryptography >= 1.8, < 3 -pyOpenSSL >= 16.0.0, < 18 +cryptography >= 2.1.4, < 3 +pyOpenSSL == 22.1.0 certifi >= 2015.11.20.1 xmlsec >= 1.3.3 reportlab diff --git a/setup.py b/setup.py index 19f52c6a..e9e1ab40 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages -VERSION = "1.0.61" +VERSION = "1.0.62" setup( @@ -53,11 +53,11 @@ 'urllib3 >= 1.22', 'xmlsec >= 1.3.3', # apt update;apt install libxmlsec1-dev pkg-config -y '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', + 'lxml >= 4.2.1, < 5', + 'cryptography >= 2.1.4', + 'pyOpenSSL == 22.1.0', + 'suds', + 'suds-requests4', 'reportlab', 'pytz', 'zeep', diff --git a/teste_carioca.py b/teste_carioca.py new file mode 100644 index 00000000..b874fb14 --- /dev/null +++ b/teste_carioca.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- + +import logging +from datetime import datetime +from pytrustnfe.nfe import consulta_cadastro +#import pytrustnfe.nfe +from pytrustnfe.certificado import Certificado +from pytrustnfe.nfse.paulistana import cancelamento_nfe +from pytrustnfe.nfse.paulistana import envio_lote_rps +from pytrustnfe.nfse.carioca import gerar_nfse + + +logger = logging.getLogger(__name__) +dbg = 0 + + +#certificado_path = open(b'/data/certs/23834691000124.pfx', 'rb').read() +certificado_path = open(b'/data/certs/expirado.pfx', 'rb').read() +certificado = Certificado(certificado_path, 'audaz$321') + +if dbg>1 :print('type(certificado)') +if dbg>1 :print(type(certificado)) +if dbg>9 :print(certificado.pfx) +if dbg>1 :print(certificado.password) +# Necessário criar um dicionário com os dados, validação dos dados deve +# ser feita pela aplicação que está utilizando a lib + +#retorno = envio_lote_rps(certificado, nfse=nfse) +#retorno = gerar_nfse(certificado, nfse=rps) + +#xml = { "rps" : {"rps" : { "numero" : "1" }}} +#retorno = gerar_nfse(certificado, nfse=xml) + +rps = { + 'ambiente': '2', + 'rps': { + 'ambiente': '2', + 'numero': '1', + 'serie': 'ABC', + 'tipo_rps': '1', + 'data_emissao': '2010-01-01T21:00:00', + 'natureza_operacao': '1', + 'optante_simples': '1', + 'incentivador_cultural': '2', + 'status': '1', + #'regime_tributacao': '', + #'numero_substituido': '', + '#serie_substituido': '', + '#tipo_substituido': '', + 'valor_servico': '9.99', + 'valor_deducao': '0', + 'valor_pis': '0', + 'valor_cofins': '0', + 'valor_inss': '0', + 'valor_ir': '0', + 'valor_csll': '0', + 'iss_retido': '0', + 'valor_iss': '0', + 'valor_iss_retido': '0', + 'outras_retencoes': '0', + 'base_calculo': '9.99', + 'aliquota_issqn': '0.05', + 'valor_liquido_nfse': '9.99', + 'desconto_incondicionado': '', + 'desconto_condicionado': '', + 'codigo_servico': '0107', + 'cnae_servico': '', + 'codigo_tributacao_municipio': '010701', + 'codigo_municipio': '3304557', + 'descricao': 'Venda de servico', + 'prestador': { + 'cnpj': '123456789011213', + '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', + 'complemento': '', + 'bairro': 'Corrego', + 'cidade': '4205407', # Código da cidade, de acordo com o IBGE + 'uf': 'SC', + 'cep': '88037240', + 'tomador.telefone': '', + 'tomador.email': '' + }, + } +} + + +retorno = gerar_nfse(certificado, **rps) + + + + +# retorno é um dicionário { 'received_xml':'', 'sent_xml':'', 'object': object() } +if dbg>=9 :print(retorno['sent_xml']) +if dbg>=1 :print(retorno['received_xml']) + +# retorno['object'] é um objeto python criado apartir do xml de resposta +if dbg>=9 :print(retorno['object']) +#print retorno['object'].Cabecalho.Sucesso +#print retorno['object'].ChaveNFeRPS.ChaveNFe.NumeroNFe +#print retorno['object'].ChaveNFeRPS.ChaveRPS.NumeroRPS