-
-
+
+
+
+
+
+
+
+
+
+
+
+
Legend
+
Validated
+
To Approve
+
Refused
+
+
+
+
diff --git a/addons/hr_holidays/tests/test_access_rights.py b/addons/hr_holidays/tests/test_access_rights.py
index dc1df2cc908..2d97aaf9377 100644
--- a/addons/hr_holidays/tests/test_access_rights.py
+++ b/addons/hr_holidays/tests/test_access_rights.py
@@ -17,8 +17,7 @@ class TestHrHolidaysAccessRightsCommon(TestHrHolidaysCommon):
self.leave_type = self.env['hr.leave.type'].create({
'name': 'Unlimited',
'leave_validation_type': 'hr',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
self.rd_dept.manager_id = False
self.hr_dept.manager_id = False
@@ -36,29 +35,25 @@ class TestHrHolidaysAccessRightsCommon(TestHrHolidaysCommon):
self.lt_no_validation = self.env['hr.leave.type'].create({
'name': 'Validation = no_validation',
'leave_validation_type': 'hr',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
self.lt_validation_hr = self.env['hr.leave.type'].create({
'name': 'Validation = HR',
'leave_validation_type': 'hr',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
self.lt_validation_manager = self.env['hr.leave.type'].create({
'name': 'Validation = manager',
'leave_validation_type': 'hr',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
self.lt_validation_both = self.env['hr.leave.type'].create({
'name': 'Validation = both',
'leave_validation_type': 'hr',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
self.draft_status = [
@@ -779,7 +774,7 @@ class TestMultiCompany(TestHrHolidaysCommon):
'name': 'Unlimited - Company New',
'company_id': self.new_company.id,
'leave_validation_type': 'hr',
- 'allocation_type': 'no',
+ 'requires_allocation': 'no',
})
self.rd_dept.manager_id = False
self.hr_dept.manager_id = False
diff --git a/addons/hr_holidays/tests/test_accrual_allocations.py b/addons/hr_holidays/tests/test_accrual_allocations.py
index b46da059470..9c2e2fdbf45 100644
--- a/addons/hr_holidays/tests/test_accrual_allocations.py
+++ b/addons/hr_holidays/tests/test_accrual_allocations.py
@@ -1,251 +1,556 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from datetime import datetime, time
+import datetime
+from freezegun import freeze_time
from dateutil.relativedelta import relativedelta
from odoo import fields
-
-from odoo.tools import mute_logger
+from odoo.tests import tagged
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
+@tagged('post_install', '-at_install')
class TestAccrualAllocations(TestHrHolidaysCommon):
def setUp(self):
super(TestAccrualAllocations, self).setUp()
-
- # Make sure we have the rights to create, validate and delete the leaves, leave types and allocations
- LeaveType = self.env['hr.leave.type'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True)
-
- self.accrual_type = LeaveType.create({
- 'name': 'accrual',
- 'allocation_type': 'fixed',
- 'validity_start': False,
+ self.leave_type = self.env['hr.leave.type'].create({
+ 'name': 'Paid Time Off',
+ 'time_type': 'leave',
+ 'requires_allocation': 'yes',
})
- self.unpaid_type = LeaveType.create({
- 'name': 'unpaid',
- 'allocation_type': 'no',
- 'unpaid': True,
- 'validity_start': False,
- })
-
- self.set_employee_create_date(self.employee_emp_id, '2010-02-03 00:00:00')
- self.set_employee_create_date(self.employee_hruser_id, '2010-02-03 00:00:00')
-
- def set_employee_create_date(self, id, newdate):
+ def setAllocationCreateDate(self, allocation_id, date):
""" This method is a hack in order to be able to define/redefine the create_date
- of the employees.
+ of the allocations.
This is done in SQL because ORM does not allow to write onto the create_date field.
"""
self.env.cr.execute("""
UPDATE
- hr_employee
+ hr_leave_allocation
SET create_date = '%s'
WHERE id = %s
- """ % (newdate, id))
+ """ % (date, allocation_id))
- def test_accrual_base_no_leaves(self):
- """ Test if we can allocate some leaves accrually to an employee """
- alloc = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
- 'name': 'Accrual allocation for employee',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'number_of_days': 0,
- 'number_per_interval': 1,
- 'interval_number': 1,
- 'unit_per_interval': 'days',
- 'interval_unit': 'weeks',
+ def test_frequency_daily(self):
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'daily',
+ 'maximum_leave': 10000
+ })],
})
- alloc.action_approve()
- alloc._update_accrual()
-
- self.assertEqual(alloc.number_of_days, 1, 'Employee should have been allocated one leave day')
-
- def test_accrual_base_leaves(self):
- """ Test if the accrual allocation take the unpaid leaves into account when allocating leaves """
- alloc = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
- 'name': 'Accrual allocation for employee with leaves',
- 'employee_id': self.employee_hruser_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'number_of_days': 0,
- 'number_per_interval': 1,
- 'interval_number': 1,
- 'unit_per_interval': 'days',
- 'interval_unit': 'weeks',
- })
-
- alloc.action_approve()
-
- employee = self.env['hr.employee'].browse(self.employee_hruser_id)
- # Getting the previous work date
- df = employee.resource_calendar_id.plan_days(-2, fields.Datetime.now()).date()
-
- leave = self.env['hr.leave'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
- 'name': 'Leave for hruser',
- 'employee_id': self.employee_hruser_id,
- 'holiday_status_id': self.unpaid_type.id,
- 'date_from': datetime.combine(df, time(0, 0, 0)),
- 'date_to': datetime.combine(df + relativedelta(days=1), time(0, 0, 0)),
- 'number_of_days': 1,
- })
-
- leave.action_approve()
-
- alloc._update_accrual()
-
- self.assertEqual(alloc.number_of_days, .8, 'As employee took some unpaid leaves last week, he should be allocated only .8 days')
-
- def test_accrual_many(self):
- """
- Test different configuration of accrual allocations
- """
- Allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True)
-
- alloc_0 = Allocation.create({
- 'name': '1 day per 2 weeks',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'number_of_days': 0,
- 'number_per_interval': 1,
- 'interval_number': 2,
- 'unit_per_interval': 'days',
- 'interval_unit': 'weeks',
- })
-
- alloc_1 = Allocation.create({
- 'name': '4 hours per week',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'number_of_days': 0,
- 'number_per_interval': 4,
- 'interval_number': 1,
- 'unit_per_interval': 'hours',
- 'interval_unit': 'weeks',
- })
-
- alloc_2 = Allocation.create({
- 'name': '2 day per 1 month',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'number_of_days': 0,
- 'number_per_interval': 2,
- 'interval_number': 1,
- 'unit_per_interval': 'days',
- 'interval_unit': 'months',
- })
-
- alloc_3 = Allocation.create({
- 'name': '20 days per year',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'number_of_days': 0,
- 'number_per_interval': 20,
- 'interval_number': 1,
- 'unit_per_interval': 'days',
- 'interval_unit': 'years',
- })
-
- (alloc_0 | alloc_1 | alloc_2 | alloc_3).action_approve()
-
- Allocation._update_accrual()
-
- self.assertEqual(alloc_0.number_of_days, 1)
- self.assertEqual(alloc_1.number_of_days, .5)
- self.assertEqual(alloc_2.number_of_days, 2)
- self.assertEqual(alloc_3.number_of_days, 20)
-
- def test_accrual_new_employee(self):
- """
- Test if accrual allocation takes into account the creation date
- of an employee
- """
- Allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True)
-
- self.set_employee_create_date(self.employee_emp_id, fields.Datetime.to_string(fields.Datetime.now()))
-
- alloc_0 = Allocation.create({
- 'name': 'one shot one kill',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'number_of_days': 0,
- 'number_per_interval': 1,
- 'interval_number': 1,
- 'unit_per_interval': 'days',
- 'interval_unit': 'weeks',
- })
-
- alloc_0.action_approve()
-
- Allocation._update_accrual()
-
- self.assertEqual(alloc_0.number_of_days, 0, 'Employee is new he should not get any accrual leaves')
-
- def test_accrual_multi(self):
- """ Test if the cron does not allocate leaves every time it's called but only when necessary """
- alloc = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
- 'name': '2 days per week',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'number_of_days': 0,
- 'number_per_interval': 1,
- 'interval_number': 2,
- 'unit_per_interval': 'days',
- 'interval_unit': 'weeks',
- })
- alloc.action_approve()
- alloc._update_accrual()
- alloc._update_accrual()
-
- self.assertEqual(alloc.number_of_days, 1, 'Cron only allocates 1 days every two weeks')
-
- def test_accrual_validation(self):
- """
- Test if cron does not allocate past it's validity date
- """
- Allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True)
-
- alloc_0 = Allocation.create({
- 'name': '20 days per year',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'number_of_days': 0,
- 'number_per_interval': 20,
- 'interval_number': 1,
- 'unit_per_interval': 'days',
- 'interval_unit': 'years',
- 'date_to': fields.Datetime.from_string('2015-02-03 00:00:00'),
- })
-
- alloc_0.action_approve()
-
- Allocation._update_accrual()
-
- self.assertEqual(alloc_0.number_of_days, 0, 'Cron validity passed, should not allocate any leave')
-
- def test_accrual_balance_limit(self):
- """ Test if accrual allocation does not allocate more than the balance limit"""
allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
- 'name': 'accrual 5 max',
- 'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.accrual_type.id,
- 'allocation_type': 'accrual',
- 'accrual_limit': 5,
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
'number_of_days': 0,
- 'number_per_interval': 6,
- 'interval_number': 1,
- 'unit_per_interval': 'days',
- 'interval_unit': 'weeks',
+ 'allocation_type': 'accrual',
})
- allocation.action_approve()
+ allocation.action_confirm()
+ allocation.action_validate()
+ self.assertFalse(allocation.nextcall, 'There should be no nextcall set on the allocation.')
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet.')
allocation._update_accrual()
+ tomorrow = datetime.date.today() + relativedelta(days=2)
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet. The accrual starts tomorrow.')
- self.assertEqual(allocation.number_of_days, 5, 'Should have allocated only 5 days as balance limit is 5')
+ freezer = freeze_time(tomorrow)
+ freezer.start()
+ allocation._update_accrual()
+ nextcall = datetime.date.today() + relativedelta(days=1)
+ self.assertEqual(allocation.number_of_days, 1, 'There should be 1 day allocated.')
+ self.assertEqual(allocation.nextcall, nextcall, 'The next call date of the cron should be in 2 days.')
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 1, 'There should be only 1 day allocated.')
+ freezer.stop()
+
+ def test_frequency_weekly(self):
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'weekly',
+ 'maximum_leave': 10000
+ })],
+ })
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ })
+ allocation.action_confirm()
+ allocation.action_validate()
+ self.assertFalse(allocation.nextcall, 'There should be no nextcall set on the allocation.')
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet.')
+ allocation._update_accrual()
+ nextWeek = self.env['hr.leave.accrual.level']._get_next_weekday(datetime.date.today(), 'mon')
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet. The accrual starts tomorrow.')
+
+ freezer = freeze_time(nextWeek)
+ freezer.start()
+ allocation._update_accrual()
+ nextWeek = self.env['hr.leave.accrual.level']._get_next_weekday(datetime.date.today(), 'mon')
+ self.assertEqual(allocation.number_of_days, 1, 'There should be 1 day allocated.')
+ self.assertEqual(allocation.nextcall, nextWeek, 'The next call date of the cron should be in 2 weeks')
+ freezer.stop()
+
+ def test_frequency_bimonthly(self):
+ freezer = freeze_time('2021-09-01')
+ freezer.start()
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'bimonthly',
+ 'first_day': 1,
+ 'second_day': 15,
+ 'maximum_leave': 10000,
+ })],
+ })
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ })
+ self.setAllocationCreateDate(allocation.id, '2021-09-01 00:00:00')
+ allocation.action_confirm()
+ allocation.action_validate()
+ self.assertFalse(allocation.nextcall, 'There should be no nextcall set on the allocation.')
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet.')
+ allocation._update_accrual()
+ next_date = datetime.date(2021, 9, 15)
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet. The accrual starts tomorrow.')
+ freezer.stop()
+
+ freezer = freeze_time(next_date)
+ freezer.start()
+ next_date = datetime.date(2021, 10, 1)
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 1, 'There should be 1 day allocated.')
+ self.assertEqual(allocation.nextcall, next_date, 'The next call date of the cron should be October 1st')
+ freezer.stop()
+
+ def test_frequency_monthly(self):
+ freezer = freeze_time('2021-09-01')
+ freezer.start()
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'monthly',
+ 'maximum_leave': 10000
+ })],
+ })
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ })
+ self.setAllocationCreateDate(allocation.id, '2021-09-01 00:00:00')
+ allocation.action_confirm()
+ allocation.action_validate()
+ self.assertFalse(allocation.nextcall, 'There should be no nextcall set on the allocation.')
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet.')
+ allocation._update_accrual()
+ next_date = datetime.date(2021, 10, 1)
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet. The accrual starts tomorrow.')
+ freezer.stop()
+
+ freezer = freeze_time(next_date)
+ freezer.start()
+ next_date = datetime.date(2021, 11, 1)
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 1, 'There should be 1 day allocated.')
+ self.assertEqual(allocation.nextcall, next_date, 'The next call date of the cron should be November 1st')
+ freezer.stop()
+
+ def test_frequency_biyearly(self):
+ freezer = freeze_time('2021-09-01')
+ freezer.start()
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'biyearly',
+ 'maximum_leave': 10000,
+ })],
+ })
+ #this sets up an accrual on the 1st of January and the 1st of July
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ })
+ self.setAllocationCreateDate(allocation.id, '2021-09-01 00:00:00')
+ allocation.action_confirm()
+ allocation.action_validate()
+ self.assertFalse(allocation.nextcall, 'There should be no nextcall set on the allocation.')
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet.')
+ allocation._update_accrual()
+ next_date = datetime.date(2022, 1, 1)
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet. The accrual starts tomorrow.')
+ freezer.stop()
+
+ freezer = freeze_time(next_date)
+ freezer.start()
+ next_date = datetime.date(2022, 7, 1)
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 1, 'There should be 1 day allocated.')
+ self.assertEqual(allocation.nextcall, next_date, 'The next call date of the cron should be July 1st')
+ freezer.stop()
+
+ def test_frequency_yearly(self):
+ freezer = freeze_time('2021-09-01')
+ freezer.start()
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'yearly',
+ 'maximum_leave': 10000,
+ })],
+ })
+ #this sets up an accrual on the 1st of January
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ })
+ self.setAllocationCreateDate(allocation.id, '2021-09-01 00:00:00')
+ allocation.action_confirm()
+ allocation.action_validate()
+ self.assertFalse(allocation.nextcall, 'There should be no nextcall set on the allocation.')
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet.')
+ allocation._update_accrual()
+ next_date = datetime.date(2022, 1, 1)
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet. The accrual starts tomorrow.')
+ freezer.stop()
+
+ freezer = freeze_time(next_date)
+ freezer.start()
+ next_date = datetime.date(2023, 1, 1)
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 1, 'There should be 1 day allocated.')
+ self.assertEqual(allocation.nextcall, next_date, 'The next call date of the cron should be January 1st 2023')
+ freezer.stop()
+
+ def test_check_gain(self):
+ # 2 accruals, one based on worked time, one not
+ # check gain
+ freezer = freeze_time('2021-08-30')
+ freezer.start()
+ calendar_emp = self.env['resource.calendar'].create({
+ 'name': '40 Hours',
+ 'tz': self.employee_emp.tz,
+ 'attendance_ids': [
+ (0, 0, {
+ 'name': '%s_%d' % ('40 Hours', index),
+ 'hour_from': 8,
+ 'hour_to': 12,
+ 'dayofweek': str(index),
+ 'day_period': 'morning'
+ }, {
+ 'name': '%s_%d' % ('40 Hours', index),
+ 'hour_from': 13,
+ 'hour_to': 18,
+ 'dayofweek': str(index),
+ 'day_period': 'afternoon'
+ }) for index in range(5)
+ ],
+ })
+ self.employee_emp.resource_calendar_id = calendar_emp.id
+
+ accrual_plan_not_based_on_worked_time = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 5,
+ 'added_value_type': 'days',
+ 'frequency': 'weekly',
+ 'maximum_leave': 10000,
+ })],
+ })
+ accrual_plan_based_on_worked_time = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 5,
+ 'added_value_type': 'days',
+ 'frequency': 'weekly',
+ 'maximum_leave': 10000,
+ 'is_based_on_worked_time': True,
+ })],
+ })
+ allocation_not_worked_time = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan_not_based_on_worked_time.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ 'state': 'validate',
+ })
+ allocation_worked_time = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan_based_on_worked_time.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ 'state': 'validate',
+ })
+ self.setAllocationCreateDate(allocation_not_worked_time.id, '2021-08-01 00:00:00')
+ self.setAllocationCreateDate(allocation_worked_time.id, '2021-08-01 00:00:00')
+ holiday_type = self.env['hr.leave.type'].create({
+ 'name': 'Paid Time Off',
+ 'requires_allocation': 'no',
+ 'responsible_id': self.user_hrmanager_id,
+ })
+ leave = self.env['hr.leave'].create({
+ 'name': 'leave',
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': holiday_type.id,
+ 'date_from': '2021-09-02 00:00:00',
+ 'date_to': '2021-09-02 23:59:59',
+ })
+ leave.action_validate()
+ self.assertFalse(allocation_not_worked_time.nextcall, 'There should be no nextcall set on the allocation.')
+ self.assertFalse(allocation_worked_time.nextcall, 'There should be no nextcall set on the allocation.')
+ self.assertEqual(allocation_not_worked_time.number_of_days, 0, 'There should be no days allocated yet.')
+ self.assertEqual(allocation_worked_time.number_of_days, 0, 'There should be no days allocated yet.')
+ freezer.stop()
+ next_date = datetime.date(2021, 9, 6)
+ freezer = freeze_time(next_date)
+ freezer.start()
+ # next_date = datetime.date(2021, 9, 13)
+ self.env['hr.leave.allocation']._update_accrual()
+ self.assertEqual(allocation_not_worked_time.number_of_days, 5, 'There should be 5 days allocated.')
+ # 3.75 -> starts 1 day after allocation date -> 31/08-3/09 => 4 days - 1 days time off => (3 / 4) * 5 days
+ self.assertEqual(allocation_worked_time.number_of_days, 3.75, 'There should be 5 days allocated.')
+ self.assertEqual(allocation_not_worked_time.nextcall, datetime.date(2021, 9, 13), 'The next call date of the cron should be the September 13th')
+ self.assertEqual(allocation_worked_time.nextcall, datetime.date(2021, 9, 13), 'The next call date of the cron should be the September 13th')
+ freezer.stop()
+
+ freezer = freeze_time(next_date + relativedelta(days=7))
+ freezer.start()
+ next_date = datetime.date(2021, 9, 20)
+ self.env['hr.leave.allocation']._update_accrual()
+ self.assertEqual(allocation_not_worked_time.number_of_days, 10, 'There should be 10 days allocated.')
+ self.assertEqual(allocation_not_worked_time.nextcall, next_date, 'The next call date of the cron should be September 20th')
+ self.assertEqual(allocation_worked_time.number_of_days, 8.75, 'There should be 9 days allocated.')
+ self.assertEqual(allocation_worked_time.nextcall, next_date, 'The next call date of the cron should be September 20th')
+ freezer.stop()
+
+ def test_check_max_value(self):
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'daily',
+ 'maximum_leave': 1,
+ })],
+ })
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ })
+ allocation.action_confirm()
+ allocation.action_validate()
+ allocation._update_accrual()
+ tomorrow = datetime.date.today() + relativedelta(days=2)
+ self.assertEqual(allocation.number_of_days, 0, 'There should be no days allocated yet. The accrual starts tomorrow.')
+
+ freezer = freeze_time(tomorrow)
+ freezer.start()
+ allocation._update_accrual()
+ nextcall = datetime.date.today() + relativedelta(days=1)
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 1, 'There should be only 1 day allocated.')
+ freezer.stop()
+
+ freezer = freeze_time(nextcall)
+ freezer.start()
+ allocation._update_accrual()
+ nextcall = datetime.date.today() + relativedelta(days=1)
+ #The maximum value is 1 so this shouldn't change anything
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 1, 'There should be only 1 day allocated.')
+ freezer.stop()
+
+ def test_accrual_transition_immediately(self):
+ #1 accrual with 2 levels and level transition immediately
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'transition_mode': 'immediately',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'weekly',
+ 'maximum_leave': 1,
+ }), (0, 0, {
+ 'start_count': 10,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'weekly',
+ 'maximum_leave': 1,
+ })],
+ })
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ })
+ allocation.action_confirm()
+ allocation.action_validate()
+ next_date = datetime.date.today() + relativedelta(days=11)
+ second_level = self.env['hr.leave.accrual.level'].search([('accrual_plan_id', '=', accrual_plan.id), ('start_count', '=', 10)])
+ self.assertEqual(allocation._get_current_accrual_plan_level_id(next_date), second_level, 'The second level should be selected')
+
+ def test_accrual_transition_after_period(self):
+ # 1 accrual with 2 levels and level transition after
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'transition_mode': 'end_of_accrual',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'weekly',
+ 'maximum_leave': 1,
+ }), (0, 0, {
+ 'start_count': 10,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'weekly',
+ 'maximum_leave': 1,
+ })],
+ })
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 0,
+ 'allocation_type': 'accrual',
+ })
+ allocation.action_confirm()
+ allocation.action_validate()
+ next_date = datetime.date.today() + relativedelta(days=11)
+ second_level = self.env['hr.leave.accrual.level'].search([('accrual_plan_id', '=', accrual_plan.id), ('start_count', '=', 10)])
+ self.assertEqual(allocation._get_current_accrual_plan_level_id(next_date), second_level, 'The second level should be selected')
+
+ def test_unused_accrual_lost(self):
+ #1 accrual with 2 levels and level transition immediately
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'daily',
+ 'maximum_leave': 1,
+ 'action_with_unused_accruals': 'lost',
+ })],
+ })
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 10,
+ 'allocation_type': 'accrual',
+ })
+ allocation.action_confirm()
+ allocation.action_validate()
+
+ freezer = freeze_time('2022-01-01')
+ freezer.start()
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 0, 'There number of days should be reset')
+ freezer.stop()
+
+ def test_unused_accrual_postponed(self):
+ # 1 accrual with 2 levels and level transition after
+ # This also tests retroactivity
+ accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({
+ 'name': 'Accrual Plan For Test',
+ 'level_ids': [(0, 0, {
+ 'start_count': 1,
+ 'start_type': 'day',
+ 'added_value': 1,
+ 'added_value_type': 'days',
+ 'frequency': 'daily',
+ 'maximum_leave': 25,
+ 'action_with_unused_accruals': 'postponed',
+ })],
+ })
+ allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
+ 'name': 'Accrual allocation for employee',
+ 'accrual_plan_id': accrual_plan.id,
+ 'employee_id': self.employee_emp.id,
+ 'holiday_status_id': self.leave_type.id,
+ 'number_of_days': 10,
+ 'allocation_type': 'accrual',
+ })
+ allocation.action_confirm()
+ allocation.action_validate()
+
+ freezer = freeze_time('2022-01-01')
+ freezer.start()
+ allocation._update_accrual()
+ self.assertEqual(allocation.number_of_days, 25, 'The maximum number of days should be reached and kept.')
+ freezer.stop()
diff --git a/addons/hr_holidays/tests/test_allocation_access_rights.py b/addons/hr_holidays/tests/test_allocation_access_rights.py
index 2d4c973eafb..b68ffc200dc 100644
--- a/addons/hr_holidays/tests/test_allocation_access_rights.py
+++ b/addons/hr_holidays/tests/test_allocation_access_rights.py
@@ -4,6 +4,7 @@
from odoo import tests
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
from odoo.exceptions import AccessError, UserError
+import time
@tests.tagged('access_rights', 'post_install', '-at_install')
@@ -16,31 +17,33 @@ class TestAllocationRights(TestHrHolidaysCommon):
self.employee_emp.parent_id = False
self.employee_emp.leave_manager_id = False
- self.lt_validation_hr = self.env['hr.leave.type'].create({
+ self.lt_no_validation = self.env['hr.leave.type'].create({
'name': 'Validation = HR',
- 'allocation_validation_type': 'hr',
- 'allocation_type': 'fixed_allocation',
- 'validity_start': False,
+ 'allocation_validation_type': 'officer',
+ 'requires_allocation': 'no',
+ 'employee_requests': 'yes',
})
self.lt_validation_manager = self.env['hr.leave.type'].create({
'name': 'Validation = manager',
- 'allocation_validation_type': 'manager',
- 'allocation_type': 'fixed_allocation',
- 'validity_start': False,
+ 'allocation_validation_type': 'officer',
+ 'requires_allocation': 'yes',
+ 'employee_requests': 'yes',
})
- self.lt_validation_both = self.env['hr.leave.type'].create({
- 'name': 'Validation = both',
- 'allocation_validation_type': 'both',
- 'allocation_type': 'fixed_allocation',
- 'validity_start': False,
+ self.lt_allocation_manager = self.env['hr.leave.type'].create({
+ 'name': 'Validation = manager',
+ 'allocation_validation_type': 'set',
+ 'requires_allocation': 'yes',
+ 'employee_requests': 'no',
})
def request_allocation(self, user, values={}):
values = dict(values, **{
'name': 'Allocation',
'number_of_days': 1,
+ 'date_from': time.strftime('%Y-01-01'),
+ 'date_to': time.strftime('%Y-12-31'),
})
return self.env['hr.leave.allocation'].with_user(user).create(values)
@@ -51,18 +54,17 @@ class TestAccessRightsSimpleUser(TestAllocationRights):
""" A simple user can request an allocation but not approve it """
values = {
'employee_id': self.employee_emp.id,
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
with self.assertRaises(UserError):
- allocation.action_approve()
+ allocation.action_validate()
def test_simple_user_request_fixed_allocation(self):
- """ A simple user cannot request an allocation if set by HR """
- self.lt_validation_hr.allocation_type = 'fixed'
+ """ A simple user cannot request an allocation if employee requests is not enabled """
values = {
'employee_id': self.employee_emp.id,
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_allocation_manager.id,
}
with self.assertRaises(AccessError):
self.request_allocation(self.user_employee.id, values)
@@ -71,12 +73,14 @@ class TestAccessRightsSimpleUser(TestAllocationRights):
""" A simple user can reset to draft only his own allocation """
values = {
'employee_id': self.employee_emp.id,
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
- self.assertEqual(allocation.state, 'confirm')
+ self.assertEqual(allocation.state, 'draft')
+ allocation.action_confirm()
+ self.assertEqual(allocation.state, 'confirm', "It should be confirmed")
allocation.action_draft()
- self.assertEqual(allocation.state, 'draft', "It should be reset to draft state")
+ self.assertEqual(allocation.state, 'draft', "It should have been reset to draft")
class TestAccessRightsEmployeeManager(TestAllocationRights):
@@ -104,7 +108,8 @@ class TestAccessRightsEmployeeManager(TestAllocationRights):
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
- allocation.action_approve()
+ allocation.action_confirm()
+ allocation.action_validate()
self.assertEqual(allocation.state, 'validate', "The allocation should be validated")
def test_manager_refuse_request_allocation(self):
@@ -114,6 +119,7 @@ class TestAccessRightsEmployeeManager(TestAllocationRights):
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
+ allocation.action_confirm()
allocation.action_refuse()
self.assertEqual(allocation.state, 'refuse', "The allocation should be validated")
@@ -134,61 +140,37 @@ class TestAccessRightsEmployeeManager(TestAllocationRights):
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
- with self.assertRaises(UserError):
- allocation.action_approve()
-
- def test_manager_only_first_approval(self):
- """ A manager can only do the first approval """
- values = {
- 'employee_id': self.managed_employee.id,
- 'holiday_status_id': self.lt_validation_both.id,
- }
- allocation = self.request_allocation(self.user_employee.id, values)
- allocation.action_approve()
with self.assertRaises(UserError):
allocation.action_validate()
-
class TestAccessRightsHolidayUser(TestAllocationRights):
def test_holiday_user_request_allocation(self):
""" A holiday user can request and approve an allocation for any employee """
values = {
'employee_id': self.employee_emp.id,
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_hruser.id, values)
- allocation.action_approve()
+ allocation.action_confirm()
+ allocation.action_validate()
self.assertEqual(allocation.state, 'validate', "It should have been validated")
def test_holiday_user_request_fixed_allocation(self):
""" A holiday user can request and approve an allocation if set by HR """
- self.lt_validation_hr.allocation_type = 'fixed'
values = {
'employee_id': self.employee_emp.id,
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_allocation_manager.id,
}
allocation = self.request_allocation(self.user_hruser.id, values)
- allocation.action_approve()
- self.assertEqual(allocation.state, 'validate', "It should have been validated")
-
- def test_holiday_user_both_second_approval(self):
- """ A holiday user can only do the second approval when double validation """
- values = {
- 'employee_id': self.employee_emp.id,
- 'holiday_status_id': self.lt_validation_both.id,
- }
- allocation = self.request_allocation(self.user_hruser.id, values)
- with self.assertRaises(UserError):
- allocation.action_approve()
- allocation.sudo().action_approve() # First approval by someone else
+ allocation.action_confirm()
allocation.action_validate()
self.assertEqual(allocation.state, 'validate', "It should have been validated")
def test_holiday_user_batch_allocation(self):
""" A holiday user cannot create a batch allocation """
values = {
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_validation_manager.id,
'holiday_type': 'company',
'mode_company_id': self.user_employee.company_id.id,
}
@@ -199,11 +181,12 @@ class TestAccessRightsHolidayUser(TestAllocationRights):
""" A holiday user cannot approve his own allocation """
values = {
'employee_id': self.employee_hruser.id,
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_hruser.id, values)
+ allocation.action_confirm()
with self.assertRaises(UserError):
- allocation.action_approve()
+ allocation.action_validate()
class TestAccessRightsHolidayManager(TestAllocationRights):
@@ -212,32 +195,22 @@ class TestAccessRightsHolidayManager(TestAllocationRights):
""" A holiday manager can approve his own allocation """
values = {
'employee_id': self.employee_hrmanager.id,
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_hrmanager.id, values)
- allocation.action_approve()
- self.assertEqual(allocation.state, 'validate', "It should have been validated")
-
- def test_holiday_manager_both_validation(self):
- """ A holiday manager can perform both validation """
- values = {
- 'employee_id': self.employee_emp.id,
- 'holiday_status_id': self.lt_validation_both.id,
- }
- allocation = self.request_allocation(self.user_hrmanager.id, values)
- allocation.action_approve()
- self.assertEqual(allocation.state, 'validate1', "It should have been validated one time")
+ allocation.action_confirm()
allocation.action_validate()
- self.assertEqual(allocation.state, 'validate', "It should have been completely validated")
+ self.assertEqual(allocation.state, 'validate', "It should have been validated")
def test_holiday_manager_refuse_validated(self):
""" A holiday manager can refuse a validated allocation """
values = {
'employee_id': self.employee_emp.id,
- 'holiday_status_id': self.lt_validation_hr.id,
+ 'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_hrmanager.id, values)
- allocation.action_approve()
+ allocation.action_confirm()
+ allocation.action_validate()
self.assertEqual(allocation.state, 'validate', "It should have been validated")
allocation.action_refuse()
self.assertEqual(allocation.state, 'refuse', "It should have been refused")
diff --git a/addons/hr_holidays/tests/test_automatic_leave_dates.py b/addons/hr_holidays/tests/test_automatic_leave_dates.py
index d3774e0974f..17089dfe5e9 100644
--- a/addons/hr_holidays/tests/test_automatic_leave_dates.py
+++ b/addons/hr_holidays/tests/test_automatic_leave_dates.py
@@ -14,8 +14,7 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
self.leave_type = self.env['hr.leave.type'].create({
'name': 'Automatic Test',
'time_type': 'leave',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
def test_no_attendances(self):
diff --git a/addons/hr_holidays/tests/test_change_department.py b/addons/hr_holidays/tests/test_change_department.py
index 83ebb1581ee..b68dd4804a5 100644
--- a/addons/hr_holidays/tests/test_change_department.py
+++ b/addons/hr_holidays/tests/test_change_department.py
@@ -14,8 +14,7 @@ class TestChangeDepartment(TestHrHolidaysCommon):
HolidayStatusManagerGroup = self.env['hr.leave.type'].with_user(self.user_hrmanager_id)
self.holidays_status_1 = HolidayStatusManagerGroup.create({
'name': 'NotLimitedHR',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
def create_holiday(name, start, end):
diff --git a/addons/hr_holidays/tests/test_company_leave.py b/addons/hr_holidays/tests/test_company_leave.py
index b5979dc19ab..02919e7509b 100644
--- a/addons/hr_holidays/tests/test_company_leave.py
+++ b/addons/hr_holidays/tests/test_company_leave.py
@@ -20,6 +20,7 @@ class TestCompanyLeave(TransactionCase):
'name': 'Bank Holiday',
'responsible_id': cls.env.user.id,
'company_id': cls.company.id,
+ 'requires_allocation': 'no',
})
cls.paid_time_off = cls.env['hr.leave.type'].create({
@@ -27,6 +28,7 @@ class TestCompanyLeave(TransactionCase):
'request_unit': 'day',
'leave_validation_type': 'both',
'company_id': cls.company.id,
+ 'requires_allocation': 'no',
})
cls.employee = cls.env['hr.employee'].create({
@@ -313,7 +315,7 @@ class TestCompanyLeave(TransactionCase):
})
company_leave._compute_date_from_to()
- with self.assertQueryCount(__system__=845, admin=865):
+ with self.assertQueryCount(__system__=846, admin=865):
# Original query count: 1987
# Without tracking/activity context keys: 5154
company_leave.action_validate()
diff --git a/addons/hr_holidays/tests/test_holidays_flow.py b/addons/hr_holidays/tests/test_holidays_flow.py
index b63c4486a5d..987ef2084c7 100644
--- a/addons/hr_holidays/tests/test_holidays_flow.py
+++ b/addons/hr_holidays/tests/test_holidays_flow.py
@@ -25,19 +25,17 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
HolidayStatusManagerGroup = HolidaysStatus.with_user(self.user_hrmanager_id)
HolidayStatusManagerGroup.create({
'name': 'WithMeetingType',
- 'allocation_type': 'no',
+ 'requires_allocation': 'no',
})
self.holidays_status_hr = HolidayStatusManagerGroup.create({
'name': 'NotLimitedHR',
- 'allocation_type': 'no',
+ 'requires_allocation': 'no',
'leave_validation_type': 'hr',
- 'validity_start': False,
})
self.holidays_status_manager = HolidayStatusManagerGroup.create({
'name': 'NotLimitedManager',
- 'allocation_type': 'no',
+ 'requires_allocation': 'no',
'leave_validation_type': 'manager',
- 'validity_start': False,
})
HolidaysEmployeeGroup = Requests.with_user(self.user_employee_id)
@@ -86,9 +84,10 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
holiday_status_paid_time_off = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
- 'allocation_type': 'fixed',
+ 'requires_allocation': 'yes',
+ 'employee_requests': 'no',
+ 'allocation_validation_type': 'set',
'leave_validation_type': 'both',
- 'validity_start': time.strftime('%Y-%m-01'),
'responsible_id': self.env.ref('base.user_admin').id,
})
@@ -99,12 +98,16 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
'number_of_days': 20,
'employee_id': self.employee_emp_id,
'state': 'validate',
+ 'date_from': time.strftime('%Y-%m-01'),
+ 'date_to': time.strftime('%Y-12-31'),
}, {
'name': 'Paid Time off for David',
'holiday_status_id': holiday_status_paid_time_off.id,
'number_of_days': 20,
'employee_id': self.ref('hr.employee_admin'),
'state': 'validate',
+ 'date_from': time.strftime('%Y-%m-01'),
+ 'date_to': time.strftime('%Y-12-31'),
}
])
@@ -122,16 +125,15 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
HolidayStatusManagerGroup = HolidaysStatus.with_user(self.user_hrmanager_id)
HolidayStatusManagerGroup.create({
'name': 'WithMeetingType',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
self.holidays_status_limited = HolidayStatusManagerGroup.create({
'name': 'Limited',
- 'allocation_type': 'fixed',
- 'allocation_validation_type': 'both',
+ 'requires_allocation': 'yes',
+ 'employee_requests': 'no',
+ 'allocation_validation_type': 'set',
'leave_validation_type': 'both',
- 'validity_start': False,
})
HolidaysEmployeeGroup = Requests.with_user(self.user_employee_id)
@@ -141,9 +143,11 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_status_limited.id,
'number_of_days': 2,
+ 'state': 'confirm',
+ 'date_from': time.strftime('%Y-%m-01'),
+ 'date_to': time.strftime('%Y-12-31'),
})
# HrUser validates the first step
- aloc1_user_group.action_approve()
# HrManager validates the second step
aloc1_user_group.with_user(self.user_hrmanager_id).action_validate()
@@ -165,11 +169,6 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
hol_status_2_employee_group.invalidate_cache()
_check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 1.0)
- # HrManager validates the first step
- hol2_user_group.with_user(self.user_hrmanager_id).action_approve()
- self.assertEqual(hol2.state, 'validate1',
- 'hr_holidays: first validation should lead to validate1 state')
-
# HrManager validates the second step
hol2_user_group.with_user(self.user_hrmanager_id).action_validate()
self.assertEqual(hol2.state, 'validate',
@@ -216,7 +215,6 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
hol3.action_confirm()
self.assertEqual(hol3.state, 'confirm', 'hr_holidays: confirming should lead to confirm state')
# I validate the holiday request by clicking on "To Approve" button.
- hol3.action_approve()
hol3.action_validate()
self.assertEqual(hol3.state, 'validate', 'hr_holidays: validation should lead to validate state')
# Check left days for casual leave: 19 days left
@@ -243,9 +241,10 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
holiday_status_paid_time_off = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
- 'allocation_type': 'fixed',
+ 'requires_allocation': 'yes',
+ 'employee_requests': 'no',
+ 'allocation_validation_type': 'set',
'leave_validation_type': 'both',
- 'validity_start': time.strftime('%Y-%m-01'),
'responsible_id': self.env.ref('base.user_admin').id,
})
@@ -255,6 +254,8 @@ class TestHolidaysFlow(TestHrHolidaysCommon):
'number_of_days': 20,
'employee_id': self.ref('hr.employee_admin'),
'state': 'validate',
+ 'date_from': time.strftime('%Y-%m-01'),
+ 'date_to': time.strftime('%Y-12-31'),
})
leave_vals = {
diff --git a/addons/hr_holidays/tests/test_hr_leave_type.py b/addons/hr_holidays/tests/test_hr_leave_type.py
index 852603a2d06..6a35e412ed0 100644
--- a/addons/hr_holidays/tests/test_hr_leave_type.py
+++ b/addons/hr_holidays/tests/test_hr_leave_type.py
@@ -15,8 +15,7 @@ class TestHrLeaveType(TestHrHolidaysCommon):
leave_type = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'time_type': 'leave',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
leave_1 = self.env['hr.leave'].create({
@@ -39,5 +38,5 @@ class TestHrLeaveType(TestHrHolidaysCommon):
with self.assertRaises(AccessError):
self.env['hr.leave.type'].with_user(self.user_hruser_id).create({
'name': 'UserCheats',
- 'allocation_type': 'no',
+ 'requires_allocation': 'no',
})
diff --git a/addons/hr_holidays/tests/test_leave_requests.py b/addons/hr_holidays/tests/test_leave_requests.py
index c0c4f3ea79f..7c3be743969 100644
--- a/addons/hr_holidays/tests/test_leave_requests.py
+++ b/addons/hr_holidays/tests/test_leave_requests.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, date
+import time
from dateutil.relativedelta import relativedelta
from pytz import timezone, UTC
@@ -34,22 +35,19 @@ class TestLeaveRequests(TestHrHolidaysCommon):
self.holidays_type_1 = LeaveType.create({
'name': 'NotLimitedHR',
- 'allocation_type': 'no',
+ 'requires_allocation': 'no',
'leave_validation_type': 'hr',
- 'validity_start': False,
})
self.holidays_type_2 = LeaveType.create({
'name': 'Limited',
- 'allocation_type': 'fixed_allocation',
+ 'requires_allocation': 'yes',
+ 'employee_requests': 'yes',
'leave_validation_type': 'hr',
- 'validity_start': False,
})
self.holidays_type_3 = LeaveType.create({
'name': 'TimeNotLimited',
- 'allocation_type': 'no',
+ 'requires_allocation': 'no',
'leave_validation_type': 'manager',
- 'validity_start': fields.Datetime.from_string('2017-01-01 00:00:00'),
- 'validity_stop': fields.Datetime.from_string('2017-06-01 00:00:00'),
})
self.set_employee_create_date(self.employee_emp_id, '2010-02-03 00:00:00')
@@ -111,8 +109,11 @@ class TestLeaveRequests(TestHrHolidaysCommon):
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 2,
+ 'state': 'confirm',
+ 'date_from': time.strftime('%Y-1-1'),
+ 'date_to': time.strftime('%Y-12-31'),
})
- aloc1_user_group.action_approve()
+ aloc1_user_group.action_validate()
holiday_status = self.holidays_type_2.with_user(self.user_employee_id)
self._check_holidays_status(holiday_status, 2.0, 0.0, 2.0, 2.0)
@@ -137,10 +138,21 @@ class TestLeaveRequests(TestHrHolidaysCommon):
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_accrual_validity_time_valid(self):
""" Employee ask leave during a valid validity time """
+
+ self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).create({
+ 'name': 'Sick Time Off',
+ 'holiday_status_id': self.holidays_type_2.id,
+ 'employee_id': self.employee_emp.id,
+ 'date_from': fields.Datetime.from_string('2017-01-01 00:00:00'),
+ 'date_to': fields.Datetime.from_string('2017-06-01 00:00:00'),
+ 'number_of_days': 10,
+ 'state': 'validate',
+ })
+
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Valid time period',
'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.holidays_type_3.id,
+ 'holiday_status_id': self.holidays_type_2.id,
'date_from': fields.Datetime.from_string('2017-03-03 06:00:00'),
'date_to': fields.Datetime.from_string('2017-03-11 19:00:00'),
'number_of_days': 1,
@@ -148,12 +160,12 @@ class TestLeaveRequests(TestHrHolidaysCommon):
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_accrual_validity_time_not_valid(self):
- """ Employee ask leav during a not valid validity time """
+ """ Employee ask leave when there's no valid allocation """
with self.assertRaises(ValidationError):
- self.env['hr.leave'].with_user(self.user_employee_id).create({
+ self.env['hr.leave'].with_user(self.user_employee).create({
'name': 'Sick Time Off',
'employee_id': self.employee_emp_id,
- 'holiday_status_id': self.holidays_type_3.id,
+ 'holiday_status_id': self.holidays_type_2.id,
'date_from': fields.Datetime.from_string('2017-07-03 06:00:00'),
'date_to': fields.Datetime.from_string('2017-07-11 19:00:00'),
'number_of_days': 1,
@@ -182,6 +194,8 @@ class TestLeaveRequests(TestHrHolidaysCommon):
allocation_form = Form(self.env['hr.leave.allocation'].with_user(self.user_employee))
allocation_form.name = 'New Allocation Request'
allocation_form.holiday_status_id = self.holidays_type_2
+ allocation_form.date_from = date(2019, 5, 6)
+ allocation_form.date_to = date(2019, 5, 6)
allocation = allocation_form.save()
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
@@ -307,8 +321,11 @@ class TestLeaveRequests(TestHrHolidaysCommon):
'holiday_status_id': leave_type.id,
'number_of_days': 20,
'employee_id': employee.id,
+ 'state': 'confirm',
+ 'date_from': time.strftime('2018-1-1'),
+ 'date_to': time.strftime('%Y-1-1'),
})
- allocation.action_approve()
+ allocation.action_validate()
leave1 = self.env['hr.leave'].create({
'name': 'Holiday 1 week',
@@ -374,7 +391,7 @@ class TestLeaveRequests(TestHrHolidaysCommon):
'name': 'Sick',
'request_unit': 'hour',
'leave_validation_type': 'both',
- 'allocation_type': 'no',
+ 'requires_allocation': 'no',
})
leave1 = self.env['hr.leave'].create({
'name': 'Sick 1 week during christmas snif',
@@ -428,13 +445,13 @@ class TestLeaveRequests(TestHrHolidaysCommon):
# 12 13 14 15 16 17 18
# 19 20 21 22 23 24 25
# 26 27 28 29 30 31
- local_date_from = datetime(2019, 1, 1, 7, 0, 0)
- local_date_to = datetime(2019, 1, 1, 19, 0, 0)
+ local_date_from = datetime(2020, 1, 1, 7, 0, 0)
+ local_date_to = datetime(2020, 1, 1, 19, 0, 0)
for tz in timezones_to_test:
self._test_leave_with_tz(tz, local_date_from, local_date_to, 1)
# We, Th, Fr, Mo, Tu, We => 6 days
- local_date_from = datetime(2019, 1, 1, 7, 0, 0)
- local_date_to = datetime(2019, 1, 8, 19, 0, 0)
+ local_date_from = datetime(2020, 1, 1, 7, 0, 0)
+ local_date_to = datetime(2020, 1, 8, 19, 0, 0)
for tz in timezones_to_test:
- self._test_leave_with_tz(tz, local_date_from, local_date_to, 6)
+ self._test_leave_with_tz(tz, local_date_from, local_date_to, 6)#TODO JUD check why this fails
diff --git a/addons/hr_holidays/tests/test_out_of_office.py b/addons/hr_holidays/tests/test_out_of_office.py
index 42301a085a5..a71fd55b3fc 100644
--- a/addons/hr_holidays/tests/test_out_of_office.py
+++ b/addons/hr_holidays/tests/test_out_of_office.py
@@ -18,8 +18,7 @@ class TestOutOfOffice(TestHrHolidaysCommon):
self.leave_type = self.env['hr.leave.type'].create({
'name': 'Legal Leaves',
'time_type': 'leave',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
def test_leave_ooo(self):
@@ -66,8 +65,7 @@ class TestOutOfOfficePerformance(TestHrHolidaysCommon, TransactionCaseWithUserDe
self.leave_type = self.env['hr.leave.type'].create({
'name': 'Legal Leaves',
'time_type': 'leave',
- 'allocation_type': 'no',
- 'validity_start': False,
+ 'requires_allocation': 'no',
})
self.leave_date_end = (datetime.today() + relativedelta(days=3))
self.leave = self.env['hr.leave'].create({
diff --git a/addons/hr_holidays/views/hr_holidays_views.xml b/addons/hr_holidays/views/hr_holidays_views.xml
index 7ff814f70b5..46292c6724d 100644
--- a/addons/hr_holidays/views/hr_holidays_views.xml
+++ b/addons/hr_holidays/views/hr_holidays_views.xml
@@ -28,21 +28,21 @@
@@ -65,7 +65,7 @@
id="menu_hr_holidays_report"
name="Reporting"
parent="menu_hr_holidays_root"
- groups="hr_holidays.group_hr_holidays_manager"
+ groups="hr_holidays.group_hr_holidays_user"
sequence="4"/>
+
+
+
+
+
+