@@ -18,22 +18,20 @@ class AppointmentType(models.Model):
18
18
19
19
capacity_type = fields .Selection (
20
20
[
21
- ("single_booking " , "Single Booking" ),
21
+ ("one_booking " , "One Booking" ),
22
22
("multiple_bookings" , "Multiple Bookings" ),
23
23
("multiple_seats" , "Multiple Seats" ),
24
24
],
25
25
string = "Capacity Type" ,
26
26
required = True ,
27
- default = "single_booking " ,
27
+ default = "one_booking " ,
28
28
)
29
-
30
29
user_capacity_count = fields .Integer (
31
30
"User cpacity count" ,
32
31
default = 1 ,
33
32
help = "Maximum number of users bookings per slot (for multiple bookings or multiple seats)." ,
34
33
)
35
34
36
-
37
35
@api .constrains ("user_capacity_count" )
38
36
def _check_user_capacity_count (self ):
39
37
for record in self :
@@ -91,7 +89,7 @@ def _slot_availability_is_resource_available(self, slot, resource, availability_
91
89
slot_start_dt_utc , slot_end_dt_utc = slot ['UTC' ][0 ], slot ['UTC' ][1 ]
92
90
resource_to_bookings = availability_values .get ('resource_to_bookings' )
93
91
# Check if there is already a booking line for the time slot and make it available
94
- # only if the resource is shareable and the capacity_type is not single_booking .
92
+ # only if the resource is shareable and the capacity_type is not one_booking .
95
93
# This avoid to mark the resource as "available" and compute unnecessary remaining capacity computation
96
94
# because of potential linked resources.
97
95
if resource_to_bookings .get (resource ):
@@ -108,7 +106,6 @@ def _slot_availability_is_resource_available(self, slot, resource, availability_
108
106
109
107
return True
110
108
111
-
112
109
def _slot_availability_select_best_resources (self , capacity_info , asked_capacity ):
113
110
""" Check and select the best resources for the capacity needed
114
111
:params main_resources_remaining_capacity <dict>: dict containing remaining capacities of resources available
@@ -120,7 +117,7 @@ def _slot_availability_select_best_resources(self, capacity_info, asked_capacity
120
117
available_resources = self .env ['appointment.resource' ].concat (* capacity_info .keys ()).sorted ('sequence' )
121
118
if not available_resources :
122
119
return self .env ['appointment.resource' ]
123
- if self .capacity_type == 'single_booking ' :
120
+ if self .capacity_type == 'one_booking ' :
124
121
return available_resources [0 ] if self .assign_method != 'time_resource' else available_resources
125
122
126
123
perfect_matches = available_resources .filtered (
@@ -209,10 +206,9 @@ def _slots_fill_users_availability(self, slots, start_dt, end_dt, filter_users=N
209
206
else :
210
207
slot ['staff_user_id' ] = available_staff_users
211
208
212
-
213
-
214
209
def _slot_availability_is_user_available (self , slot , staff_user , availability_values , asked_capacity = 1 ):
215
- """ This method verifies if the user is available on the given slot.
210
+ """
211
+ This method verifies if the user is available on the given slot.
216
212
It checks whether the user has calendar events clashing and if he
217
213
is included in slot's restricted users.
218
214
@@ -235,8 +231,7 @@ def _slot_availability_is_user_available(self, slot, staff_user, availability_va
235
231
return False
236
232
237
233
partner_to_events = availability_values .get ('partner_to_events' ) or {}
238
- users_remaining_capacity = self ._get_users_remaining_capacity (staff_user , slot ['UTC' ][0 ], slot ['UTC' ][1 ],
239
- availability_values = availability_values )
234
+ users_remaining_capacity = self ._get_users_remaining_capacity (staff_user , slot ['UTC' ][0 ], slot ['UTC' ][1 ])
240
235
if partner_to_events .get (staff_user .partner_id ):
241
236
for day_dt in rrule .rrule (freq = rrule .DAILY ,
242
237
dtstart = slot_start_dt_utc ,
@@ -247,7 +242,7 @@ def _slot_availability_is_user_available(self, slot, staff_user, availability_va
247
242
# return False
248
243
for event in day_events :
249
244
if not event .allday and (event .start < slot_end_dt_utc and event .stop > slot_start_dt_utc ):
250
- if self .capacity_type != "single_booking " and self == event .appointment_type_id :
245
+ if self .capacity_type != "one_booking " and self == event .appointment_type_id :
251
246
if users_remaining_capacity ['total_remaining_capacity' ] >= asked_capacity :
252
247
continue
253
248
return False
@@ -260,13 +255,12 @@ def _slot_availability_is_user_available(self, slot, staff_user, availability_va
260
255
return False
261
256
return True
262
257
263
- def _get_users_remaining_capacity (self , users , slot_start_utc , slot_stop_utc , availability_values = None ):
264
- """
258
+ def _get_users_remaining_capacity (self , users , slot_start_utc , slot_stop_utc ):
259
+ """
265
260
Compute the remaining capacity for users in a specific time slot.
266
261
:param <res.users> users : record containing one or a multiple of user
267
262
:param datetime slot_start_utc: start of slot (in naive UTC)
268
263
:param datetime slot_stop_utc: end of slot (in naive UTC)
269
- :param dict availability_values: dict of data used for availability check.
270
264
271
265
:return remaining_capacity:
272
266
"""
@@ -277,17 +271,12 @@ def _get_users_remaining_capacity(self, users, slot_start_utc, slot_stop_utc, av
277
271
if not all_users :
278
272
return {'total_remaining_capacity' : 0 }
279
273
280
- booking_lines = self .env ['appointment.booking.line' ].sudo ()
281
- if availability_values is None :
282
- availability_values = self . _slot_availability_prepare_users_values ( all_users , slot_start_utc , slot_stop_utc )
283
- users_to_bookings = availability_values . get ( 'users_to_bookings ' , {})
284
-
274
+ booking_lines = self .env ['appointment.booking.line' ].sudo (). search ([
275
+ ( 'appointment_user_id' , 'in' , all_users . ids ),
276
+ ( 'event_start' , '<' , slot_stop_utc ),
277
+ ( 'event_stop ' , '>' , slot_start_utc ),
278
+ ])
285
279
users_remaining_capacity = {}
286
- for user , booking_lines_ids in users_to_bookings .items ():
287
- if user in all_users :
288
- booking_lines |= booking_lines_ids
289
- booking_lines = booking_lines .filtered (lambda bl : bl .event_start < slot_stop_utc and bl .event_stop > slot_start_utc )
290
-
291
280
users_booking_lines = booking_lines .grouped ('appointment_user_id' )
292
281
293
282
for user in all_users :
@@ -296,50 +285,9 @@ def _get_users_remaining_capacity(self, users, slot_start_utc, slot_stop_utc, av
296
285
users_remaining_capacity .update (total_remaining_capacity = sum (users_remaining_capacity .values ()))
297
286
return users_remaining_capacity
298
287
299
- def _slot_availability_prepare_users_values (self , staff_users , start_dt , end_dt ):
300
- """
301
- Override to add booking values.
302
-
303
- :return: update ``super()`` values with users booking vaues, formatted like
304
- {
305
- 'users_to_bookings': dict giving their corresponding bookings within the given time range
306
- (see ``_slot_availability_prepare_users_bookings_values()``);
307
- }
308
- """
309
- users_values = super ()._slot_availability_prepare_users_values (staff_users , start_dt , end_dt )
310
- users_values .update (self ._slot_availability_prepare_users_bookings_values (staff_users , start_dt , end_dt ))
311
- return users_values
312
-
313
- def _slot_availability_prepare_users_bookings_values (self , users , start_dt_utc , end_dt_utc ):
314
- """
315
- This method retrieves and organizes bookings for the given users within the specified time range.
316
- Users may handle multiple appointment types, so all overlapping bookings must be considered
317
- to prevent double booking.
318
-
319
- :param <res.users> users: A recordset of staff users for whom availability is being checked.
320
- :param datetime start_dt_utc: The start of the appointment check boundary in UTC.
321
- :param datetime end_dt_utc: The end of the appointment check boundary in UTC.
322
-
323
- :return: A dict containing booking data, formatted as:
324
- {
325
- 'users_to_bookings': A dict mapping user IDs to their booking records,
326
- }
327
- """
328
- users_to_bookings = {}
329
- if users :
330
- booking_lines = self .env ['appointment.booking.line' ].sudo ().search ([
331
- ('appointment_user_id' , 'in' , users .ids ),
332
- ('event_start' , '<' , end_dt_utc ),
333
- ('event_stop' , '>' , start_dt_utc ),
334
- ])
335
-
336
- users_to_bookings = booking_lines .grouped ('appointment_user_id' )
337
- return {
338
- 'users_to_bookings' : users_to_bookings ,
339
- }
340
-
341
288
def _get_appointment_slots (self , timezone , filter_users = None , filter_resources = None , asked_capacity = 1 , reference_date = None ):
342
- """ Fetch available slots to book an appointment.
289
+ """
290
+ Fetch available slots to book an appointment.
343
291
344
292
:param str timezone: timezone string e.g.: 'Europe/Brussels' or 'Etc/GMT+1'
345
293
:param <res.users> filter_users: filter available slots for those users (can be a singleton
@@ -390,13 +338,13 @@ def _get_appointment_slots(self, timezone, filter_users=None, filter_resources=N
390
338
if self .category == 'custom' and unique_slots :
391
339
# Custom appointment type, the first day should depend on the first slot datetime
392
340
start_first_slot = unique_slots [0 ].start_datetime
393
- first_day_utc = start_first_slot if reference_date > start_first_slot else reference_date
341
+ first_day_utc = min ( reference_date , start_first_slot )
394
342
first_day = requested_tz .fromutc (first_day_utc + relativedelta (hours = self .min_schedule_hours ))
395
343
appointment_duration_days = (unique_slots [- 1 ].end_datetime .date () - reference_date .date ()).days
396
344
last_day = requested_tz .fromutc (reference_date + relativedelta (days = appointment_duration_days ))
397
345
elif self .category == 'punctual' :
398
346
# Punctual appointment type, the first day is the start_datetime if it is in the future, else the first day is now
399
- first_day = requested_tz .fromutc (self . start_datetime if self .start_datetime > now else now )
347
+ first_day = requested_tz .fromutc (max ( now , self .start_datetime ) )
400
348
last_day = requested_tz .fromutc (self .end_datetime )
401
349
else :
402
350
# Recurring appointment type
0 commit comments