from datetime import date, timedelta from typing import List from KeRS.celery import app from events.models import Event, EventRegistration, TimeSlot from users.models import CustomUser def calc_score(user: CustomUser): registrations_last_month: List[EventRegistration] = EventRegistration.objects \ .filter(user_id=user.id, time_slot__event__date__gt=date.today() - timedelta(days=30), time_slot__event__date__lte=date.today(), state=EventRegistration.ADMITTED) score = 0 for r in registrations_last_month: days_ago = (date.today() - r.time_slot.event.date).days score += 1 / (days_ago + 1) return score @app.task(bind=True) def assign_reservations(self, dry_run=False): """ Check if there are any events the next day. If so, calculate the current score for every interested user and assign the ones with the lowest scores. :param dry_run: If this is set to true, no persistent changes will be made. :return: """ print("Assigning reservations") print("======================") # Get all events of tomorrow events: List[Event] = Event.objects.filter(date=date.today() + timedelta(days=1)) # Get all timeslots of tomorrow timeslots: List[TimeSlot] = TimeSlot.objects.filter(event_id__in=map(lambda e: e.id, events)) # Reservations registrations: List[EventRegistration] = EventRegistration.objects.filter( time_slot_id__in=map(lambda timeslot: timeslot.id, timeslots), state=EventRegistration.INTERESTED) if len(registrations) == 0: print("NO REGISTRATIONS?") # Relevant users users = set(map(lambda r: r.user, registrations)) scores = list(map(calc_score, users)) queue = sorted(list(zip(users, scores)), key=lambda tup: tup[1]) print(f"Scores: {scores}") print(f"Queue: {queue}") for timeslot in timeslots: print(f"EVENT: {timeslot.event.date} - {timeslot.event.capacity}") timeslot_registrations = list(filter(lambda r: r.time_slot == timeslot, registrations)) timeslot_users = set(map(lambda r: r.user, timeslot_registrations)) timeslot_queue = list(filter(lambda element: element[0] in timeslot_users, queue)) for user in timeslot_queue[0:timeslot.event.capacity]: print(f"Selected {user[0]}") r = EventRegistration.objects.get( time_slot_id=timeslot.id, user_id=user[0].id ) r.state = EventRegistration.ADMITTED if not dry_run: r.save()