forked from Mapan/odoo17e
139 lines
7.3 KiB
Python
139 lines
7.3 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from datetime import datetime, timedelta
|
|
import itertools
|
|
import pytz
|
|
|
|
from odoo.tests import users
|
|
from odoo.addons.appointment.tests.test_appointment_gantt import AppointmentGanttTestCommon
|
|
from odoo.addons.resource.models.utils import Intervals
|
|
|
|
|
|
class AppointmentHRGanttTest(AppointmentGanttTestCommon):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.env['hr.employee'].sudo().create({
|
|
'company_id': cls.user_bob.company_id.id,
|
|
'resource_calendar_id': cls.env['resource.calendar'].create({
|
|
'name': 'Appointment Gantt User Calendar',
|
|
'attendance_ids': [
|
|
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
|
|
(0, 0, {'name': 'Monday Lunch', 'dayofweek': '0', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
|
|
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
|
],
|
|
}).id,
|
|
'user_id': cls.user_bob.id,
|
|
})
|
|
|
|
@users('apt_manager', 'staff_user_bxls')
|
|
def test_gantt_calendar_unavailable(self):
|
|
"""Check that calendar unavailabilities and conflicting meetings are properly computed when grouping by attendees."""
|
|
self.apt_types.staff_user_ids += self.user_john
|
|
|
|
# inverted time slots over the test interval (0 -> 23)
|
|
appointment_slot_unavailabilities = Intervals([(
|
|
datetime(2022, 2, 14, 0, 0, tzinfo=pytz.UTC),
|
|
datetime(2022, 2, 14, 9, 0, tzinfo=pytz.UTC),
|
|
set(),
|
|
), (
|
|
datetime(2022, 2, 14, 12, 0, tzinfo=pytz.UTC),
|
|
datetime(2022, 2, 14, 14, 0, tzinfo=pytz.UTC),
|
|
set(),
|
|
), (
|
|
datetime(2022, 2, 14, 17, 0, tzinfo=pytz.UTC),
|
|
datetime(2022, 2, 14, 23, 0, tzinfo=pytz.UTC),
|
|
set(),
|
|
)])
|
|
base_bob_unavailabilities = [{
|
|
'start': self.reference_monday.replace(hour=0, minute=0, tzinfo=pytz.UTC),
|
|
'stop': self.reference_monday.replace(hour=7, minute=0, tzinfo=pytz.UTC),
|
|
}, {
|
|
'start': self.reference_monday.replace(hour=11, minute=0, tzinfo=pytz.UTC),
|
|
'stop': self.reference_monday.replace(hour=12, minute=0, tzinfo=pytz.UTC)
|
|
}, {
|
|
'start': self.reference_monday.replace(hour=16, minute=0, tzinfo=pytz.UTC),
|
|
'stop': self.reference_monday.replace(hour=23, minute=0, tzinfo=pytz.UTC)
|
|
}]
|
|
|
|
# clean up between @users subtests
|
|
self.env['calendar.event'].sudo().search([
|
|
('partner_ids', 'in', [self.user_bob.partner_id.id, self.user_john.partner_id.id])
|
|
]).unlink()
|
|
self.env['resource.calendar.leaves'].sudo().search([
|
|
('calendar_id', '=', self.user_bob.resource_calendar_id.id)
|
|
]).unlink()
|
|
all_company_meeting = self._create_meetings(
|
|
self.staff_user_bxls,
|
|
[(self.reference_monday.replace(hour=14),
|
|
self.reference_monday.replace(hour=14) + timedelta(hours=1),
|
|
False,
|
|
)],
|
|
self.apt_types[0].id
|
|
)
|
|
CalendarLeaveSudo = self.env['resource.calendar.leaves'].sudo()
|
|
|
|
for with_leave, with_meeting, specific_apt_type in itertools.product([True, False], [True, False], [True, False]):
|
|
with self.subTest(with_leave=with_leave, with_meeting=with_meeting, specific_apt_type=specific_apt_type):
|
|
CalendarLeaveSudo.search([('calendar_id', '=', self.user_bob.resource_calendar_id.id)]).unlink()
|
|
all_company_meeting.partner_ids = False
|
|
if with_leave:
|
|
CalendarLeaveSudo.create({
|
|
'calendar_id': self.user_bob.resource_calendar_id.id,
|
|
'date_from': self.reference_monday.replace(hour=9),
|
|
'date_to': self.reference_monday.replace(hour=9) + timedelta(hours=1),
|
|
'name': 'Monday Morning Leave'
|
|
})
|
|
if with_meeting:
|
|
all_company_meeting.partner_ids = self.user_john.partner_id + self.user_bob.partner_id
|
|
|
|
ctx = dict(self.gantt_context)
|
|
if specific_apt_type:
|
|
ctx.update({'default_appointment_type_id': self.apt_types[0].id})
|
|
gantt_data = self.env['calendar.event'].with_context(ctx).gantt_unavailability(
|
|
self.reference_monday.replace(hour=0),
|
|
self.reference_monday.replace(hour=23),
|
|
'day',
|
|
group_bys=['partner_ids', 'user_id'],
|
|
rows=[{
|
|
'groupedBy': ['partner_ids', 'user_id'],
|
|
'resId': self.user_bob.partner_id.id,
|
|
'rows': [{'groupedBy': ['user_id'], 'resId': self.user_bob.id, 'rows': []}] if with_meeting else []
|
|
}, {
|
|
'groupedBy': ['partner_ids', 'user_id'],
|
|
'resId': self.user_john.partner_id.id,
|
|
'rows': [{'groupedBy': ['user_id'], 'resId': self.user_john.id, 'rows': []}] if with_meeting else []
|
|
}]
|
|
)
|
|
|
|
bob_data, john_data = gantt_data
|
|
bob_unavailabilities = list(base_bob_unavailabilities)
|
|
john_unavailabilities = []
|
|
if with_meeting:
|
|
all_company_unavailability = {
|
|
'start': self.reference_monday.replace(hour=14, tzinfo=pytz.UTC),
|
|
'stop': self.reference_monday.replace(hour=14, tzinfo=pytz.UTC) + timedelta(hours=1),
|
|
}
|
|
bob_unavailabilities.append(all_company_unavailability)
|
|
john_unavailabilities.append(all_company_unavailability)
|
|
if with_leave:
|
|
bob_unavailabilities.append({
|
|
'start': self.reference_monday.replace(hour=9, tzinfo=pytz.UTC),
|
|
'stop': self.reference_monday.replace(hour=9, tzinfo=pytz.UTC) + timedelta(hours=1),
|
|
})
|
|
if specific_apt_type:
|
|
bob_unavailabilities = [{'start': start, 'stop': stop} for start, stop, _ in Intervals([
|
|
(unavailability['start'], unavailability['stop'], set()) for unavailability in bob_unavailabilities
|
|
]) | appointment_slot_unavailabilities]
|
|
john_unavailabilities = [{'start': start, 'stop': stop} for start, stop, _ in Intervals([
|
|
(unavailability['start'], unavailability['stop'], set()) for unavailability in john_unavailabilities
|
|
]) | appointment_slot_unavailabilities]
|
|
self.assertEqual(
|
|
bob_data['unavailabilities'], sorted(bob_unavailabilities, key=lambda start_stop: start_stop['start']),
|
|
'Bob should not be available when attending another meeting or outside of his HR schedule.'
|
|
)
|
|
self.assertEqual(
|
|
john_data['unavailabilities'], sorted(john_unavailabilities, key=lambda start_stop: start_stop['start']),
|
|
'John should not be available when attending another meeting.'
|
|
)
|