[rentals] Simplify locker index view/template rendering
Also create locker info instances when a new locker unit is created
This commit is contained in:
parent
937646798a
commit
ff723e019d
@ -29,10 +29,11 @@ server = [
|
|||||||
[tool.black]
|
[tool.black]
|
||||||
|
|
||||||
[tool.djlint]
|
[tool.djlint]
|
||||||
|
profile="django"
|
||||||
extension = ".dj.html"
|
extension = ".dj.html"
|
||||||
indent = 2
|
indent = 2
|
||||||
blank_line_after_tag = "load,extends"
|
blank_line_after_tag = "load,extends"
|
||||||
ignore = "T003,H017,H030,H031"
|
ignore = "T003,H017,H021,H030,H031"
|
||||||
|
|
||||||
[[tool.pdm.source]]
|
[[tool.pdm.source]]
|
||||||
url = "https://pypi.org/simple"
|
url = "https://pypi.org/simple"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
|
|
||||||
from membershipworks.models import Member
|
from membershipworks.models import Member
|
||||||
|
|
||||||
@ -29,6 +29,17 @@ class LockerUnit(models.Model):
|
|||||||
rows = models.PositiveIntegerField(default=5)
|
rows = models.PositiveIntegerField(default=5)
|
||||||
columns = models.PositiveIntegerField(default=2)
|
columns = models.PositiveIntegerField(default=2)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if self._state.adding:
|
||||||
|
# Create LockerInfo for each locker
|
||||||
|
with transaction.atomic():
|
||||||
|
super().save(self, *args, **kwargs)
|
||||||
|
for column in range(self.columns):
|
||||||
|
for row in range(self.rows):
|
||||||
|
self.lockers.create(column=column + 1, row=row + 1)
|
||||||
|
else:
|
||||||
|
super().save(self, *args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
# TODO: add constraint to check for letter overlaps
|
# TODO: add constraint to check for letter overlaps
|
||||||
constraints = [
|
constraints = [
|
||||||
@ -47,20 +58,6 @@ class LockerUnit(models.Model):
|
|||||||
def number_for_locker(self, column: int, row: int) -> int:
|
def number_for_locker(self, column: int, row: int) -> int:
|
||||||
return row + self.first_number + (self.columns - column - 1) * self.rows
|
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,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: add check constraint to ensure that column and number are within locker_unit bounds
|
# TODO: add check constraint to ensure that column and number are within locker_unit bounds
|
||||||
class LockerInfo(models.Model):
|
class LockerInfo(models.Model):
|
||||||
@ -92,11 +89,17 @@ class LockerInfo(models.Model):
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def letter(self) -> str:
|
||||||
|
return self.locker_unit.letter_for_column(self.column)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def number(self) -> int:
|
||||||
|
return self.locker_unit.number_for_locker(self.column, self.row)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def address(self) -> str:
|
def address(self) -> str:
|
||||||
letter = self.locker_unit.letter_for_column(self.column)
|
return f"{self.letter}{self.number}"
|
||||||
number = self.locker_unit.number_for_locker(self.column, self.row)
|
|
||||||
return f"{letter}{number}"
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.locker_unit}-{self.address} [{self.renter}]"
|
return f"{self.locker_unit}-{self.address} [{self.renter}]"
|
||||||
|
@ -25,22 +25,6 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.locker[data-columns="2"] {
|
|
||||||
grid-template-columns: repeat(2, min-content);
|
|
||||||
}
|
|
||||||
.locker[data-columns="4"] {
|
|
||||||
grid-template-columns: repeat(4, min-content);
|
|
||||||
}
|
|
||||||
.locker[data-columns="6"] {
|
|
||||||
grid-template-columns: repeat(6, min-content);
|
|
||||||
}
|
|
||||||
.locker[data-columns="8"] {
|
|
||||||
grid-template-columns: repeat(8, min-content);
|
|
||||||
}
|
|
||||||
.locker[data-columns="10"] {
|
|
||||||
grid-template-columns: repeat(10, min-content);
|
|
||||||
}
|
|
||||||
|
|
||||||
.locker .door {
|
.locker .door {
|
||||||
background-color: hsl(24, 100%, 25%);
|
background-color: hsl(24, 100%, 25%);
|
||||||
border: 0.2rem solid black;
|
border: 0.2rem solid black;
|
||||||
@ -63,21 +47,22 @@
|
|||||||
<div>{{ bank.location }}</div>
|
<div>{{ bank.location }}</div>
|
||||||
<div class="lockers">
|
<div class="lockers">
|
||||||
{% for unit, lockers in units.items %}
|
{% for unit, lockers in units.items %}
|
||||||
<div class="locker" data-columns="{{ unit.columns }}">
|
<div class="locker"
|
||||||
{% for row, column, locker, form in lockers %}
|
style="grid-template-columns: repeat({{ unit.columns }}, min-content);">
|
||||||
<div class="dropdown">
|
{% for locker_form in lockers %}
|
||||||
|
<div class="dropdown"
|
||||||
|
style="grid-row-start: {{ locker_form.instance.row|add:"1" }}; grid-column-start: {{ locker_form.instance.column|add:"
|
||||||
|
1>
|
||||||
<span class="door {{ perms.rentals.view_lockerinfo|yesno:"btn dropdown-toggle," }}"
|
<span class="door {{ perms.rentals.view_lockerinfo|yesno:"btn dropdown-toggle," }}"
|
||||||
data-bs-toggle="dropdown"
|
data-bs-toggle="dropdown"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
data-rented="{{ locker.renter|yesno:"true,false" }}"
|
data-rented="{{ locker_form.instance.renter|yesno:"true,false" }}">
|
||||||
data-row="{{ row }}"
|
<h3 class="locker-address">{{ locker_form.instance.address }}</h3>
|
||||||
data-column="{{ column }}">
|
|
||||||
<h3 class="locker-name">{{ bank.initial }}{{ row }}{{ column }}</h3>
|
|
||||||
<div class="locker-status">
|
<div class="locker-status">
|
||||||
{% if locker.renter is not None %}
|
{% if locker_form.instance.renter is not None %}
|
||||||
{% if perms.rentals.view_lockerinfo %}
|
{% if perms.rentals.view_lockerinfo %}
|
||||||
{{ locker.renter }}
|
{{ locker_form.instance.renter }}
|
||||||
{% else %}
|
{% else %}
|
||||||
Occupied
|
Occupied
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -88,19 +73,19 @@
|
|||||||
</span>
|
</span>
|
||||||
{% if perms.rentals.view_lockerinfo %}
|
{% if perms.rentals.view_lockerinfo %}
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<div class="dropdown-header">{{ locker }}</div>
|
<div class="dropdown-header">{{ locker_form.instance }}</div>
|
||||||
<form class="p-2"
|
<form class="p-2"
|
||||||
action="{% url 'rentals:locker' locker.id %}"
|
action="{% url 'rentals:locker' locker_form.instance.id %}"
|
||||||
method="post">
|
method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<fieldset {{ perms.rentals.change_lockerinfo|yesno:",disabled" }}>
|
<fieldset {{ perms.rentals.change_lockerinfo|yesno:",disabled" }}>
|
||||||
{% for field in form.visible_fields %}
|
{% for field in locker_form.visible_fields %}
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
{{ field }}
|
{{ field }}
|
||||||
{{ field.label_tag }}
|
{{ field.label_tag }}
|
||||||
{{ field.errors }}
|
{{ field.errors }}
|
||||||
{% if field.help_text %}
|
{% if field.help_text %}
|
||||||
<p class="form-text">
|
<p class="form-text text-nowrap">
|
||||||
{{ field.help_text|safe }}
|
{{ field.help_text|safe }}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -108,7 +93,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
{% if perms.rentals.change_lockerinfo %}
|
{% if perms.rentals.change_lockerinfo %}
|
||||||
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
|
{% for hidden in locker_form.hidden_fields %}{{ hidden }}{% endfor %}
|
||||||
<input class="btn btn-primary" type="submit" value="Submit">
|
<input class="btn btn-primary" type="submit" value="Submit">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
|
@ -11,10 +11,7 @@ from .forms import LockerInfoForm
|
|||||||
def lockerIndex(request):
|
def lockerIndex(request):
|
||||||
locker_banks = {
|
locker_banks = {
|
||||||
bank: {
|
bank: {
|
||||||
unit: [
|
unit: [LockerInfoForm(instance=locker) for locker in unit.lockers.all()]
|
||||||
(col, num, locker, LockerInfoForm(instance=locker))
|
|
||||||
for col, num, locker in unit.iter_doors()
|
|
||||||
]
|
|
||||||
for unit in bank.units.all()
|
for unit in bank.units.all()
|
||||||
}
|
}
|
||||||
for bank in LockerBank.objects.all()
|
for bank in LockerBank.objects.all()
|
||||||
|
Loading…
Reference in New Issue
Block a user