From b7e6cedb89ad54c6232153101e466ed90d9b1cac Mon Sep 17 00:00:00 2001 From: Daniele Andreotti Date: Mon, 7 Aug 2023 15:32:20 +0200 Subject: [PATCH 01/17] Code cleanup --- .../browser/prenotazioni_context_state.py | 67 +++++++++++++++++-- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py index 99d788a4..84c0a4dd 100644 --- a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py +++ b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py @@ -212,6 +212,7 @@ def get_week_table(self, day): week_table_overrides = json.loads( getattr(self.context, "week_table_overrides", "[]") or "[]" ) + if not week_table_overrides: return week_table @@ -402,11 +403,37 @@ def get_anonymous_booking_url(self, day, slot, slot_min_size=0): return self.unavailable_slot_booking_url @memoize - def get_gates(self): + def get_gates(self, booking_date): """ Get's the gates, available and unavailable """ - return self.context.getGates() or [""] + gates = self.context.getGates() or [""] + + week_table_overrides = json.loads( + getattr(self.context, "week_table_overrides", "[]") or "[]" + ) + + if week_table_overrides: + gates_override = week_table_overrides[0].get("gates", []) + if gates_override: + for override in week_table_overrides: + from_month = int(override.get("from_month", "")) + from_day = int(override.get("from_day", "")) + to_month = int(override.get("to_month", "")) + to_day = int(override.get("to_day", "")) + toYear = booking_date.year + + if from_month > to_month: + # next year + toYear += 1 + + fromDate = date(booking_date.year, from_month, from_day) + toDate = date(toYear, to_month, to_day) + + if fromDate <= booking_date <= toDate: + gates = gates_override + + return gates @memoize def get_unavailable_gates(self): @@ -416,11 +443,11 @@ def get_unavailable_gates(self): return self.context.getUnavailable_gates() @memoize - def get_available_gates(self): + def get_available_gates(self, booking_date): """ Get's the gates declared available """ - total = set(self.get_gates()) + total = set(self.get_gates(booking_date)) if self.get_unavailable_gates(): unavailable = set(self.get_unavailable_gates()) else: @@ -483,7 +510,7 @@ def get_free_gates_in_slot(self, booking_date, booking_end_date=None): :param booking_date: a DateTime object """ - available = set(self.get_available_gates()) + available = set(self.get_available_gates(booking_date)) busy = set(self.get_busy_gates_in_slot(booking_date, booking_end_date)) return available - busy @@ -611,8 +638,34 @@ def get_pauses_in_day_folder(self, booking_date): This method takes all pauses from the week table and convert it on slot :param booking_date: a date as a datetime or a string """ + weekday = booking_date.weekday() + + week_table_overrides = json.loads( + getattr(self.context, "week_table_overrides", "[]") or "[]" + ) + + pause_override = week_table_overrides[0].get("pauses", []) pause_table = self.context.pause_table or [] + + if pause_override: + for override in week_table_overrides: + from_month = int(override.get("from_month", "")) + from_day = int(override.get("from_day", "")) + to_month = int(override.get("to_month", "")) + to_day = int(override.get("to_day", "")) + toYear = booking_date.year + + if from_month > to_month: + # next year + toYear += 1 + + fromDate = date(booking_date.year, from_month, from_day) + toDate = date(toYear, to_month, to_day) + + if fromDate <= booking_date <= toDate: + pause_table = pause_override + today_pauses = [row for row in pause_table if row["day"] == str(weekday)] pauses = [] if today_pauses: @@ -695,7 +748,7 @@ def get_busy_slots(self, booking_date, period="day"): slots = self.get_busy_slots_in_period(booking_date, period) for slot in slots: if slot.context.portal_type == PAUSE_PORTAL_TYPE: - for gate in self.get_gates(): + for gate in self.get_gates(booking_date): slots_by_gate.setdefault(gate, []).append(slot) else: slots_by_gate.setdefault(slot.gate, []).append(slot) @@ -719,7 +772,7 @@ def get_free_slots(self, booking_date, period="day"): else: intervals = [day_intervals[period]] slots_by_gate = self.get_busy_slots(booking_date, period) - gates = self.get_gates() + gates = self.get_gates(booking_date) availability = {} for gate in gates: # unavailable gates doesn't have free slots From 9cb3d99f19fe0b067b6cf00fdd8261f835d7d7b0 Mon Sep 17 00:00:00 2001 From: Daniele Andreotti Date: Mon, 7 Aug 2023 15:37:08 +0200 Subject: [PATCH 02/17] updated history --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 0f28a778..60e10602 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog 2.0.0.dev4 (unreleased) ----------------------- +- Add logic to override pauses and gates. + [daniele] + - Fix default start/end time for search @bookings [mamico] From ecb5a8e6a561f262ca4e720c593f2a142818a33b Mon Sep 17 00:00:00 2001 From: Daniele Andreotti Date: Thu, 10 Aug 2023 15:57:54 +0200 Subject: [PATCH 03/17] fixed tests and code --- .../browser/prenotazioni_context_state.py | 16 ++++++++++------ .../prenotazioni/tests/test_prenotazione.py | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py index 84c0a4dd..caaadda7 100644 --- a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py +++ b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py @@ -403,7 +403,7 @@ def get_anonymous_booking_url(self, day, slot, slot_min_size=0): return self.unavailable_slot_booking_url @memoize - def get_gates(self, booking_date): + def get_gates(self, booking_date=None): """ Get's the gates, available and unavailable """ @@ -412,7 +412,6 @@ def get_gates(self, booking_date): week_table_overrides = json.loads( getattr(self.context, "week_table_overrides", "[]") or "[]" ) - if week_table_overrides: gates_override = week_table_overrides[0].get("gates", []) if gates_override: @@ -421,7 +420,11 @@ def get_gates(self, booking_date): from_day = int(override.get("from_day", "")) to_month = int(override.get("to_month", "")) to_day = int(override.get("to_day", "")) - toYear = booking_date.year + + if not booking_date: + toYear = datetime.today().year + else: + toYear = booking_date.year if from_month > to_month: # next year @@ -443,7 +446,7 @@ def get_unavailable_gates(self): return self.context.getUnavailable_gates() @memoize - def get_available_gates(self, booking_date): + def get_available_gates(self, booking_date=None): """ Get's the gates declared available """ @@ -638,14 +641,15 @@ def get_pauses_in_day_folder(self, booking_date): This method takes all pauses from the week table and convert it on slot :param booking_date: a date as a datetime or a string """ - weekday = booking_date.weekday() week_table_overrides = json.loads( getattr(self.context, "week_table_overrides", "[]") or "[]" ) - pause_override = week_table_overrides[0].get("pauses", []) + pause_override = [] + if week_table_overrides: + pause_override = week_table_overrides[0].get("pauses", []) pause_table = self.context.pause_table or [] if pause_override: diff --git a/src/redturtle/prenotazioni/tests/test_prenotazione.py b/src/redturtle/prenotazioni/tests/test_prenotazione.py index c95ab95c..57ce71f4 100644 --- a/src/redturtle/prenotazioni/tests/test_prenotazione.py +++ b/src/redturtle/prenotazioni/tests/test_prenotazione.py @@ -92,10 +92,10 @@ def setUp(self): def test_add_booking_anonymous(self): self.api_session.auth = None - booking_date = "{}T09:00:00".format( + booking_date = "{}T09:00:00+00:00".format( (date.today() + timedelta(1)).strftime("%Y-%m-%d") ) - booking_expiration_date = "{}T09:30:00".format( + booking_expiration_date = "{}T09:30:00+00:00".format( (date.today() + timedelta(1)).strftime("%Y-%m-%d") ) res = self.api_session.post( From bc708e421e05ca790ca002f9049eb174b1cd6a9e Mon Sep 17 00:00:00 2001 From: Daniele Andreotti Date: Wed, 16 Aug 2023 15:00:09 +0200 Subject: [PATCH 04/17] added tests --- .../tests/test_pauses_overrides.py | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 src/redturtle/prenotazioni/tests/test_pauses_overrides.py diff --git a/src/redturtle/prenotazioni/tests/test_pauses_overrides.py b/src/redturtle/prenotazioni/tests/test_pauses_overrides.py new file mode 100644 index 00000000..430f17ba --- /dev/null +++ b/src/redturtle/prenotazioni/tests/test_pauses_overrides.py @@ -0,0 +1,210 @@ +# -*- coding: utf-8 -*- +from datetime import date +import transaction + +from plone.app.testing import ( + SITE_OWNER_NAME, + SITE_OWNER_PASSWORD, + TEST_USER_ID, + setRoles, +) +from plone.restapi.testing import RelativeSession +from redturtle.prenotazioni.testing import ( + REDTURTLE_PRENOTAZIONI_API_FUNCTIONAL_TESTING, +) +from redturtle.prenotazioni.testing import ( + REDTURTLE_PRENOTAZIONI_FUNCTIONAL_TESTING, +) +from plone import api + +import unittest +import json + + +class TestContextState(unittest.TestCase): + layer = REDTURTLE_PRENOTAZIONI_FUNCTIONAL_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.folder_prenotazioni = api.content.create( + container=self.portal, + type="PrenotazioniFolder", + title="Prenota foo", + description="", + daData=date.today(), + booking_types=[ + {"name": "Type A", "duration": "30"}, + ], + gates=["Gate A"], + pause_table=[ + {"day": "0", "pause_start": "0900", "pause_end": "0915"}, + {"day": "1", "pause_start": "0900", "pause_end": "0915"}, + {"day": "2", "pause_start": "0900", "pause_end": "0915"}, + {"day": "3", "pause_start": "0900", "pause_end": "0915"}, + {"day": "4", "pause_start": "0900", "pause_end": "0915"}, + {"day": "5", "pause_start": "0900", "pause_end": "0915"}, + ], + week_table=[ + { + "day": "Lunedì", + "morning_start": "0700", + "morning_end": "1000", + "afternoon_start": None, + "afternoon_end": None, + }, + ], + week_table_overrides=json.dumps( + [ + { + "from_day": "1", + "from_month": "1", + "to_month": "2", + "pauses": [ + {"day": "0", "pause_end": "1200", "pause_start": "1000"}, + {"day": "1", "pause_end": "1200", "pause_start": "1000"}, + {"day": "2", "pause_end": "1200", "pause_start": "1000"}, + {"day": "3", "pause_end": "1200", "pause_start": "1000"}, + {"day": "4", "pause_end": "1200", "pause_start": "1000"}, + {"day": "5", "pause_end": "1200", "pause_start": "1000"}, + ], + "to_day": "18", + "week_table": [ + { + "day": "Lunedì", + "morning_start": "1100", + "morning_end": "1200", + "afternoon_start": None, + "afternoon_end": None, + }, + ], + } + ] + ), + ) + api.content.transition(obj=self.folder_prenotazioni, transition="publish") + transaction.commit() + + self.view = api.content.get_view( + name="prenotazioni_context_state", + context=self.folder_prenotazioni, + request=self.request, + ) + + def test_day_in_override_pause_table(self): + now = date.today() + res = self.view.get_pauses_in_day_folder(date(now.year, 1, 10)) + pause = res[0] + self.assertEqual(pause.start, '10:00') and self.assertEqual(pause.stop, '12:00') + + def test_day_not_in_override_pause_table(self): + now = date.today() + res = self.view.get_pauses_in_day_folder(date(now.year, 6, 10)) + pause = res[0] + self.assertNotEqual(pause.start, '10:00') and self.assertNotEqual(pause.stop, '12:00') + + +class TestAPIPost(unittest.TestCase): + layer = REDTURTLE_PRENOTAZIONI_API_FUNCTIONAL_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.folder_prenotazioni = api.content.create( + container=self.portal, + type="PrenotazioniFolder", + title="Prenota foo", + description="", + daData=date.today(), + booking_types=[ + {"name": "Type A", "duration": "30"}, + ], + gates=["Gate A"], + pause_table=[ + {"day": "0", "pause_start": "0900", "pause_end": "0915"}, + {"day": "1", "pause_start": "0900", "pause_end": "0915"}, + {"day": "2", "pause_start": "0900", "pause_end": "0915"}, + {"day": "3", "pause_start": "0900", "pause_end": "0915"}, + {"day": "4", "pause_start": "0900", "pause_end": "0915"}, + {"day": "5", "pause_start": "0900", "pause_end": "0915"}, + ], + week_table=[ + { + "day": "Lunedì", + "morning_start": "0700", + "morning_end": "1000", + "afternoon_start": None, + "afternoon_end": None, + }, + ], + week_table_overrides=json.dumps( + [ + { + "from_day": "1", + "from_month": "1", + "to_month": "2", + "pauses": [ + {"day": "0", "pause_end": "1200", "pause_start": "1000"}, + {"day": "1", "pause_end": "1200", "pause_start": "1000"}, + {"day": "2", "pause_end": "1200", "pause_start": "1000"}, + {"day": "3", "pause_end": "1200", "pause_start": "1000"}, + {"day": "4", "pause_end": "1200", "pause_start": "1000"}, + {"day": "5", "pause_end": "1200", "pause_start": "1000"}, + ], + "to_day": "18", + "week_table": [ + { + "day": "Lunedì", + "morning_start": "1100", + "morning_end": "1200", + "afternoon_start": None, + "afternoon_end": None, + }, + ], + } + ] + ), + ) + api.content.transition(obj=self.folder_prenotazioni, transition="publish") + transaction.commit() + + self.api_session = RelativeSession(self.portal_url) + self.api_session.headers.update({"Accept": "application/json"}) + self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + + self.view = api.content.get_view( + name="prenotazioni_context_state", + context=self.folder_prenotazioni, + request=self.request, + ) + + def tearDown(self): + self.api_session.close() + + def test_add_booking_in_overrided_pause(self): + self.api_session.auth = None + booking_date = "{}T11:00:00+00:00".format( + (date(date.today().year, 1, 10)).strftime("%Y-%m-%d") + ) + + res = self.api_session.post( + self.folder_prenotazioni.absolute_url() + "/@booking", + json={ + "booking_date": booking_date, + "booking_type": "Type A", + "fields": [ + {"name": "fullname", "value": "Mario Rossi"}, + {"name": "email", "value": "mario.rossi@example"}, + ], + }, + ) + + self.assertNotEqual(res.status_code, 200) From 795ba4f0c1b5aa1db88d5d368cb84f665a74491d Mon Sep 17 00:00:00 2001 From: Daniele Andreotti Date: Wed, 16 Aug 2023 15:08:18 +0200 Subject: [PATCH 05/17] blacked --- src/redturtle/prenotazioni/tests/test_pauses_overrides.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/redturtle/prenotazioni/tests/test_pauses_overrides.py b/src/redturtle/prenotazioni/tests/test_pauses_overrides.py index 430f17ba..827c9ae6 100644 --- a/src/redturtle/prenotazioni/tests/test_pauses_overrides.py +++ b/src/redturtle/prenotazioni/tests/test_pauses_overrides.py @@ -99,13 +99,15 @@ def test_day_in_override_pause_table(self): now = date.today() res = self.view.get_pauses_in_day_folder(date(now.year, 1, 10)) pause = res[0] - self.assertEqual(pause.start, '10:00') and self.assertEqual(pause.stop, '12:00') + self.assertEqual(pause.start, "10:00") and self.assertEqual(pause.stop, "12:00") def test_day_not_in_override_pause_table(self): now = date.today() res = self.view.get_pauses_in_day_folder(date(now.year, 6, 10)) pause = res[0] - self.assertNotEqual(pause.start, '10:00') and self.assertNotEqual(pause.stop, '12:00') + self.assertNotEqual(pause.start, "10:00") and self.assertNotEqual( + pause.stop, "12:00" + ) class TestAPIPost(unittest.TestCase): From 3ff8de86eec680edac071969f9fbcac73b93c632 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Wed, 16 Aug 2023 15:47:54 +0200 Subject: [PATCH 06/17] stop on first override --- src/redturtle/prenotazioni/browser/prenotazioni_context_state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py index 2aa6b606..eb519cab 100644 --- a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py +++ b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py @@ -416,6 +416,7 @@ def get_gates(self, booking_date=None): if fromDate <= booking_date <= toDate: gates = gates_override + break unavailable = self.context.getUnavailable_gates() or [] return [ From c8fa4a25c5b1ae24f147f676cd2e3daf4ae77f17 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Wed, 16 Aug 2023 15:50:17 +0200 Subject: [PATCH 07/17] black --- .../prenotazioni/browser/prenotazioni_context_state.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py index eb519cab..4fd90bd1 100644 --- a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py +++ b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py @@ -439,7 +439,9 @@ def get_available_gates(self, booking_date=None): """ Get's the gates declared available """ - return [gate["name"] for gate in self.get_gates(booking_date) if gate["available"]] + return [ + gate["name"] for gate in self.get_gates(booking_date) if gate["available"] + ] def get_busy_gates_in_slot(self, booking_date, booking_end_date=None): """ From f1e7790ebd6f0fd7f0f0a4dba29cc1298db20c64 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Fri, 18 Aug 2023 14:15:28 +0200 Subject: [PATCH 08/17] normalize field names --- .../prenotazioni/browser/prenotazioni_context_state.py | 9 ++++----- .../prenotazioni/tests/test_pauses_overrides.py | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py index 4fd90bd1..cd2d5ac4 100644 --- a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py +++ b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py @@ -413,8 +413,7 @@ def get_gates(self, booking_date=None): fromDate = date(booking_date.year, from_month, from_day) toDate = date(toYear, to_month, to_day) - - if fromDate <= booking_date <= toDate: + if fromDate <= booking_date.date() <= toDate: gates = gates_override break @@ -638,7 +637,7 @@ def get_pauses_in_day_folder(self, booking_date): pause_override = [] if week_table_overrides: - pause_override = week_table_overrides[0].get("pauses", []) + pause_override = week_table_overrides[0].get("pause_table", []) pause_table = self.context.pause_table or [] if pause_override: @@ -679,9 +678,9 @@ def get_existing_slots_in_day_folder(self, booking_date): """ bookings = self.get_bookings_in_day_folder(booking_date) pauses = self.get_pauses_in_day_folder(booking_date) - bookins_list = list(map(ISlot, bookings)) + bookings_list = list(map(ISlot, bookings)) pauses_list = list(map(ISlot, pauses)) - return bookins_list + pauses_list + return bookings_list + pauses_list def get_busy_slots_in_stormynight(self, booking_date): """This will show the slots that will not show elsewhere""" diff --git a/src/redturtle/prenotazioni/tests/test_pauses_overrides.py b/src/redturtle/prenotazioni/tests/test_pauses_overrides.py index 827c9ae6..077531c7 100644 --- a/src/redturtle/prenotazioni/tests/test_pauses_overrides.py +++ b/src/redturtle/prenotazioni/tests/test_pauses_overrides.py @@ -64,7 +64,7 @@ def setUp(self): "from_day": "1", "from_month": "1", "to_month": "2", - "pauses": [ + "pause_table": [ {"day": "0", "pause_end": "1200", "pause_start": "1000"}, {"day": "1", "pause_end": "1200", "pause_start": "1000"}, {"day": "2", "pause_end": "1200", "pause_start": "1000"}, @@ -153,7 +153,7 @@ def setUp(self): "from_day": "1", "from_month": "1", "to_month": "2", - "pauses": [ + "pause_table": [ {"day": "0", "pause_end": "1200", "pause_start": "1000"}, {"day": "1", "pause_end": "1200", "pause_start": "1000"}, {"day": "2", "pause_end": "1200", "pause_start": "1000"}, From 4cfc38f5caaf949d9e4d4dbcfe61c38096997232 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 21 Aug 2023 15:14:54 +0200 Subject: [PATCH 09/17] removed unused unavailable_gates field --- .../prenotazioni/adapters/conflict.py | 2 +- .../browser/prenotazioni_context_state.py | 54 +++++-------------- .../content/prenotazioni_folder.py | 19 ------- .../en/LC_MESSAGES/redturtle.prenotazioni.po | 10 ---- .../it/LC_MESSAGES/redturtle.prenotazioni.po | 10 ---- .../locales/redturtle.prenotazioni.pot | 10 ---- 6 files changed, 14 insertions(+), 91 deletions(-) diff --git a/src/redturtle/prenotazioni/adapters/conflict.py b/src/redturtle/prenotazioni/adapters/conflict.py index 98fd4408..742125f7 100644 --- a/src/redturtle/prenotazioni/adapters/conflict.py +++ b/src/redturtle/prenotazioni/adapters/conflict.py @@ -60,7 +60,7 @@ def get_limit(self): # XXX: per come è ora la funzione probabilmente questa condizione non è mai vera # if not self.prenotazioni.get_gates(): # return 1 - return len(self.prenotazioni.get_available_gates()) + return len(self.prenotazioni.get_gates()) def unrestricted_prenotazioni(self, **kw): """ diff --git a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py index cd2d5ac4..1f1d9aa0 100644 --- a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py +++ b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py @@ -388,6 +388,11 @@ def get_gates(self, booking_date=None): """ Get's the gates, available and unavailable """ + + if isinstance(booking_date, datetime): + # sometimes booking_date is passed as date and sometimes as datetime + booking_date = booking_date.date() + gates = self.context.getGates() or [""] week_table_overrides = json.loads( @@ -410,37 +415,12 @@ def get_gates(self, booking_date=None): if from_month > to_month: # next year toYear += 1 - fromDate = date(booking_date.year, from_month, from_day) toDate = date(toYear, to_month, to_day) - if fromDate <= booking_date.date() <= toDate: + if fromDate <= booking_date <= toDate: gates = gates_override break - - unavailable = self.context.getUnavailable_gates() or [] - return [ - { - "name": gate, - "available": gate not in unavailable, - } - for gate in gates or [""] - ] - - @memoize - def get_unavailable_gates(self): - """ - Get's the gates declared unavailable - """ - return self.context.getUnavailable_gates() - - @memoize - def get_available_gates(self, booking_date=None): - """ - Get's the gates declared available - """ - return [ - gate["name"] for gate in self.get_gates(booking_date) if gate["available"] - ] + return gates def get_busy_gates_in_slot(self, booking_date, booking_end_date=None): """ @@ -464,9 +444,6 @@ def get_busy_gates_in_slot(self, booking_date, booking_end_date=None): booking_date=booking_date, booking_end_date=booking_end_date, ) - # unavailable gates are always busy - if self.get_unavailable_gates(): - gates.update(self.get_unavailable_gates()) return gates def get_full_gates_in_date( @@ -498,7 +475,7 @@ def get_free_gates_in_slot(self, booking_date, booking_end_date=None): :param booking_date: a DateTime object """ - available = set(self.get_available_gates(booking_date)) + available = set(self.get_gates(booking_date)) busy = set(self.get_busy_gates_in_slot(booking_date, booking_end_date)) return available - busy @@ -657,7 +634,6 @@ def get_pauses_in_day_folder(self, booking_date): if fromDate <= booking_date <= toDate: pause_table = pause_override - today_pauses = [row for row in pause_table if row["day"] == str(weekday)] pauses = [] for pause in today_pauses: @@ -765,15 +741,11 @@ def get_free_slots(self, booking_date, period="day"): gates = [gate["name"] for gate in self.get_gates(booking_date)] availability = {} for gate in gates: - # unavailable gates doesn't have free slots - if self.get_unavailable_gates() and gate in self.get_unavailable_gates(): - availability[gate] = [] - else: - availability.setdefault(gate, []) - gate_slots = slots_by_gate.get(gate, []) - for interval in intervals: - if interval: - availability[gate].extend(interval - gate_slots) + availability.setdefault(gate, []) + gate_slots = slots_by_gate.get(gate, []) + for interval in intervals: + if interval: + availability[gate].extend(interval - gate_slots) return availability def get_freebusy_slots(self, booking_date, period="day"): diff --git a/src/redturtle/prenotazioni/content/prenotazioni_folder.py b/src/redturtle/prenotazioni/content/prenotazioni_folder.py index de522aaa..4a7909da 100644 --- a/src/redturtle/prenotazioni/content/prenotazioni_folder.py +++ b/src/redturtle/prenotazioni/content/prenotazioni_folder.py @@ -433,22 +433,6 @@ def get_options(): default=[], ) - unavailable_gates = schema.List( - title=_("unavailable_gates_label", "Unavailable gates"), - description=_( - "unavailable_gates_help", - default="Add a gate here (one per line) if, " - "for some reason, " - "it is not be available." - "The specified gate will not be taken in to " # noqa - "account for slot allocation. " - "Each line should match a corresponding " - 'line in the "Gates" field', - ), - required=False, - value_type=schema.TextLine(), - default=[], - ) auto_confirm = schema.Bool( title=_("auto_confirm", default="Automatically confirm."), description=_( @@ -719,9 +703,6 @@ def getDescriptionAgenda(self): def getGates(self): return self.gates - def getUnavailable_gates(self): - return self.unavailable_gates - def getDaData(self): return self.daData 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 20ed6dbd..a50cfbf9 100644 --- a/src/redturtle/prenotazioni/locales/en/LC_MESSAGES/redturtle.prenotazioni.po +++ b/src/redturtle/prenotazioni/locales/en/LC_MESSAGES/redturtle.prenotazioni.po @@ -1374,16 +1374,6 @@ msgstr "" msgid "to_month_too_days_error" msgstr "" -#. Default: "Add a gate here (one per line) if, for some reason, it is not be available.The specified gate will not be taken in to account for slot allocation. Each line should match a corresponding line in the \"Gates\" field" -#: redturtle/prenotazioni/content/prenotazioni_folder.py:437 -msgid "unavailable_gates_help" -msgstr "" - -#. Default: "Unavailable gates" -#: redturtle/prenotazioni/content/prenotazioni_folder.py:436 -msgid "unavailable_gates_label" -msgstr "" - #. Default: "Unbookable time" #: redturtle/prenotazioni/browser/templates/prenotazione_macros.pt:304 msgid "unbookable_time" 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 d4e5e2e1..916e2cfd 100644 --- a/src/redturtle/prenotazioni/locales/it/LC_MESSAGES/redturtle.prenotazioni.po +++ b/src/redturtle/prenotazioni/locales/it/LC_MESSAGES/redturtle.prenotazioni.po @@ -1381,16 +1381,6 @@ msgstr "Devi impostare una data di inizio." msgid "to_month_too_days_error" msgstr "Il giorno selezionato non è compatibile col mese selezionato nel campo \"Al\"." -#. Default: "Add a gate here (one per line) if, for some reason, it is not be available.The specified gate will not be taken in to account for slot allocation. Each line should match a corresponding line in the \"Gates\" field" -#: redturtle/prenotazioni/content/prenotazioni_folder.py:437 -msgid "unavailable_gates_help" -msgstr "Aggiungi una postazione (uno per riga) se, per qualche motivo, non è disponibile. La postazione specificata non sarà considerata per l'allocazione degli appuntamenti. Le righe devono essere uguali a quelle nel campo \"Postazioni preposte\"." - -#. Default: "Unavailable gates" -#: redturtle/prenotazioni/content/prenotazioni_folder.py:436 -msgid "unavailable_gates_label" -msgstr "Postazioni non disponibili" - #. Default: "Unbookable time" #: redturtle/prenotazioni/browser/templates/prenotazione_macros.pt:304 msgid "unbookable_time" diff --git a/src/redturtle/prenotazioni/locales/redturtle.prenotazioni.pot b/src/redturtle/prenotazioni/locales/redturtle.prenotazioni.pot index c0b2e77f..2dace55a 100644 --- a/src/redturtle/prenotazioni/locales/redturtle.prenotazioni.pot +++ b/src/redturtle/prenotazioni/locales/redturtle.prenotazioni.pot @@ -1377,16 +1377,6 @@ msgstr "" msgid "to_month_too_days_error" msgstr "" -#. Default: "Add a gate here (one per line) if, for some reason, it is not be available.The specified gate will not be taken in to account for slot allocation. Each line should match a corresponding line in the \"Gates\" field" -#: redturtle/prenotazioni/content/prenotazioni_folder.py:437 -msgid "unavailable_gates_help" -msgstr "" - -#. Default: "Unavailable gates" -#: redturtle/prenotazioni/content/prenotazioni_folder.py:436 -msgid "unavailable_gates_label" -msgstr "" - #. Default: "Unbookable time" #: redturtle/prenotazioni/browser/templates/prenotazione_macros.pt:304 msgid "unbookable_time" From 128fca427ec87418a1d055e071bb9d80f61ef4d9 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Tue, 22 Aug 2023 10:20:21 +0200 Subject: [PATCH 10/17] fix tests and widget --- .../browser/prenotazioni_context_state.py | 107 ++++----- .../static/widget/js/WidgetContainer/index.js | 14 ++ .../widget/js/WidgetDataContainer/index.js | 4 + .../static/widget/js/fields/GatesField.js | 104 +++++++++ .../static/widget/js/fields/GatesField.less | 24 ++ .../widget/js/fields/PauseTableField.js | 137 +++++++++++ .../widget/js/fields/PauseTableField.less | 0 .../static/widget/js/fields/SelectField.js | 11 +- .../restapi/services/booking/add.py | 33 +-- src/redturtle/prenotazioni/tests/helpers.py | 52 +++++ .../tests/test_pauses_overrides.py | 214 +++++++++++++----- 11 files changed, 566 insertions(+), 134 deletions(-) create mode 100644 src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.js create mode 100644 src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.less create mode 100644 src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.js create mode 100644 src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.less create mode 100644 src/redturtle/prenotazioni/tests/helpers.py diff --git a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py index 1f1d9aa0..9c06d617 100644 --- a/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py +++ b/src/redturtle/prenotazioni/browser/prenotazioni_context_state.py @@ -22,10 +22,13 @@ from six.moves import map from six.moves import range +import logging import itertools import json import six +logger = logging.getLogger(__name__) + class PrenotazioniContextState(BrowserView): @@ -168,15 +171,13 @@ def is_configured_day(self, day): ) ) - def get_week_table(self, day): - week_table = getattr(self.context, "week_table", {}) + def get_week_overrides(self, day): week_table_overrides = json.loads( getattr(self.context, "week_table_overrides", "[]") or "[]" ) if not week_table_overrides: - return week_table - + return {} for override in week_table_overrides: from_month = int(override.get("from_month", "")) from_day = int(override.get("from_day", "")) @@ -193,10 +194,17 @@ def get_week_table(self, day): if isinstance(day, datetime): if fromDate <= day.date() <= toDate: - return override["week_table"] + return override else: if fromDate <= day <= toDate: - return override["week_table"] + return override + return {} + + def get_week_table(self, day): + week_table = getattr(self.context, "week_table", []) + overrides = self.get_week_overrides(day) + if overrides: + week_table = overrides.get("week_table", []) or week_table return week_table def is_before_allowed_period(self, day): @@ -386,41 +394,18 @@ def get_anonymous_booking_url(self, day, slot, slot_min_size=0): @memoize def get_gates(self, booking_date=None): """ - Get's the gates, available and unavailable + Get the gates for booking_date """ if isinstance(booking_date, datetime): # sometimes booking_date is passed as date and sometimes as datetime booking_date = booking_date.date() - gates = self.context.getGates() or [""] - - week_table_overrides = json.loads( - getattr(self.context, "week_table_overrides", "[]") or "[]" - ) - if week_table_overrides: - gates_override = week_table_overrides[0].get("gates", []) - if gates_override: - for override in week_table_overrides: - from_month = int(override.get("from_month", "")) - from_day = int(override.get("from_day", "")) - to_month = int(override.get("to_month", "")) - to_day = int(override.get("to_day", "")) - - if not booking_date: - toYear = datetime.today().year - else: - toYear = booking_date.year - - if from_month > to_month: - # next year - toYear += 1 - fromDate = date(booking_date.year, from_month, from_day) - toDate = date(toYear, to_month, to_day) - if fromDate <= booking_date <= toDate: - gates = gates_override - break - return gates + gates = self.context.getGates() + overrides = self.get_week_overrides(day=booking_date) + if overrides: + gates = overrides.get("gates", []) or gates + return gates or [""] def get_busy_gates_in_slot(self, booking_date, booking_end_date=None): """ @@ -484,7 +469,11 @@ def get_day_intervals(self, day): """Return the time ranges of this day""" weekday = day.weekday() week_table = self.get_week_table(day=day) - day_table = week_table[weekday] + try: + day_table = week_table[weekday] + except IndexError as e: + logger.warning(e) + return {} # Convert date + time (localtime) to datetime (utc) morning_start = hm2DT(day, day_table["morning_start"]) morning_end = hm2DT(day, day_table["morning_end"]) @@ -606,34 +595,16 @@ def get_pauses_in_day_folder(self, booking_date): This method takes all pauses from the week table and convert it on slot :param booking_date: a date as a datetime or a string """ - weekday = booking_date.weekday() - - week_table_overrides = json.loads( - getattr(self.context, "week_table_overrides", "[]") or "[]" - ) - - pause_override = [] - if week_table_overrides: - pause_override = week_table_overrides[0].get("pause_table", []) pause_table = self.context.pause_table or [] + overrides = self.get_week_overrides(day=booking_date) + if overrides: + pause_table = overrides.get("pause_table", []) or pause_table - if pause_override: - for override in week_table_overrides: - from_month = int(override.get("from_month", "")) - from_day = int(override.get("from_day", "")) - to_month = int(override.get("to_month", "")) - to_day = int(override.get("to_day", "")) - toYear = booking_date.year - - if from_month > to_month: - # next year - toYear += 1 + if not pause_table: + return [] - fromDate = date(booking_date.year, from_month, from_day) - toDate = date(toYear, to_month, to_day) + weekday = booking_date.weekday() - if fromDate <= booking_date <= toDate: - pause_table = pause_override today_pauses = [row for row in pause_table if row["day"] == str(weekday)] pauses = [] for pause in today_pauses: @@ -684,7 +655,10 @@ def get_busy_slots_in_period(self, booking_date, period="day"): """ if period == "stormynight": return self.get_busy_slots_in_stormynight(booking_date) - interval = self.get_day_intervals(booking_date)[period] + intervals = self.get_day_intervals(booking_date) + if not intervals: + return [] + interval = intervals[period] if interval.start() == "" and interval.stop() == "": return [] allowed_review_states = ["pending", "confirmed", PAUSE_SLOT] @@ -716,7 +690,7 @@ def get_busy_slots(self, booking_date, period="day"): for slot in slots: if slot.context.portal_type == PAUSE_PORTAL_TYPE: for gate in self.get_gates(booking_date): - slots_by_gate.setdefault(gate["name"], []).append(slot) + slots_by_gate.setdefault(gate, []).append(slot) else: slots_by_gate.setdefault(slot.gate, []).append(slot) return slots_by_gate @@ -733,12 +707,14 @@ def get_free_slots(self, booking_date, period="day"): } """ day_intervals = self.get_day_intervals(booking_date) + if not day_intervals: + return {} if period == "day": intervals = [day_intervals["morning"], day_intervals["afternoon"]] else: intervals = [day_intervals[period]] slots_by_gate = self.get_busy_slots(booking_date, period) - gates = [gate["name"] for gate in self.get_gates(booking_date)] + gates = self.get_gates(booking_date) availability = {} for gate in gates: availability.setdefault(gate, []) @@ -775,8 +751,11 @@ def get_anonymous_slots(self, booking_date, period="day"): {'anonymous_gate': [slot2, slot3], } """ - interval = self.get_day_intervals(booking_date)[period] slots_by_gate = {"anonymous_gate": []} + intervals = self.get_day_intervals(booking_date) + if not intervals: + return slots_by_gate + interval = intervals[period] if not interval or len(interval) == 0: return slots_by_gate start = interval.lower_value diff --git a/src/redturtle/prenotazioni/browser/static/widget/js/WidgetContainer/index.js b/src/redturtle/prenotazioni/browser/static/widget/js/WidgetContainer/index.js index 47eda582..1a12868d 100644 --- a/src/redturtle/prenotazioni/browser/static/widget/js/WidgetContainer/index.js +++ b/src/redturtle/prenotazioni/browser/static/widget/js/WidgetContainer/index.js @@ -18,6 +18,7 @@ class WidgetContainer extends Component { }; const updateWidgetField = value => { + console.log('VALORE AGGIORNATO: ', value); document.getElementById(this.props.fieldId).value = JSON.stringify(value); }; @@ -79,6 +80,8 @@ class WidgetContainer extends Component { afternoon_end: '', }, ], + gates: [], + pause_table: [], }); this.setState({ ...this.state, @@ -124,6 +127,17 @@ class WidgetContainer extends Component { return { token: key.toString(), title: key.toString() }; }), }, + weekDays: { + items: [ + { token: '0', title: 'Monday' }, + { token: '1', title: 'Tuesday' }, + { token: '2', title: 'Wednesday' }, + { token: '3', title: 'Thursday' }, + { token: '4', title: 'Friday' }, + { token: '5', title: 'Saturday' }, + { token: '6', title: 'Sunday' }, + ], + }, }, translations: {}, addRow: this.addRow, diff --git a/src/redturtle/prenotazioni/browser/static/widget/js/WidgetDataContainer/index.js b/src/redturtle/prenotazioni/browser/static/widget/js/WidgetDataContainer/index.js index 718ed42c..44da7f12 100644 --- a/src/redturtle/prenotazioni/browser/static/widget/js/WidgetDataContainer/index.js +++ b/src/redturtle/prenotazioni/browser/static/widget/js/WidgetDataContainer/index.js @@ -3,6 +3,8 @@ import PropTypes from 'prop-types'; import WidgetContext from '../utils/widgetContext'; import IntervalSelectorField from '../fields/IntervalSelectorField'; import DaysTableField from '../fields/DaysTableField'; +import GatesField from '../fields/GatesField'; +import PauseTableField from '../fields/PauseTableField'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPlus, @@ -113,6 +115,8 @@ const WidgetDataContainer = () => {
+ +
diff --git a/src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.js b/src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.js new file mode 100644 index 00000000..cb7d8c77 --- /dev/null +++ b/src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.js @@ -0,0 +1,104 @@ +import React, { useContext, useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import WidgetContext from '../utils/widgetContext'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faPlus, faTrash } from '@fortawesome/free-solid-svg-icons'; + +import './GatesField.less'; + +const LineField = ({ value, row, updateField }) => { + const [data, setData] = useState({ text: '', timeout: 0 }); + + const updateText = targetValue => { + if (data.timeout) { + clearInterval(data.timeout); + } + const timeout = setTimeout(() => { + updateField({ row, id: 'gates', value: targetValue }); + }, 1000); + setData({ text: targetValue, timeout }); + }; + useEffect(() => { + setData({ text: value, timeout: 0 }); + }, [value]); + + return ( + updateText(e.target.value)} + /> + ); +}; + +const GatesField = ({ value, row }) => { + const { gates } = value; + const { updateField, getTranslationFor } = useContext(WidgetContext); + const onUpdateRow = data => { + const newValue = gates.map((rowText, rowIdx) => { + if (rowIdx === data.row) { + return data.value; + } else { + return rowText; + } + }); + updateField({ row, id: 'gates', value: newValue }); + }; + + const onAddRow = e => { + e.preventDefault(); + let newValue = gates.map(text => text); + newValue.push(''); + updateField({ row, id: 'gates', value: newValue }); + }; + const onDeleteRow = deletedRow => { + let newValue = gates.filter((text, idx) => idx !== deletedRow); + updateField({ row, id: 'gates', value: newValue }); + }; + + return ( +
+ {getTranslationFor('gates_label')} + {gates.map((rowValue, idx) => ( +
+
+ +
+
+ +
+
+ ))} + +
+ ); +}; + +LineField.propTypes = { + value: PropTypes.string, + row: PropTypes.number, + updateField: PropTypes.func, +}; +GatesField.propTypes = { + value: PropTypes.object, + row: PropTypes.number, +}; + +export default GatesField; diff --git a/src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.less b/src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.less new file mode 100644 index 00000000..29565f5f --- /dev/null +++ b/src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.less @@ -0,0 +1,24 @@ +.array-rows { + .row { + display: flex; + align-items: center; + margin: 0; + + input[type='text'] { + height: auto; + } + + +.row { + margin-top: 1rem; + } + + .column { + margin-right: 1rem; + } + } + + button.context { + margin-top: 1rem; + font-size: 1.25rem; + } +} diff --git a/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.js b/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.js new file mode 100644 index 00000000..8d2c2843 --- /dev/null +++ b/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.js @@ -0,0 +1,137 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; +import WidgetContext from '../utils/widgetContext'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faPlus, faTrash } from '@fortawesome/free-solid-svg-icons'; +import SelectField from './SelectField'; + +import './PauseTableField.less'; + +const PauseRow = ({ value, row, updateField, onDeleteRow }) => { + const { getTranslationFor } = useContext(WidgetContext); + + const onUpdateSelect = ({ id, value: selectValue }) => { + let newValue = { ...value }; + newValue[id] = selectValue; + updateField({ row, value: newValue }); + }; + console.log(value); + return ( + + + + + + + + + + + + + + + ); +}; + +const PauseTableField = ({ value, row }) => { + const { pause_table } = value; + const { updateField, getTranslationFor } = useContext(WidgetContext); + + const onUpdateRow = data => { + const newValue = pause_table.map((rowValue, rowIdx) => + rowIdx === data.row ? data.value : rowValue, + ); + updateField({ row, id: 'pause_table', value: newValue }); + }; + + const onAddRow = e => { + e.preventDefault(); + let newValue = pause_table.map(value => value); + newValue.push({ day: null, pause_start: null, pause_end: null }); + updateField({ row, id: 'pause_table', value: newValue }); + }; + const onDeleteRow = deletedRow => { + let newValue = pause_table.filter((value, idx) => idx !== deletedRow); + updateField({ row, id: 'pause_table', value: newValue }); + }; + + return ( +
+ {getTranslationFor('pause_table_label')} + + + + + + + + + + + + {pause_table.map((rowValue, idx) => ( + + ))} + +
+ {getTranslationFor('day_label')} + + {getTranslationFor('pause_start_label')} + + {getTranslationFor('pause_end_label')} +
+ + +
+ ); +}; + +PauseRow.propTypes = { + value: PropTypes.object, + row: PropTypes.number, + updateField: PropTypes.func, + onDeleteRow: PropTypes.func, +}; +PauseTableField.propTypes = { + value: PropTypes.object, + row: PropTypes.number, +}; + +export default PauseTableField; diff --git a/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.less b/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.less new file mode 100644 index 00000000..e69de29b diff --git a/src/redturtle/prenotazioni/browser/static/widget/js/fields/SelectField.js b/src/redturtle/prenotazioni/browser/static/widget/js/fields/SelectField.js index dace0fef..ae1006cc 100644 --- a/src/redturtle/prenotazioni/browser/static/widget/js/fields/SelectField.js +++ b/src/redturtle/prenotazioni/browser/static/widget/js/fields/SelectField.js @@ -6,21 +6,26 @@ import WidgetContext from '../utils/widgetContext'; // import './index.less'; const SelectField = ({ value, id, row, vocId, multi, customUpdateField }) => { - const { vocabularies, updateField } = useContext(WidgetContext); + const { vocabularies, updateField, getTranslationFor } = useContext( + WidgetContext, + ); const vocab = vocabularies[vocId]; if (!vocab) { return ''; } const options = vocab.items.map(item => { - return { value: item.token, label: item.title }; + return { value: item.token, label: getTranslationFor(item.title) }; }); - const selectValue = options.filter(option => { + let selectValue = options.filter(option => { if (Array.isArray(value)) { return value.includes(option.value); } else { return value === option.value; } }); + if (!multi) { + selectValue = selectValue[0] || null; + } return ( { let newValue = null; if (Array.isArray(value)) { @@ -53,6 +64,8 @@ SelectField.propTypes = { multi: PropTypes.bool, row: PropTypes.number, customUpdateField: PropTypes.func, + key: PropTypes.any, + placeholder: PropTypes.string, }; export default SelectField; From ec747506044b6d9978380f46bfa86a91657d3662 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 23 Aug 2023 14:26:28 +0200 Subject: [PATCH 15/17] fix label --- .../browser/static/widget/js/fields/PauseTableField.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.js b/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.js index e9b026c6..ae8c5c1c 100644 --- a/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.js +++ b/src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.js @@ -88,14 +88,13 @@ const PauseTableField = ({ value, row }) => { const onDeleteRow = deletedRow => { let newValue = pause_table.filter((value, idx) => idx !== deletedRow); - console.log(newValue); updateField({ row, id: 'pause_table', value: newValue }); }; return (
- {getTranslationFor('pause_table_label')} + {getTranslationFor('Pause table')}
{pause_table.length > 0 && ( From 28407f64ac918eaab911cedc3d1a432c67fcfe68 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 23 Aug 2023 14:27:06 +0200 Subject: [PATCH 16/17] build widget --- .../browser/static/widget/dist/prod/main.css | 6 ++++-- .../browser/static/widget/dist/prod/main.css.map | 2 +- .../browser/static/widget/dist/prod/main.js | 10 +++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.css b/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.css index bddffa0a..cdcd35d2 100644 --- a/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.css +++ b/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.css @@ -1,5 +1,7 @@ -.period-selector-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex}.period-selector-wrapper .block{-webkit-box-flex:1;-ms-flex:1 0 calc(25% - 1rem);flex-grow:1;flex-shrink:0;flex-basis:calc(25% - 1rem)} - +.period-selector-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;gap:2rem;padding-bottom:1rem}.period-selector-wrapper .period{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:1rem}.period-selector-wrapper .period .label{-webkit-box-flex:0;-ms-flex:0 0 0px;flex:0 0}.period-selector-wrapper .block{-webkit-box-flex:1;-ms-flex:1 0 calc(25% - 1rem);flex-grow:1;flex-shrink:0;flex-basis:calc(25% - 1rem)} +.days-table-wrapper table td,.days-table-wrapper table th{padding:.5rem;vertical-align:middle}.days-table-wrapper table th{background-color:#ececec} +.gates-rows{margin:3rem 0}.gates-rows .row{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:1rem 0 0}.gates-rows .row input[type=text]{height:auto}.gates-rows .row+.row{margin-top:1rem}.gates-rows .row .column{margin-right:1rem}.gates-rows button.context{margin-top:1rem;font-size:1.25rem} +.pause-table-wrapper{margin-top:1rem}.pause-table-wrapper table td,.pause-table-wrapper table th{padding:.5rem;vertical-align:middle}.pause-table-wrapper table th{background-color:#ececec}.pause-table-wrapper table td.actions{width:50px}.pause-table-wrapper button.context{margin-top:1rem} #formfield-form-widgets-week_table_overrides .data-wrapper .json-row,.week-table-overrides-widget .data-wrapper .json-row{margin:10px;background-color:#fff;border:1px solid #ccc}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row button,.week-table-overrides-widget .data-wrapper .json-row button{font-size:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row button+strong,.week-table-overrides-widget .data-wrapper .json-row button+strong{margin-left:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header,.week-table-overrides-widget .data-wrapper .json-row .row-header{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#f3f3f3}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header strong,.week-table-overrides-widget .data-wrapper .json-row .row-header strong{margin-right:auto}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header .actions button,.week-table-overrides-widget .data-wrapper .json-row .row-header .actions button{margin-left:.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-content,.week-table-overrides-widget .data-wrapper .json-row .row-content{padding:0 1rem 1rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-content .column.block,.week-table-overrides-widget .data-wrapper .json-row .row-content .column.block{padding-top:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .data-footer,.week-table-overrides-widget .data-wrapper .data-footer{padding:10px}#formfield-form-widgets-week_table_overrides .data-wrapper .data-footer button.context,.week-table-overrides-widget .data-wrapper .data-footer button.context{font-size:1.5rem} /*# sourceMappingURL=main.css.map*/ \ No newline at end of file diff --git a/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.css.map b/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.css.map index bf138cb0..91713524 100644 --- a/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.css.map +++ b/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.css.map @@ -1 +1 @@ -{"version":3,"file":"main.css","sources":["webpack:///./src/redturtle/prenotazioni/browser/static/widget/js/fields/IntervalSelectorField.less","webpack:///./src/redturtle/prenotazioni/browser/static/widget/js/WidgetDataContainer/index.less"],"sourcesContent":[".period-selector-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex}.period-selector-wrapper .block{-webkit-box-flex:1;-ms-flex:1 0 calc(25% - 1rem);flex-grow:1;flex-shrink:0;flex-basis:calc(25% - 1rem)}","#formfield-form-widgets-week_table_overrides .data-wrapper .json-row,.week-table-overrides-widget .data-wrapper .json-row{margin:10px;background-color:#fff;border:1px solid #ccc}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row button,.week-table-overrides-widget .data-wrapper .json-row button{font-size:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row button+strong,.week-table-overrides-widget .data-wrapper .json-row button+strong{margin-left:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header,.week-table-overrides-widget .data-wrapper .json-row .row-header{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#f3f3f3}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header strong,.week-table-overrides-widget .data-wrapper .json-row .row-header strong{margin-right:auto}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header .actions button,.week-table-overrides-widget .data-wrapper .json-row .row-header .actions button{margin-left:.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-content,.week-table-overrides-widget .data-wrapper .json-row .row-content{padding:0 1rem 1rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-content .column.block,.week-table-overrides-widget .data-wrapper .json-row .row-content .column.block{padding-top:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .data-footer,.week-table-overrides-widget .data-wrapper .data-footer{padding:10px}#formfield-form-widgets-week_table_overrides .data-wrapper .data-footer button.context,.week-table-overrides-widget .data-wrapper .data-footer button.context{font-size:1.5rem}"],"mappings":"AAAA;;ACAA;","sourceRoot":""} \ No newline at end of file +{"version":3,"file":"main.css","sources":["webpack:///./src/redturtle/prenotazioni/browser/static/widget/js/fields/IntervalSelectorField.less","webpack:///./src/redturtle/prenotazioni/browser/static/widget/js/fields/DaysTableField.less","webpack:///./src/redturtle/prenotazioni/browser/static/widget/js/fields/GatesField.less","webpack:///./src/redturtle/prenotazioni/browser/static/widget/js/fields/PauseTableField.less","webpack:///./src/redturtle/prenotazioni/browser/static/widget/js/WidgetDataContainer/index.less"],"sourcesContent":[".period-selector-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;gap:2rem;padding-bottom:1rem}.period-selector-wrapper .period{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:1rem}.period-selector-wrapper .period .label{-webkit-box-flex:0;-ms-flex:0 0 0px;flex:0 0}.period-selector-wrapper .block{-webkit-box-flex:1;-ms-flex:1 0 calc(25% - 1rem);flex-grow:1;flex-shrink:0;flex-basis:calc(25% - 1rem)}",".days-table-wrapper table td,.days-table-wrapper table th{padding:.5rem;vertical-align:middle}.days-table-wrapper table th{background-color:#ececec}",".gates-rows{margin:3rem 0}.gates-rows .row{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:1rem 0 0}.gates-rows .row input[type=text]{height:auto}.gates-rows .row+.row{margin-top:1rem}.gates-rows .row .column{margin-right:1rem}.gates-rows button.context{margin-top:1rem;font-size:1.25rem}",".pause-table-wrapper{margin-top:1rem}.pause-table-wrapper table td,.pause-table-wrapper table th{padding:.5rem;vertical-align:middle}.pause-table-wrapper table th{background-color:#ececec}.pause-table-wrapper table td.actions{width:50px}.pause-table-wrapper button.context{margin-top:1rem}","#formfield-form-widgets-week_table_overrides .data-wrapper .json-row,.week-table-overrides-widget .data-wrapper .json-row{margin:10px;background-color:#fff;border:1px solid #ccc}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row button,.week-table-overrides-widget .data-wrapper .json-row button{font-size:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row button+strong,.week-table-overrides-widget .data-wrapper .json-row button+strong{margin-left:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header,.week-table-overrides-widget .data-wrapper .json-row .row-header{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#f3f3f3}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header strong,.week-table-overrides-widget .data-wrapper .json-row .row-header strong{margin-right:auto}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-header .actions button,.week-table-overrides-widget .data-wrapper .json-row .row-header .actions button{margin-left:.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-content,.week-table-overrides-widget .data-wrapper .json-row .row-content{padding:0 1rem 1rem}#formfield-form-widgets-week_table_overrides .data-wrapper .json-row .row-content .column.block,.week-table-overrides-widget .data-wrapper .json-row .row-content .column.block{padding-top:1.5rem}#formfield-form-widgets-week_table_overrides .data-wrapper .data-footer,.week-table-overrides-widget .data-wrapper .data-footer{padding:10px}#formfield-form-widgets-week_table_overrides .data-wrapper .data-footer button.context,.week-table-overrides-widget .data-wrapper .data-footer button.context{font-size:1.5rem}"],"mappings":"AAAA;ACAA;ACAA;ACAA;ACAA;","sourceRoot":""} \ No newline at end of file diff --git a/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.js b/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.js index 2fdb318f..93e17681 100644 --- a/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.js +++ b/src/redturtle/prenotazioni/browser/static/widget/dist/prod/main.js @@ -1,9 +1,9 @@ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=69)}([function(e,t,n){"use strict";e.exports=n(22)},function(e,t,n){e.exports=n(44)()},function(e,t,n){"use strict";var r=n(12),a=Object.prototype.toString;function o(e){return"[object Array]"===a.call(e)}function i(e){return void 0===e}function l(e){return null!==e&&"object"==typeof e}function u(e){if("[object Object]"!==a.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function s(e){return"[object Function]"===a.call(e)}function c(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),o(e))for(var n=0,r=e.length;n=200&&e<300}};s.headers={common:{Accept:"application/json, text/plain, */*"}},r.forEach(["delete","get","head"],(function(e){s.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){s.headers[e]=r.merge(i)})),e.exports=s}).call(this,n(55))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;t=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}(this.props,[]);return function(e){c.forEach((function(t){return delete e[t]}))}(a),a.className=this.props.inputClassName,a.id=this.state.inputId,a.style=n,i.default.createElement("div",{className:this.props.className,style:t},this.renderStyles(),i.default.createElement("input",r({},a,{ref:this.inputRef})),i.default.createElement("div",{ref:this.sizerRef,style:s},e),this.props.placeholder?i.default.createElement("div",{ref:this.placeHolderSizerRef,style:s},this.props.placeholder):null)}}]),t}(o.Component);m.propTypes={className:l.default.string,defaultValue:l.default.any,extraWidth:l.default.oneOfType([l.default.number,l.default.string]),id:l.default.string,injectStyles:l.default.bool,inputClassName:l.default.string,inputRef:l.default.func,inputStyle:l.default.object,minWidth:l.default.oneOfType([l.default.number,l.default.string]),onAutosize:l.default.func,onChange:l.default.func,placeholder:l.default.string,placeholderIsMinWidth:l.default.bool,style:l.default.object,value:l.default.any},m.defaultProps={minWidth:1,injectStyles:!0},t.default=m},function(e,t,n){"use strict"; +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=71)}([function(e,t,n){"use strict";e.exports=n(22)},function(e,t,n){e.exports=n(44)()},function(e,t,n){"use strict";var r=n(12),a=Object.prototype.toString;function o(e){return"[object Array]"===a.call(e)}function i(e){return void 0===e}function l(e){return null!==e&&"object"==typeof e}function u(e){if("[object Object]"!==a.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function s(e){return"[object Function]"===a.call(e)}function c(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),o(e))for(var n=0,r=e.length;n=200&&e<300}};s.headers={common:{Accept:"application/json, text/plain, */*"}},r.forEach(["delete","get","head"],(function(e){s.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){s.headers[e]=r.merge(i)})),e.exports=s}).call(this,n(57))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;t=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}(this.props,[]);return function(e){c.forEach((function(t){return delete e[t]}))}(a),a.className=this.props.inputClassName,a.id=this.state.inputId,a.style=n,i.default.createElement("div",{className:this.props.className,style:t},this.renderStyles(),i.default.createElement("input",r({},a,{ref:this.inputRef})),i.default.createElement("div",{ref:this.sizerRef,style:s},e),this.props.placeholder?i.default.createElement("div",{ref:this.placeHolderSizerRef,style:s},this.props.placeholder):null)}}]),t}(o.Component);m.propTypes={className:l.default.string,defaultValue:l.default.any,extraWidth:l.default.oneOfType([l.default.number,l.default.string]),id:l.default.string,injectStyles:l.default.bool,inputClassName:l.default.string,inputRef:l.default.func,inputStyle:l.default.object,minWidth:l.default.oneOfType([l.default.number,l.default.string]),onAutosize:l.default.func,onChange:l.default.func,placeholder:l.default.string,placeholderIsMinWidth:l.default.bool,style:l.default.object,value:l.default.any},m.defaultProps={minWidth:1,injectStyles:!0},t.default=m},function(e,t,n){"use strict"; /* object-assign (c) Sindre Sorhus @license MIT -*/var r=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable;function i(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,l,u=i(e),s=1;se.length)&&(t=e.length);for(var n=0,r=new Array(t);n{const r=t<0?e.length+t:t;if(r>=0&&r(e=[...e],r(e,t,n),e),e.exports.mutate=r},function(e,t,n){"use strict"; +*/var r=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable;function i(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,l,u=i(e),s=1;se.length)&&(t=e.length);for(var n=0,r=new Array(t);n{const r=t<0?e.length+t:t;if(r>=0&&r(e=[...e],r(e,t,n),e),e.exports.mutate=r},function(e,t,n){"use strict"; /** @license React v16.14.0 * react.production.min.js * @@ -11,7 +11,7 @@ object-assign * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var r=n(8),a="function"==typeof Symbol&&Symbol.for,o=a?Symbol.for("react.element"):60103,i=a?Symbol.for("react.portal"):60106,l=a?Symbol.for("react.fragment"):60107,u=a?Symbol.for("react.strict_mode"):60108,s=a?Symbol.for("react.profiler"):60114,c=a?Symbol.for("react.provider"):60109,f=a?Symbol.for("react.context"):60110,p=a?Symbol.for("react.forward_ref"):60112,d=a?Symbol.for("react.suspense"):60113,m=a?Symbol.for("react.memo"):60115,h=a?Symbol.for("react.lazy"):60116,v="function"==typeof Symbol&&Symbol.iterator;function b(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;nj.length&&j.push(e)}function M(e,t,n){return null==e?0:function e(t,n,r,a){var l=typeof t;"undefined"!==l&&"boolean"!==l||(t=null);var u=!1;if(null===t)u=!0;else switch(l){case"string":case"number":u=!0;break;case"object":switch(t.$$typeof){case o:case i:u=!0}}if(u)return r(a,t,""===n?"."+R(t,0):n),1;if(u=0,n=""===n?".":n+":",Array.isArray(t))for(var s=0;sj.length&&j.push(e)}function M(e,t,n){return null==e?0:function e(t,n,r,a){var l=typeof t;"undefined"!==l&&"boolean"!==l||(t=null);var u=!1;if(null===t)u=!0;else switch(l){case"string":case"number":u=!0;break;case"object":switch(t.$$typeof){case o:case i:u=!0}}if(u)return r(a,t,""===n?"."+R(t,0):n),1;if(u=0,n=""===n?".":n+":",Array.isArray(t))for(var s=0;s