1077 lines
31 KiB
Python
1077 lines
31 KiB
Python
#!/usr/bin/env python
|
|
|
|
import sqlite3
|
|
import click
|
|
from peewee import *
|
|
from playhouse.fields import PasswordField, ManyToManyField
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import os, sys
|
|
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
sys.path.insert(0, parent_dir)
|
|
|
|
|
|
from controllers import util
|
|
from settings import log, VERSION, PATH_CP
|
|
|
|
|
|
database_proxy = Proxy()
|
|
class BaseModel(Model):
|
|
class Meta:
|
|
database = database_proxy
|
|
|
|
|
|
def conectar(opt):
|
|
db = {
|
|
'sqlite': SqliteDatabase,
|
|
'postgres': PostgresqlDatabase,
|
|
'mysql': MySQLDatabase,
|
|
}
|
|
db_type = opt.pop('type')
|
|
db_name = opt.pop('name')
|
|
if not db_type in db:
|
|
log.error('Tipo de base de datos no soportado')
|
|
return False
|
|
#~ print ('DB NAME', db_name)
|
|
database = db[db_type](db_name, **opt)
|
|
try:
|
|
database_proxy.initialize(database)
|
|
database_proxy.connect()
|
|
log.info('Conectado a la BD...')
|
|
return True
|
|
except OperationalError as e:
|
|
log.error('Error al intentar conectar a la base de datos')
|
|
log.error(e)
|
|
return False
|
|
|
|
|
|
def desconectar():
|
|
if database_proxy.obj is None:
|
|
return
|
|
if not database_proxy.is_closed():
|
|
database_proxy.close()
|
|
log.info('Desconectado a la BD...')
|
|
return
|
|
|
|
|
|
class Configuracion(BaseModel):
|
|
clave = TextField()
|
|
valor = TextField(default='')
|
|
|
|
class Meta:
|
|
order_by = ('clave',)
|
|
indexes = (
|
|
(('clave', 'valor'), True),
|
|
)
|
|
|
|
|
|
class Tags(BaseModel):
|
|
tag = TextField(index=True, unique=True)
|
|
|
|
class Meta:
|
|
order_by = ('tag',)
|
|
|
|
|
|
class Usuarios(BaseModel):
|
|
usuario = TextField(unique=True)
|
|
nombre = TextField(default='')
|
|
apellidos = TextField(default='')
|
|
correo = TextField(default='')
|
|
contraseña = PasswordField()
|
|
es_superusuario = BooleanField(default=False)
|
|
es_admin = BooleanField(default=False)
|
|
es_activo = BooleanField(default=True)
|
|
fecha_ingreso = DateTimeField(default=util.now)
|
|
ultimo_ingreso = DateTimeField(null=True)
|
|
|
|
def __str__(self):
|
|
t = '{} {} ({})'
|
|
return t.format(self.nombre, self.apellidos, self.usuario)
|
|
|
|
class Meta:
|
|
order_by = ('nombre', 'apellidos')
|
|
|
|
|
|
class SATRegimenes(BaseModel):
|
|
key = TextField(index=True, unique=True)
|
|
name = TextField(index=True)
|
|
activo = BooleanField(default=False)
|
|
default = BooleanField(default=False)
|
|
fisica = BooleanField(default=False)
|
|
moral = BooleanField(default=False)
|
|
|
|
class Meta:
|
|
order_by = ('name',)
|
|
indexes = (
|
|
(('key', 'name'), True),
|
|
)
|
|
|
|
|
|
class Emisor(BaseModel):
|
|
rfc = TextField(index=True)
|
|
nombre = TextField()
|
|
calle = TextField(default='')
|
|
no_exterior = TextField(default='')
|
|
no_interior = TextField(default='')
|
|
colonia = TextField(default='')
|
|
municipio = TextField(default='')
|
|
estado = TextField(default='')
|
|
pais = TextField(default='')
|
|
codigo_postal = TextField(default='')
|
|
cp_expedicion = TextField(default='')
|
|
es_moral = BooleanField(default=False)
|
|
es_ong = BooleanField(default=False)
|
|
es_escuela = BooleanField(default=False)
|
|
autorizacion = TextField(default='')
|
|
fecha_autorizacion = DateField(null=True)
|
|
fecha_dof = DateField(null=True)
|
|
telefono = TextField(default='')
|
|
correo = TextField(default='')
|
|
web = TextField(default='')
|
|
curp = TextField(default='')
|
|
regimenes = ManyToManyField(SATRegimenes, related_name='emisores')
|
|
|
|
def __str__(self):
|
|
t = '{} ({})'
|
|
return t.format(self.nombre, self.rfc)
|
|
|
|
class Meta:
|
|
order_by = ('nombre',)
|
|
|
|
|
|
class Certificado(BaseModel):
|
|
key = BlobField()
|
|
key_enc = TextField(default='')
|
|
cer = BlobField()
|
|
cer_pem = TextField(default='')
|
|
cer_txt = TextField(default='')
|
|
p12 = BlobField()
|
|
serie = TextField(default='')
|
|
rfc = TextField(default='')
|
|
desde = DateTimeField()
|
|
hasta = DateTimeField()
|
|
|
|
def __str__(self):
|
|
return self.serie
|
|
|
|
|
|
class Folios(BaseModel):
|
|
serie = TextField()
|
|
inicio = IntegerField(default=1)
|
|
default = BooleanField(default=False)
|
|
usar_con = TextField(default='')
|
|
|
|
class Meta:
|
|
order_by = ('-default', 'serie', 'inicio')
|
|
indexes = (
|
|
(('serie', 'inicio'), True),
|
|
)
|
|
|
|
@classmethod
|
|
def get_all(cls):
|
|
rows = (Folios
|
|
.select(
|
|
Folios.id,
|
|
Folios.serie.alias('value'),
|
|
Folios.usar_con,
|
|
)
|
|
.dicts()
|
|
)
|
|
return tuple(rows)
|
|
|
|
|
|
class Categorias(BaseModel):
|
|
categoria = TextField()
|
|
padre = ForeignKeyField('self', null=True, related_name='hijos')
|
|
|
|
class Meta:
|
|
order_by = ('categoria',)
|
|
indexes = (
|
|
(('categoria', 'padre'), True),
|
|
)
|
|
|
|
@classmethod
|
|
def get_all(cls):
|
|
rows = (Categorias.select(
|
|
Categorias.id,
|
|
Categorias.categoria.alias('value'),
|
|
Categorias.padre.alias('parent_id'))
|
|
).dicts()
|
|
return tuple(rows)
|
|
|
|
|
|
class CondicionesPago(BaseModel):
|
|
condicion = TextField(unique=True)
|
|
|
|
class Meta:
|
|
order_by = ('condicion',)
|
|
|
|
|
|
class SATUnidades(BaseModel):
|
|
key = TextField(unique=True, index=True)
|
|
name = TextField(default='', index=True)
|
|
activo = BooleanField(default=False)
|
|
default = BooleanField(default=False)
|
|
|
|
class Meta:
|
|
order_by = ('name',)
|
|
indexes = (
|
|
(('key', 'name'), True),
|
|
)
|
|
|
|
@classmethod
|
|
def get_activos(cls):
|
|
rows = (SATUnidades
|
|
.select(
|
|
SATUnidades.id,
|
|
SATUnidades.name.alias('value'))
|
|
.where(SATUnidades.activo==True)
|
|
.dicts()
|
|
)
|
|
return tuple(rows)
|
|
|
|
|
|
class SATFormaPago(BaseModel):
|
|
key = TextField(unique=True, index=True)
|
|
name = TextField(default='', index=True)
|
|
activo = BooleanField(default=False)
|
|
default = BooleanField(default=False)
|
|
|
|
class Meta:
|
|
order_by = ('-default', 'name',)
|
|
indexes = (
|
|
(('key', 'name'), True),
|
|
)
|
|
|
|
@classmethod
|
|
def get_activos(cls):
|
|
rows = (SATFormaPago
|
|
.select(
|
|
SATFormaPago.id,
|
|
SATFormaPago.name.alias('value'))
|
|
.where(SATFormaPago.activo==True)
|
|
.dicts()
|
|
)
|
|
return tuple(rows)
|
|
|
|
|
|
class SATAduanas(BaseModel):
|
|
key = TextField(unique=True, index=True)
|
|
name = TextField(default='', index=True)
|
|
activo = BooleanField(default=False)
|
|
default = BooleanField(default=False)
|
|
|
|
class Meta:
|
|
order_by = ('-default', 'name',)
|
|
indexes = (
|
|
(('key', 'name'), True),
|
|
)
|
|
|
|
|
|
class SATMonedas(BaseModel):
|
|
key = TextField(unique=True, index=True)
|
|
name = TextField(default='', index=True)
|
|
activo = BooleanField(default=False)
|
|
default = BooleanField(default=False)
|
|
|
|
class Meta:
|
|
order_by = ('-default', 'name',)
|
|
indexes = (
|
|
(('key', 'name'), True),
|
|
)
|
|
|
|
@classmethod
|
|
def get_activos(cls):
|
|
rows = (SATMonedas
|
|
.select(
|
|
SATMonedas.key.alias('id'),
|
|
SATMonedas.name.alias('value'))
|
|
.where(SATMonedas.activo==True)
|
|
.dicts()
|
|
)
|
|
return tuple(rows)
|
|
|
|
|
|
class SATImpuestos(BaseModel):
|
|
key = TextField(index=True)
|
|
name = TextField(default='', index=True)
|
|
factor = TextField(default='T')
|
|
tipo = TextField(default='T')
|
|
tasa = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
activo = BooleanField(default=False)
|
|
default = BooleanField(default=False)
|
|
|
|
class Meta:
|
|
order_by = ('-default', 'name',)
|
|
indexes = (
|
|
(('key', 'factor', 'tipo', 'tasa'), True),
|
|
)
|
|
|
|
@classmethod
|
|
def get_activos(self):
|
|
rows = SATImpuestos.select().where(SATImpuestos.activo==True).dicts()
|
|
return tuple(rows)
|
|
|
|
|
|
class SATUsoCfdi(BaseModel):
|
|
key = TextField(index=True, unique=True)
|
|
name = TextField(default='', index=True)
|
|
activo = BooleanField(default=False)
|
|
default = BooleanField(default=False)
|
|
fisica = BooleanField(default=True)
|
|
moral = BooleanField(default=False)
|
|
|
|
class Meta:
|
|
order_by = ('-default', 'name',)
|
|
indexes = (
|
|
(('key', 'name'), True),
|
|
)
|
|
|
|
@classmethod
|
|
def get_activos(cls):
|
|
rows = (SATUsoCfdi
|
|
.select(
|
|
SATUsoCfdi.key.alias('id'),
|
|
SATUsoCfdi.name.alias('value'),
|
|
SATUsoCfdi.fisica,
|
|
SATUsoCfdi.moral,
|
|
)
|
|
.where(SATUsoCfdi.activo==True)
|
|
.dicts()
|
|
)
|
|
return tuple(rows)
|
|
|
|
|
|
class Addendas(BaseModel):
|
|
nombre = TextField(unique=True)
|
|
addenda = TextField()
|
|
|
|
class Meta:
|
|
order_by = ('nombre',)
|
|
|
|
|
|
class Socios(BaseModel):
|
|
tipo_persona = IntegerField(default=1)
|
|
rfc = TextField(index=True)
|
|
nombre = TextField(index=True)
|
|
slug = TextField(default='')
|
|
nombre_comercial = TextField(index=True, default='')
|
|
calle = TextField(default='')
|
|
no_exterior = TextField(default='')
|
|
no_interior = TextField(default='')
|
|
colonia = TextField(default='')
|
|
municipio = TextField(default='')
|
|
estado = TextField(default='')
|
|
pais = TextField(default='')
|
|
codigo_postal = TextField(default='')
|
|
notas = TextField(default='')
|
|
telefonos = TextField(default='')
|
|
es_activo = BooleanField(default=True)
|
|
es_ong = BooleanField(default=False)
|
|
fecha_alta = DateField(default=util.now)
|
|
dias_pago = IntegerField(default=0)
|
|
dias_habiles = BooleanField(default=False)
|
|
es_cliente = BooleanField(default=False)
|
|
es_proveedor = BooleanField(default=False)
|
|
cuenta_cliente = TextField(default='')
|
|
cuenta_proveedor = TextField(default='')
|
|
web = TextField(default='')
|
|
correo_facturas = TextField(default='')
|
|
forma_pago = ForeignKeyField(SATFormaPago, null=True)
|
|
condicion_pago = ForeignKeyField(CondicionesPago, null=True)
|
|
addenda = ForeignKeyField(Addendas, null=True)
|
|
uso_cfdi = ForeignKeyField(SATUsoCfdi, null=True)
|
|
tags = ManyToManyField(Tags, related_name='socios_tags')
|
|
|
|
def __str__(self):
|
|
t = '{} ({})'
|
|
return t.format(self.nombre, self.rfc)
|
|
|
|
class Meta:
|
|
order_by = ('nombre',)
|
|
indexes = (
|
|
(('rfc', 'slug'), True),
|
|
)
|
|
|
|
def _clean(self, values):
|
|
fields = util.clean(values)
|
|
fields['rfc'] = fields['rfc'].upper()
|
|
fields['nombre'] = util.spaces(fields['nombre'])
|
|
fields['slug'] = util.to_slug(fields['nombre'])
|
|
fb = ('dias_habiles', 'es_activo', 'es_cliente',
|
|
'es_proveedor', 'es_ong')
|
|
for name in fb:
|
|
fields[name] = bool(fields[name].replace('0', ''))
|
|
return fields
|
|
|
|
@classmethod
|
|
def get_(cls, values):
|
|
if values:
|
|
id = int(values['id'])
|
|
row = Socios.select().where(Socios.id==id).dicts()[0]
|
|
return row
|
|
|
|
rows = Socios.select(Socios.id, Socios.rfc, Socios.nombre).dicts()
|
|
return {'ok': True, 'rows': tuple(rows)}
|
|
|
|
@classmethod
|
|
def get_by_client(cls, values):
|
|
id = int(values.get('id', 0))
|
|
if id:
|
|
row = (Socios
|
|
.select(
|
|
Socios.id, Socios.nombre, Socios.rfc)
|
|
.where(
|
|
(Socios.id==id) & (Socios.es_cliente==True))
|
|
.dicts()
|
|
)
|
|
if len(row):
|
|
return {'ok': True, 'row': row[0]}
|
|
return {'ok': False}
|
|
|
|
name = values.get('name', '')
|
|
if name:
|
|
rows = (Socios
|
|
.select(Socios.id, Socios.nombre, Socios.rfc)
|
|
.where((Socios.es_cliente==True) &
|
|
(Socios.rfc.contains(name) |
|
|
Socios.nombre.contains(name)))
|
|
.dicts())
|
|
return tuple(rows)
|
|
return {'ok': False}
|
|
|
|
@classmethod
|
|
def add(cls, values):
|
|
fields = cls._clean(cls, values)
|
|
try:
|
|
obj = Socios.create(**fields)
|
|
except IntegrityError:
|
|
msg = 'Ya existe el RFC y Razón Social'
|
|
data = {'ok': False, 'row': {}, 'new': True, 'msg': msg}
|
|
return data
|
|
|
|
#~ ToDo Agregar Condicion de pago y tags
|
|
|
|
row = {
|
|
'id': obj.id,
|
|
'rfc': obj.rfc,
|
|
'nombre': obj.nombre,
|
|
}
|
|
data = {'ok': True, 'row': row, 'new': True}
|
|
return data
|
|
|
|
@classmethod
|
|
def actualizar(cls, values, id):
|
|
fields = cls._clean(cls, values)
|
|
try:
|
|
q = Socios.update(**fields).where(Socios.id==id)
|
|
q.execute()
|
|
except IntegrityError:
|
|
msg = 'Ya existe el RFC y Razón Social'
|
|
data = {'ok': False, 'row': {}, 'new': True, 'msg': msg}
|
|
return data
|
|
|
|
row = {
|
|
'id': id,
|
|
'rfc': fields['rfc'],
|
|
'nombre': fields['nombre'],
|
|
}
|
|
data = {'ok': True, 'row': row, 'new': False}
|
|
return data
|
|
|
|
@classmethod
|
|
def remove(cls, id):
|
|
count = (Facturas
|
|
.select(fn.COUNT(Facturas.id)).join(Socios)
|
|
.where(Socios.id==id)
|
|
.count())
|
|
if count:
|
|
return False
|
|
|
|
q = Socios.delete().where(Socios.id==id)
|
|
return bool(q.execute())
|
|
|
|
|
|
class Productos(BaseModel):
|
|
categoria = ForeignKeyField(Categorias, null=True)
|
|
clave = TextField(unique=True, index=True)
|
|
clave_sat = TextField()
|
|
descripcion = TextField(index=True)
|
|
unidad = ForeignKeyField(SATUnidades)
|
|
valor_unitario = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
ultimo_costo = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
descuento = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
inventario = BooleanField(default=False)
|
|
existencia = DoubleField(default=0.0)
|
|
minimo = DoubleField(default=0.0)
|
|
codigo_barras = TextField(default='')
|
|
cuenta_predial = TextField(default='')
|
|
es_activo = BooleanField(default=True)
|
|
impuestos = ManyToManyField(SATImpuestos, related_name='productos')
|
|
tags = ManyToManyField(Tags, related_name='productos_tags')
|
|
|
|
class Meta:
|
|
order_by = ('descripcion',)
|
|
|
|
@classmethod
|
|
def next_key(cls):
|
|
value = Productos.select(fn.Max(Productos.id)).scalar()
|
|
if value is None:
|
|
value = 1
|
|
else:
|
|
value += 1
|
|
return {'value': value}
|
|
|
|
@classmethod
|
|
def get_by(cls, values):
|
|
id = int(values.get('id', 0))
|
|
if id:
|
|
row = (Productos
|
|
.select(Productos.id, Productos.clave, Productos.descripcion,
|
|
SATUnidades.name.alias('unidad'), Productos.valor_unitario)
|
|
.join(SATUnidades).switch(Productos)
|
|
.where(Productos.id==id).dicts())
|
|
if len(row):
|
|
model_pt = Productos.impuestos.get_through_model()
|
|
taxes = tuple(model_pt
|
|
.select(
|
|
model_pt.productos_id.alias('product'),
|
|
model_pt.satimpuestos_id.alias('tax'))
|
|
.where(model_pt.productos_id==id).dicts())
|
|
return {'ok': True, 'row': row[0], 'taxes': taxes}
|
|
return {'ok': False}
|
|
|
|
name = values.get('name', '')
|
|
if name:
|
|
rows = (Products
|
|
.select(Products.id, Products.key, Products.description,
|
|
SATUnidades.name.alias('unit'), Products.price)
|
|
.join(SATUnidades).switch(Products)
|
|
.where(Products.description.contains(name)).dicts())
|
|
return tuple(rows)
|
|
return {'ok': False}
|
|
|
|
@classmethod
|
|
def get_(cls, values):
|
|
if values:
|
|
id = int(values['id'])
|
|
row = (Productos
|
|
.select(
|
|
Productos.id,
|
|
Productos.es_activo.alias('es_activo_producto'),
|
|
Productos.categoria,
|
|
Productos.clave,
|
|
Productos.clave_sat,
|
|
Productos.descripcion,
|
|
Productos.unidad,
|
|
Productos.valor_unitario,
|
|
)
|
|
.where(Productos.id==id).dicts()[0]
|
|
)
|
|
obj = Productos.get(Productos.id==id)
|
|
taxes = [row.id for row in obj.impuestos]
|
|
return {'row': row, 'taxes': taxes}
|
|
|
|
rows = (Productos
|
|
.select(
|
|
Productos.id,
|
|
Productos.clave,
|
|
Productos.descripcion,
|
|
SATUnidades.name.alias('unidad'),
|
|
Productos.valor_unitario)
|
|
.join(SATUnidades)
|
|
.dicts()
|
|
)
|
|
return {'ok': True, 'rows': tuple(rows)}
|
|
|
|
def _clean(self, values):
|
|
taxes = util.loads(values.pop('taxes'))
|
|
fields = util.clean(values)
|
|
|
|
fields['es_activo'] = fields.pop('es_activo_producto')
|
|
fields['descripcion'] = util.spaces(fields['descripcion'])
|
|
fields['unidad'] = int(fields['unidad'])
|
|
fields['valor_unitario'] = fields['valor_unitario'].replace(
|
|
'$', '').replace(',', '')
|
|
|
|
fb = ('es_activo', 'inventario')
|
|
for name in fb:
|
|
fields[name] = bool(fields[name].replace('0', ''))
|
|
|
|
return fields, taxes
|
|
|
|
@classmethod
|
|
def add(cls, values):
|
|
fields, taxes = cls._clean(cls, values)
|
|
|
|
if Productos.select().where(Productos.clave==fields['clave']).exists():
|
|
msg = 'Clave ya existe'
|
|
return {'ok': False, 'msg': msg}
|
|
|
|
obj_taxes = SATImpuestos.select().where(SATImpuestos.id.in_(taxes))
|
|
|
|
with database_proxy.transaction():
|
|
obj = Productos.create(**fields)
|
|
obj.impuestos = obj_taxes
|
|
row = {
|
|
'id': obj.id,
|
|
'clave': obj.clave,
|
|
'descripcion': obj.descripcion,
|
|
'unidad': obj.unidad.name,
|
|
'valor_unitario': obj.valor_unitario,
|
|
}
|
|
data = {'ok': True, 'row': row, 'new': True}
|
|
return data
|
|
|
|
@classmethod
|
|
def actualizar(cls, values, id):
|
|
fields, taxes = cls._clean(cls, values)
|
|
obj_taxes = SATImpuestos.select().where(SATImpuestos.id.in_(taxes))
|
|
with database_proxy.transaction():
|
|
q = Productos.update(**fields).where(Productos.id==id)
|
|
try:
|
|
q.execute()
|
|
except IntegrityError:
|
|
msg = 'Ya existe un producto con esta clave'
|
|
data = {'ok': False, 'row': {}, 'new': False, 'msg': msg}
|
|
return data
|
|
|
|
obj = Productos.get(Productos.id==id)
|
|
obj.impuestos = obj_taxes
|
|
row = {
|
|
'id': obj.id,
|
|
'clave': obj.clave,
|
|
'descripcion': obj.descripcion,
|
|
'unidad': obj.unidad.name,
|
|
'valor_unitario': obj.valor_unitario,
|
|
}
|
|
data = {'ok': True, 'row': row, 'new': False}
|
|
return data
|
|
|
|
@classmethod
|
|
def remove(cls, id):
|
|
count = (FacturasDetalle
|
|
.select(fn.COUNT(FacturasDetalle.id)).join(Productos)
|
|
.where(Productos.id==id)
|
|
.count()
|
|
)
|
|
if count:
|
|
return False
|
|
|
|
with database_proxy.transaction():
|
|
obj = Productos.get(Productos.id==id)
|
|
obj.impuestos.clear()
|
|
obj.tags.clear()
|
|
q = Productos.delete().where(Productos.id==id)
|
|
return bool(q.execute())
|
|
|
|
|
|
class Facturas(BaseModel):
|
|
cliente = ForeignKeyField(Socios)
|
|
serie = TextField(default='')
|
|
folio = IntegerField(default=0)
|
|
fecha = DateTimeField(default=util.now)
|
|
fecha_timbrado = DateTimeField(null=True)
|
|
forma_pago = TextField(default='')
|
|
condiciones_pago = TextField(default='')
|
|
subtotal = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
descuento = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
moneda = TextField(default='MXN')
|
|
tipo_cambio = DecimalField(default=1.0, decimal_places=6, auto_round=True)
|
|
total = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
total_mn = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
tipo_comprobante = TextField(default='I')
|
|
metodo_pago = TextField(default='PUE')
|
|
lugar_expedicion = TextField(default='')
|
|
confirmacion = TextField(default='')
|
|
uso_cfdi = TextField(default='')
|
|
total_retenciones = DecimalField(
|
|
decimal_places=6, auto_round=True, null=True)
|
|
total_trasladados = DecimalField(
|
|
decimal_places=6, auto_round=True, null=True)
|
|
xml = TextField(default='')
|
|
uuid = UUIDField(null=True)
|
|
estatus = TextField(default='Guardada')
|
|
regimen_fiscal = TextField(default='')
|
|
notas = TextField(default='')
|
|
pagada = BooleanField(default=False)
|
|
error = TextField(default='')
|
|
|
|
class Meta:
|
|
order_by = ('fecha',)
|
|
|
|
|
|
class FacturasDetalle(BaseModel):
|
|
factura = ForeignKeyField(Facturas)
|
|
producto = ForeignKeyField(Productos, null=True)
|
|
cantidad = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
valor_unitario = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
descuento = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
precio_final = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
importe = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
descripcion = TextField(default='')
|
|
unidad = TextField(default='')
|
|
clave = TextField(default='')
|
|
clave_sat = TextField(default='')
|
|
categoria = TextField(default='')
|
|
aduana = TextField(default='')
|
|
pedimento = TextField(default='')
|
|
fecha_pedimento = DateField(null=True)
|
|
alumno = TextField(default='')
|
|
curp = TextField(default='')
|
|
nivel = TextField(default='')
|
|
autorizacion = TextField(default='')
|
|
cuenta_predial = TextField(default='')
|
|
|
|
class Meta:
|
|
order_by = ('factura',)
|
|
|
|
|
|
class FacturasImpuestos(BaseModel):
|
|
factura = ForeignKeyField(Facturas)
|
|
impuesto = ForeignKeyField(SATImpuestos)
|
|
base = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
importe = DecimalField(default=0.0, decimal_places=6, auto_round=True)
|
|
|
|
class Meta:
|
|
order_by = ('factura',)
|
|
indexes = (
|
|
(('factura', 'impuesto'), True),
|
|
)
|
|
|
|
|
|
def authenticate(args):
|
|
respuesta = {'login': False, 'msg': 'No Autorizado', 'user': ''}
|
|
values = util.get_con(args['rfc'])
|
|
if not values:
|
|
return respuesta
|
|
|
|
conectar(values)
|
|
try:
|
|
obj = Usuarios.get(usuario=args['usuario'], es_activo=True)
|
|
except Usuarios.DoesNotExist:
|
|
return respuesta
|
|
|
|
if not obj.contraseña.check_password(args['contra']):
|
|
return respuesta
|
|
|
|
obj.ultimo_ingreso = util.now()
|
|
obj.save()
|
|
respuesta['msg'] = ''
|
|
respuesta['login'] = True
|
|
respuesta['user'] = str(obj)
|
|
respuesta['super'] = obj.es_superusuario
|
|
#~ desconectar()
|
|
return respuesta
|
|
|
|
|
|
def get_cp(cp):
|
|
con = sqlite3.connect(PATH_CP)
|
|
cursor = con.cursor()
|
|
sql = """
|
|
SELECT colonia, municipio, estado
|
|
FROM colonias, municipios, estados
|
|
WHERE colonias.id_municipio=municipios.id
|
|
AND municipios.id_estado=estados.id
|
|
AND cp=?
|
|
ORDER BY colonia"""
|
|
cursor.execute(sql, (cp,))
|
|
rows = cursor.fetchall()
|
|
cursor.close()
|
|
con.close()
|
|
|
|
data = {}
|
|
if rows:
|
|
data = {
|
|
'estado': rows[0][2],
|
|
'municipio': rows[0][1],
|
|
}
|
|
if len(rows) == 1:
|
|
data['colonia'] = rows[0][0]
|
|
else:
|
|
data['colonia'] = [r[0] for r in rows]
|
|
return data
|
|
|
|
|
|
def get_sat_key(key):
|
|
return util.get_sat_key('products', key)
|
|
|
|
|
|
def _init_values():
|
|
data = (
|
|
{'key': 'version', 'value': VERSION},
|
|
{'key': 'rfc_publico', 'value': 'XAXX010101000'},
|
|
{'key': 'rfc_extranjero', 'value': 'XEXX010101000'},
|
|
)
|
|
for row in data:
|
|
try:
|
|
Configuration.create(**row)
|
|
except IntegrityError:
|
|
pass
|
|
log.info('Valores iniciales insertados...')
|
|
return
|
|
|
|
|
|
def _crear_tablas():
|
|
tablas = [Addendas, Categorias, Certificado, CondicionesPago, Configuracion,
|
|
Emisor, Facturas, FacturasDetalle, FacturasImpuestos, Folios, Productos,
|
|
SATAduanas, SATFormaPago, SATImpuestos, SATMonedas, SATRegimenes,
|
|
SATUnidades, SATUsoCfdi, Socios, Tags, Usuarios,
|
|
Emisor.regimenes.get_through_model(),
|
|
Socios.tags.get_through_model(),
|
|
Productos.impuestos.get_through_model(),
|
|
Productos.tags.get_through_model(),
|
|
]
|
|
database_proxy.create_tables(tablas, True)
|
|
log.info('Tablas creadas correctamente...')
|
|
return True
|
|
|
|
|
|
def migrate_tables():
|
|
connect()
|
|
log.info('Tablas migradas correctamente...')
|
|
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):
|
|
con = sqlite3.connect(COMPANIES)
|
|
cursor = con.cursor()
|
|
sql = """
|
|
INSERT INTO names
|
|
VALUES (?, ?)"""
|
|
try:
|
|
cursor.execute(sql, (rfc, args))
|
|
except sqlite3.IntegrityError as e:
|
|
log.error(e)
|
|
return False
|
|
|
|
con.commit()
|
|
cursor.close()
|
|
con.close()
|
|
return True
|
|
|
|
|
|
def _iniciar_bd():
|
|
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)
|
|
if _crear_tablas():
|
|
return
|
|
|
|
log.error('No se pudieron crear las tablas')
|
|
return
|
|
|
|
|
|
def _agregar_rfc():
|
|
rfc = input('Introduce el nuevo RFC: ').strip().upper()
|
|
if not rfc:
|
|
msg = 'El RFC es requerido'
|
|
log.error(msg)
|
|
return
|
|
|
|
datos = input('Introduce los datos de conexión: ').strip()
|
|
if not datos:
|
|
msg = 'Los datos de conexión son requeridos'
|
|
log.error(msg)
|
|
return
|
|
|
|
opt = util.parse_con(datos)
|
|
if not opt:
|
|
log.error('Datos de conexión incompletos')
|
|
return
|
|
|
|
args = opt.copy()
|
|
if conectar(args):
|
|
if _add_emisor(rfc, util.dumps(opt)) and _crear_tablas():
|
|
log.info('RFC agregado correctamente...')
|
|
return
|
|
|
|
log.error('No se pudo agregar el RFC')
|
|
return
|
|
|
|
|
|
def _listar_rfc():
|
|
data = util.get_rfcs()
|
|
for row in data:
|
|
msg = 'RFC: {}\n\t{}'.format(row[0], row[1])
|
|
log.info(msg)
|
|
return
|
|
|
|
|
|
def _importar_valores(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...')
|
|
regimen = ''
|
|
rows = util.loads(open(archivo, 'r').read())
|
|
for row in rows:
|
|
log.info('\tImportando tabla: {}'.format(row['tabla']))
|
|
if row['tabla'] == 'Emisor' and 'regimen' in row:
|
|
regimen = row['regimen']
|
|
table = globals()[row['tabla']]
|
|
for r in row['datos']:
|
|
try:
|
|
table.create(**r)
|
|
except IntegrityError:
|
|
pass
|
|
|
|
if regimen:
|
|
emisor = Emisor.select()[0]
|
|
regimen = SATRegimenes.get(SATRegimenes.key == regimen)
|
|
emisor.regimenes.clear()
|
|
emisor.regimenes.add(regimen)
|
|
|
|
log.info('Importación terminada...')
|
|
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'
|
|
|
|
@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('-rfc', '--rfc', help=help_rfc, 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('-a', '--archivo')
|
|
def main(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña, rfc,
|
|
borrar_rfc, listar_rfc, importar_valores, archivo):
|
|
opt = locals()
|
|
|
|
if opt['iniciar_bd']:
|
|
_iniciar_bd()
|
|
sys.exit(0)
|
|
|
|
if opt['migrar_bd']:
|
|
migrate_tables()
|
|
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['rfc']:
|
|
_agregar_rfc()
|
|
sys.exit(0)
|
|
|
|
if opt['borrar_rfc']:
|
|
_borrar_rfc()
|
|
sys.exit(0)
|
|
|
|
if opt['listar_rfc']:
|
|
_listar_rfc()
|
|
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)
|
|
|
|
_importar_valores(opt['archivo'])
|
|
sys.exit(0)
|
|
|
|
return
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|