From 83fd04082b9510578c0ddcae5aea1026d2d29514 Mon Sep 17 00:00:00 2001
From: Ernesto Rico Schmidt <ernesto@helsinki.at>
Date: Wed, 15 Feb 2023 17:16:47 -0400
Subject: [PATCH] Refactor generate_timeslots to not use ids/pks

---
 program/models.py | 96 +++++++++++++++++++++++------------------------
 1 file changed, 46 insertions(+), 50 deletions(-)

diff --git a/program/models.py b/program/models.py
index 8a0b3232..58d52d66 100644
--- a/program/models.py
+++ b/program/models.py
@@ -19,7 +19,6 @@
 #
 
 from datetime import datetime, time, timedelta
-from textwrap import dedent
 
 from dateutil.relativedelta import relativedelta
 from dateutil.rrule import rrule
@@ -401,63 +400,64 @@ class Schedule(models.Model):
         Returns a list of timeslot objects based on a schedule and its rrule
         Returns past timeslots as well, starting from first_date (not today)
         """
-
-        by_week_no = None
-        by_week_no_end = None
-        by_weekday_end = int(schedule.by_weekday)
-        starts = []
-        ends = []
         timeslots = []
-        # Handle ending weekday for timeslots over midnight
-        if schedule.end_time < schedule.start_time:
-            if schedule.by_weekday < 6:
-                by_weekday_end = int(schedule.by_weekday + 1)
-            else:
-                by_weekday_end = 0
 
-        # Handle ending dates for timeslots over midnight
+        # adjust last_date if end_time is after midnight
         if schedule.end_time < schedule.start_time:
             last_date = schedule.first_date + timedelta(days=+1)
         else:
             last_date = schedule.first_date
 
-        if schedule.rrule.freq == 0:  # Ignore weekdays for one-time timeslots
-            by_weekday_start = None
-            by_weekday_end = None
-        elif schedule.rrule.freq == 3 and schedule.rrule.pk == 2:  # Daily timeslots
-            by_weekday_start = (0, 1, 2, 3, 4, 5, 6)
-            by_weekday_end = (0, 1, 2, 3, 4, 5, 6)
+        if schedule.rrule.freq == 3:  # daily: Ignore schedule.by_weekday to set by_weekday
+            by_weekday_start = by_weekday_end = (0, 1, 2, 3, 4, 5, 6)
+        elif (
+                schedule.rrule.freq == 2
+                and schedule.rrule.interval == 1
+                and schedule.rrule.by_weekdays is None
+        ):  # weekly: Use schedule.by_weekday for by_weekday
+            by_weekday_start = by_weekday_end = int(schedule.by_weekday)
+
+            # adjust by_weekday_end if end_time is after midnight
+            if schedule.end_time < schedule.start_time:
+                by_weekday_end = by_weekday_start + 1 if by_weekday_start < 6 else 0
         elif (
-            schedule.rrule.freq == 3 and schedule.rrule.pk == 3
-        ):  # Business days MO - FR/SA
-            by_weekday_start = (0, 1, 2, 3, 4)
+                schedule.rrule.freq == 2
+                and schedule.rrule.interval == 1
+                and schedule.rrule.by_weekdays == "0,1,2,3,4"
+        ):  # weekly on business days: Use schedule.rrule.by_weekdays to set by_weekday
+            by_weekday_start = by_weekday_end = [
+                int(wd) for wd in schedule.rrule.by_weekdays.split(",")
+            ]
+
+            # adjust by_weekday_end if end_time is after midnight
             if schedule.end_time < schedule.start_time:
-                # End days for over midnight
                 by_weekday_end = (1, 2, 3, 4, 5)
-            else:
-                by_weekday_end = (0, 1, 2, 3, 4)
-        elif schedule.rrule.freq == 2 and schedule.rrule.pk == 7:  # Even calendar weeks
-            by_weekday_start = int(schedule.by_weekday)
-            by_week_no = list(range(2, 54, 2))
-            # Reverse ending weeks if from Sun - Mon
-            if by_weekday_start == 6 and by_weekday_end == 0:
-                by_week_no_end = list(range(1, 54, 2))
-            else:
-                by_week_no_end = by_week_no
-        elif schedule.rrule.freq == 2 and schedule.rrule.pk == 8:  # Odd calendar weeks
-            by_weekday_start = int(schedule.by_weekday)
-            by_week_no = list(range(1, 54, 2))
-            # Reverse ending weeks if from Sun - Mon
-            if by_weekday_start == 6 and by_weekday_end == 0:
-                by_week_no_end = list(range(2, 54, 2))
-            else:
-                by_week_no_end = by_week_no
+        elif (
+                schedule.rrule.freq == 2
+                and schedule.rrule.interval == 1
+                and schedule.rrule.by_weekdays == "5,6"
+        ):  # weekly on weekends: Use schedule.rrule.by_weekdays to set by_weekday
+            by_weekday_start = by_weekday_end = [
+                int(wd) for wd in schedule.rrule.by_weekdays.split(",")
+            ]
+
+            # adjust by_weekday_end if end_time is after midnight
+            if schedule.end_time < schedule.start_time:
+                by_weekday_end = (6, 0)
+        elif schedule.rrule.freq == 0:  # once: Ignore schedule.by_weekday to set by_weekday
+            by_weekday_start = by_weekday_end = None
         else:
-            by_weekday_start = int(schedule.by_weekday)
+            by_weekday_start = by_weekday_end = (
+                int(schedule.by_weekday) if schedule.by_weekday else None
+            )
 
-        if schedule.rrule.freq == 0:
-            starts.append(datetime.combine(schedule.first_date, schedule.start_time))
-            ends.append(datetime.combine(last_date, schedule.end_time))
+            # adjust by_weekday_end if end_time is after midnight
+            if schedule.end_time < schedule.start_time:
+                by_weekday_end = by_weekday_start + 1 if by_weekday_start < 6 else 0
+
+        if schedule.rrule.freq == 0:  # once:
+            starts = [datetime.combine(schedule.first_date, schedule.start_time)]
+            ends = [datetime.combine(last_date, schedule.end_time)]
         else:
             starts = list(
                 rrule(
@@ -467,10 +467,8 @@ class Schedule(models.Model):
                     until=schedule.last_date + relativedelta(days=+1),
                     bysetpos=schedule.rrule.by_set_pos,
                     byweekday=by_weekday_start,
-                    byweekno=by_week_no,
                 )
             )
-
             ends = list(
                 rrule(
                     freq=schedule.rrule.freq,
@@ -479,12 +477,10 @@ class Schedule(models.Model):
                     until=schedule.last_date + relativedelta(days=+1),
                     bysetpos=schedule.rrule.by_set_pos,
                     byweekday=by_weekday_end,
-                    byweekno=by_week_no_end,
                 )
             )
 
         for k in range(min(len(starts), len(ends))):
-
             # Correct dates for the (relatively seldom) case if:
             # E.g.: 1st Monday from 23:00:00 to 1st Tuesday 00:00:00
             #       produces wrong end dates if the 1st Tuesday is before the 1st Monday
-- 
GitLab