import pytz from dateutil.relativedelta import relativedelta from odoo import fields, _ from odoo.http import request, route from odoo.addons.appointment.controllers.appointment import AppointmentController from odoo.addons.base.models.ir_qweb import keep_query from werkzeug.exceptions import NotFound class AppointmentEventController(AppointmentController): @route( ["/appointment//submit"], type="http", auth="public", website=True, methods=["POST"], ) def appointment_form_submit( self, appointment_type_id, datetime_str, duration_str, staff_user_id, name, phone, email, **kwargs ): appointment_type = self._fetch_and_check_private_appointment_types( kwargs.get("filter_appointment_type_ids"), kwargs.get("filter_staff_user_ids"), kwargs.get("invite_token"), current_appointment_type_id=int(appointment_type_id), ) if not appointment_type: raise NotFound() if not appointment_type.create_events: return super().appointment_form_submit( appointment_type_id, datetime_str, duration_str, staff_user_id, name, phone, email, **kwargs ) # new process i # if booking a slot should create an event timezone = request.session.get("timezone") or appointment_type.appointment_tz tz_session = pytz.timezone(timezone) date_start = ( tz_session.localize(fields.Datetime.from_string(datetime_str)) .astimezone(pytz.utc) .replace(tzinfo=None) ) duration = float(duration_str) date_end = date_start + relativedelta(hours=duration) invite_token = kwargs.get("invite_token") # check availability of the selected user again (in case someone else booked while the client was entering the form) staff_user = request.env["res.users"].sudo().browse(int(staff_user_id)).exists() if staff_user not in appointment_type.sudo().staff_user_ids: raise NotFound() if staff_user and not staff_user.partner_id.calendar_verify_availability( date_start, date_end ): return request.redirect( "/appointment/%s?%s" % (appointment_type.id, keep_query("*", state="failed-staff-user")) ) Partner = self._get_customer_partner() or request.env[ "res.partner" ].sudo().search([("email", "=like", email)], limit=1) if Partner: if not Partner.calendar_verify_availability(date_start, date_end): return request.redirect( "/appointment/%s?%s" % (appointment_type.id, keep_query("*", state="failed-partner")) ) if not Partner.mobile: Partner.write({"mobile": phone}) if not Partner.email: Partner.write({"email": email}) else: Partner = Partner.create( { "name": name, "mobile": Partner._phone_format( phone, country=self._get_customer_country() ), "email": email, "lang": request.lang.code, } ) # partner_inputs dictionary structures all answer inputs received on the appointment submission: key is question id, value # is answer id (as string) for choice questions, text input for text questions, array of ids for multiple choice questions. partner_inputs = {} event_type = appointment_type.event_type_id event = ( request.env["event.event"] .sudo() .create( { "name": event_type.name, "date_begin": date_start, "date_end": date_end, "date_tz": timezone, "event_type_id": event_type.id, "user_id": int(staff_user_id), "address_id": appointment_type.location_id.id, } ) ) event = event.sudo() event.sudo().with_user(int(staff_user_id)).add_to_agenda() event.activity_schedule( act_type_xmlid="appointment_event.mail_activity_type_validate_date", summary=_("New booking to check"), note=_( "Check date availability and set automatic validation for next bookers." ), user_id=staff_user_id, ) event.write({"website_published": True}) return request.redirect(event.website_url)