130 lines
4.6 KiB
Python
130 lines
4.6 KiB
Python
from datetime import datetime, timedelta
|
|
|
|
import pytz
|
|
|
|
from odoo import fields, http
|
|
from odoo.http import request
|
|
|
|
|
|
class McsAppointmentController(http.Controller):
|
|
def _type_or_404(self, appointment_type_id):
|
|
appointment_type = (
|
|
request.env["mcs.appointment.type"]
|
|
.sudo()
|
|
.search(
|
|
[
|
|
("id", "=", appointment_type_id),
|
|
("active", "=", True),
|
|
("website_published", "=", True),
|
|
],
|
|
limit=1,
|
|
)
|
|
)
|
|
if not appointment_type:
|
|
return request.not_found()
|
|
return appointment_type
|
|
|
|
def _display_slots(self, appointment_type, day):
|
|
tz = appointment_type._timezone()
|
|
slots = []
|
|
for slot in appointment_type.get_available_slots(day):
|
|
start_utc = pytz.UTC.localize(slot["start"])
|
|
stop_utc = pytz.UTC.localize(slot["stop"])
|
|
slots.append(
|
|
{
|
|
"start": fields.Datetime.to_string(slot["start"]),
|
|
"stop": fields.Datetime.to_string(slot["stop"]),
|
|
"label": "%s - %s"
|
|
% (
|
|
start_utc.astimezone(tz).strftime("%I:%M %p"),
|
|
stop_utc.astimezone(tz).strftime("%I:%M %p"),
|
|
),
|
|
}
|
|
)
|
|
return slots
|
|
|
|
@http.route(["/appointments"], type="http", auth="public", website=True)
|
|
def appointments(self, **kwargs):
|
|
types = request.env["mcs.appointment.type"].sudo().search(
|
|
request.env["mcs.appointment.type"]._public_domain()
|
|
)
|
|
return request.render(
|
|
"mcs_appointment_booking.appointment_type_list",
|
|
{"appointment_types": types},
|
|
)
|
|
|
|
@http.route(
|
|
["/appointments/<int:appointment_type_id>"],
|
|
type="http",
|
|
auth="public",
|
|
website=True,
|
|
)
|
|
def appointment_type(self, appointment_type_id, date=None, **kwargs):
|
|
appointment_type = self._type_or_404(appointment_type_id)
|
|
if hasattr(appointment_type, "status_code"):
|
|
return appointment_type
|
|
today = fields.Date.context_today(request.env.user)
|
|
selected_day = fields.Date.to_date(date) if date else today
|
|
max_day = today + timedelta(days=appointment_type.max_schedule_days)
|
|
if selected_day < today:
|
|
selected_day = today
|
|
if selected_day > max_day:
|
|
selected_day = max_day
|
|
day_options = [today + timedelta(days=index) for index in range(appointment_type.max_schedule_days)]
|
|
return request.render(
|
|
"mcs_appointment_booking.appointment_type_page",
|
|
{
|
|
"appointment_type": appointment_type,
|
|
"selected_day": selected_day,
|
|
"day_options": day_options,
|
|
"slots": self._display_slots(appointment_type, selected_day),
|
|
},
|
|
)
|
|
|
|
@http.route(
|
|
["/appointments/<int:appointment_type_id>/book"],
|
|
type="http",
|
|
auth="public",
|
|
website=True,
|
|
methods=["POST"],
|
|
)
|
|
def appointment_book(self, appointment_type_id, **post):
|
|
appointment_type = self._type_or_404(appointment_type_id)
|
|
if hasattr(appointment_type, "status_code"):
|
|
return appointment_type
|
|
|
|
start = fields.Datetime.from_string(post.get("start"))
|
|
stop = fields.Datetime.from_string(post.get("stop"))
|
|
booking = request.env["mcs.appointment.booking"].sudo().create(
|
|
{
|
|
"appointment_type_id": appointment_type.id,
|
|
"customer_name": (post.get("customer_name") or "").strip(),
|
|
"customer_email": (post.get("customer_email") or "").strip(),
|
|
"customer_phone": (post.get("customer_phone") or "").strip(),
|
|
"start": start,
|
|
"stop": stop,
|
|
"notes": (post.get("notes") or "").strip(),
|
|
}
|
|
)
|
|
booking.action_confirm()
|
|
return request.redirect("/appointments/confirmed/%s" % booking.access_token)
|
|
|
|
@http.route(
|
|
["/appointments/confirmed/<string:token>"],
|
|
type="http",
|
|
auth="public",
|
|
website=True,
|
|
)
|
|
def appointment_confirmed(self, token, **kwargs):
|
|
booking = (
|
|
request.env["mcs.appointment.booking"]
|
|
.sudo()
|
|
.search([("access_token", "=", token)], limit=1)
|
|
)
|
|
if not booking:
|
|
return request.not_found()
|
|
return request.render(
|
|
"mcs_appointment_booking.appointment_confirmed",
|
|
{"booking": booking},
|
|
)
|