Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
f964e4120b | |
![]() |
910cd0bedb |
|
@ -1,5 +1,10 @@
|
||||||
# Lista de cambios
|
# Lista de cambios
|
||||||
|
|
||||||
|
## v 1.0.0 [00-abr-24]
|
||||||
|
---
|
||||||
|
* Se refactoriza la descarga
|
||||||
|
|
||||||
|
|
||||||
## v 0.6.0 [27-Mar-22]
|
## v 0.6.0 [27-Mar-22]
|
||||||
---
|
---
|
||||||
* Fix - Cambios del SAT
|
* Fix - Cambios del SAT
|
||||||
|
|
Binary file not shown.
|
@ -1,4 +1,3 @@
|
||||||
httpx
|
cryptography==42.0.5
|
||||||
peewee
|
requests
|
||||||
cryptography==3.4.8
|
|
||||||
lxml
|
lxml
|
|
@ -1,86 +1,93 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from sat import util
|
from util import app
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
if args.fiel_validar:
|
|
||||||
util.fiel_validar(args)
|
if args.descarga_web:
|
||||||
|
app.download_web(args)
|
||||||
return
|
return
|
||||||
|
|
||||||
if args.solicitar_descarga:
|
# ~ if args.fiel_validar:
|
||||||
util.solicitar_descarga(args)
|
# ~ util.fiel_validar(args)
|
||||||
return
|
# ~ return
|
||||||
|
|
||||||
if args.verificar_descarga:
|
# ~ if args.solicitar_descarga:
|
||||||
util.verificar_descarga(args)
|
# ~ util.solicitar_descarga(args)
|
||||||
return
|
# ~ return
|
||||||
|
|
||||||
if args.descargar_archivos:
|
# ~ if args.verificar_descarga:
|
||||||
util.descargar_archivos(args)
|
# ~ util.verificar_descarga(args)
|
||||||
return
|
# ~ return
|
||||||
|
|
||||||
util.descargar(args)
|
# ~ if args.descargar_archivos:
|
||||||
|
# ~ util.descargar_archivos(args)
|
||||||
|
# ~ return
|
||||||
|
|
||||||
|
# ~ util.descargar(args)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def _process_command_line_arguments():
|
def _process_command_line_arguments():
|
||||||
now = util.today()
|
|
||||||
year = now.year
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='CFDI Descarga SAT')
|
parser = argparse.ArgumentParser(description='CFDI Descarga SAT')
|
||||||
|
|
||||||
help = 'Valida la FIEL'
|
# ~ help = 'Valida la FIEL'
|
||||||
parser.add_argument('-fv', '--fiel-validar', help=help,
|
# ~ parser.add_argument('-fv', '--fiel-validar', help=help,
|
||||||
|
# ~ action='store_true', default=False, required=False)
|
||||||
|
|
||||||
|
# ~ help = "Descargar por Tipo: t=todos(default), e=emitidas, r=recibidas"
|
||||||
|
# ~ parser.add_argument('-t', '--tipo', help=help,
|
||||||
|
# ~ dest='type', default='t', choices=['t', 'e', 'r'])
|
||||||
|
# ~ help = "Año de la descarga entre 2014 y el año actual (predeterminado)."
|
||||||
|
# ~ parser.add_argument('-a', '--año', help=help,
|
||||||
|
# ~ dest='year', default=year, type=int, choices=range(2014, year+1))
|
||||||
|
# ~ help = "Mes de la descarga, el mes actual es el predeterminado"
|
||||||
|
# ~ parser.add_argument('-m', '--mes', help=help,
|
||||||
|
# ~ dest='month', default=0, type=int, choices=range(13))
|
||||||
|
# ~ help = "Día de la descarga, de forma predeterminada no se usa"
|
||||||
|
# ~ parser.add_argument('-d', '--dia', help=help,
|
||||||
|
# ~ dest='day', default=0, type=int, choices=range(31))
|
||||||
|
# ~ help = "Intervalo de días a partir de la fecha actual y hacia a atras"
|
||||||
|
# ~ parser.add_argument('-ud', '--ultimos-dias', help=help,
|
||||||
|
# ~ dest='last_days', default=0, type=int, choices=range(30))
|
||||||
|
# ~ help = "Fecha inicial AAAA-MM-DD"
|
||||||
|
# ~ parser.add_argument('-fi', '--fecha-inicial', help=help,
|
||||||
|
# ~ dest='date_start', default='')
|
||||||
|
# ~ help = "Fecha final AAAA-MM-DD"
|
||||||
|
# ~ parser.add_argument('-ff', '--fecha-final', help=help,
|
||||||
|
# ~ dest='date_end', default='')
|
||||||
|
|
||||||
|
# ~ help = 'Solicitar descarga'
|
||||||
|
# ~ parser.add_argument('-sd', '--solicitar-descarga', help=help,
|
||||||
|
# ~ action='store_true', default=False, required=False)
|
||||||
|
# ~ help = 'Verificar estatus de descarga'
|
||||||
|
# ~ parser.add_argument('-vd', '--verificar-descarga', help=help,
|
||||||
|
# ~ action='store_true', default=False, required=False)
|
||||||
|
# ~ help = 'Descargar archivos'
|
||||||
|
# ~ parser.add_argument('-da', '--descargar-archivos', help=help,
|
||||||
|
# ~ action='store_true', default=False, required=False)
|
||||||
|
# ~ help = 'ID de solicitud'
|
||||||
|
# ~ parser.add_argument('-id', '--id-solicitud', dest='id_request',
|
||||||
|
# ~ help=help, default='')
|
||||||
|
# ~ help = 'ID archivo'
|
||||||
|
# ~ parser.add_argument('-ida', '--id-archivo', dest='id_file',
|
||||||
|
# ~ help=help, default='')
|
||||||
|
# ~ help = 'Ruta de descarga de archivos'
|
||||||
|
# ~ parser.add_argument('-dd', '--directorio-descargas', dest='path_download',
|
||||||
|
# ~ help=help, default='')
|
||||||
|
|
||||||
|
help = 'Descargar de la página web'
|
||||||
|
parser.add_argument('-dw', '--descarga-web', help=help,
|
||||||
action='store_true', default=False, required=False)
|
action='store_true', default=False, required=False)
|
||||||
|
|
||||||
help = 'Ruta al directorio con la FIEL'
|
help = 'Ruta al directorio con la FIEL'
|
||||||
parser.add_argument('-fd', '--fiel-dir', help=help, default='')
|
parser.add_argument('-fd', '--fiel-directorio', help=help, default='')
|
||||||
help = "Nombre de los archivos FIEL, el predeterminado es 'fiel'"
|
help = "Nombre de los archivos FIEL, el predeterminado es 'fiel'"
|
||||||
parser.add_argument('-fn', '--fiel-nombre', help=help, default='fiel')
|
parser.add_argument('-fn', '--fiel-nombre', help=help, default='fiel')
|
||||||
|
|
||||||
help = "Descargar por Tipo: t=todos(default), e=emitidas, r=recibidas"
|
|
||||||
parser.add_argument('-t', '--tipo', help=help,
|
|
||||||
dest='type', default='t', choices=['t', 'e', 'r'])
|
|
||||||
help = "Año de la descarga entre 2014 y el año actual (predeterminado)."
|
|
||||||
parser.add_argument('-a', '--año', help=help,
|
|
||||||
dest='year', default=year, type=int, choices=range(2014, year+1))
|
|
||||||
help = "Mes de la descarga, el mes actual es el predeterminado"
|
|
||||||
parser.add_argument('-m', '--mes', help=help,
|
|
||||||
dest='month', default=0, type=int, choices=range(13))
|
|
||||||
help = "Día de la descarga, de forma predeterminada no se usa"
|
|
||||||
parser.add_argument('-d', '--dia', help=help,
|
|
||||||
dest='day', default=0, type=int, choices=range(31))
|
|
||||||
help = "Intervalo de días a partir de la fecha actual y hacia a atras"
|
|
||||||
parser.add_argument('-ud', '--ultimos-dias', help=help,
|
|
||||||
dest='last_days', default=0, type=int, choices=range(30))
|
|
||||||
help = "Fecha inicial AAAA-MM-DD"
|
|
||||||
parser.add_argument('-fi', '--fecha-inicial', help=help,
|
|
||||||
dest='date_start', default='')
|
|
||||||
help = "Fecha final AAAA-MM-DD"
|
|
||||||
parser.add_argument('-ff', '--fecha-final', help=help,
|
|
||||||
dest='date_end', default='')
|
|
||||||
|
|
||||||
help = 'Solicitar descarga'
|
|
||||||
parser.add_argument('-sd', '--solicitar-descarga', help=help,
|
|
||||||
action='store_true', default=False, required=False)
|
|
||||||
help = 'Verificar estatus de descarga'
|
|
||||||
parser.add_argument('-vd', '--verificar-descarga', help=help,
|
|
||||||
action='store_true', default=False, required=False)
|
|
||||||
help = 'Descargar archivos'
|
|
||||||
parser.add_argument('-da', '--descargar-archivos', help=help,
|
|
||||||
action='store_true', default=False, required=False)
|
|
||||||
help = 'ID de solicitud'
|
|
||||||
parser.add_argument('-id', '--id-solicitud', dest='id_request',
|
|
||||||
help=help, default='')
|
|
||||||
help = 'ID archivo'
|
|
||||||
parser.add_argument('-ida', '--id-archivo', dest='id_file',
|
|
||||||
help=help, default='')
|
|
||||||
help = 'Ruta de descarga de archivos'
|
|
||||||
parser.add_argument('-dd', '--directorio-descargas', dest='path_download',
|
|
||||||
help=help, default='')
|
|
||||||
|
|
||||||
help = 'Descargar solo metadatos'
|
help = 'Descargar solo metadatos'
|
||||||
parser.add_argument('-md', '--metadata', help=help,
|
parser.add_argument('-md', '--metadata', help=help,
|
||||||
action='store_true', default=False, required=False)
|
action='store_true', default=False, required=False)
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
DEBUG = False
|
|
||||||
|
|
||||||
# ~ Este valor se usa para cifrar la FIEL
|
|
||||||
# ~ Si la cambias en producción, debes de validar de nuevo las FIELs
|
|
||||||
TOKEN = ''
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from conf import DEBUG
|
|
||||||
|
|
||||||
|
|
||||||
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
|
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
|
||||||
|
@ -12,3 +11,5 @@ logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m')
|
||||||
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE)
|
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE)
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
TIMEOUT = 60
|
|
@ -0,0 +1,71 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from .sat import SATPortal
|
||||||
|
from .cfdi_cert import CertSign
|
||||||
|
from settings import log
|
||||||
|
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
def is_dir(path):
|
||||||
|
return Path(path).is_dir()
|
||||||
|
|
||||||
|
|
||||||
|
def join(*paths):
|
||||||
|
return Path(paths[0]).joinpath(*paths[1:])
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_fiel_args(args):
|
||||||
|
fiel_path = args.fiel_directorio
|
||||||
|
fiel_name = args.fiel_nombre
|
||||||
|
|
||||||
|
if not fiel_path:
|
||||||
|
msg = 'El directorio con la FIEL es requerido'
|
||||||
|
log.error(msg)
|
||||||
|
return False, {}
|
||||||
|
|
||||||
|
if not is_dir(fiel_path):
|
||||||
|
msg = f'La ruta no existe o no es un directorio. \nRuta: {fiel_path}'
|
||||||
|
log.error(msg)
|
||||||
|
return False, {}
|
||||||
|
|
||||||
|
path_cer = join(fiel_path, f'{fiel_name}.cer')
|
||||||
|
path_key = join(fiel_path, f'{fiel_name}.key')
|
||||||
|
path_enc = join(fiel_path, f'{fiel_name}.enc')
|
||||||
|
path_pem = join(fiel_path, f'{fiel_name}.pem')
|
||||||
|
|
||||||
|
if not path_cer.is_file():
|
||||||
|
msg = f'No se encontró el archivo CER. \nRuta: {path_cer}'
|
||||||
|
log.error(msg)
|
||||||
|
return False, {}
|
||||||
|
|
||||||
|
if not path_key.is_file():
|
||||||
|
msg = f'No se encontró el archivo KEY. \nRuta: {path_key}'
|
||||||
|
log.error(msg)
|
||||||
|
return False, {}
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'cer': path_cer.read_bytes(),
|
||||||
|
'key': path_key.read_bytes(),
|
||||||
|
# ~ 'enc': path_enc.read_bytes(),
|
||||||
|
'pem': path_pem.read_bytes(),
|
||||||
|
}
|
||||||
|
return True, data
|
||||||
|
|
||||||
|
|
||||||
|
def download_web(args):
|
||||||
|
# ~ print(args)
|
||||||
|
result, files = _validate_fiel_args(args)
|
||||||
|
if not result:
|
||||||
|
return
|
||||||
|
|
||||||
|
fiel = CertSign(files['pem'])
|
||||||
|
fiel.get_data_cer(files['cer'])
|
||||||
|
|
||||||
|
sat = SATPortal()
|
||||||
|
if sat.login(fiel):
|
||||||
|
sleep(3)
|
||||||
|
sat.logout()
|
||||||
|
|
||||||
|
return
|
|
@ -0,0 +1 @@
|
||||||
|
/home/elmau/Projects/cfdi/cfdi-cert/source/cfdi_cert.py
|
|
@ -0,0 +1,219 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# ~ import niquests
|
||||||
|
import base64
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from requests import Session, exceptions
|
||||||
|
from requests.adapters import HTTPAdapter
|
||||||
|
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
|
||||||
|
from urllib3 import PoolManager
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
from settings import TIMEOUT, log
|
||||||
|
|
||||||
|
|
||||||
|
requests.packages.urllib3.disable_warnings()
|
||||||
|
|
||||||
|
|
||||||
|
class CipherAdapter(HTTPAdapter):
|
||||||
|
def init_poolmanager(self, connections, maxsize, block=False):
|
||||||
|
ctx = create_urllib3_context(ciphers=":HIGH:!DH:!aNULL")
|
||||||
|
self.poolmanager = PoolManager(
|
||||||
|
num_pools=connections, maxsize=maxsize, block=block, ssl_context=ctx)
|
||||||
|
|
||||||
|
|
||||||
|
class SATPortal(object):
|
||||||
|
BROWSER = 'Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0'
|
||||||
|
HOST = 'cfdiau.sat.gob.mx'
|
||||||
|
REFERER = 'https://cfdiau.sat.gob.mx/nidp/app/login?id=SATUPCFDiCon&sid=0&option=credential&sid=0'
|
||||||
|
URL = {
|
||||||
|
'MAIN': 'https://portalcfdi.facturaelectronica.sat.gob.mx/',
|
||||||
|
'PORTAL': 'https://portalcfdi.facturaelectronica.sat.gob.mx/',
|
||||||
|
}
|
||||||
|
URL['LOGOUT'] = f"{URL['PORTAL']}logout.aspx?salir=y"
|
||||||
|
URL['CONSULTA'] = f"{URL['PORTAL']}Consulta.aspx"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
# ~ self._s = niquests.Session()
|
||||||
|
self._s = Session()
|
||||||
|
self._s.mount('https://', CipherAdapter())
|
||||||
|
|
||||||
|
def _add_headers(self, headers):
|
||||||
|
for k, v in headers.items():
|
||||||
|
self._s.headers[k] = v
|
||||||
|
return
|
||||||
|
|
||||||
|
def _get(self, url):
|
||||||
|
# ~ log.debug('URL: {}'.format(url))
|
||||||
|
try:
|
||||||
|
result = self._s.get(url, timeout=TIMEOUT)
|
||||||
|
if result.status_code != 200:
|
||||||
|
msg = f'Code: {result.status_code}. URL: {url}'
|
||||||
|
log.error(msg)
|
||||||
|
return ''
|
||||||
|
except exceptions.Timeout:
|
||||||
|
msg = 'Tiempo de espera agotado'
|
||||||
|
self.not_network = True
|
||||||
|
log.error(msg)
|
||||||
|
self.error = msg
|
||||||
|
return ''
|
||||||
|
except exceptions.ConnectionError:
|
||||||
|
msg = 'Revisa la conexión a Internet'
|
||||||
|
self.not_network = True
|
||||||
|
log.error(msg)
|
||||||
|
self.error = msg
|
||||||
|
return ''
|
||||||
|
|
||||||
|
return result.text
|
||||||
|
|
||||||
|
def _post(self, url, data={}):
|
||||||
|
# ~ log.debug('URL: {}'.format(url))
|
||||||
|
try:
|
||||||
|
result = self._s.post(url, data=data, timeout=TIMEOUT)
|
||||||
|
if result.status_code != 200:
|
||||||
|
msg = f'Code: {result.status_code}. URL: {url}'
|
||||||
|
log.error(msg)
|
||||||
|
return ''
|
||||||
|
except exceptions.Timeout:
|
||||||
|
msg = 'Tiempo de espera agotado'
|
||||||
|
self.not_network = True
|
||||||
|
log.error(msg)
|
||||||
|
self.error = msg
|
||||||
|
return ''
|
||||||
|
except exceptions.ConnectionError:
|
||||||
|
msg = 'Revisa la conexión a Internet'
|
||||||
|
self.not_network = True
|
||||||
|
log.error(msg)
|
||||||
|
self.error = msg
|
||||||
|
return ''
|
||||||
|
|
||||||
|
return result.text
|
||||||
|
|
||||||
|
def _read_form(self, html, login=False):
|
||||||
|
values = {}
|
||||||
|
parser = etree.HTMLParser()
|
||||||
|
tree = etree.fromstring(html, parser)
|
||||||
|
|
||||||
|
if login:
|
||||||
|
for node in tree.xpath('//input'):
|
||||||
|
try:
|
||||||
|
values[node.attrib['id']] = node.attrib['value']
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
for node in tree.xpath('//input | //select'):
|
||||||
|
a = node.attrib
|
||||||
|
if a.get('type', '') and a['type'] == 'hidden':
|
||||||
|
if 'name' in a and 'value' in a:
|
||||||
|
values[a['name']] = a['value']
|
||||||
|
|
||||||
|
return values
|
||||||
|
|
||||||
|
def _get_headers(self, host, referer, ajax=False):
|
||||||
|
acept = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
||||||
|
headers = {
|
||||||
|
'Accept': acept,
|
||||||
|
'Accept-Encoding': 'gzip, deflate, br',
|
||||||
|
'Accept-Language': 'en-US,en;q=0.5',
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'DNT': '1',
|
||||||
|
'Host': host,
|
||||||
|
'Referer': referer,
|
||||||
|
'Upgrade-Insecure-Requests': '1',
|
||||||
|
'User-Agent': self.BROWSER,
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
}
|
||||||
|
if ajax:
|
||||||
|
headers.update({
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
'X-MicrosoftAjax': 'Delta=true',
|
||||||
|
'x-requested-with': 'XMLHttpRequest',
|
||||||
|
'Pragma': 'no-cache',
|
||||||
|
})
|
||||||
|
return headers
|
||||||
|
|
||||||
|
def _get_token(self, firma, co):
|
||||||
|
co = base64.b64encode(co.encode('utf-8')).decode('utf-8')
|
||||||
|
data = f'{co}#{firma}'.encode('utf-8')
|
||||||
|
token = base64.b64encode(data).decode('utf-8')
|
||||||
|
return token
|
||||||
|
|
||||||
|
def _sign(self, values, fiel):
|
||||||
|
fert = f'{fiel.cer.not_after:%y%m%d%H%M%SZ}'
|
||||||
|
co = f"{values['tokenuuid']}|{fiel.cer.rfc}|{fiel.cer.serial_number2}"
|
||||||
|
firma = base64.b64encode(fiel.sign(co).encode()).decode('utf-8')
|
||||||
|
token = self._get_token(firma, co)
|
||||||
|
|
||||||
|
keys = ('credentialsRequired', 'guid', 'ks', 'urlApplet')
|
||||||
|
data = {k: values[k] for k in keys}
|
||||||
|
data['fert'] = fert
|
||||||
|
data['token'] = token
|
||||||
|
data['arc'] = ''
|
||||||
|
data['placer'] = ''
|
||||||
|
data['secuence'] = ''
|
||||||
|
data['seeder'] = ''
|
||||||
|
data['tan'] = ''
|
||||||
|
return data
|
||||||
|
|
||||||
|
def login(self, fiel):
|
||||||
|
HOST = 'cfdicontribuyentes.accesscontrol.windows.net'
|
||||||
|
REFERER = 'https://cfdiau.sat.gob.mx/nidp/wsfed/ep?id=SATUPCFDiCon&sid=0&option=credential&sid=0'
|
||||||
|
URL_LOGIN = 'https://cfdiau.sat.gob.mx/nidp/app/login?id=SATx509Custom&sid=0&option=credential&sid=0'
|
||||||
|
|
||||||
|
result = self._s.get(self.URL['MAIN'])
|
||||||
|
url_redirect = result.history[-1].headers['Location']
|
||||||
|
self._add_headers({'Host': self.HOST})
|
||||||
|
result = self._get(url_redirect)
|
||||||
|
headers = {
|
||||||
|
'User-Agent': self.BROWSER,
|
||||||
|
'Referer': f'{REFERER}{url_redirect}'}
|
||||||
|
self._add_headers(headers)
|
||||||
|
result = self._post(URL_LOGIN)
|
||||||
|
values = self._read_form(result, True)
|
||||||
|
data = self._sign(values, fiel)
|
||||||
|
headers = self._get_headers(self.HOST, self.REFERER)
|
||||||
|
self._add_headers(headers)
|
||||||
|
result = self._post(URL_LOGIN, data)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
msg = 'Error al identificarse en el SAT'
|
||||||
|
log.error(msg)
|
||||||
|
return False
|
||||||
|
|
||||||
|
data = self._read_form(result)
|
||||||
|
|
||||||
|
# Inicio
|
||||||
|
result = self._post(self.URL['MAIN'], data)
|
||||||
|
data = self._get_post_type_search(result)
|
||||||
|
headers = self._get_headers(self.HOST, self.URL['MAIN'])
|
||||||
|
|
||||||
|
# Consulta
|
||||||
|
self._add_headers(headers)
|
||||||
|
result = self._post(self.URL['CONSULTA'], data)
|
||||||
|
msg = 'Se ha identificado en el SAT'
|
||||||
|
log.info(msg)
|
||||||
|
self.is_connect = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _get_post_type_search(self, html, emitidas=False):
|
||||||
|
tipo_busqueda = 'RdoTipoBusquedaReceptor'
|
||||||
|
if emitidas:
|
||||||
|
tipo_busqueda = 'RdoTipoBusquedaEmisor'
|
||||||
|
sm = 'ctl00$MainContent$UpnlBusqueda|ctl00$MainContent$BtnBusqueda'
|
||||||
|
post = self._read_form(html)
|
||||||
|
post['ctl00$MainContent$TipoBusqueda'] = tipo_busqueda
|
||||||
|
post['__ASYNCPOST'] = 'true'
|
||||||
|
post['__EVENTTARGET'] = ''
|
||||||
|
post['__EVENTARGUMENT'] = ''
|
||||||
|
post['ctl00$ScriptManager1'] = sm
|
||||||
|
return post
|
||||||
|
|
||||||
|
def logout(self):
|
||||||
|
msg = 'Cerrando sessión en el SAT'
|
||||||
|
log.debug(msg)
|
||||||
|
result = self._get(self.URL['LOGOUT'])
|
||||||
|
self.is_connect = False
|
||||||
|
msg = 'Sesión cerrada en el SAT'
|
||||||
|
log.info(msg)
|
||||||
|
return
|
Loading…
Reference in New Issue