odex30_standard/odex30_base/resource_booking/models/calendar_event.py

115 lines
4.5 KiB
Python

# Copyright 2021 Tecnativa - Jairo Llopis
# Copyright 2022 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class CalendarEvent(models.Model):
_inherit = "calendar.event"
# One2one field, actually
resource_booking_ids = fields.One2many(
comodel_name="resource.booking",
inverse_name="meeting_id",
string="Resource booking",
)
@api.constrains("resource_booking_ids", "start", "stop")
def _check_bookings_scheduling(self):
"""Scheduled bookings must have no conflicts."""
bookings = self.sudo().resource_booking_ids
return bookings._check_scheduling()
def _validate_booking_modifications(self):
"""Make sure you can cancel a booking meeting."""
bookings = self.sudo().resource_booking_ids
modifiable = bookings.filtered("is_modifiable")
frozen = bookings - modifiable
if frozen:
raise ValidationError(
_(
"You are not allowed to alter these bookings because "
"they exceeded their modification deadlines:\n\n- %s"
)
% "\n- ".join(frozen.mapped("display_name"))
)
def unlink(self):
"""Check you're allowed to unschedule it."""
self._validate_booking_modifications()
return super().unlink()
def write(self, vals):
"""Check you're allowed to reschedule it."""
before = [(one.start, one.stop) for one in self]
result = super().write(vals)
rescheduled = self
for (old_start, old_stop), new in zip(before, self):
if old_start == new.start and old_stop == new.stop:
rescheduled -= new
rescheduled._validate_booking_modifications()
return result
@api.model_create_multi
def create(self, vals_list):
"""Transfer resource booking to _attendees_values by context.
We need to serialize the creation in that case.
mail_notify_author key from context is necessary to force the notification
to be sent to author.
"""
vals_list2 = []
records = self.env["calendar.event"]
for vals in vals_list:
if "resource_booking_ids" in vals:
records += super(
CalendarEvent,
self.with_context(
resource_booking_ids=vals["resource_booking_ids"],
mail_notify_author=True,
),
).create(vals)
else:
vals_list2.append(vals)
records += super().create(vals_list2)
return records
def get_interval(self, interval, tz=None):
"""Autofix tz from related resource booking.
This function is called to render calendar.event notification mails.
Any notification related to a resource.booking must be emitted in the
same TZ as the resource.booking. Otherwise it's confusing to the user.
"""
tz = self.resource_booking_ids.type_id.resource_calendar_id.tz or tz
return super().get_interval(interval=interval, tz=tz)
def _attendees_values(self, partner_commands):
"""Autoconfirm resource attendees if preselected and hand-picked on RB.
NOTE: There's no support for changing `resource_booking_ids` once the meeting
is created nor having more than one Rb attached to the same meeting, but that's
not a real case for now.
"""
attendee_commands = super()._attendees_values(partner_commands)
partner_ids = False
for cmd in self.env.context.get("resource_booking_ids", []):
if cmd[0] == 0 and not cmd[2].get("combination_auto_assign", True):
partner_ids = [cmd[2]["partner_id"]]
elif cmd[0] == 6:
rb = self.env["resource.booking"].browse(cmd[2])
if rb.combination_auto_assign:
continue # only auto-confirm if handpicked combination
partner_ids = rb.combination_id.resource_ids.user_id.partner_id.ids
for command in attendee_commands:
if command[0] != 0:
continue
if not partner_ids:
rb = self.sudo().resource_booking_ids
partner_ids = rb.combination_id.resource_ids.user_id.partner_id.ids
if command[2]["partner_id"] in partner_ids:
command[2]["state"] = "accepted"
return attendee_commands