From 6d68f730fd435cbf8a0307b959daaae190c666c3 Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Fri, 15 May 2026 17:35:15 +0200 Subject: [PATCH 1/2] Refactor methods into one for getting checked in tickets --- src/camps/models.py | 147 +++++++++----------------------------------- src/camps/tests.py | 62 ++++++++++++++----- src/tokens/views.py | 2 +- 3 files changed, 78 insertions(+), 133 deletions(-) diff --git a/src/camps/models.py b/src/camps/models.py index 2e5a67662..5998d1014 100644 --- a/src/camps/models.py +++ b/src/camps/models.py @@ -356,132 +356,43 @@ def event_slots(self): EventSlot = apps.get_model("program", "EventSlot") return EventSlot.objects.filter(event_session__in=self.event_sessions.all()) - @property - def checked_in_full_week_adults(self) -> int: - """Return the count of full week adult tickets checked in""" - shop_tickets = ( - ShopTicket.objects.filter( - ticket_type=self.ticket_type_full_week_adult, - ).exclude(used_at=None) - ).count() - - sponsor_tickets = ( - SponsorTicket.objects.filter( - ticket_type=self.ticket_type_full_week_adult, - ).exclude(used_at=None) - ).count() - - prize_tickets = ( - PrizeTicket.objects.filter( - ticket_type=self.ticket_type_full_week_adult, - ).exclude(used_at=None) - ).count() - - return shop_tickets + sponsor_tickets + prize_tickets - - @property - def checked_in_full_week_children(self) -> int: - """Return the count of full week children tickets checked in""" - shop_tickets = ( - ShopTicket.objects.filter( - ticket_type=self.ticket_type_full_week_child, - ).exclude(used_at=None) - ).count() - - sponsor_tickets = ( - SponsorTicket.objects.filter( - ticket_type=self.ticket_type_full_week_child, - ).exclude(used_at=None) - ).count() - - prize_tickets = ( - PrizeTicket.objects.filter( - ticket_type=self.ticket_type_full_week_child, - ).exclude(used_at=None) - ).count() - - return shop_tickets + sponsor_tickets + prize_tickets + def checked_in_tickets(self, ticket_type, start_time=None, end_time=None) -> list: + """Return the count of one day tickets checked in.""" + shop_tickets = ShopTicket.objects.filter(ticket_type=ticket_type).exclude(used_at=None) + sponsor_tickets = SponsorTicket.objects.filter(ticket_type=ticket_type).exclude(used_at=None) + prize_tickets = PrizeTicket.objects.filter(ticket_type=ticket_type).exclude(used_at=None) + + if start_time: + shop_tickets = shop_tickets.filter(used_at__gte=start_time) + sponsor_tickets = sponsor_tickets.filter(used_at__gte=start_time) + prize_tickets = prize_tickets.filter(used_at__gte=start_time) + if end_time: + shop_tickets = shop_tickets.filter(used_at__lte=end_time) + sponsor_tickets = sponsor_tickets.filter(used_at__lte=end_time) + prize_tickets = prize_tickets.filter(used_at__lte=end_time) + + return list(shop_tickets) + list(sponsor_tickets) + list(prize_tickets) @property - def checked_in_one_day_adults(self) -> int: - """Return the count of todays one day adult tickets checked in. - - Count tickets with a checked in timestamp from 0600-0600 next day. - Reason being early arriving participants might get checked in before 10. - """ - now = timezone.localtime() - today_06_hour = now.replace(hour=6, minute=0, second=0) - if now < today_06_hour: - start = today_06_hour - timezone.timedelta(days=1) - end = today_06_hour - else: - start = today_06_hour - end = today_06_hour + timezone.timedelta(days=1) - - shop_tickets = ( - ShopTicket.objects.filter( - ticket_type=self.ticket_type_one_day_adult, - ).filter(used_at__gte=start, used_at__lt=end) - ).count() - - sponsor_tickets = ( - SponsorTicket.objects.filter( - ticket_type=self.ticket_type_one_day_adult, - ).filter(used_at__gte=start, used_at__lt=end) - ).count() - - prize_tickets = ( - PrizeTicket.objects.filter( - ticket_type=self.ticket_type_one_day_adult, - ).filter(used_at__gte=start, used_at__lt=end) - ).count() - - return shop_tickets + sponsor_tickets + prize_tickets - - @property - def checked_in_one_day_children(self) -> int: - """Return the count of todays one day children tickets checked in. + def todays_participant_count(self) -> int: + """Calculate todays participant count from all used 'full week' tickets + and todays used 'one day' tickets. Count tickets with a checked in timestamp from 0600-0600 next day. Reason being early arriving participants might get checked in before 10. """ now = timezone.localtime() - today_06_hour = now.replace(hour=6, minute=0, second=0) - if now < today_06_hour: - start = today_06_hour - timezone.timedelta(days=1) - end = today_06_hour + limit = now.replace(hour=6, minute=0, second=0) + if now < limit: + start = limit - timezone.timedelta(days=1) + end = limit else: - start = today_06_hour - end = today_06_hour + timezone.timedelta(days=1) - - shop_tickets = ( - ShopTicket.objects.filter( - ticket_type=self.ticket_type_one_day_child, - ).filter(used_at__gte=start, used_at__lt=end) - ).count() - - sponsor_tickets = ( - SponsorTicket.objects.filter( - ticket_type=self.ticket_type_one_day_child, - ).filter(used_at__gte=start, used_at__lt=end) - ).count() + start = limit + end = limit + timezone.timedelta(days=1) - prize_tickets = ( - PrizeTicket.objects.filter( - ticket_type=self.ticket_type_one_day_child, - ).filter(used_at__gte=start, used_at__lt=end) - ).count() - - return shop_tickets + sponsor_tickets + prize_tickets - - @property - def participant_count(self) -> int: - """Retrieve the participant count for all used 'full week' tickets - and todays used 'one day' tickets. - """ return ( - self.checked_in_full_week_adults - + self.checked_in_full_week_children - + self.checked_in_one_day_adults - + self.checked_in_one_day_children + len(self.checked_in_tickets(self.ticket_type_full_week_adult)) + + len(self.checked_in_tickets(self.ticket_type_full_week_child)) + + len(self.checked_in_tickets(self.ticket_type_one_day_adult, start, end)) + + len(self.checked_in_tickets(self.ticket_type_one_day_child, start, end)) ) diff --git a/src/camps/tests.py b/src/camps/tests.py index 9ed6370e1..b962139ac 100644 --- a/src/camps/tests.py +++ b/src/camps/tests.py @@ -69,18 +69,24 @@ def test_checked_in_full_week_adults_all_ticket_types(self) -> None: self.full_week_adults["sponsor_tickets"][0], self.full_week_adults["prize_tickets"][0], ] + for ticket in tickets: ticket.used_at = self.camp.camp.lower ticket.save() - assert self.camp.checked_in_full_week_adults == 3 + result = self.camp.checked_in_tickets(self.camp.ticket_type_full_week_adult) + + assert len(result) == len(tickets) def test_checked_in_full_week_children_shop_tickets(self) -> None: """Test the return value of checked in full week children with shop ticket""" ticket = self.full_week_children[0] ticket.used_at = self.camp.camp.lower ticket.save() - assert self.camp.checked_in_full_week_children == 1 + + result = self.camp.checked_in_tickets(self.camp.ticket_type_full_week_child) + + assert len(result) == 1 def test_checked_in_full_week_children_with_sponsor_ticket(self) -> None: """Test the return value of checked in full week children with sponsor ticket""" @@ -90,7 +96,10 @@ def test_checked_in_full_week_children_with_sponsor_ticket(self) -> None: ticket_type=self.camp.ticket_type_full_week_child, used_at=self.camp.camp.lower, ) - assert self.camp.checked_in_full_week_children == 1 + + result = self.camp.checked_in_tickets(self.camp.ticket_type_full_week_child) + + assert len(result) == 1 def test_checked_in_full_week_children_with_prize_ticket(self) -> None: """Test the return value of checked in full week children with prize ticket""" @@ -100,7 +109,10 @@ def test_checked_in_full_week_children_with_prize_ticket(self) -> None: comment="Prize winner", used_at=self.camp.camp.lower, ) - assert self.camp.checked_in_full_week_children == 1 + + result = self.camp.checked_in_tickets(self.camp.ticket_type_full_week_child) + + assert len(result) == 1 def test_checked_in_one_day_adults(self) -> None: """Test the return value of checked in one day adults today""" @@ -108,7 +120,9 @@ def test_checked_in_one_day_adults(self) -> None: ticket.used_at = timezone.localtime() ticket.save() - assert self.camp.checked_in_one_day_adults == 2 + result = self.camp.checked_in_tickets(self.camp.ticket_type_one_day_adult) + + assert len(result) == 2 def test_checked_in_one_day_adults_with_sponsor_ticket(self) -> None: """Test the return value of checked in one day adults @@ -121,7 +135,9 @@ def test_checked_in_one_day_adults_with_sponsor_ticket(self) -> None: used_at=timezone.localtime(), ) - assert self.camp.checked_in_one_day_adults == 1 + result = self.camp.checked_in_tickets(self.camp.ticket_type_one_day_adult) + + assert len(result) == 1 def test_checked_in_one_day_adults_with_prize_ticket(self) -> None: """Test the return value of checked in one day adults @@ -134,7 +150,9 @@ def test_checked_in_one_day_adults_with_prize_ticket(self) -> None: used_at=timezone.localtime(), ) - assert self.camp.checked_in_one_day_adults == 1 + result = self.camp.checked_in_tickets(self.camp.ticket_type_one_day_adult) + + assert len(result) == 1 def test_checked_in_one_day_adults_timing(self) -> None: """Test check in before 06 yesterday don't count""" @@ -146,7 +164,12 @@ def test_checked_in_one_day_adults_timing(self) -> None: not_valid.used_at = timezone.localtime() - timezone.timedelta(days=2) not_valid.save() - assert self.camp.checked_in_one_day_adults == 1 + result = self.camp.checked_in_tickets( + self.camp.ticket_type_one_day_adult, + start_time=timezone.localtime().replace(hour=6, minute=0, second=0) + ) + + assert len(result) == 1 def test_checked_in_one_day_children(self) -> None: """Test the return value of checked in one day children today""" @@ -154,7 +177,9 @@ def test_checked_in_one_day_children(self) -> None: ticket.used_at = timezone.localtime() ticket.save() - assert self.camp.checked_in_one_day_children == 2 + result = self.camp.checked_in_tickets(self.camp.ticket_type_one_day_child) + + assert len(result) == 2 def test_checked_in_one_day_children_with_sponsor_ticket(self) -> None: """Test the return value of checked in one day children @@ -167,7 +192,9 @@ def test_checked_in_one_day_children_with_sponsor_ticket(self) -> None: used_at=timezone.localtime(), ) - assert self.camp.checked_in_one_day_children == 1 + result = self.camp.checked_in_tickets(self.camp.ticket_type_one_day_child) + + assert len(result) == 1 def test_checked_in_one_day_children_with_prize_ticket(self) -> None: """Test the return value of checked in one day children @@ -180,7 +207,9 @@ def test_checked_in_one_day_children_with_prize_ticket(self) -> None: used_at=timezone.localtime(), ) - assert self.camp.checked_in_one_day_children == 1 + result = self.camp.checked_in_tickets(self.camp.ticket_type_one_day_child) + + assert len(result) == 1 def test_checked_in_one_day_children_timing(self) -> None: """Test check in before 06 yesterday don't count""" @@ -192,9 +221,14 @@ def test_checked_in_one_day_children_timing(self) -> None: not_valid.used_at = timezone.localtime() - timezone.timedelta(days=2) not_valid.save() - assert self.camp.checked_in_one_day_children == 1 + result = self.camp.checked_in_tickets( + self.camp.ticket_type_one_day_child, + start_time=timezone.localtime().replace(hour=6, minute=0, second=0) + ) + + assert len(result) == 1 - def test_participant_count(self) -> None: + def test_todays_participant_count(self) -> None: """Test the count of all participants""" adult_full_week = self.full_week_adults["shop_tickets"][0] adult_full_week.used_at = self.camp.camp.lower @@ -212,7 +246,7 @@ def test_participant_count(self) -> None: child_one_day.used_at = timezone.localtime() child_one_day.save() - assert self.camp.participant_count == 4 + assert self.camp.todays_participant_count == 4 def test_year_of_camp(self) -> None: """Test the property `year` return current year of camp.""" diff --git a/src/tokens/views.py b/src/tokens/views.py index 363163968..10d434fa1 100644 --- a/src/tokens/views.py +++ b/src/tokens/views.py @@ -99,7 +99,7 @@ def get_total_players_metrics(self, camp_finds: QuerySet) -> dict: .last() ) unique_player_count = camp_finds.distinct("user").count() - non_player_count = self.request.camp.participant_count + non_player_count = self.request.camp.todays_participant_count if non_player_count: # Avoid ZeroDivisionError players_pct = unique_player_count / (unique_player_count + non_player_count) * 100 From e2c3792c1a5337fb1e125ccecab8302f5702f78c Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Fri, 15 May 2026 17:46:34 +0200 Subject: [PATCH 2/2] Rename params and rephrase doc string. --- src/camps/models.py | 34 ++++++++++++++++++---------------- src/camps/tests.py | 4 ++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/camps/models.py b/src/camps/models.py index 5998d1014..b6f1c5eb1 100644 --- a/src/camps/models.py +++ b/src/camps/models.py @@ -356,20 +356,22 @@ def event_slots(self): EventSlot = apps.get_model("program", "EventSlot") return EventSlot.objects.filter(event_session__in=self.event_sessions.all()) - def checked_in_tickets(self, ticket_type, start_time=None, end_time=None) -> list: - """Return the count of one day tickets checked in.""" + def checked_in_tickets(self, ticket_type, used_before=None, used_after=None) -> list: + """Get a concatenated list with all tickets of the specified type + and support for filtering before/after time for when a ticket was used. + """ shop_tickets = ShopTicket.objects.filter(ticket_type=ticket_type).exclude(used_at=None) sponsor_tickets = SponsorTicket.objects.filter(ticket_type=ticket_type).exclude(used_at=None) prize_tickets = PrizeTicket.objects.filter(ticket_type=ticket_type).exclude(used_at=None) - if start_time: - shop_tickets = shop_tickets.filter(used_at__gte=start_time) - sponsor_tickets = sponsor_tickets.filter(used_at__gte=start_time) - prize_tickets = prize_tickets.filter(used_at__gte=start_time) - if end_time: - shop_tickets = shop_tickets.filter(used_at__lte=end_time) - sponsor_tickets = sponsor_tickets.filter(used_at__lte=end_time) - prize_tickets = prize_tickets.filter(used_at__lte=end_time) + if used_before: + shop_tickets = shop_tickets.filter(used_at__lte=used_before) + sponsor_tickets = sponsor_tickets.filter(used_at__lte=used_before) + prize_tickets = prize_tickets.filter(used_at__lte=used_before) + if used_after: + shop_tickets = shop_tickets.filter(used_at__gte=used_after) + sponsor_tickets = sponsor_tickets.filter(used_at__gte=used_after) + prize_tickets = prize_tickets.filter(used_at__gte=used_after) return list(shop_tickets) + list(sponsor_tickets) + list(prize_tickets) @@ -384,15 +386,15 @@ def todays_participant_count(self) -> int: now = timezone.localtime() limit = now.replace(hour=6, minute=0, second=0) if now < limit: - start = limit - timezone.timedelta(days=1) - end = limit + used_after = limit - timezone.timedelta(days=1) + used_before = limit else: - start = limit - end = limit + timezone.timedelta(days=1) + used_after = limit + used_before = limit + timezone.timedelta(days=1) return ( len(self.checked_in_tickets(self.ticket_type_full_week_adult)) + len(self.checked_in_tickets(self.ticket_type_full_week_child)) - + len(self.checked_in_tickets(self.ticket_type_one_day_adult, start, end)) - + len(self.checked_in_tickets(self.ticket_type_one_day_child, start, end)) + + len(self.checked_in_tickets(self.ticket_type_one_day_adult, used_before, used_after)) + + len(self.checked_in_tickets(self.ticket_type_one_day_child, used_before, used_after)) ) diff --git a/src/camps/tests.py b/src/camps/tests.py index b962139ac..569d6adbc 100644 --- a/src/camps/tests.py +++ b/src/camps/tests.py @@ -166,7 +166,7 @@ def test_checked_in_one_day_adults_timing(self) -> None: result = self.camp.checked_in_tickets( self.camp.ticket_type_one_day_adult, - start_time=timezone.localtime().replace(hour=6, minute=0, second=0) + used_after=timezone.localtime().replace(hour=6, minute=0, second=0) ) assert len(result) == 1 @@ -223,7 +223,7 @@ def test_checked_in_one_day_children_timing(self) -> None: result = self.camp.checked_in_tickets( self.camp.ticket_type_one_day_child, - start_time=timezone.localtime().replace(hour=6, minute=0, second=0) + used_after=timezone.localtime().replace(hour=6, minute=0, second=0) ) assert len(result) == 1