nexus-5/core/models/schedule.py
2026-01-26 11:09:40 -05:00

97 lines
4.4 KiB
Python

import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from core.models.base import BaseModel
from core.models.account import AccountAddress
class Schedule(BaseModel):
"""
Service schedules for accounts.
"""
name = models.CharField(max_length=255, blank=True, null=True, verbose_name="Name")
account_address = models.ForeignKey(AccountAddress, on_delete=models.PROTECT, related_name='schedules',
verbose_name="Account Service Address", null=True)
monday_service = models.BooleanField(default=False, verbose_name="Monday Service")
tuesday_service = models.BooleanField(default=False, verbose_name="Tuesday Service")
wednesday_service = models.BooleanField(default=False, verbose_name="Wednesday Service")
thursday_service = models.BooleanField(default=False, verbose_name="Thursday Service")
friday_service = models.BooleanField(default=False, verbose_name="Friday Service")
saturday_service = models.BooleanField(default=False, verbose_name="Saturday Service")
sunday_service = models.BooleanField(default=False, verbose_name="Sunday Service")
weekend_service = models.BooleanField(default=False, verbose_name="Weekend Service",
help_text=(
"When enabled, represents a single service visit on Friday that can be performed "
"any time between Friday-Sunday and verified by Monday morning. "
"Individual Fri/Sat/Sun service flags must be disabled when this is enabled."))
schedule_exception = models.TextField(blank=True, null=True, verbose_name="Schedule Exceptions",
help_text=(
"Notes about any exceptions or special requirements for this schedule"))
start_date = models.DateField(verbose_name="Start Date", help_text="Date when this schedule becomes active")
end_date = models.DateField(blank=True, null=True, verbose_name="End Date",
help_text="Optional date when this schedule expires")
class Meta:
ordering = ['-start_date']
verbose_name = "Schedule"
verbose_name_plural = "Schedules"
indexes = [
models.Index(fields=['account_address', 'start_date']),
models.Index(fields=['weekend_service']),
]
def __str__(self):
return f"Schedule for {self.account_address.account.name} - {self.account_address.name if self.account_address.name else 'Primary Service Address'}"
def clean(self):
"""Validate schedule configuration"""
super().clean()
if self.end_date and self.start_date > self.end_date:
raise ValidationError({
'end_date': "End date must be after start date"
})
start = self.start_date
end = self.end_date or datetime.date.max
qs = Schedule.objects.filter(account_address=self.account_address)
if self.pk:
qs = qs.exclude(pk=self.pk)
overlaps = qs.filter(
Q(end_date__isnull=True, start_date__lte=end) |
Q(end_date__isnull=False, start_date__lte=end, end_date__gte=start)
)
if overlaps.exists():
raise ValidationError("Schedule dates overlap with an existing schedule for this address.")
# Validate weekend service configuration
if self.weekend_service:
weekend_days = [
self.friday_service,
self.saturday_service,
self.sunday_service
]
if any(weekend_days):
raise ValidationError({
'weekend_service': "When weekend service is enabled, Friday, Saturday, "
"and Sunday service flags must be disabled"
})
has_regular_service = any([
self.monday_service,
self.tuesday_service,
self.wednesday_service,
self.thursday_service,
self.friday_service,
self.saturday_service,
self.sunday_service
])
if not has_regular_service and not self.weekend_service:
raise ValidationError(
"At least one service day or weekend service must be selected"
)