115 lines
4.4 KiB
Python
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
|