65 lines
3.1 KiB
Python
65 lines
3.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import pytz
|
|
from datetime import datetime, time
|
|
|
|
from odoo import fields, models
|
|
|
|
|
|
class ResPartner(models.Model):
|
|
_inherit = "res.partner"
|
|
|
|
upcoming_appointment_ids = fields.Many2many('calendar.event', string="Upcoming Appointments", compute="_compute_upcoming_appointment_ids")
|
|
|
|
def _compute_upcoming_appointment_ids(self):
|
|
partner_upcoming_appointments = dict(self.env['calendar.event']._read_group(
|
|
[('appointment_booker_id', 'in', self.ids), ('appointment_type_id', '!=', False), ('start', '>', datetime.now())],
|
|
['appointment_booker_id'],
|
|
['id:recordset'],
|
|
))
|
|
for partner in self:
|
|
partner.upcoming_appointment_ids = partner_upcoming_appointments.get(partner, False)
|
|
|
|
def calendar_verify_availability(self, date_start, date_end, appointment_type=None):
|
|
""" Verify availability of the partner(s) for the appointment between 2 datetimes on their
|
|
calendar. We only verify events that are not linked to an appointment type with resources since
|
|
someone could take multiple appointment for multiple resources. The availability of
|
|
resources is managed separately by booking lines (see ``appointment.booking.line`` model)
|
|
|
|
:param datetime date_start: beginning of slot boundary. Not timezoned UTC;
|
|
:param datetime date_end: end of slot boundary. Not timezoned UTC;
|
|
"""
|
|
all_events = self.env['calendar.event'].search(
|
|
['&',
|
|
('partner_ids', 'in', self.ids),
|
|
'&', '&',
|
|
('show_as', '=', 'busy'),
|
|
('stop', '>', datetime.combine(date_start, time.min)),
|
|
('start', '<', datetime.combine(date_end, time.max)),
|
|
],
|
|
order='start asc',
|
|
)
|
|
events_excluding_appointment_resource = all_events.filtered(lambda ev: ev.appointment_type_id.schedule_based_on != 'resources')
|
|
for event in events_excluding_appointment_resource:
|
|
if event.allday or (event.start < date_end and event.stop > date_start):
|
|
# Skip marking the staff user unavailable for the same appointment
|
|
if (appointment_type and self <= appointment_type.staff_user_ids.partner_id and
|
|
event.appointment_type_id == appointment_type):
|
|
continue
|
|
tz = pytz.timezone(event.user_id.tz) if event.user_id.tz else pytz.utc
|
|
if event.allday:
|
|
start_utc = tz.localize(event.start).astimezone(pytz.utc).replace(tzinfo=None)
|
|
stop_utc = tz.localize(event.stop).astimezone(pytz.utc).replace(tzinfo=None)
|
|
else:
|
|
start_utc = event.start
|
|
stop_utc = event.stop
|
|
if start_utc < date_end and stop_utc > date_start:
|
|
if event.attendee_ids.filtered_domain(
|
|
[('state', '!=', 'declined'),
|
|
('partner_id', 'in', self.ids)]
|
|
):
|
|
return False
|
|
|
|
return True
|