Import clients form CSV

This commit is contained in:
Mauricio Baeza 2021-02-10 23:02:12 -06:00
commit b5bdcbbeb3
5 changed files with 69 additions and 397 deletions

View File

@ -1,3 +1,8 @@
v 1.41.0 [10-Feb-2021]
----------------------
- Importar clientes desde archivo CSV
v 1.40.1 [09-Feb-2021]
----------------------
- Fix #422

View File

@ -1 +1 @@
1.40.1
1.41.0

View File

@ -18,6 +18,7 @@
import base64
import collections
import csv
import datetime
import getpass
import json
@ -30,6 +31,7 @@ import smtplib
import sqlite3
import subprocess
import threading
import unicodedata
import zipfile
from pathlib import Path
from xml.sax.saxutils import escape
@ -759,3 +761,20 @@ def get_status_sat(xml):
return node.text
def spaces(value):
return '\n'.join([' '.join(l.split()) for l in value.split('\n')])
def to_slug(string):
value = (unicodedata.normalize('NFKD', string)
.encode('ascii', 'ignore')
.decode('ascii').lower())
return value.replace(' ', '_')
def read_csv(path, args={'delimiter': '|'}):
with open(path) as f:
reader = csv.DictReader(f, **args)
rows = [r for r in reader]
return rows

View File

@ -9797,389 +9797,6 @@ def _importar_valores(archivo='', rfc=''):
return
# ~ def _importar_socios(rows):
# ~ log.info('\tImportando Clientes...')
# ~ totals = len(rows)
# ~ for i, row in enumerate(rows):
# ~ msg = '\tGuardando cliente {} de {}'.format(i+1, totals)
# ~ log.info(msg)
# ~ try:
# ~ with database_proxy.atomic() as txn:
# ~ Socios.create(**row)
# ~ except IntegrityError:
# ~ msg = '\tSocio existente: {}'.format(row['nombre'])
# ~ log.info(msg)
# ~ log.info('\tClientes importados...')
# ~ return
# ~ def _existe_factura(row):
# ~ filtro = (Facturas.uuid==row['uuid'])
# ~ if row['uuid'] is None:
# ~ filtro = (
# ~ (Facturas.serie==row['serie']) &
# ~ (Facturas.folio==row['folio'])
# ~ )
# ~ return Facturas.select().where(filtro).exists()
# ~ def _importar_facturas(rows):
# ~ log.info('\tImportando Facturas...')
# ~ totals = len(rows)
# ~ for i, row in enumerate(rows):
# ~ msg = '\tGuardando factura {} de {}'.format(i+1, totals)
# ~ log.info(msg)
# ~ try:
# ~ detalles = row.pop('detalles')
# ~ impuestos = row.pop('impuestos')
# ~ cliente = row.pop('cliente')
# ~ row['cliente'] = Socios.get(**cliente)
# ~ with database_proxy.atomic() as txn:
# ~ if _existe_factura(row):
# ~ msg = '\tFactura existente: {}{}'.format(
# ~ row['serie'], row['folio'])
# ~ log.info(msg)
# ~ continue
# ~ obj = Facturas.create(**row)
# ~ for detalle in detalles:
# ~ detalle['factura'] = obj
# ~ FacturasDetalle.create(**detalle)
# ~ for impuesto in impuestos:
# ~ imp = SATImpuestos.get(**impuesto['filtro'])
# ~ new = {
# ~ 'factura': obj,
# ~ 'impuesto': imp,
# ~ 'importe': impuesto['importe'],
# ~ }
# ~ try:
# ~ with database_proxy.atomic() as txn:
# ~ FacturasImpuestos.create(**new)
# ~ except IntegrityError as e:
# ~ pass
# ~ except IntegrityError as e:
# ~ print (e)
# ~ msg = '\tFactura: id: {}'.format(row['serie'] + str(row['folio']))
# ~ log.error(msg)
# ~ break
# ~ log.info('\tFacturas importadas...')
# ~ return
# ~ def _importar_categorias(rows):
# ~ log.info('\tImportando Categorías...')
# ~ for row in rows:
# ~ with database_proxy.atomic() as txn:
# ~ try:
# ~ Categorias.create(**row)
# ~ except IntegrityError:
# ~ msg = '\tCategoria: ({}) {}'.format(row['padre'], row['categoria'])
# ~ log.error(msg)
# ~ log.info('\tCategorías importadas...')
# ~ return
# ~ def _get_id_unidad(unidad):
# ~ try:
# ~ if 'pieza' in unidad.lower():
# ~ unidad = 'pieza'
# ~ if 'metros' in unidad.lower():
# ~ unidad = 'metro'
# ~ if 'tramo' in unidad.lower():
# ~ unidad = 'paquete'
# ~ if 'juego' in unidad.lower():
# ~ unidad = 'par'
# ~ if 'bolsa' in unidad.lower():
# ~ unidad = 'globo'
# ~ if unidad.lower() == 'no aplica':
# ~ unidad = 'servicio'
# ~ obj = SATUnidades.get(SATUnidades.name.contains(unidad))
# ~ except SATUnidades.DoesNotExist:
# ~ msg = '\tNo se encontró la unidad: {}'.format(unidad)
# ~ return unidad
# ~ return str(obj.id)
# ~ def _get_impuestos(impuestos):
# ~ lines = '|'
# ~ for impuesto in impuestos:
# ~ if impuesto['tasa'] == '-2/3':
# ~ tasa = str(round(2/3, 6))
# ~ else:
# ~ if impuesto['tasa'] == 'EXENTO':
# ~ tasa = '0.00'
# ~ else:
# ~ tasa = str(round(float(impuesto['tasa']) / 100.0, 6))
# ~ info = (
# ~ IMPUESTOS.get(impuesto['nombre']),
# ~ impuesto['nombre'],
# ~ impuesto['tipo'][0],
# ~ tasa,
# ~ )
# ~ lines += '|'.join(info) + '|'
# ~ return lines
# ~ def _generar_archivo_productos(archivo):
# ~ rfc = input('Introduce el RFC: ').strip().upper()
# ~ if not rfc:
# ~ msg = 'El RFC es requerido'
# ~ log.error(msg)
# ~ return
# ~ args = util.get_con(rfc)
# ~ if not args:
# ~ return
# ~ conectar(args)
# ~ log.info('Importando datos...')
# ~ app = util.ImportFacturaLibre(archivo, rfc)
# ~ if not app.is_connect:
# ~ log.error('\t{}'.format(app._error))
# ~ return
# ~ rows = app.import_productos()
# ~ p, _, _, _ = util.get_path_info(archivo)
# ~ path_txt = util._join(p, 'productos_{}.txt'.format(rfc))
# ~ log.info('\tGenerando archivo: {}'.format(path_txt))
# ~ fields = (
# ~ 'clave',
# ~ 'clave_sat',
# ~ 'unidad',
# ~ 'categoria',
# ~ 'descripcion',
# ~ 'valor_unitario',
# ~ 'existencia',
# ~ 'inventario',
# ~ 'codigo_barras',
# ~ 'cuenta_predial',
# ~ 'ultimo_precio',
# ~ 'minimo',
# ~ )
# ~ data = ['|'.join(fields)]
# ~ not_units = []
# ~ for row in rows:
# ~ impuestos = row.pop('impuestos', ())
# ~ line = [str(row[r]) for r in fields]
# ~ if line[10] == 'None':
# ~ line[10] = '0.0'
# ~ line[2] = _get_id_unidad(line[2])
# ~ try:
# ~ int(line[2])
# ~ except ValueError:
# ~ if not line[2] in not_units:
# ~ not_units.append(line[2])
# ~ msg = 'No se encontró la unidad: {}'.format(line[2])
# ~ log.error(msg)
# ~ continue
# ~ line = '|'.join(line) + _get_impuestos(impuestos)
# ~ data.append(line)
# ~ with open(path_txt, 'w') as fh:
# ~ fh.write('\n'.join(data))
# ~ log.info('\tArchivo generado: {}'.format(path_txt))
# ~ return
# ~ def importar_bdfl():
# ~ try:
# ~ emisor = Emisor.select()[0]
# ~ except IndexError:
# ~ msg = 'Configura primero al emisor'
# ~ return {'ok': False, 'msg': msg}
# ~ name = '{}.sqlite'.format(emisor.rfc.lower())
# ~ path = util._join('/tmp', name)
# ~ log.info('Importando datos...')
# ~ app = util.ImportFacturaLibre(path, emisor.rfc)
# ~ if not app.is_connect:
# ~ msg = app._error
# ~ log.error('\t{}'.format(msg))
# ~ return {'ok': False, 'msg': msg}
# ~ data = app.import_data()
# ~ _importar_socios(data['Socios'])
# ~ _importar_facturas(data['Facturas'])
# ~ _importar_categorias(data['Categorias'])
# ~ msg = 'Importación terminada...'
# ~ log.info(msg)
# ~ return {'ok': True, 'msg': msg}
# ~ def _importar_factura_libre(archivo):
# ~ rfc = input('Introduce el RFC: ').strip().upper()
# ~ if not rfc:
# ~ msg = 'El RFC es requerido'
# ~ log.error(msg)
# ~ return
# ~ args = util.get_con(rfc)
# ~ if not args:
# ~ return
# ~ conectar(args)
# ~ log.info('Importando datos...')
# ~ app = util.ImportFacturaLibre(archivo, rfc)
# ~ if not app.is_connect:
# ~ log.error('\t{}'.format(app._error))
# ~ return
# ~ data = app.import_data()
# ~ _importar_socios(data['Socios'])
# ~ _importar_facturas(data['Facturas'])
# ~ _importar_categorias(data['Categorias'])
# ~ log.info('Importación terminada...')
# ~ return
# ~ def _exist_ticket(row):
# ~ filters = (
# ~ (Tickets.serie==row['serie']) &
# ~ (Tickets.folio==row['folio'])
# ~ )
# ~ return Tickets.select().where(filters).exists()
# ~ def _import_tickets(rows):
# ~ log.info('\tImportando Tickets...')
# ~ for row in rows:
# ~ try:
# ~ details = row.pop('details')
# ~ taxes = row.pop('taxes')
# ~ with database_proxy.atomic() as txn:
# ~ if _exist_ticket(row):
# ~ msg = '\tTicket existente: {}{}'.format(
# ~ row['serie'], row['folio'])
# ~ log.info(msg)
# ~ continue
# ~ if not row['factura'] is None and row['factura']:
# ~ row['factura'] = Facturas.get(
# ~ Facturas.serie==row['factura']['serie'],
# ~ Facturas.folio==row['factura']['folio'])
# ~ else:
# ~ row['factura'] = None
# ~ obj = Tickets.create(**row)
# ~ for detail in details:
# ~ detail['ticket'] = obj
# ~ TicketsDetalle.create(**detail)
# ~ for tax in taxes:
# ~ imp = SATImpuestos.get(**tax['filter'])
# ~ new = {
# ~ 'ticket': obj,
# ~ 'impuesto': imp,
# ~ 'importe': tax['import'],
# ~ }
# ~ TicketsImpuestos.create(**new)
# ~ except IntegrityError as e:
# ~ print (e)
# ~ msg = '\tTicket: id: {}'.format(row['serie'] + str(row['folio']))
# ~ log.error(msg)
# ~ log.info('\tTickets importadas...')
# ~ return
# ~ def _importar_productos(archivo):
# ~ rfc = input('Introduce el RFC: ').strip().upper()
# ~ if not rfc:
# ~ msg = 'El RFC es requerido'
# ~ log.error(msg)
# ~ return
# ~ args = util.get_con(rfc)
# ~ if not args:
# ~ return
# ~ conectar(args)
# ~ log.info('Importando productos...')
# ~ fields = (
# ~ 'clave',
# ~ 'clave_sat',
# ~ 'unidad',
# ~ 'categoria',
# ~ 'descripcion',
# ~ 'valor_unitario',
# ~ 'existencia',
# ~ 'inventario',
# ~ 'codigo_barras',
# ~ 'cuenta_predial',
# ~ 'ultimo_precio',
# ~ 'minimo',
# ~ )
# ~ rows = util.read_file(archivo, 'r').split('\n')
# ~ for i, row in enumerate(rows):
# ~ if i == 0:
# ~ continue
# ~ data = row.split('|')
# ~ print (data)
# ~ new = {}
# ~ for i, f in enumerate(fields):
# ~ if not len(data[0]):
# ~ continue
# ~ if i in (2, 3):
# ~ try:
# ~ new[f] = int(data[i])
# ~ except ValueError:
# ~ continue
# ~ elif i in (5, 6, 10, 11):
# ~ new[f] = float(data[i])
# ~ elif i == 7:
# ~ new[f] = bool(data[i])
# ~ else:
# ~ new[f] = data[i]
# ~ impuestos = data[i + 1:-1]
# ~ if not impuestos:
# ~ taxes = [SATImpuestos.select().where(SATImpuestos.id==6)]
# ~ else:
# ~ taxes = []
# ~ try:
# ~ for i in range(0, len(impuestos), 4):
# ~ w = {
# ~ 'key': impuestos[i],
# ~ 'name': impuestos[i+1],
# ~ 'tipo': impuestos[i+2],
# ~ 'tasa': float(impuestos[i+3]),
# ~ }
# ~ taxes.append(SATImpuestos.get_o_crea(w))
# ~ except IndexError:
# ~ print ('IE', data)
# ~ continue
# ~ with database_proxy.transaction():
# ~ try:
# ~ obj = Productos.create(**new)
# ~ obj.impuestos = taxes
# ~ except IntegrityError as e:
# ~ pass
# ~ log.info('Importación terminada...')
# ~ return
def _import_from_folder(path):
files = util.get_files(path, 'json')
if not files:
@ -10505,32 +10122,59 @@ def _migrate_cert(rfc):
return
def _test(rfc):
if not rfc:
rfc = input('Introduce el RFC: ').strip().upper()
def _import_clients(rfc, path):
if not rfc:
msg = 'El RFC es requerido'
log.error(msg)
return
if not path:
msg = 'El archivo CSV es necesario'
log.error(msg)
return
args = util.get_con(rfc)
if not args:
return
conectar(args)
log.info('Test con...')
log.info('Importando clientes...')
query = Socios.select(Socios.id, Socios.nombre, Socios.rfc).where(Socios.nombre.contains('Lopez'))
print(query)
data = utils.read_csv(path)
t = len(data)
ok = 0
for i, row in enumerate(data):
msg = f'\tImportando cliente {i+1} de {t}'
log.info(msg)
row['rfc'] = row['rfc'].upper()
row['nombre'] = utils.spaces(row['nombre'])
row['slug'] = utils.to_slug(row['nombre'])
w = ((Socios.rfc==row['rfc']) & (Socios.slug==row['slug']))
if Socios.select().where(w).exists():
msg = '\tYa existe el RFC y Razón Social'
log.info(msg)
continue
row['es_cliente'] = True
row['forma_pago'] = SATFormaPago.get(SATFormaPago.id==row['forma_pago'])
try:
obj = Socios.create(**row)
ok += 1
except Exception as e:
log.error(e)
break
desconectar()
log.info('End test...')
msg = f'Total de clientes: {t}'
log.info(msg)
msg = f'Clientes nuevos: {ok}'
log.info(msg)
log.info('Proceso terminado correctamente...')
return
def _process_command_line_arguments():
parser = argparse.ArgumentParser(
description='Empresa Libre')
@ -10554,11 +10198,13 @@ def _process_command_line_arguments():
action='store_true', default=False, required=False)
parser.add_argument('-ed', '--export-documents', dest='export_documents',
action='store_true', default=False, required=False)
parser.add_argument('-ic', '--import-clients', dest='import_clients',
action='store_true', default=False, required=False)
parser.add_argument('-mc' , '--migrate-cert', dest='migrate_cert',
action='store_true', default=False, required=False)
parser.add_argument('-r', '--rfc', dest='rfc', default='')
parser.add_argument('-f', '--file', dest='file', default='')
return parser.parse_args()
@ -10603,7 +10249,9 @@ def main(args):
_migrate_cert(args.rfc)
return
# ~ _test(args.rfc)
if args.import_clients:
_import_clients(args.rfc, args.file)
return
return

View File

@ -42,7 +42,7 @@ except ImportError:
DEBUG = DEBUG
VERSION = '1.40.1'
VERSION = '1.41.0'
EMAIL_SUPPORT = ('soporte@empresalibre.mx',)
TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION)