From 2cc6b780493fe976ba66791bc60ee2fcb0bc6f2b Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Wed, 18 Dec 2024 10:45:38 +0200 Subject: [PATCH 01/14] Move Name and Description fields higher in resource form Refs TTVA-220 --- .../respa_admin/resources/form/_general_info.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/respa_admin/templates/respa_admin/resources/form/_general_info.html b/respa_admin/templates/respa_admin/resources/form/_general_info.html index 7f0632efd..12d3906b6 100644 --- a/respa_admin/templates/respa_admin/resources/form/_general_info.html +++ b/respa_admin/templates/respa_admin/resources/form/_general_info.html @@ -9,11 +9,6 @@

{% trans "General information" %}

{% include "respa_admin/forms/_select.html" with field=form.unit inline=True %} {% include "respa_admin/forms/_select.html" with field=form.type inline=True %} -
-

{% trans "Purposes" %}

- {% include "respa_admin/forms/_errors.html" with field=form.purposes %} - {{ form.purposes }} -

{% trans "Name and description" %}

{% include "respa_admin/forms/_input.html" with field=form.name_fi %} @@ -24,6 +19,11 @@

{% trans "Name and description" %}

{% include "respa_admin/forms/_textarea_input.html" with field=form.description_en %} {% include "respa_admin/forms/_textarea_input.html" with field=form.description_sv %}
+
+

{% trans "Purposes" %}

+ {% include "respa_admin/forms/_errors.html" with field=form.purposes %} + {{ form.purposes }} +

{% trans "Contact person" %}

{% include "respa_admin/forms/_textarea_input.html" with field=form.responsible_contact_info_fi %} From 999675e8581222ebc6602b2f88e1d859c12d2682 Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Wed, 18 Dec 2024 15:06:55 +0200 Subject: [PATCH 02/14] Add missing migration --- resources/migrations/0122_auto_20241218_1457.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 resources/migrations/0122_auto_20241218_1457.py diff --git a/resources/migrations/0122_auto_20241218_1457.py b/resources/migrations/0122_auto_20241218_1457.py new file mode 100644 index 000000000..11c0990b5 --- /dev/null +++ b/resources/migrations/0122_auto_20241218_1457.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.11 on 2024-12-18 12:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0121_auto_20231218_1250'), + ] + + operations = [ + migrations.AlterModelOptions( + name='resourceaccess', + options={'verbose_name': 'Resource access method', 'verbose_name_plural': 'Resource access methods'}, + ), + ] From f4b286356ff9f037481408422521da4cc2c9f11c Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Wed, 18 Dec 2024 15:08:19 +0200 Subject: [PATCH 03/14] Remove trailing whitespace --- resources/models/reservation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/models/reservation.py b/resources/models/reservation.py index df14a0dac..fd3f9dde5 100644 --- a/resources/models/reservation.py +++ b/resources/models/reservation.py @@ -709,7 +709,7 @@ def clean(self, **kwargs): valid_reservations_for_same_unit = reservations_for_same_unit.exclude( state=Reservation.CANCELLED ) - # Exclude current reservation from the valid_reservations_for_same_unit list to allow user to + # Exclude current reservation from the valid_reservations_for_same_unit list to allow user to # update reservation if new times overlaps only with the original times of the same reservation original_reservation = kwargs.get("original_reservation", None) if original_reservation: From 4c2d02e43b6d3a239b43fee10d76948708b0d715 Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Thu, 19 Dec 2024 14:18:46 +0200 Subject: [PATCH 04/14] Send reservation reminders Add a management command to send reservation reminders for reservations that start within 24 hours. Refs TTVA-219 --- locale/fi/LC_MESSAGES/django.po | 3 + locale/sv/LC_MESSAGES/django.po | 3 + notifications/management/__init__.py | 0 notifications/management/commands/__init__.py | 0 .../commands/send_reservation_reminders.py | 35 +++++++ .../0012_add_reservation_reminder_type.py | 71 ++++++++++++++ ...reate_reservation_reminder_notification.py | 92 +++++++++++++++++++ notifications/models.py | 3 + .../tests/test_send_reservation_reminders.py | 69 ++++++++++++++ .../0123_reservation_reminder_sent.py | 18 ++++ resources/models/reservation.py | 1 + 11 files changed, 295 insertions(+) create mode 100644 notifications/management/__init__.py create mode 100644 notifications/management/commands/__init__.py create mode 100644 notifications/management/commands/send_reservation_reminders.py create mode 100644 notifications/migrations/0012_add_reservation_reminder_type.py create mode 100644 notifications/migrations/0013_create_reservation_reminder_notification.py create mode 100644 notifications/tests/test_send_reservation_reminders.py create mode 100644 resources/migrations/0123_reservation_reminder_sent.py diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index 025e92b8b..5f325f77d 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -2202,3 +2202,6 @@ msgstr "Takaisin" #, python-brace-format msgid "Missing information required by SAP: {}" msgstr "SAP:n vaatimia tietoja puuttuu: {}" + +msgid "Reservation reminder" +msgstr "Muistutus varauksesta" diff --git a/locale/sv/LC_MESSAGES/django.po b/locale/sv/LC_MESSAGES/django.po index e9b50336a..9ffd906f5 100644 --- a/locale/sv/LC_MESSAGES/django.po +++ b/locale/sv/LC_MESSAGES/django.po @@ -1789,3 +1789,6 @@ msgid "" msgstr "" "anger om användaren är en General Administrator med särskilda behörigheter " "för många objekt inom Respa" + +msgid "Reservation reminder" +msgstr "Bokningspåminnelse" diff --git a/notifications/management/__init__.py b/notifications/management/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/notifications/management/commands/__init__.py b/notifications/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/notifications/management/commands/send_reservation_reminders.py b/notifications/management/commands/send_reservation_reminders.py new file mode 100644 index 000000000..c1797890c --- /dev/null +++ b/notifications/management/commands/send_reservation_reminders.py @@ -0,0 +1,35 @@ +import logging +from datetime import timedelta + +from django.core.management import BaseCommand +from django.utils import timezone + +from resources.models import Reservation + +logger = logging.getLogger(__name__) + + +def send_reservation_reminder(reservation): + reservation.send_reservation_mail(notification_type="reservation_reminder") + reservation.reminder_sent = True + reservation.save() + + +class Command(BaseCommand): + help = "Send reservation reminders" + + def handle(self, *args, **options): + """ + Send reservation reminders for reservations that start in the next 24 hours. + """ + + reservations = Reservation.objects.filter( + begin__gte=timezone.now(), + begin__lte=timezone.now() + timedelta(days=1), + reminder_sent=False, + ) + + logger.info(f"Sending reminders for {reservations.count()} reservations") + + for reservation in reservations: + send_reservation_reminder(reservation) diff --git a/notifications/migrations/0012_add_reservation_reminder_type.py b/notifications/migrations/0012_add_reservation_reminder_type.py new file mode 100644 index 000000000..4a83285d2 --- /dev/null +++ b/notifications/migrations/0012_add_reservation_reminder_type.py @@ -0,0 +1,71 @@ +# Generated by Django 2.2.11 on 2024-12-19 08:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("notifications", "0011_create_invoice_requested_notifications"), + ] + + operations = [ + migrations.AlterField( + model_name="notificationtemplate", + name="type", + field=models.CharField( + choices=[ + ("reservation_requested", "Reservation requested"), + ( + "reservation_requested_official", + "Reservation requested official", + ), + ("reservation_requested", "Reservation invoice requested"), + ( + "reservation_requested_official", + "Reservation invoice requested official", + ), + ("reservation_cancelled", "Reservation cancelled"), + ( + "reservation_cancelled_official", + "Reservation cancelled official", + ), + ("reservation_confirmed", "Reservation confirmed"), + ( + "reservation_confirmed_official", + "Reservation confirmed official", + ), + ("reservation_created", "Reservation created"), + ("reservation_changed", "Reservation changed"), + ("reservation_denied", "Reservation denied"), + ("reservation_denied_official", "Reservation denied official"), + ( + "reservation_created_with_access_code", + "Reservation created with access code", + ), + ( + "reservation_access_code_created", + "Access code was created for a reservation", + ), + ("paid_reservation_approved", "Paid reservation approved"), + ( + "paid_reservation_approved_official", + "Paid reservation approved official", + ), + ("catering_order_created", "Catering order created"), + ("catering_order_modified", "Catering order modified"), + ("catering_order_deleted", "Catering order deleted"), + ("reservation_comment_created", "Reservation comment created"), + ( + "catering_order_comment_created", + "Catering order comment created", + ), + ("reservation_reminder", "Reservation reminder"), + ], + db_index=True, + max_length=100, + unique=True, + verbose_name="Type", + ), + ), + ] diff --git a/notifications/migrations/0013_create_reservation_reminder_notification.py b/notifications/migrations/0013_create_reservation_reminder_notification.py new file mode 100644 index 000000000..3283f8b55 --- /dev/null +++ b/notifications/migrations/0013_create_reservation_reminder_notification.py @@ -0,0 +1,92 @@ +# Generated by Django 2.2.11 on 2024-12-19 08:35 + +from django.db import migrations +from django.template import Context, Template + +BODY_TEMPLATES = { + "en": """ +Hello, + +{{ message }} + +{% verbatim %} +Resource: {{ resource }} +Unit: {{ unit }} +Starts: {{ begin }} +Ends: {{ end }} +{% endverbatim %} + +This is an automated message, please don't reply to this. + +Best regards, +Varaamo +""", + "fi": """ +Hei, + +{{ message }} + +{% verbatim %} +Tila: {{ resource }} +Toimipiste: {{ unit }} +Alkaa: {{ begin }} +Päättyy: {{ end }} +{% endverbatim %} + +Tämä on automaattinen viesti, joten ethän vastaa tähän. + +Ystävällisin terveisin, +Varaamo +""", +} + + +def forwards(apps, schema_editor): + NotificationTemplate = apps.get_model("notifications", "NotificationTemplate") + NotificationTemplateTranslation = apps.get_model( + "notifications", + "NotificationTemplateTranslation", + ) + + notification, created = NotificationTemplate.objects.get_or_create( + type="reservation_reminder" + ) + if created: + translations = [] + for language, subject, message in [ + ( + "en", + "Upcoming reservation", + "You have a reservation coming up soon:", + ), + ( + "fi", + "Muistathan lähestyvän varauksesi", + "Sinulla on pian varaus:", + ), + ]: + body = Template(BODY_TEMPLATES[language]).render( + Context( + { + "message": message, + } + ) + ) + translations.append( + NotificationTemplateTranslation( + master_id=notification.id, + language_code=language, + subject=subject, + body=body, + ) + ) + NotificationTemplateTranslation.objects.bulk_create(translations) + + +class Migration(migrations.Migration): + + dependencies = [ + ("notifications", "0012_add_reservation_reminder_type"), + ] + + operations = [migrations.RunPython(forwards, migrations.RunPython.noop)] diff --git a/notifications/models.py b/notifications/models.py index 025424998..f4085486f 100644 --- a/notifications/models.py +++ b/notifications/models.py @@ -46,6 +46,8 @@ class NotificationType: RESERVATION_COMMENT_CREATED = "reservation_comment_created" CATERING_ORDER_COMMENT_CREATED = "catering_order_comment_created" + RESERVATION_REMINDER = "reservation_reminder" + class NotificationTemplateException(Exception): pass @@ -107,6 +109,7 @@ class NotificationTemplate(TranslatableModel): NotificationType.CATERING_ORDER_COMMENT_CREATED, _("Catering order comment created"), ), + (NotificationType.RESERVATION_REMINDER, _("Reservation reminder")), ) type = models.CharField( diff --git a/notifications/tests/test_send_reservation_reminders.py b/notifications/tests/test_send_reservation_reminders.py new file mode 100644 index 000000000..1a67ed2ad --- /dev/null +++ b/notifications/tests/test_send_reservation_reminders.py @@ -0,0 +1,69 @@ +from datetime import timedelta +from unittest import mock + +import pytest +from django.core.management import call_command +from django.utils import timezone + +from resources.models import Reservation, Resource, ResourceType, Unit + + +@pytest.fixture +def reservation(): + resource_type = ResourceType.objects.get_or_create(main_type="space", name="space")[0] + unit = Unit.objects.create(name="Test unit") + resource = Resource.objects.create( + name="Test resource", + type=resource_type, + unit=unit, + ) + reservation = Reservation.objects.create( + resource=resource, + begin=timezone.now() + timedelta(hours=23), + end=timezone.now() + timedelta(hours=24), + reminder_sent=False, + ) + return reservation + + +@pytest.mark.django_db +def test_send_reservation_reminder(reservation): + """ + Test that the reminder is sent and the reminder_sent field is updated. + """ + with mock.patch( + "resources.models.Reservation.send_reservation_mail" + ) as mock_send_mail: + call_command("send_reservation_reminders") + reservation.refresh_from_db() + assert reservation.reminder_sent is True + mock_send_mail.assert_called_once_with(notification_type="reservation_reminder") + + +@pytest.mark.django_db +def test_no_reminder_if_already_sent(reservation): + """ + Test that the reminder is not sent if it has already been sent. + """ + reservation.reminder_sent = True + reservation.save() + with mock.patch( + "resources.models.Reservation.send_reservation_mail" + ) as mock_send_mail: + call_command("send_reservation_reminders") + mock_send_mail.assert_not_called() + + +@pytest.mark.django_db +def test_no_reminder_for_reservation_not_within_24_hours(reservation): + """ + Test that the reminder is not sent if the reservation is not in the next 24 hours. + """ + reservation.begin = timezone.now() + timedelta(days=2) + reservation.end = timezone.now() + timedelta(days=2, hours=1) + reservation.save() + with mock.patch( + "notifications.management.commands.send_reservation_reminders.send_reservation_reminder" + ) as mock_send_reminder: + call_command("send_reservation_reminders") + mock_send_reminder.assert_not_called() diff --git a/resources/migrations/0123_reservation_reminder_sent.py b/resources/migrations/0123_reservation_reminder_sent.py new file mode 100644 index 000000000..5c0fd115a --- /dev/null +++ b/resources/migrations/0123_reservation_reminder_sent.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.11 on 2024-12-18 13:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0122_auto_20241218_1457'), + ] + + operations = [ + migrations.AddField( + model_name='reservation', + name='reminder_sent', + field=models.BooleanField(default=False, verbose_name='Reminder sent'), + ), + ] diff --git a/resources/models/reservation.py b/resources/models/reservation.py index fd3f9dde5..468ab8572 100644 --- a/resources/models/reservation.py +++ b/resources/models/reservation.py @@ -193,6 +193,7 @@ class Reservation(ModifiableModel): state = models.CharField( max_length=32, choices=STATE_CHOICES, verbose_name=_("State"), default=CREATED ) + reminder_sent = models.BooleanField(default=False, verbose_name=_("Reminder sent")) approver = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Approver"), From 5138f8c24019d6ce9f6792bd2c49b8a61b772e0e Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Wed, 8 Jan 2025 09:28:18 +0200 Subject: [PATCH 05/14] Hide inactive purposes from respa admin resource form Add a new field `active` to the `Purpose` model. Admin users can change this field in Django admin. Hide inactive purposes from the resource form in the Respa admin. Refs TTVA-218 --- locale/fi/LC_MESSAGES/django.po | 3 +++ locale/sv/LC_MESSAGES/django.po | 3 +++ resources/migrations/0124_purpose_active.py | 18 ++++++++++++++++++ resources/models/resource.py | 4 ++++ respa_admin/forms.py | 2 +- respa_admin/tests/test_resource_forms.py | 16 ++++++++++++++-- 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 resources/migrations/0124_purpose_active.py diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index 5f325f77d..c03039508 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -2205,3 +2205,6 @@ msgstr "SAP:n vaatimia tietoja puuttuu: {}" msgid "Reservation reminder" msgstr "Muistutus varauksesta" + +msgid "Inactive purposes are not shown in the Respa admin." +msgstr "Jos käyttötarkoitus ei ole aktiivinen, sitä ei näytetä Respan adminissa." diff --git a/locale/sv/LC_MESSAGES/django.po b/locale/sv/LC_MESSAGES/django.po index 9ffd906f5..b2ebe75e8 100644 --- a/locale/sv/LC_MESSAGES/django.po +++ b/locale/sv/LC_MESSAGES/django.po @@ -1792,3 +1792,6 @@ msgstr "" msgid "Reservation reminder" msgstr "Bokningspåminnelse" + +msgid "Inactive purposes are not shown in the Respa admin." +msgstr "Inaktiva syften visas inte i Respa administratören." diff --git a/resources/migrations/0124_purpose_active.py b/resources/migrations/0124_purpose_active.py new file mode 100644 index 000000000..93de82ace --- /dev/null +++ b/resources/migrations/0124_purpose_active.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.11 on 2025-01-07 13:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0123_reservation_reminder_sent'), + ] + + operations = [ + migrations.AddField( + model_name='purpose', + name='active', + field=models.BooleanField(default=True, help_text='Inactive purposes are not shown in the Respa admin.', verbose_name='Active'), + ), + ] diff --git a/resources/models/resource.py b/resources/models/resource.py index 7d15a83e2..c16f63282 100644 --- a/resources/models/resource.py +++ b/resources/models/resource.py @@ -115,6 +115,10 @@ class Purpose(ModifiableModel, NameIdentifiedModel): ) name = models.CharField(verbose_name=_("Name"), max_length=200) public = models.BooleanField(default=True, verbose_name=_("Public")) + active = models.BooleanField( + default=True, + verbose_name=_("Active"), + help_text=_("Inactive purposes are not shown in the Respa admin.")) class Meta: verbose_name = _("purpose") diff --git a/respa_admin/forms.py b/respa_admin/forms.py index 06ef9fc21..f2321bf50 100644 --- a/respa_admin/forms.py +++ b/respa_admin/forms.py @@ -173,7 +173,7 @@ class Meta: class ResourceForm(forms.ModelForm): purposes = forms.ModelMultipleChoiceField( widget=RespaCheckboxSelect, - queryset=Purpose.objects.all(), + queryset=Purpose.objects.filter(active=True), required=True, ) diff --git a/respa_admin/tests/test_resource_forms.py b/respa_admin/tests/test_resource_forms.py index 253963ff6..4bad7fe81 100644 --- a/respa_admin/tests/test_resource_forms.py +++ b/respa_admin/tests/test_resource_forms.py @@ -6,9 +6,9 @@ from django.utils import translation from freezegun import freeze_time -from resources.models import Resource +from resources.models import Purpose, Resource -from ..forms import get_period_formset +from ..forms import ResourceForm, get_period_formset NEW_RESOURCE_URL = reverse_lazy("respa_admin:new-resource") @@ -236,3 +236,15 @@ def test_editing_resource_via_form_view(admin_client, valid_resource_form_data): edited_resource = Resource.objects.first() assert edited_resource.name_fi == "Edited name" assert resource.name_fi != edited_resource.name + + +@pytest.mark.django_db +def test_only_active_purposes_are_visible(): + active_purpose = Purpose.objects.create(name="Active Purpose", active=True) + inactive_purpose = Purpose.objects.create(name="Inactive Purpose", active=False) + + form = ResourceForm() + purposes_field = form.fields['purposes'] + + assert list(purposes_field.queryset) == [active_purpose] + assert inactive_purpose not in purposes_field.queryset From 674af76e07f46bb5742dc03b14340d5c863fdb5c Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Wed, 8 Jan 2025 10:07:18 +0200 Subject: [PATCH 06/14] Hide inactive terms of use from respa admin resource form Add a new field `active` to the `TermsOfUse` model. Admin users can change this field in Django admin. Hide inactive terms of use from the resource form in the Respa admin. Refs TTVA-218 --- locale/fi/LC_MESSAGES/django.po | 3 ++ locale/sv/LC_MESSAGES/django.po | 3 ++ .../migrations/0125_termsofuse_active.py | 18 +++++++++++ resources/models/resource.py | 5 +++ respa_admin/forms.py | 6 ++-- respa_admin/tests/test_resource_forms.py | 32 ++++++++++++++++++- 6 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 resources/migrations/0125_termsofuse_active.py diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index c03039508..ae84dd07e 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -2208,3 +2208,6 @@ msgstr "Muistutus varauksesta" msgid "Inactive purposes are not shown in the Respa admin." msgstr "Jos käyttötarkoitus ei ole aktiivinen, sitä ei näytetä Respan adminissa." + +msgid "Inactive terms are not shown in the Respa admin." +msgstr "Jos ehto ei ole aktiivinen, sitä ei näytetä Respan adminissa." diff --git a/locale/sv/LC_MESSAGES/django.po b/locale/sv/LC_MESSAGES/django.po index b2ebe75e8..f3c765b1a 100644 --- a/locale/sv/LC_MESSAGES/django.po +++ b/locale/sv/LC_MESSAGES/django.po @@ -1795,3 +1795,6 @@ msgstr "Bokningspåminnelse" msgid "Inactive purposes are not shown in the Respa admin." msgstr "Inaktiva syften visas inte i Respa administratören." + +msgid "Inactive terms are not shown in the Respa admin." +msgstr "Inaktiva villkor visas inte i Respa administratören." diff --git a/resources/migrations/0125_termsofuse_active.py b/resources/migrations/0125_termsofuse_active.py new file mode 100644 index 000000000..40546f1f1 --- /dev/null +++ b/resources/migrations/0125_termsofuse_active.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.11 on 2025-01-08 07:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0124_purpose_active'), + ] + + operations = [ + migrations.AddField( + model_name='termsofuse', + name='active', + field=models.BooleanField(default=True, help_text='Inactive terms are not shown in the Respa admin.', verbose_name='Active'), + ), + ] diff --git a/resources/models/resource.py b/resources/models/resource.py index c16f63282..15d59f5ad 100644 --- a/resources/models/resource.py +++ b/resources/models/resource.py @@ -148,6 +148,11 @@ class TermsOfUse(ModifiableModel, AutoIdentifiedModel): choices=TERMS_TYPES, default=TERMS_TYPE_GENERIC, ) + active = models.BooleanField( + default=True, + verbose_name=_("Active"), + help_text=_("Inactive terms are not shown in the Respa admin.") + ) class Meta: verbose_name = pgettext_lazy("singular", "terms of use") diff --git a/respa_admin/forms.py b/respa_admin/forms.py index f2321bf50..00f7fd74a 100644 --- a/respa_admin/forms.py +++ b/respa_admin/forms.py @@ -297,10 +297,12 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["generic_terms"].queryset = TermsOfUse.objects.filter( - terms_type=TermsOfUse.TERMS_TYPE_GENERIC + terms_type=TermsOfUse.TERMS_TYPE_GENERIC, + active=True, ) self.fields["payment_terms"].queryset = TermsOfUse.objects.filter( - terms_type=TermsOfUse.TERMS_TYPE_PAYMENT + terms_type=TermsOfUse.TERMS_TYPE_PAYMENT, + active=True, ) self.fields["authentication"].choices = [ choice diff --git a/respa_admin/tests/test_resource_forms.py b/respa_admin/tests/test_resource_forms.py index 4bad7fe81..26a901966 100644 --- a/respa_admin/tests/test_resource_forms.py +++ b/respa_admin/tests/test_resource_forms.py @@ -6,7 +6,7 @@ from django.utils import translation from freezegun import freeze_time -from resources.models import Purpose, Resource +from resources.models import Purpose, Resource, TermsOfUse from ..forms import ResourceForm, get_period_formset @@ -248,3 +248,33 @@ def test_only_active_purposes_are_visible(): assert list(purposes_field.queryset) == [active_purpose] assert inactive_purpose not in purposes_field.queryset + + +@pytest.mark.django_db +def test_only_active_terms_of_use_are_visible(): + active_generic_terms = TermsOfUse.objects.create( + name="Active Generic Terms", + terms_type=TermsOfUse.TERMS_TYPE_GENERIC, + active=True) + active_payment_terms = TermsOfUse.objects.create( + name="Active Payment Terms", + terms_type=TermsOfUse.TERMS_TYPE_PAYMENT, + active=True) + inactive_generic_terms = TermsOfUse.objects.create( + name="Inactive Generic Terms", + terms_type=TermsOfUse.TERMS_TYPE_GENERIC, + active=False) + inactive_payment_terms = TermsOfUse.objects.create( + name="Inactive Payment Terms", + terms_type=TermsOfUse.TERMS_TYPE_PAYMENT, + active=False) + + form = ResourceForm() + generic_terms_field = form.fields['generic_terms'] + payment_terms_field = form.fields['payment_terms'] + + assert list(generic_terms_field.queryset) == [active_generic_terms] + assert inactive_generic_terms not in generic_terms_field.queryset + + assert list(payment_terms_field.queryset) == [active_payment_terms] + assert inactive_payment_terms not in payment_terms_field.queryset From ff55bf46b49a42367c6b0671b08f2e5dac62da48 Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Wed, 8 Jan 2025 10:35:14 +0200 Subject: [PATCH 07/14] Hide inactive resource types from respa admin resource form Add a new field `active` to the `ResourceType` model. Admin users can change this field in Django admin. Hide inactive resource types from the resource form in the Respa admin. Refs TTVA-218 --- locale/fi/LC_MESSAGES/django.po | 3 +++ locale/sv/LC_MESSAGES/django.po | 3 +++ .../migrations/0126_resourcetype_active.py | 18 +++++++++++++++++ resources/models/resource.py | 5 +++++ respa_admin/forms.py | 2 ++ respa_admin/tests/test_resource_forms.py | 20 ++++++++++++++++++- 6 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 resources/migrations/0126_resourcetype_active.py diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index ae84dd07e..4c9681f06 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -2211,3 +2211,6 @@ msgstr "Jos käyttötarkoitus ei ole aktiivinen, sitä ei näytetä Respan admin msgid "Inactive terms are not shown in the Respa admin." msgstr "Jos ehto ei ole aktiivinen, sitä ei näytetä Respan adminissa." + +msgid "Inactive resource types are not shown in the Respa admin." +msgstr "Jos resurssityyppi ei ole aktiivinen, sitä ei näytetä Respan adminissa." diff --git a/locale/sv/LC_MESSAGES/django.po b/locale/sv/LC_MESSAGES/django.po index f3c765b1a..fc3ae1cea 100644 --- a/locale/sv/LC_MESSAGES/django.po +++ b/locale/sv/LC_MESSAGES/django.po @@ -1798,3 +1798,6 @@ msgstr "Inaktiva syften visas inte i Respa administratören." msgid "Inactive terms are not shown in the Respa admin." msgstr "Inaktiva villkor visas inte i Respa administratören." + +msgid "Inactive resource types are not shown in the Respa admin." +msgstr "Inaktiva resurstyper visas inte i Respa administratören." diff --git a/resources/migrations/0126_resourcetype_active.py b/resources/migrations/0126_resourcetype_active.py new file mode 100644 index 000000000..72dfb67e1 --- /dev/null +++ b/resources/migrations/0126_resourcetype_active.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.11 on 2025-01-08 08:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0125_termsofuse_active'), + ] + + operations = [ + migrations.AddField( + model_name='resourcetype', + name='active', + field=models.BooleanField(default=True, help_text='Inactive resource types are not shown in the Respa admin.', verbose_name='Active'), + ), + ] diff --git a/resources/models/resource.py b/resources/models/resource.py index 15d59f5ad..f81c50480 100644 --- a/resources/models/resource.py +++ b/resources/models/resource.py @@ -93,6 +93,11 @@ class ResourceType(ModifiableModel, AutoIdentifiedModel): verbose_name=_("Main type"), max_length=20, choices=MAIN_TYPES ) name = models.CharField(verbose_name=_("Name"), max_length=200) + active = models.BooleanField( + default=True, + verbose_name=_("Active"), + help_text=_("Inactive resource types are not shown in the Respa admin.") + ) class Meta: verbose_name = _("resource type") diff --git a/respa_admin/forms.py b/respa_admin/forms.py index 00f7fd74a..712ca5835 100644 --- a/respa_admin/forms.py +++ b/respa_admin/forms.py @@ -14,6 +14,7 @@ ResourceAccess, ResourceAccessibility, ResourceImage, + ResourceType, TermsOfUse, Unit, UnitAuthorization, @@ -296,6 +297,7 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.fields["type"].queryset = ResourceType.objects.filter(active=True) self.fields["generic_terms"].queryset = TermsOfUse.objects.filter( terms_type=TermsOfUse.TERMS_TYPE_GENERIC, active=True, diff --git a/respa_admin/tests/test_resource_forms.py b/respa_admin/tests/test_resource_forms.py index 26a901966..52152fe23 100644 --- a/respa_admin/tests/test_resource_forms.py +++ b/respa_admin/tests/test_resource_forms.py @@ -6,7 +6,7 @@ from django.utils import translation from freezegun import freeze_time -from resources.models import Purpose, Resource, TermsOfUse +from resources.models import Purpose, Resource, ResourceType, TermsOfUse from ..forms import ResourceForm, get_period_formset @@ -278,3 +278,21 @@ def test_only_active_terms_of_use_are_visible(): assert list(payment_terms_field.queryset) == [active_payment_terms] assert inactive_payment_terms not in payment_terms_field.queryset + + +@pytest.mark.django_db +def test_only_active_resource_types_are_visible(): + active_resource_type = ResourceType.objects.create( + name="Active space", + main_type="space", + active=True) + inactive_resource_type = ResourceType.objects.create( + name="Inactive space", + main_type="space", + active=False) + + form = ResourceForm() + resource_type_field = form.fields['type'] + + assert list(resource_type_field.queryset) == [active_resource_type] + assert inactive_resource_type not in resource_type_field.queryset From 4999a5f3b78b3802c1d69530152880b31c2f86ea Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Wed, 8 Jan 2025 11:30:52 +0200 Subject: [PATCH 08/14] Hide inactive reservation metadata sets from respa admin resource form Add a new field `active` to the `ReservationMetadataSet` model. Admin users can change this field in Django admin. Hide inactive reservation metadata sets from the resource form in the Respa admin. Refs TTVA-218 --- locale/fi/LC_MESSAGES/django.po | 3 +++ locale/sv/LC_MESSAGES/django.po | 3 +++ .../0127_reservationmetadataset_active.py | 18 ++++++++++++++++++ resources/models/reservation.py | 5 +++++ respa_admin/forms.py | 4 ++++ respa_admin/tests/test_resource_forms.py | 18 +++++++++++++++++- 6 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 resources/migrations/0127_reservationmetadataset_active.py diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index 4c9681f06..cbcb6a7ea 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -2214,3 +2214,6 @@ msgstr "Jos ehto ei ole aktiivinen, sitä ei näytetä Respan adminissa." msgid "Inactive resource types are not shown in the Respa admin." msgstr "Jos resurssityyppi ei ole aktiivinen, sitä ei näytetä Respan adminissa." + +msgid "Inactive metadata sets are not shown in the resource form in Respa admin." +msgstr "Jos metatietojoukko ei ole aktiivinen, sitä ei näytetä resurssin lomakkeessa Respan adminissa." diff --git a/locale/sv/LC_MESSAGES/django.po b/locale/sv/LC_MESSAGES/django.po index fc3ae1cea..ace2dc6d1 100644 --- a/locale/sv/LC_MESSAGES/django.po +++ b/locale/sv/LC_MESSAGES/django.po @@ -1801,3 +1801,6 @@ msgstr "Inaktiva villkor visas inte i Respa administratören." msgid "Inactive resource types are not shown in the Respa admin." msgstr "Inaktiva resurstyper visas inte i Respa administratören." + +msgid "Inactive metadata sets are not shown in the resource form in Respa admin." +msgstr "Inaktiva metadatauppsättningar visas inte i resursformuläret i Respa administratören." diff --git a/resources/migrations/0127_reservationmetadataset_active.py b/resources/migrations/0127_reservationmetadataset_active.py new file mode 100644 index 000000000..218ab2517 --- /dev/null +++ b/resources/migrations/0127_reservationmetadataset_active.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.11 on 2025-01-08 08:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0126_resourcetype_active'), + ] + + operations = [ + migrations.AddField( + model_name='reservationmetadataset', + name='active', + field=models.BooleanField(default=True, help_text='Inactive metadata sets are not shown in the resource form in Respa admin.', verbose_name='Active'), + ), + ] diff --git a/resources/models/reservation.py b/resources/models/reservation.py index 468ab8572..3b4e42a54 100644 --- a/resources/models/reservation.py +++ b/resources/models/reservation.py @@ -1027,6 +1027,11 @@ class ReservationMetadataSet(ModifiableModel): related_name="metadata_sets_required", blank=True, ) + active = models.BooleanField( + default=True, + verbose_name=_("Active"), + help_text=_("Inactive metadata sets are not shown in the resource form in Respa admin."), + ) class Meta: verbose_name = _("Reservation metadata set") diff --git a/respa_admin/forms.py b/respa_admin/forms.py index 712ca5835..594f10cd8 100644 --- a/respa_admin/forms.py +++ b/respa_admin/forms.py @@ -10,6 +10,7 @@ Equipment, Period, Purpose, + ReservationMetadataSet, Resource, ResourceAccess, ResourceAccessibility, @@ -312,6 +313,9 @@ def __init__(self, *args, **kwargs): if choice[0] not in ["", "none"] ] self.fields["authentication"].initial = ["weak"] + self.fields["reservation_metadata_set"].queryset = ( + ReservationMetadataSet.objects.filter(active=True) + ) def clean_notification_email_addresses(self): notification_email_addresses = self.cleaned_data["notification_email_addresses"] diff --git a/respa_admin/tests/test_resource_forms.py b/respa_admin/tests/test_resource_forms.py index 52152fe23..c2623d39c 100644 --- a/respa_admin/tests/test_resource_forms.py +++ b/respa_admin/tests/test_resource_forms.py @@ -6,7 +6,7 @@ from django.utils import translation from freezegun import freeze_time -from resources.models import Purpose, Resource, ResourceType, TermsOfUse +from resources.models import Purpose, ReservationMetadataSet, Resource, ResourceType, TermsOfUse from ..forms import ResourceForm, get_period_formset @@ -296,3 +296,19 @@ def test_only_active_resource_types_are_visible(): assert list(resource_type_field.queryset) == [active_resource_type] assert inactive_resource_type not in resource_type_field.queryset + + +@pytest.mark.django_db +def test_only_reservation_metadata_sets_are_visible(): + active_metadata_set = ReservationMetadataSet.objects.create( + name="Active metadata set", + active=True) + inactive_metadata_set = ReservationMetadataSet.objects.create( + name="Inactive metadata set", + active=False) + + form = ResourceForm() + metadata_set_field = form.fields['reservation_metadata_set'] + + assert list(metadata_set_field.queryset) == [active_metadata_set] + assert inactive_metadata_set not in metadata_set_field.queryset From c1487033f37ce30afe60cb1c02e748195a981a9e Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Wed, 8 Jan 2025 13:57:03 +0200 Subject: [PATCH 09/14] Hide inactive equipments from respa admin resource form Add a new field `active` to the `Equipment` model. Admin users can change this field in Django admin. Hide inactive equipments from the resource form in the Respa admin. Refs TTVA-218 --- locale/fi/LC_MESSAGES/django.po | 3 +++ locale/sv/LC_MESSAGES/django.po | 3 +++ resources/migrations/0128_equipment_active.py | 18 +++++++++++++ resources/models/equipment.py | 5 ++++ respa_admin/forms.py | 2 +- respa_admin/tests/test_resource_forms.py | 26 ++++++++++++++++++- 6 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 resources/migrations/0128_equipment_active.py diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index cbcb6a7ea..4351c02db 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -2217,3 +2217,6 @@ msgstr "Jos resurssityyppi ei ole aktiivinen, sitä ei näytetä Respan adminiss msgid "Inactive metadata sets are not shown in the resource form in Respa admin." msgstr "Jos metatietojoukko ei ole aktiivinen, sitä ei näytetä resurssin lomakkeessa Respan adminissa." + +msgid "Inactive equipment is not shown in the Respa admin." +msgstr "Jos varuste ei ole aktiivinen, sitä ei näytetä Respan adminissa." diff --git a/locale/sv/LC_MESSAGES/django.po b/locale/sv/LC_MESSAGES/django.po index ace2dc6d1..19ef60a43 100644 --- a/locale/sv/LC_MESSAGES/django.po +++ b/locale/sv/LC_MESSAGES/django.po @@ -1804,3 +1804,6 @@ msgstr "Inaktiva resurstyper visas inte i Respa administratören." msgid "Inactive metadata sets are not shown in the resource form in Respa admin." msgstr "Inaktiva metadatauppsättningar visas inte i resursformuläret i Respa administratören." + +msgid "Inactive equipment is not shown in the Respa admin." +msgstr "Inaktiva utrustningar visas inte i Respa administratören." diff --git a/resources/migrations/0128_equipment_active.py b/resources/migrations/0128_equipment_active.py new file mode 100644 index 000000000..c2af0bec9 --- /dev/null +++ b/resources/migrations/0128_equipment_active.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.11 on 2025-01-08 11:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0127_reservationmetadataset_active'), + ] + + operations = [ + migrations.AddField( + model_name='equipment', + name='active', + field=models.BooleanField(default=True, help_text='Inactive equipment is not shown in the Respa admin.', verbose_name='Active'), + ), + ] diff --git a/resources/models/equipment.py b/resources/models/equipment.py index 659622560..87f04fbfc 100644 --- a/resources/models/equipment.py +++ b/resources/models/equipment.py @@ -24,6 +24,11 @@ class Equipment(ModifiableModel, AutoIdentifiedModel): name = models.CharField(verbose_name=_('Name'), max_length=200) category = models.ForeignKey(EquipmentCategory, verbose_name=_('Category'), related_name='equipment', on_delete=models.CASCADE) + active = models.BooleanField( + default=True, + verbose_name=_('Active'), + help_text=_('Inactive equipment is not shown in the Respa admin.') + ) class Meta: verbose_name = pgettext_lazy('singular', 'equipment') diff --git a/respa_admin/forms.py b/respa_admin/forms.py index 594f10cd8..572e41185 100644 --- a/respa_admin/forms.py +++ b/respa_admin/forms.py @@ -182,7 +182,7 @@ class ResourceForm(forms.ModelForm): equipment = forms.ModelMultipleChoiceField( required=False, widget=RespaCheckboxSelect, - queryset=Equipment.objects.all(), + queryset=Equipment.objects.filter(active=True), ) name_fi = forms.CharField( diff --git a/respa_admin/tests/test_resource_forms.py b/respa_admin/tests/test_resource_forms.py index c2623d39c..574b14468 100644 --- a/respa_admin/tests/test_resource_forms.py +++ b/respa_admin/tests/test_resource_forms.py @@ -6,7 +6,9 @@ from django.utils import translation from freezegun import freeze_time -from resources.models import Purpose, ReservationMetadataSet, Resource, ResourceType, TermsOfUse +from resources.models import ( + Equipment, EquipmentCategory, Purpose, ReservationMetadataSet, Resource, ResourceType, TermsOfUse +) from ..forms import ResourceForm, get_period_formset @@ -312,3 +314,25 @@ def test_only_reservation_metadata_sets_are_visible(): assert list(metadata_set_field.queryset) == [active_metadata_set] assert inactive_metadata_set not in metadata_set_field.queryset + + +@pytest.mark.django_db +def test_only_active_equipments_are_visible(): + category = EquipmentCategory.objects.create( + id="category", + name="Category" + ) + active_equipment = Equipment.objects.create( + name="Active equipment", + category=category, + active=True) + inactive_equipment = Equipment.objects.create( + name="Inactive equipment", + category=category, + active=False) + + form = ResourceForm() + equipment_field = form.fields['equipment'] + + assert list(equipment_field.queryset) == [active_equipment] + assert inactive_equipment not in equipment_field.queryset From 70129400aa8c5e9e4cf6c81c8a6a0f53e6889815 Mon Sep 17 00:00:00 2001 From: Pauliina Ilmanen Date: Thu, 9 Jan 2025 13:17:35 +0200 Subject: [PATCH 10/14] Rename people_capacity to people_capacity_lower People capacity will be split into two fields: `people_capacity_lower` and `people_capacity_upper` for adding a possibility to define a range of the space capacity. Rename the `people_capacity` field to `people_capacity_lower` in the `Resource` model and keep the data of the original field in this new field. Keep the original name `people_capacity` in the API until UI changes are done. Refs TTVA-217 --- .sanitizerconfig | 2 +- openapi.yaml | 4 ++-- resources/api/resource.py | 5 ++-- resources/importer/kirjasto10.py | 6 ++--- .../migrations/0129_rename_people_capacity.py | 18 ++++++++++++++ resources/models/resource.py | 2 +- resources/tests/test_resource_api.py | 24 +++++++++---------- respa_admin/forms.py | 2 +- .../respa_admin/resources/form/_booking.html | 2 +- respa_admin/tests/conftest.py | 2 +- 10 files changed, 43 insertions(+), 24 deletions(-) create mode 100644 resources/migrations/0129_rename_people_capacity.py diff --git a/.sanitizerconfig b/.sanitizerconfig index fc48ac74b..b2de98372 100644 --- a/.sanitizerconfig +++ b/.sanitizerconfig @@ -372,7 +372,7 @@ strategy: name_fi: null name_sv: null need_manual_confirmation: null - people_capacity: null + people_capacity_lower: null public: null reservable: null reservable_days_in_advance: null diff --git a/openapi.yaml b/openapi.yaml index 3b28da599..21d4fd633 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -526,7 +526,7 @@ paths: in: query description: Order queryset by given resource fields, accepted values are `resource_name_fi`, `resource_name_en`, `resource_name_sv`, `unit_name_fi`, - `unit_name_en`, `unit_name_sv`, `type`, `people_capacity`. Prefix parameter + `unit_name_en`, `unit_name_sv`, `type`, `people_capacity_lower`. Prefix parameter value with `-` to get reverse ordering. schema: type: string @@ -1043,7 +1043,7 @@ components: authentication: type: string description: The type of authentication required to reserve the resource - people_capacity: + people_capacity_lower: type: number description: The maximum number of people for the resource area: diff --git a/resources/api/resource.py b/resources/api/resource.py index 906011019..2edc57d35 100644 --- a/resources/api/resource.py +++ b/resources/api/resource.py @@ -198,6 +198,7 @@ class ResourceSerializer( ExtraDataMixin, TranslatedModelSerializer, munigeo_api.GeoModelSerializer ): purposes = PurposeSerializer(many=True) + people_capacity = serializers.IntegerField(source='people_capacity_lower') images = NestedResourceImageSerializer(many=True) equipment = ResourceEquipmentSerializer( many=True, read_only=True, source="resource_equipment" @@ -677,7 +678,7 @@ def __init__(self, *args, **kwargs): field_name="type__id", lookup_expr="in", widget=django_filters.widgets.CSVWidget ) people = django_filters.NumberFilter( - field_name="people_capacity", lookup_expr="gte" + field_name="people_capacity_lower", lookup_expr="gte" ) need_manual_confirmation = django_filters.BooleanFilter( field_name="need_manual_confirmation", widget=DRFFilterBooleanWidget @@ -721,7 +722,7 @@ def __init__(self, *args, **kwargs): ("type__name_fi", "type_name_fi"), ("type__name_en", "type_name_en"), ("type__name_sv", "type_name_sv"), - ("people_capacity", "people_capacity"), + ("people_capacity_lower", "people_capacity_lower"), ("accessibility_priority", "accessibility"), ), ) diff --git a/resources/importer/kirjasto10.py b/resources/importer/kirjasto10.py index 80101d9f1..38ea16571 100644 --- a/resources/importer/kirjasto10.py +++ b/resources/importer/kirjasto10.py @@ -94,9 +94,9 @@ def import_resources(self): except ValueError: area = None try: - people_capacity = int(res_data['Max henkilömäärä']) + people_capacity_lower = int(res_data['Max henkilömäärä']) except ValueError: - people_capacity = None + people_capacity_lower = None try: min_period = datetime.timedelta(minutes=int(60 * float(res_data['Varausaika min'].replace(',', '.')))) except ValueError: @@ -119,7 +119,7 @@ def import_resources(self): data = dict( unit_id=unit.pk, - people_capacity=people_capacity, + people_capacity_lower=people_capacity_lower, area=area, need_manual_confirmation=confirm, min_period=min_period, diff --git a/resources/migrations/0129_rename_people_capacity.py b/resources/migrations/0129_rename_people_capacity.py new file mode 100644 index 000000000..0aca609e7 --- /dev/null +++ b/resources/migrations/0129_rename_people_capacity.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.11 on 2025-01-09 10:15 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('resources', '0128_equipment_active'), + ] + + operations = [ + migrations.RenameField( + model_name='resource', + old_name='people_capacity', + new_name='people_capacity_lower', + ), + ] diff --git a/resources/models/resource.py b/resources/models/resource.py index f81c50480..75d9be75b 100644 --- a/resources/models/resource.py +++ b/resources/models/resource.py @@ -332,7 +332,7 @@ class Resource(ModifiableModel, AutoIdentifiedModel): max_length=20, choices=AUTHENTICATION_TYPES, ) - people_capacity = models.PositiveIntegerField( + people_capacity_lower = models.PositiveIntegerField( verbose_name=_("People capacity"), null=True, blank=True ) area = models.PositiveIntegerField( diff --git a/resources/tests/test_resource_api.py b/resources/tests/test_resource_api.py index f1f5d0581..5dbd138da 100644 --- a/resources/tests/test_resource_api.py +++ b/resources/tests/test_resource_api.py @@ -1487,34 +1487,34 @@ def test_order_by_filter(list_url, api_client, resource_in_unit, resource_in_uni assert response.data["results"][0]["type"]["id"] == resource_in_unit2.type.id # test resource people capacity - resource_in_unit.people_capacity = 1 + resource_in_unit.people_capacity_lower = 1 resource_in_unit.save() - resource_in_unit2.people_capacity = 50 + resource_in_unit2.people_capacity_lower = 50 resource_in_unit2.save() - response = api_client.get("%s?order_by=people_capacity" % list_url) + response = api_client.get("%s?order_by=people_capacity_lower" % list_url) assert response.status_code == 200 assert_response_objects(response, [resource_in_unit, resource_in_unit2]) assert ( - response.data["results"][0]["people_capacity"] - == resource_in_unit.people_capacity + response.data["results"][0]["people_capacity_lower"] + == resource_in_unit.people_capacity_lower ) assert ( - response.data["results"][1]["people_capacity"] - == resource_in_unit2.people_capacity + response.data["results"][1]["people_capacity_lower"] + == resource_in_unit2.people_capacity_lower ) - response = api_client.get("%s?order_by=-people_capacity" % list_url) + response = api_client.get("%s?order_by=-people_capacity_lower" % list_url) assert response.status_code == 200 assert_response_objects(response, [resource_in_unit, resource_in_unit2]) assert ( - response.data["results"][1]["people_capacity"] - == resource_in_unit.people_capacity + response.data["results"][1]["people_capacity_lower"] + == resource_in_unit.people_capacity_lower ) assert ( - response.data["results"][0]["people_capacity"] - == resource_in_unit2.people_capacity + response.data["results"][0]["people_capacity_lower"] + == resource_in_unit2.people_capacity_lower ) diff --git a/respa_admin/forms.py b/respa_admin/forms.py index 572e41185..c9086e310 100644 --- a/respa_admin/forms.py +++ b/respa_admin/forms.py @@ -240,7 +240,7 @@ class Meta: "equipment", "access_methods", "external_reservation_url", - "people_capacity", + "people_capacity_lower", "area", "min_period", "max_period", diff --git a/respa_admin/templates/respa_admin/resources/form/_booking.html b/respa_admin/templates/respa_admin/resources/form/_booking.html index 1cc9b7934..336f7ef2f 100644 --- a/respa_admin/templates/respa_admin/resources/form/_booking.html +++ b/respa_admin/templates/respa_admin/resources/form/_booking.html @@ -6,7 +6,7 @@

{% trans "Booking information" %}

{% trans "*Mandatory fields" %}
- {% include "respa_admin/forms/_input.html" with field=form.people_capacity %} + {% include "respa_admin/forms/_input.html" with field=form.people_capacity_lower %} {% include "respa_admin/forms/_input.html" with field=form.area %}
{% include "respa_admin/forms/_input.html" with field=form.people_capacity_lower %} + {% include "respa_admin/forms/_input.html" with field=form.people_capacity_upper %} {% include "respa_admin/forms/_input.html" with field=form.area %}
{% include "respa_admin/forms/_input.html" with field=form.people_capacity_lower %} - {% include "respa_admin/forms/_input.html" with field=form.people_capacity_upper %} {% include "respa_admin/forms/_input.html" with field=form.area %}