2026-04-27 11:32:36 -04:00

115 lines
4.4 KiB
Python

import secrets
from odoo import api, fields, models
from odoo.exceptions import UserError, ValidationError
class McsAppointmentBooking(models.Model):
_name = "mcs.appointment.booking"
_description = "Appointment Booking"
_inherit = ["mail.thread", "mail.activity.mixin"]
_order = "start desc"
name = fields.Char(compute="_compute_name", store=True)
appointment_type_id = fields.Many2one(
"mcs.appointment.type", required=True, ondelete="restrict", tracking=True
)
company_id = fields.Many2one(
related="appointment_type_id.company_id", store=True, readonly=True
)
user_id = fields.Many2one(
related="appointment_type_id.user_id", string="Host", store=True, readonly=True
)
partner_id = fields.Many2one("res.partner", string="Customer")
customer_name = fields.Char(required=True, tracking=True)
customer_email = fields.Char(required=True, tracking=True)
customer_phone = fields.Char()
start = fields.Datetime(required=True, tracking=True)
stop = fields.Datetime(required=True, tracking=True)
duration = fields.Float(related="appointment_type_id.duration", readonly=True)
state = fields.Selection(
[
("draft", "Draft"),
("confirmed", "Confirmed"),
("cancelled", "Cancelled"),
],
default="draft",
required=True,
tracking=True,
)
notes = fields.Text()
calendar_event_id = fields.Many2one("calendar.event", readonly=True, copy=False)
access_token = fields.Char(default=lambda self: secrets.token_urlsafe(24), copy=False)
@api.depends("appointment_type_id", "customer_name", "start")
def _compute_name(self):
for booking in self:
parts = [
booking.appointment_type_id.name or "Appointment",
booking.customer_name or "Customer",
]
if booking.start:
parts.append(fields.Datetime.to_string(booking.start))
booking.name = " - ".join(parts)
@api.constrains("start", "stop")
def _check_dates(self):
for booking in self:
if booking.start and booking.stop and booking.start >= booking.stop:
raise ValidationError("Appointment end must be after start.")
def _ensure_partner(self):
self.ensure_one()
if self.partner_id:
return self.partner_id
partner = self.env["res.partner"].sudo().search(
[("email", "=", self.customer_email)], limit=1
)
if not partner:
partner = self.env["res.partner"].sudo().create(
{
"name": self.customer_name,
"email": self.customer_email,
"phone": self.customer_phone,
"company_id": self.company_id.id,
}
)
self.partner_id = partner.id
return partner
def action_confirm(self):
for booking in self:
if booking.state == "confirmed":
continue
busy = booking.appointment_type_id._busy_intervals(booking.start, booking.stop)
busy = [
interval
for interval in busy
if not booking.calendar_event_id
or interval != (booking.calendar_event_id.start, booking.calendar_event_id.stop)
]
if not booking.appointment_type_id._is_free(booking.start, booking.stop, busy):
raise UserError("This time slot is no longer available.")
partner = booking._ensure_partner()
event_vals = {
"name": booking.name,
"start": booking.start,
"stop": booking.stop,
"user_id": booking.user_id.id,
"partner_ids": [(6, 0, [partner.id, booking.user_id.partner_id.id])],
"description": booking.notes or "",
}
if booking.calendar_event_id:
booking.calendar_event_id.write(event_vals)
else:
booking.calendar_event_id = self.env["calendar.event"].sudo().create(event_vals).id
booking.state = "confirmed"
def action_cancel(self):
for booking in self:
booking.state = "cancelled"
if booking.calendar_event_id:
booking.calendar_event_id.sudo().unlink()
booking.calendar_event_id = False