forked from val-lop20/Pagina-de-Asistencia-MAC
199 lines
6.9 KiB
Python
199 lines
6.9 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Script para procesar asistencias desde Excel y agregarlas a la base de datos.
|
|
"""
|
|
import os
|
|
import sys
|
|
import django
|
|
import pandas as pd
|
|
from datetime import datetime
|
|
|
|
# Configurar Django
|
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mac_attendance.settings')
|
|
django.setup()
|
|
|
|
from django.contrib.auth.models import User
|
|
from authentication.models import UserProfile
|
|
from events.models import Event
|
|
from attendance.models import Attendance, AttendanceStats
|
|
from django.utils import timezone
|
|
|
|
|
|
def process_attendance_file(excel_file, event_title, assistant_username):
|
|
"""
|
|
Procesa el archivo de asistencias y las agrega a la base de datos.
|
|
|
|
Args:
|
|
excel_file: Ruta al archivo Excel
|
|
event_title: Título de la conferencia/evento
|
|
assistant_username: Username del asistente que registra
|
|
"""
|
|
print("=" * 80)
|
|
print("PROCESANDO ASISTENCIAS")
|
|
print("=" * 80)
|
|
print()
|
|
|
|
# 1. Verificar que el evento existe
|
|
print(f"[1/5] Buscando evento: '{event_title}'...")
|
|
try:
|
|
event = Event.objects.get(title=event_title)
|
|
print(f"✓ Evento encontrado: {event.title} (ID: {event.id})")
|
|
print(f" Fecha: {event.date}")
|
|
print(f" Tipo: {event.event_type}")
|
|
except Event.DoesNotExist:
|
|
print(f"✗ ERROR: No se encontró el evento '{event_title}'")
|
|
print("\nEventos disponibles:")
|
|
for ev in Event.objects.all():
|
|
print(f" - {ev.title} ({ev.date})")
|
|
return
|
|
print()
|
|
|
|
# 2. Verificar que el asistente existe
|
|
print(f"[2/5] Buscando asistente: '{assistant_username}'...")
|
|
try:
|
|
assistant_user = User.objects.get(username=assistant_username)
|
|
assistant_profile = UserProfile.objects.get(user=assistant_user, user_type='assistant')
|
|
print(f"✓ Asistente encontrado: {assistant_profile.full_name}")
|
|
print(f" Username: {assistant_user.username}")
|
|
except (User.DoesNotExist, UserProfile.DoesNotExist):
|
|
print(f"✗ ERROR: No se encontró el asistente '{assistant_username}'")
|
|
print("\nAsistentes disponibles:")
|
|
for profile in UserProfile.objects.filter(user_type='assistant'):
|
|
print(f" - {profile.user.username}: {profile.full_name}")
|
|
return
|
|
print()
|
|
|
|
# 3. Leer archivo Excel
|
|
print(f"[3/5] Leyendo archivo: {excel_file}...")
|
|
try:
|
|
df = pd.read_excel(excel_file)
|
|
print(f"✓ Archivo leído correctamente")
|
|
print(f" Total de registros: {len(df)}")
|
|
print(f" Columnas: {list(df.columns)}")
|
|
except Exception as e:
|
|
print(f"✗ ERROR al leer el archivo: {e}")
|
|
return
|
|
print()
|
|
|
|
# 4. Procesar cada registro
|
|
print(f"[4/5] Procesando asistencias...")
|
|
print()
|
|
|
|
created_count = 0
|
|
skipped_count = 0
|
|
error_count = 0
|
|
updated_students = []
|
|
|
|
for idx, row in df.iterrows():
|
|
account_number_raw = str(row['account_number']).strip()
|
|
name_in_excel = str(row['full_name']).strip()
|
|
|
|
# Normalizar número de cuenta: quitar espacios y tomar solo los primeros 8 dígitos
|
|
account_number = account_number_raw.replace(' ', '').replace('-', '')[:8]
|
|
|
|
print(f" [{idx+1}/{len(df)}] Procesando: {account_number} (original: {account_number_raw}) - {name_in_excel}")
|
|
|
|
# Buscar el estudiante en la BD
|
|
try:
|
|
student_profile = UserProfile.objects.get(
|
|
account_number=account_number,
|
|
user_type='student'
|
|
)
|
|
|
|
# Verificar si el nombre coincide
|
|
if student_profile.full_name != name_in_excel:
|
|
print(f" ⚠ Nombre diferente en BD: '{student_profile.full_name}'")
|
|
else:
|
|
print(f" ✓ Estudiante encontrado: {student_profile.full_name}")
|
|
|
|
# Verificar si ya existe el registro de asistencia
|
|
existing = Attendance.objects.filter(
|
|
student=student_profile,
|
|
event=event
|
|
).first()
|
|
|
|
if existing:
|
|
print(f" ⊘ Ya existe registro de asistencia - OMITIDO")
|
|
skipped_count += 1
|
|
continue
|
|
|
|
# Crear el registro de asistencia con skip_validation
|
|
attendance = Attendance(
|
|
student=student_profile,
|
|
event=event,
|
|
timestamp=timezone.now(),
|
|
registered_by=assistant_profile,
|
|
registration_method='manual',
|
|
notes=f'Importado desde Excel: {os.path.basename(excel_file)}',
|
|
is_valid=True
|
|
)
|
|
# Guardar omitiendo validaciones de tiempo
|
|
attendance.save(skip_validation=True)
|
|
|
|
print(f" ✓ Asistencia creada (ID: {attendance.id})")
|
|
created_count += 1
|
|
updated_students.append(student_profile)
|
|
|
|
except UserProfile.DoesNotExist:
|
|
print(f" ✗ ERROR: Estudiante no encontrado en BD - {account_number}")
|
|
error_count += 1
|
|
except Exception as e:
|
|
print(f" ✗ ERROR: {str(e)}")
|
|
error_count += 1
|
|
|
|
print()
|
|
|
|
# 5. Actualizar estadísticas
|
|
print(f"[5/5] Actualizando estadísticas de asistencia...")
|
|
print()
|
|
|
|
for student_profile in set(updated_students): # Eliminar duplicados
|
|
try:
|
|
# Obtener o crear las estadísticas del estudiante
|
|
stats, created = AttendanceStats.objects.get_or_create(
|
|
student=student_profile
|
|
)
|
|
|
|
# Calcular estadísticas
|
|
total_events = Event.objects.filter(is_active=True).count()
|
|
attended = Attendance.objects.filter(
|
|
student=student_profile,
|
|
is_valid=True
|
|
).values('event').distinct().count()
|
|
|
|
percentage = (attended / total_events * 100) if total_events > 0 else 0
|
|
|
|
# Actualizar
|
|
stats.total_events = total_events
|
|
stats.attended_events = attended
|
|
stats.attendance_percentage = round(percentage, 2)
|
|
stats.last_updated = timezone.now()
|
|
stats.save()
|
|
|
|
print(f" ✓ {student_profile.full_name}: {attended}/{total_events} eventos ({percentage:.2f}%)")
|
|
|
|
except Exception as e:
|
|
print(f" ✗ Error al actualizar {student_profile.full_name}: {e}")
|
|
|
|
print()
|
|
print("=" * 80)
|
|
print("RESUMEN")
|
|
print("=" * 80)
|
|
print(f" Asistencias creadas: {created_count}")
|
|
print(f" Registros omitidos: {skipped_count} (ya existían)")
|
|
print(f" Errores: {error_count}")
|
|
print(f" Total procesados: {len(df)}")
|
|
print()
|
|
print("✓ Proceso completado")
|
|
print("=" * 80)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Parámetros
|
|
EXCEL_FILE = "/app/Asistencias_Procesadas.xlsx"
|
|
EVENT_TITLE = "Tecnologías IIoT al servicio de la Industria"
|
|
ASSISTANT_USERNAME = "asst_11111111" # El único asistente que hay
|
|
|
|
process_attendance_file(EXCEL_FILE, EVENT_TITLE, ASSISTANT_USERNAME)
|