diff --git a/CHANGES.rst b/CHANGES.rst index abc8e8e4..b578cc47 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -18,6 +18,9 @@ Changelog 2.7.7 (2024-08-22) ------------------ +- Booking additional fields. + [folix-01] + - Bookings details help text in `Tipologia prenotazione`. [folix-01] @@ -49,7 +52,7 @@ Changelog 2.7.3 (2024-06-14) ------------------ -- With an experimental envionment `SEE_OWN_ANONYMOUS_BOOKINGS` set to `True`, the endpoint will return +- With an experimental envionment `SEE_OWN_ANONYMOUS_BOOKINGS` set to `True`, the endpoint will return also the bookings created by anonymous users with the same fiscalcode of the authenticated user. [mamico] diff --git a/README.rst b/README.rst index 54f91793..a29e842f 100644 --- a/README.rst +++ b/README.rst @@ -510,6 +510,7 @@ Response:: { "duration": "60", "name": "Rilascio CIE" + "booking_additional_fields_schema": {"name": "field1", "description": "Field number 1", "type": "text", "required": true} } ] }, @@ -703,6 +704,66 @@ Response:: ] } +Booking Additional Fields +========================= + +You can also create the addtional fields for your booking, you just need to compile +them in your PrenotazioneType. +And they will appear in the ["booking_types"]["booking_additional_fields_schema"] +in your booking schema so you can compile them for your booking in this way: + +@booking +-------- + +Create booking with an additional field + +POST +~~~~ + +This endpoint allows to create a new booking. + +Example:: + + curl http://localhost:8080/Plone/++api++//@booking \ + -X POST \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "booking_date": "2023-05-23T09:00:00+02:00", + "booking_type": "Type x", + "fields": [ + {"name": "fullname", "value": "Mario Rossi"}, + {"name": "email", "value": "mario.rossi@example"} + ], + "additional_fields": [{"name": "field1", "value": "Addional field text"}] + }' + +Response:: + + { + "booking_code": "17E3E6", + "booking_date": "2023-05-22T09:09:00", + "booking_expiration_date": "2023-05-22T09:10:00", + "booking_type": "Type x", + "company": null, + "cosa_serve": null, + "description": "", + "email": "mario.rossi@example", + "fiscalcode": "", + "gate": "gate 1", + "id": "mario-rossi-1", + "phone": "", + "staff_notes": null, + "title": "Mario Rossi", + "additional_fields": [{"name": "field1", "value": "Addional field text"}] + } + +Available types are +------------------- + +- **text**: Text which uses default zope.schema.TextLine validation + + Special Views ============== diff --git a/buildout.cfg b/buildout.cfg index 48dac86f..f64db6fb 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -9,3 +9,6 @@ extends = eggs += Products.PrintingMailHost design.plone.ioprenoto + +[versions] +docutils=0.21.2 diff --git a/src/redturtle/prenotazioni/adapters/booker.py b/src/redturtle/prenotazioni/adapters/booker.py index 90542a57..3f512408 100644 --- a/src/redturtle/prenotazioni/adapters/booker.py +++ b/src/redturtle/prenotazioni/adapters/booker.py @@ -191,6 +191,8 @@ def generate_params(self, data, force_gate, duration): if fiscalcode: params["fiscalcode"] = fiscalcode.upper() + params["additional_fields"] = data.get("additional_fields", []) + return params def _create(self, data, duration=-1, force_gate=""): diff --git a/src/redturtle/prenotazioni/content/prenotazione.py b/src/redturtle/prenotazioni/content/prenotazione.py index c4e23351..444516e4 100644 --- a/src/redturtle/prenotazioni/content/prenotazione.py +++ b/src/redturtle/prenotazioni/content/prenotazione.py @@ -4,6 +4,7 @@ import six from DateTime import DateTime from plone import api +from plone import schema as plone_schema from plone.app.event.base import default_timezone from plone.app.z3cform.widget import DatetimeFieldWidget from plone.autoform import directives @@ -186,6 +187,15 @@ class IPrenotazione(model.Schema): required=False, title=_("label_booking_staff_notes", "Staff notes") ) + # Schema is defined in PrenotaizioneType as an datagridfield, and here we save the data as an json + # in base of selected type + additional_fields = schema.List( + title="Additional fields, not editable", + required=False, + value_type=plone_schema.JSONField(), + default=[], + ) + directives.widget( "booking_date", DatetimeFieldWidget, diff --git a/src/redturtle/prenotazioni/content/prenotazione_type.py b/src/redturtle/prenotazioni/content/prenotazione_type.py index 252bbe1c..393fa36c 100644 --- a/src/redturtle/prenotazioni/content/prenotazione_type.py +++ b/src/redturtle/prenotazioni/content/prenotazione_type.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- +from collective.z3cform.datagridfield.datagridfield import DataGridFieldFactory +from collective.z3cform.datagridfield.row import DictRow from plone.app.textfield import RichText +from plone.autoform import directives as form from plone.dexterity.content import Item from plone.supermodel import model from zope import schema @@ -8,6 +11,40 @@ from redturtle.prenotazioni import _ +class IBookingAdditionalFieldsSchema(model.Schema): + # TODO: definire un validatore per fare in modo che il nome sia unico e + # che non contenga caratteri strani non ammessi + name = schema.TextLine( + title=_("booking_additional_field_name", default="id"), + required=True, + default="", + description=_( + "booking_additional_field_name_help", + default="Additional field id must be unique", + ), + ) + label = schema.TextLine( + title=_("booking_additional_field_label", default="Label"), + required=True, + default="", + ) + type = schema.Choice( + title=_("booking_additional_field_type", default="Tipo"), + required=True, + vocabulary="redturtle.prenotazioni.booking_additional_fields_types", + ) + required = schema.Bool( + title=_("booking_additional_field_required", default="Required"), + required=False, + default=False, + ) + description = schema.TextLine( + title=_("booking_additional_field_description", default="Descrizione"), + required=False, + default="", + ) + + class IPrenotazioneType(model.Schema): """Marker interface and Dexterity Python Schema for Prenotazione""" @@ -38,13 +75,43 @@ class IPrenotazioneType(model.Schema): booking_details_help_text = RichText( required=False, - title=_("booking_details_help_text_label", default="Bookign detail help text"), + title=_("booking_details_help_text_label", default="Booking detail help text"), description=_( "booking_details_help_text_label_help", default='This field will be visualized as "Details" helptext during the booking steps', ), ) + booking_additional_fields_schema = schema.List( + title=_( + "booking_additional_fields_schema_title", + default="Booking additional fields schema", + ), + default=[], + value_type=DictRow(schema=IBookingAdditionalFieldsSchema), + description=_( + "booking_additional_fields_schema_description", + default="This schema is being used for the additional booking fields", + ), + required=False, + ) + + form.widget( + "booking_additional_fields_schema", + DataGridFieldFactory, + frontendOptions={ + "widget": "data_grid", + }, + ) + + model.fieldset( + "additional_fields", + label=_("booking_additional_fields_schema_title"), + fields=[ + "booking_additional_fields_schema", + ], + ) + @implementer(IPrenotazioneType) class PrenotazioneType(Item): diff --git a/src/redturtle/prenotazioni/interfaces.py b/src/redturtle/prenotazioni/interfaces.py index 07d3ec4d..b0246c7f 100644 --- a/src/redturtle/prenotazioni/interfaces.py +++ b/src/redturtle/prenotazioni/interfaces.py @@ -43,7 +43,7 @@ class IBookingAPPIoMessage(Interface): class IBookingNotificatorSupervisorUtility(Interface): - """Bookign notificator supervisor + """Booking notificator supervisor basically contains the business logic to allow/disallow the notification sending to gateways """ diff --git a/src/redturtle/prenotazioni/locales/en/LC_MESSAGES/redturtle.prenotazioni.po b/src/redturtle/prenotazioni/locales/en/LC_MESSAGES/redturtle.prenotazioni.po index a2ce06d6..4cbbc3de 100644 --- a/src/redturtle/prenotazioni/locales/en/LC_MESSAGES/redturtle.prenotazioni.po +++ b/src/redturtle/prenotazioni/locales/en/LC_MESSAGES/redturtle.prenotazioni.po @@ -31,6 +31,11 @@ msgstr "" msgid "Add" msgstr "" +#: redturtle/prenotazioni/restapi/services/booking/add.py:213 +#: redturtle/prenotazioni/restapi/services/booking/update.py:73 +msgid "Additional field '${additional_field_name}' value is required." +msgstr "" + #: redturtle/prenotazioni/content/prenotazioni_folder.py:433 #: redturtle/prenotazioni/content/validators.py:222 msgid "Afternoon start should not be greater than end." @@ -122,6 +127,11 @@ msgstr "" msgid "Could not send {gateway_type} message due to internal errors" msgstr "" +#: redturtle/prenotazioni/restapi/services/booking/add.py:230 +#: redturtle/prenotazioni/restapi/services/booking/update.py:90 +msgid "Could not validate value for the ${field_name} due to: ${err_message}" +msgstr "" + #: redturtle/prenotazioni/content/prenotazioni_folder.py:207 msgid "Data fine validità" msgstr "" @@ -156,7 +166,7 @@ msgstr "" msgid "Email from" msgstr "" -#: redturtle/prenotazioni/content/prenotazione.py:175 +#: redturtle/prenotazioni/content/prenotazione.py:176 msgid "Expiration date booking" msgstr "" @@ -170,7 +180,7 @@ msgid "Friday" msgstr "" #: redturtle/prenotazioni/browser/templates/prenotazione.pt:107 -#: redturtle/prenotazioni/content/prenotazione.py:170 +#: redturtle/prenotazioni/content/prenotazione.py:171 msgid "Gate" msgstr "" @@ -325,7 +335,7 @@ msgstr "" msgid "Print" msgstr "" -#: redturtle/prenotazioni/restapi/services/booking/add.py:120 +#: redturtle/prenotazioni/restapi/services/booking/add.py:123 msgid "Required input '${field}' is missing." msgstr "" @@ -349,12 +359,12 @@ msgstr "" msgid "Select a day" msgstr "" -#: redturtle/prenotazioni/adapters/booker.py:299 -#: redturtle/prenotazioni/restapi/services/booking/add.py:63 +#: redturtle/prenotazioni/adapters/booker.py:301 +#: redturtle/prenotazioni/restapi/services/booking/add.py:66 msgid "Sorry, this slot is not available anymore." msgstr "" -#: redturtle/prenotazioni/adapters/booker.py:342 +#: redturtle/prenotazioni/adapters/booker.py:344 msgid "Sorry, this slot is not available or does not fit your booking." msgstr "" @@ -362,7 +372,7 @@ msgstr "" msgid "Sorry, you can not book this slot for now." msgstr "" -#: redturtle/prenotazioni/content/prenotazione.py:171 +#: redturtle/prenotazioni/content/prenotazione.py:172 msgid "Sportello a cui presentarsi" msgstr "" @@ -454,11 +464,11 @@ msgstr "" msgid "The phone number of the user who made the reservation." msgstr "" -#: redturtle/prenotazioni/adapters/booker.py:391 +#: redturtle/prenotazioni/adapters/booker.py:393 msgid "This day is not valid." msgstr "" -#: redturtle/prenotazioni/adapters/booker.py:386 +#: redturtle/prenotazioni/adapters/booker.py:388 msgid "This gate has some booking schedule in this time period." msgstr "" @@ -478,7 +488,12 @@ msgstr "" msgid "Uninstalls the redturtle.prenotazioni.demo add-on (demo site purpose only)." msgstr "" -#: redturtle/prenotazioni/restapi/services/booking/add.py:156 +#: redturtle/prenotazioni/restapi/services/booking/add.py:200 +#: redturtle/prenotazioni/restapi/services/booking/update.py:56 +msgid "Unknown additional field '${additional_field_name}'." +msgstr "" + +#: redturtle/prenotazioni/restapi/services/booking/add.py:159 msgid "Unknown booking type '${booking_type}'." msgstr "" @@ -504,7 +519,7 @@ msgstr "" msgid "Yes" msgstr "" -#: redturtle/prenotazioni/restapi/services/booking/add.py:113 +#: redturtle/prenotazioni/restapi/services/booking/add.py:116 msgid "You are not allowed to force the gate." msgstr "" @@ -600,7 +615,7 @@ msgid "auto_confirm_manager_help" msgstr "" #. Default: "End date should be greater than start." -#: redturtle/prenotazioni/restapi/services/available_slots/get.py:63 +#: redturtle/prenotazioni/restapi/services/available_slots/get.py:62 msgid "available_slots_wrong_dates" msgstr "" @@ -897,12 +912,12 @@ msgid "delete_reservation_request" msgstr "" #. Default: "Unique booking code" -#: redturtle/prenotazioni/content/prenotazione.py:181 +#: redturtle/prenotazioni/content/prenotazione.py:182 msgid "description_booking_code" msgstr "" #. Default: "If you work for a company, please specify its name." -#: redturtle/prenotazioni/content/prenotazione.py:161 +#: redturtle/prenotazioni/content/prenotazione.py:162 msgid "description_company" msgstr "" @@ -1063,7 +1078,7 @@ msgid "invalid_date" msgstr "" #. Default: "Invalid email address" -#: redturtle/prenotazioni/content/prenotazione.py:32 +#: redturtle/prenotazioni/content/prenotazione.py:33 msgid "invalid_email_address" msgstr "" @@ -1074,12 +1089,12 @@ msgid "invalid_end:search_date" msgstr "" #. Default: "Invalid fiscal code" -#: redturtle/prenotazioni/content/prenotazione.py:40 +#: redturtle/prenotazioni/content/prenotazione.py:41 msgid "invalid_fiscalcode" msgstr "" #. Default: "Invalid phone number" -#: redturtle/prenotazioni/content/prenotazione.py:28 +#: redturtle/prenotazioni/content/prenotazione.py:29 msgid "invalid_phone_number" msgstr "" @@ -1088,7 +1103,7 @@ msgid "invalid_time" msgstr "" #. Default: "This date is past" -#: redturtle/prenotazioni/content/prenotazione.py:36 +#: redturtle/prenotazioni/content/prenotazione.py:37 msgid "is_not_future_date" msgstr "" @@ -1150,13 +1165,13 @@ msgstr "" #. Default: "Staff notes" #: redturtle/prenotazioni/browser/templates/prenotazione.pt:113 -#: redturtle/prenotazioni/content/prenotazione.py:186 +#: redturtle/prenotazioni/content/prenotazione.py:187 msgid "label_booking_staff_notes" msgstr "" #. Default: "Booking time" #: redturtle/prenotazioni/browser/prenotazione_move.py:30 -#: redturtle/prenotazioni/content/prenotazione.py:126 +#: redturtle/prenotazioni/content/prenotazione.py:127 msgid "label_booking_time" msgstr "" @@ -1894,7 +1909,7 @@ msgid "to_month_too_days_error" msgstr "" #. Default: "You can't add a booking with type '${booking_type}'." -#: redturtle/prenotazioni/restapi/services/booking/add.py:132 +#: redturtle/prenotazioni/restapi/services/booking/add.py:135 msgid "unauthorized_add_vacation" msgstr "" diff --git a/src/redturtle/prenotazioni/locales/it/LC_MESSAGES/redturtle.prenotazioni.po b/src/redturtle/prenotazioni/locales/it/LC_MESSAGES/redturtle.prenotazioni.po index e5f20dd3..c6f38c92 100644 --- a/src/redturtle/prenotazioni/locales/it/LC_MESSAGES/redturtle.prenotazioni.po +++ b/src/redturtle/prenotazioni/locales/it/LC_MESSAGES/redturtle.prenotazioni.po @@ -33,6 +33,11 @@ msgstr "Una cartella che conterrà le prenotazioni per questo day" msgid "Add" msgstr "Aggiungi" +#: redturtle/prenotazioni/restapi/services/booking/add.py:213 +#: redturtle/prenotazioni/restapi/services/booking/update.py:73 +msgid "Additional field '${additional_field_name}' value is required." +msgstr "Campo aggiuntivo '${additional_field_name}' è obbligatorio." + #: redturtle/prenotazioni/content/prenotazioni_folder.py:433 #: redturtle/prenotazioni/content/validators.py:222 msgid "Afternoon start should not be greater than end." @@ -124,6 +129,11 @@ msgstr "Elenco dei contenuti" msgid "Could not send {gateway_type} message due to internal errors" msgstr "Non è stato possibile inviare la notifica via {gateway_type}" +#: redturtle/prenotazioni/restapi/services/booking/add.py:230 +#: redturtle/prenotazioni/restapi/services/booking/update.py:90 +msgid "Could not validate value for the ${field_name} due to: ${err_message}" +msgstr "Non è stato possibile validare valore del campo ${field_name} a causa di: ${err_message}" + #: redturtle/prenotazioni/content/prenotazioni_folder.py:207 msgid "Data fine validità" msgstr "Data fine validità" @@ -158,7 +168,7 @@ msgstr "Modifica" msgid "Email from" msgstr "Mittente" -#: redturtle/prenotazioni/content/prenotazione.py:175 +#: redturtle/prenotazioni/content/prenotazione.py:176 msgid "Expiration date booking" msgstr "Data scandenza prenotazione" @@ -172,7 +182,7 @@ msgid "Friday" msgstr "Venerdì" #: redturtle/prenotazioni/browser/templates/prenotazione.pt:107 -#: redturtle/prenotazioni/content/prenotazione.py:170 +#: redturtle/prenotazioni/content/prenotazione.py:171 msgid "Gate" msgstr "Postazione" @@ -327,7 +337,7 @@ msgstr "PrenotazioniYear" msgid "Print" msgstr "Stampa" -#: redturtle/prenotazioni/restapi/services/booking/add.py:120 +#: redturtle/prenotazioni/restapi/services/booking/add.py:123 msgid "Required input '${field}' is missing." msgstr "Campo obbligatorio '${field}' mancante." @@ -351,12 +361,12 @@ msgstr "Parametri di ricerca" msgid "Select a day" msgstr "Seleziona un giorno" -#: redturtle/prenotazioni/adapters/booker.py:299 -#: redturtle/prenotazioni/restapi/services/booking/add.py:63 +#: redturtle/prenotazioni/adapters/booker.py:301 +#: redturtle/prenotazioni/restapi/services/booking/add.py:66 msgid "Sorry, this slot is not available anymore." msgstr "Ci dispiace, ma questo intervallo di tempo non è più disponibile" -#: redturtle/prenotazioni/adapters/booker.py:342 +#: redturtle/prenotazioni/adapters/booker.py:344 msgid "Sorry, this slot is not available or does not fit your booking." msgstr "Ci dispiace questo intervallo di tempo non è disponibile o non è adatto alla tua prenotazione." @@ -364,7 +374,7 @@ msgstr "Ci dispiace questo intervallo di tempo non è disponibile o non è adatt msgid "Sorry, you can not book this slot for now." msgstr "Ci dispiace, ma questo intervallo di tempo non è al momento disponibile" -#: redturtle/prenotazioni/content/prenotazione.py:171 +#: redturtle/prenotazioni/content/prenotazione.py:172 msgid "Sportello a cui presentarsi" msgstr "Postazione a cui presentarsi" @@ -456,11 +466,11 @@ msgstr "Le informazioni per raggiungere l'ufficio presso cui si prenota" msgid "The phone number of the user who made the reservation." msgstr "Il numero di telefono di chi ha prenotato" -#: redturtle/prenotazioni/adapters/booker.py:391 +#: redturtle/prenotazioni/adapters/booker.py:393 msgid "This day is not valid." msgstr "Il giorno inserito non è valido." -#: redturtle/prenotazioni/adapters/booker.py:386 +#: redturtle/prenotazioni/adapters/booker.py:388 msgid "This gate has some booking schedule in this time period." msgstr "Lo sportello selezionato ha già delle prenotazioni nel periodo indicato." @@ -480,7 +490,12 @@ msgstr "Disinstall redturtle.prenotazioni" msgid "Uninstalls the redturtle.prenotazioni.demo add-on (demo site purpose only)." msgstr "Disinstalla redturtle.prenotazioni.demo." -#: redturtle/prenotazioni/restapi/services/booking/add.py:156 +#: redturtle/prenotazioni/restapi/services/booking/add.py:200 +#: redturtle/prenotazioni/restapi/services/booking/update.py:56 +msgid "Unknown additional field '${additional_field_name}'." +msgstr "Campo aggiuntivo sconosciuto '${additional_field_name}'." + +#: redturtle/prenotazioni/restapi/services/booking/add.py:159 msgid "Unknown booking type '${booking_type}'." msgstr "Tipologia di prenotazione sconosciuta '${booking_type}'." @@ -506,7 +521,7 @@ msgstr "Schedulazione Settimanale" msgid "Yes" msgstr "Si" -#: redturtle/prenotazioni/restapi/services/booking/add.py:113 +#: redturtle/prenotazioni/restapi/services/booking/add.py:116 msgid "You are not allowed to force the gate." msgstr "Non hai i permessi necessari a forzare lo sportello." @@ -602,7 +617,7 @@ msgid "auto_confirm_manager_help" msgstr "Tutte le prenotazioni create dai Gestori verranno accettate automaticamente." #. Default: "End date should be greater than start." -#: redturtle/prenotazioni/restapi/services/available_slots/get.py:63 +#: redturtle/prenotazioni/restapi/services/available_slots/get.py:62 msgid "available_slots_wrong_dates" msgstr "La data di fine prenotazione deve essere maggiore della data di inizio." @@ -621,6 +636,46 @@ msgstr "Tempo prenotabile " msgid "booked_prenotation_message" msgstr "${day}, ore ${booking_time}, prenotato da ${booked_by}, prenotazione: ${booking_type} durata: ${duration} minuti" +#. Default: "Descrizione" +#: redturtle/prenotazioni/content/prenotazione_type.py:32 +msgid "booking_additional_field_description" +msgstr "" + +#. Default: "Label" +#: redturtle/prenotazioni/content/prenotazione_type.py:27 +msgid "booking_additional_field_label" +msgstr "" + +#. Default: "id" +#: redturtle/prenotazioni/content/prenotazione_type.py:18 +msgid "booking_additional_field_name" +msgstr "" + +#. Default: "Additional field id must be unique" +#: redturtle/prenotazioni/content/prenotazione_type.py:21 +msgid "booking_additional_field_name_help" +msgstr "Identificativo del campo aggiuntivo, deve essere unico e non contenere spazi o caratteri speciali" + +#. Default: "Required" +#: redturtle/prenotazioni/content/prenotazione_type.py:42 +msgid "booking_additional_field_required" +msgstr "Obbligatorio" + +#. Default: "Tipo" +#: redturtle/prenotazioni/content/prenotazione_type.py:37 +msgid "booking_additional_field_type" +msgstr "" + +#. Default: "This schema is being used for the additional booking fields" +#: redturtle/prenotazioni/content/prenotazione_type.py:92 +msgid "booking_additional_fields_schema_description" +msgstr "Campi aggiuntivi richiesti per questa tipologia" + +#. Default: "Booking additional fields schema" +#: redturtle/prenotazioni/content/prenotazione_type.py:86 +msgid "booking_additional_fields_schema_title" +msgstr "Campi aggiuntivi" + #. Default: "Booking canceled: " #: redturtle/prenotazioni/behaviors/booking_folder/notifications/email/notification_email_message.py:371 msgid "booking_canceled_mail_subject_part" @@ -642,13 +697,13 @@ msgstr "Prenotazione creata" msgid "booking_deleted_success" msgstr "La tua prenotazione è stata cancellata." -#. Default: "Bookign detail help text" -#: redturtle/prenotazioni/content/prenotazione_type.py:41 +#. Default: "Booking detail help text" +#: redturtle/prenotazioni/content/prenotazione_type.py:78 msgid "booking_details_help_text_label" msgstr "Istruzioni per campo dettaglio nella prenotazione" #. Default: "This field will be visualized as \"Details\" helptext during the booking steps" -#: redturtle/prenotazioni/content/prenotazione_type.py:42 +#: redturtle/prenotazioni/content/prenotazione_type.py:79 msgid "booking_details_help_text_label_help" msgstr "Il testo verra visualizzato come testo d'aiuto per la compilazione del campo \"Dettagli\" da parte del cittadino nella form della prenotazione" @@ -672,7 +727,7 @@ msgid "booking_refused" msgstr "Prenotazione rifiutata " #. Default: "Duration value" -#: redturtle/prenotazioni/content/prenotazione_type.py:15 +#: redturtle/prenotazioni/content/prenotazione_type.py:52 msgid "booking_type_duration_label" msgstr "Durata" @@ -682,12 +737,12 @@ msgid "booking_type_name" msgstr "Nome" #. Default: "List of requirements to recieve the service" -#: redturtle/prenotazioni/content/prenotazione_type.py:23 +#: redturtle/prenotazioni/content/prenotazione_type.py:60 msgid "booking_type_requirements_help" msgstr "Elencare le informazioni utili per il giorno della prenotazione, come ad esempio i documenti da presentare." #. Default: "Requirements" -#: redturtle/prenotazioni/content/prenotazione_type.py:22 +#: redturtle/prenotazioni/content/prenotazione_type.py:59 msgid "booking_type_requirements_labled" msgstr "Cosa serve" @@ -900,12 +955,12 @@ msgid "delete_reservation_request" msgstr "Cancella la richiesta di prenotazione per: ${name}" #. Default: "Unique booking code" -#: redturtle/prenotazioni/content/prenotazione.py:181 +#: redturtle/prenotazioni/content/prenotazione.py:182 msgid "description_booking_code" msgstr "Codice univoco della prenotazione" #. Default: "If you work for a company, please specify its name." -#: redturtle/prenotazioni/content/prenotazione.py:161 +#: redturtle/prenotazioni/content/prenotazione.py:162 msgid "description_company" msgstr "Se lavori per un'azienda, compila questo campo." @@ -1067,7 +1122,7 @@ msgid "invalid_date" msgstr "La data deve essere nel formato AAAA/MM/GG" #. Default: "Invalid email address" -#: redturtle/prenotazioni/content/prenotazione.py:32 +#: redturtle/prenotazioni/content/prenotazione.py:33 msgid "invalid_email_address" msgstr "Indirizzo email non valido" @@ -1078,12 +1133,12 @@ msgid "invalid_end:search_date" msgstr "Data di ricerca non valilda" #. Default: "Invalid fiscal code" -#: redturtle/prenotazioni/content/prenotazione.py:40 +#: redturtle/prenotazioni/content/prenotazione.py:41 msgid "invalid_fiscalcode" msgstr "Codice fiscale non valido" #. Default: "Invalid phone number" -#: redturtle/prenotazioni/content/prenotazione.py:28 +#: redturtle/prenotazioni/content/prenotazione.py:29 msgid "invalid_phone_number" msgstr "Numero di telefono non valido" @@ -1093,10 +1148,15 @@ msgid "invalid_time" msgstr "L'ora deve essere nel formato HH:MM" #. Default: "This date is past" -#: redturtle/prenotazioni/content/prenotazione.py:36 +#: redturtle/prenotazioni/content/prenotazione.py:37 msgid "is_not_future_date" msgstr "La data è nel passato." +#. Default: "Text line" +#: redturtle/prenotazioni/vocabularies/voc_booking_additional_fiels_types.py:34 +msgid "label_booking_additional_field_textline" +msgstr "Riga di testo" + #. Default: "Booking code" #: redturtle/prenotazioni/browser/templates/delete_reservation.pt:106 #: redturtle/prenotazioni/browser/templates/prenotazione.pt:123 @@ -1155,13 +1215,13 @@ msgstr "Numero di telefono" #. Default: "Staff notes" #: redturtle/prenotazioni/browser/templates/prenotazione.pt:113 -#: redturtle/prenotazioni/content/prenotazione.py:186 +#: redturtle/prenotazioni/content/prenotazione.py:187 msgid "label_booking_staff_notes" msgstr "Note del personale" #. Default: "Booking time" #: redturtle/prenotazioni/browser/prenotazione_move.py:30 -#: redturtle/prenotazioni/content/prenotazione.py:126 +#: redturtle/prenotazioni/content/prenotazione.py:127 msgid "label_booking_time" msgstr "Data e ora" @@ -1914,7 +1974,7 @@ msgid "to_month_too_days_error" msgstr "Il giorno selezionato non è compatibile col mese selezionato nel campo \"Al\"." #. Default: "You can't add a booking with type '${booking_type}'." -#: redturtle/prenotazioni/restapi/services/booking/add.py:132 +#: redturtle/prenotazioni/restapi/services/booking/add.py:135 msgid "unauthorized_add_vacation" msgstr "Impossibile creare una nuova prenotazione per la tipologia '${booking_type}'." diff --git a/src/redturtle/prenotazioni/locales/redturtle.prenotazioni.pot b/src/redturtle/prenotazioni/locales/redturtle.prenotazioni.pot index ef7bf69a..e84ebdb8 100644 --- a/src/redturtle/prenotazioni/locales/redturtle.prenotazioni.pot +++ b/src/redturtle/prenotazioni/locales/redturtle.prenotazioni.pot @@ -159,7 +159,7 @@ msgstr "" msgid "Email from" msgstr "" -#: redturtle/prenotazioni/content/prenotazione.py:175 +#: redturtle/prenotazioni/content/prenotazione.py:176 msgid "Expiration date booking" msgstr "" @@ -173,7 +173,7 @@ msgid "Friday" msgstr "" #: redturtle/prenotazioni/browser/templates/prenotazione.pt:107 -#: redturtle/prenotazioni/content/prenotazione.py:170 +#: redturtle/prenotazioni/content/prenotazione.py:171 msgid "Gate" msgstr "" @@ -365,7 +365,7 @@ msgstr "" msgid "Sorry, you can not book this slot for now." msgstr "" -#: redturtle/prenotazioni/content/prenotazione.py:171 +#: redturtle/prenotazioni/content/prenotazione.py:172 msgid "Sportello a cui presentarsi" msgstr "" @@ -603,7 +603,7 @@ msgid "auto_confirm_manager_help" msgstr "" #. Default: "End date should be greater than start." -#: redturtle/prenotazioni/restapi/services/available_slots/get.py:63 +#: redturtle/prenotazioni/restapi/services/available_slots/get.py:62 msgid "available_slots_wrong_dates" msgstr "" @@ -622,6 +622,46 @@ msgstr "" msgid "booked_prenotation_message" msgstr "" +#. Default: "Descrizione" +#: redturtle/prenotazioni/content/prenotazione_type.py:32 +msgid "booking_additional_field_description" +msgstr "" + +#. Default: "Label" +#: redturtle/prenotazioni/content/prenotazione_type.py:27 +msgid "booking_additional_field_label" +msgstr "" + +#. Default: "id" +#: redturtle/prenotazioni/content/prenotazione_type.py:18 +msgid "booking_additional_field_name" +msgstr "" + +#. Default: "Additional field id must be unique" +#: redturtle/prenotazioni/content/prenotazione_type.py:21 +msgid "booking_additional_field_name_help" +msgstr "" + +#. Default: "Required" +#: redturtle/prenotazioni/content/prenotazione_type.py:42 +msgid "booking_additional_field_required" +msgstr "" + +#. Default: "Tipo" +#: redturtle/prenotazioni/content/prenotazione_type.py:37 +msgid "booking_additional_field_type" +msgstr "" + +#. Default: "This schema is being used for the additional bookign fields" +#: redturtle/prenotazioni/content/prenotazione_type.py:79 +msgid "booking_additional_fields_schema_description" +msgstr "" + +#. Default: "Booking additional fields schema" +#: redturtle/prenotazioni/content/prenotazione_type.py:73 +msgid "booking_additional_fields_schema_title" +msgstr "" + #. Default: "Booking canceled: " #: redturtle/prenotazioni/behaviors/booking_folder/notifications/email/notification_email_message.py:371 msgid "booking_canceled_mail_subject_part" @@ -643,12 +683,12 @@ msgid "booking_deleted_success" msgstr "" #. Default: "Bookign detail help text" -#: redturtle/prenotazioni/content/prenotazione_type.py:41 +#: redturtle/prenotazioni/content/prenotazione_type.py:65 msgid "booking_details_help_text_label" msgstr "" #. Default: "This field will be visualized as \"Details\" helptext during the booking steps" -#: redturtle/prenotazioni/content/prenotazione_type.py:42 +#: redturtle/prenotazioni/content/prenotazione_type.py:66 msgid "booking_details_help_text_label_help" msgstr "" @@ -672,7 +712,7 @@ msgid "booking_refused" msgstr "" #. Default: "Duration value" -#: redturtle/prenotazioni/content/prenotazione_type.py:15 +#: redturtle/prenotazioni/content/prenotazione_type.py:39 msgid "booking_type_duration_label" msgstr "" @@ -682,12 +722,12 @@ msgid "booking_type_name" msgstr "" #. Default: "List of requirements to recieve the service" -#: redturtle/prenotazioni/content/prenotazione_type.py:23 +#: redturtle/prenotazioni/content/prenotazione_type.py:47 msgid "booking_type_requirements_help" msgstr "" #. Default: "Requirements" -#: redturtle/prenotazioni/content/prenotazione_type.py:22 +#: redturtle/prenotazioni/content/prenotazione_type.py:46 msgid "booking_type_requirements_labled" msgstr "" @@ -900,12 +940,12 @@ msgid "delete_reservation_request" msgstr "" #. Default: "Unique booking code" -#: redturtle/prenotazioni/content/prenotazione.py:181 +#: redturtle/prenotazioni/content/prenotazione.py:182 msgid "description_booking_code" msgstr "" #. Default: "If you work for a company, please specify its name." -#: redturtle/prenotazioni/content/prenotazione.py:161 +#: redturtle/prenotazioni/content/prenotazione.py:162 msgid "description_company" msgstr "" @@ -1066,7 +1106,7 @@ msgid "invalid_date" msgstr "" #. Default: "Invalid email address" -#: redturtle/prenotazioni/content/prenotazione.py:32 +#: redturtle/prenotazioni/content/prenotazione.py:33 msgid "invalid_email_address" msgstr "" @@ -1077,12 +1117,12 @@ msgid "invalid_end:search_date" msgstr "" #. Default: "Invalid fiscal code" -#: redturtle/prenotazioni/content/prenotazione.py:40 +#: redturtle/prenotazioni/content/prenotazione.py:41 msgid "invalid_fiscalcode" msgstr "" #. Default: "Invalid phone number" -#: redturtle/prenotazioni/content/prenotazione.py:28 +#: redturtle/prenotazioni/content/prenotazione.py:29 msgid "invalid_phone_number" msgstr "" @@ -1091,10 +1131,15 @@ msgid "invalid_time" msgstr "" #. Default: "This date is past" -#: redturtle/prenotazioni/content/prenotazione.py:36 +#: redturtle/prenotazioni/content/prenotazione.py:37 msgid "is_not_future_date" msgstr "" +#. Default: "Text line" +#: redturtle/prenotazioni/vocabularies/voc_booking_additional_fiels_types.py:19 +msgid "label_booking_additional_field_textline" +msgstr "" + #. Default: "Booking code" #: redturtle/prenotazioni/browser/templates/delete_reservation.pt:106 #: redturtle/prenotazioni/browser/templates/prenotazione.pt:123 @@ -1153,13 +1198,13 @@ msgstr "" #. Default: "Staff notes" #: redturtle/prenotazioni/browser/templates/prenotazione.pt:113 -#: redturtle/prenotazioni/content/prenotazione.py:186 +#: redturtle/prenotazioni/content/prenotazione.py:187 msgid "label_booking_staff_notes" msgstr "" #. Default: "Booking time" #: redturtle/prenotazioni/browser/prenotazione_move.py:30 -#: redturtle/prenotazioni/content/prenotazione.py:126 +#: redturtle/prenotazioni/content/prenotazione.py:127 msgid "label_booking_time" msgstr "" diff --git a/src/redturtle/prenotazioni/restapi/serializers/adapters/prenotazione.py b/src/redturtle/prenotazioni/restapi/serializers/adapters/prenotazione.py index 5146a01b..227199b9 100644 --- a/src/redturtle/prenotazioni/restapi/serializers/adapters/prenotazione.py +++ b/src/redturtle/prenotazioni/restapi/serializers/adapters/prenotazione.py @@ -100,6 +100,7 @@ def __call__(self, *args, **kwargs): "requirements": requirements, "modification_date": json_compatible(self.prenotazione.modified()), "creation_date": json_compatible(self.prenotazione.created()), + "additional_fields": self.prenotazione.additional_fields, } @@ -134,6 +135,7 @@ def __call__(self, *args, **kwargs): "email": self.prenotazione.email, "fiscalcode": self.prenotazione.fiscalcode, "phone": self.prenotazione.phone, + "additional_fields": self.prenotazione.additional_fields, "staff_notes": self.prenotazione.staff_notes, "company": self.prenotazione.company, "vacation": self.prenotazione.isVacation(), diff --git a/src/redturtle/prenotazioni/restapi/serializers/adapters/prenotazione_type.py b/src/redturtle/prenotazioni/restapi/serializers/adapters/prenotazione_type.py index 21a24d22..bcd526df 100644 --- a/src/redturtle/prenotazioni/restapi/serializers/adapters/prenotazione_type.py +++ b/src/redturtle/prenotazioni/restapi/serializers/adapters/prenotazione_type.py @@ -27,4 +27,7 @@ def __call__(self, *args, **kwargs): "booking_details_help_text": json_compatible( self.context.booking_details_help_text, self.context ), + "booking_additional_fields_schema": json_compatible( + self.context.booking_additional_fields_schema + ), } diff --git a/src/redturtle/prenotazioni/restapi/services/available_slots/get.py b/src/redturtle/prenotazioni/restapi/services/available_slots/get.py index ee8d467b..9581bcd7 100644 --- a/src/redturtle/prenotazioni/restapi/services/available_slots/get.py +++ b/src/redturtle/prenotazioni/restapi/services/available_slots/get.py @@ -23,7 +23,6 @@ def reply(self): If you pass the `first_available` flag the site will search in all the available time range of the Bookging Folder or in the next year and obtain the first one if exits, note that this option is only allowed for Booking Managers """ - # XXX: nocache also for anonymous self.request.response.setHeader("Cache-Control", "no-cache") diff --git a/src/redturtle/prenotazioni/restapi/services/booking/add.py b/src/redturtle/prenotazioni/restapi/services/booking/add.py index bf818f56..d80d0c70 100644 --- a/src/redturtle/prenotazioni/restapi/services/booking/add.py +++ b/src/redturtle/prenotazioni/restapi/services/booking/add.py @@ -9,8 +9,11 @@ from plone.restapi.interfaces import ISerializeToJsonSummary from zExceptions import BadRequest from zope.component import getMultiAdapter +from zope.component import getUtility from zope.component import queryMultiAdapter from zope.interface import alsoProvides +from zope.schema._bootstrapinterfaces import ValidationError +from zope.schema.interfaces import IVocabularyFactory from redturtle.prenotazioni import _ from redturtle.prenotazioni import logger @@ -160,4 +163,84 @@ def validate(self): ) raise BadRequest(msg) + # booking.additional_fields validation below + additional_fields = data.get("additional_fields") or [] + + # rewrite the fields to prevent not required data + additional_fields_data = [] + + field_types_vocabulary = getUtility( + IVocabularyFactory, + "redturtle.prenotazioni.booking_additional_fields_types", + )(self.context) + + field_types_validators = { + i.value: i.field_validator for i in field_types_vocabulary + } + + booking_type = list( + filter( + lambda i: i.title == data["booking_type"], + self.context.get_booking_types(), + ) + )[0] + + for field_schema in booking_type.booking_additional_fields_schema or []: + field = list( + filter( + lambda i: i.get("name") == field_schema.get("name"), + additional_fields, + ) + ) + + if not field and field_schema.get("required", False): + raise BadRequest( + api.portal.translate( + _( + "Additional field '${additional_field_name}' is missing.", + mapping=dict( + additional_field_name=field_schema.get("name") + ), + ) + ) + ) + elif not field: + continue + + field = field[0] + + try: + if not field.get("value"): + raise BadRequest( + api.portal.translate( + _( + "Additional field '${additional_field_name}' value is missing.", + mapping=dict( + additional_field_name=field_schema.get("name") + ), + ) + ) + ) + + # Validation + field_types_validators.get(field_schema.get("type"))(field.get("value")) + + except ValidationError as e: + raise BadRequest( + api.portal.translate( + _( + "Could not validate value for the ${field_name} due to: ${err_message}", + mapping=dict( + field_name=field_schema.get("name"), err_message=str(e) + ), + ) + ) + ) + + additional_fields_data.append( + {"name": field.get("name"), "value": field.get("value")} + ) + + data_fields["additional_fields"] = additional_fields_data + return data, data_fields diff --git a/src/redturtle/prenotazioni/restapi/services/booking/configure.zcml b/src/redturtle/prenotazioni/restapi/services/booking/configure.zcml index 03148c9d..58879ead 100644 --- a/src/redturtle/prenotazioni/restapi/services/booking/configure.zcml +++ b/src/redturtle/prenotazioni/restapi/services/booking/configure.zcml @@ -31,6 +31,13 @@ name="@booking" /> + + + diff --git a/src/redturtle/prenotazioni/vocabularies/voc_booking_additional_fiels_types.py b/src/redturtle/prenotazioni/vocabularies/voc_booking_additional_fiels_types.py new file mode 100644 index 00000000..c7e501ca --- /dev/null +++ b/src/redturtle/prenotazioni/vocabularies/voc_booking_additional_fiels_types.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +from zope.interface import implementer +from zope.schema import TextLine +from zope.schema.interfaces import IVocabularyFactory +from zope.schema.vocabulary import SimpleTerm +from zope.schema.vocabulary import SimpleVocabulary + +from redturtle.prenotazioni import _ + + +class SimpleTermFieldType(SimpleTerm): + field_validator = None + + def __init__(self, *args, **kwargs): + self.field_validator = kwargs.get("field_validator") + + if self.field_validator: + del kwargs["field_validator"] + + return super().__init__(*args, **kwargs) + + +@implementer(IVocabularyFactory) +class BookingAdditionalFieldsTypesVocabulary(object): + def __call__(self, context): + return SimpleVocabulary( + # Other fields may be added in the future + [ + SimpleTermFieldType( + "text", + "text", + context.translate( + _( + "label_booking_additional_field_textline", + default="Text line", + ) + ), + field_validator=TextLine().validate, + ) + ] + ) + + +BookingAdditionalFieldsTypesVocabularyFactory = BookingAdditionalFieldsTypesVocabulary()