1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/appointment/tests/test_appointment_resource.py
2024-12-10 09:04:09 +07:00

1210 lines
59 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, timedelta
from freezegun import freeze_time
from odoo import Command
from odoo.addons.appointment.tests.common import AppointmentCommon
from odoo.exceptions import ValidationError
from odoo.tests import Form, tagged, users, warmup
@tagged('appointment_resources', 'post_install', '-at_install')
class AppointmentResource(AppointmentCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.appointment_manage_capacity, cls.appointment_regular = cls.env['appointment.type'].create([{
'appointment_tz': 'UTC',
'min_schedule_hours': 1.0,
'max_schedule_days': 8,
'name': 'Managed Test',
'resource_manage_capacity': True,
'schedule_based_on': 'resources',
'slot_ids': [(0, 0, {
'weekday': str(cls.reference_monday.isoweekday()),
'start_hour': 6,
'end_hour': 18,
})],
}, {
'appointment_tz': 'UTC',
'min_schedule_hours': 1.0,
'max_schedule_days': 8,
'name': 'Unmanaged Test',
'resource_manage_capacity': False,
'schedule_based_on': 'resources',
'slot_ids': [(0, 0, {
'weekday': str(cls.reference_monday.isoweekday()),
'start_hour': 6,
'end_hour': 18,
})],
}])
cls.resource_1, cls.resource_2, cls.resource_3 = cls.env['appointment.resource'].create([{
'appointment_type_ids': cls.appointment_manage_capacity.ids,
'capacity': 3,
'name': 'Resource 1',
}, {
'appointment_type_ids': cls.appointment_manage_capacity.ids,
'capacity': 2,
'name': 'Resource 2',
'shareable': True,
}, {
'appointment_type_ids': (cls.appointment_manage_capacity | cls.appointment_regular).ids,
'capacity': 1,
'name': 'Resource 3',
}])
@users('apt_manager')
def test_appointment_resource_default_appointment_type(self):
"""Check that the default appointment type is properly deduced from the default appointment resource."""
resource_3_type_ids = self.resource_3.appointment_type_ids
Event = self.env['calendar.event']
states = [(self.resource_3, None, resource_3_type_ids[0]),
(self.resource_3, resource_3_type_ids[1], resource_3_type_ids[1])]
for resource, default_type, expected_type_id in states:
context = {
'booking_gantt_create_record': True,
'default_resource_ids': resource.ids
}
if default_type:
context.update(default_appointment_type_id=default_type.id)
event = Form(Event.with_context(context))
self.assertEqual(event.appointment_type_id, expected_type_id)
@users('apt_manager')
def test_appointment_resource_link(self):
""" Test link between resources when they are combinable. """
resource_1, resource_2 = self.env['appointment.resource'].create([
{
'capacity': 4,
'name': 'Table of 4',
},
{
'capacity': 2,
'name': 'Table of 2',
}
])
self.assertFalse(resource_1.linked_resource_ids)
self.assertFalse(resource_2.linked_resource_ids)
# Test: link resource 2 to resource 1, and add a new resource as an
# embedded 2many creation
resource_1.write({
'linked_resource_ids': [
(4, resource_2.id), # new link
(0, 0, { # embedded creation
'capacity': 1,
'name': 'OnTheFly Table of 1'
}),
],
})
new_resource_1 = self.env['appointment.resource'].search([('name', '=', 'OnTheFly Table of 1')])
self.assertEqual(len(new_resource_1), 1, 'Should have created a new resource')
self.assertEqual(new_resource_1.linked_resource_ids, resource_1,
'Link works both ways')
self.assertFalse(new_resource_1.source_resource_ids)
self.assertEqual(new_resource_1.destination_resource_ids, resource_1,
'Resource 2 is destination of link between 1 and 2')
self.assertEqual(
resource_1.linked_resource_ids,
resource_2 + new_resource_1,
'Resource 1 should be linked to linked resource 2 and newly created new'
)
self.assertEqual(resource_1.source_resource_ids, resource_2 + new_resource_1)
self.assertFalse(resource_1.destination_resource_ids)
self.assertEqual(resource_2.linked_resource_ids, resource_1,
'Link works both ways')
self.assertFalse(resource_2.source_resource_ids)
self.assertEqual(resource_2.destination_resource_ids, resource_1,
'Resource 2 is destination of link between 1 and 2')
# Test: break link to resource 2, add an existing one (check duplication)
# and create yet another one
resource_1.write({
'linked_resource_ids': [
(3, resource_2.id), # break link
(4, new_resource_1.id), # already existing
(0, 0, {
'capacity': 1,
'name': 'OnTheFly Table of 1 (bis)'
}),
],
})
new_resource_2 = self.env['appointment.resource'].search([('name', '=', 'OnTheFly Table of 1 (bis)')])
self.assertEqual(len(new_resource_2), 1, 'Should have created a new resource')
self.assertEqual(new_resource_1.linked_resource_ids, resource_1,
'Link works both ways')
self.assertFalse(new_resource_1.source_resource_ids)
self.assertEqual(new_resource_1.destination_resource_ids, resource_1)
self.assertEqual(new_resource_2.linked_resource_ids, resource_1,
'Link works both ways')
self.assertFalse(new_resource_2.source_resource_ids)
self.assertEqual(new_resource_2.destination_resource_ids, resource_1)
self.assertEqual(
resource_1.linked_resource_ids,
new_resource_1 + new_resource_2,
'Resource 1 should be linked to linked resource 2 and newly created new'
)
self.assertEqual(resource_1.source_resource_ids, new_resource_1 + new_resource_2)
self.assertFalse(resource_1.destination_resource_ids)
self.assertFalse(resource_2.linked_resource_ids)
self.assertFalse(resource_2.source_resource_ids)
self.assertFalse(resource_2.destination_resource_ids)
# Test: update link based on destination, not source as previous tests
resource_2.write({
'linked_resource_ids': [
(4, new_resource_1.id), # add a new entry in destination
]
})
new_resource_2.write({
'linked_resource_ids': [
(3, resource_1.id), # break link
(4, resource_2.id), # new link, will have both sources and dest
(4, new_resource_1.id), # new link
]
})
self.assertEqual(len(new_resource_2), 1, 'Should have created a new resource')
self.assertEqual(new_resource_1.linked_resource_ids, resource_1 + resource_2 + new_resource_2)
self.assertFalse(new_resource_1.source_resource_ids)
self.assertEqual(new_resource_1.destination_resource_ids, resource_1 + resource_2 + new_resource_2)
self.assertEqual(new_resource_2.linked_resource_ids, resource_2 + new_resource_1)
self.assertEqual(new_resource_2.source_resource_ids, resource_2 + new_resource_1)
self.assertFalse(new_resource_2.destination_resource_ids)
self.assertEqual(resource_1.linked_resource_ids, new_resource_1)
self.assertEqual(resource_1.source_resource_ids, new_resource_1)
self.assertFalse(resource_1.destination_resource_ids)
self.assertEqual(resource_2.linked_resource_ids, new_resource_1 + new_resource_2)
self.assertEqual(resource_2.source_resource_ids, new_resource_1)
self.assertEqual(resource_2.destination_resource_ids, new_resource_2)
@users('apt_manager')
def test_appointment_resource_field(self):
"""Check that the appointment_resource_id field works as expected"""
booking = self.env['calendar.event'].with_context(self._test_context).create([{
'appointment_type_id': self.appointment_manage_capacity.id,
'name': 'Booking',
'start': datetime(2022, 2, 15, 14, 0, 0),
'stop': datetime(2022, 2, 15, 15, 0, 0),
}])
self.assertFalse(booking.appointment_resource_id)
booking.appointment_resource_id = self.resource_1
self.assertEqual(booking.appointment_resource_id, self.resource_1)
self.assertEqual(len(booking.booking_line_ids), 1)
self.assertEqual(booking.booking_line_ids.appointment_resource_id, self.resource_1)
booking_line_1 = booking.booking_line_ids[0]
booking.write({'booking_line_ids': [Command.create({
'appointment_resource_id': self.resource_2.id,
'calendar_event_id': booking.id,
'capacity_reserved': 1})]
})
self.assertFalse(booking.appointment_resource_id, 'More than one booking lines should mean no singular resource id.')
self.assertEqual(booking.booking_line_ids.appointment_resource_id, self.resource_1 | self.resource_2)
booking_lines_before = booking.booking_line_ids
resources_before = booking.appointment_resource_ids
booking.appointment_resource_id = self.resource_3
self.assertEqual(len(booking.booking_line_ids), 2, 'Setting the singular resource when there already are multiple booking lines should do nothing.')
self.assertEqual(booking_lines_before, booking.booking_line_ids)
self.assertEqual(resources_before, booking.appointment_resource_ids)
booking.booking_line_ids = booking_line_1
self.assertEqual(len(booking.booking_line_ids), 1)
self.assertEqual(booking.appointment_resource_id, self.resource_1)
booking.appointment_resource_id = False
self.assertEqual(len(booking.booking_line_ids), 0)
self.assertFalse(booking.appointment_resource_id)
self.assertFalse(booking.booking_line_ids)
@users('apt_manager')
def test_appointment_resources_remaining_capacity(self):
""" Test that the remaining capacity of resources are correctly computed """
appointment = self.appointment_manage_capacity
resource_1 = self.resource_1
resource_2 = self.resource_2
start = datetime(2022, 2, 15, 14, 0, 0)
end = start + timedelta(hours=1)
self.assertTrue(appointment._get_resources_remaining_capacity(resource_1, start, end)['total_remaining_capacity'] == 3)
self.assertTrue(appointment._get_resources_remaining_capacity(resource_2, start, end)['total_remaining_capacity'] == 2)
# Create bookings for resource
booking_1, booking_2 = self.env['calendar.event'].with_context(self._test_context).create([{
'appointment_type_id': appointment.id,
'booking_line_ids': [(0, 0, {'appointment_resource_id': resource_1.id, 'capacity_reserved': 1, 'capacity_used': resource_1.capacity})],
'name': 'Booking 1',
'start': start,
'stop': end,
}, {
'appointment_type_id': appointment.id,
'booking_line_ids': [(0, 0, {'appointment_resource_id': resource_2.id, 'capacity_reserved': 1})],
'name': 'Booking 2',
'start': start,
'stop': end,
}])
bookings = booking_1 + booking_2
self.assertTrue(
appointment._get_resources_remaining_capacity(resource_1, start, end)['total_remaining_capacity'] == 0,
'The resource should have no availabilities left')
self.assertTrue(
appointment._get_resources_remaining_capacity(resource_2, start, end)['total_remaining_capacity'] == 1,
'The resource should have 1 availability left because it is shareable')
bookings.unlink()
resource_1.linked_resource_ids = resource_2
self.assertTrue(
appointment._get_resources_remaining_capacity(resource_1, start, end)['total_remaining_capacity'] == 5,
"The resource should have 5 availabilities (3 from the resource and 2 from the other linked to it)")
self.assertTrue(appointment._get_resources_remaining_capacity(resource_2, start, end)['total_remaining_capacity'] == 5)
self.assertTrue(appointment._get_resources_remaining_capacity(resource_1, start, end)[resource_1] == 3)
self.assertTrue(appointment._get_resources_remaining_capacity(resource_2, start, end)[resource_2] == 2)
booking = self.env['calendar.event'].with_context(self._test_context).create([{
'appointment_type_id': appointment.id,
'booking_line_ids': [
(0, 0, {'appointment_resource_id': resource_1.id, 'capacity_reserved': 3, 'capacity_used': 3}),
(0, 0, {'appointment_resource_id': resource_2.id, 'capacity_reserved': 1}),
],
'name': 'Booking',
'start': start,
'stop': end,
}])
self.assertTrue(len(booking.appointment_resource_ids) == 2)
self.assertTrue(
appointment._get_resources_remaining_capacity(resource_1, start, end)['total_remaining_capacity'] == 1,
'The resource should have 1 availability left (the one from resource_2)')
self.assertTrue(
appointment._get_resources_remaining_capacity(resource_1, start, end)[resource_1] == 0,
'The resource should have no availability left if alone')
self.assertTrue(
appointment._get_resources_remaining_capacity(resource_2, start, end)['total_remaining_capacity'] == 1,
'The resource should have 1 availability left')
self.assertDictEqual(
appointment._get_resources_remaining_capacity(self.env['appointment.resource'], start, end),
{'total_remaining_capacity': 0},
'No result should give dict with correct accumulated values.')
@tagged('appointment_resources', 'post_install', '-at_install')
class AppointmentResourceBookingTest(AppointmentCommon):
@users('apt_manager')
@warmup
def test_appointment_resources(self):
""" Slots generation and availability of appointment type with resources """
appointment = self.env['appointment.type'].create({
'appointment_tz': 'UTC',
'assign_method': 'time_auto_assign',
'min_schedule_hours': 1.0,
'max_schedule_days': 8,
'name': 'Test',
'resource_manage_capacity': True,
'schedule_based_on': 'resources',
'slot_ids': [(0, 0, {
'weekday': str(self.reference_monday.isoweekday()),
'start_hour': 6,
'end_hour': 18,
})],
})
self.env['appointment.resource'].create([
{
'appointment_type_ids': appointment.ids,
'capacity': 3,
'name': 'Resource %s' % i,
} for i in range(20)
])
# Flush everything, notably tracking values, as it may impact performances
self.flush_tracking()
with freeze_time(self.reference_now):
with self.assertQueryCount(default=10):
appointment._get_appointment_slots('UTC')
def test_appointment_resources_availability(self):
""" Check that resource slots are all available for an appointment """
appointment = self.env['appointment.type'].create({
'appointment_tz': 'UTC',
'name': 'Resource appointment',
'resource_manage_capacity': False,
'schedule_based_on': 'resources',
'slot_ids': [
(0, 0, {
'weekday': str(self.reference_monday.isoweekday()),
'start_hour': 0,
'end_hour': 0,
}),
],
})
periods = [
{'name': 'Morning', 'hour_from': 0, 'hour_to': 11.99, 'day_period': 'morning'},
{'name': 'Afternoon', 'hour_from': 12, 'hour_to': 24, 'day_period': 'afternoon'}
]
week_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
resource_calendar = self.env['resource.calendar'].create({
'name': 'Default Calendar',
'company_id': False,
'hours_per_day': 24,
'attendance_ids': [
(0, 0, {
'name': f'{day} {period["name"]}',
'dayofweek': str(week_days.index(day)),
'hour_from': period['hour_from'],
'hour_to': period['hour_to'],
'day_period': period['day_period']
})
for day in week_days
for period in periods
],
})
# Default resource_calendar_id, Mon-Sun 12am-11:59am 12pm-11:59pm
resource = self.env['appointment.resource'].create({
'name': 'Resource',
'appointment_type_ids': appointment,
'resource_calendar_id': resource_calendar.id,
})
with freeze_time(self.reference_now):
slots = appointment._get_appointment_slots(timezone='UTC', filter_resources=resource)
self.assertSlots(
slots,
[
{
'name_formated': 'February 2022',
'month_date': datetime(2022, 2, 1),
'weeks_count': 5,
},
],
{
'enddate': self.global_slots_enddate,
'startdate': self.reference_now_monthweekstart,
'slots_start_hours': list(range(24)),
'slots_startdate': self.reference_monday.date(),
'slots_weekdays_nowork': range(1, 7), # Resource only available on monday (0)
},
)
def test_appointment_resources_check_organizer_validation_conditions(self):
appointment_vals_list = [{
'appointment_type_id': self.apt_type_resource.id,
'name': 'Booking',
'start': datetime(2022, 2, 15, 14, 0, 0),
'stop': datetime(2022, 2, 15, 15, 0, 0),
}, {
'appointment_type_id': self.apt_type_bxls_2days.id,
'name': 'Booking',
'start': datetime(2022, 2, 15, 10, 0, 0),
'stop': datetime(2022, 2, 15, 11, 0, 0),
}, {
'appointment_type_id': False,
'name': 'Booking',
'start': datetime(2022, 2, 15, 10, 0, 0),
'stop': datetime(2022, 2, 15, 11, 0, 0),
}]
self.assertEqual(self.env['calendar.event']._check_organizer_validation_conditions(appointment_vals_list), [False, True, True])
@users('apt_manager')
def test_appointment_resources_combinable(self):
""" Check that combinable resources are correctly process. """
table_c2, table_c4, table_c6 = self.env['appointment.resource'].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': i,
'name': 'Table for %s' % i,
'sequence': i,
} for i in range(2, 7, 2)])
table_c2.linked_resource_ids = (table_c4 + table_c6)
table_c4.linked_resource_ids = (table_c2 + table_c6)
table_c6.linked_resource_ids = (table_c2 + table_c4)
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC')
resource_slots_c1 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=3)
resource_slots_c3 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
resource_slots_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=6)
resource_slots_c6 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=9)
resource_slots_c9 = self._filter_appointment_slots(slots)
available_resources_c1 = [resource['id'] for resource in resource_slots_c1[0]['available_resources']]
available_resources_c3 = [resource['id'] for resource in resource_slots_c3[0]['available_resources']]
available_resources_c4 = [resource['id'] for resource in resource_slots_c4[0]['available_resources']]
available_resources_c6 = [resource['id'] for resource in resource_slots_c6[0]['available_resources']]
available_resources_c9 = [resource['id'] for resource in resource_slots_c9[0]['available_resources']]
self.assertListEqual(available_resources_c1, table_c2.ids)
self.assertListEqual(available_resources_c3, table_c4.ids,
"The table for 4 should be selected here as it's linked to the table for 2 and we don't want to lose capacity with a combination")
self.assertListEqual(available_resources_c4, table_c4.ids)
self.assertListEqual(available_resources_c6, table_c6.ids)
self.assertListEqual(available_resources_c9, (table_c4 + table_c6).ids)
table_c4.sequence = 1
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC')
resource_slots_c1 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=3)
resource_slots_c3 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
resource_slots_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=6)
resource_slots_c6 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=9)
resource_slots_c9 = self._filter_appointment_slots(slots)
available_resources_c1 = [resource['id'] for resource in resource_slots_c1[0]['available_resources']]
available_resources_c3 = [resource['id'] for resource in resource_slots_c3[0]['available_resources']]
available_resources_c4 = [resource['id'] for resource in resource_slots_c4[0]['available_resources']]
available_resources_c6 = [resource['id'] for resource in resource_slots_c6[0]['available_resources']]
available_resources_c9 = [resource['id'] for resource in resource_slots_c9[0]['available_resources']]
self.assertListEqual(available_resources_c1, table_c4.ids)
self.assertListEqual(available_resources_c3, table_c4.ids)
self.assertListEqual(available_resources_c4, table_c4.ids)
self.assertListEqual(available_resources_c6, table_c6.ids)
self.assertListEqual(available_resources_c9, (table_c4 + table_c6).ids)
@users('apt_manager')
def test_appointment_resources_combinable_avoid_losing_extra_capacity(self):
""" Check that we don't lose capacity with the resource selected.
If a capacity needed is greater than the capacity of the resource initially selected
we should check if the linked resources of the one selected are not a better fit to avoid losing capacity.
"""
nordic, scandinavian, snow = self.env["appointment.resource"].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 4,
'name': 'Nordic',
'sequence': 2,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 8,
'name': 'Scandinavian',
'sequence': 3,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 6,
'name': 'Snow',
'sequence': 4,
}])
nordic.linked_resource_ids = scandinavian
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
available_resources_c5 = [resource['id'] for resource in resource_slots_c5[0]['available_resources']]
self.assertListEqual(available_resources_c5, scandinavian.ids)
snow.sequence = 1
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
available_resources_c5 = [resource['id'] for resource in resource_slots_c5[0]['available_resources']]
self.assertListEqual(available_resources_c5, snow.ids)
snow.sequence = 4
scandinavian.write({
'linked_resource_ids': [(4, nordic.id)],
'sequence': 1,
})
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=2)
resource_slots_c2 = self._filter_appointment_slots(slots)
available_resources_c5 = [resource['id'] for resource in resource_slots_c5[0]['available_resources']]
available_resources_c2 = [resource['id'] for resource in resource_slots_c2[0]['available_resources']]
self.assertListEqual(available_resources_c5, scandinavian.ids)
self.assertListEqual(available_resources_c2, scandinavian.ids)
@users('apt_manager')
def test_appointment_resources_combinable_complex(self):
""" Check resources assignation when the linked resources are not mirrored for all resources """
table1_c2, table2_c2, table3_c2 = self.env['appointment.resource'].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 2,
'name': 'Table 2A',
'sequence': 1,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 2,
'name': 'Table 2B',
'sequence': 3,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 2,
'name': 'Table 2C',
'sequence': 2,
}])
table1_c2.linked_resource_ids = table2_c2 + table3_c2
table2_c2.linked_resource_ids = table1_c2 + table3_c2
table3_c2.linked_resource_ids = table1_c2 + table2_c2
table_c3 = self.env['appointment.resource'].create({
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 3,
'name': 'Table 3A',
'sequence': 4,
})
table1_c6, table2_c6 = self.env['appointment.resource'].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 6,
'name': 'Table 6A',
'sequence': 5,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 6,
'name': 'Table 6B',
'sequence': 6,
}])
table1_c6.linked_resource_ids = table_c3
table2_c6.linked_resource_ids = table1_c2 + table2_c2 + table3_c2
table1_c8, table2_c8, bar = self.env['appointment.resource'].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 8,
'name': 'Table 8A',
'sequence': 8,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 8,
'name': 'Table 8B',
'sequence': 9,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 10,
'name': 'Bar',
'sequence': 15,
'shareable': True,
}])
table1_c8.sequence = 10
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
resource_slots_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=8)
resource_slots_c8 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=10)
resource_slots_c10 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=12)
resource_slots_c12 = self._filter_appointment_slots(slots)
available_resources_c4 = [resource['id'] for resource in resource_slots_c4[0]['available_resources']]
available_resources_c8 = [resource['id'] for resource in resource_slots_c8[0]['available_resources']]
available_resources_c10 = [resource['id'] for resource in resource_slots_c10[0]['available_resources']]
available_resources_c12 = [resource['id'] for resource in resource_slots_c12[0]['available_resources']]
self.assertListEqual(available_resources_c4, (table1_c2 + table3_c2).ids)
self.assertListEqual(available_resources_c8, table2_c8.ids)
self.assertListEqual(available_resources_c10, bar.ids)
self.assertListEqual(available_resources_c12, (table2_c6 + table2_c6.linked_resource_ids).sorted('sequence').ids)
@users('apt_manager')
def test_appointment_resources_combinable_last_availability(self):
""" Check that the last resource available is correctly computed with linked resources """
table_c2, table_c3 = self.env["appointment.resource"].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 2,
'name': 'Table for 2',
'sequence': 1,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 3,
'name': 'Table for 3',
'sequence': 2,
}])
table_c2.linked_resource_ids = table_c3
# Create a booking for the first resource for all its capacity
start = datetime(2022, 2, 14, 15, 0, 0)
end = start + timedelta(hours=1)
self.env['calendar.event'].with_context(self._test_context).create({
'appointment_type_id': self.apt_type_resource.id,
'booking_line_ids': [(0, 0, {'appointment_resource_id': table_c2.id, 'capacity_reserved': 2, 'capacity_used': 2})],
'name': 'Booking 1',
'start': start,
'stop': end,
})
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=2)
resource_slots_c2 = self._filter_appointment_slots(slots)
available_resources_c2 = [resource['id'] for resource in resource_slots_c2[0]['available_resources']]
self.assertEqual(set(available_resources_c2), set(table_c3.ids),
"Only the table for 3 should be available as the other is booked")
self._test_slot_generate_available_resources(self.apt_type_resource, 2, 'UTC', start, end, table_c3, available_resources_c2, reference_date=self.reference_now)
@users('apt_manager')
def test_appointment_resources_combinable_performance(self):
""" Simple use case of appointment type with combinable resources """
appointment = self.env['appointment.type'].create({
'appointment_tz': 'UTC',
'assign_method': 'time_auto_assign',
'min_schedule_hours': 1.0,
'max_schedule_days': 8,
'name': 'Test',
'resource_manage_capacity': True,
'schedule_based_on': 'resources',
'slot_ids': [(0, 0, {
'weekday': str(self.reference_monday.isoweekday()),
'start_hour': 6,
'end_hour': 18,
})],
})
table1_c2, table2_c2, table3_c2 = self.env['appointment.resource'].create([
{
'appointment_type_ids': appointment.ids,
'capacity': 2,
'name': 'Table %s - 2' % (i + 1),
} for i in range(3)
])
table1_c4, table2_c4, table3_c4 = self.env['appointment.resource'].create([
{
'appointment_type_ids': appointment.ids,
'capacity': 4,
'name': 'Table %s - 4' % (i + 1),
} for i in range(3)
])
table1_c6 = self.env['appointment.resource'].create({
'appointment_type_ids': appointment.ids,
'capacity': 6,
'name': 'Table - 6',
})
(table1_c4 + table2_c4 + table3_c4).linked_resource_ids = table1_c2 + table2_c2 + table3_c2 + table1_c6
(table1_c2 + table2_c2 + table3_c2).linked_resource_ids = table1_c4 + table2_c4 + table3_c4
table1_c6.linked_resource_ids = table1_c4 + table2_c4 + table3_c4
# Flush everything, notably tracking values, as it may impact performances
self.flush_tracking()
with freeze_time(self.reference_now):
with self.assertQueryCount(default=12):
slots = appointment._get_appointment_slots('UTC')
resource_slots = self._filter_appointment_slots(
slots,
filter_weekdays=[0],
)
table1_c2_slots = self._filter_appointment_slots(
slots,
filter_weekdays=[0],
filter_resources=table1_c2,
)
self.assertTrue(len(resource_slots) > 0)
self.assertEqual(len(resource_slots), len(table1_c2_slots))
with self.assertQueryCount(default=4):
slots = appointment._get_appointment_slots('UTC', asked_capacity=5)
resource_slots = self._filter_appointment_slots(
slots,
filter_weekdays=[0],
)
table1_c2_slots = self._filter_appointment_slots(
slots,
filter_weekdays=[0],
filter_resources=table1_c2,
)
table1_c2_c4_slots = self._filter_appointment_slots(
slots,
filter_weekdays=[0],
filter_resources=(table1_c2 + table1_c4),
)
self.assertTrue(len(resource_slots) > 0)
self.assertEqual(len(table1_c2_slots), 0)
self.assertEqual(len(resource_slots), len(table1_c2_c4_slots))
@users('apt_manager')
def test_appointment_resources_combinable_with_time_resource(self):
""" Check that the last resource available is correctly computed with linked resources """
table_c2, table_c3 = self.env["appointment.resource"].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 2,
'name': 'Table for 2',
'sequence': 1,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 3,
'name': 'Table for 3',
'sequence': 2,
}])
table_c2.linked_resource_ids = table_c3
self.apt_type_resource.assign_method = 'time_resource'
start = datetime(2022, 2, 14, 15, 0, 0)
end = start + timedelta(hours=1)
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=2)
resource_slots_c2 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
available_resources_c2 = [resource['id'] for resource in resource_slots_c2[0]['available_resources']]
available_resources_c5 = [resource['id'] for resource in resource_slots_c5[0]['available_resources']]
self.assertEqual(set(available_resources_c2), set((table_c2 + table_c3).ids),
"Both resources should be available as the asked capacity is available in both")
self._test_slot_generate_available_resources(self.apt_type_resource, 2, 'UTC', start, end, table_c2 + table_c3, available_resources_c2, reference_date=self.reference_now)
self.assertEqual(set(available_resources_c5), set((table_c2 + table_c3).ids),
"Both resources should be available as the asked capacity correspond to the remaining total")
self._test_slot_generate_available_resources(self.apt_type_resource, 5, 'UTC', start, end, table_c2 + table_c3, available_resources_c5, reference_date=self.reference_now)
# Create a booking for the first resource
self.env['calendar.event'].with_context(self._test_context).create({
'appointment_type_id': self.apt_type_resource.id,
'booking_line_ids': [(0, 0, {'appointment_resource_id': table_c2.id, 'capacity_reserved': 1, 'capacity_used': 1})],
'name': 'Booking 1',
'start': start,
'stop': end,
})
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=2)
resource_slots_c2 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
available_resources_c2 = [resource['id'] for resource in resource_slots_c2[0]['available_resources']]
self.assertEqual(set(available_resources_c2), set(table_c3.ids),
"Only the table for 3 should be remaining as the other is booked")
self._test_slot_generate_available_resources(self.apt_type_resource, 2, 'UTC', start, end, table_c3, available_resources_c2, reference_date=self.reference_now)
self.assertEqual(len(resource_slots_c5), 0, "There should not be enough availability for the asked capacity")
@users('apt_manager')
def test_appointment_resources_sequence(self):
""" Check that the sequence is correctly taken into account when selecting resources for slots """
resource_1, resource_2 = self.env['appointment.resource'].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 4,
'name': 'Resource 1',
'sequence': 5,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 10,
'name': 'Resource 2',
'sequence': 10,
}])
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC')
resource_slots_c1 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
resource_slots_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=6)
resource_slots_c6 = self._filter_appointment_slots(slots)
available_resources_c1 = [resource['id'] for resource in resource_slots_c1[0]['available_resources']]
available_resources_c4 = [resource['id'] for resource in resource_slots_c4[0]['available_resources']]
available_resources_c6 = [resource['id'] for resource in resource_slots_c6[0]['available_resources']]
self.assertTrue(len(resource_slots_c1) > 0)
self.assertListEqual(available_resources_c1, resource_1.ids)
self.assertTrue(len(resource_slots_c4) > 0)
self.assertListEqual(available_resources_c4, resource_1.ids)
self.assertTrue(len(resource_slots_c6) > 0)
self.assertListEqual(available_resources_c6, resource_2.ids)
resource_2.sequence = 1
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC')
resource_slots_c1 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
resource_slots_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=6)
resource_slots_c6 = self._filter_appointment_slots(slots)
available_resources_c1 = [resource['id'] for resource in resource_slots_c1[0]['available_resources']]
available_resources_c4 = [resource['id'] for resource in resource_slots_c4[0]['available_resources']]
available_resources_c6 = [resource['id'] for resource in resource_slots_c6[0]['available_resources']]
self.assertTrue(len(resource_slots_c1) > 0)
self.assertListEqual(available_resources_c1, resource_2.ids)
self.assertTrue(len(resource_slots_c4) > 0)
self.assertListEqual(available_resources_c4, resource_1.ids)
self.assertTrue(len(resource_slots_c6) > 0)
self.assertListEqual(available_resources_c6, resource_2.ids)
@users('apt_manager')
def test_appointment_resources_shareable(self):
""" Check shareable resources are correctly used """
resource, resource_shareable = self.env['appointment.resource'].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 5,
'name': 'Resource',
'sequence': 5,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 10,
'name': 'Resource Shareable',
'sequence': 10,
'shareable': True,
}])
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
resource_slots_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=6)
resource_slots_c6 = self._filter_appointment_slots(slots)
available_resources_c4 = [resource['id'] for resource in resource_slots_c4[0]['available_resources']]
available_resources_c6 = [resource['id'] for resource in resource_slots_c6[0]['available_resources']]
self.assertListEqual(available_resources_c4, resource.ids)
self.assertListEqual(available_resources_c6, resource_shareable.ids)
start = datetime(2022, 2, 14, 15, 0, 0)
end = start + timedelta(hours=1)
self.env['calendar.event'].with_context(self._test_context).create([{
'appointment_type_id': self.apt_type_resource.id,
'booking_line_ids': [(0, 0, {'appointment_resource_id': resource_shareable.id, 'capacity_reserved': 4, 'capacity_used': 4})],
'name': 'Booking 1',
'start': start,
'stop': end,
}, {
'appointment_type_id': self.apt_type_resource.id,
'booking_line_ids': [(0, 0, {'appointment_resource_id': resource_shareable.id, 'capacity_reserved': 2, 'capacity_used': 2})],
'name': 'Booking 2',
'start': start,
'stop': end,
}])
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
resource_slots_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=6)
resource_slots_c6 = self._filter_appointment_slots(slots)
available_resources_c4 = [resource['id'] for resource in resource_slots_c4[0]['available_resources']]
available_resources_c5 = [resource['id'] for resource in resource_slots_c5[0]['available_resources']]
available_resources_c6 = resource_slots_c6 and [resource['id'] for resource in resource_slots_c6[0]['available_resources']]
self.assertListEqual(available_resources_c4, resource.ids)
self.assertListEqual(available_resources_c5, resource.ids)
self.assertListEqual(available_resources_c6, [])
resource_shareable.sequence = 1
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
resource_slots_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
available_resources_c4 = [resource['id'] for resource in resource_slots_c4[0]['available_resources']]
available_resources_c5 = [resource['id'] for resource in resource_slots_c5[0]['available_resources']]
self.assertListEqual(available_resources_c4, resource_shareable.ids)
self.assertListEqual(available_resources_c5, resource.ids)
@users('apt_manager')
def test_appointment_resources_shareable_linked_with_capacity(self):
""" Check that resources shareable linked together with the capacity management
correctly compute the remaining capacity """
resource_1, resource_2 = self.env['appointment.resource'].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 5,
'name': 'Resource 1',
'sequence': 5,
'shareable': True,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 6,
'name': 'Resource 2',
'sequence': 10,
'shareable': True,
}])
resource_1.linked_resource_ids = resource_2
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=7)
resource_slots_c7 = self._filter_appointment_slots(slots)
available_resources_c5 = [resource['id'] for resource in resource_slots_c5[0]['available_resources']]
available_resources_c7 = [resource['id'] for resource in resource_slots_c7[0]['available_resources']]
self.assertListEqual(available_resources_c5, resource_1.ids,
"Should pick the first resource as it's a best match")
self.assertListEqual(available_resources_c7, (resource_1 + resource_2).ids,
"Should pick both resources as asked capacity exceeds each resource capacity")
# Create a booking for the first resource for all its capacity
start = datetime(2022, 2, 14, 15, 0, 0)
end = start + timedelta(hours=1)
self.env['calendar.event'].with_context(self._test_context).create({
'appointment_type_id': self.apt_type_resource.id,
'booking_line_ids': [(0, 0, {'appointment_resource_id': resource_1.id, 'capacity_reserved': 5, 'capacity_used': 5})],
'name': 'Booking 1',
'start': start,
'stop': end,
})
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
resource_slots_c5 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=7)
resource_slots_c7 = self._filter_appointment_slots(slots)
available_resources_c5 = [resource['id'] for resource in resource_slots_c5[0]['available_resources']]
self.assertListEqual(available_resources_c5, resource_2.ids,
"Should pick the second resource as the first one is already taken")
self.assertEqual(len(resource_slots_c7), 0,
"There should not be enough capacity remaining for the asked capacity")
@users('apt_manager')
def test_appointment_resources_shareable_performance(self):
"""" Simple use case with shareable resources """
appointment = self.env['appointment.type'].create({
'appointment_tz': 'UTC',
'assign_method': 'time_auto_assign',
'min_schedule_hours': 1.0,
'max_schedule_days': 8,
'name': 'Test',
'resource_manage_capacity': True,
'schedule_based_on': 'resources',
'slot_ids': [(0, 0, {
'weekday': str(self.reference_monday.isoweekday()),
'start_hour': 6,
'end_hour': 18,
})],
})
self.env['appointment.resource'].create([
{
'appointment_type_ids': appointment.ids,
'capacity': 5,
'name': 'Resource %s' % i,
'shareable': True,
} for i in range(20)
])
# Flush everything, notably tracking values, as it may impact performances
self.flush_tracking()
with freeze_time(self.reference_now):
with self.assertQueryCount(default=12):
appointment._get_appointment_slots('UTC')
@users('apt_manager')
def test_appointment_resources_restrict_resources(self):
"""" Check that resources restricted on slots are taken into account """
appointment = self.env['appointment.type'].create({
'appointment_tz': 'UTC',
'assign_method': 'time_resource', # easier to check all resources available for each slot
'min_schedule_hours': 1.0,
'max_schedule_days': 5,
'name': 'Test',
'resource_manage_capacity': True,
'schedule_based_on': 'resources',
'slot_ids': [(0, 0, {
'weekday': str(self.reference_monday.isoweekday()),
'start_hour': 15,
'end_hour': 16,
}), (0, 0, {
'weekday': str(self.reference_monday.isoweekday() + 1),
'start_hour': 15,
'end_hour': 16,
}), (0, 0, {
'weekday': str(self.reference_monday.isoweekday() + 2),
'start_hour': 15,
'end_hour': 16,
})],
})
resource1, resource2, resource3 = self.env['appointment.resource'].create([
{
'appointment_type_ids': appointment.ids,
'name': 'Resource %s' % i,
} for i in range(3)
])
appointment.slot_ids[0].restrict_to_resource_ids = resource1.ids
appointment.slot_ids[1].restrict_to_resource_ids = (resource2 + resource3).ids
with freeze_time(self.reference_now):
slots = appointment._get_appointment_slots('UTC')
monday_slots = self._filter_appointment_slots(slots, filter_weekdays=[0])
tuesday_slots = self._filter_appointment_slots(slots, filter_weekdays=[1])
wednesday_slots = self._filter_appointment_slots(slots, filter_weekdays=[2])
available_resources_monday = [resource['id'] for resource in monday_slots[0]['available_resources']]
available_resources_tuesday = [resource['id'] for resource in tuesday_slots[0]['available_resources']]
available_resources_wednesday = [resource['id'] for resource in wednesday_slots[0]['available_resources']]
self.assertListEqual(available_resources_monday, resource1.ids)
self.assertListEqual(available_resources_tuesday, (resource2 + resource3).ids)
self.assertListEqual(available_resources_wednesday, (resource1 + resource2 + resource3).ids)
@users('apt_manager')
def test_appointment_resources_assign_time_resource(self):
""" Check that all resources are available with time_resource assign method. """
self.apt_type_resource.assign_method = 'time_resource'
nordic, scandinavian, snow = self.env["appointment.resource"].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 4,
'name': 'Nordic',
'sequence': 2,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 8,
'name': 'Scandinavian',
'sequence': 3,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 6,
'name': 'Snow',
'sequence': 4,
}])
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC')
available_resources_c1 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=4)
available_resources_c4 = self._filter_appointment_slots(slots)
slots = self.apt_type_resource._get_appointment_slots('UTC', asked_capacity=5)
available_resources_c5 = self._filter_appointment_slots(slots)
available_resources_c1 = [resource['id'] for resource in available_resources_c1[0]['available_resources']]
available_resources_c4 = [resource['id'] for resource in available_resources_c4[0]['available_resources']]
available_resources_c5 = [resource['id'] for resource in available_resources_c5[0]['available_resources']]
self.assertListEqual(available_resources_c1, (nordic + scandinavian + snow).ids,
"All resources should be available with asked_capacity=1")
self.assertListEqual(available_resources_c4, (nordic + scandinavian + snow).ids,
"All resources should be available, the perfect matches are ignored with time_resource assign method")
self.assertListEqual(available_resources_c5, (scandinavian + snow).ids)
@users('apt_manager')
def test_appointment_resources_booked_for_all_appointments(self):
""" Check that a resource can only be booked once, even if shared among appointment_types """
paddle_court = self.env["appointment.resource"].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 1,
'name': 'Paddle Court',
}])
self.apt_type_resource_2 = self.apt_type_resource.copy()
# Assert initial data
with freeze_time(self.reference_now):
slots = self.apt_type_resource_2._get_appointment_slots('UTC')
resource_slots = self._filter_appointment_slots(slots)
self.assertEqual(len(resource_slots), 1)
# Resource is booked on its slot on appointment_type_resource
self.env['calendar.event'].with_context(self._test_context).create({
'appointment_type_id': self.apt_type_resource.id,
'booking_line_ids': [(0, 0, {
'appointment_resource_id': paddle_court.id,
'capacity_reserved': 1,
'capacity_used': paddle_court.capacity
})],
'name': 'Booking 1',
'start': datetime(2022, 2, 14, 15, 0, 0),
'stop': datetime(2022, 2, 14, 15, 0, 0) + timedelta(hours=1),
})
# Check other appointment_type availabilities
with freeze_time(self.reference_now):
slots = self.apt_type_resource_2._get_appointment_slots('UTC')
resource_slots = self._filter_appointment_slots(slots)
self.assertEqual(len(resource_slots), 0, "Once a resource is booked on a slot, it should not be available anymore to other appointment types.")
@users('apt_manager')
def test_appointment_resources_duplicate(self):
""" Check that we can correctly duplicate resource bookings """
table, other_table = self.env["appointment.resource"].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 2,
'name': 'Table for 2',
'sequence': 1,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 4,
'name': 'Table for 4',
'sequence': 2,
}])
start = datetime(2022, 2, 14, 15, 0, 0)
end = start + timedelta(hours=1)
booking = self.env['calendar.event'].with_context(self._test_context).create({
'appointment_type_id': self.apt_type_resource.id,
'booking_line_ids': [
(0, 0, {'appointment_resource_id': table.id, 'capacity_reserved': 2, 'capacity_used': 2}),
(0, 0, {'appointment_resource_id': other_table.id, 'capacity_reserved': 3}),
],
'name': 'Resource booking',
'start': start,
'stop': end,
})
duplicate = booking.copy()
self.assertEqual(booking.name, duplicate.name, "Resource booking should have duplicated correctly")
self.assertListEqual(booking.resource_ids.ids, duplicate.resource_ids.ids, "Resources should be the same")
self.assertEqual(booking.resource_total_capacity_used, duplicate.resource_total_capacity_used, "Capacity used should be the same")
self.assertEqual(booking.resource_total_capacity_reserved, duplicate.resource_total_capacity_reserved, "Capacity reserved should be the same")
self.assertListEqual(
[bl.capacity_reserved for bl in booking.booking_line_ids],
[bl.capacity_reserved for bl in duplicate.booking_line_ids],
"Capacity reserved should be the same for each booking line",
)
@users('apt_manager')
def test_appointment_resources_without_capacity_management(self):
""" Check use case where capacity management is not activated """
self.apt_type_resource.resource_manage_capacity = False
resource_1, resource_2, resource_3 = self.env['appointment.resource'].create([{
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 6,
'name': 'Resource 1',
'sequence': 1,
'shareable': True,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 4,
'name': 'Resource 2',
'sequence': 2,
}, {
'appointment_type_ids': self.apt_type_resource.ids,
'capacity': 1,
'name': 'Resource 3',
'sequence': 3
}])
resource_2.linked_resource_ids = resource_3
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC')
resource_slots = self._filter_appointment_slots(slots)
available_resources = [resource['id'] for resource in resource_slots[0]['available_resources']]
self.assertListEqual(available_resources, resource_1.ids)
start = datetime(2022, 2, 14, 15, 0, 0)
end = start + timedelta(hours=1)
booking = self.env['calendar.event'].with_context(self._test_context).create({
'appointment_type_id': self.apt_type_resource.id,
'booking_line_ids': [(0, 0, {'appointment_resource_id': resource_1.id, 'capacity_reserved': 1, 'capacity_used': resource_1.capacity})],
'name': 'Booking 1',
'start': start,
'stop': end,
})
self.assertEqual(booking.booking_line_ids.capacity_reserved, 1)
self.assertEqual(booking.booking_line_ids.capacity_used, 6,
"When we don't manage capacity, the shareable option should be ignored")
with freeze_time(self.reference_now):
slots = self.apt_type_resource._get_appointment_slots('UTC')
resource_slots = self._filter_appointment_slots(slots)
available_resources = [resource['id'] for resource in resource_slots[0]['available_resources']]
self.assertListEqual(available_resources, resource_2.ids,
"The first resource should now be unavailable and the second one is chosen")