Resources¶
A resource (resource.resource) is something that works according to a
working schedule (calendar_id, required), in a
timezone (tz, required). It is either a human (resource_type = 'user', optionally linked to a
user) or a material resource (a machine, a meeting room).
Business models rarely use resource.resource directly: they inherit from the abstract
resource.mixin, which creates a resource for each record and exposes its calendar, timezone and
the work time computations. hr.employee and mrp.workcenter are the main examples.
The resource mixin¶
A model inheriting from resource.mixin gets:
resource_id: theresource.resourceof the record, created automatically oncreate(_prepare_resource_valuesbuilds its values);resource_calendar_id,company_idandtz, related to the resource.
class MaintenanceTeam(models.Model):
_name = 'my.maintenance.team'
_inherit = ['resource.mixin']
_description = 'Maintenance Team'
name = fields.Char(related='resource_id.name', store=True, readonly=False)
The mixin provides the usual work time computations for a batch of records. Contrary to the
calendar-level methods of resource.calendar, they take the leaves of each resource into
account:
_get_work_days_data_batch()The work duration of each record between two datetimes, as
{record_id: {'days': float, 'hours': float}}._get_leave_days_data_batch()The leave duration of each record, in the same format.
_list_work_time_per_day()The work hours of each record, per day:
{record_id: [(date, hours), ...]}._adjust_to_calendar()Snaps a period to the working hours of each record: the first work interval start of the start day and the last work interval end of the end day.
_get_calendars()The calendar of each record at a date.
hr.employeeoverrides it to return the calendar of the employee’s version at that date.
Example
from datetime import datetime
from zoneinfo import ZoneInfo
employees = env['hr.employee'].search([], limit=3)
brussels = ZoneInfo('Europe/Brussels')
start = datetime(2026, 10, 19, tzinfo=brussels)
end = datetime(2026, 10, 24, tzinfo=brussels)
employees._get_work_days_data_batch(start, end)
# {employee_id: {'days': 5.0, 'hours': 40.0}, ...}
employees._list_work_time_per_day(start, end)
# {employee_id: [(date(2026, 10, 19), 8.0), (date(2026, 10, 20), 8.0), ...], ...}
Resources with several calendars¶
The calendar of a resource can change over time. In resource, a resource has a single
calendar, but hr makes it follow the versions of the employee. To support this, the methods of
resource.resource work with calendar validity periods:
_get_calendars_validity_within_period()Returns
{resource_id: {calendar: Intervals}}: which calendar applies to each resource, when, within a period. Inresource, one calendar over the whole period._get_valid_work_intervals()Returns the work intervals of each resource, computed with the right calendar on each period, as a tuple
({resource_id: Intervals}, {calendar_id: Intervals}). This is the method to use to get the work intervals of resources whose calendar may change, e.g. in planning applications._get_calendar_data_at()The calendar, hours per week and hours per day valid at a date.
_get_unavailable_intervals()The unavailable intervals of each resource, in UTC, for Gantt views.
Example
resources = employees.resource_id
work_intervals, calendar_intervals = resources._get_valid_work_intervals(start, end)
work_intervals[resources[0].id] # Intervals of the first resource
Flexible resources¶
Planning applications need a work budget rather than work intervals for resources with a
flexible calendar:
_get_flexible_resource_valid_work_intervals() returns
whole-day intervals with a daily and a weekly hours budget, and
_get_flexible_resource_work_hours() computes how many
hours can be consumed in some intervals within these budgets.
Pitfalls¶
_get_work_intervalis deprecated: use_adjust_to_calendar._adjust_to_calendarand the mixin methods accept naive datetimes and consider them as UTC._get_leave_days_data_batchand_list_work_time_per_dayuse the current calendar of the records (resource_calendar_id), while_get_work_days_data_batchuses_get_calendars.Pass
compute_leaves=Falsein the context of_list_work_time_per_dayto ignore leaves.
Reference¶
Original definition from resource¶
- model odoo.addons.resource.models.resource_resource.ResourceResource[código fonte]¶
- _name = resource.resource¶
- calendar_id: int¶
- Required
- Name
Working Time
- Comodel
Define the working schedule of the resource. Assign a flexible calendar for fully flexible working hours.
- time_efficiency: float¶
- Required
- Name
Efficiency Factor
- Default
100
This field is used to calculate the expected duration of a work order at this work center. For example, if a work order takes one hour and the efficiency factor is 100%, then the expected duration will be one hour. If the efficiency factor is 200%, however the expected duration will be 30 minutes.
- _get_resources_per_tz()[código fonte]¶
Group the resources by timezone, in the format expected by the
resources_per_tzargument of theresource.calendarinterval methods.- Retorna
{ZoneInfo: resource.resource recordset}(empty dict for no resource)- Tipo de retorno
- _get_calendars_validity_within_period(start, end, default_company=None)[código fonte]¶
Return, for each resource, the calendars it uses within the period and when each of them applies. Here a resource has a single calendar valid on the whole period;
hroverrides it so that an employee uses the calendar of each of its contract versions on their own validity period.- Parâmetros
start (datetime) – timezone-aware start of the period
end (datetime) – timezone-aware end of the period
default_company –
res.companywhose default calendar is used whenselfis empty (current company by default)
- Retorna
{resource_id: {resource.calendar: Intervals}}(nesteddefaultdict). Whenselfis empty, the keyFalsemaps the default calendar to the whole period.- Tipo de retorno
- _get_valid_work_intervals(start, end, calendars=None, compute_leaves=True)[código fonte]¶
Return the work intervals of each resource between
startandend, taking into account that a resource may use several calendars over the period (see_get_calendars_validity_within_period()): the work intervals of each calendar are restricted to its validity period, then united.This is the entry point to know when resources work, e.g. in planning, project or MRP scheduling. Flexible calendars give the intervals described in
resource.calendar._attendance_intervals_batch; a falsy calendar (possible with overrides) gives the whole period.- Parâmetros
start (datetime) – timezone-aware start of the period
end (datetime) – timezone-aware end of the period
calendars – optional extra
resource.calendarrecords for which the calendar-level work intervals are wanted in the second returned dictcompute_leaves (bool) – deduct leaves
- Retorna
a pair
(resource_work_intervals, calendar_work_intervals):{resource_id: Intervals}(in each resource’s timezone) and{calendar_id: Intervals}(calendar-level result of every calendar used)- Tipo de retorno
- _get_calendar_data_at(date_target, tz=False)[código fonte]¶
Return the calendar data applying to each resource at
date_target. Here it is the resource’s own calendar;hroverrides it to use the employee’s contract version valid at that date (date_targetbeing converted totz).- Retorna
{resource: {'resource_calendar_id': resource.calendar, 'hours_per_week': float, 'hours_per_day': float}}- Tipo de retorno
Return the periods during which each resource does not work between
startandend, according to its calendar (resource.calendar._unavailable_intervals_batch), e.g. to grey out Gantt views (planning, project, MRP).- Parâmetros
start (datetime) – start of the period, naive means UTC
end (datetime) – end of the period, naive means UTC
- Retorna
{resource_id: Intervals}expressed in UTC (only the leaves for flexible resources, which are missing when they have no leave)- Tipo de retorno
- _adjust_to_calendar(start, end, compute_leaves=True)[código fonte]¶
Snap
startandendto the closest work interval boundaries of each resource’s calendar (seeresource.calendar._get_closest_work_time), e.g. to propose default dates in planning or time off forms.startis matched against interval starts between the beginning of its day and the end of the day ofend;endis matched against interval ends betweenstartand the end of its day. Computation happens in the resource timezone.Example: with attendances 8:00-13:00 and 14:00-17:00,
start=9:00andend=18:00(same day) give(8:00, 17:00).- Parâmetros
start (datetime) – start to adjust, naive means UTC
end (datetime) – end to adjust, naive means UTC
compute_leaves (bool) – deduct leaves from the work intervals
- Retorna
{resource: (start, end)}; each value is in the timezone of the given argument (naive UTC if it was naive), orNoneif no boundary was found- Tipo de retorno
- _is_flexible()[código fonte]¶
Return whether the resource’s calendar is flexible (type
undefined), seeresource.calendar._is_flexible.
- _is_fully_flexible()[código fonte]¶
Return whether the resource’s calendar is fully flexible (no attendance and no hours target), see
resource.calendar._is_fully_flexible.
- _get_flexible_resource_valid_work_intervals(start, end)[código fonte]¶
Flexible counterpart of
_get_valid_work_intervals(), for resources that all have a flexible calendar. Since they have no attendance, it returns availability as whole days plus hour budgets, to be consumed by_get_flexible_resource_work_hours().The budgets are computed on the full weeks (per the user language’s first day of the week) containing the period. Each leave day (leaves counted as absence only, as for the work intervals) is removed from the intervals and its
hours_per_daydeducted from the budgets. Fully flexible resources get intervals but no budget.- Parâmetros
start (datetime) – timezone-aware start of the period
end (datetime) – timezone-aware end of the period
- Retorna
a triple
(work_intervals, hours_per_day, hours_per_week):{resource_id: Intervals}: whole-day intervals in the resource timezone, leave days removed, restricted to[start, end];{resource_id: {date: float}}: daily budget (at mosthours_per_day), for the days of the period;{resource_id: {(year, week_number): float}}: weekly budget (at mosthours_per_week, or the calendar’s full time hours).
Three empty dicts when
selfis empty.- Tipo de retorno
- _get_flexible_resource_work_hours(intervals, flexible_resources_hours_per_day, flexible_resources_hours_per_week, work_hours_per_day=None)[código fonte]¶
Return how many hours this flexible resource can work within
intervals, capped day by day by the daily budget and the remaining weekly budget, as computed by_get_flexible_resource_valid_work_intervals(). For a fully flexible resource (or withouthours_per_day), simply return the total duration ofintervals.- Parâmetros
intervals – intervals of the resource to evaluate, e.g. a planning slot intersected with its work intervals
flexible_resources_hours_per_day (dict) –
{date: float}budget of this resourceflexible_resources_hours_per_week (dict) –
{(year, week_number): float}budget of this resource (not modified)work_hours_per_day – optional
defaultdict(float)filled in place with the hours retained perdate
- Tipo de retorno
Original definition from resource¶
- model odoo.addons.resource.models.resource_mixin.ResourceMixin[código fonte]¶
- _name = resource.mixin¶
- _get_calendars(date_from=None)[código fonte]¶
Return the calendar of each record. Here it is always
resource_calendar_id;hroverrides it to return the calendar of the contract version valid atdate_from.- Parâmetros
date_from – date or datetime at which the calendar is wanted
- Retorna
{record_id: resource.calendar}(keys are ids ofself, not resources)- Tipo de retorno
- _get_work_days_data_batch(from_datetime, to_datetime, compute_leaves=True, calendar=None, domain=None)[código fonte]¶
Return the working time of each record between two datetimes, in days and hours: work intervals of its resource (its own leaves and global leaves deducted) converted by
resource.calendar._get_attendance_intervals_days_data.- Parâmetros
from_datetime (datetime) – start of the period, naive means UTC
to_datetime (datetime) – end of the period, naive means UTC
compute_leaves (bool) – deduct leaves
calendar –
resource.calendarto use for all records instead of the one given by_get_calendars()atfrom_datetimedomain (list) – leave domain,
Nonemeans[('count_as', '=', 'absence')]
- Retorna
{record_id: {'days': float, 'hours': float}}- Tipo de retorno
- _get_leave_days_data_batch(from_datetime, to_datetime, calendar=None, domain=None)[código fonte]¶
Return the leave time of each record between two datetimes, in days and hours: the part of its attendance intervals covered by leaves (its own and global ones), converted by
resource.calendar._get_attendance_intervals_days_data.For a fully flexible calendar, the whole period is returned (
daysbeing the number of full 24-hour periods, as a float).- Parâmetros
from_datetime (datetime) – start of the period, naive means UTC
to_datetime (datetime) – end of the period, naive means UTC
calendar –
resource.calendarto use for all records instead of theirresource_calendar_iddomain (list) – leave domain,
Nonemeans[('count_as', '=', 'absence')]
- Retorna
{record_id: {'days': float, 'hours': float}}- Tipo de retorno
- _list_work_time_per_day(from_datetime, to_datetime, calendar=None, domain=None)[código fonte]¶
Return the work hours of each record per day, from the work intervals of its resource (leaves deducted unless the context key
compute_leavesisFalse). Days are those of the interval starts, in the resource timezone.- Parâmetros
from_datetime (datetime) – start of the period, naive means UTC
to_datetime (datetime) – end of the period, naive means UTC
calendar –
resource.calendarto use for all records instead of theirresource_calendar_iddomain (list) – leave domain,
Nonemeans[('count_as', '=', 'absence')]
- Retorna
{record_id: [(date, hours), ...]}sorted by date, only days with work- Tipo de retorno
- _adjust_to_calendar(start, end)[código fonte]¶
Same as
resource.resource._adjust_to_calendar(leaves deducted), keyed by the records ofself.- Retorna
{record: (start, end)}- Tipo de retorno
- _prepare_resource_values(vals, tz)[código fonte]¶