Files
pagasis/backend/process_attendance.py
T
2025-10-21 22:08:48 -06:00

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)