Tablas para Nómina

This commit is contained in:
Mauricio Baeza 2018-01-14 20:28:19 -06:00
parent 9785c7a72c
commit 133aed9c85
4 changed files with 2421 additions and 9 deletions

View File

@ -260,6 +260,14 @@ def get_file(path):
return open(path, 'rb')
def get_files(path, ext='xml'):
docs = []
for folder, _, files in os.walk(path):
pattern = re.compile('\.{}'.format(ext), re.IGNORECASE)
docs += [os.path.join(folder,f) for f in files if pattern.search(f)]
return tuple(docs)
def read_file(path, mode='rb'):
return open(path, mode).read()
@ -308,6 +316,10 @@ def loads(data):
return json.loads(data)
def import_json(path):
return loads(read_file(path, 'r'))
def clean(values):
for k, v in values.items():
if isinstance(v, str):

View File

@ -17,7 +17,8 @@ if __name__ == '__main__':
from controllers import util
from settings import log, VERSION, PATH_CP, COMPANIES, PRE, CURRENT_CFDI, \
INIT_VALUES, DEFAULT_PASSWORD, DECIMALES, IMPUESTOS, DEFAULT_SAT_PRODUCTO, \
CANCEL_SIGNATURE, PUBLIC, DEFAULT_SERIE_TICKET, DECIMALES_TAX, TITLE_APP
CANCEL_SIGNATURE, PUBLIC, DEFAULT_SERIE_TICKET, CURRENT_CFDI_NOMINA, \
DEFAULT_SAT_NOMINA, DECIMALES_TAX, TITLE_APP
FORMAT = '{0:.2f}'
@ -650,6 +651,7 @@ class SATRegimenes(BaseModel):
class Emisor(BaseModel):
rfc = TextField(unique=True)
curp = TextField(unique=True)
nombre = TextField(default='')
nombre_comercial = TextField(default='')
calle = TextField(default='')
@ -675,6 +677,7 @@ class Emisor(BaseModel):
token_timbrado = TextField(default='')
token_soporte = TextField(default='')
logo = TextField(default='')
registro_patronal = TextField(default='')
regimenes = ManyToManyField(SATRegimenes, related_name='emisores')
def __str__(self):
@ -1843,6 +1846,208 @@ class SATUsoCfdi(BaseModel):
return tuple(rows)
class SATEstados(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
pais = TextField(default='')
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name', 'pais'), True),
)
def __str__(self):
return 'Estado: {} ({})'.format(self.name, self.key)
class SATOrigenRecurso(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Origen Recurso: {} ({})'.format(self.name, self.key)
class SATPeriodicidadPago(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Periodicidad de Pago: {} ({})'.format(self.name, self.key)
class SATTipoContrato(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Tipo de Contrato: {} ({})'.format(self.name, self.key)
class SATTipoDeduccion(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
clave = TextField(default='')
nombre = TextField(default='')
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Tipo de Deducción: {} ({})'.format(self.name, self.key)
class SATTipoHoras(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Tipo de Horas: {} ({})'.format(self.name, self.key)
class SATTipoIncapacidad(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Tipo de Incapacidad: {} ({})'.format(self.name, self.key)
class SATTipoJornada(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Tipo de Jornada: {} ({})'.format(self.name, self.key)
class SATTipoNomina(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Tipo de Nómina: {} ({})'.format(self.name, self.key)
class SATTipoOtroPago(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
clave = TextField(default='')
nombre = TextField(default='')
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Tipo de Otro Pago: {} ({})'.format(self.name, self.key)
class SATTipoPercepcion(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
clave = TextField(default='')
nombre = TextField(default='')
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Tipo de Percepción: {} ({})'.format(self.name, self.key)
class SATTipoRegimen(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Regimen de contratación: {} ({})'.format(self.name, self.key)
class SATRiesgoPuesto(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
activo = BooleanField(default=True)
class Meta:
order_by = ('name',)
indexes = (
(('key', 'name'), True),
)
def __str__(self):
return 'Riesgo Puesto: {} ({})'.format(self.name, self.key)
class TipoCambio(BaseModel):
dia = DateField(default=util.now)
moneda = ForeignKeyField(SATMonedas)
@ -4975,6 +5180,275 @@ class SeriesProductos(BaseModel):
order_by = ('serie',)
class Departamentos(BaseModel):
nombre = TextField(default='')
descripcion = TextField(default='')
class Meta:
order_by = ('nombre',)
class Puestos(BaseModel):
nombre = TextField(default='')
descripcion = TextField(default='')
departamento = ForeignKeyField(Departamentos)
class Meta:
order_by = ('nombre',)
indexes = (
(('nombre', 'departamento'), True),
)
class Empleados(BaseModel):
num_empleado = TextField(default='')
rfc = TextField(default='', unique=True)
curp = TextField(default='', unique=True)
nombre = TextField(default='')
paterno = TextField(default='')
materno = TextField(default='')
nombre_completo = TextField(default='')
es_activo = BooleanField(default=True)
es_extranjero = BooleanField(default=False)
fecha_alta = DateField(default=util.now)
fecha_ingreso = DateField(default=util.now)
imss = TextField(default='')
tipo_contrato = ForeignKeyField(SATTipoContrato)
es_sindicalizado = BooleanField(default=False)
tipo_jornada = ForeignKeyField(SATTipoJornada, null=True)
tipo_regimen = ForeignKeyField(SATTipoRegimen)
puesto = ForeignKeyField(Puestos, null=True)
riesgo_puesto = ForeignKeyField(SATRiesgoPuesto, null=True)
periodicidad_pago = ForeignKeyField(SATPeriodicidadPago)
banco = ForeignKeyField(SATBancos, null=True)
cuenta_bancaria = TextField(default='')
clabe = TextField(default='')
salario_base = DecimalField(default=0.0, max_digits=18, decimal_places=6,
auto_round=True)
salario_diario = DecimalField(default=0.0, max_digits=18, decimal_places=6,
auto_round=True)
estado = ForeignKeyField(SATEstados)
codigo_postal = TextField(default='')
notas = TextField(default='')
class Meta:
order_by = ('nombre_completo',)
indexes = (
(('num_empleado', 'rfc'), True),
)
class CfdiNomina(BaseModel):
empleado = ForeignKeyField(Empleados)
version = TextField(default=CURRENT_CFDI)
serie = TextField(default='')
folio = IntegerField(default=0)
fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S'])
fecha_timbrado = DateTimeField(null=True)
forma_pago = TextField(default='')
condiciones_pago = TextField(default='')
subtotal = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
descuento = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
moneda = TextField(default='MXN')
tipo_cambio = DecimalField(default=1.0, max_digits=15, decimal_places=6,
auto_round=True)
total = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_mn = DecimalField(default=0.0, max_digits=20, 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(
max_digits=20, decimal_places=6, auto_round=True, null=True)
total_trasladados = DecimalField(
max_digits=20, decimal_places=6, auto_round=True, null=True)
xml = TextField(default='')
uuid = UUIDField(null=True)
estatus = TextField(default='Guardada')
estatus_sat = TextField(default='Vigente')
regimen_fiscal = TextField(default='')
notas = TextField(default='')
saldo = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
pagada = BooleanField(default=False)
cancelada = BooleanField(default=False)
fecha_cancelacion = DateTimeField(null=True)
acuse = TextField(default='')
tipo_relacion = TextField(default='')
error = TextField(default='')
version = TextField(default=CURRENT_CFDI_NOMINA)
registro_patronal = TextField(default='')
rfc_patron_origen = TextField(default='')
tipo_nomina = ForeignKeyField(SATTipoNomina)
fecha_pago = DateField()
fecha_inicial_pago = DateField()
fecha_final_pago = DateField()
dias_pagados = DecimalField(default=0.0, max_digits=12, decimal_places=2,
auto_round=True)
origen_recurso = ForeignKeyField(SATOrigenRecurso, null=True)
monto_recurso_propio = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
class Meta:
order_by = ('fecha',)
class CfdiNominaDetalle(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
clave_sat = TextField(default=DEFAULT_SAT_NOMINA['CLAVE'])
cantidad = DecimalField(default=1.0, max_digits=18, decimal_places=6,
auto_round=True)
clave_unidad = TextField(default=DEFAULT_SAT_NOMINA['UNIDAD'])
descripcion = TextField(default=DEFAULT_SAT_NOMINA['DESCRIPCION'])
valor_unitario = DecimalField(default=0.0, max_digits=18, decimal_places=6,
auto_round=True)
importe = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
descuento = DecimalField(default=0.0, max_digits=18, decimal_places=6,
auto_round=True)
class Meta:
order_by = ('cfdi',)
class CfdiNominaTotales(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
subtotal = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
descuento = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_percepciones = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
total_gravado = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_exento = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_deducciones = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_otros_pagos = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_sueldos = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_separacion = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_jubilacion = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_retenciones = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
total_otras_deducciones = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
total = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
class CfdiNominaJubilacion(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
total_una_exhibicion = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
total_parcialidad = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
monto_diario = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
ingreso_acumulable = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
ingreso_no_acumulable = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
class CfdiNominaSeparacion(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
total_pagado = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
years_servicio = IntegerField(default=0)
ultimo_sueldo = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
ingreso_acumulable = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
ingreso_no_acumulable = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
class CfdiNominaPercepciones(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
tipo_percepcion = ForeignKeyField(SATTipoPercepcion)
importe_gravado = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
importe_exento = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
valor_mercado = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
precio_al_ortorgarse = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
class CfdiNominaDeducciones(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
tipo_deduccion = ForeignKeyField(SATTipoDeduccion)
importe = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
class CfdiNominaOtroPago(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
tipo_otro_pago = ForeignKeyField(SATTipoOtroPago)
importe = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
subsidio_causado = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
saldo_a_favor = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
year = IntegerField(default=0)
remanente_saldo = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
class CfdiNominaIncapacidad(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
dias = IntegerField(default=0)
tipo = ForeignKeyField(SATTipoIncapacidad)
importe = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
class CfdiNominaHorasExtra(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
dias = IntegerField(default=0)
tipos_horas = ForeignKeyField(SATTipoHoras)
horas_extra = IntegerField(default=0)
importe_pagado = DecimalField(default=0.0, max_digits=20,
decimal_places=6, auto_round=True)
class CfdiNominaSubcontratos(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
rfc = TextField(default='')
porcentaje = DecimalField(default=0.0, max_digits=12, decimal_places=2,
auto_round=True)
class Meta:
order_by = ('cfdi',)
class CfdiNominaOtros(BaseModel):
cfdi = ForeignKeyField(CfdiNomina)
node = TextField(default='')
key = TextField(default='')
value = TextField(default='')
class CfdiNominaRelacionados(BaseModel):
cfdi = ForeignKeyField(CfdiNomina, related_name='original')
cfdi_origen = ForeignKeyField(CfdiNomina, related_name='relacion')
class Meta:
order_by = ('cfdi',)
def authenticate(args):
respuesta = {'login': False, 'msg': 'No Autorizado', 'user': ''}
values = util.get_con(args['rfc'])
@ -5114,14 +5588,22 @@ def _crear_tablas(rfc):
PreFacturasRelacionadas, Tickets, TicketsDetalle, TicketsImpuestos,
SATAduanas, SATFormaPago, SATImpuestos, SATMonedas, SATRegimenes,
SATTipoRelacion, SATUnidades, SATUsoCfdi, SATBancos,
SATNivelesEducativos,
Socios, Contactos, ContactoCorreos, ContactoDirecciones,
ContactoTelefonos,
SATNivelesEducativos, SATEstados, SATRiesgoPuesto, SATPeriodicidadPago,
SATOrigenRecurso, SATTipoContrato, SATTipoDeduccion, SATTipoHoras,
SATTipoIncapacidad, SATTipoJornada, SATTipoNomina, SATTipoOtroPago,
SATTipoPercepcion, SATTipoRegimen,
Socios, Contactos, ContactoCorreos, ContactoDirecciones, Empleados,
ContactoTelefonos, Departamentos, Puestos,
Tags, Usuarios, CuentasBanco, TipoCambio, MovimientosBanco,
TipoCorreo, TipoDireccion, TipoPariente, TipoResponsable, TipoTelefono,
TipoTitulo, TipoMovimientoAlumno, TipoMovimientoAlmacen,
CfdiPagos, NivelesEducativos, Alumnos, AlumnosParientes, Grupos,
ParienteDirecciones, ParienteTelefonos, ParienteCorreos,
CfdiNomina, CfdiNominaDeducciones, CfdiNominaDetalle,
CfdiNominaHorasExtra, CfdiNominaIncapacidad, CfdiNominaJubilacion,
CfdiNominaOtroPago, CfdiNominaOtros, CfdiNominaPercepciones,
CfdiNominaRelacionados, CfdiNominaSeparacion, CfdiNominaSubcontratos,
CfdiNominaTotales,
Emisor.regimenes.get_through_model(),
Socios.tags.get_through_model(),
Productos.impuestos.get_through_model(),
@ -5166,7 +5648,16 @@ def _migrate_tables():
conectar(args)
tablas = [Sucursales]
tablas = [Sucursales, SATEstados, SATRiesgoPuesto, SATPeriodicidadPago,
SATOrigenRecurso, SATTipoContrato, SATTipoDeduccion, SATTipoHoras,
SATTipoIncapacidad, SATTipoJornada, SATTipoNomina, SATTipoOtroPago,
SATTipoPercepcion, SATTipoRegimen, Departamentos, Puestos, Empleados,
CfdiNomina, CfdiNominaDeducciones, CfdiNominaDetalle,
CfdiNominaHorasExtra, CfdiNominaIncapacidad, CfdiNominaJubilacion,
CfdiNominaOtroPago, CfdiNominaOtros, CfdiNominaPercepciones,
CfdiNominaRelacionados, CfdiNominaSeparacion, CfdiNominaSubcontratos,
CfdiNominaTotales,
]
log.info('Creando nuevas tablas...')
database_proxy.create_tables(tablas, True)
log.info('Tablas creadas correctamente...')
@ -5175,12 +5666,23 @@ def _migrate_tables():
migrations = []
migrator = PostgresqlMigrator(database_proxy)
sucursal = ForeignKeyField(Sucursales, null=True, to_field=Sucursales.id)
columns = [c.name for c in database_proxy.get_columns('usuarios')]
if not 'sucursal_id' in columns:
sucursal = ForeignKeyField(Sucursales, null=True, to_field=Sucursales.id)
migrations.append(
migrator.add_column('usuarios', 'sucursal_id', sucursal))
columns = [c.name for c in database_proxy.get_columns('emisor')]
if not 'registro_patronal' in columns:
registro_patronal = TextField(default='')
migrations.append(
migrator.add_column(
'emisor', 'registro_patronal', registro_patronal))
if not 'curp' in columns:
curp = TextField(default='')
migrations.append(
migrator.add_column('emisor', 'curp', curp))
if migrations:
with database_proxy.atomic() as txn:
migrate(*migrations)
@ -5732,7 +6234,7 @@ def _importar_factura_libre_gambas(conexion):
_importar_socios(data['Socios'])
_importar_facturas(data['Facturas'])
_importar_categorias(data['Categorias'])
# ~ _importar_productos_gambas(data['Productos'])
_importar_productos_gambas(data['Productos'])
_import_tickets(data['Tickets'])
log.info('Importación terminada...')
@ -5907,6 +6409,41 @@ def _importar_productos(archivo):
return
def _import_from_folder(path):
files = util.get_files(path, 'json')
if not files:
msg = 'No se encontraron archivos para importar'
log.error(msg)
return
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 valores...')
for p in files:
msg = '\tImportando tabla: {}'
data = util.import_json(p)
log.info(msg.format(data['tabla']))
table = globals()[data['tabla']]
for r in data['datos']:
try:
with database_proxy.atomic() as txn:
table.create(**r)
except IntegrityError:
pass
log.info('Valores importados...')
return
def _test():
rfc = input('Introduce el RFC: ').strip().upper()
if not rfc:
@ -5957,10 +6494,12 @@ help_lr = 'Listar RFCs'
@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')
def main(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña,
agregar_rfc, borrar_rfc, listar_rfc, importar_valores, archivo, conexion,
factura_libre, factura_libre_gambas, test, generar_archivo_productos,
importar_productos, backup_dbs, no_bd, alta, rfc, detalle):
importar_productos, backup_dbs, no_bd, alta, rfc, detalle,
importar_directorio):
opt = locals()
@ -6066,6 +6605,9 @@ def main(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña,
_importar_productos(opt['archivo'])
sys.exit(0)
if opt['importar_directorio']:
_import_from_folder(opt['importar_directorio'])
if opt['backup_dbs']:
util.backup_dbs()

View File

@ -115,6 +115,7 @@ PRE = {
}
CURRENT_CFDI = '3.3'
CURRENT_CFDI_NOMINA = '1.2'
DECIMALES = 2
DECIMALES_TAX = 4
IMPUESTOS = {
@ -134,4 +135,9 @@ DEFAULT_SERIE_TICKET = 'T'
DIR_FACTURAS = 'facturas'
USAR_TOKEN = False
CANCEL_SIGNATURE = False
PUBLIC = 'Público en general'
PUBLIC = 'Público en general'
DEFAULT_SAT_NOMINA = {
'CLAVE': '84111505',
'UNIDAD': 'ACT',
'DESCRIPCION': 'Pago de nómina',
}

File diff suppressed because it is too large Load Diff