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",)