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 export view #210

Merged
merged 8 commits into from
Jun 24, 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
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Changelog
2.7.4 (unreleased)
------------------

- Nothing changed yet.
- @@bookings-export view.
[folix-01]


2.7.3 (2024-06-14)
Expand Down
12 changes: 11 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ Response::

If a user is authenticated and, he is not a site operator, returns all own bookings.

With an experimental envionment `SEE_OWN_ANONYMOUS_BOOKINGS` set to `True`, the endpoint will return
With an experimental envionment `SEE_OWN_ANONYMOUS_BOOKINGS` set to `True`, the endpoint will return
also the bookings created by anonymous users with the same fiscalcode of the authenticated user.

@booking-notify
Expand Down Expand Up @@ -734,6 +734,16 @@ have the Reminder Notification Gap field populated. If you intend to set up a cr
The script is located at src/redturtle/prenotazioni/scripts/notify_upcoming_bookings.py.


@@bookings-export
-----------------

Export bookings by passed **date** in ISO format or today by default.

Example::
curl -i http://localhost:8080/Plone/@@bookings-export?date=2024-06-21

Response::
Binary csv file

Scripts
=======
Expand Down
159 changes: 159 additions & 0 deletions src/redturtle/prenotazioni/browser/bookings_export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
import csv
import datetime

from plone import api
from Products.Five import BrowserView
from six import StringIO
from zExceptions import BadRequest

from redturtle.prenotazioni import _
from redturtle.prenotazioni.restapi.serializers.adapters.prenotazione import (
get_booking_wf_state_title,
)
from redturtle.prenotazioni.utilities.dateutils import get_default_timezone


class BookingsExport(BrowserView):
filename = "Bookings_export"
date = None

@property
def csv_fields(self):
return [
api.portal.translate(_("csv_export_uid", default="UID")),
api.portal.translate(_("csv_export_code", default="CODE")),
api.portal.translate(_("csv_export_type", default="TYPE")),
api.portal.translate(_("csv_export_phone", default="PHONE")),
api.portal.translate(_("csv_export_email", default="EMAIL")),
api.portal.translate(_("csv_export_name", default="NAME SURNAME")),
api.portal.translate(_("csv_export_fiscalcode", default="FISCALCODE")),
api.portal.translate(_("csv_export_start_time", default="BOOKING START")),
api.portal.translate(
_("csv_export_end_time", default="BOOKING EXPIRATION")
),
api.portal.translate(_("csv_export_state", default="STATE")),
api.portal.translate(_("csv_export_gate", default="GATE")),
api.portal.translate(_("csv_export_notes", default="NOTES")),
api.portal.translate(
_("csv_export_booking_folder", default="BOOKING FOLDER")
),
api.portal.translate(_("csv_export_company", default="COMPANY")),
]

@property
def csv_filename(self):
"""Return a filename for this csv"""

return "%s-%s.csv" % (self.filename, self.date.date().isoformat())

@property
def brains(self):

return api.portal.get_tool("portal_catalog").unrestrictedSearchResults(
portal_type="Prenotazione",
Date={
"query": (
get_default_timezone(True).localize(self.date),
get_default_timezone(True).localize(
self.date.replace(hour=23, minute=59)
),
),
"range": "min:max",
},
review_state="confirmed",
sort_on="Date",
)

def setHeader(self, *args):
"""
Shorcut for setting headers in the request
"""
return self.context.REQUEST.RESPONSE.setHeader(*args)

def brain2row(self, brain):
"""
returns a generator with the booking data
"""
booking = brain.getObject()

return {
api.portal.translate(_("csv_export_uid", default="UID")): booking.UID(),
api.portal.translate(
_("csv_export_code", default="CODE")
): booking.getBookingCode(),
api.portal.translate(
_("csv_export_type", default="TYPE")
): booking.booking_type,
api.portal.translate(_("csv_export_phone", default="PHONE")): booking.phone,
api.portal.translate(_("csv_export_email", default="EMAIL")): booking.email,
api.portal.translate(
_("csv_export_fiscalcode", default="FISCALCODE")
): getattr(booking, "fiscalcode", "").upper(),
api.portal.translate(
_("csv_export_start_time", default="BOOKING START")
): booking.booking_date.strftime("%Y-%m-%d %H:%M"),
api.portal.translate(
_("csv_export_end_time", default="BOOKING EXPIRATION")
): booking.booking_expiration_date.strftime("%Y-%m-%d %H:%M"),
api.portal.translate(
_("csv_export_notes", default="NOTES")
): booking.description,
api.portal.translate(
_("csv_export_state", default="STATE")
): get_booking_wf_state_title(booking),
api.portal.translate(_("csv_export_gate", default="GATE")): booking.gate,
api.portal.translate(
_("csv_export_booking_folder", default="BOOKING FOLDER")
): booking.getPrenotazioniFolder().Title(),
api.portal.translate(
_("csv_export_company", default="COMPANY")
): booking.company,
api.portal.translate(
_("csv_export_name", default="NAME SURNAME")
): booking.title,
}

def get_csv_rows(self):
"""Return the csv rows as a dictionary"""
for brain in self.brains:
yield self.brain2row(brain)

def get_csv(self):
"""Get a csv out of the view brains"""

buffer = StringIO()
csv_writer = csv.DictWriter(buffer, fieldnames=self.csv_fields)

csv_writer.writeheader()

for row in self.get_csv_rows():
csv_writer.writerow(row)

buffer.seek(0)

return buffer.getvalue().encode("utf-8")

def __call__(self):
date = self.request.get("date")

if not date:
self.date = datetime.datetime.combine(
datetime.date.today(), datetime.datetime.min.time()
)
else:
try:
self.date = datetime.datetime.combine(
datetime.date.fromisoformat(date), datetime.datetime.min.time()
)
except ValueError:
raise BadRequest(_("Bad date format passed"))
self.setHeader(
"Content-Disposition", "attachment;filename=%s" % self.csv_filename
)
self.request.response.setHeader(
"Content-Type",
"application/csv",
)

return self.get_csv()
7 changes: 7 additions & 0 deletions src/redturtle/prenotazioni/browser/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@
permission="redturtle.prenotazioni.SearchPrenotazioni"
/>

<browser:page
name="bookings-export"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".bookings_export.BookingsExport"
permission="cmf.ModifyPortalContent"
/>

<!-- define new widget -->
<class class=".widget.WeekTableOverridesWidget">
<require
Expand Down
Loading
Loading