Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bookings limit #96

Merged
merged 9 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Changelog
[mamico]

- Remove Contributor from the package permissions map
- Add configurable simultaneous bookings limit for the same user.
[folix-01]


Expand Down
74 changes: 60 additions & 14 deletions src/redturtle/prenotazioni/adapters/booker.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from datetime import timedelta
from random import choice

from DateTime import DateTime
from plone import api
from plone.memoize.instance import memoize
from six.moves.urllib.parse import parse_qs, urlparse
Expand All @@ -15,14 +16,11 @@
from redturtle.prenotazioni.adapters.slot import BaseSlot
from redturtle.prenotazioni.config import VERIFIED_BOOKING
from redturtle.prenotazioni.content.prenotazione import VACATION_TYPE
from redturtle.prenotazioni.exceptions import BookerException, BookingsLimitExceded
from redturtle.prenotazioni.prenotazione_event import MovedPrenotazione
from redturtle.prenotazioni.utilities.dateutils import exceedes_date_limit


class BookerException(Exception):
pass


class IBooker(Interface):
"""Interface for a booker"""

Expand All @@ -43,6 +41,44 @@ def prenotazioni(self):
"""The prenotazioni context state view"""
return self.context.unrestrictedTraverse("@@prenotazioni_context_state") # noqa

def _validate_user_limit(self, fiscalcode):
"""Control if user did not exceed the limit yet

Args:
fiscalcode (str): User's fiscal code

Returns:
None

Raises:
BookingsLimitExceded: User exceeded limit
"""

if not self.context.max_bookings_allowed:
return

if len(self.get_future_bookings_by_fiscalcode(fiscalcode)) >= (
self.context.max_bookings_allowed
):
raise BookingsLimitExceded

def get_future_bookings_by_fiscalcode(self, fiscalcode):
"""Find all the future bookings registered for the same fiscalcode"""
result = []

for booking in api.content.find(
mamico marked this conversation as resolved.
Show resolved Hide resolved
portal_type="Prenotazione",
fiscalcode=fiscalcode,
path={"query": "/".join(self.context.getPhysicalPath())},
Date={"query": DateTime(), "range": "min"},
review_state={
"query": ("confirmed", "pending", "private"),
},
):
result.append(booking.getObject())

return result

def get_available_gate(self, booking_date, booking_expiration_date=None):
"""
Find which gate is free to serve this booking
Expand Down Expand Up @@ -99,28 +135,35 @@ def _create(self, data, duration=-1, force_gate=""):
gate = available_gate
else:
gate = force_gate

fiscalcode = data.get("fiscalcode", "").upper()
user = api.user.get_current()

if not fiscalcode:
fiscalcode = (
user.getProperty("fiscalcode", "") or user.getId() or ""
).upper() # noqa

mamico marked this conversation as resolved.
Show resolved Hide resolved
if fiscalcode:
params["fiscalcode"] = fiscalcode
self._validate_user_limit(fiscalcode)

obj = api.content.create(
type="Prenotazione",
container=container,
booking_expiration_date=booking_expiration_date,
gate=gate,
**params
**params,
)

annotations = IAnnotations(obj)

annotations[VERIFIED_BOOKING] = False

if not api.user.is_anonymous() and not api.user.has_permission(
"Modify portal content", obj=container
):
user = api.user.get_current()
data_fiscalcode = getattr(obj, "fiscalcode", "") or ""
fiscalcode = data_fiscalcode.upper()
if not fiscalcode:
obj.fiscalcode = (
user.getProperty("fiscalcode", "") or user.getId() or ""
).upper() # noqa
elif user.hasProperty("fiscalcode") and fiscalcode:
if user.hasProperty("fiscalcode") and fiscalcode:
if (user.getProperty("fiscalcode") or "").upper() == fiscalcode:
logger.info("Booking verified: {}".format(obj.absolute_url()))
annotations[VERIFIED_BOOKING] = True
Expand Down Expand Up @@ -190,7 +233,10 @@ def move(self, booking, data):
data["booking_type"] = booking.getBooking_type()
conflict_manager = self.prenotazioni.conflict_manager
current_data = booking.getBooking_date()
current = {"booking_date": current_data, "booking_type": data["booking_type"]}
current = {
"booking_date": current_data,
"booking_type": data["booking_type"],
}
current_slot = conflict_manager.get_choosen_slot(current)
current_gate = getattr(booking, "gate", "")
exclude = {current_gate: [current_slot]}
Expand Down
12 changes: 12 additions & 0 deletions src/redturtle/prenotazioni/content/prenotazioni_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,18 @@ def data_validation(data):
required=False,
)

max_bookings_allowed = schema.Int(
title=_(
"max_bookings_allowed_label",
default="Maximum bookings number allowed",
),
description=_(
"max_bookings_allowed_description",
default="Number of simultaneous bookins allowed for the same user.",
),
required=False,
)

model.fieldset(
"dates",
label=_("Date validità"),
Expand Down
2 changes: 2 additions & 0 deletions src/redturtle/prenotazioni/exceptions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from .booker import BookerException, BookingsLimitExceded # noqa
9 changes: 9 additions & 0 deletions src/redturtle/prenotazioni/exceptions/booker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
class BookerException(Exception):
pass


class BookingsLimitExceded(BookerException):
def __init__(self, *args, **kwargs):
if "message" not in kwargs.keys():
kwargs["message"] = "Booking limit is exceed for the current user"
Loading