# Part of Odoo. See LICENSE file for full copyright and licensing details. from datetime import date from psycopg2.errors import CheckViolation from odoo.tests import tagged from odoo.tests.common import freeze_time from odoo.exceptions import AccessError, ValidationError from odoo.tools import mute_logger from odoo.addons.hr.tests.common import TestHrCommon from odoo.addons.mail.tests.common import mail_new_test_user @tagged('post_install', '-at_install') class TestHrVersion(TestHrCommon): def test_dates_constraints(self): employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01' }) self.assertFalse(employee.contract_date_start) self.assertFalse(employee.contract_date_end) employee.write({ 'contract_date_start': '2020-01-01', 'contract_date_end': False }) self.assertEqual(employee.contract_date_start, date(2020, 1, 1)) self.assertFalse(employee.contract_date_end) employee.write({ 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31' }) self.assertEqual(employee.contract_date_start, date(2020, 1, 1)) self.assertEqual(employee.contract_date_end, date(2020, 12, 31)) employee.write({ 'contract_date_start': False, 'contract_date_end': False }) self.assertFalse(employee.contract_date_start) self.assertFalse(employee.contract_date_end) with self.assertRaises(CheckViolation), mute_logger('odoo.sql_db'): employee.write({ 'contract_date_start': False, 'contract_date_end': '2020-12-31' }) with self.assertRaises(ValidationError): employee.write({ 'contract_date_start': '2021-01-01', 'contract_date_end': '2020-12-31' }) def test_contracts_no_overlap(self): # Simple overlap cases employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31' }) with self.assertRaises(ValidationError): employee.create_version({ 'date_version': '2019-06-01', 'contract_date_start': '2019-06-01', 'contract_date_end': '2020-05-31' }) with self.assertRaises(ValidationError): employee.create_version({ 'date_version': '2020-06-01', 'contract_date_start': '2020-06-01', 'contract_date_end': '2021-05-31' }) with self.assertRaises(ValidationError): employee.create_version({ 'date_version': '2020-02-01', 'contract_date_start': '2020-02-01', 'contract_date_end': '2020-10-31' }) # It should not detect overlap with archived versions employee.create_version({ 'active': False, 'date_version': '2019-06-01', 'contract_date_start': '2019-06-01', 'contract_date_end': '2020-05-31' }) def test_occupation_dates(self): """ Occupation dates are global for the employee, they are a list of intervals (date_from, date_to) where the employee is in contract (date_from and date_to included). """ # A single version and no contract employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01' }) self.assertEqual(employee._get_all_contract_dates(), []) # A single version and contract employee.write({ 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31' }) occupation_dates = [(date(2020, 1, 1), date(2020, 12, 31))] self.assertEqual(employee._get_all_contract_dates(), occupation_dates) # 2 versions with 1 contract each employee.create_version({ 'date_version': '2021-01-01', 'contract_date_start': '2021-01-01', 'contract_date_end': '2023-12-31' }) occupation_dates = [ (date(2020, 1, 1), date(2020, 12, 31)), (date(2021, 1, 1), date(2023, 12, 31)), ] self.assertEqual(employee._get_all_contract_dates(), occupation_dates) # 3 versions with 2 sharing the same contract employee.create_version({ 'date_version': '2022-01-01', }) self.assertEqual(employee._get_all_contract_dates(), occupation_dates) # 4 versions with 2 sharing the same contract, the last one is permanent employee.create_version({ 'date_version': '2025-01-01', 'contract_date_start': '2025-01-01', }) occupation_dates = [ (date(2020, 1, 1), date(2020, 12, 31)), (date(2021, 1, 1), date(2023, 12, 31)), (date(2025, 1, 1), False), ] self.assertEqual(employee._get_all_contract_dates(), occupation_dates) def test_dates_new_version_out_of_contract(self): """ If the new version falls on a period out of contract, clear the dates """ # Create a new version after the end of the current contract employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31', }) version = employee.create_version({ 'date_version': '2021-01-01' }) self.assertFalse(version.contract_date_start) self.assertFalse(version.contract_date_end) # Forcing the contract_date_start and or contract_date_end in the 'create' should override False employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31', }) version = employee.create_version({ 'date_version': '2021-01-01', 'contract_date_start': '2021-01-01', 'contract_date_end': '2021-12-31' }) self.assertEqual(version.contract_date_start, date(2021, 1, 1)) self.assertEqual(version.contract_date_end, date(2021, 12, 31)) # Create a new version before the start of the current contract employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31', }) version = employee.create_version({'date_version': '2019-01-01'}) self.assertFalse(version.contract_date_start) self.assertFalse(version.contract_date_end) # Create a new version between two contracts employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31' }) employee.create_version({ 'date_version': '2022-01-01', 'contract_date_start': '2022-01-01', 'contract_date_end': '2022-12-31' }) version = employee.create_version({ 'date_version': '2021-01-01', }) self.assertFalse(version.contract_date_start) self.assertFalse(version.contract_date_end) def test_dates_new_version_in_contract(self): """ If the new version falls on some contract, copy its contract dates """ # Create a new version on a permanent contract employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', }) version = employee.create_version({ 'date_version': '2021-01-01' }) self.assertEqual(version.contract_date_start, date(2020, 1, 1)) self.assertFalse(version.contract_date_end) # Create a new version on a fixed term contract employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'contract_date_start': '2020-01-01', 'contract_date_end': '2021-12-31' }) version = employee.create_version({'date_version': '2021-01-01'}) self.assertEqual(version.contract_date_start, date(2020, 1, 1)) self.assertEqual(version.contract_date_end, date(2021, 12, 31)) # Create a new version on any contract interval regardless of the version valid at that date employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31' }) employee.create_version({ 'date_version': '2022-01-01', 'contract_date_start': '2021-01-01', 'contract_date_end': '2022-12-31' }) version = employee.create_version({ 'date_version': '2021-01-01', }) self.assertEqual(version.contract_date_start, date(2021, 1, 1)) self.assertEqual(version.contract_date_end, date(2022, 12, 31)) def test_dates_synchronisation(self): """ All versions that share or will share (at the end of a 'write') the same contract_date_start are synchronized. """ employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', 'contract_date_end': '2021-12-31', }) v1 = employee.version_id v2 = employee.create_version({ 'date_version': '2021-01-01', 'contract_date_end': '2022-12-31', }) self.assertEqual(v2.contract_date_end, date(2022, 12, 31)) self.assertEqual(v1.contract_date_end, v2.contract_date_end) v1.write({ 'contract_date_start': '2021-01-01', }) self.assertEqual(v1.contract_date_start, date(2021, 1, 1)) self.assertEqual(v1.contract_date_start, v2.contract_date_start) v2.write({ 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31', }) self.assertEqual(v2.contract_date_start, date(2020, 1, 1)) self.assertEqual(v1.contract_date_start, v2.contract_date_start) self.assertEqual(v2.contract_date_end, date(2020, 12, 31)) self.assertEqual(v1.contract_date_end, v2.contract_date_end) v3 = employee.create_version({ 'date_version': '2030-01-01', 'contract_date_start': '2030-01-01', }) versions = [] for i in range(10): versions.append(employee.create_version({ 'date_version': f'20{31 + i}-01-01', })) v3.write({ 'contract_date_end': '2040-12-31', }) for version in versions: self.assertEqual(version.contract_date_end, date(2040, 12, 31)) def test_1_version_contract_synchronisation(self): """ When an employee has only one version, the contract_date_start should be synchronized with the date_version. """ employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', }) version = employee.version_id employee.write({'contract_date_start': '2019-01-01'}) self.assertEqual(version.contract_date_start, version.date_version) # date_version should not be reset if the contract_date_start is set to False employee.write({'contract_date_start': False}) self.assertEqual(version.date_version, date(2019, 1, 1)) employee.write({'contract_date_start': '2021-01-01'}) self.assertEqual(version.contract_date_start, version.date_version) def test_2_versions_contract_synchronisation(self): """ When an employee has two versions, the synchronisation should stop """ employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', }) v1 = employee.version_id employee.write({'contract_date_start': '2019-01-01'}) self.assertEqual(v1.contract_date_start, v1.date_version) v2 = employee.create_version({'date_version': '2021-01-01'}) employee.write({'contract_date_start': '2020-01-01'}) self.assertEqual(v1.date_version, date(2019, 1, 1)) self.assertEqual(v2.date_version, date(2021, 1, 1)) # Archived versions do not count. # So if we archive v2, the synchronisation should start again. v2.active = False employee.write({'contract_date_start': '2021-01-01'}) self.assertEqual(v1.contract_date_start, v1.date_version) def test_in_out_contract(self): """ Check that an employee is in or out of the contract at a specific date. """ # If no contract dates are defined, the employee is not considered in contract employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', }) self.assertFalse(employee._is_in_contract(date(2010, 1, 1))) self.assertFalse(employee._is_in_contract(date(2020, 1, 1))) self.assertFalse(employee._is_in_contract(date(2030, 1, 1))) # In a permanent contract, the employee is contract since the contract_date_start employee.contract_date_start = '2020-01-01' self.assertFalse(employee._is_in_contract(date(2010, 1, 1))) self.assertTrue(employee._is_in_contract(date(2020, 1, 1))) self.assertTrue(employee._is_in_contract(date(2030, 1, 1))) # In a fixed term contract, the employee is contract in between the contract dates employee.contract_date_end = '2029-12-31' self.assertFalse(employee._is_in_contract(date(2010, 1, 1))) self.assertTrue(employee._is_in_contract(date(2020, 1, 1))) self.assertFalse(employee._is_in_contract(date(2030, 1, 1))) def test_cron_update_current_version(self): cron = self.env.ref('hr.ir_cron_data_employee_update_current_version') with freeze_time(date(2020, 1, 1)), self.enter_registry_test_mode(): employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', }) v1 = employee.version_id v2 = employee.create_version({ 'date_version': '2020-01-02' }) self.assertEqual(v1, employee.current_version_id) cron.method_direct_trigger() self.assertEqual(v1, employee.current_version_id) with freeze_time(date(2020, 1, 2)), self.enter_registry_test_mode(): self.assertEqual(v1, employee.current_version_id) cron.method_direct_trigger() self.assertEqual(v2, employee.current_version_id) def test_related_fields_on_version(self): """ Some groups have been added to avoid users with basic access to HR app see some critical (like wage field for instance) This test makes sure the groups added in version fields is also in the employee fields related. However, to define the same groups in employee fields, we have to redefine the related fields (readonly=False, related='version_id.{field_name}) Otherwise, the field we loose the linked with the version field and could be readonly instead of editable. """ version_fields = { f_name: field for f_name, field in self.env['hr.version']._fields.items() if field.groups and field.groups not in ['hr.group_hr_user', 'base.group_user'] and not (field.related and field.related.startswith('employee_id')) } employee_fields = { f_name: field for f_name, field in self.env['hr.employee']._fields.items() if f_name in version_fields } fields_without_group = [] fields_without_related = [] fields_readonly = [] for f_name, field in employee_fields.items(): v_field = version_fields[f_name] if not (field.groups and field.groups != v_field): fields_without_group.append(f_name) elif not (field.related and field.related == f'version_id.{f_name}'): fields_without_related.append(f_name) elif field.readonly != v_field.readonly: fields_readonly.append(f_name) self.assertFalse(fields_without_group, "Inconsistency between some employee fields and version ones (those employees fields should have the same groups than related one in version") self.assertFalse(fields_without_related, "Some employee fields have the same name than the version ones but they are not related") self.assertFalse(fields_readonly, "(Readonly) Inconsistency between some employee fields and version ones, the both fields (in version and employee) have to be readonly or editable") def test_multi_edit_contract_sync_same_contract(self): """ Test the multi-edit contract sync feature when the targeted versions share the same contract. """ employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31', }) versions = employee.version_id versions |= employee.create_version({'date_version': '2020-04-01'}) versions |= employee.create_version({'date_version': '2020-08-01'}) versions[:2].contract_date_end = "2020-9-30" for version in versions: self.assertEqual(version.contract_date_end, date(2020, 9, 30)) def test_multi_edit_contract_sync_different_contract(self): """ Test the multi-edit contract sync feature when the targeted versions have different contracts. """ employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-5-31', }) versions = employee.version_id versions |= employee.create_version({'date_version': '2020-04-01'}) versions |= employee.create_version({ 'date_version': '2020-08-01', 'contract_date_start': '2020-08-01', }) with self.assertRaises(ValidationError): versions[:2].contract_date_end = "2020-9-30" def test_multi_edit_other(self): """ Test the multi-edit when the targeted versions have different contracts Different fields than contract_date_start and contract_date_end are changed. """ jobA = self.env['hr.job'].create({'name': "Job A"}) jobB = self.env['hr.job'].create({'name': "Job B"}) employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-5-31', 'job_id': jobA.id, }) versions = employee.version_id versions |= employee.create_version({'date_version': '2020-04-01'}) versions |= employee.create_version({ 'date_version': '2020-08-01', 'contract_date_start': '2020-08-01', 'job_id': jobA.id, }) versions[1:].job_id = jobB.id self.assertEqual(versions[0].job_id.id, jobA.id) for version in versions[1:]: self.assertEqual(version.job_id.id, jobB.id) def test_multi_edit_other_and_contract_date_sync(self): """ Test the multi-edit when the targeted versions have the same contract Different contract_dates and other fields are changed. """ jobA = self.env['hr.job'].create({'name': "Job A"}) jobB = self.env['hr.job'].create({'name': "Job B"}) employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-12-31', 'job_id': jobA.id, }) versions = employee.version_id versions |= employee.create_version({'date_version': '2020-04-01'}) versions |= employee.create_version({'date_version': '2020-08-01'}) versions[1:].write({ "contract_date_end": "2020-9-30", "job_id": jobB.id, }) self.assertEqual(versions[0].job_id.id, jobA.id) self.assertEqual(versions[0].contract_date_end, date(2020, 9, 30)) for version in versions[1:]: self.assertEqual(version.job_id.id, jobB.id) self.assertEqual(version.contract_date_end, date(2020, 9, 30)) def test_delete_version(self): employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', }) v1 = employee.version_id v2 = employee.create_version({ 'date_version': '2021-01-01', }) v3 = employee.create_version({ 'date_version': '2022-01-01', }) self.assertEqual(employee.current_version_id, v3) v3.unlink() self.assertEqual(employee.current_version_id, v2) v1.unlink() self.assertEqual(employee.current_version_id, v2) with self.assertRaises(ValidationError): v2.unlink() def test_multi_edit_multi_employees_no_contract(self): """ Test the multi-edit when there is one version per employee, without contract """ employee_john, employee_rob = self.env['hr.employee'].create([ { 'name': 'John Doe', 'date_version': '2020-01-01', }, { 'name': 'Rob Carter', 'date_version': '2020-10-18', } ]) versions = (employee_john | employee_rob).version_id versions.write({ 'contract_date_start': '2021-10-10' }) self.assertEqual(versions[0].contract_date_start, date(2021, 10, 10)) self.assertEqual(versions[1].contract_date_start, date(2021, 10, 10)) def test_multi_edit_multi_employees_mix_contract(self): """ Test the multi-edit when there is one version per employee, some with contract """ employee_john, employee_rob = self.env['hr.employee'].create([ { 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', }, { 'name': 'Rob Carter', 'date_version': '2020-10-18', } ]) versions = (employee_john | employee_rob).version_id versions.write({ 'contract_date_start': '2021-10-10' }) self.assertEqual(versions[0].contract_date_start, date(2021, 10, 10)) self.assertEqual(versions[1].contract_date_start, date(2021, 10, 10)) def test_multi_edit_multi_employees_all_contract(self): """ Test the multi-edit when there is one version per employee, all with different contract """ employee_john, employee_rob = self.env['hr.employee'].create([ { 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', }, { 'name': 'Rob Carter', 'date_version': '2020-10-18', 'contract_date_start': '2020-10-18', } ]) versions = (employee_john | employee_rob).version_id versions |= employee_john.create_version({ 'date_version': '2021-08-01', 'contract_date_start': '2020-01-01', }) versions.write({ 'contract_date_start': '2021-10-10' }) self.assertEqual(versions[0].contract_date_start, date(2021, 10, 10)) self.assertEqual(versions[1].contract_date_start, date(2021, 10, 10)) self.assertEqual(versions[2].contract_date_start, date(2021, 10, 10)) def test_multi_edit_multi_employees_incompatible(self): """ Test the multi-edit when there is one version per employee, one with incompatible dates """ employee_john, employee_rob = self.env['hr.employee'].create([ { 'name': 'John Doe', 'date_version': '2020-01-01', 'contract_date_start': '2020-01-01', 'contract_date_end': '2020-10-10' }, { 'name': 'Rob Carter', 'date_version': '2020-10-18', 'contract_date_start': '2020-10-18', } ]) versions = (employee_john | employee_rob).version_id versions |= employee_john.create_version({ 'date_version': '2021-08-01', 'contract_date_start': '2021-08-01', }) with self.assertRaises(ValidationError): versions.write({ 'contract_date_start': '2021-10-10' }) def test_hr_version_fields_tracking(self): tracking_blacklist = { "__last_update", "active_employee", "activity_ids", "company_country_id", "contract_wage", "country_code", "create_date", "create_uid", "currency_id", "date_end", "date_start", "departure_description", "display_name", "id", "is_current", "is_flexible", "is_fully_flexible", "is_future", "is_in_contract", "is_past", "job_title", "last_modified_date", "last_modified_on", "last_modified_uid", "member_of_department", "message_follower_ids", "message_ids", "message_partner_ids", "rating_ids", "template_warning", "tz", "website_message_ids", "work_location_name", "work_location_type", "write_date", "write_uid", } hr_version_model = self.env['hr.version'] fields_without_tracking = [] for field_name, field in hr_version_model._fields.items(): if field_name in tracking_blacklist: continue if field.compute and not field.inverse: continue if field.related: continue if hasattr(field, 'store') and field.store is False: continue if hasattr(field, 'tracking') and not field.tracking: fields_without_tracking.append(field_name) self.assertFalse( fields_without_tracking, f"The following hr.version fields should have tracking=True: {fields_without_tracking}", ) def test_related_fields_on_version_onchange(self): """ This test is to ensure that each _onchange method on version has a corresponding _onchange on employee that calls it. """ version_methods = {method for method in dir(self.env['hr.version']) if method.startswith('_onchange')} employee_methods = {method for method in dir(self.env['hr.employee']) if method.startswith('_onchange')} not_implemented_onchanges = version_methods - employee_methods self.assertFalse( not_implemented_onchanges, f"""The following _onchange methods on hr.version should have corresponding methods implemented on hr.employee: {not_implemented_onchanges}\n You might need to implement methods with the same name on hr.employee and call the corresponding self.version_id._onchange inside""" ) def test_search_on_version_fields(self): Department = self.env['hr.department'].with_context(tracking_disable=True) rd_dep = Department.create({ 'name': 'Research and devlopment', }) employee1, employee2 = employees = self.env['hr.employee'].create([ { 'contract_date_start': '2020-10-10', 'wage': 3000, 'name': 'Employee1', 'hr_responsible_id': self.res_users_hr_manager.id, 'department_id': rd_dep.id, }, { 'contract_date_start': '2022-10-10', 'wage': 2000, 'name': 'Employee2', }, ]) internal_user = mail_new_test_user( self.env, email='internal_user@example.com', login='internal_user', name='Internal User', ) self.employee.department_id = rd_dep self.employee.user_id = internal_user HrEmployeePublic_with_internal_user = self.env['hr.employee.public'].with_user(internal_user) with self.assertRaises(AccessError, msg="Internal user should not be able to access to hr.employee model"): HrEmployeePublic_with_internal_user.search([ ('employee_id.contract_date_start', '<', '2022-01-01'), ('id', 'in', employees.ids), ]) with self.assertRaises(AccessError, msg="Internal user should not be able to access to hr.employee model"): HrEmployeePublic_with_internal_user.search([('employee_id.wage', '=', 2000), ('id', 'in', employees.ids)]) with self.assertRaises(AccessError, msg="Internal user should not be able to access to hr.employee model"): HrEmployeePublic_with_internal_user.search([('employee_id.version_id.wage', '=', 2000), ('id', 'in', employees.ids)]) self.assertEqual( HrEmployeePublic_with_internal_user.search([('name', '=', 'Employee2'), ('id', 'in', employees.ids)]), self.env['hr.employee.public'].browse(employee2.id), ) self.assertEqual( HrEmployeePublic_with_internal_user.search([('member_of_department', '=', True), ('id', 'in', employees.ids)]), self.env['hr.employee.public'].browse(employee1.id), ) HrEmployee_with_office_user = self.env['hr.employee'].with_user(self.res_users_hr_officer) self.employee.user_id = self.res_users_hr_officer with self.assertRaises(AccessError, msg="HR Officer should not be able to access to 'payroll fields'"): HrEmployee_with_office_user.search([('contract_date_start', '<', '2022-01-01'), ('id', 'in', employees.ids)]) with self.assertRaises(AccessError, msg="HR Officer should not be able to access to 'payroll fields'"): HrEmployee_with_office_user.search([('wage', '=', 2000), ('id', 'in', employees.ids)]) with self.assertRaises(AccessError, msg="HR Officer should not be able to access to 'payroll fields'"): HrEmployee_with_office_user.search([('version_id.wage', '=', 2000), ('id', 'in', employees.ids)]) self.assertEqual(HrEmployee_with_office_user.search([('name', '=', 'Employee1'), ('id', 'in', employees.ids)]), employee1) self.assertEqual(HrEmployee_with_office_user.search([('hr_responsible_id', '=', self.res_users_hr_manager.id), ('id', 'in', employees.ids)]), employee1) self.assertEqual(HrEmployee_with_office_user.search([('version_id.hr_responsible_id', '=', self.res_users_hr_manager.id), ('id', 'in', employees.ids)]), employee1) self.assertEqual(HrEmployee_with_office_user.search([('member_of_department', '=', True), ('id', 'in', employees.ids)]), employee1) if payroll_group := self.env.ref('hr_payroll.group_hr_payroll_user', raise_if_not_found=False): self.res_users_hr_manager.group_ids += payroll_group HrEmployee_with_manager_user = self.env['hr.employee'].with_user(self.res_users_hr_manager) self.employee.user_id = self.res_users_hr_manager self.assertEqual(HrEmployee_with_manager_user.search([('contract_date_start', '<', '2022-01-01'), ('id', 'in', employees.ids)]), employee1) self.assertEqual(HrEmployee_with_manager_user.search([('wage', '=', 2000), ('id', 'in', employees.ids)]), employee2) self.assertEqual(HrEmployee_with_manager_user.search([('version_id.wage', '=', 2000), ('id', 'in', employees.ids)]), employee2) self.assertEqual(HrEmployee_with_manager_user.search([('hr_responsible_id', '=', self.res_users_hr_manager.id), ('id', 'in', employees.ids)]), employee1) self.assertEqual(HrEmployee_with_manager_user.search([('version_id.hr_responsible_id', '=', self.res_users_hr_manager.id), ('id', 'in', employees.ids)]), employee1) self.assertEqual(HrEmployee_with_manager_user.search([('member_of_department', '=', True), ('id', 'in', employees.ids)]), employee1) def test_archive_or_unassign_all_versions(self): employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', }) another_employee = self.env['hr.employee'].create({ 'name': 'Jane Doe' }) employee.create_version({ 'date_version': '2021-01-01', }) # make sure there are at least 2 versions self.assertEqual(len(employee.version_ids), 2) # attempt to archive all versions with self.assertRaises(ValidationError): employee.version_ids.action_archive() # attempt to reassign all versions with self.assertRaises(ValidationError): employee.version_ids.write({"employee_id": another_employee.id}) def test_unlink_version_except_one(self): employee = self.env['hr.employee'].create({ 'name': 'John Doe', 'date_version': '2020-01-01', }) version = employee.create_version({ 'date_version': '2021-01-01', }) self.assertEqual(len(employee.version_ids), 2) version.unlink() self.assertEqual(len(employee.version_ids), 1) def test_date_version_sync_contract_date_start_for_single_version(self): """ This test is to ensure that in case when an employee has only one version, writing contract_date_start on the employee will synchronize the version.date_version with that contract_date_start """ with freeze_time(date(2025, 12, 20)), self.enter_registry_test_mode(): employee = self.env['hr.employee'].create({ 'name': 'John Doe', }) version = employee.version_id self.assertEqual(version.date_version, date(2025, 12, 20)) employee.write({'contract_date_start': '2025-12-10'}) self.assertEqual(version.contract_date_start, date(2025, 12, 10)) self.assertEqual(version.date_version, date(2025, 12, 10)) # date_version should not be reset if contract_date_start is cleared employee.write({'contract_date_start': False}) self.assertEqual(version.date_version, date(2025, 12, 10)) # and setting it again should re-sync employee.write({'contract_date_start': '2025-12-15'}) self.assertEqual(version.contract_date_start, date(2025, 12, 15)) self.assertEqual(version.date_version, date(2025, 12, 15))