Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX]hr_employee_calendar_planning:incorrect hours_per_day #1436

Draft
wants to merge 1 commit into
base: 16.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion hr_employee_calendar_planning/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Employee Calendar Planning",
"version": "16.0.1.1.9",
"version": "16.0.1.1.10",
"category": "Human Resources",
"website": "https://github.com/OCA/hr",
"author": "Tecnativa,Odoo Community Association (OCA)",
Expand All @@ -11,6 +11,7 @@
"depends": ["hr"],
"data": [
"security/ir.model.access.csv",
"data/data.xml",
"views/hr_employee_views.xml",
"views/resource_calendar_views.xml",
],
Expand Down
18 changes: 18 additions & 0 deletions hr_employee_calendar_planning/data/data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo noupdate="1">
<record id="ir_cron_create_time_reports" model="ir.cron">
<field name="name">Hr Employee: Recompute hours per day</field>
<field name="model_id" ref="hr_employee_calendar_planning.model_hr_employee" />
<field name="state">code</field>
<field name="code">model.cron_recompute_hours_per_day()</field>
<field name="interval_type">days</field>
<field name="interval_number">1</field>
<field name="numbercall">-1</field>
<field
name="nextcall"
eval="datetime.now().replace(hour=1, minute=0, second=0, microsecond=0) + timedelta(days=1)"
/>
<field name="doall" eval="True" />
<field name="active" eval="True" />
</record>
</odoo>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from openupgradelib import openupgrade


@openupgrade.migrate()
def migrate(env, version):
env["hr.employee"].cron_recompute_hours_per_day()
54 changes: 50 additions & 4 deletions hr_employee_calendar_planning/models/hr_employee.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Copyright 2022-2023 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from datetime import date

from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools import config
Expand Down Expand Up @@ -58,6 +60,43 @@
]
return vals

def _get_current_hours_per_day(self):
"""
Checks all calendars and uses the most specific first (date_start and date_end are set).
If no calendar matches it checks for calendars where no date_end is set.
If no calendar matches it checks for calendars where no date_start is set.
If no calendar matches it checks for calenders with neither date_start nor date_end.
It returns the hours_per_day of the first matching resource calendar.
If no calendar matches or no calendar exists -1 is returned.
:return: the current valid hours per day
"""
if not self.calendar_ids:
return -1
today = date.today()
relevant_calendars = self.calendar_ids.filtered(
lambda x: x.date_start
and x.date_end
and x.date_start <= today <= x.date_end
)
if relevant_calendars:
return relevant_calendars[0].calendar_id.hours_per_day
relevant_calendars = self.calendar_ids.filtered(
lambda x: x.date_start and not x.date_end and x.date_start <= today
)
if relevant_calendars:
return relevant_calendars[0].calendar_id.hours_per_day
relevant_calendars = self.calendar_ids.filtered(
lambda x: not x.date_start and x.date_end and today <= x.date_end
)
if relevant_calendars:
return relevant_calendars[0].calendar_id.hours_per_day

Check warning on line 92 in hr_employee_calendar_planning/models/hr_employee.py

View check run for this annotation

Codecov / codecov/patch

hr_employee_calendar_planning/models/hr_employee.py#L92

Added line #L92 was not covered by tests
relevant_calendars = self.calendar_ids.filtered(
lambda x: not x.date_start and not x.date_end
)
if relevant_calendars:
return relevant_calendars[0].calendar_id.hours_per_day
return -1

def _regenerate_calendar(self):
self.ensure_one()
vals_list = []
Expand Down Expand Up @@ -115,11 +154,11 @@
)
else:
self.resource_calendar_id.attendance_ids = vals_list
# Set the hours per day to the last (top date end) calendar line to apply
# Set the hours per day to the value of the current resource calendar
current_hours_per_day = self._get_current_hours_per_day()
if current_hours_per_day >= 0:
self.resource_id.calendar_id.hours_per_day = current_hours_per_day
if self.calendar_ids:
self.resource_id.calendar_id.hours_per_day = self.calendar_ids[
0
].calendar_id.hours_per_day
# set global leaves
self.copy_global_leaves()

Expand Down Expand Up @@ -162,6 +201,13 @@
to_unlink.unlink()
return self.env["resource.calendar.leaves"].create(new_vals).ids

def cron_recompute_hours_per_day(self):
employees = self.search([])

Check warning on line 205 in hr_employee_calendar_planning/models/hr_employee.py

View check run for this annotation

Codecov / codecov/patch

hr_employee_calendar_planning/models/hr_employee.py#L205

Added line #L205 was not covered by tests
for employee in employees:
current_hours_per_day = employee._get_current_hours_per_day()

Check warning on line 207 in hr_employee_calendar_planning/models/hr_employee.py

View check run for this annotation

Codecov / codecov/patch

hr_employee_calendar_planning/models/hr_employee.py#L207

Added line #L207 was not covered by tests
if current_hours_per_day >= 0:
employee.resource_id.calendar_id.hours_per_day = current_hours_per_day

Check warning on line 209 in hr_employee_calendar_planning/models/hr_employee.py

View check run for this annotation

Codecov / codecov/patch

hr_employee_calendar_planning/models/hr_employee.py#L209

Added line #L209 was not covered by tests

def regenerate_calendar(self):
for item in self:
item._regenerate_calendar()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Copyright 2021-2023 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from datetime import date, timedelta

from odoo import exceptions, fields
from odoo.tests import common, new_test_user

Expand Down Expand Up @@ -454,3 +456,68 @@ def test_create_employee_multi(self):
]
)
self.assertEqual(len(employees), 2)

def test_get_current_hours_per_day(self):
employee_calendar1 = self.env["hr.employee.calendar"].create(
{
"date_start": date.today() - timedelta(days=2),
"date_end": date.today() + timedelta(days=2),
"employee_id": self.employee.id,
"calendar_id": self.calendar1.id,
}
)
self.assertEqual(
self.employee.resource_calendar_id.hours_per_day,
self.calendar1.hours_per_day,
)
self.calendar2.attendance_ids[
-1
].unlink() # Make hours_per_day different for calendar 1 and 2
employee_calendar2 = self.env["hr.employee.calendar"].create(
{
"date_start": date.today() + timedelta(days=3),
"date_end": date.today() + timedelta(days=5),
"employee_id": self.employee.id,
"calendar_id": self.calendar2.id,
}
)
self.assertEqual(
self.employee.resource_calendar_id.hours_per_day,
self.calendar1.hours_per_day,
)
employee_calendar1.write(
{
"date_start": employee_calendar1.date_start + timedelta(days=5),
"date_end": employee_calendar1.date_start + timedelta(days=7),
}
)
employee_calendar2.write(
{
"date_start": date.today() - timedelta(days=2),
"date_end": None,
}
)
self.assertEqual(
self.employee.resource_calendar_id.hours_per_day,
self.calendar2.hours_per_day,
)
employee_calendar1.write(
{
"date_start": None,
"date_end": None,
}
)
self.assertEqual(
self.employee.resource_calendar_id.hours_per_day,
self.calendar2.hours_per_day,
)
employee_calendar2.write(
{
"date_start": date.today() + timedelta(days=2),
"date_end": None,
}
)
self.assertEqual(
self.employee.resource_calendar_id.hours_per_day,
self.calendar1.hours_per_day,
)
Loading