oca-hr/odoo-bringout-oca-hr-holidays-resource_leaves_geographic/resource_leaves_geographic/models/resource_calendar.py
Ernad Husremovic dfcda4100c Move all OCA HR modules from oca-technical to dedicated oca-hr submodule
Reorganized 67 HR-related modules for better structure:
- Moved all odoo-bringout-oca-hr-* packages from packages/oca-technical/
- Now organized in dedicated packages/oca-hr/ submodule
- Includes attendance, expense, holiday, employee, and contract modules
- Maintains all module functionality while improving project organization

This creates a cleaner separation between general technical modules
and HR-specific functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 17:11:28 +02:00

87 lines
3.6 KiB
Python

# 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