new file: generar_unificado.py modified: routes_admin.py modified: routes_worker.py modified: templates/admin_rendiciones.html new file: templates/admin_report_horarios.html modified: templates/macros/modals.html modified: templates/worker_dashboard.html modified: templates/worker_history.html
185 lines
8.0 KiB
Python
185 lines
8.0 KiB
Python
import random
|
|
from datetime import date, timedelta
|
|
from werkzeug.security import generate_password_hash
|
|
from database import get_db_connection, init_db
|
|
|
|
def generar_historico_definitivo(dias_atras=180):
|
|
init_db()
|
|
conn = get_db_connection()
|
|
c = conn.cursor()
|
|
|
|
# 1. LIMPIEZA TOTAL (Evita el choque con los datos por defecto de database.py)
|
|
print("Limpiando datos de prueba anteriores...")
|
|
c.execute("DELETE FROM rendicion_items")
|
|
c.execute("DELETE FROM rendiciones")
|
|
c.execute("DELETE FROM workers WHERE is_admin = 0")
|
|
conn.commit()
|
|
|
|
c.execute("SELECT id, name FROM modulos")
|
|
modulos = c.fetchall()
|
|
|
|
if not modulos:
|
|
print("Error: No hay módulos creados.")
|
|
return
|
|
|
|
# 2. RECLUTAMIENTO FORZADO PARA TODOS LOS MÓDULOS
|
|
print(f"Reclutando personal para {len(modulos)} módulos...")
|
|
default_pass = generate_password_hash("123456")
|
|
workers_data = []
|
|
|
|
for mod_id, mod_name in modulos:
|
|
tipos = ["Full Time", "Full Time", "Part Time", "Part Time"]
|
|
for i in range(4):
|
|
# Usamos un RUT fijo basado en la iteración para no inflar la DB si lo corres sin limpiar
|
|
rut_falso = f"{10 + i}.{mod_id:03d}.100-{i}"
|
|
nombre_falso = f"Trabajador {i+1} ({mod_name})"
|
|
phone_falso = f"+56 9 8888 {mod_id:02d}{i:02d}"
|
|
|
|
workers_data.append((
|
|
rut_falso, nombre_falso, phone_falso,
|
|
default_pass, 0, mod_id, tipos[i]
|
|
))
|
|
|
|
c.executemany('''INSERT OR IGNORE INTO workers
|
|
(rut, name, phone, password_hash, is_admin, modulo_id, tipo)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)''', workers_data)
|
|
conn.commit()
|
|
|
|
# 3. PREPARACIÓN DE DATOS
|
|
c.execute("SELECT id, modulo_id FROM workers WHERE is_admin = 0")
|
|
all_workers_data = c.fetchall()
|
|
todos_los_trabajadores = [w[0] for w in all_workers_data]
|
|
|
|
trabajadores_por_modulo = {}
|
|
for w_id, m_id in all_workers_data:
|
|
if m_id not in trabajadores_por_modulo:
|
|
trabajadores_por_modulo[m_id] = []
|
|
trabajadores_por_modulo[m_id].append(w_id)
|
|
|
|
c.execute("SELECT id, price, commission FROM productos")
|
|
productos = c.fetchall()
|
|
|
|
# 4. VIAJE EN EL TIEMPO
|
|
hoy = date.today()
|
|
fecha_inicio = hoy - timedelta(days=dias_atras)
|
|
rendiciones_creadas = 0
|
|
|
|
# Textos de ejemplo para los gastos
|
|
motivos_gastos = [
|
|
"Compra bidón de agua",
|
|
"Artículos de aseo",
|
|
"Lápices y cuaderno",
|
|
"Reparación menor del módulo",
|
|
"Bolsas para entregar productos",
|
|
"Cinta adhesiva",
|
|
"Pilas para escáner"
|
|
]
|
|
|
|
print(f"Generando turnos con gastos aleatorios desde {fecha_inicio} hasta {hoy}...")
|
|
|
|
for i in range(dias_atras + 1):
|
|
fecha_actual = fecha_inicio + timedelta(days=i)
|
|
fecha_str = fecha_actual.strftime('%Y-%m-%d')
|
|
|
|
for modulo_id, mod_name in modulos:
|
|
workers_modulo = trabajadores_por_modulo.get(modulo_id, [])
|
|
if not workers_modulo:
|
|
continue
|
|
|
|
num_turnos = random.randint(1, 2)
|
|
turnos_a_hacer = [True, False] if num_turnos == 2 else [random.choice([True, False])]
|
|
|
|
for es_manana in turnos_a_hacer:
|
|
# Reemplazos (15%)
|
|
es_reemplazo = random.random() < 0.15
|
|
if es_reemplazo and len(todos_los_trabajadores) > len(workers_modulo):
|
|
posibles_reemplazos = [w for w in todos_los_trabajadores if w not in workers_modulo]
|
|
worker_id = random.choice(posibles_reemplazos)
|
|
else:
|
|
worker_id = random.choice(workers_modulo)
|
|
|
|
if es_manana:
|
|
hora_entrada = f"{random.randint(8, 10):02d}:{random.choice(['00', '30'])}"
|
|
hora_salida = f"{random.randint(14, 16):02d}:{random.choice(['00', '30'])}"
|
|
else:
|
|
hora_entrada = f"{random.randint(13, 15):02d}:{random.choice(['00', '30'])}"
|
|
hora_salida = f"{random.randint(19, 21):02d}:{random.choice(['00', '30'])}"
|
|
|
|
# Acompañante (70%)
|
|
companion_id = None
|
|
comp_in, comp_out = None, None
|
|
if random.random() < 0.70:
|
|
posibles_comp = [w for w in todos_los_trabajadores if w != worker_id]
|
|
if posibles_comp:
|
|
companion_id = random.choice(posibles_comp)
|
|
comp_in, comp_out = hora_entrada, hora_salida
|
|
|
|
num_prods = random.randint(1, 5)
|
|
prods_elegidos = random.sample(productos, min(num_prods, len(productos)))
|
|
items_a_insertar = []
|
|
total_calculado = 0
|
|
|
|
for prod in prods_elegidos:
|
|
p_id, p_price, p_comm = prod
|
|
cantidad = random.randint(1, 6)
|
|
items_a_insertar.append((p_id, cantidad, p_price, p_comm))
|
|
total_calculado += (p_price * cantidad)
|
|
|
|
debito, credito, mp, efectivo = 0, 0, 0, 0
|
|
b_debito, b_credito, b_mp, b_efectivo = 0, 0, 0, 0
|
|
|
|
divisiones = random.randint(1, 3)
|
|
monto_restante = int(total_calculado)
|
|
metodos = ["debito", "credito", "mp", "efectivo"]
|
|
random.shuffle(metodos)
|
|
|
|
for idx, metodo in enumerate(metodos[:divisiones]):
|
|
monto = monto_restante if idx == divisiones - 1 else random.randint(0, monto_restante // 2)
|
|
monto_restante -= monto
|
|
|
|
if monto > 0:
|
|
boletas = random.randint(1, 4)
|
|
if metodo == "debito": debito, b_debito = monto, boletas
|
|
elif metodo == "credito": credito, b_credito = monto, boletas
|
|
elif metodo == "mp": mp, b_mp = monto, boletas
|
|
elif metodo == "efectivo": efectivo, b_efectivo = monto, boletas
|
|
|
|
tipo_registro = "Reemplazo histórico" if es_reemplazo else "Turno histórico"
|
|
|
|
# === LÓGICA DE GASTOS RANDOM ===
|
|
# 15% de probabilidad de tener un gasto en el turno (entre $2.000 y $15.000)
|
|
gastos = 0
|
|
if random.random() < 0.15:
|
|
gastos = random.randint(2, 15) * 1000
|
|
tipo_registro += f" | {random.choice(motivos_gastos)}"
|
|
|
|
c.execute('''
|
|
INSERT INTO rendiciones
|
|
(worker_id, companion_id, modulo_id, fecha, hora_entrada, hora_salida,
|
|
companion_hora_entrada, companion_hora_salida,
|
|
venta_debito, venta_credito, venta_mp, venta_efectivo,
|
|
boletas_debito, boletas_credito, boletas_mp, boletas_efectivo,
|
|
gastos, observaciones, worker_comision, companion_comision)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)
|
|
''', (worker_id, companion_id, modulo_id, fecha_str, hora_entrada, hora_salida,
|
|
comp_in, comp_out, debito, credito, mp, efectivo,
|
|
b_debito, b_credito, b_mp, b_efectivo,
|
|
gastos, tipo_registro, 1 if companion_id else 0))
|
|
|
|
r_id = c.lastrowid
|
|
|
|
for item in items_a_insertar:
|
|
p_id, cant, p_price, p_comm = item
|
|
c.execute('''
|
|
INSERT INTO rendicion_items (rendicion_id, producto_id, cantidad, precio_historico, comision_historica)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
''', (r_id, p_id, cant, p_price, p_comm))
|
|
|
|
rendiciones_creadas += 1
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
print(f"Éxito: Se inyectaron {rendiciones_creadas} rendiciones para TODOS los módulos.")
|
|
|
|
if __name__ == '__main__':
|
|
generar_historico_definitivo(180) |