[rentals] Allow reserving lockers for internal makerspace use

This commit is contained in:
Adam Goldsmith 2022-03-15 21:59:48 -04:00
parent 3225f2ff87
commit 87df8d460c
4 changed files with 65 additions and 8 deletions

View File

@ -10,4 +10,5 @@ class LockerInfoForm(forms.ModelForm):
"blind_code", "blind_code",
"bitting_code", "bitting_code",
"renter", "renter",
"reserved",
] ]

View File

@ -0,0 +1,30 @@
# Generated by Django 4.0.2 on 2022-03-16 01:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("rentals", "0002_lockerinfo_notes"),
]
operations = [
migrations.AddField(
model_name="lockerinfo",
name="reserved",
field=models.BooleanField(
default=False,
help_text="Locker is reserved for MakerSpace use, and cannot be rented.",
),
),
migrations.AddConstraint(
model_name="lockerinfo",
constraint=models.CheckConstraint(
check=models.Q(
("reserved", False), ("renter__isnull", True), _connector="OR"
),
name="locker_not_reserved_and_rented",
),
),
]

View File

@ -1,7 +1,8 @@
from django.contrib import admin from django.contrib import admin
from django.core import validators from django.core import validators
from django.core.exceptions import ValidationError
from django.db import models, transaction from django.db import models, transaction
from django.db.models import F from django.db.models import F, Q
from django.db.models.functions import Chr, Ord, Concat from django.db.models.functions import Chr, Ord, Concat
@ -85,15 +86,31 @@ class LockerInfo(models.Model):
renter = models.ForeignKey( renter = models.ForeignKey(
Member, on_delete=models.CASCADE, null=True, blank=True, db_constraint=False Member, on_delete=models.CASCADE, null=True, blank=True, db_constraint=False
) )
reserved = models.BooleanField(
default=False,
help_text="Locker is reserved for MakerSpace use, and cannot be rented.",
)
notes = models.TextField(blank=True) notes = models.TextField(blank=True)
def clean(self):
if self.reserved and self.renter is not None:
raise ValidationError("Locker cannot both be reserved and rented!")
class Meta: class Meta:
constraints = [ constraints = [
models.UniqueConstraint( models.UniqueConstraint(
fields=["locker_unit", "column", "row"], name="unique_locker_info" fields=["locker_unit", "column", "row"], name="unique_locker_info"
) ),
models.CheckConstraint(
check=Q(reserved=False) | Q(renter__isnull=True),
name="locker_not_reserved_and_rented",
),
] ]
@property
def available(self) -> bool:
return self.renter is None and not self.reserved
@property @property
def letter(self) -> str: def letter(self) -> str:
return self.locker_unit.letter_for_column(self.column) return self.locker_unit.letter_for_column(self.column)

View File

@ -39,7 +39,7 @@
justify-content: center; justify-content: center;
color: lightgray; color: lightgray;
} }
.locker .door:not([data-rented="false"]) { .locker .door[data-available="False"] {
background-color: hsl(24, 15%, 25%);; background-color: hsl(24, 15%, 25%);;
} }
</style> </style>
@ -60,7 +60,7 @@
data-bs-auto-close="outside" data-bs-auto-close="outside"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
data-rented="{{ locker_form.instance.renter|yesno:"true,false" }}"> data-available="{{ locker_form.instance.available }}">
<h3 class="locker-address mb-0">{{ locker_form.instance.address }}</h3> <h3 class="locker-address mb-0">{{ locker_form.instance.address }}</h3>
<div class="locker-status text-wrap"> <div class="locker-status text-wrap">
{% if locker_form.instance.renter is not None %} {% if locker_form.instance.renter is not None %}
@ -69,6 +69,8 @@
{% else %} {% else %}
Occupied Occupied
{% endif %} {% endif %}
{% elif locker_form.instance.reserved %}
Reserved
{% else %} {% else %}
Empty Empty
{% endif %} {% endif %}
@ -83,12 +85,19 @@
{% csrf_token %} {% csrf_token %}
<fieldset {{ perms.rentals.change_lockerinfo|yesno:",disabled" }}> <fieldset {{ perms.rentals.change_lockerinfo|yesno:",disabled" }}>
{% for field in locker_form.visible_fields %} {% for field in locker_form.visible_fields %}
<div class="form-floating mb-3"> <div class="mb-3">
{% if field.widget_type == 'checkbox' %}
{% render_field field class+="btn-check" %}
{{ field|add_label_class:"btn btn-outline-primary" }}
{% else %}
<div class="form-floating">
{% render_field field class+="form-control" %} {% render_field field class+="form-control" %}
{{ field.label_tag }} {{ field.label_tag }}
</div>
{% endif %}
{{ field.errors }} {{ field.errors }}
{% if field.help_text %} {% if field.help_text %}
<p class="form-text text-nowrap"> <p class="form-text">
{{ field.help_text|safe }} {{ field.help_text|safe }}
</p> </p>
{% endif %} {% endif %}