diff --git a/CHANGES.rst b/CHANGES.rst index 1252b9fe..089aaa55 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -28,6 +28,9 @@ Changelog - Remove "immediate=True" from mailhost send in send_email_to_managers because can cause multiple sends when there are conflicts. [cekk] +- Better handle edge-case when a booking is created inside a pause (booking created before pause set in folder config). + [cekk] + 2.0.0 (2023-09-12) ------------------ diff --git a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py index b44b2c1a..8e0e4d61 100644 --- a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py +++ b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py @@ -742,7 +742,28 @@ def get_free_slots(self, booking_date, period="day"): availability = {} for gate in gates: availability.setdefault(gate, []) - gate_slots = slots_by_gate.get(gate, []) + all_gate_slots = slots_by_gate.get(gate, []) + pauses_slots = [ + x for x in all_gate_slots if x.context.portal_type == PAUSE_PORTAL_TYPE + ] + booking_slots = [ + x for x in all_gate_slots if x.context.portal_type != PAUSE_PORTAL_TYPE + ] + gate_slots = [] + gate_slots.extend(pauses_slots) + for slot in booking_slots: + skip = False + for pause in pauses_slots: + if slot in pause: + # edge-case when there is a slot created inside a pause range. + # probably this is because the slot (booking) has been created before + # someone set the pause. + # the booking should be listed, but its slot can't appear here because + # could mess free slots calc. + skip = True + break + if not skip: + gate_slots.append(slot) for interval in intervals: if interval: availability[gate].extend(interval - gate_slots) diff --git a/src/redturtle/prenotazioni/tests/test_move_booking_api.py b/src/redturtle/prenotazioni/tests/test_move_booking_api.py index a14bb32b..73e9cf6f 100644 --- a/src/redturtle/prenotazioni/tests/test_move_booking_api.py +++ b/src/redturtle/prenotazioni/tests/test_move_booking_api.py @@ -119,7 +119,6 @@ def test_move_booking_to_used_slot(self): "gate": "Gate A", }, ) - self.assertEqual(response.status_code, 400) self.assertEqual( response.json()["message"], diff --git a/src/redturtle/prenotazioni/tests/test_prenotazioni_context_state.py b/src/redturtle/prenotazioni/tests/test_prenotazioni_context_state.py new file mode 100644 index 00000000..9b52602c --- /dev/null +++ b/src/redturtle/prenotazioni/tests/test_prenotazioni_context_state.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +import unittest +from datetime import date, datetime +from Acquisition import aq_parent +from plone import api +from plone.app.testing import ( + SITE_OWNER_NAME, + SITE_OWNER_PASSWORD, + TEST_USER_ID, + setRoles, +) +from plone.restapi.testing import RelativeSession +from redturtle.prenotazioni.adapters.booker import IBooker +from redturtle.prenotazioni.testing import REDTURTLE_PRENOTAZIONI_INTEGRATION_TESTING +from redturtle.prenotazioni.tests.helpers import WEEK_TABLE_SCHEMA + + +class TestPrenotazioniContextState(unittest.TestCase): + layer = REDTURTLE_PRENOTAZIONI_INTEGRATION_TESTING + + def setUp(self): + self.app = self.layer["app"] + self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + self.api_session_admin = RelativeSession(self.portal_url) + self.api_session_admin.headers.update({"Accept": "application/json"}) + self.api_session_admin.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + + self.portal_url = self.portal.absolute_url() + self.folder_prenotazioni = api.content.create( + container=self.portal, + type="PrenotazioniFolder", + title="Folder", + description="", + daData=date.today(), + booking_types=[ + {"name": "Type A", "duration": "30"}, + ], + gates=["Gate A"], + week_table=WEEK_TABLE_SCHEMA, + ) + + def test_get_free_slots_skip_bookigs_inside_pause_range(self): + booker = IBooker(self.folder_prenotazioni) + + today = date.today() + # need this just to have the day container + aq_parent( + booker.create( + { + "booking_date": datetime( + today.year, today.month, today.day, 10, 00 + ), + "booking_type": "Type A", + "title": "foo", + } + ) + ) + + self.folder_prenotazioni.pause_table = [ + {"day": "0", "pause_end": "1100", "pause_start": "0800"}, + {"day": "1", "pause_end": "1100", "pause_start": "0800"}, + {"day": "2", "pause_end": "1100", "pause_start": "0800"}, + {"day": "3", "pause_end": "1100", "pause_start": "0800"}, + {"day": "4", "pause_end": "1100", "pause_start": "0800"}, + {"day": "5", "pause_end": "1100", "pause_start": "0800"}, + {"day": "6", "pause_end": "1100", "pause_start": "0800"}, + {"day": "7", "pause_end": "1100", "pause_start": "0800"}, + ] + + view = api.content.get_view( + context=self.folder_prenotazioni, + request=self.request, + name="prenotazioni_context_state", + ) + res = view.get_free_slots(today) + # available slots are only arount the pause and not inside it + self.assertEqual(len(res["Gate A"]), 2) + self.assertEqual(view.get_free_slots(today)["Gate A"][0].start(), "07:00") + self.assertEqual(view.get_free_slots(today)["Gate A"][0].stop(), "08:00") + self.assertEqual(view.get_free_slots(today)["Gate A"][1].start(), "11:00") + self.assertEqual(view.get_free_slots(today)["Gate A"][1].stop(), "13:00")