From 4b4204db1041d56bc8ee3ef4d696ecaf98001922 Mon Sep 17 00:00:00 2001 From: Matti Lamppu Date: Wed, 18 Sep 2024 13:01:40 +0300 Subject: [PATCH] Move terms of use to the new app --- applications/admin/application_round/form.py | 5 +- ...094_alter_applicationround_terms_of_use.py | 30 ++++ applications/models/application_round.py | 2 +- .../commands/data_creation/create_caisa.py | 27 ++-- .../data_creation/create_reservation_units.py | 24 ++-- config/settings.py | 2 +- locale/fi/LC_MESSAGES/django.po | 129 ++++++++---------- locale/sv/LC_MESSAGES/django.po | 123 ++++++++--------- .../admin/reservation_unit/form.py | 11 +- ...rvationunit_cancellation_terms_and_more.py | 64 +++++++++ reservation_units/models/reservation_unit.py | 11 +- .../terms_of_use/booking_terms.jinja | 0 .../terms_of_use/components/base.jinja | 0 terms_of_use/admin/__init__.py | 5 - terms_of_use/admin/terms_of_use.py | 46 ------- terms_of_use/apps.py | 5 - .../migrations/0006_delete_termsofuse.py | 22 +++ terms_of_use/models.py | 61 --------- terms_of_use/translation.py | 8 -- tests/factories/terms_of_use.py | 5 +- .../test_reservation_unit_admin_terms.py | 18 +-- .../test_reservation_unit/test_query.py | 10 +- .../test_update_draft.py | 8 +- .../test_update_not_draft.py | 4 +- tests/test_rest_api/test_terms_pdf.py | 6 +- tilavarauspalvelu/admin/__init__.py | 2 + tilavarauspalvelu/admin/terms_of_use/admin.py | 46 +++++++ .../graphql/types/terms_of_use/filtersets.py | 2 +- .../api/graphql/types/terms_of_use/types.py | 2 +- tilavarauspalvelu/api/rest/views.py | 2 +- tilavarauspalvelu/enums.py | 10 ++ .../migrations/0002_termsofuse.py | 54 ++++++++ tilavarauspalvelu/models/__init__.py | 2 + .../models/terms_of_use/actions.py | 14 ++ .../models/terms_of_use/model.py | 62 +++++++++ .../models/terms_of_use/queryset.py | 10 ++ tilavarauspalvelu/translation.py | 7 +- 37 files changed, 504 insertions(+), 335 deletions(-) create mode 100644 applications/migrations/0094_alter_applicationround_terms_of_use.py create mode 100644 reservation_units/migrations/0106_alter_reservationunit_cancellation_terms_and_more.py rename {terms_of_use/templates => templates}/terms_of_use/booking_terms.jinja (100%) rename {terms_of_use/templates => templates}/terms_of_use/components/base.jinja (100%) delete mode 100644 terms_of_use/admin/__init__.py delete mode 100644 terms_of_use/admin/terms_of_use.py delete mode 100644 terms_of_use/apps.py create mode 100644 terms_of_use/migrations/0006_delete_termsofuse.py delete mode 100644 terms_of_use/models.py delete mode 100644 terms_of_use/translation.py create mode 100644 tilavarauspalvelu/migrations/0002_termsofuse.py diff --git a/applications/admin/application_round/form.py b/applications/admin/application_round/form.py index 307da47b9..7240756a0 100644 --- a/applications/admin/application_round/form.py +++ b/applications/admin/application_round/form.py @@ -9,7 +9,8 @@ from applications.models import ApplicationRound from common.fields.forms import disabled_widget from reservation_units.models import ReservationUnit -from terms_of_use.models import TermsOfUse +from tilavarauspalvelu.enums import TermsOfUseTypeChoices +from tilavarauspalvelu.models import TermsOfUse class ApplicationRoundAdminForm(forms.ModelForm): @@ -41,7 +42,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: kwargs["initial"]["status"] = ApplicationRoundStatusChoice(instance.status).label self.base_fields["reservation_units"].queryset = ReservationUnit.objects.select_related("unit").all() self.base_fields["terms_of_use"].queryset = TermsOfUse.objects.filter( - terms_type=TermsOfUse.TERMS_TYPE_RECURRING + terms_type=TermsOfUseTypeChoices.RECURRING ) super().__init__(*args, **kwargs) diff --git a/applications/migrations/0094_alter_applicationround_terms_of_use.py b/applications/migrations/0094_alter_applicationround_terms_of_use.py new file mode 100644 index 000000000..1fee688fa --- /dev/null +++ b/applications/migrations/0094_alter_applicationround_terms_of_use.py @@ -0,0 +1,30 @@ +# Generated by Django 5.1.1 on 2024-09-18 09:48 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("applications", "0093_remove_applicationround_target_group"), + ("tilavarauspalvelu", "0002_termsofuse"), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.AlterField( + model_name="applicationround", + name="terms_of_use", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="application_rounds", + to="tilavarauspalvelu.termsofuse", + ), + ), + ], + # We just moved the model, so no need to modify foreign keys + database_operations=[], + ), + ] diff --git a/applications/models/application_round.py b/applications/models/application_round.py index 87e198f3b..438d3736c 100644 --- a/applications/models/application_round.py +++ b/applications/models/application_round.py @@ -67,7 +67,7 @@ class ApplicationRound(models.Model): related_name="application_rounds", ) terms_of_use = models.ForeignKey( - "terms_of_use.TermsOfUse", + "tilavarauspalvelu.TermsOfUse", null=True, blank=False, on_delete=models.SET_NULL, diff --git a/common/management/commands/data_creation/create_caisa.py b/common/management/commands/data_creation/create_caisa.py index 161ce9c88..eb267d9c5 100644 --- a/common/management/commands/data_creation/create_caisa.py +++ b/common/management/commands/data_creation/create_caisa.py @@ -23,7 +23,8 @@ ) from reservations.models import ReservationMetadataSet from spaces.models import Space, Unit -from terms_of_use.models import TermsOfUse +from tilavarauspalvelu.enums import TermsOfUseTypeChoices +from tilavarauspalvelu.models import TermsOfUse from .utils import SetName, with_logs @@ -67,7 +68,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "name_en": "Payment terms - free of charge", "name_sv": "Betalningsvillkor - kostnadsfritt", "text": "", - "terms_type": TermsOfUse.TERMS_TYPE_PAYMENT, + "terms_type": TermsOfUseTypeChoices.PAYMENT, }, ) payment_terms_1, _ = TermsOfUse.objects.get_or_create( @@ -82,7 +83,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "Palvelussa ilmoitetut hinnat sisältävät arvolisäveron. " "Mahdolliset lisäpalvelut eivät sisälly hintaan.", ), - "terms_type": TermsOfUse.TERMS_TYPE_PAYMENT, + "terms_type": TermsOfUseTypeChoices.PAYMENT, }, ) payment_terms_3, _ = TermsOfUse.objects.get_or_create( @@ -103,7 +104,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "vähintään 18 vuoden ikää. Palvelussa ilmoitetut hinnat sisältävät arvolisäveron. " "Mahdolliset lisäpalvelut eivät sisälly hintaan.", ), - "terms_type": TermsOfUse.TERMS_TYPE_PAYMENT, + "terms_type": TermsOfUseTypeChoices.PAYMENT, }, ) payment_terms_4, _ = TermsOfUse.objects.get_or_create( @@ -124,7 +125,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "ilmoitetut hinnat sisältävät arvolisäveron. Mahdolliset lisäpalvelut " "eivät sisälly hintaan." ), - "terms_type": TermsOfUse.TERMS_TYPE_PAYMENT, + "terms_type": TermsOfUseTypeChoices.PAYMENT, }, ) @@ -143,7 +144,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "Varaajan tulee olla täysi-ikäinen. Tilassa järjestettävä tilaisuus " "ei saa häiritä muuta kirjaston toimintaa, asiakkaita tai käyttäjiä." ), - "terms_type": TermsOfUse.TERMS_TYPE_SERVICE, + "terms_type": TermsOfUseTypeChoices.SERVICE, }, ) service_terms_library, _ = TermsOfUse.objects.get_or_create( @@ -156,7 +157,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "text": ( "Tähän varaukseen sovelletaan Helsingin kaupungin tilojen ja laitteiden varaamisen sopimusehtoja." ), - "terms_type": TermsOfUse.TERMS_TYPE_SERVICE, + "terms_type": TermsOfUseTypeChoices.SERVICE, }, ) service_terms_gadgets, _ = TermsOfUse.objects.get_or_create( @@ -173,7 +174,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "Tilaustöiden tekeminen korvausta vastaan tai ammattimainen " "tulonhankinta ei ole sallittua." ), - "terms_type": TermsOfUse.TERMS_TYPE_SERVICE, + "terms_type": TermsOfUseTypeChoices.SERVICE, }, ) service_terms_youth, _ = TermsOfUse.objects.get_or_create( @@ -190,7 +191,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "Yöpyminen on sallittu vain nuorisopalveluiden leirikeskuksissa " "tai vastaavissa tiloissa, jotka on tarkoitettu yöpymiseen." ), - "terms_type": TermsOfUse.TERMS_TYPE_SERVICE, + "terms_type": TermsOfUseTypeChoices.SERVICE, }, ) @@ -210,7 +211,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "ei ole mahdollista. Jos varaus on maksullinen, käyttämättä " "jääneen vuoron maksua ei palauteta." ), - "terms_type": TermsOfUse.TERMS_TYPE_CANCELLATION, + "terms_type": TermsOfUseTypeChoices.CANCELLATION, }, ) cancel_terms_zero_days, _ = TermsOfUse.objects.get_or_create( @@ -224,7 +225,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "Varauksen voi perua Varaamossa veloituksetta ennen varauksen alkamista. " "Myöhästyessäsi yli 15 minuuttia varaus vapautetaan muiden käyttöön." ), - "terms_type": TermsOfUse.TERMS_TYPE_CANCELLATION, + "terms_type": TermsOfUseTypeChoices.CANCELLATION, }, ) cancel_terms_14_days, _ = TermsOfUse.objects.get_or_create( @@ -238,7 +239,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "Varauksen voi perua veloituksetta kaksi viikkoa (14 vrk) ennen varauksen alkamista. " "Myöhemmin tehdyistä peruutuksista peritään täysi hinta." ), - "terms_type": TermsOfUse.TERMS_TYPE_CANCELLATION, + "terms_type": TermsOfUseTypeChoices.CANCELLATION, }, ) @@ -272,7 +273,7 @@ def _create_caisa(metadata_sets: dict[SetName, ReservationMetadataSet]) -> None: "muutos liittyy hinnoittelun tarkoituksenmukaiseen kohtuullistamiseen, " "varauksen tekijän sitä kirjallisesti hakiessa." ), - "terms_type": TermsOfUse.TERMS_TYPE_PAYMENT, + "terms_type": TermsOfUseTypeChoices.PAYMENT, }, ) diff --git a/common/management/commands/data_creation/create_reservation_units.py b/common/management/commands/data_creation/create_reservation_units.py index 5ea646d40..9118f8de4 100644 --- a/common/management/commands/data_creation/create_reservation_units.py +++ b/common/management/commands/data_creation/create_reservation_units.py @@ -30,8 +30,8 @@ from reservations.models import ReservationMetadataSet from resources.models import Resource from spaces.models import Unit -from terms_of_use.models import TermsOfUse -from tilavarauspalvelu.models import Service +from tilavarauspalvelu.enums import TermsOfUseTypeChoices +from tilavarauspalvelu.models import Service, TermsOfUse from .create_seasonal_booking import _create_application_round_time_slots from .utils import ( @@ -117,7 +117,7 @@ def _create_reservation_units( authentication=weighted_choice(AuthenticationType.values, weights=[2, 1]), can_apply_free_of_charge=can_apply_free_of_charge, cancellation_rule=next(cancellation_rules_loop), - cancellation_terms=terms_of_use[TermsOfUse.TERMS_TYPE_CANCELLATION], + cancellation_terms=terms_of_use[TermsOfUseTypeChoices.CANCELLATION.value], contact_information=faker_fi.text(), description=description.fi, description_en=description.en, @@ -137,8 +137,8 @@ def _create_reservation_units( name_fi=f"{name} FI", name_sv=f"{name} SV", origin_hauki_resource=random.choice(hauki_resources), - payment_terms=terms_of_use[TermsOfUse.TERMS_TYPE_PAYMENT], - pricing_terms=terms_of_use[TermsOfUse.TERMS_TYPE_PRICING], + payment_terms=terms_of_use[TermsOfUseTypeChoices.PAYMENT.value], + pricing_terms=terms_of_use[TermsOfUseTypeChoices.PRICING.value], rank=i, reservation_begins=datetime(2021, 1, 1, tzinfo=UTC), reservation_cancelled_instructions=cancelled.fi, @@ -158,7 +158,7 @@ def _create_reservation_units( reservation_unit_type=next(reservation_unit_types_loop), reservations_max_days_before=max_before, reservations_min_days_before=min_before, - service_specific_terms=terms_of_use[TermsOfUse.TERMS_TYPE_SERVICE], + service_specific_terms=terms_of_use[TermsOfUseTypeChoices.SERVICE.value], surface_area=random.randint(10, 1000), terms_of_use=terms.fi, terms_of_use_en=terms.en, @@ -397,7 +397,7 @@ def _create_terms_of_use() -> dict[str, TermsOfUse]: text_fi=text_fi, text_sv=text_sv, text_en=text_en, - terms_type=TermsOfUse.TERMS_TYPE_GENERIC, + terms_type=TermsOfUseTypeChoices.GENERIC, ) # @@ -405,11 +405,11 @@ def _create_terms_of_use() -> dict[str, TermsOfUse]: # terms_of_use: list[TermsOfUse] = [] term_types: list[str] = [ - TermsOfUse.TERMS_TYPE_PAYMENT, - TermsOfUse.TERMS_TYPE_CANCELLATION, - TermsOfUse.TERMS_TYPE_RECURRING, - TermsOfUse.TERMS_TYPE_SERVICE, - TermsOfUse.TERMS_TYPE_PRICING, + TermsOfUseTypeChoices.PAYMENT.value, + TermsOfUseTypeChoices.CANCELLATION.value, + TermsOfUseTypeChoices.RECURRING.value, + TermsOfUseTypeChoices.SERVICE.value, + TermsOfUseTypeChoices.PRICING.value, ] for term_type in term_types: name = term_type.replace("_", " ").title() diff --git a/config/settings.py b/config/settings.py index 8f090e031..aa5289124 100644 --- a/config/settings.py +++ b/config/settings.py @@ -145,7 +145,7 @@ def APP_VERSION(cls) -> str: TEMPLATES = [ { "BACKEND": "django_jinja.jinja2.Jinja2", - "DIRS": [], + "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, }, { diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index 45d8bc154..b7dc36bf2 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -39,31 +39,6 @@ msgstr "" msgid "My bookings" msgstr "Omat Varaukset" -#: tilavarauspalvelu/api/gdpr/views.py -msgid "User has upcoming or too recent reservations." -msgstr "Käyttäjällä on tulevia tai liian äskettäisiä varauksia." - -#: tilavarauspalvelu/api/gdpr/views.py -msgid "User has an unhandled application." -msgstr "Käyttäjällä on käsittelemätön hakemus." - -#: tilavarauspalvelu/api/gdpr/views.py -msgid "User has open payments." -msgstr "Käyttäjällä on avoimia maksuja." - -#: tilavarauspalvelu/api/graphql/extensions/fields.py -msgid "A valid integer is required." -msgstr "Syötä oikea kokonaisluku." - -#: tilavarauspalvelu/api/graphql/extensions/fields.py -#, python-format -msgid "" -"Choice \"%(choice)s\" is not allowed. Allowed choices are: " -"%(allowed_choices)s." -msgstr "" -"Valinta \"%(choice)s\" ei ole sallittu. Mahdolliset valinnat ovat: " -"%(allowed_choices)s." - #: applications/admin/address.py merchants/admin/payment_merchant.py msgid "Street address" msgstr "Katuosoite" @@ -410,7 +385,6 @@ msgstr "" #: reservation_units/models/reservation_unit_type.py #: reservations/admin/reservation/form.py #: reservations/models/reservation_metadata.py resources/models.py -#: services/models.py terms_of_use/models.py msgid "Name" msgstr "Nimi" @@ -1357,6 +1331,18 @@ msgstr "SQL loki" msgid "SQL logs" msgstr "SQL lokit" +#: config/settings.py merchants/enums.py +msgid "Finnish" +msgstr "Suomi" + +#: config/settings.py merchants/enums.py +msgid "English" +msgstr "Englanti" + +#: config/settings.py merchants/enums.py +msgid "Swedish" +msgstr "Ruotsi" + #: email_notification/admin/email_template_tester.py #, python-format msgid "Test Email '%s' successfully sent." @@ -1528,18 +1514,6 @@ msgstr "" "Etsi maksutunnuksella, varauksen tunnuksella, verkkokaupan tunnuksella, " "varauksen nimellä tai varausyksikön nimellä" -#: merchants/enums.py config/settings.py -msgid "Finnish" -msgstr "Suomi" - -#: merchants/enums.py config/settings.py -msgid "Swedish" -msgstr "Ruotsi" - -#: merchants/enums.py config/settings.py -msgid "English" -msgstr "Englanti" - #: merchants/enums.py msgctxt "OrderStatus" msgid "Draft" @@ -1868,11 +1842,11 @@ msgstr "Käyttöehdot (Englanniksi)" msgid "Terms of use (Swedish)" msgstr "Käyttöehdot (Ruotsiksi)" -#: reservation_units/admin/reservation_unit/form.py terms_of_use/models.py +#: reservation_units/admin/reservation_unit/form.py tilavarauspalvelu/enums.py msgid "Payment terms" msgstr "Maksuehdot" -#: reservation_units/admin/reservation_unit/form.py terms_of_use/models.py +#: reservation_units/admin/reservation_unit/form.py tilavarauspalvelu/enums.py msgid "Cancellation terms" msgstr "Peruutusehdot" @@ -1880,7 +1854,7 @@ msgstr "Peruutusehdot" msgid "Service specific terms" msgstr "Palvelukohtaiset ehdot" -#: reservation_units/admin/reservation_unit/form.py terms_of_use/models.py +#: reservation_units/admin/reservation_unit/form.py tilavarauspalvelu/enums.py msgid "Pricing terms" msgstr "Hinnoitteluehdot" @@ -1966,13 +1940,11 @@ msgstr "Pinta-ala" #: reservation_units/admin/reservation_unit/form.py #: reservations/admin/reservation/form.py resources/models.py -#: services/models.py msgid "Buffer time before" msgstr "Tauko ennen varausta" #: reservation_units/admin/reservation_unit/form.py #: reservations/admin/reservation/form.py resources/models.py -#: services/models.py msgid "Buffer time after" msgstr "Tauko varauksen jälkeen" @@ -3047,22 +3019,6 @@ msgctxt "ResourceLocationType" msgid "Movable" msgstr "Siirrettävä" -#: services/models.py -msgid "Introduction" -msgstr "Perehdytys" - -#: services/models.py -msgid "Catering" -msgstr "Tarjoilu" - -#: services/models.py -msgid "Configuration" -msgstr "Konfiguraatio" - -#: services/models.py -msgid "Service type" -msgstr "Palvelun tyyppi" - #: spaces/admin/space.py msgid "Search by name or unit name" msgstr "Etsi nimellä tai toimipisteen nimellä" @@ -3121,32 +3077,61 @@ msgstr "Ei, vie minut takaisin" msgid "Reset allocations" msgstr "Nollaa allokoinnit" -#: terms_of_use/models.py +#: tilavarauspalvelu/api/gdpr/views.py +msgid "User has upcoming or too recent reservations." +msgstr "Käyttäjällä on tulevia tai liian äskettäisiä varauksia." + +#: tilavarauspalvelu/api/gdpr/views.py +msgid "User has an unhandled application." +msgstr "Käyttäjällä on käsittelemätön hakemus." + +#: tilavarauspalvelu/api/gdpr/views.py +msgid "User has open payments." +msgstr "Käyttäjällä on avoimia maksuja." + +#: tilavarauspalvelu/api/graphql/extensions/fields.py +msgid "A valid integer is required." +msgstr "Syötä oikea kokonaisluku." + +#: tilavarauspalvelu/api/graphql/extensions/fields.py +#, python-format +msgid "" +"Choice \"%(choice)s\" is not allowed. Allowed choices are: " +"%(allowed_choices)s." +msgstr "" +"Valinta \"%(choice)s\" ei ole sallittu. Mahdolliset valinnat ovat: " +"%(allowed_choices)s." + +#: tilavarauspalvelu/enums.py +msgid "Introduction" +msgstr "Perehdytys" + +#: tilavarauspalvelu/enums.py +msgid "Catering" +msgstr "Tarjoilu" + +#: tilavarauspalvelu/enums.py +msgid "Configuration" +msgstr "Konfiguraatio" + +#: tilavarauspalvelu/enums.py msgid "Generic terms" msgstr "Yleiset ehdot" -#: terms_of_use/models.py +#: tilavarauspalvelu/enums.py msgid "Recurring reservation terms" msgstr "Kausivarauksen ehdot" -#: terms_of_use/models.py +#: tilavarauspalvelu/enums.py msgid "Service-specific terms" msgstr "Palvelukohtaiset ehdot" -#: terms_of_use/models.py -msgid "Text" -msgstr "Teksti" - -#: terms_of_use/models.py -msgid "Terms type" -msgstr "Ehtotyyppi" - -#: terms_of_use/models.py +#: tilavarauspalvelu/models/misc/terms_of_use/model.py msgctxt "singular" msgid "terms of use" msgstr "Käyttöehto" -#: terms_of_use/models.py +#: tilavarauspalvelu/models/misc/terms_of_use/model.py msgctxt "plural" msgid "terms of use" msgstr "Käyttöehdot" diff --git a/locale/sv/LC_MESSAGES/django.po b/locale/sv/LC_MESSAGES/django.po index 1a427436f..63be9e119 100644 --- a/locale/sv/LC_MESSAGES/django.po +++ b/locale/sv/LC_MESSAGES/django.po @@ -39,29 +39,6 @@ msgstr "" msgid "My bookings" msgstr "Mina bokningar" -#: tilavarauspalvelu/api/gdpr/views.py -msgid "User has upcoming or too recent reservations." -msgstr "" - -#: tilavarauspalvelu/api/gdpr/views.py -msgid "User has an unhandled application." -msgstr "" - -#: tilavarauspalvelu/api/gdpr/views.py -msgid "User has open payments." -msgstr "" - -#: tilavarauspalvelu/api/graphql/extensions/fields.py -msgid "A valid integer is required." -msgstr "" - -#: tilavarauspalvelu/api/graphql/extensions/fields.py -#, python-format -msgid "" -"Choice \"%(choice)s\" is not allowed. Allowed choices are: " -"%(allowed_choices)s." -msgstr "" - #: applications/admin/address.py merchants/admin/payment_merchant.py msgid "Street address" msgstr "" @@ -397,7 +374,6 @@ msgstr "" #: reservation_units/models/reservation_unit_type.py #: reservations/admin/reservation/form.py #: reservations/models/reservation_metadata.py resources/models.py -#: services/models.py terms_of_use/models.py msgid "Name" msgstr "" @@ -1315,6 +1291,18 @@ msgstr "" msgid "SQL logs" msgstr "" +#: config/settings.py merchants/enums.py +msgid "Finnish" +msgstr "" + +#: config/settings.py merchants/enums.py +msgid "English" +msgstr "" + +#: config/settings.py merchants/enums.py +msgid "Swedish" +msgstr "" + #: email_notification/admin/email_template_tester.py #, python-format msgid "Test Email '%s' successfully sent." @@ -1480,18 +1468,6 @@ msgid "" "name, or Reservation Unit name" msgstr "" -#: merchants/enums.py config/settings.py -msgid "Finnish" -msgstr "" - -#: merchants/enums.py config/settings.py -msgid "Swedish" -msgstr "" - -#: merchants/enums.py config/settings.py -msgid "English" -msgstr "" - #: merchants/enums.py msgctxt "OrderStatus" msgid "Draft" @@ -1810,11 +1786,11 @@ msgstr "" msgid "Terms of use (Swedish)" msgstr "" -#: reservation_units/admin/reservation_unit/form.py terms_of_use/models.py +#: reservation_units/admin/reservation_unit/form.py tilavarauspalvelu/enums.py msgid "Payment terms" msgstr "" -#: reservation_units/admin/reservation_unit/form.py terms_of_use/models.py +#: reservation_units/admin/reservation_unit/form.py tilavarauspalvelu/enums.py msgid "Cancellation terms" msgstr "" @@ -1822,7 +1798,7 @@ msgstr "" msgid "Service specific terms" msgstr "" -#: reservation_units/admin/reservation_unit/form.py terms_of_use/models.py +#: reservation_units/admin/reservation_unit/form.py tilavarauspalvelu/enums.py msgid "Pricing terms" msgstr "" @@ -1908,13 +1884,11 @@ msgstr "" #: reservation_units/admin/reservation_unit/form.py #: reservations/admin/reservation/form.py resources/models.py -#: services/models.py msgid "Buffer time before" msgstr "" #: reservation_units/admin/reservation_unit/form.py #: reservations/admin/reservation/form.py resources/models.py -#: services/models.py msgid "Buffer time after" msgstr "" @@ -2975,22 +2949,6 @@ msgctxt "ResourceLocationType" msgid "Movable" msgstr "" -#: services/models.py -msgid "Introduction" -msgstr "" - -#: services/models.py -msgid "Catering" -msgstr "" - -#: services/models.py -msgid "Configuration" -msgstr "" - -#: services/models.py -msgid "Service type" -msgstr "" - #: spaces/admin/space.py msgid "Search by name or unit name" msgstr "" @@ -3049,32 +3007,59 @@ msgstr "" msgid "Reset allocations" msgstr "" -#: terms_of_use/models.py -msgid "Generic terms" +#: tilavarauspalvelu/api/gdpr/views.py +msgid "User has upcoming or too recent reservations." msgstr "" -#: terms_of_use/models.py -msgid "Recurring reservation terms" +#: tilavarauspalvelu/api/gdpr/views.py +msgid "User has an unhandled application." msgstr "" -#: terms_of_use/models.py -msgid "Service-specific terms" +#: tilavarauspalvelu/api/gdpr/views.py +msgid "User has open payments." msgstr "" -#: terms_of_use/models.py -msgid "Text" +#: tilavarauspalvelu/api/graphql/extensions/fields.py +msgid "A valid integer is required." msgstr "" -#: terms_of_use/models.py -msgid "Terms type" +#: tilavarauspalvelu/api/graphql/extensions/fields.py +#, python-format +msgid "" +"Choice \"%(choice)s\" is not allowed. Allowed choices are: " +"%(allowed_choices)s." +msgstr "" + +#: tilavarauspalvelu/enums.py +msgid "Introduction" +msgstr "" + +#: tilavarauspalvelu/enums.py +msgid "Catering" +msgstr "" + +#: tilavarauspalvelu/enums.py +msgid "Configuration" +msgstr "" + +#: tilavarauspalvelu/enums.py +msgid "Generic terms" +msgstr "" + +#: tilavarauspalvelu/enums.py +msgid "Recurring reservation terms" +msgstr "" + +#: tilavarauspalvelu/enums.py +msgid "Service-specific terms" msgstr "" -#: terms_of_use/models.py +#: tilavarauspalvelu/models/misc/terms_of_use/model.py msgctxt "singular" msgid "terms of use" msgstr "" -#: terms_of_use/models.py +#: tilavarauspalvelu/models/misc/terms_of_use/model.py msgctxt "plural" msgid "terms of use" msgstr "" diff --git a/reservation_units/admin/reservation_unit/form.py b/reservation_units/admin/reservation_unit/form.py index 8d7ceb2de..b050e5f15 100644 --- a/reservation_units/admin/reservation_unit/form.py +++ b/reservation_units/admin/reservation_unit/form.py @@ -7,7 +7,8 @@ from applications.models import ApplicationRoundTimeSlot from applications.validators import validate_string_time from reservation_units.models import ReservationUnit -from terms_of_use.models import TermsOfUse +from tilavarauspalvelu.enums import TermsOfUseTypeChoices +from tilavarauspalvelu.models import TermsOfUse def remove_empty_timeslots(timeslots: list[dict[str, str]]) -> None: @@ -48,10 +49,10 @@ class Meta: class ReservationUnitAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs) -> None: qs = TermsOfUse.objects.all() - self.base_fields["pricing_terms"].queryset = qs.filter(terms_type=TermsOfUse.TERMS_TYPE_PRICING) - self.base_fields["payment_terms"].queryset = qs.filter(terms_type=TermsOfUse.TERMS_TYPE_PAYMENT) - self.base_fields["cancellation_terms"].queryset = qs.filter(terms_type=TermsOfUse.TERMS_TYPE_CANCELLATION) - self.base_fields["service_specific_terms"].queryset = qs.filter(terms_type=TermsOfUse.TERMS_TYPE_SERVICE) + self.base_fields["pricing_terms"].queryset = qs.filter(terms_type=TermsOfUseTypeChoices.PRICING) + self.base_fields["payment_terms"].queryset = qs.filter(terms_type=TermsOfUseTypeChoices.PAYMENT) + self.base_fields["cancellation_terms"].queryset = qs.filter(terms_type=TermsOfUseTypeChoices.CANCELLATION) + self.base_fields["service_specific_terms"].queryset = qs.filter(terms_type=TermsOfUseTypeChoices.SERVICE) super().__init__(*args, **kwargs) class Meta: diff --git a/reservation_units/migrations/0106_alter_reservationunit_cancellation_terms_and_more.py b/reservation_units/migrations/0106_alter_reservationunit_cancellation_terms_and_more.py new file mode 100644 index 000000000..aa04d558e --- /dev/null +++ b/reservation_units/migrations/0106_alter_reservationunit_cancellation_terms_and_more.py @@ -0,0 +1,64 @@ +# Generated by Django 5.1.1 on 2024-09-18 09:48 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("reservation_units", "0105_alter_reservationunit_services"), + ("tilavarauspalvelu", "0002_termsofuse"), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.AlterField( + model_name="reservationunit", + name="cancellation_terms", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="cancellation_terms_reservation_unit", + to="tilavarauspalvelu.termsofuse", + ), + ), + migrations.AlterField( + model_name="reservationunit", + name="payment_terms", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="payment_terms_reservation_unit", + to="tilavarauspalvelu.termsofuse", + ), + ), + migrations.AlterField( + model_name="reservationunit", + name="pricing_terms", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="pricing_terms_reservation_unit", + to="tilavarauspalvelu.termsofuse", + ), + ), + migrations.AlterField( + model_name="reservationunit", + name="service_specific_terms", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="service_specific_terms_reservation_unit", + to="tilavarauspalvelu.termsofuse", + ), + ), + ], + # We just moved the model, so no need to modify foreign keys + database_operations=[], + ), + ] diff --git a/reservation_units/models/reservation_unit.py b/reservation_units/models/reservation_unit.py index c7bff1017..ef0edae79 100644 --- a/reservation_units/models/reservation_unit.py +++ b/reservation_units/models/reservation_unit.py @@ -30,8 +30,7 @@ from reservation_units.models import ReservationUnitCancellationRule, ReservationUnitType from reservations.models import ReservationMetadataSet from spaces.models import Unit - from terms_of_use.models import TermsOfUse - + from tilavarauspalvelu.models import TermsOfUse __all__ = [ "ReservationUnit", @@ -150,28 +149,28 @@ class ReservationUnit(SearchDocumentMixin, models.Model): on_delete=models.SET_NULL, ) cancellation_terms: TermsOfUse | None = models.ForeignKey( - "terms_of_use.TermsOfUse", + "tilavarauspalvelu.TermsOfUse", related_name="cancellation_terms_reservation_unit", blank=True, null=True, on_delete=models.SET_NULL, ) service_specific_terms: TermsOfUse | None = models.ForeignKey( - "terms_of_use.TermsOfUse", + "tilavarauspalvelu.TermsOfUse", related_name="service_specific_terms_reservation_unit", blank=True, null=True, on_delete=models.SET_NULL, ) pricing_terms: TermsOfUse | None = models.ForeignKey( - "terms_of_use.TermsOfUse", + "tilavarauspalvelu.TermsOfUse", related_name="pricing_terms_reservation_unit", blank=True, null=True, on_delete=models.SET_NULL, ) payment_terms: TermsOfUse | None = models.ForeignKey( - "terms_of_use.TermsOfUse", + "tilavarauspalvelu.TermsOfUse", related_name="payment_terms_reservation_unit", blank=True, null=True, diff --git a/terms_of_use/templates/terms_of_use/booking_terms.jinja b/templates/terms_of_use/booking_terms.jinja similarity index 100% rename from terms_of_use/templates/terms_of_use/booking_terms.jinja rename to templates/terms_of_use/booking_terms.jinja diff --git a/terms_of_use/templates/terms_of_use/components/base.jinja b/templates/terms_of_use/components/base.jinja similarity index 100% rename from terms_of_use/templates/terms_of_use/components/base.jinja rename to templates/terms_of_use/components/base.jinja diff --git a/terms_of_use/admin/__init__.py b/terms_of_use/admin/__init__.py deleted file mode 100644 index eac320829..000000000 --- a/terms_of_use/admin/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .terms_of_use import TermsOfUseAdmin - -__all__ = [ - "TermsOfUseAdmin", -] diff --git a/terms_of_use/admin/terms_of_use.py b/terms_of_use/admin/terms_of_use.py deleted file mode 100644 index b9d1d7b8a..000000000 --- a/terms_of_use/admin/terms_of_use.py +++ /dev/null @@ -1,46 +0,0 @@ -from admin_extra_buttons.decorators import button -from admin_extra_buttons.mixins import ExtraButtonsMixin -from django.contrib import admin -from django.core.handlers.wsgi import WSGIRequest -from django.forms import ModelForm -from django.http import HttpResponseRedirect -from django.urls import reverse -from modeltranslation.admin import TranslationAdmin -from tinymce.widgets import TinyMCE - -from terms_of_use.models import TermsOfUse - -__all__ = [ - "TermsOfUseAdmin", -] - - -class TermsOfUseAdminForm(ModelForm): - class Meta: - model = TermsOfUse - fields = [ - "id", - "name", - "text", - "terms_type", - ] - widgets = {"text": TinyMCE()} - - -@admin.register(TermsOfUse) -class TermsOfUseAdmin(ExtraButtonsMixin, TranslationAdmin): - # List - list_display = [ - "id", - "name", - "terms_type", - ] - list_filter = ["terms_type"] - - # Form - form = TermsOfUseAdminForm - - @button(label="Show PDF", change_form=True, visible=lambda self: self.original.id == "booking") - def show_pdf(self, request: WSGIRequest) -> HttpResponseRedirect: - url = reverse("terms_of_use_pdf") + "?as_attachment=False" - return HttpResponseRedirect(url) diff --git a/terms_of_use/apps.py b/terms_of_use/apps.py deleted file mode 100644 index 882eac3e9..000000000 --- a/terms_of_use/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class TermsOfUseConfig(AppConfig): - name = "terms_of_use" diff --git a/terms_of_use/migrations/0006_delete_termsofuse.py b/terms_of_use/migrations/0006_delete_termsofuse.py new file mode 100644 index 000000000..28ca3af8d --- /dev/null +++ b/terms_of_use/migrations/0006_delete_termsofuse.py @@ -0,0 +1,22 @@ +# Generated by Django 5.1.1 on 2024-09-18 09:48 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("applications", "0094_alter_applicationround_terms_of_use"), + ("reservation_units", "0106_alter_reservationunit_cancellation_terms_and_more"), + ("terms_of_use", "0005_alter_termsofuse_options"), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.DeleteModel( + name="TermsOfUse", + ), + ], + database_operations=[], + ), + ] diff --git a/terms_of_use/models.py b/terms_of_use/models.py deleted file mode 100644 index 786ecc87c..000000000 --- a/terms_of_use/models.py +++ /dev/null @@ -1,61 +0,0 @@ -from django.db import models -from django.utils.translation import gettext_lazy as _ -from django.utils.translation import pgettext_lazy - -from config.utils.auditlog_util import AuditLogger - -__all__ = [ - "TermsOfUse", -] - - -class TermsOfUse(models.Model): - TERMS_TYPE_GENERIC = "generic_terms" - TERMS_TYPE_PAYMENT = "payment_terms" - TERMS_TYPE_CANCELLATION = "cancellation_terms" - TERMS_TYPE_RECURRING = "recurring_terms" - TERMS_TYPE_SERVICE = "service_terms" - TERMS_TYPE_PRICING = "pricing_terms" - - TERMS_TYPES = ( - (TERMS_TYPE_GENERIC, _("Generic terms")), - (TERMS_TYPE_PAYMENT, _("Payment terms")), - (TERMS_TYPE_CANCELLATION, _("Cancellation terms")), - (TERMS_TYPE_RECURRING, _("Recurring reservation terms")), - (TERMS_TYPE_SERVICE, _("Service-specific terms")), - (TERMS_TYPE_PRICING, _("Pricing terms")), - ) - - id = models.CharField(primary_key=True, max_length=100) - name = models.CharField(verbose_name=_("Name"), max_length=255, null=True, blank=True) - text = models.TextField(verbose_name=_("Text")) - terms_type = models.CharField( - blank=False, - verbose_name=_("Terms type"), - max_length=40, - choices=TERMS_TYPES, - default=TERMS_TYPE_GENERIC, - ) - - # Translated field hints - name_fi: str | None - name_en: str | None - name_sv: str | None - text_fi: str | None - text_en: str | None - text_sv: str | None - - class Meta: - db_table = "terms_of_use" - base_manager_name = "objects" - verbose_name = pgettext_lazy("singular", "terms of use") - verbose_name_plural = pgettext_lazy("plural", "terms of use") - ordering = [ - "pk", - ] - - def __str__(self) -> str: - return self.name - - -AuditLogger.register(TermsOfUse) diff --git a/terms_of_use/translation.py b/terms_of_use/translation.py deleted file mode 100644 index 9440dfed6..000000000 --- a/terms_of_use/translation.py +++ /dev/null @@ -1,8 +0,0 @@ -from modeltranslation.translator import TranslationOptions, register - -from terms_of_use.models import TermsOfUse - - -@register(TermsOfUse) -class TermsOfUseTranslationOptions(TranslationOptions): - fields = ["name", "text"] diff --git a/tests/factories/terms_of_use.py b/tests/factories/terms_of_use.py index 1a084122b..17777a2d2 100644 --- a/tests/factories/terms_of_use.py +++ b/tests/factories/terms_of_use.py @@ -1,7 +1,8 @@ import factory from factory import fuzzy -from terms_of_use.models import TermsOfUse +from tilavarauspalvelu.enums import TermsOfUseTypeChoices +from tilavarauspalvelu.models import TermsOfUse from ._base import GenericDjangoModelFactory @@ -17,4 +18,4 @@ class Meta: id = factory.Sequence(lambda n: f"terms-{n}") name = fuzzy.FuzzyText() text = fuzzy.FuzzyText() - terms_type = fuzzy.FuzzyChoice([terms_type for terms_type, _ in TermsOfUse.TERMS_TYPES]) + terms_type = fuzzy.FuzzyChoice(TermsOfUseTypeChoices.values) diff --git a/tests/test_admin/test_reservation_unit_admin_terms.py b/tests/test_admin/test_reservation_unit_admin_terms.py index 38ba3d152..e247f2190 100644 --- a/tests/test_admin/test_reservation_unit_admin_terms.py +++ b/tests/test_admin/test_reservation_unit_admin_terms.py @@ -5,8 +5,8 @@ from reservation_units.admin.reservation_unit.admin import ReservationUnitAdmin from reservation_units.enums import ReservationKind, ReservationStartInterval from reservation_units.models import ReservationUnit -from terms_of_use.models import TermsOfUse from tests.factories import ReservationUnitFactory, TermsOfUseFactory +from tilavarauspalvelu.enums import TermsOfUseTypeChoices # Applied to all tests pytestmark = [ @@ -27,7 +27,7 @@ def get_valid_data(): def test_reservation_unit_admin__terms_validation__pricing_terms__accepts_type_pricing(): reservation_unit = ReservationUnitFactory.create() - pricing_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_PRICING) + pricing_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.PRICING) request = RequestFactory().get(f"/admin/reservation_units/reservationunit/{reservation_unit.id}/change/") @@ -44,7 +44,7 @@ def test_reservation_unit_admin__terms_validation__pricing_terms__accepts_type_p def test_reservation_unit_admin__terms_validation__pricing_terms__errors_when_type_not_pricing(): reservation_unit = ReservationUnitFactory.create() - wrong_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_GENERIC) + wrong_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.GENERIC) request = RequestFactory().get(f"/admin/reservation_units/reservationunit/{reservation_unit.id}/change/") @@ -61,7 +61,7 @@ def test_reservation_unit_admin__terms_validation__pricing_terms__errors_when_ty def test_reservation_unit_admin__terms_validation__payment_terms__accepts_type_payment(): reservation_unit = ReservationUnitFactory.create() - payment_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_PAYMENT) + payment_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.PAYMENT) request = RequestFactory().get(f"/admin/reservation_units/reservationunit/{reservation_unit.id}/change/") @@ -78,7 +78,7 @@ def test_reservation_unit_admin__terms_validation__payment_terms__accepts_type_p def test_reservation_unit_admin__terms_validation__payment_terms__errors_when_type_not_payment(): reservation_unit = ReservationUnitFactory.create() - wrong_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_GENERIC) + wrong_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.GENERIC) request = RequestFactory().get(f"/admin/reservation_units/reservationunit/{reservation_unit.id}/change/") @@ -95,7 +95,7 @@ def test_reservation_unit_admin__terms_validation__payment_terms__errors_when_ty def test_reservation_unit_admin__terms_validation__cancellation_terms__accepts_type_cancellation(): reservation_unit = ReservationUnitFactory.create() - cancellation_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_CANCELLATION) + cancellation_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.CANCELLATION) request = RequestFactory().get(f"/admin/reservation_units/reservationunit/{reservation_unit.id}/change/") @@ -112,7 +112,7 @@ def test_reservation_unit_admin__terms_validation__cancellation_terms__accepts_t def test_reservation_unit_admin__terms_validation__cancellation_terms__errors_when_type_not_cancellation(): reservation_unit = ReservationUnitFactory.create() - wrong_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_GENERIC) + wrong_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.GENERIC) request = RequestFactory().get(f"/admin/reservation_units/reservationunit/{reservation_unit.id}/change/") @@ -129,7 +129,7 @@ def test_reservation_unit_admin__terms_validation__cancellation_terms__errors_wh def test_reservation_unit_admin__terms_validation__service_specific_terms__accepts_type_service(): reservation_unit = ReservationUnitFactory.create() - service_specific_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_SERVICE) + service_specific_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.SERVICE) request = RequestFactory().get(f"/admin/reservation_units/reservationunit/{reservation_unit.id}/change/") @@ -146,7 +146,7 @@ def test_reservation_unit_admin__terms_validation__service_specific_terms__accep def test_reservation_unit_admin__terms_validation__service_specific_terms__errors_when_type_not_service(): reservation_unit = ReservationUnitFactory.create() - wrong_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_GENERIC) + wrong_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.GENERIC) request = RequestFactory().get(f"/admin/reservation_units/reservationunit/{reservation_unit.id}/change/") diff --git a/tests/test_graphql_api/test_reservation_unit/test_query.py b/tests/test_graphql_api/test_reservation_unit/test_query.py index d1fa04153..611e8370b 100644 --- a/tests/test_graphql_api/test_reservation_unit/test_query.py +++ b/tests/test_graphql_api/test_reservation_unit/test_query.py @@ -8,7 +8,6 @@ from common.date_utils import local_datetime, next_hour from reservation_units.enums import PricingType, ReservationUnitPublishingState from reservations.enums import ReservationStateChoice, ReservationTypeChoice -from terms_of_use.models import TermsOfUse from tests.factories import ( ApplicationRoundFactory, ApplicationRoundTimeSlotFactory, @@ -28,6 +27,7 @@ TermsOfUseFactory, UserFactory, ) +from tilavarauspalvelu.enums import TermsOfUseTypeChoices from .helpers import reservation_unit_query, reservation_units_query @@ -266,10 +266,10 @@ def test_reservation_unit__query__all_to_one_relations(graphql): reservation_unit = ReservationUnitFactory.create( cancellation_rule=ReservationUnitCancellationRuleFactory.create(), metadata_set=ReservationMetadataSetFactory.create(), - cancellation_terms=TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_CANCELLATION), - service_specific_terms=TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_SERVICE), - pricing_terms=TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_PRICING), - payment_terms=TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_PAYMENT), + cancellation_terms=TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.CANCELLATION), + service_specific_terms=TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.SERVICE), + pricing_terms=TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.PRICING), + payment_terms=TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.PAYMENT), payment_product=PaymentProductFactory.create(), payment_merchant=PaymentMerchantFactory.create(), ) diff --git a/tests/test_graphql_api/test_reservation_unit/test_update_draft.py b/tests/test_graphql_api/test_reservation_unit/test_update_draft.py index 86e3b1436..9256055d1 100644 --- a/tests/test_graphql_api/test_reservation_unit/test_update_draft.py +++ b/tests/test_graphql_api/test_reservation_unit/test_update_draft.py @@ -5,8 +5,8 @@ from config.utils.auditlog_util import AuditLogger from reservation_units.enums import AuthenticationType from reservation_units.models import ReservationUnit -from terms_of_use.models import TermsOfUse from tests.factories import ReservationMetadataSetFactory, ReservationUnitFactory, TermsOfUseFactory +from tilavarauspalvelu.enums import TermsOfUseTypeChoices from .helpers import UPDATE_MUTATION, get_draft_update_input_data @@ -63,9 +63,9 @@ def test_reservation_unit__update__metadata_set__null(graphql): def test_reservation_unit__update__terms_of_use(graphql): graphql.login_with_superuser() - payment_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_PAYMENT) - cancellation_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_CANCELLATION) - service_specific_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_SERVICE) + payment_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.PAYMENT) + cancellation_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.CANCELLATION) + service_specific_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.SERVICE) reservation_unit = ReservationUnitFactory.create(is_draft=True) data = get_draft_update_input_data( reservation_unit, diff --git a/tests/test_graphql_api/test_reservation_unit/test_update_not_draft.py b/tests/test_graphql_api/test_reservation_unit/test_update_not_draft.py index 40453e2a5..3fbca0275 100644 --- a/tests/test_graphql_api/test_reservation_unit/test_update_not_draft.py +++ b/tests/test_graphql_api/test_reservation_unit/test_update_not_draft.py @@ -2,8 +2,8 @@ from merchants.enums import PaymentType from reservation_units.enums import ReservationStartInterval -from terms_of_use.models import TermsOfUse from tests.factories import ReservationUnitCancellationRuleFactory, ReservationUnitFactory, TermsOfUseFactory +from tilavarauspalvelu.enums import TermsOfUseTypeChoices from .helpers import UPDATE_MUTATION, get_non_draft_update_input_data @@ -214,7 +214,7 @@ def test_reservation_unit__update__pricing_terms(graphql): graphql.login_with_superuser() reservation_unit = ReservationUnitFactory.create(is_draft=False) - pricing_terms = TermsOfUseFactory.create(terms_type=TermsOfUse.TERMS_TYPE_PRICING) + pricing_terms = TermsOfUseFactory.create(terms_type=TermsOfUseTypeChoices.PRICING) data = get_non_draft_update_input_data(reservation_unit, pricingTerms=pricing_terms.pk) response = graphql(UPDATE_MUTATION, input_data=data) diff --git a/tests/test_rest_api/test_terms_pdf.py b/tests/test_rest_api/test_terms_pdf.py index d7d95a0e9..d76cb4112 100644 --- a/tests/test_rest_api/test_terms_pdf.py +++ b/tests/test_rest_api/test_terms_pdf.py @@ -5,8 +5,8 @@ from pypdf import PdfReader from rest_framework.reverse import reverse -from terms_of_use.models import TermsOfUse from tests.factories import TermsOfUseFactory +from tilavarauspalvelu.enums import TermsOfUseTypeChoices if TYPE_CHECKING: from django.http import FileResponse, JsonResponse @@ -25,7 +25,7 @@ def test_terms_pdf(api_client): text_fi="Test Terms of Use text", text_en="Test Terms of Use text English", text_sv="Test Terms of Use text Swedish", - terms_type=TermsOfUse.TERMS_TYPE_GENERIC, + terms_type=TermsOfUseTypeChoices.GENERIC, ) url = reverse("terms_of_use_pdf") @@ -57,7 +57,7 @@ def test_terms_pdf__not_as_attachment(api_client): text_fi="Test Terms of Use text", text_en="Test Terms of Use text English", text_sv="Test Terms of Use text Swedish", - terms_type=TermsOfUse.TERMS_TYPE_GENERIC, + terms_type=TermsOfUseTypeChoices.GENERIC, ) url = reverse("terms_of_use_pdf") + "?as_attachment=False" diff --git a/tilavarauspalvelu/admin/__init__.py b/tilavarauspalvelu/admin/__init__.py index f5f328321..95d630e20 100644 --- a/tilavarauspalvelu/admin/__init__.py +++ b/tilavarauspalvelu/admin/__init__.py @@ -1,5 +1,7 @@ from .service.admin import ServiceAdmin +from .terms_of_use.admin import TermsOfUseAdmin __all__ = [ "ServiceAdmin", + "TermsOfUseAdmin", ] diff --git a/tilavarauspalvelu/admin/terms_of_use/admin.py b/tilavarauspalvelu/admin/terms_of_use/admin.py index e69de29bb..614cccb51 100644 --- a/tilavarauspalvelu/admin/terms_of_use/admin.py +++ b/tilavarauspalvelu/admin/terms_of_use/admin.py @@ -0,0 +1,46 @@ +from admin_extra_buttons.decorators import button +from admin_extra_buttons.mixins import ExtraButtonsMixin +from django.contrib import admin +from django.core.handlers.wsgi import WSGIRequest +from django.forms import ModelForm +from django.http import HttpResponseRedirect +from django.urls import reverse +from modeltranslation.admin import TranslationAdmin +from tinymce.widgets import TinyMCE + +from tilavarauspalvelu.models import TermsOfUse + +__all__ = [ + "TermsOfUseAdmin", +] + + +class TermsOfUseAdminForm(ModelForm): + class Meta: + model = TermsOfUse + fields = [ + "id", + "name", + "text", + "terms_type", + ] + widgets = {"text": TinyMCE()} + + +@admin.register(TermsOfUse) +class TermsOfUseAdmin(ExtraButtonsMixin, TranslationAdmin): + # List + list_display = [ + "id", + "name", + "terms_type", + ] + list_filter = ["terms_type"] + + # Form + form = TermsOfUseAdminForm + + @button(label="Show PDF", change_form=True, visible=lambda self: self.original.id == "booking") + def show_pdf(self, request: WSGIRequest) -> HttpResponseRedirect: + url = reverse("terms_of_use_pdf") + "?as_attachment=False" + return HttpResponseRedirect(url) diff --git a/tilavarauspalvelu/api/graphql/types/terms_of_use/filtersets.py b/tilavarauspalvelu/api/graphql/types/terms_of_use/filtersets.py index 9645f48b2..05f1a92bb 100644 --- a/tilavarauspalvelu/api/graphql/types/terms_of_use/filtersets.py +++ b/tilavarauspalvelu/api/graphql/types/terms_of_use/filtersets.py @@ -1,7 +1,7 @@ from django_filters import MultipleChoiceFilter from graphene_django_extensions import ModelFilterSet -from terms_of_use.models import TermsOfUse +from tilavarauspalvelu.models import TermsOfUse __all__ = [ "TermsOfUseFilterSet", diff --git a/tilavarauspalvelu/api/graphql/types/terms_of_use/types.py b/tilavarauspalvelu/api/graphql/types/terms_of_use/types.py index 1efea48d4..493805757 100644 --- a/tilavarauspalvelu/api/graphql/types/terms_of_use/types.py +++ b/tilavarauspalvelu/api/graphql/types/terms_of_use/types.py @@ -1,7 +1,7 @@ import graphene from graphene_django_extensions import DjangoNode -from terms_of_use.models import TermsOfUse +from tilavarauspalvelu.models import TermsOfUse from .filtersets import TermsOfUseFilterSet from .permissions import TermsOfUsePermission diff --git a/tilavarauspalvelu/api/rest/views.py b/tilavarauspalvelu/api/rest/views.py index 75b290a55..0ff60db32 100644 --- a/tilavarauspalvelu/api/rest/views.py +++ b/tilavarauspalvelu/api/rest/views.py @@ -10,7 +10,7 @@ from common.pdf import render_to_pdf from common.utils import ical_hmac_signature from reservations.models import Reservation -from terms_of_use.models import TermsOfUse +from tilavarauspalvelu.models import TermsOfUse __all__ = [ "reservation_ical", diff --git a/tilavarauspalvelu/enums.py b/tilavarauspalvelu/enums.py index 9fb923bdf..e6b2c2915 100644 --- a/tilavarauspalvelu/enums.py +++ b/tilavarauspalvelu/enums.py @@ -3,6 +3,7 @@ __all__ = [ "ServiceTypeChoices", + "TermsOfUseTypeChoices", ] @@ -10,3 +11,12 @@ class ServiceTypeChoices(models.TextChoices): INTRODUCTION = "introduction", _("Introduction") CATERING = "catering", _("Catering") CONFIGURATION = "configuration", _("Configuration") + + +class TermsOfUseTypeChoices(models.TextChoices): + GENERIC = "generic_terms", _("Generic terms") + PAYMENT = "payment_terms", _("Payment terms") + CANCELLATION = "cancellation_terms", _("Cancellation terms") + RECURRING = "recurring_terms", _("Recurring reservation terms") + SERVICE = "service_terms", _("Service-specific terms") + PRICING = "pricing_terms", _("Pricing terms") diff --git a/tilavarauspalvelu/migrations/0002_termsofuse.py b/tilavarauspalvelu/migrations/0002_termsofuse.py new file mode 100644 index 000000000..9a6031096 --- /dev/null +++ b/tilavarauspalvelu/migrations/0002_termsofuse.py @@ -0,0 +1,54 @@ +# Generated by Django 5.1.1 on 2024-09-18 09:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("tilavarauspalvelu", "0001_initial"), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.CreateModel( + name="TermsOfUse", + fields=[ + ("id", models.CharField(max_length=100, primary_key=True, serialize=False)), + ("name", models.CharField(blank=True, max_length=255, null=True)), + ("name_fi", models.CharField(blank=True, max_length=255, null=True)), + ("name_en", models.CharField(blank=True, max_length=255, null=True)), + ("name_sv", models.CharField(blank=True, max_length=255, null=True)), + ("text", models.TextField()), + ("text_fi", models.TextField(null=True)), + ("text_en", models.TextField(null=True)), + ("text_sv", models.TextField(null=True)), + ( + "terms_type", + models.CharField( + choices=[ + ("generic_terms", "Generic terms"), + ("payment_terms", "Payment terms"), + ("cancellation_terms", "Cancellation terms"), + ("recurring_terms", "Recurring reservation terms"), + ("service_terms", "Service-specific terms"), + ("pricing_terms", "Pricing terms"), + ], + default="generic_terms", + max_length=40, + ), + ), + ], + options={ + "verbose_name": "terms of use", + "verbose_name_plural": "terms of use", + "db_table": "terms_of_use", + "ordering": ["pk"], + "base_manager_name": "objects", + }, + ), + ], + # We just moved the model, so no need create a new table + database_operations=[], + ), + ] diff --git a/tilavarauspalvelu/models/__init__.py b/tilavarauspalvelu/models/__init__.py index 60bdb23ec..a962f403d 100644 --- a/tilavarauspalvelu/models/__init__.py +++ b/tilavarauspalvelu/models/__init__.py @@ -1,5 +1,7 @@ from .service.model import Service +from .terms_of_use.model import TermsOfUse __all__ = [ "Service", + "TermsOfUse", ] diff --git a/tilavarauspalvelu/models/terms_of_use/actions.py b/tilavarauspalvelu/models/terms_of_use/actions.py index e69de29bb..b6196e130 100644 --- a/tilavarauspalvelu/models/terms_of_use/actions.py +++ b/tilavarauspalvelu/models/terms_of_use/actions.py @@ -0,0 +1,14 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from .model import TermsOfUse + + +__all__ = [ + "TermsOfUseActions", +] + + +class TermsOfUseActions: + def __init__(self, terms_of_use: "TermsOfUse") -> None: + self.terms_of_use = terms_of_use diff --git a/tilavarauspalvelu/models/terms_of_use/model.py b/tilavarauspalvelu/models/terms_of_use/model.py index e69de29bb..0180c1b2e 100644 --- a/tilavarauspalvelu/models/terms_of_use/model.py +++ b/tilavarauspalvelu/models/terms_of_use/model.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from functools import cached_property +from typing import TYPE_CHECKING + +from django.db import models +from django.utils.translation import pgettext_lazy + +from config.utils.auditlog_util import AuditLogger +from tilavarauspalvelu.enums import TermsOfUseTypeChoices + +from .queryset import TermsOfUseQuerySet + +if TYPE_CHECKING: + from .actions import TermsOfUseActions + +__all__ = [ + "TermsOfUse", +] + + +class TermsOfUse(models.Model): + id = models.CharField(primary_key=True, max_length=100) + name = models.CharField(max_length=255, null=True, blank=True) + text = models.TextField() + terms_type = models.CharField( + blank=False, + max_length=40, + choices=TermsOfUseTypeChoices.choices, + default=TermsOfUseTypeChoices.GENERIC, + ) + + # Translated field hints + name_fi: str | None + name_en: str | None + name_sv: str | None + text_fi: str | None + text_en: str | None + text_sv: str | None + + objects = TermsOfUseQuerySet.as_manager() + + class Meta: + db_table = "terms_of_use" + base_manager_name = "objects" + verbose_name = pgettext_lazy("singular", "terms of use") + verbose_name_plural = pgettext_lazy("plural", "terms of use") + ordering = ["pk"] + + def __str__(self) -> str: + return self.name + + @cached_property + def actions(self) -> TermsOfUseActions: + # Import actions inline to defer loading them. + # This allows us to avoid circular imports. + from .actions import TermsOfUseActions + + return TermsOfUseActions(self) + + +AuditLogger.register(TermsOfUse) diff --git a/tilavarauspalvelu/models/terms_of_use/queryset.py b/tilavarauspalvelu/models/terms_of_use/queryset.py index e69de29bb..b29fc5dd3 100644 --- a/tilavarauspalvelu/models/terms_of_use/queryset.py +++ b/tilavarauspalvelu/models/terms_of_use/queryset.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from django.db import models + +__all__ = [ + "TermsOfUseQuerySet", +] + + +class TermsOfUseQuerySet(models.QuerySet): ... diff --git a/tilavarauspalvelu/translation.py b/tilavarauspalvelu/translation.py index 08662a301..d9cbdfadd 100644 --- a/tilavarauspalvelu/translation.py +++ b/tilavarauspalvelu/translation.py @@ -1,9 +1,14 @@ from modeltranslation.decorators import register from modeltranslation.translator import TranslationOptions -from .models import Service +from .models import Service, TermsOfUse @register(Service) class ServiceTranslationOptions(TranslationOptions): fields = ["name"] + + +@register(TermsOfUse) +class TermsOfUseTranslationOptions(TranslationOptions): + fields = ["name", "text"]