Files
2026-09-24 12:32:59 +03:30

103 lines
3.6 KiB
Python

from django.db import models
from django.utils import timezone
from apps.core.models import TimeStampedModel, UUIDModel
class Facility(UUIDModel, TimeStampedModel):
name = models.CharField(max_length=200)
def __str__(self) -> str:
return self.name
class ProcessingLine(UUIDModel, TimeStampedModel):
facility = models.ForeignKey(Facility, on_delete=models.CASCADE, related_name="lines")
name = models.CharField(max_length=200)
def __str__(self) -> str:
return f"{self.facility.name} / {self.name}"
class Holiday(UUIDModel):
date = models.DateField(unique=True)
class FacilitySchedule(UUIDModel, TimeStampedModel):
"""Per-facility, per-date availability: capacity for the day and days off.
If a schedule row exists for a date and ``is_open`` is False, no slots are
generated for that day. ``capacity``/``start_time``/``end_time`` override the
global Reservation settings for that date.
"""
facility = models.ForeignKey(Facility, on_delete=models.CASCADE, related_name="schedules")
date = models.DateField(db_index=True)
is_open = models.BooleanField(default=True)
capacity = models.PositiveIntegerField(default=2)
start_time = models.TimeField(null=True, blank=True)
end_time = models.TimeField(null=True, blank=True)
note = models.CharField(max_length=200, blank=True)
class Meta:
ordering = ["-date"]
constraints = [
models.UniqueConstraint(fields=["facility", "date"], name="uniq_facility_schedule_date")
]
def __str__(self) -> str:
return f"{self.facility.name} {self.date}"
class Slot(UUIDModel):
facility = models.ForeignKey(Facility, on_delete=models.CASCADE, related_name="slots")
line = models.ForeignKey(
ProcessingLine, on_delete=models.CASCADE, related_name="slots", null=True, blank=True
)
date = models.DateField(db_index=True)
start_time = models.TimeField()
end_time = models.TimeField()
capacity = models.PositiveIntegerField(default=1)
max_weight_kg = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
booked_count = models.PositiveIntegerField(default=0)
blocked = models.BooleanField(default=False)
class Meta:
constraints = [
models.UniqueConstraint(fields=["facility", "line", "date", "start_time"], name="uniq_slot_time")
]
def is_available(self) -> bool:
return (
not self.blocked
and self.booked_count < self.capacity
and self.date >= timezone.localdate()
)
class Reservation(UUIDModel, TimeStampedModel):
class Status(models.TextChoices):
PENDING = "pending", "Pending approval"
CONFIRMED = "confirmed", "Confirmed"
REJECTED = "rejected", "Rejected"
ARRIVED = "arrived", "Arrived"
WEIGHED = "weighed", "Weighed"
CANCELLED = "cancelled", "Cancelled"
EXPIRED = "expired", "Expired"
title = models.CharField(max_length=200, blank=True)
customer = models.ForeignKey("accounts.Customer", on_delete=models.CASCADE, related_name="reservations")
slot = models.ForeignKey(Slot, on_delete=models.PROTECT, related_name="reservations")
status = models.CharField(max_length=16, choices=Status.choices, default=Status.PENDING)
notes = models.TextField(blank=True)
approved_by = models.ForeignKey(
"accounts.User", null=True, blank=True, on_delete=models.SET_NULL, related_name="approved_reservations"
)
approved_at = models.DateTimeField(null=True, blank=True)
class Meta:
ordering = ["-created_at"]
def __str__(self) -> str:
return self.title or f"Reservation {self.id}"