Files
odoo_source/addons/hr_contract/models/resource_resource.py
T
Audric Onockx (auon) f95555d0e5 [FIX] hr,hr_contract,resource: allocate hours before resource creation
Steps :
- On a new DB (no demo data). Say created at 15:00. - Go to planning.
- Add a shift for today.
- Set the dates from 08:00 to 17:00.

Issue :
The 'Allocated Time' = 02:00.

Cause :
We used to count from the resource creation min to the departure max. So, in this case, not from 08:00, but from 15:00.
While this might seem logical, it confuses users in onboarding.

Fix :
Calculate the whole time, regardless of the resource lifespan.

Notes :
- Similar issues solved with this commit :
> Once the shift validated, the avatar progress bar uses
the same allocated time.
> Same in Project Task gantt view.
- When contract is installed, if the resource does not have a contract, the Allocated Time = 0. Now, it is calculated from the resource calendar.

task-2983993

closes odoo/odoo#102732

X-original-commit: 6a61d1c4c56075ade36f6f32e7a61f1f6c771a6f
Related: odoo/enterprise#32547
Signed-off-by: Laurent Stukkens (ltu) <ltu@odoo.com>
2022-10-08 09:42:49 +02:00

57 lines
3.1 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
from datetime import datetime
from pytz import timezone
from odoo import models
from odoo.addons.resource.models.resource import Intervals
class ResourceResource(models.Model):
_inherit = 'resource.resource'
def _get_calendars_validity_within_period(self, start, end, default_company=None):
assert start.tzinfo and end.tzinfo
if not self:
return super()._get_calendars_validity_within_period(start, end, default_company=default_company)
calendars_within_period_per_resource = defaultdict(lambda: defaultdict(Intervals)) # keys are [resource id:integer][calendar:self.env['resource.calendar']]
# Employees that have ever had an active contract
employee_ids_with_active_contracts = {
contract['employee_id'][0] for contract in
self.env['hr.contract']._read_group(
domain=[
('employee_id', 'in', self.employee_id.ids),
'|', ('state', '=', 'open'),
'|', ('state', '=', 'close'),
'&', ('state', '=', 'draft'), ('kanban_state', '=', 'done')
],
fields=['employee_id'], groupby=['employee_id']
)
}
resource_without_contract = self.filtered(
lambda r: not r.employee_id\
or not r.employee_id.id in employee_ids_with_active_contracts\
or r.employee_id.employee_type not in ['employee', 'student']
)
if resource_without_contract:
calendars_within_period_per_resource.update(
super(ResourceResource, resource_without_contract)._get_calendars_validity_within_period(start, end, default_company=default_company)
)
resource_with_contract = self - resource_without_contract
if not resource_with_contract:
return calendars_within_period_per_resource
timezones = {resource.tz for resource in resource_with_contract}
date_start = min(start.astimezone(timezone(tz)).date() for tz in timezones)
date_end = max(end.astimezone(timezone(tz)).date() for tz in timezones)
contracts = resource_with_contract.employee_id._get_contracts(
date_start, date_end, states=['open', 'draft', 'close']
).filtered(lambda c: c.state in ['open', 'close'] or c.kanban_state == 'done')
for contract in contracts:
tz = timezone(contract.employee_id.tz)
calendars_within_period_per_resource[contract.employee_id.resource_id.id][contract.resource_calendar_id] |= Intervals([(
tz.localize(datetime.combine(contract.date_start, datetime.min.time())) if contract.date_start > start.astimezone(tz).date() else start,
tz.localize(datetime.combine(contract.date_end, datetime.max.time())) if contract.date_end and contract.date_end < end.astimezone(tz).date() else end,
self.env['resource.calendar.attendance']
)])
return calendars_within_period_per_resource