From 726e34febc9d9d2adc422b96c100b0b0fd4419df Mon Sep 17 00:00:00 2001 From: Laetitia Da Costa Date: Fri, 7 Nov 2025 10:33:15 +0100 Subject: [PATCH] [IMP]hr_negative_leave:add tests --- hr_negative_leave/models/hr_leave_type.py | 25 ++--- hr_negative_leave/tests/__init__.py | 1 + .../tests/test_hr_negative_leave.py | 91 +++++++++++++++++++ 3 files changed, 98 insertions(+), 19 deletions(-) create mode 100644 hr_negative_leave/tests/__init__.py create mode 100644 hr_negative_leave/tests/test_hr_negative_leave.py diff --git a/hr_negative_leave/models/hr_leave_type.py b/hr_negative_leave/models/hr_leave_type.py index 93c13cf..c0e774c 100644 --- a/hr_negative_leave/models/hr_leave_type.py +++ b/hr_negative_leave/models/hr_leave_type.py @@ -15,27 +15,11 @@ class HolidaysType(models.Model): allows_negative = fields.Boolean(string='Allow Negative Leaves', help="If checked, users request can exceed the allocated days and balance can go in negative.") - remaining_leaves_allowing_negative = fields.Float( - string="Remaining Leaves when Negative Allowed", - compute='_compute_remaining_leaves_allowing_negative', - ) - - def _compute_remaining_leaves_allowing_negative(self): - for holiday_type in self: - if holiday_type.allows_negative: - # if left != usable : remaining_leaves_allowing_negative = left + usable - if holiday_type.virtual_remaining_leaves < 0 (holiday_type.max_leaves - holiday_type.virtual_leaves_taken) != holiday_type.virtual_remaining_leaves: - holiday_type.remaining_leaves_allowing_negative = holiday_type.max_leaves - holiday_type.virtual_leaves_taken + holiday_type.virtual_remaining_leaves - else: - # else : remaining_leaves_allowing_negative = left as usual - holiday_type.remaining_leaves_allowing_negative = holiday_type.max_leaves - holiday_type.virtual_leaves_taken - else: - holiday_type.remaining_leaves_allowing_negative = None - @api.depends('requires_allocation') def _compute_valid(self): res = super()._compute_valid() for holiday_type in res: + #if negative is allowed, then the holiday type is valid in any case if not holiday_type.has_valid_allocation: holiday_type.has_valid_allocation = holiday_type.allows_negative @@ -155,9 +139,9 @@ class HolidaysType(models.Model): continue # calculate the number of days/hours for this allocation (allocation days/hours - leaves already taken) virtual_remaining_leaves = (available_allocation.number_of_days if leave_unit == 'days' else available_allocation.number_of_hours_display) - allocations_days_consumed[employee_id][holiday_status_id][available_allocation]['virtual_leaves_taken'] - ########################################### + ############################################# # Modification for leaves allowing negative # - ########################################### + ############################################# # if negative is allowed for this leave type, we can exceed the number of available days in this allocation if holiday_status_id.allows_negative: max_leaves = leave_duration @@ -165,6 +149,9 @@ class HolidaysType(models.Model): # if negative is not allowed for this leave type, then we cannot exceed the allocation amount # the max leaves for this allocation is the minimum between the remaining available days and the leave duration max_leaves = min(virtual_remaining_leaves, leave_duration) + #################################################### + # END OF Modification for leaves allowing negative # + #################################################### # the new calculation of days taken for this allocation is previous taken + max_leaves (which can never exceed the allocation total) days_consumed[available_allocation]['virtual_leaves_taken'] += max_leaves if leave.state == 'validate': diff --git a/hr_negative_leave/tests/__init__.py b/hr_negative_leave/tests/__init__.py new file mode 100644 index 0000000..2314210 --- /dev/null +++ b/hr_negative_leave/tests/__init__.py @@ -0,0 +1 @@ +from . import test_hr_negative_leave \ No newline at end of file diff --git a/hr_negative_leave/tests/test_hr_negative_leave.py b/hr_negative_leave/tests/test_hr_negative_leave.py new file mode 100644 index 0000000..b012ba9 --- /dev/null +++ b/hr_negative_leave/tests/test_hr_negative_leave.py @@ -0,0 +1,91 @@ +from datetime import date, timedelta + +from odoo.tests import tagged +from odoo.tests.common import TransactionCase +from odoo.exceptions import UserError + + +@tagged('post_install', '-at_install') +class TestHrNegativeLeave(TransactionCase): + def setUp(self): + super().setUp() + + # create a simple employee + self.employee = self.env['hr.employee'].create({ + 'name': 'NegTest Employee', + }) + # create a user + self.user = self.env['res.users'].create({ + 'name': 'Test user', + 'login': 'test user', + 'employee_id': self.employee.id, + }) + # prepare a leave type and an allocation with 1 day available + self.leave_type = self.env['hr.leave.type'].create({ + 'name': 'NegTest Type', + 'request_unit': 'day', + 'requires_allocation': 'yes', + 'allows_negative': False, + }) + self.allocation = self.env['hr.leave.allocation'].create({ + 'name': 'Alloc 1d', + 'employee_id': self.employee.id, + 'holiday_status_id': self.leave_type.id, + 'number_of_days': 1.0, + 'date_from': date.today() - timedelta(days=1), + 'allocation_type': 'regular', + }) + + def test_negative_not_allowed_raises(self): + + self.allocation.action_validate() + #self.leave_type._compute_leaves() + + """If the leave type does NOT allow negative, trying to confirm a leave + that exceeds allocations should raise a UserError.""" + leave = self.env['hr.leave'].create({ + 'name': 'Too many days', + 'employee_id': self.employee.id, + 'holiday_status_id': self.leave_type.id, + 'request_date_from': date.today(), + 'request_date_to': date.today() + timedelta(days=1), + 'number_of_days': 2.0, + 'state': 'draft', + }) + # self.leave_type._compute_leaves() + + with self.assertRaises(UserError): + leave.write({'state': 'validate'}) + + def test_negative_allowed_allows_excess(self): + + self.env.user = self.user + self.env.user.employee_id = self.employee + + self.allocation.action_validate() + + """If the leave type allows negative, confirming a leave that exceeds + allocations must NOT raise an error.""" + # flip the flag on the leave type + self.leave_type.allows_negative = True + leave = self.env['hr.leave'].create({ + 'name': 'Too many days', + 'employee_id': self.employee.id, + 'holiday_status_id': self.leave_type.id, + 'date_from': date.today(), + 'date_to': date.today() + timedelta(days=1), + 'number_of_days': 2.0, + 'state': 'draft', + }) + # should not raise + leave.write({'state': 'confirm'}) + + # check remaining leaves is negative + self.leave_type._compute_leaves() + + # Allocated in time off popup (Alloué) + self.assertEqual(self.leave_type.max_leaves, 1, "max_leaves should be 1",) + # Approuved in time off popup (Approuvé) + self.assertEqual(self.leave_type.virtual_leaves_taken, 2, "virtual_leaves_taken should be 2",) + # Remaining in time off popup (Restants) + self.assertEqual(self.leave_type.max_leaves - self.leave_type.virtual_leaves_taken, -1, "remaining leaves should display in timeoff popup -1",)