diff --git a/src/openforms/appointments/base.py b/src/openforms/appointments/base.py index ff4b626e7b..0367aa3315 100644 --- a/src/openforms/appointments/base.py +++ b/src/openforms/appointments/base.py @@ -49,21 +49,6 @@ def __str__(self): return self.identifier -@dataclass() -class Customer: - """ - Deprecated in favour of the :class:`CustomerDetails`. - """ - - last_name: str - birthdate: date - initials: str | None = None - phonenumber: str | None = None - - def __str__(self): - return self.last_name - - F = TypeVar("F", bound=TextChoices) # generic type for the plugin-specific enum of field names @@ -210,7 +195,7 @@ def create_appointment( products: list[Product], location: Location, start_at: datetime, - client: CustomerDetails[F] | Customer, + client: CustomerDetails[F], remarks: str = "", ) -> str: """ @@ -219,7 +204,7 @@ def create_appointment( :param products: List of :class:`Product`, as obtained from :meth:`get_available_products`. :param location: An :class:`Location`, as obtained from :meth:`get_locations`. :param start_at: A `datetime` to start the appointment, as obtained from :meth:`get_dates`. - :param client: A :class:`Customer` that holds client details. + :param client: A :class:`CustomerDetails` that holds client details. :param remarks: A ``str`` for additional remarks, added to the appointment. :returns: An appointment identifier as ``str``. :raises AppointmentCreateFailed: If the appointment could not be created. diff --git a/src/openforms/appointments/contrib/demo/plugin.py b/src/openforms/appointments/contrib/demo/plugin.py index fe3cb57808..aec28e3ae0 100644 --- a/src/openforms/appointments/contrib/demo/plugin.py +++ b/src/openforms/appointments/contrib/demo/plugin.py @@ -43,7 +43,7 @@ def get_dates(self, products, location, start_at=None, end_at=None): def get_times(self, products, location, day): today = timezone.localdate() - times = (time(12, 0), time(15, 15), time(15, 45)) + times = (time(12, 0), time(15, 15), time(15, 45), time(17, 45)) return [timezone.make_aware(datetime.combine(today, _time)) for _time in times] def get_required_customer_fields( diff --git a/src/openforms/appointments/contrib/jcc/plugin.py b/src/openforms/appointments/contrib/jcc/plugin.py index 40586a2703..0879caacea 100644 --- a/src/openforms/appointments/contrib/jcc/plugin.py +++ b/src/openforms/appointments/contrib/jcc/plugin.py @@ -1,5 +1,4 @@ import logging -import warnings from collections import Counter from contextlib import contextmanager from datetime import date, datetime @@ -20,14 +19,7 @@ from openforms.plugins.exceptions import InvalidPluginConfiguration from openforms.utils.date import TIMEZONE_AMS, datetime_in_amsterdam -from ...base import ( - AppointmentDetails, - BasePlugin, - Customer, - CustomerDetails, - Location, - Product, -) +from ...base import AppointmentDetails, BasePlugin, CustomerDetails, Location, Product from ...exceptions import ( AppointmentCreateFailed, AppointmentDeleteFailed, @@ -251,28 +243,10 @@ def create_appointment( products: list[Product], location: Location, start_at: datetime, - client: CustomerDetails[CustomerFields] | Customer, + client: CustomerDetails[CustomerFields], remarks: str = "", ) -> str: product_ids = squash_ids(products) - - # Phasing out Customer in favour of CustomerDetails, so convert to the new type - if isinstance(client, Customer): - warnings.warn( - "Fixed customer fields via the Customer class are deprecated, use " - "dynamic CustomerDetails with 'get_required_customer_fields' instead.", - DeprecationWarning, - ) - client = CustomerDetails( - details={ - CustomerFields.last_name: client.last_name, - CustomerFields.birthday: client.birthdate.isoformat(), - # Phone number is often required for appointment, - # use fake phone number if no client phone number - CustomerFields.main_tel: client.phonenumber or "0123456789", - } - ) - customer_details = { FIELD_TO_XML_NAME[key]: value for key, value in client.details.items() } diff --git a/src/openforms/appointments/contrib/qmatic/plugin.py b/src/openforms/appointments/contrib/qmatic/plugin.py index d49b3aa206..9c639abeb6 100644 --- a/src/openforms/appointments/contrib/qmatic/plugin.py +++ b/src/openforms/appointments/contrib/qmatic/plugin.py @@ -1,5 +1,4 @@ import json -import logging import warnings from collections import Counter from contextlib import contextmanager @@ -19,14 +18,7 @@ from openforms.formio.typing import Component from openforms.plugins.exceptions import InvalidPluginConfiguration -from ...base import ( - AppointmentDetails, - BasePlugin, - Customer, - CustomerDetails, - Location, - Product, -) +from ...base import AppointmentDetails, BasePlugin, CustomerDetails, Location, Product from ...exceptions import ( AppointmentCreateFailed, AppointmentDeleteFailed, @@ -73,25 +65,6 @@ def wrapper(*args, **kwargs) -> T: return decorator -def normalize_customer_details(client: _CustomerDetails | Customer) -> _CustomerDetails: - # Phasing out Customer in favour of CustomerDetails, so convert to the new type - if isinstance(client, Customer): - warnings.warn( - "Fixed customer fields via the Customer class are deprecated, use " - "dynamic CustomerDetails with 'get_required_customer_fields' instead.", - DeprecationWarning, - ) - client = _CustomerDetails( - details={ - CustomerFields.last_name: client.last_name, - CustomerFields.birthday: client.birthdate.isoformat(), - CustomerFields.first_name: client.initials or "", - CustomerFields.phone_number: client.phonenumber or "", - } - ) - return client - - @register("qmatic") class QmaticAppointment(BasePlugin[CustomerFields]): """ @@ -314,11 +287,18 @@ def create_appointment( products: list[Product], location: Location, start_at: datetime, - client: _CustomerDetails | Customer, + client: _CustomerDetails, remarks: str = "", ) -> str: assert products, "Can't book for empty products" - customer = normalize_customer_details(client) + customer = _CustomerDetails( + details={ + CustomerFields.last_name: client.last_name, + CustomerFields.birthday: client.birthdate.isoformat(), + CustomerFields.first_name: client.initials or "", + CustomerFields.phone_number: client.phonenumber or "", + } + ) product_names = ", ".join(sorted({product.name for product in products})) unique_product_ids, num_customers = self._count_products(products) diff --git a/src/openforms/appointments/tasks.py b/src/openforms/appointments/tasks.py index 4411a750ed..4cbd164f1b 100644 --- a/src/openforms/appointments/tasks.py +++ b/src/openforms/appointments/tasks.py @@ -1,5 +1,4 @@ import logging -import warnings from celery_once import QueueOnce @@ -8,10 +7,8 @@ from .core import book_for_submission from .exceptions import AppointmentRegistrationFailed, NoAppointmentForm -from .models import AppointmentInfo -from .utils import book_appointment_for_submission -__all__ = ["maybe_register_appointment"] +__all__ = ["register_appointment"] logger = logging.getLogger(__name__) @@ -21,7 +18,7 @@ ignore_result=False, once={"graceful": True}, # do not spam error monitoring ) -def maybe_register_appointment(submission_id: int) -> None | str: +def register_appointment(submission_id: int) -> None | str: """ Register an appointment for the submission IF relevant. @@ -32,26 +29,9 @@ def maybe_register_appointment(submission_id: int) -> None | str: be stored in the database. If appointment registration fails, this feedback should find its way back to the end-user. """ - warnings.warn( - "This task is deprecated because of the new appointment flow.", - PendingDeprecationWarning, - ) - logger.info("Registering appointment for submission %d (if needed!)", submission_id) + logger.info("Registering appointment for submission %d", submission_id) submission = Submission.objects.select_related("form").get(id=submission_id) - try: - appointment_id = submission.appointment_info.appointment_id - except AppointmentInfo.DoesNotExist: - pass - else: - # idempotency - do not register a new appointment if there already is one. - if appointment_id: - logger.info( - "Submission %s already has an appointment ID, aborting.", submission.pk - ) - return - - # Try the new appointments implementation first try: return book_for_submission(submission=submission) except NoAppointmentForm: @@ -63,15 +43,3 @@ def maybe_register_appointment(submission_id: int) -> None | str: extra={"submission": submission_id}, ) raise - - # otherwise, fall back to the old form - logger.info("Attempting old appointment booking for submission %r", submission_id) - try: - book_appointment_for_submission(submission) - except AppointmentRegistrationFailed as exc: - logger.info( - "Appointment registration failed, aborting workflow.", - exc_info=exc, - extra={"submission": submission_id}, - ) - raise diff --git a/src/openforms/appointments/utils.py b/src/openforms/appointments/utils.py index 2d9213dfab..0b7b435d92 100644 --- a/src/openforms/appointments/utils.py +++ b/src/openforms/appointments/utils.py @@ -2,25 +2,18 @@ import io import logging import re -import warnings -from datetime import datetime from django.utils.translation import gettext_lazy as _ import elasticapm import qrcode -from openforms.forms.models import Form, FormStep from openforms.logging import logevent from openforms.submissions.models import Submission -from .base import BasePlugin, Customer, Location, Product +from .base import BasePlugin from .constants import AppointmentDetailsStatus -from .exceptions import ( - AppointmentCreateFailed, - AppointmentDeleteFailed, - AppointmentRegistrationFailed, -) +from .exceptions import AppointmentDeleteFailed from .models import Appointment, AppointmentInfo, AppointmentsConfig from .registry import register @@ -36,18 +29,6 @@ def get_plugin(plugin: str = "") -> BasePlugin: return register[plugin] -def get_missing_fields_labels( - appointment_data: dict, missing_fields_keys: list[str] -) -> list[str]: - labels = [] - for key in missing_fields_keys: - if label := appointment_data.get(key, {}).get("label"): - labels.append(label) - else: - labels.append(key) - return sorted(labels) - - def get_formatted_phone_number(phone_number: str | None) -> str | None: """ Remove any character that isn't numeric or a space, +, or - character @@ -61,118 +42,6 @@ def get_formatted_phone_number(phone_number: str | None) -> str | None: return phone_number[:16] -@elasticapm.capture_span(span_type="app.appointments.book") -def book_appointment_for_submission(submission: Submission) -> None: - warnings.warn( - "Old-style appointments are deprecated, please update the form to use " - "the reworked appointments.", - DeprecationWarning, - ) - try: - # Delete the previous appointment info if there is one since - # since a new one will be created - # This function will be called multiple times on a failure so - # this is the case a previous appointment_info may exist - submission.appointment_info.delete() - except AppointmentInfo.DoesNotExist: - pass - - appointment_data = submission.get_merged_appointment_data() - - expected_information = [ - "productIDAndName", - "locationIDAndName", - "appStartTime", - "clientLastName", - "clientDateOfBirth", - ] - - absent_or_empty_information = [] - - for key in expected_information: - # there is a non-empty value, continue - this is good - if appointment_data.get(key, {}).get("value"): - continue - absent_or_empty_information.append(key) - - # Submission was never intended to make an appointment so just return - if set(absent_or_empty_information) == set(expected_information): - return - - # Partially filled out form (or appointment fields are present in the form and not - # filled at all). Note that the "contract" states an exception gets raised here - # which aborts the celery chain execution so that the end-user can be shown the - # error information. - if absent_or_empty_information: - # Incomplete information to make an appointment - logevent.appointment_register_skip(submission) - missing_fields_labels = get_missing_fields_labels( - appointment_data, absent_or_empty_information - ) - error_information = _( - "The following appointment fields should be filled out: {fields}" - ).format(fields=", ".join(missing_fields_labels)) - AppointmentInfo.objects.create( - status=AppointmentDetailsStatus.missing_info, - error_information=error_information, - submission=submission, - ) - raise AppointmentRegistrationFailed( - "No registration attempted because of incomplete information. " - ) - - product = Product( - identifier=appointment_data["productIDAndName"]["value"]["identifier"], - name=appointment_data["productIDAndName"]["value"]["name"], - ) - location = Location( - identifier=appointment_data["locationIDAndName"]["value"]["identifier"], - name=appointment_data["locationIDAndName"]["value"]["name"], - ) - appointment_client = Customer( - last_name=appointment_data["clientLastName"]["value"], - birthdate=datetime.strptime( - appointment_data["clientDateOfBirth"]["value"], "%Y-%m-%d" - ).date(), - phonenumber=get_formatted_phone_number( - appointment_data.get("clientPhoneNumber", {}).get("value") - ), - ) - start_at = datetime.strptime( - appointment_data["appStartTime"]["value"], "%Y-%m-%dT%H:%M:%S%z" - ) - - plugin = get_plugin() - try: - logevent.appointment_register_start(submission, plugin) - appointment_id = plugin.create_appointment( - [product], location, start_at, appointment_client - ) - appointment_info = AppointmentInfo.objects.create( - status=AppointmentDetailsStatus.success, - appointment_id=appointment_id, - submission=submission, - start_time=start_at, - ) - logevent.appointment_register_success(appointment_info, plugin) - except AppointmentCreateFailed as e: - logger.error("Appointment creation failed", exc_info=e) - # This is displayed to the end-user! - error_information = _( - "A technical error occurred while we tried to book your appointment. " - "Please verify if all the data is correct or try again later." - ) - appointment_info = AppointmentInfo.objects.create( - status=AppointmentDetailsStatus.failed, - error_information=error_information, - submission=submission, - ) - logevent.appointment_register_failure(appointment_info, plugin, e) - raise AppointmentRegistrationFailed("Unable to create appointment") from e - - cancel_previous_submission_appointment(submission) - - @elasticapm.capture_span(span_type="app.appointments.cancel") def cancel_previous_submission_appointment(submission: Submission) -> None: """ @@ -260,26 +129,6 @@ def create_base64_qrcode(text): return base64.b64encode(buffer.read()).decode("ascii") -def find_first_appointment_step(form: Form) -> FormStep | None: - """ - Find the first step in a form dealing with appointments. - - This looks at the component configuration for each step and detects if a component - is holding appointment-related meta-information. If no such step is found, ``None`` - is returned. - """ - for form_step in form.formstep_set.select_related("form_definition"): - for component in form_step.iter_components(recursive=True): - if "appointments" not in component: - continue - - if component["appointments"].get("showProducts"): - return form_step - - # no component in any form step found that satisfies - return None - - def get_confirmation_mail_suffix(submission: Submission) -> str: """ Determine the suffix, if appropriate for the subject of the confirmation mail. diff --git a/src/openforms/formio/formatters/tests/files/appointments_components.json b/src/openforms/formio/formatters/tests/files/appointments_components.json index 5d5f657ba7..e69de29bb2 100644 --- a/src/openforms/formio/formatters/tests/files/appointments_components.json +++ b/src/openforms/formio/formatters/tests/files/appointments_components.json @@ -1,805 +0,0 @@ -{ - "display": "form", - "components": [ - { - "id": "e1vezz1", - "key": "appointmentProduct", - "type": "select", - "input": true, - "label": "Select Appointment Product", - "limit": 100, - "filter": "", - "hidden": false, - "idPath": "id", - "prefix": "", - "suffix": "", - "unique": false, - "widget": null, - "dataSrc": "values", - "dbIndex": false, - "overlay": { - "top": "", - "left": "", - "style": "", - "width": "", - "height": "" - }, - "tooltip": "", - "disabled": false, - "lazyLoad": true, - "multiple": false, - "redrawOn": "", - "tabindex": "", - "template": "{{ item.label }}", - "validate": { - "custom": "", - "unique": false, - "plugins": [], - "multiple": false, - "required": true, - "customPrivate": false, - "onlyAvailableItems": false, - "strictDateValidation": false - }, - "autofocus": false, - "encrypted": false, - "hideLabel": false, - "indexeddb": { - "filter": {} - }, - "minSearch": 0, - "modalEdit": false, - "protected": false, - "refreshOn": "", - "tableView": true, - "attributes": {}, - "errorLabel": "", - "persistent": true, - "properties": {}, - "validateOn": "change", - "clearOnHide": true, - "conditional": { - "eq": "", - "show": null, - "when": null - }, - "customClass": "", - "description": "", - "fuseOptions": { - "include": "score", - "threshold": 0.3 - }, - "ignoreCache": false, - "placeholder": "", - "searchField": "", - "showInEmail": true, - "authenticate": false, - "defaultValue": "", - "registration": { - "attribute": "" - }, - "selectFields": "", - "customOptions": {}, - "dataGridLabel": false, - "labelPosition": "top", - "readOnlyValue": false, - "searchEnabled": true, - "showCharCount": false, - "showWordCount": false, - "uniqueOptions": false, - "valueProperty": "", - "calculateValue": "", - "clearOnRefresh": false, - "useExactSearch": false, - "calculateServer": false, - "isSensitiveData": false, - "selectThreshold": 0.3, - "allowMultipleMasks": false, - "customDefaultValue": "", - "allowCalculateOverride": false, - "appointments": { - "showProducts": true - } - }, - { - "id": "e1vezz2", - "key": "appointmentProductEmpty", - "type": "select", - "input": true, - "label": "Select Appointment Product Empty", - "limit": 100, - "filter": "", - "hidden": false, - "idPath": "id", - "prefix": "", - "suffix": "", - "unique": false, - "widget": null, - "dataSrc": "values", - "dbIndex": false, - "overlay": { - "top": "", - "left": "", - "style": "", - "width": "", - "height": "" - }, - "tooltip": "", - "disabled": false, - "lazyLoad": true, - "multiple": false, - "redrawOn": "", - "tabindex": "", - "template": "{{ item.label }}", - "validate": { - "custom": "", - "unique": false, - "plugins": [], - "multiple": false, - "required": true, - "customPrivate": false, - "onlyAvailableItems": false, - "strictDateValidation": false - }, - "autofocus": false, - "encrypted": false, - "hideLabel": false, - "indexeddb": { - "filter": {} - }, - "minSearch": 0, - "modalEdit": false, - "protected": false, - "refreshOn": "", - "tableView": true, - "attributes": {}, - "errorLabel": "", - "persistent": true, - "properties": {}, - "validateOn": "change", - "clearOnHide": true, - "conditional": { - "eq": "", - "show": null, - "when": null - }, - "customClass": "", - "description": "", - "fuseOptions": { - "include": "score", - "threshold": 0.3 - }, - "ignoreCache": false, - "placeholder": "", - "searchField": "", - "showInEmail": true, - "authenticate": false, - "defaultValue": "", - "registration": { - "attribute": "" - }, - "selectFields": "", - "customOptions": {}, - "dataGridLabel": false, - "labelPosition": "top", - "readOnlyValue": false, - "searchEnabled": true, - "showCharCount": false, - "showWordCount": false, - "uniqueOptions": false, - "valueProperty": "", - "calculateValue": "", - "clearOnRefresh": false, - "useExactSearch": false, - "calculateServer": false, - "isSensitiveData": false, - "selectThreshold": 0.3, - "allowMultipleMasks": false, - "customDefaultValue": "", - "allowCalculateOverride": false, - "appointments": { - "showProducts": true - } - }, - { - "id": "e1vezz3", - "key": "appointmentLocation", - "type": "select", - "input": true, - "label": "Select Appointment Location", - "limit": 100, - "filter": "", - "hidden": false, - "idPath": "id", - "prefix": "", - "suffix": "", - "unique": false, - "widget": null, - "dataSrc": "values", - "dbIndex": false, - "overlay": { - "top": "", - "left": "", - "style": "", - "width": "", - "height": "" - }, - "tooltip": "", - "disabled": false, - "lazyLoad": true, - "multiple": false, - "redrawOn": "", - "tabindex": "", - "template": "{{ item.label }}", - "validate": { - "custom": "", - "unique": false, - "plugins": [], - "multiple": false, - "required": true, - "customPrivate": false, - "onlyAvailableItems": false, - "strictDateValidation": false - }, - "autofocus": false, - "encrypted": false, - "hideLabel": false, - "indexeddb": { - "filter": {} - }, - "minSearch": 0, - "modalEdit": false, - "protected": false, - "refreshOn": "", - "tableView": true, - "attributes": {}, - "errorLabel": "", - "persistent": true, - "properties": {}, - "validateOn": "change", - "clearOnHide": true, - "conditional": { - "eq": "", - "show": null, - "when": null - }, - "customClass": "", - "description": "", - "fuseOptions": { - "include": "score", - "threshold": 0.3 - }, - "ignoreCache": false, - "placeholder": "", - "searchField": "", - "showInEmail": true, - "authenticate": false, - "defaultValue": "", - "registration": { - "attribute": "" - }, - "selectFields": "", - "customOptions": {}, - "dataGridLabel": false, - "labelPosition": "top", - "readOnlyValue": false, - "searchEnabled": true, - "showCharCount": false, - "showWordCount": false, - "uniqueOptions": false, - "valueProperty": "", - "calculateValue": "", - "clearOnRefresh": false, - "useExactSearch": false, - "calculateServer": false, - "isSensitiveData": false, - "selectThreshold": 0.3, - "allowMultipleMasks": false, - "customDefaultValue": "", - "allowCalculateOverride": false, - "appointments": { - "showLocations": true - } - }, - { - "id": "e1vezz4", - "key": "appointmentLocationEmpty", - "type": "select", - "input": true, - "label": "Select Appointment Location Empty", - "limit": 100, - "filter": "", - "hidden": false, - "idPath": "id", - "prefix": "", - "suffix": "", - "unique": false, - "widget": null, - "dataSrc": "values", - "dbIndex": false, - "overlay": { - "top": "", - "left": "", - "style": "", - "width": "", - "height": "" - }, - "tooltip": "", - "disabled": false, - "lazyLoad": true, - "multiple": false, - "redrawOn": "", - "tabindex": "", - "template": "{{ item.label }}", - "validate": { - "custom": "", - "unique": false, - "plugins": [], - "multiple": false, - "required": true, - "customPrivate": false, - "onlyAvailableItems": false, - "strictDateValidation": false - }, - "autofocus": false, - "encrypted": false, - "hideLabel": false, - "indexeddb": { - "filter": {} - }, - "minSearch": 0, - "modalEdit": false, - "protected": false, - "refreshOn": "", - "tableView": true, - "attributes": {}, - "errorLabel": "", - "persistent": true, - "properties": {}, - "validateOn": "change", - "clearOnHide": true, - "conditional": { - "eq": "", - "show": null, - "when": null - }, - "customClass": "", - "description": "", - "fuseOptions": { - "include": "score", - "threshold": 0.3 - }, - "ignoreCache": false, - "placeholder": "", - "searchField": "", - "showInEmail": true, - "authenticate": false, - "defaultValue": "", - "registration": { - "attribute": "" - }, - "selectFields": "", - "customOptions": {}, - "dataGridLabel": false, - "labelPosition": "top", - "readOnlyValue": false, - "searchEnabled": true, - "showCharCount": false, - "showWordCount": false, - "uniqueOptions": false, - "valueProperty": "", - "calculateValue": "", - "clearOnRefresh": false, - "useExactSearch": false, - "calculateServer": false, - "isSensitiveData": false, - "selectThreshold": 0.3, - "allowMultipleMasks": false, - "customDefaultValue": "", - "allowCalculateOverride": false, - "appointments": { - "showLocations": true - } - }, - { - "id": "e1vezz5", - "key": "appointmentDate", - "type": "select", - "input": true, - "label": "Select Appointment Date", - "limit": 100, - "filter": "", - "hidden": false, - "idPath": "id", - "prefix": "", - "suffix": "", - "unique": false, - "widget": null, - "dataSrc": "values", - "dbIndex": false, - "overlay": { - "top": "", - "left": "", - "style": "", - "width": "", - "height": "" - }, - "tooltip": "", - "disabled": false, - "lazyLoad": true, - "multiple": false, - "redrawOn": "", - "tabindex": "", - "template": "{{ item.label }}", - "validate": { - "custom": "", - "unique": false, - "plugins": [], - "multiple": false, - "required": true, - "customPrivate": false, - "onlyAvailableItems": false, - "strictDateValidation": false - }, - "autofocus": false, - "encrypted": false, - "hideLabel": false, - "indexeddb": { - "filter": {} - }, - "minSearch": 0, - "modalEdit": false, - "protected": false, - "refreshOn": "", - "tableView": true, - "attributes": {}, - "errorLabel": "", - "persistent": true, - "properties": {}, - "validateOn": "change", - "clearOnHide": true, - "conditional": { - "eq": "", - "show": null, - "when": null - }, - "customClass": "", - "description": "", - "fuseOptions": { - "include": "score", - "threshold": 0.3 - }, - "ignoreCache": false, - "placeholder": "", - "searchField": "", - "showInEmail": true, - "authenticate": false, - "defaultValue": "", - "registration": { - "attribute": "" - }, - "selectFields": "", - "customOptions": {}, - "dataGridLabel": false, - "labelPosition": "top", - "readOnlyValue": false, - "searchEnabled": true, - "showCharCount": false, - "showWordCount": false, - "uniqueOptions": false, - "valueProperty": "", - "calculateValue": "", - "clearOnRefresh": false, - "useExactSearch": false, - "calculateServer": false, - "isSensitiveData": false, - "selectThreshold": 0.3, - "allowMultipleMasks": false, - "customDefaultValue": "", - "allowCalculateOverride": false, - "appointments": { - "showDates": true - } - }, - { - "id": "e1vezz6", - "key": "appointmentDateEmpty", - "type": "select", - "input": true, - "label": "Select Appointment Date Empty", - "limit": 100, - "filter": "", - "hidden": false, - "idPath": "id", - "prefix": "", - "suffix": "", - "unique": false, - "widget": null, - "dataSrc": "values", - "dbIndex": false, - "overlay": { - "top": "", - "left": "", - "style": "", - "width": "", - "height": "" - }, - "tooltip": "", - "disabled": false, - "lazyLoad": true, - "multiple": false, - "redrawOn": "", - "tabindex": "", - "template": "{{ item.label }}", - "validate": { - "custom": "", - "unique": false, - "plugins": [], - "multiple": false, - "required": true, - "customPrivate": false, - "onlyAvailableItems": false, - "strictDateValidation": false - }, - "autofocus": false, - "encrypted": false, - "hideLabel": false, - "indexeddb": { - "filter": {} - }, - "minSearch": 0, - "modalEdit": false, - "protected": false, - "refreshOn": "", - "tableView": true, - "attributes": {}, - "errorLabel": "", - "persistent": true, - "properties": {}, - "validateOn": "change", - "clearOnHide": true, - "conditional": { - "eq": "", - "show": null, - "when": null - }, - "customClass": "", - "description": "", - "fuseOptions": { - "include": "score", - "threshold": 0.3 - }, - "ignoreCache": false, - "placeholder": "", - "searchField": "", - "showInEmail": true, - "authenticate": false, - "defaultValue": "", - "registration": { - "attribute": "" - }, - "selectFields": "", - "customOptions": {}, - "dataGridLabel": false, - "labelPosition": "top", - "readOnlyValue": false, - "searchEnabled": true, - "showCharCount": false, - "showWordCount": false, - "uniqueOptions": false, - "valueProperty": "", - "calculateValue": "", - "clearOnRefresh": false, - "useExactSearch": false, - "calculateServer": false, - "isSensitiveData": false, - "selectThreshold": 0.3, - "allowMultipleMasks": false, - "customDefaultValue": "", - "allowCalculateOverride": false, - "appointments": { - "showDates": true - } - }, - { - "id": "e1vezz7", - "key": "appointmentTime", - "type": "select", - "input": true, - "label": "Select Appointment Time", - "limit": 100, - "filter": "", - "hidden": false, - "idPath": "id", - "prefix": "", - "suffix": "", - "unique": false, - "widget": null, - "dataSrc": "values", - "dbIndex": false, - "overlay": { - "top": "", - "left": "", - "style": "", - "width": "", - "height": "" - }, - "tooltip": "", - "disabled": false, - "lazyLoad": true, - "multiple": false, - "redrawOn": "", - "tabindex": "", - "template": "{{ item.label }}", - "validate": { - "custom": "", - "unique": false, - "plugins": [], - "multiple": false, - "required": true, - "customPrivate": false, - "onlyAvailableItems": false, - "strictDateValidation": false - }, - "autofocus": false, - "encrypted": false, - "hideLabel": false, - "indexeddb": { - "filter": {} - }, - "minSearch": 0, - "modalEdit": false, - "protected": false, - "refreshOn": "", - "tableView": true, - "attributes": {}, - "errorLabel": "", - "persistent": true, - "properties": {}, - "validateOn": "change", - "clearOnHide": true, - "conditional": { - "eq": "", - "show": null, - "when": null - }, - "customClass": "", - "description": "", - "fuseOptions": { - "include": "score", - "threshold": 0.3 - }, - "ignoreCache": false, - "placeholder": "", - "searchField": "", - "showInEmail": true, - "authenticate": false, - "defaultValue": "", - "registration": { - "attribute": "" - }, - "selectFields": "", - "customOptions": {}, - "dataGridLabel": false, - "labelPosition": "top", - "readOnlyValue": false, - "searchEnabled": true, - "showCharCount": false, - "showWordCount": false, - "uniqueOptions": false, - "valueProperty": "", - "calculateValue": "", - "clearOnRefresh": false, - "useExactSearch": false, - "calculateServer": false, - "isSensitiveData": false, - "selectThreshold": 0.3, - "allowMultipleMasks": false, - "customDefaultValue": "", - "allowCalculateOverride": false, - "appointments": { - "showTimes": true - } - }, - { - "id": "e1vezz8", - "key": "appointmentTimeEmpty", - "type": "select", - "input": true, - "label": "Select Appointment Time Empty", - "limit": 100, - "filter": "", - "hidden": false, - "idPath": "id", - "prefix": "", - "suffix": "", - "unique": false, - "widget": null, - "dataSrc": "values", - "dbIndex": false, - "overlay": { - "top": "", - "left": "", - "style": "", - "width": "", - "height": "" - }, - "tooltip": "", - "disabled": false, - "lazyLoad": true, - "multiple": false, - "redrawOn": "", - "tabindex": "", - "template": "{{ item.label }}", - "validate": { - "custom": "", - "unique": false, - "plugins": [], - "multiple": false, - "required": true, - "customPrivate": false, - "onlyAvailableItems": false, - "strictDateValidation": false - }, - "autofocus": false, - "encrypted": false, - "hideLabel": false, - "indexeddb": { - "filter": {} - }, - "minSearch": 0, - "modalEdit": false, - "protected": false, - "refreshOn": "", - "tableView": true, - "attributes": {}, - "errorLabel": "", - "persistent": true, - "properties": {}, - "validateOn": "change", - "clearOnHide": true, - "conditional": { - "eq": "", - "show": null, - "when": null - }, - "customClass": "", - "description": "", - "fuseOptions": { - "include": "score", - "threshold": 0.3 - }, - "ignoreCache": false, - "placeholder": "", - "searchField": "", - "showInEmail": true, - "authenticate": false, - "defaultValue": "", - "registration": { - "attribute": "" - }, - "selectFields": "", - "customOptions": {}, - "dataGridLabel": false, - "labelPosition": "top", - "readOnlyValue": false, - "searchEnabled": true, - "showCharCount": false, - "showWordCount": false, - "uniqueOptions": false, - "valueProperty": "", - "calculateValue": "", - "clearOnRefresh": false, - "useExactSearch": false, - "calculateServer": false, - "isSensitiveData": false, - "selectThreshold": 0.3, - "allowMultipleMasks": false, - "customDefaultValue": "", - "allowCalculateOverride": false, - "appointments": { - "showTimes": true - } - } - ] -} diff --git a/src/openforms/formio/formatters/tests/files/appointments_data.json b/src/openforms/formio/formatters/tests/files/appointments_data.json index 888c38843e..e69de29bb2 100644 --- a/src/openforms/formio/formatters/tests/files/appointments_data.json +++ b/src/openforms/formio/formatters/tests/files/appointments_data.json @@ -1,10 +0,0 @@ -{ - "appointmentProduct": {"identifier": "foo", "name": "Foo Product"}, - "appointmentProductEmpty": "", - "appointmentLocation": {"identifier": "foo", "name": "Foo Location"}, - "appointmentLocationEmpty": "", - "appointmentDate": "2022-02-14", - "appointmentDateEmpty": "", - "appointmentTime": "2022-02-14T08:15:00+01:00", - "appointmentTimeEmpty": "" -} diff --git a/src/openforms/submissions/models/submission.py b/src/openforms/submissions/models/submission.py index f41ec6716f..a527d0403a 100644 --- a/src/openforms/submissions/models/submission.py +++ b/src/openforms/submissions/models/submission.py @@ -688,38 +688,6 @@ def get_last_completed_step(self) -> SubmissionStep | None: submission_state = self.load_execution_state() return submission_state.get_last_completed_step() - def get_merged_appointment_data(self) -> dict[str, dict[str, str | dict]]: - component_config_key_to_appointment_key = { - "appointments.showProducts": "productIDAndName", - "appointments.showLocations": "locationIDAndName", - "appointments.showTimes": "appStartTime", - "appointments.lastName": "clientLastName", - "appointments.birthDate": "clientDateOfBirth", - "appointments.phoneNumber": "clientPhoneNumber", - } - - merged_data = self.data - appointment_data = {} - - for component in self.form.iter_components(recursive=True): - # is this component any of the keys were looking for? - for ( - component_key, - appointment_key, - ) in component_config_key_to_appointment_key.items(): - is_the_right_component = glom(component, component_key, default=False) - if not is_the_right_component: - continue - - # it is the right component, get the value and store it - appointment_data[appointment_key] = { - "label": component["label"], - "value": merged_data.get(component["key"]), - } - break - - return appointment_data - @property def data(self) -> dict[str, Any]: """The filled-in data of the submission. diff --git a/src/openforms/submissions/tasks/__init__.py b/src/openforms/submissions/tasks/__init__.py index 38c80485a1..6fdbfe4dac 100644 --- a/src/openforms/submissions/tasks/__init__.py +++ b/src/openforms/submissions/tasks/__init__.py @@ -7,7 +7,7 @@ from celery import chain from celery.result import AsyncResult -from openforms.appointments.tasks import maybe_register_appointment +from openforms.appointments.tasks import register_appointment from openforms.celery import app from openforms.config.models import GlobalConfiguration @@ -33,9 +33,8 @@ def on_post_submission_event(submission_id: int, event: PostSubmissionEvents) -> # this can run any time because they have been claimed earlier cleanup_temporary_files_for.delay(submission_id) - # If the form involves appointments and no appointment has been scheduled yet, schedule it. - # Todo: deprecated => Not needed with the new appointment flow - register_appointment_task = maybe_register_appointment.si(submission_id) + # Register an appointment if the submission is for a form which is configured to create appointments. + register_appointment_task = register_appointment.si(submission_id) # Perform any pre-registration task specified by the registration plugin. If no registration plugin is configured, # just set a submission reference (if it hasn't already been set)