From 2cc6e7046ae2984b981ee33c32550cd7618f5929 Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Tue, 21 Jan 2020 23:25:13 -0600 Subject: [PATCH] Add new PAC --- source/app/controllers/comercio/__init__.py | 3 + source/app/controllers/comercio/comercio.py | 338 +++++++++++++++ source/app/controllers/util.py | 2 +- source/app/controllers/utils.py | 124 ++++-- source/app/models/main.py | 454 ++++++++++---------- 5 files changed, 663 insertions(+), 258 deletions(-) create mode 100644 source/app/controllers/comercio/__init__.py create mode 100644 source/app/controllers/comercio/comercio.py diff --git a/source/app/controllers/comercio/__init__.py b/source/app/controllers/comercio/__init__.py new file mode 100644 index 0000000..195aadd --- /dev/null +++ b/source/app/controllers/comercio/__init__.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 + +from .comercio import PACComercioDigital diff --git a/source/app/controllers/comercio/comercio.py b/source/app/controllers/comercio/comercio.py new file mode 100644 index 0000000..a6e625b --- /dev/null +++ b/source/app/controllers/comercio/comercio.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python +# ~ +# ~ PAC +# ~ Copyright (C) 2018-2019 Mauricio Baeza Servin - public [AT] elmau [DOT] net +# ~ +# ~ This program is free software: you can redistribute it and/or modify +# ~ it under the terms of the GNU General Public License as published by +# ~ the Free Software Foundation, either version 3 of the License, or +# ~ (at your option) any later version. +# ~ +# ~ This program is distributed in the hope that it will be useful, +# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of +# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# ~ GNU General Public License for more details. +# ~ +# ~ You should have received a copy of the GNU General Public License +# ~ along with this program. If not, see . + + +import logging + +import lxml.etree as ET +import requests +from requests.exceptions import ConnectionError + +from .conf import DEBUG, AUTH + + +LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s' +LOG_DATE = '%d/%m/%Y %H:%M:%S' +logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m') +logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m') +logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m') +logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE) +log = logging.getLogger(__name__) + +logging.getLogger('requests').setLevel(logging.ERROR) + + +TIMEOUT = 10 + + +class PACComercioDigital(object): + ws = 'https://{}.comercio-digital.mx/{}' + api = 'https://app2.comercio-digital.mx/{}' + URL = { + 'timbra': ws.format('ws', 'timbre/timbrarV5.aspx'), + 'cancel': ws.format('cancela', 'cancela3/cancelarUuid'), + 'cancelxml': ws.format('cancela', 'cancela3/cancelarXml'), + 'client': api.format('x3/altaEmpresa'), + 'saldo': api.format('x3/saldo'), + 'timbres': api.format('x3/altaTimbres'), + } + CODES = { + '000': '000 Exitoso', + '004': '004 RFC {} ya esta dado de alta con Estatus=A', + '704': '704 Usuario Invalido', + } + NS_CFDI = { + 'cfdi': 'http://www.sat.gob.mx/cfd/3', + 'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital', + } + + if DEBUG: + ws = 'https://pruebas.comercio-digital.mx/{}' + URL = { + 'timbra': ws.format('timbre/timbrarV5.aspx'), + 'cancel': ws.format('cancela3/cancelarUuid'), + 'cancelxml': ws.format('cancela3/cancelarXml'), + 'client': api.format('x3/altaEmpresa'), + 'saldo': api.format('x3/saldo'), + 'timbres': api.format('x3/altaTimbres'), + } + + def __init__(self): + self.error = '' + self.cfdi_uuid = '' + self.date_stamped = '' + + def _error(self, msg): + self.error = str(msg) + log.error(msg) + return + + def _post(self, url, data, headers={}): + result = None + headers['host'] = url.split('/')[2] + headers['Content-type'] = 'text/plain' + headers['Connection'] = 'Keep-Alive' + + try: + result = requests.post(url, data=data, headers=headers, timeout=TIMEOUT) + except ConnectionError as e: + self._error(e) + + return result + + def _validate_cfdi(self, xml): + """ + Comercio Digital solo soporta la declaración con doble comilla + """ + tree = ET.fromstring(xml.encode()) + xml = ET.tostring(tree, + pretty_print=True, doctype='') + return xml + + def stamp(self, cfdi, auth={}): + if DEBUG or not auth: + auth = AUTH + + url = self.URL['timbra'] + headers = { + 'usrws': auth['user'], + 'pwdws': auth['pass'], + 'tipo': 'XML', + } + cfdi = self._validate_cfdi(cfdi) + result = self._post(url, cfdi, headers) + + if result is None: + return '' + + if result.status_code != 200: + return '' + + if 'errmsg' in result.headers: + self._error(result.headers['errmsg']) + return '' + + xml = result.content + tree = ET.fromstring(xml) + self.cfdi_uuid = tree.xpath( + 'string(//cfdi:Complemento/tdf:TimbreFiscalDigital/@UUID)', + namespaces=self.NS_CFDI) + self.date_stamped = tree.xpath( + 'string(//cfdi:Complemento/tdf:TimbreFiscalDigital/@FechaTimbrado)', + namespaces=self.NS_CFDI) + + return xml.decode() + + def _get_data_cancel(self, cfdi, info, auth): + NS_CFDI = { + 'cfdi': 'http://www.sat.gob.mx/cfd/3', + 'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital', + } + tree = ET.fromstring(cfdi) + tipo = tree.xpath( + 'string(//cfdi:Comprobante/@TipoDeComprobante)', + namespaces=NS_CFDI) + total = tree.xpath( + 'string(//cfdi:Comprobante/@Total)', + namespaces=NS_CFDI) + rfc_emisor = tree.xpath( + 'string(//cfdi:Comprobante/cfdi:Emisor/@Rfc)', + namespaces=NS_CFDI) + rfc_receptor = tree.xpath( + 'string(//cfdi:Comprobante/cfdi:Receptor/@Rfc)', + namespaces=NS_CFDI) + uid = tree.xpath( + 'string(//cfdi:Complemento/tdf:TimbreFiscalDigital/@UUID)', + namespaces=NS_CFDI) + data = ( + f"USER={auth['user']}", + f"PWDW={auth['pass']}", + f"RFCE={rfc_emisor}", + f"UUID={uid}", + f"PWDK={info['pass']}", + f"KEYF={info['key']}", + f"CERT={info['cer']}", + f"TIPO={info['tipo']}", + f"ACUS=SI", + f"RFCR={rfc_receptor}", + f"TIPOC={tipo}", + f"TOTAL={total}", + ) + return '\n'.join(data) + + def cancel(self, cfdi, info, auth={}): + if not auth: + auth = AUTH + url = self.URL['cancel'] + data = self._get_data_cancel(cfdi, info, auth) + + result = self._post(url, data) + + if result is None: + return '' + + if result.status_code != 200: + return '' + + if result.headers['codigo'] != '000': + self._error(result.headers['errmsg']) + return '' + + return result.content + + def _get_headers_cancel_xml(self, cfdi, info, auth): + NS_CFDI = { + 'cfdi': 'http://www.sat.gob.mx/cfd/3', + 'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital', + } + tree = ET.fromstring(cfdi) + tipo = tree.xpath( + 'string(//cfdi:Comprobante/@TipoDeComprobante)', + namespaces=NS_CFDI) + total = tree.xpath( + 'string(//cfdi:Comprobante/@Total)', + namespaces=NS_CFDI) + rfc_receptor = tree.xpath( + 'string(//cfdi:Comprobante/cfdi:Receptor/@Rfc)', + namespaces=NS_CFDI) + + headers = { + 'usrws': auth['user'], + 'pwdws': auth['pass'], + 'rfcr': rfc_receptor, + 'total': total, + 'tipocfdi': tipo, + } + headers.update(info) + + return headers + + def cancel_xml(self, cfdi, xml, info, auth={}): + if not auth: + auth = AUTH + url = self.URL['cancelxml'] + headers = self._get_headers_cancel_xml(cfdi, info, auth) + result = self._post(url, xml, headers) + + if result is None: + return '' + + if result.status_code != 200: + return '' + + if result.headers['codigo'] != '000': + self._error(result.headers['errmsg']) + return '' + + return result.content + + def _get_data_client(self, auth, values): + data = [f"usr_ws={auth['user']}", f"pwd_ws={auth['pass']}"] + fields = ( + 'rfc_contribuyente', + 'nombre_contribuyente', + 'calle', + 'noExterior', + 'noInterior', + 'colonia', + 'localidad', + 'municipio', + 'estado', + 'pais', + 'cp', + 'contacto', + 'telefono', + 'email', + 'rep_nom', + 'rep_rfc', + 'email_fact', + 'pwd_asignado', + ) + data += [f"{k}={values[k]}" for k in fields] + + return '\n'.join(data) + + def client_add(self, data): + auth = AUTH + url = self.URL['client'] + data = self._get_data_client(auth, data) + + result = self._post(url, data) + + if result is None: + return False + + if result.status_code != 200: + self._error(f'Code: {result.status_code}') + return False + + if result.text != self.CODES['000']: + self._error(result.text) + return False + + return True + + def client_balance(self, data): + url = self.URL['saldo'] + host = url.split('/')[2] + headers = { + 'Content-type': 'text/plain', + 'Host': host, + 'Connection' : 'Keep-Alive', + } + try: + result = requests.get(url, params=data, headers=headers, timeout=TIMEOUT) + except ConnectionError as e: + self._error(e) + return '' + + if result.status_code != 200: + return '' + + if result.text == self.CODES['704']: + self._error(result.text) + return '' + + return result.text + + def client_add_timbres(self, data, auth={}): + if not auth: + auth = AUTH + url = self.URL['timbres'] + data = '\n'.join(( + f"usr_ws={auth['user']}", + f"pwd_ws={auth['pass']}", + f"rfc_recibir={data['rfc']}", + f"num_timbres={data['timbres']}" + )) + + result = self._post(url, data) + + if result is None: + return False + + if result.status_code != 200: + self._error(f'Code: {result.status_code}') + return False + + if result.text != self.CODES['000']: + self._error(result.text) + return False + + return True + diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py index 70a465c..3806ab9 100644 --- a/source/app/controllers/util.py +++ b/source/app/controllers/util.py @@ -589,7 +589,7 @@ def timbra_xml(xml, auth): if not DEBUG and not auth: msg = 'Sin datos para timbrar' - result = {'ok': True, 'error': msg} + result = {'ok': False, 'error': msg} return result result = {'ok': True, 'error': ''} diff --git a/source/app/controllers/utils.py b/source/app/controllers/utils.py index 7c58cb7..8b13b09 100644 --- a/source/app/controllers/utils.py +++ b/source/app/controllers/utils.py @@ -19,6 +19,7 @@ import base64 import collections import datetime +import getpass import json import logging import math @@ -50,6 +51,7 @@ from dateutil import parser import seafileapi from settings import DEBUG, DB_COMPANIES, PATHS +from .comercio import PACComercioDigital LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s' @@ -70,6 +72,9 @@ if DEBUG: PG_DUMP = 'pg_dump -h localhost -U postgres' PSQL = 'psql -h localhost -U postgres' +PACS = { + 'comercio': PACComercioDigital +} #~ https://github.com/kennethreitz/requests/blob/v1.2.3/requests/structures.py#L37 class CaseInsensitiveDict(collections.MutableMapping): @@ -394,9 +399,19 @@ def _sql_companies(sql, args=()): return data -def rfc_get(): - sql = "SELECT * FROM names" - data = _sql_companies(sql) +def get_data_con(rfc): + data = rfc_get(rfc)[0][0] + return loads(data) + + +def rfc_get(rfc=''): + if rfc: + sql = "SELECT con FROM names WHERE rfc = ?" + w = (rfc,) + else: + w = () + sql = "SELECT * FROM names" + data = _sql_companies(sql, w) return data @@ -448,35 +463,34 @@ def _get_pass(rfc): return rfc -def _backup_db(rfc, data, path_bk, is_mv, url_seafile): - if data['type'] != 'postgres': - return - - log.info('Generando backup de: {}'.format(rfc)) - bk_name = '{}.bk'.format(rfc.lower()) - path_db = _join(path_bk, bk_name) - args = 'pg_dump -U postgres -Fc {} > "{}"'.format(data['name'], path_db) - result = _call(args) +def _backup_db(rfc, is_mv, url_seafile): + log.info(f'Generando backup de: {rfc.upper()}') + bk_name = f'{rfc}.bk' + path = _join(PATHS['BK'], bk_name) + args = f'{PG_DUMP} -d {rfc} -Fc -f "{path}"' + _run(args) log.info('\tBackup local generado...') + if is_mv: - path_target = _join(Path.home(), PATH_INVOICES) - if Path(path_target).exists(): + path_target = _validate_path_local() + if path_target: path_target = _join(path_target, bk_name) - shutil.copy(path_db, path_target) + shutil.copy(path, path_target) else: log.error('\tNo existe la carpeta compartida...') - sql = 'select correo_timbrado, token_soporte from emisor;' - args = 'psql -U postgres -d {} -Atc "{}"'.format(data['name'], sql) - result = _call(args) - if not result: - log.error('\tSin datos para backup remoto') - return + # ~ sql = 'select correo_timbrado, token_soporte from emisor;' + # ~ args = 'psql -U postgres -d {} -Atc "{}"'.format(data['name'], sql) + # ~ result = _call(args) + # ~ if not result: + # ~ log.error('\tSin datos para backup remoto') + # ~ return + + # ~ data = result.strip().split('|') + # ~ if not data[1]: + # ~ log.error('\tSin token de soporte') + # ~ return - data = result.strip().split('|') - if not data[1]: - log.error('\tSin token de soporte') - return # ~ email = data[0] # ~ uuid = data[1] # ~ email = 'hola@elmau.net' @@ -490,19 +504,15 @@ def _backup_db(rfc, data, path_bk, is_mv, url_seafile): return -def db_backup(path_companies, path_bk, is_mv, url_seafile): - con = sqlite3.connect(path_companies) - cursor = con.cursor() - sql = "SELECT * FROM names" - cursor.execute(sql) - rows = cursor.fetchall() - if rows is None: +def db_backup(is_mv, url_seafile): + data = rfc_get() + if not len(data): + msg = 'Sin bases de datos a respaldar' + log.info(msg) return - cursor.close() - con.close() - for rfc, data in rows: - _backup_db(rfc, json.loads(data), path_bk, is_mv, url_seafile) + for rfc, _ in data: + _backup_db(rfc.lower(), is_mv, url_seafile) return @@ -542,3 +552,45 @@ def now(): def get_days(date): return (now() - date).days + + +def get_pass(): + pass1 = getpass.getpass('Introduce la contraseña: ') + pass2 = getpass.getpass('Confirma la contraseña: ') + + if pass1 != pass2: + msg = 'Las contraseñas son diferentes' + return False, msg + + password = pass1.strip() + if not password: + msg = 'La contraseña es necesaria' + return False, msg + + return True, password + + +def xml_stamp(xml, auth, name): + if not DEBUG and not auth: + msg = 'Sin datos para timbrar' + result = {'ok': False, 'error': msg} + return result + + result = {'ok': True, 'error': ''} + if name == 'comercio': + auth = {'user': auth['RFC'], 'pass': auth['PASS']} + else: + auth = {'user': auth['USER'], 'pass': auth['PASS']} + + pac = PACS[name]() + xml_stamped = pac.stamp(xml, auth) + + if not xml_stamped: + result['ok'] = False + result['error'] = pac.error + return result + + result['xml'] = xml_stamped + result['uuid'] = pac.cfdi_uuid + result['fecha'] = pac.date_stamped + return result diff --git a/source/app/models/main.py b/source/app/models/main.py index 6695639..1d43452 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -19,7 +19,7 @@ import argparse from decimal import Decimal import sqlite3 -import click +# ~ import click from peewee import * from playhouse.fields import PasswordField, ManyToManyField from playhouse.shortcuts import case, SQL, cast @@ -5000,10 +5000,15 @@ class Facturas(BaseModel): obj.save() enviar_correo = util.get_bool(Configuracion.get_('correo_directo')) + pac = Configuracion.get_('pac').lower() anticipo = False msg = 'Factura timbrada correctamente' - result = util.timbra_xml(obj.xml, auth) + if pac: + result = utils.xml_stamp(obj.xml, auth, pac) + else: + result = util.timbra_xml(obj.xml, auth) + if result['ok']: obj.xml = result['xml'] obj.uuid = result['uuid'] @@ -9247,64 +9252,6 @@ def _migrate_tables(rfc=''): return -def _agregar_superusuario(): - args = util.get_con() - if not args: - return - - conectar(args) - usuario = input('Introduce el nuevo nombre para el superusuario: ').strip() - if not usuario: - msg = 'El nombre de usuario es requerido' - log.erro(msg) - return - ok, contraseña = util.get_pass() - if not ok: - log.error(contraseña) - return - try: - obj = Usuarios.create( - usuario=usuario, contraseña=contraseña, es_superusuario=True) - except IntegrityError: - msg = 'El usuario ya existe' - log.error(msg) - return - - log.info('SuperUsuario creado correctamente...') - return - - -def _cambiar_contraseña(): - args = util.get_con() - if not args: - return - - conectar(args) - usuario = input('Introduce el nombre de usuario: ').strip() - if not usuario: - msg = 'El nombre de usuario es requerido' - log.error(msg) - return - - try: - obj = Usuarios.get(usuario=usuario) - except Usuarios.DoesNotExist: - msg = 'El usuario no existe' - log.error(msg) - return - - ok, contraseña = util.get_pass() - if not ok: - log.error(contraseña) - return - - obj.contraseña = contraseña - obj.save() - - log.info('Contraseña cambiada correctamente...') - return - - def _add_emisor(rfc, args): util._valid_db_companies() con = sqlite3.connect(COMPANIES) @@ -9484,7 +9431,7 @@ def _importar_valores(archivo='', rfc=''): try: with database_proxy.atomic() as txn: table.create(**r) - except IntegrityError: + except: pass log.info('Importación terminada...') @@ -9794,44 +9741,6 @@ def _import_tickets(rows): return -def _importar_productos_gambas(rows): - log.info('Importando productos...') - - KEYS = { - 'Exento': '000', - 'ISR': '001', - 'IVA': '002', - } - - totals = len(rows) - for i, row in enumerate(rows): - msg = '\tGuardando producto {} de {}'.format(i+1, totals) - log.info(msg) - - source_taxes = row.pop('impuestos') - row['unidad'] = SATUnidades.get(SATUnidades.key==row['unidad']) - taxes = [] - for tax in source_taxes: - w = { - 'key': KEYS[tax[0]], - 'name': tax[0], - 'tasa': float(tax[1]), - 'tipo': tax[2][0], - } - taxes.append(SATImpuestos.get_o_crea(w)) - - with database_proxy.transaction(): - try: - obj = Productos.create(**row) - obj.impuestos = taxes - except IntegrityError as e: - msg = '\tProducto ya existe' - log.info(msg) - - log.info('Importación terminada...') - return - - def _importar_productos(archivo): rfc = input('Introduce el RFC: ').strip().upper() if not rfc: @@ -10124,6 +10033,87 @@ def _update_sat(): return +def _new_superuser(rfc): + rfc = rfc.lower() + if not rfc: + log.error('Falta el RFC') + return + + if not utils.rfc_exists(rfc): + msg = 'El RFC no esta dado de alta' + log.error(msg) + return + + args = utils.get_data_con(rfc) + + user = input('Introduce el nuevo nombre para el superusuario: ').strip() + if not user: + msg = 'El nombre de usuario es requerido' + log.error(msg) + return + + ok, password = utils.get_pass() + if not ok: + log.error(password) + return + + conectar(args) + try: + obj = Usuarios.create( + usuario=user, contraseña=password, es_superusuario=True) + msg = 'SuperUsuario creado correctamente...' + log.info(msg) + except IntegrityError: + msg = 'El usuario ya existe' + log.error(msg) + + desconectar() + return + + +def _change_pass(rfc): + rfc = rfc.lower() + if not rfc: + log.error('Falta el RFC') + return + + if not utils.rfc_exists(rfc): + msg = 'El RFC no esta dado de alta' + log.error(msg) + return + + args = utils.get_data_con(rfc) + conectar(args) + + user = input('Introduce el nombre de usuario: ').strip() + if not user: + msg = 'El nombre de usuario es requerido' + log.error(msg) + desconectar() + return + + try: + obj = Usuarios.get(usuario=user) + except Usuarios.DoesNotExist: + msg = 'El usuario no existe' + log.error(msg) + desconectar() + return + + ok, password = utils.get_pass() + if not ok: + log.error(password) + desconectar() + return + + obj.contraseña = password + obj.save() + + desconectar() + log.info('Contraseña cambiada correctamente...') + return + + def _process_command_line_arguments(): parser = argparse.ArgumentParser( description='Empresa Libre') @@ -10135,8 +10125,16 @@ def _process_command_line_arguments(): action='store_true', default=False, required=False) parser.add_argument('-ndb', '--no-database', dest='no_database', action='store_true', default=False, required=False) + parser.add_argument('-m', '--migrate', dest='migrate', + action='store_true', default=False, required=False) parser.add_argument('-us', '--update-sat', dest='update_sat', action='store_true', default=False, required=False) + parser.add_argument('-ns', '--new-superuser', dest='new_superuser', + action='store_true', default=False, required=False) + parser.add_argument('-cp', '--change-pass', dest='change_pass', + action='store_true', default=False, required=False) + parser.add_argument('-bk', '--backup', dest='backup', + action='store_true', default=False, required=False) parser.add_argument('-r', '--rfc', dest='rfc', default='') return parser.parse_args() @@ -10155,155 +10153,169 @@ def main(args): _delete_client(args.rfc, args.no_database) return + if args.migrate: + _migrate_tables(args.rfc) + return + if args.update_sat: _update_sat() + return + + if args.new_superuser: + _new_superuser(args.rfc) + return + + if args.change_pass: + _change_pass(args.rfc) + return + + if args.backup: + utils.db_backup(IS_MV, URL['SEAFILE']) return -CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) -help_create_tables = 'Crea las tablas en la base de datos' -help_migrate_db = 'Migra las tablas en la base de datos' -help_superuser = 'Crea un nuevo super usuario' -help_change_pass = 'Cambia la contraseña a un usuario' -help_rfc = 'Agrega un nuevo RFC' -help_br = 'Elimina un RFC' -help_lr = 'Listar RFCs' +# ~ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) +# ~ help_create_tables = 'Crea las tablas en la base de datos' +# ~ help_migrate_db = 'Migra las tablas en la base de datos' +# ~ help_superuser = 'Crea un nuevo super usuario' +# ~ help_change_pass = 'Cambia la contraseña a un usuario' +# ~ help_rfc = 'Agrega un nuevo RFC' +# ~ help_br = 'Elimina un RFC' +# ~ help_lr = 'Listar RFCs' -@click.command(context_settings=CONTEXT_SETTINGS) -@click.option('-bd', '--iniciar-bd',help=help_create_tables, - is_flag=True, default=False) -@click.option('-m', '--migrar-bd', help=help_migrate_db, - is_flag=True, default=False) -@click.option('-ns', '--nuevo-superusuario', help=help_superuser, - is_flag=True, default=False) -@click.option('-cc', '--cambiar-contraseña', help=help_change_pass, - is_flag=True, default=False) -@click.option('-br', '--borrar-rfc', help=help_br, is_flag=True, default=False) -@click.option('-lr', '--listar-rfc', help=help_lr, is_flag=True, default=False) -@click.option('-i', '--importar-valores', is_flag=True, default=False) -@click.option('-f', '--archivo') -@click.option('-c', '--conexion') -@click.option('-fl', '--factura-libre', is_flag=True, default=False) -@click.option('-t', '--test', is_flag=True, default=False) -@click.option('-gap', '--generar-archivo-productos', is_flag=True, default=False) -@click.option('-ip', '--importar-productos', is_flag=True, default=False) -@click.option('-bk', '--backup-dbs', is_flag=True, default=False) -@click.option('-n', '--no-bd', is_flag=True, default=False) -@click.option('-a', '--alta', is_flag=True, default=False) -@click.option('-r', '--rfc') -@click.option('-d', '--detalle', is_flag=True, default=False) -@click.option('-id', '--importar-directorio') -@click.option('-ed', '--exportar_documentos', is_flag=True, default=False) -def main2(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña, - borrar_rfc, listar_rfc, importar_valores, archivo, conexion, - factura_libre, test, generar_archivo_productos, - importar_productos, backup_dbs, no_bd, alta, rfc, detalle, - importar_directorio, exportar_documentos): +# ~ @click.command(context_settings=CONTEXT_SETTINGS) +# ~ @click.option('-bd', '--iniciar-bd',help=help_create_tables, + # ~ is_flag=True, default=False) +# ~ @click.option('-m', '--migrar-bd', help=help_migrate_db, + # ~ is_flag=True, default=False) +# ~ @click.option('-ns', '--nuevo-superusuario', help=help_superuser, + # ~ is_flag=True, default=False) +# ~ @click.option('-cc', '--cambiar-contraseña', help=help_change_pass, + # ~ is_flag=True, default=False) +# ~ @click.option('-br', '--borrar-rfc', help=help_br, is_flag=True, default=False) +# ~ @click.option('-lr', '--listar-rfc', help=help_lr, is_flag=True, default=False) +# ~ @click.option('-i', '--importar-valores', is_flag=True, default=False) +# ~ @click.option('-f', '--archivo') +# ~ @click.option('-c', '--conexion') +# ~ @click.option('-fl', '--factura-libre', is_flag=True, default=False) +# ~ @click.option('-t', '--test', is_flag=True, default=False) +# ~ @click.option('-gap', '--generar-archivo-productos', is_flag=True, default=False) +# ~ @click.option('-ip', '--importar-productos', is_flag=True, default=False) +# ~ @click.option('-bk', '--backup-dbs', is_flag=True, default=False) +# ~ @click.option('-n', '--no-bd', is_flag=True, default=False) +# ~ @click.option('-a', '--alta', is_flag=True, default=False) +# ~ @click.option('-r', '--rfc') +# ~ @click.option('-d', '--detalle', is_flag=True, default=False) +# ~ @click.option('-id', '--importar-directorio') +# ~ @click.option('-ed', '--exportar_documentos', is_flag=True, default=False) +# ~ def main2(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña, + # ~ borrar_rfc, listar_rfc, importar_valores, archivo, conexion, + # ~ factura_libre, test, generar_archivo_productos, + # ~ importar_productos, backup_dbs, no_bd, alta, rfc, detalle, + # ~ importar_directorio, exportar_documentos): - opt = locals() + # ~ opt = locals() - if opt['alta']: - if not opt['rfc']: - msg = 'Falta el RFC' - raise click.ClickException(msg) - # ~ empresa_agregar(opt['rfc'], no_bd) - _new_client(opt['rfc'], no_bd) - sys.exit(0) + # ~ if opt['alta']: + # ~ if not opt['rfc']: + # ~ msg = 'Falta el RFC' + # ~ raise click.ClickException(msg) + # ~ _new_client(opt['rfc'], no_bd) + # ~ sys.exit(0) - if opt['iniciar_bd']: - _iniciar_bd() - sys.exit(0) + # ~ if opt['iniciar_bd']: + # ~ _iniciar_bd() + # ~ sys.exit(0) - if opt['migrar_bd']: - _migrate_tables(rfc) - sys.exit(0) + # ~ if opt['migrar_bd']: + # ~ _migrate_tables(rfc) + # ~ sys.exit(0) - if opt['nuevo_superusuario']: - _agregar_superusuario() - sys.exit(0) + # ~ if opt['nuevo_superusuario']: + # ~ _agregar_superusuario() + # ~ sys.exit(0) - if opt['cambiar_contraseña']: - _cambiar_contraseña() - sys.exit(0) + # ~ if opt['cambiar_contraseña']: + # ~ _cambiar_contraseña() + # ~ sys.exit(0) - if opt['borrar_rfc']: - _borrar_rfc() - sys.exit(0) + # ~ if opt['borrar_rfc']: + # ~ _borrar_rfc() + # ~ sys.exit(0) - if opt['listar_rfc']: - _listar_rfc(opt['detalle']) - sys.exit(0) + # ~ if opt['listar_rfc']: + # ~ _listar_rfc(opt['detalle']) + # ~ sys.exit(0) - if opt['importar_valores']: - if not opt['archivo']: - msg = 'Falta la ruta del archivo importar' - raise click.ClickException(msg) - if not util.is_file(opt['archivo']): - msg = 'No es un archivo' - raise click.ClickException(msg) + # ~ if opt['importar_valores']: + # ~ if not opt['archivo']: + # ~ msg = 'Falta la ruta del archivo importar' + # ~ raise click.ClickException(msg) + # ~ if not util.is_file(opt['archivo']): + # ~ msg = 'No es un archivo' + # ~ raise click.ClickException(msg) - _importar_valores(opt['archivo']) - sys.exit(0) + # ~ _importar_valores(opt['archivo']) + # ~ sys.exit(0) - if opt['factura_libre']: - if not opt['archivo']: - msg = 'Falta la ruta de la base de datos' - raise click.ClickException(msg) - if not util.is_file(opt['archivo']): - msg = 'No es un archivo' - raise click.ClickException(msg) - _, _, _, ext = util.get_path_info(opt['archivo']) - if ext != '.sqlite': - msg = 'No es una base de datos' - raise click.ClickException(msg) + # ~ if opt['factura_libre']: + # ~ if not opt['archivo']: + # ~ msg = 'Falta la ruta de la base de datos' + # ~ raise click.ClickException(msg) + # ~ if not util.is_file(opt['archivo']): + # ~ msg = 'No es un archivo' + # ~ raise click.ClickException(msg) + # ~ _, _, _, ext = util.get_path_info(opt['archivo']) + # ~ if ext != '.sqlite': + # ~ msg = 'No es una base de datos' + # ~ raise click.ClickException(msg) - _importar_factura_libre(opt['archivo']) - sys.exit(0) + # ~ _importar_factura_libre(opt['archivo']) + # ~ sys.exit(0) - if opt['generar_archivo_productos']: - if not opt['archivo']: - msg = 'Falta la ruta de la base de datos' - raise click.ClickException(msg) - if not util.is_file(opt['archivo']): - msg = 'No es un archivo' - raise click.ClickException(msg) - _, _, _, ext = util.get_path_info(opt['archivo']) - if ext != '.sqlite': - msg = 'No es una base de datos' - raise click.ClickException(msg) + # ~ if opt['generar_archivo_productos']: + # ~ if not opt['archivo']: + # ~ msg = 'Falta la ruta de la base de datos' + # ~ raise click.ClickException(msg) + # ~ if not util.is_file(opt['archivo']): + # ~ msg = 'No es un archivo' + # ~ raise click.ClickException(msg) + # ~ _, _, _, ext = util.get_path_info(opt['archivo']) + # ~ if ext != '.sqlite': + # ~ msg = 'No es una base de datos' + # ~ raise click.ClickException(msg) - _generar_archivo_productos(opt['archivo']) - sys.exit(0) + # ~ _generar_archivo_productos(opt['archivo']) + # ~ sys.exit(0) - if opt['importar_productos']: - if not opt['archivo']: - msg = 'Falta la ruta del archivo' - raise click.ClickException(msg) - if not util.is_file(opt['archivo']): - msg = 'No es un archivo' - raise click.ClickException(msg) - _, _, _, ext = util.get_path_info(opt['archivo']) - if ext != '.txt': - msg = 'No es un archivo de texto' - raise click.ClickException(msg) + # ~ if opt['importar_productos']: + # ~ if not opt['archivo']: + # ~ msg = 'Falta la ruta del archivo' + # ~ raise click.ClickException(msg) + # ~ if not util.is_file(opt['archivo']): + # ~ msg = 'No es un archivo' + # ~ raise click.ClickException(msg) + # ~ _, _, _, ext = util.get_path_info(opt['archivo']) + # ~ if ext != '.txt': + # ~ msg = 'No es un archivo de texto' + # ~ raise click.ClickException(msg) - _importar_productos(opt['archivo']) - sys.exit(0) + # ~ _importar_productos(opt['archivo']) + # ~ sys.exit(0) - if opt['importar_directorio']: - _import_from_folder(opt['importar_directorio']) - sys.exit(0) + # ~ if opt['importar_directorio']: + # ~ _import_from_folder(opt['importar_directorio']) + # ~ sys.exit(0) - if opt['backup_dbs']: - # ~ util.backup_dbs() - utils.db_backup(DB_COMPANIES, PATHS['BK'], IS_MV, URL['SEAFILE']) - sys.exit(0) + # ~ if opt['backup_dbs']: + # ~ utils.db_backup(DB_COMPANIES, PATHS['BK'], IS_MV, URL['SEAFILE']) + # ~ sys.exit(0) - if opt['exportar_documentos']: - _exportar_documentos() + # ~ if opt['exportar_documentos']: + # ~ _exportar_documentos() - return + # ~ return if __name__ == '__main__':