# -*- coding: utf-8 -*- # Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. from datetime import datetime from dateutil.relativedelta import relativedelta from flectra.exceptions import AccessError, ValidationError, UserError from flectra.tools import mute_logger, test_reports from flectra.addons.hr_holidays.tests.common import TestHrHolidaysBase class TestHolidaysFlow(TestHrHolidaysBase): @mute_logger('flectra.addons.base.ir.ir_model', 'flectra.models') def test_00_leave_request_flow(self): """ Testing leave request flow """ Holidays = self.env['hr.holidays'] HolidaysStatus = self.env['hr.holidays.status'] def _check_holidays_status(holiday_status, ml, lt, rl, vrl): self.assertEqual(holiday_status.max_leaves, ml, 'hr_holidays: wrong type days computation') self.assertEqual(holiday_status.leaves_taken, lt, 'hr_holidays: wrong type days computation') self.assertEqual(holiday_status.remaining_leaves, rl, 'hr_holidays: wrong type days computation') self.assertEqual(holiday_status.virtual_remaining_leaves, vrl, 'hr_holidays: wrong type days computation') # HrUser creates some holiday statuses -> crash because only HrManagers should do this with self.assertRaises(AccessError): HolidaysStatus.sudo(self.user_hruser_id).create({ 'name': 'UserCheats', 'limit': True, }) # HrManager creates some holiday statuses HolidayStatusManagerGroup = HolidaysStatus.sudo(self.user_hrmanager_id) HolidayStatusManagerGroup.create({ 'name': 'WithMeetingType', 'limit': True, 'categ_id': self.env['calendar.event.type'].sudo(self.user_hrmanager_id).create({'name': 'NotLimitedMeetingType'}).id }) self.holidays_status_1 = HolidayStatusManagerGroup.create({ 'name': 'NotLimited', 'limit': True, }) self.holidays_status_2 = HolidayStatusManagerGroup.create({ 'name': 'Limited', 'limit': False, 'double_validation': True, }) # -------------------------------------------------- # Case1: unlimited type of leave request # -------------------------------------------------- # Employee creates a leave request for another employee -> should crash HolidaysEmployeeGroup = Holidays.sudo(self.user_employee_id) with self.assertRaises(ValidationError): HolidaysEmployeeGroup.create({ 'name': 'Hol10', 'employee_id': self.employee_hruser_id, 'holiday_status_id': self.holidays_status_1.id, 'date_from': (datetime.today() - relativedelta(days=1)), 'date_to': datetime.today(), 'number_of_days_temp': 1, }) Holidays.search([('name', '=', 'Hol10')]).unlink() # Employee creates a leave request in a no-limit category hol1_employee_group = HolidaysEmployeeGroup.create({ 'name': 'Hol11', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.holidays_status_1.id, 'date_from': (datetime.today() - relativedelta(days=1)), 'date_to': datetime.today(), 'number_of_days_temp': 1, }) hol1_user_group = hol1_employee_group.sudo(self.user_hruser_id) self.assertEqual(hol1_user_group.state, 'confirm', 'hr_holidays: newly created leave request should be in confirm state') # Employee validates its leave request -> should not work with self.assertRaises(UserError): hol1_employee_group.action_approve() self.assertEqual(hol1_user_group.state, 'confirm', 'hr_holidays: employee should not be able to validate its own leave request') # HrUser validates the employee leave request hol1_user_group.action_approve() self.assertEqual(hol1_user_group.state, 'validate', 'hr_holidays: validates leave request should be in validate state') # -------------------------------------------------- # Case2: limited type of leave request # -------------------------------------------------- # Employee creates a new leave request at the same time -> crash, avoid interlapping with self.assertRaises(ValidationError): HolidaysEmployeeGroup.create({ 'name': 'Hol21', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.holidays_status_1.id, 'date_from': (datetime.today() - relativedelta(days=1)).strftime('%Y-%m-%d %H:%M'), 'date_to': datetime.today(), 'number_of_days_temp': 1, }) # Employee creates a leave request in a limited category -> crash, not enough days left with self.assertRaises(ValidationError): HolidaysEmployeeGroup.create({ 'name': 'Hol22', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.holidays_status_2.id, 'date_from': (datetime.today() + relativedelta(days=0)).strftime('%Y-%m-%d %H:%M'), 'date_to': (datetime.today() + relativedelta(days=1)), 'number_of_days_temp': 1, }) # Clean transaction Holidays.search([('name', 'in', ['Hol21', 'Hol22'])]).unlink() # HrUser allocates some leaves to the employee aloc1_user_group = Holidays.sudo(self.user_hruser_id).create({ 'name': 'Days for limited category', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.holidays_status_2.id, 'type': 'add', 'number_of_days_temp': 2, }) # HrUser validates the first step aloc1_user_group.action_approve() # HrManager validates the second step aloc1_user_group.sudo(self.user_hrmanager_id).action_validate() # Checks Employee has effectively some days left hol_status_2_employee_group = self.holidays_status_2.sudo(self.user_employee_id) _check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 2.0) # Employee creates a leave request in the limited category, now that he has some days left hol2 = HolidaysEmployeeGroup.create({ 'name': 'Hol22', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.holidays_status_2.id, 'date_from': (datetime.today() + relativedelta(days=2)).strftime('%Y-%m-%d %H:%M'), 'date_to': (datetime.today() + relativedelta(days=3)), 'number_of_days_temp': 1, }) hol2_user_group = hol2.sudo(self.user_hruser_id) # Check left days: - 1 virtual remaining day _check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 1.0) # HrUser validates the first step hol2_user_group.action_approve() self.assertEqual(hol2.state, 'validate1', 'hr_holidays: first validation should lead to validate1 state') # HrManager validates the second step hol2_user_group.sudo(self.user_hrmanager_id).action_validate() self.assertEqual(hol2.state, 'validate', 'hr_holidays: second validation should lead to validate state') # Check left days: - 1 day taken _check_holidays_status(hol_status_2_employee_group, 2.0, 1.0, 1.0, 1.0) # HrManager finds an error: he refuses the leave request hol2.sudo(self.user_hrmanager_id).action_refuse() self.assertEqual(hol2.state, 'refuse', 'hr_holidays: refuse should lead to refuse state') # Check left days: 2 days left again _check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 2.0) # Annoyed, HrUser tries to fix its error and tries to reset the leave request -> does not work, only HrManager with self.assertRaises(UserError): hol2_user_group.action_draft() self.assertEqual(hol2.state, 'refuse', 'hr_holidays: hr_user should not be able to reset a refused leave request') # HrManager resets the request hol2_manager_group = hol2.sudo(self.user_hrmanager_id) hol2_manager_group.action_draft() self.assertEqual(hol2.state, 'draft', 'hr_holidays: resetting should lead to draft state') # HrManager changes the date and put too much days -> crash when confirming hol2_manager_group.write({ 'date_from': (datetime.today() + relativedelta(days=4)).strftime('%Y-%m-%d %H:%M'), 'date_to': (datetime.today() + relativedelta(days=7)), 'number_of_days_temp': 4, }) with self.assertRaises(ValidationError): hol2_manager_group.action_confirm() employee_id = self.ref('hr.employee_root') # cl can be of maximum 20 days for employee_root hol3_status = self.env.ref('hr_holidays.holiday_status_cl').with_context(employee_id=employee_id) # I assign the dates in the holiday request for 1 day hol3 = Holidays.create({ 'name': 'Sick Leave', 'holiday_status_id': hol3_status.id, 'date_from': datetime.today().strftime('%Y-%m-10 10:00:00'), 'date_to': datetime.today().strftime('%Y-%m-11 19:00:00'), 'employee_id': employee_id, 'type': 'remove', 'number_of_days_temp': 1 }) # I find a small mistake on my leave request to I click on "Refuse" button to correct a mistake. hol3.action_refuse() self.assertEqual(hol3.state, 'refuse', 'hr_holidays: refuse should lead to refuse state') # I again set to draft and then confirm. hol3.action_draft() self.assertEqual(hol3.state, 'draft', 'hr_holidays: resetting should lead to draft state') 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() self.assertEqual(hol3.state, 'validate', 'hr_holidays: validation should lead to validate state') # Check left days for casual leave: 19 days left _check_holidays_status(hol3_status, 20.0, 1.0, 19.0, 19.0) def test_10_leave_summary_reports(self): # Print the HR Holidays(Summary Department) Report through the wizard ctx = { 'model': 'hr.department', 'active_ids': [self.ref('hr.employee_root'), self.ref('hr.employee_qdp'), self.ref('hr.employee_al')] } data_dict = { 'date_from': datetime.today().strftime('%Y-%m-01'), 'depts': [(6, 0, [self.ref('hr.dep_sales')])], 'holiday_type': 'Approved' } test_reports.try_report_action(self.env.cr, self.env.uid, 'action_hr_holidays_summary_dept', wiz_data=data_dict, context=ctx, our_module='hr_holidays') # Print the HR Holidays(Summary Employee) Report through the wizard ctx = { 'model': 'hr.employee', 'active_ids': [self.ref('hr.employee_root'), self.ref('hr.employee_qdp'), self.ref('hr.employee_al')] } data_dict = { 'date_from': datetime.today().strftime('%Y-%m-01'), 'emp': [(6, 0, [self.ref('hr.employee_root'), self.ref('hr.employee_qdp'), self.ref('hr.employee_al')])], 'holiday_type': 'Approved' } test_reports.try_report_action(self.env.cr, self.env.uid, 'action_hr_holidays_summary_employee', wiz_data=data_dict, context=ctx, our_module='hr_holidays')