# Copyright 2024 Moduon Team S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0) from collections import defaultdict from odoo import fields, models from odoo.addons.resource.models.resource import Intervals class ResourceCalendar(models.Model): _inherit = "resource.calendar" def _get_general_time_off_intervals_by_state(self, domain=None, any_calendar=False): """Get a map of State to Intervals of leaves for the given domain.""" domain = domain or [] # Respect the any_calendar option if not any_calendar: domain = [("calendar_id", "in", self.ids + [False])] + domain # Ensure that the leaves are not related to a specific resource domain = [("resource_id", "=", False)] + domain # Iterate all matching leaves state_interval_map = defaultdict(Intervals) for res_cal_leave in self.env["resource.calendar.leaves"].search(domain): # Convert to aware datetime with user timezone dttf = fields.Datetime.context_timestamp( res_cal_leave, res_cal_leave.date_from ) dttt = fields.Datetime.context_timestamp( res_cal_leave, res_cal_leave.date_to ) # Add the interval to the corresponding State or False if no state if res_cal_leave.state_ids: for state in res_cal_leave.state_ids: state_interval_map[state.id] |= Intervals( [(dttf, dttt, res_cal_leave)] ) else: state_interval_map[False] |= Intervals([(dttf, dttt, res_cal_leave)]) return state_interval_map def _leave_intervals_batch( self, start_dt, end_dt, resources=None, domain=None, tz=None, any_calendar=False ): # All interval batches (with/out State) res = super()._leave_intervals_batch( start_dt, end_dt, resources=resources, domain=domain, tz=tz, any_calendar=any_calendar, ) # Overwrite the result if resources are specified, but only with # the global leaves (skipping the local leaves) using the domain for resource in resources or []: res.update( super()._leave_intervals_batch( start_dt, end_dt, resources=resource, domain=[("state_ids", "=", False)], # Force global leaves tz=tz, any_calendar=any_calendar, ) ) # Get Local interval batches by State state_interval_map = self._get_general_time_off_intervals_by_state( domain=domain, any_calendar=any_calendar ) # Post-process generated intervals for resource_id in res.keys(): if not resource_id: # If no resource is specified, only consider Global leaves res[resource_id] = state_interval_map[False] else: # If resource is specified, add Local Leaves to the result if # the State of its Work Address has Local leaves resource_state_id = ( self.env["hr.employee"] .sudo() .search([("resource_id", "=", resource_id)], limit=1) .address_id.state_id.id ) if resource_state_id in state_interval_map: res[resource_id] |= state_interval_map[resource_state_id] return res