cmsmanage/rentals/models.py

103 lines
3.3 KiB
Python
Raw Normal View History

from django.core import validators
from django.db import models
from membershipworks.models import Member
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 __str__(self):
last_letter = chr(ord(self.first_letter) + self.columns - 1)
last_number = self.first_number + self.columns * self.rows
return f"{self.bank.name} (Unit {last_letter}{self.first_number}-{self.first_letter}{last_number})"
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 + (self.columns - column - 1) * self.rows
def iter_doors(self):
for row in range(self.rows):
for column in range(self.columns):
# TODO: filter could be optimized
(locker, _) = self.lockers.get_or_create(
locker_unit=self, row=row, column=column
)
yield (
self.letter_for_column(column),
self.number_for_locker(column, row),
locker,
2022-01-24 23:37:04 -05:00
)
# TODO: add check constraint to ensure that column and number are within locker_unit bounds
class LockerInfo(models.Model):
"""Information about a single locker"""
locker_unit = models.ForeignKey(
LockerUnit, on_delete=models.CASCADE, related_name="lockers"
2022-01-24 23:37:04 -05:00
)
column = models.PositiveIntegerField()
row = models.PositiveIntegerField()
blind_code = models.CharField(
max_length=5,
help_text="Stamped on some keys. Usually D###A.",
blank=True,
)
bitting_code = models.CharField(
max_length=5,
help_text="National Disc Tumbler, depths 1-4. Read bow-to-tip.",
blank=True,
)
renter = models.ForeignKey(
Member, on_delete=models.CASCADE, null=True, blank=True, db_constraint=False
)
class Meta:
constraints = [
models.UniqueConstraint(
fields=["locker_unit", "column", "row"], name="unique_locker_info"
)
]
@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"{letter}{number}"
def __str__(self):
return f"{self.locker_unit}-{self.address} [{self.renter}]"