Skip to content

Commit

Permalink
booking info (#41)
Browse files Browse the repository at this point in the history
* booking info

* lint

* notify_on_confirm

* changelog

* more info on add service

* lint

* booking.id
  • Loading branch information
mamico authored Aug 6, 2024
1 parent b4dc3b8 commit c8bbfe2
Show file tree
Hide file tree
Showing 10 changed files with 373 additions and 2 deletions.
5 changes: 4 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ Changelog
1.2.6 (unreleased)
------------------

- Nothing changed yet.
- Added more information in the `/@booking/<bookingid>` service (e.g. booking_folder, booking_address, booking_office),
already present in the `/@bookings?fullobjects=1` service. https://github.com/RedTurtle/design.plone.ioprenoto/pull/41
These changes will be moved in the future from here to redturtle.reservations 2.3.x
[mamico]


1.2.5 (2024-04-22)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"z3c.jbot",
"plone.api>=1.8.4",
"plone.app.dexterity",
"redturtle.prenotazioni>=2.2.0",
"redturtle.prenotazioni>=2.2.0.dev0",
"design.plone.policy",
"plone.restapi>= 9.6.0",
],
Expand Down
Empty file.
34 changes: 34 additions & 0 deletions src/design/plone/ioprenoto/restapi/services/booking/add.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# TODO: il codice qui è temporaneo, va spostato in redturtle.prenotazioni
# di conseguenza l'implementazione si semplifica

from plone import api
from redturtle.prenotazioni.interfaces import ISerializeToPrenotazioneSearchableItem
from redturtle.prenotazioni.restapi.services.booking.add import (
AddBooking as BaseAddBooking,
)
from zope.component import getMultiAdapter


class AddBooking(BaseAddBooking):
def reply(self):
result = super().reply()
catalog = api.portal.get_tool("portal_catalog")
uid = result["UID"]
booking = catalog.unrestrictedSearchResults(UID=uid)[0]._unrestrictedGetObject()

response = getMultiAdapter(
(booking, self.request), ISerializeToPrenotazioneSearchableItem
)(fullobjects=True)

# BBB:
response["@type"] = booking.portal_type
response["id"] = booking.getId() # response["@id"].split("/")[-1]
response["UID"] = response["booking_id"]
response["gate"] = response["booking_gate"]
response["booking_folder_uid"] = (
response["booking_folder"]["uid"] if "booking_folder" in response else None
)
if "notify_on_confirm" not in response:
prenotazioni_folder = booking.getPrenotazioniFolder()
response["notify_on_confirm"] = prenotazioni_folder.notify_on_confirm
return response
24 changes: 24 additions & 0 deletions src/design/plone/ioprenoto/restapi/services/booking/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:plone="http://namespaces.plone.org/plone"
>

<plone:service
method="GET"
factory=".get.BookingInfo"
for="*"
permission="zope2.View"
layer="design.plone.ioprenoto.interfaces.IDesignPloneIoprenotoLayer"
name="@booking"
/>

<plone:service
method="POST"
factory=".add.AddBooking"
for="redturtle.prenotazioni.content.prenotazioni_folder.IPrenotazioniFolder"
permission="zope2.View"
layer="design.plone.ioprenoto.interfaces.IDesignPloneIoprenotoLayer"
name="@booking"
/>

</configure>
64 changes: 64 additions & 0 deletions src/design/plone/ioprenoto/restapi/services/booking/get.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# TODO: il codice qui è temporaneo, va spostato in redturtle.prenotazioni

from AccessControl import Unauthorized
from plone import api
from redturtle.prenotazioni.interfaces import ISerializeToPrenotazioneSearchableItem
from redturtle.prenotazioni.restapi.services.booking.get import BookingInfo as Base
from zope.component import getMultiAdapter


class BookingInfo(Base):
def reply(self):
if not self.booking_uid:
return self.reply_no_content(status=404)
catalog = api.portal.get_tool("portal_catalog")
query = {"portal_type": "Prenotazione", "UID": self.booking_uid}
booking = catalog.unrestrictedSearchResults(query)

if not booking:
return self.reply_no_content(status=404)

booking = booking[0]._unrestrictedGetObject()
if not booking.canAccessBooking():
raise Unauthorized

# (Pdb) pp getMultiAdapter((booking, self.request), ISerializeToPrenotazioneSearchableItem)(fullobjects=True).keys()
# dict_keys(['@id', 'title', 'description', 'booking_id', 'booking_code', 'booking_url', 'booking_date',
# 'booking_expiration_date', 'booking_type', 'booking_gate', 'booking_status', 'booking_status_label',
# 'booking_status_date', 'booking_status_notes', 'email', 'fiscalcode',
# 'phone', 'staff_notes', 'company', 'vacation', 'modification_date', 'creation_date', 'booking_folder', 'booking_address',
# 'booking_office', 'requirements', 'cosa_serve'])

# (Pdb) pp getMultiAdapter((booking, self.request), ISerializeToJson)().keys()
# dict_keys(['@id', 'UID', '@type', 'title', 'description', 'gate', 'id', 'phone', 'email', 'fiscalcode', 'company',
# 'staff_notes', 'booking_date', 'booking_expiration_date', 'booking_status', 'booking_status_label',
# 'booking_type', 'booking_folder_uid', 'vacation', 'booking_code', 'notify_on_confirm', 'cosa_serve', 'requirements',
# 'modification_date', 'creation_date'])

# nel cambio si perdono gli attributi:
# UID (diventa booking_id),
# @type (sempre 'Prenotazione'),
# gate (diventa booking_gate),
# id (ultimo pezzo dell'URL),
# staff_notes (usato?)
# booking_folder_uid (['booking_folder']['uid'])
# notify_on_confirm (usato?)

# response = getMultiAdapter((booking, self.request), ISerializeToJson)()
response = getMultiAdapter(
(booking, self.request), ISerializeToPrenotazioneSearchableItem
)(fullobjects=True)

# BBB:
response["@type"] = booking.portal_type
response["id"] = booking.getId() # response["@id"].split("/")[-1]
response["UID"] = response["booking_id"]
response["gate"] = response["booking_gate"]
response["booking_folder_uid"] = (
response["booking_folder"]["uid"] if "booking_folder" in response else None
)
if "notify_on_confirm" not in response:
prenotazioni_folder = booking.getPrenotazioniFolder()
response["notify_on_confirm"] = prenotazioni_folder.notify_on_confirm

return response
1 change: 1 addition & 0 deletions src/design/plone/ioprenoto/restapi/services/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

<include package=".bookable_list" />
<include package=".bookings" />
<include package=".booking" />
<include package=".booking_schema" />


Expand Down
242 changes: 242 additions & 0 deletions src/design/plone/ioprenoto/tests/test_booking_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
from copy import deepcopy
from datetime import date
from datetime import datetime
from datetime import timedelta
from design.plone.ioprenoto.testing import DESIGN_PLONE_IOPRENOTO_API_FUNCTIONAL_TESTING
from plone import api
from plone.app.testing import setRoles
from plone.app.testing import SITE_OWNER_NAME
from plone.app.testing import SITE_OWNER_PASSWORD
from plone.app.testing import TEST_USER_ID
from plone.app.textfield.value import RichTextValue
from plone.restapi.testing import RelativeSession
from transaction import commit
from z3c.relationfield.relation import RelationValue
from zope.component import queryUtility
from zope.intid.interfaces import IIntIds

import unittest


class TestBookingInfo(unittest.TestCase):
layer = DESIGN_PLONE_IOPRENOTO_API_FUNCTIONAL_TESTING
maxDiff = None

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()
self.today = datetime.now()

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)

setRoles(self.portal, TEST_USER_ID, ["Manager"])

self.venue = api.content.create(
container=self.portal,
title="Example venue",
type="Venue",
city="Ferrara",
country="380",
street="Foo Street 22",
)
self.unita_organizzativa = api.content.create(
container=self.portal,
type="UnitaOrganizzativa",
title="UO",
sede=[RelationValue(to_id=queryUtility(IIntIds).getId(self.venue))],
)
self.unita_organizzativa2 = api.content.create(
container=self.portal,
type="UnitaOrganizzativa",
title="UO 2",
)
self.unita_organizzativa3 = api.content.create(
container=self.portal,
type="UnitaOrganizzativa",
title="UO 3",
)

self.prenotazioni_folder = api.content.create(
container=self.portal,
type="PrenotazioniFolder",
title="Prenotazioni Folder",
orario_di_apertura="foo",
descriptionAgenda=RichTextValue(
"<h1>description agenda</h1>",
"text/html",
"text/html",
),
gates=["Gate A"],
uffici_correlati=[
RelationValue(
to_id=queryUtility(IIntIds).getId(self.unita_organizzativa)
)
],
)
week_table = deepcopy(self.prenotazioni_folder.week_table)
for day in week_table:
day["morning_start"] = "0700"
day["morning_end"] = "1300"
self.prenotazioni_folder.week_table = week_table

api.content.transition(
obj=api.content.create(
type="PrenotazioneType",
title="Type A",
duration=30,
container=self.prenotazioni_folder,
gates=["all"],
),
transition="publish",
)

# self.prenotazioni_folder2 = api.content.create(
# container=self.portal,
# type="PrenotazioniFolder",
# title="Prenotazioni Folder 2",
# uffici_correlati=[
# RelationValue(
# to_id=queryUtility(IIntIds).getId(self.unita_organizzativa)
# )
# ],
# )
# api.content.transition(
# obj=api.content.create(
# type="PrenotazioneType",
# title="Type A",
# duration=10,
# container=self.prenotazioni_folder2,
# gates=["all"],
# ),
# transition="publish",
# )
# api.content.transition(
# obj=api.content.create(
# type="PrenotazioneType",
# title="Type B",
# duration=30,
# container=self.prenotazioni_folder2,
# gates=["all"],
# ),
# transition="publish",
# )
# self.prenotazioni_folder3 = api.content.create(
# container=self.portal,
# type="PrenotazioniFolder",
# title="Prenotazioni Folder 3",
# uffici_correlati=[
# RelationValue(
# to_id=queryUtility(IIntIds).getId(self.unita_organizzativa2)
# )
# ],
# )

# self.prenotazioni_folder4 = api.content.create(
# container=self.portal,
# type="PrenotazioniFolder",
# title="Prenotazioni Folder 4",
# )

# self.servizio = api.content.create(
# container=self.portal,
# type="Servizio",
# title="Servizio",
# canale_fisico=[
# RelationValue(
# to_id=queryUtility(IIntIds).getId(self.unita_organizzativa)
# )
# ],
# )

# booker = IBooker(self.prenotazioni_folder)
# self.prenotazione1 = booker.book(
# {
# "booking_date": self.today.replace(hour=8, minute=0),
# "booking_type": "Type A",
# "title": "foo",
# "other_fields": {
# "booking_office": self.unita_organizzativa.absolute_url(),
# "booking_address": self.venue.absolute_url(),
# },
# }
# )
commit()

def test_get_bookings(self):
booking_date = "{}T10:00:00+00:00".format(
(date.today() + timedelta(3)).strftime("%Y-%m-%d")
)
res = self.api_session.post(
self.prenotazioni_folder.absolute_url() + "/@booking",
json={
"booking_date": booking_date,
"booking_type": "Type A",
"other_fields": {
"booking_office": self.unita_organizzativa.absolute_url(),
"booking_address": self.venue.absolute_url(),
},
"fields": [
{"name": "title", "value": "Mario Rossi"},
{"name": "email", "value": "mario.rossi@example"},
{"name": "description", "value": "foo"},
],
},
)
self.assertEqual(res.status_code, 200)
booking = res.json()
self.assertIn("@id", booking)
self.assertEqual(booking["id"], "mario-rossi")
self.assertEqual(
booking["booking_folder"]["@id"],
self.prenotazioni_folder.absolute_url(),
)
self.assertEqual(booking["booking_address"]["@id"], self.venue.absolute_url())
self.assertEqual(
booking["booking_office"]["@id"],
self.unita_organizzativa.absolute_url(),
)

res = self.api_session.get(
self.portal.absolute_url() + "/@bookings?fullobjects=1"
)
self.assertEqual(res.status_code, 200)
self.assertEqual(len(res.json()["items"]), 1)
booking_info = res.json()["items"][0]
self.assertIn("@id", booking_info)
self.assertEqual(
booking_info["booking_folder"]["@id"],
self.prenotazioni_folder.absolute_url(),
)
self.assertEqual(
booking_info["booking_address"]["@id"], self.venue.absolute_url()
)
self.assertEqual(
booking_info["booking_office"]["@id"],
self.unita_organizzativa.absolute_url(),
)

# TODO: andrebbe messo lo UID anche su booking_id visto che è l'attributo conosciuto come identificativo
res = self.api_session.get(
self.portal.absolute_url() + f"/@booking/{booking['UID']}"
)
booking_info = res.json()
# self.assertEqual(booking_info["@type"], "Prenotazione")
self.assertEqual(
booking_info["booking_folder"]["@id"],
self.prenotazioni_folder.absolute_url(),
)
self.assertEqual(
booking_info["booking_address"]["@id"], self.venue.absolute_url()
)
self.assertEqual(
booking_info["booking_office"]["@id"],
self.unita_organizzativa.absolute_url(),
)
self.assertEqual(
booking_info["notify_on_confirm"],
False,
)
Loading

0 comments on commit c8bbfe2

Please sign in to comment.