feat(backend): add ability to schedule member in cli

This commit is contained in:
2025-08-27 23:55:29 -04:00
parent 1379998e5b
commit 6763a31a41
7 changed files with 285 additions and 13 deletions

View File

@@ -7,7 +7,7 @@
from __future__ import annotations
from datetime import datetime, timezone
from typing import Optional, Tuple, List
from typing import Optional, Tuple, List, Iterable
from backend.repositories import (
ClassificationRepository,
@@ -48,7 +48,7 @@ class SchedulingService:
service_id: int,
*,
only_active: bool = True,
boost_seconds: int = 5 * 24 * 60 * 60,
boost_seconds: int = 2 * 24 * 60 * 60,
exclude_member_ids: Iterable[int] | None = None,
) -> Optional[Tuple[int, str, str, int]]:
"""
@@ -224,4 +224,78 @@ class SchedulingService:
status=ScheduleStatus.DECLINED,
reason=reason,
)
return ("created", new_sched.ScheduleId)
return ("created", new_sched.ScheduleId)
def preview_next_member(
self,
classification_ids: Iterable[int],
service_id: int,
*,
only_active: bool = True,
boost_seconds: int = 2 * 24 * 60 * 60,
exclude_member_ids: Iterable[int] | None = None,
) -> Optional[Tuple[int, str, str]]:
"""
Preview who would be scheduled next for a service without actually creating the schedule.
Same logic as schedule_next_member, but doesn't create any records.
Returns
-------
Tuple[member_id, first_name, last_name] | None
The member who would be scheduled next, or None if no eligible member found.
"""
# Same logic as schedule_next_member but without creating records
svc = self.service_repo.get_by_id(service_id)
if svc is None:
return None
service_type_id = svc.ServiceTypeId
target_date = svc.ServiceDate
excluded = set(exclude_member_ids or [])
candidates: List = self.member_repo.candidate_queue(
classification_ids=list(classification_ids),
only_active=only_active,
boost_seconds=boost_seconds,
)
for member in candidates:
member_id = member.MemberId
if member_id in excluded:
continue
if not self.availability_repo.get(member_id, service_type_id):
continue
if self.schedule_repo.has_schedule_on_date(member_id, target_date):
continue
if self.schedule_repo.has_any(
member_id,
service_id,
statuses=[ScheduleStatus.ACCEPTED],
):
continue
if self.schedule_repo.has_any(
member_id,
service_id,
statuses=[ScheduleStatus.PENDING],
):
continue
if self.schedule_repo.has_any(
member_id,
service_id,
statuses=[ScheduleStatus.DECLINED],
):
continue
# Found eligible member - return without creating schedule
return (
member_id,
member.FirstName,
member.LastName,
)
return None