76 lines
2.5 KiB
Python
76 lines
2.5 KiB
Python
from django.contrib.auth import get_user_model
|
|
from django.core import validators
|
|
from django.db import models
|
|
|
|
|
|
class LockerBank(models.Model):
|
|
"""A set of locker units, placed together"""
|
|
|
|
name = models.CharField(max_length=200)
|
|
location = models.CharField(max_length=200)
|
|
slug = models.SlugField(unique=True)
|
|
|
|
def __str__(self):
|
|
return f"{self.name} ({self.units.count()} units)"
|
|
|
|
|
|
class LockerUnit(models.Model):
|
|
"""A standalone set of lockers"""
|
|
|
|
bank = models.ForeignKey(
|
|
LockerBank, on_delete=models.SET_NULL, related_name="units", null=True
|
|
)
|
|
index = models.PositiveIntegerField()
|
|
first_letter = models.CharField(
|
|
max_length=1, validators=[validators.RegexValidator("[A-Z]")], unique=True
|
|
)
|
|
first_number = models.PositiveIntegerField()
|
|
rows = models.PositiveIntegerField(default=5)
|
|
columns = models.PositiveIntegerField(default=2)
|
|
|
|
class Meta:
|
|
# TODO: add constraint to check for letter overlaps
|
|
constraints = [
|
|
models.UniqueConstraint(fields=["bank", "index"], name="unique_bank_index")
|
|
]
|
|
ordering = ["index"]
|
|
|
|
def letter_for_column(self, column: int) -> str:
|
|
return chr(column + ord(self.first_letter))
|
|
|
|
def number_for_locker(self, column: int, row: int) -> int:
|
|
return row + self.first_number + column * self.rows
|
|
|
|
@property
|
|
def iter_doors(self):
|
|
for row in range(self.rows):
|
|
for column in range(self.columns):
|
|
# TODO: filter could be optimized
|
|
yield (
|
|
self.letter_for_column(column),
|
|
self.number_for_locker(column, row),
|
|
self.rentals.filter(row=row, column=column),
|
|
)
|
|
|
|
|
|
# TODO: add check constraint to ensure that column and number are within locker_unit bounds
|
|
# TODO: add unique constraint on (unit, row, column)?
|
|
class LockerRental(models.Model):
|
|
"""A rental of a single locker"""
|
|
|
|
locker_unit = models.ForeignKey(
|
|
LockerUnit, on_delete=models.CASCADE, related_name="rentals"
|
|
)
|
|
column = models.PositiveIntegerField()
|
|
row = models.PositiveIntegerField()
|
|
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
|
|
|
@property
|
|
def address(self) -> str:
|
|
letter = self.locker_unit.letter_for_column(self.column)
|
|
number = self.locker_unit.number_for_locker(self.column, self.row)
|
|
return f"{self.locker_unit}-{letter}{number}"
|
|
|
|
def __str__(self):
|
|
return f"{self.user}: {self.address}"
|