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

booking info #41

Merged
merged 7 commits into from
Aug 6, 2024
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
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
Loading