Import clients form CSV
This commit is contained in:
commit
b5bdcbbeb3
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue