mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-23 07:32:09 +02:00
19.0 vanilla
This commit is contained in:
parent
a1137a1456
commit
e1d89e11e3
2789 changed files with 1093187 additions and 605897 deletions
|
|
@ -1,3 +1,8 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_hr_work_entry
|
||||
from . import (
|
||||
test_global_time_off,
|
||||
test_hr_work_entry,
|
||||
test_work_entry,
|
||||
test_work_entry_type_data,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from odoo.fields import Date
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestWorkEntryBase(TransactionCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
cls.env.user.tz = 'Europe/Brussels'
|
||||
cls.env.ref('resource.resource_calendar_std').tz = 'Europe/Brussels'
|
||||
|
||||
cls.dep_rd = cls.env['hr.department'].create({
|
||||
'name': 'Research & Development - Test',
|
||||
})
|
||||
|
||||
# I create a new employee "Richard"
|
||||
cls.richard_emp = cls.env['hr.employee'].create({
|
||||
'name': 'Richard',
|
||||
'sex': 'male',
|
||||
'birthday': '1984-05-01',
|
||||
'country_id': cls.env.ref('base.be').id,
|
||||
'department_id': cls.dep_rd.id,
|
||||
'wage': 5000.0,
|
||||
'date_version': Date.to_date('2018-01-01'),
|
||||
'contract_date_start': Date.to_date('2018-01-01'),
|
||||
'contract_date_end': Date.today() + relativedelta(years=2),
|
||||
})
|
||||
|
||||
cls.work_entry_type = cls.env['hr.work.entry.type'].create({
|
||||
'name': 'Extra attendance',
|
||||
'is_leave': False,
|
||||
'code': 'WORKTEST200',
|
||||
})
|
||||
|
||||
cls.work_entry_type_unpaid = cls.env['hr.work.entry.type'].create({
|
||||
'name': 'Unpaid Time Off',
|
||||
'is_leave': True,
|
||||
'code': 'LEAVETEST300',
|
||||
})
|
||||
|
||||
cls.work_entry_type_leave = cls.env['hr.work.entry.type'].create({
|
||||
'name': 'Time Off',
|
||||
'is_leave': True,
|
||||
'code': 'LEAVETEST100'
|
||||
})
|
||||
|
||||
def create_work_entry(self, start, stop, work_entry_type=None):
|
||||
work_entry_type = work_entry_type or self.work_entry_type
|
||||
return self.create_work_entries([(start, stop, work_entry_type)])
|
||||
|
||||
def create_work_entries(self, intervals):
|
||||
default_work_entry_type = self.work_entry_type
|
||||
create_vals = []
|
||||
for interval in intervals:
|
||||
start = interval[0]
|
||||
stop = interval[1]
|
||||
work_entry_type = interval[2] if len(interval) == 3\
|
||||
else default_work_entry_type
|
||||
create_vals.append({
|
||||
'version_id': self.richard_emp.version_ids[0].id,
|
||||
'name': 'Work entry %s-%s' % (start, stop),
|
||||
'date_start': start,
|
||||
'date_stop': stop,
|
||||
'employee_id': self.richard_emp.id,
|
||||
'work_entry_type_id': work_entry_type.id,
|
||||
})
|
||||
create_vals = self.env['hr.version']._generate_work_entries_postprocess(create_vals)
|
||||
return self.env['hr.work.entry'].create(create_vals)
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from .common import TestWorkEntryBase
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestGlobalTimeOff(TestWorkEntryBase):
|
||||
|
||||
def test_gto_other_calendar(self):
|
||||
# Tests that a global time off in another calendar does not affect work entry generation
|
||||
# for other calendars
|
||||
other_calendar = self.env['resource.calendar'].create({
|
||||
'name': 'other calendar',
|
||||
})
|
||||
start = datetime(2018, 1, 1, 0, 0, 0)
|
||||
end = datetime(2018, 1, 1, 23, 59, 59)
|
||||
leave = self.env['resource.calendar.leaves'].create({
|
||||
'date_from': start,
|
||||
'date_to': end,
|
||||
'calendar_id': other_calendar.id,
|
||||
'work_entry_type_id': self.work_entry_type_leave.id,
|
||||
})
|
||||
contract = self.richard_emp.version_id
|
||||
contract.date_generated_from = start
|
||||
contract.date_generated_to = start
|
||||
work_entries = contract.generate_work_entries(start.date(), end.date())
|
||||
self.assertEqual(work_entries.work_entry_type_id.id, contract._get_default_work_entry_type_id())
|
||||
work_entries.unlink()
|
||||
contract.date_generated_from = start
|
||||
contract.date_generated_to = start
|
||||
leave.calendar_id = contract.resource_calendar_id
|
||||
work_entries = contract.generate_work_entries(start.date(), end.date())
|
||||
self.assertEqual(work_entries.work_entry_type_id, leave.work_entry_type_id)
|
||||
|
||||
def test_gto_no_calendar(self):
|
||||
start = datetime(2018, 1, 1, 0, 0, 0)
|
||||
end = datetime(2018, 1, 1, 23, 59, 59)
|
||||
leave = self.env['resource.calendar.leaves'].create({
|
||||
'date_from': start,
|
||||
'date_to': end,
|
||||
'work_entry_type_id': self.work_entry_type_leave.id,
|
||||
})
|
||||
contract = self.richard_emp.version_id
|
||||
contract.date_generated_from = start
|
||||
contract.date_generated_to = start
|
||||
work_entries = contract.generate_work_entries(start.date(), end.date())
|
||||
self.assertEqual(work_entries.work_entry_type_id, leave.work_entry_type_id)
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import date
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
|
||||
class TestHrWorkEntry(TransactionCase):
|
||||
|
|
@ -17,10 +21,15 @@ class TestHrWorkEntry(TransactionCase):
|
|||
cls.employee_a = cls.env['hr.employee'].create({
|
||||
'name': 'Employee A',
|
||||
'company_id': cls.company_a.id,
|
||||
'contract_date_start': '2023-01-01',
|
||||
'date_version': '2023-01-01',
|
||||
})
|
||||
cls.employee_a_first_version = cls.employee_a.version_ids[0]
|
||||
cls.employee_b = cls.env['hr.employee'].create({
|
||||
'name': 'Employee B',
|
||||
'company_id': cls.company_b.id,
|
||||
'contract_date_start': '2023-01-01',
|
||||
'date_version': '2023-01-01',
|
||||
})
|
||||
# Create a work entry type
|
||||
cls.work_entry_type = cls.env['hr.work.entry.type'].create({
|
||||
|
|
@ -34,11 +43,141 @@ class TestHrWorkEntry(TransactionCase):
|
|||
'name': 'Test Work Entry',
|
||||
'employee_id': self.employee_b.id,
|
||||
'work_entry_type_id': self.work_entry_type.id,
|
||||
'date_start': '2024-01-01 08:00:00',
|
||||
'date_stop': '2024-01-01 16:00:00',
|
||||
'date': date(2024, 1, 1),
|
||||
'duration': 8,
|
||||
})
|
||||
self.assertEqual(
|
||||
work_entry.company_id, self.employee_b.company_id,
|
||||
"Work entry should use the employee's company not the current user's company.",
|
||||
)
|
||||
|
||||
def test_work_entry_conflict_no_we_type(self):
|
||||
"""Test that work entry conflicts with no work entry type."""
|
||||
work_entry = self.env['hr.work.entry'].create({
|
||||
'name': 'Test Work Entry',
|
||||
'work_entry_type_id': False,
|
||||
'employee_id': self.employee_b.id,
|
||||
'date': date(2024, 1, 1),
|
||||
'duration': 8,
|
||||
})
|
||||
self.assertEqual(
|
||||
work_entry.state, 'conflict',
|
||||
"Work entry should conflict with no work entry type.",
|
||||
)
|
||||
work_entry = self.env['hr.work.entry'].create({
|
||||
'name': 'Test Work Entry',
|
||||
'work_entry_type_id': self.work_entry_type.id,
|
||||
'employee_id': self.employee_b.id,
|
||||
'date': date(2024, 1, 1),
|
||||
'duration': 8,
|
||||
})
|
||||
self.assertEqual(
|
||||
work_entry.state, 'draft',
|
||||
"Work entry should not conflict with a work entry type.",
|
||||
)
|
||||
work_entry.write({'work_entry_type_id': False})
|
||||
self.assertEqual(
|
||||
work_entry.state, 'conflict',
|
||||
"Work entry should conflict with no work entry type.",
|
||||
)
|
||||
|
||||
def test_work_entry_conflict_sum_duration(self):
|
||||
"""Test that work entry conflicts when the duration for one day is <= 0h or > 24h."""
|
||||
with self.assertRaises(ValidationError), mute_logger('odoo.sql_db'):
|
||||
self.env['hr.work.entry'].create({
|
||||
'name': 'Test Work Entry',
|
||||
'work_entry_type_id': False,
|
||||
'employee_id': self.employee_b.id,
|
||||
'date': date(2024, 1, 1),
|
||||
'duration': 0,
|
||||
})
|
||||
|
||||
work_entry = self.env['hr.work.entry'].create({
|
||||
'name': 'Test Work Entry',
|
||||
'work_entry_type_id': self.work_entry_type.id,
|
||||
'employee_id': self.employee_b.id,
|
||||
'date': date(2024, 1, 1),
|
||||
'duration': 8,
|
||||
})
|
||||
self.assertEqual(
|
||||
work_entry.state, 'draft',
|
||||
"Work entry should be in draft.",
|
||||
)
|
||||
work_entry_2 = self.env['hr.work.entry'].create({
|
||||
'name': 'Test Work Entry 2',
|
||||
'work_entry_type_id': self.work_entry_type.id,
|
||||
'employee_id': self.employee_b.id,
|
||||
'date': date(2024, 1, 1),
|
||||
'duration': 17,
|
||||
})
|
||||
self.assertEqual(
|
||||
(work_entry | work_entry_2).mapped('state'), ['conflict', 'conflict'],
|
||||
"Work entries with a total duration for a same day <= 0h or > 24h should conflict.",
|
||||
)
|
||||
work_entry_2.write({
|
||||
'duration': 16,
|
||||
})
|
||||
self.assertEqual(
|
||||
(work_entry | work_entry_2).mapped('state'), ['draft', 'draft'],
|
||||
"Work entries with a total duration for a same day > 0h and <= 24h should not conflict.",
|
||||
)
|
||||
|
||||
def test_nullify_work_entry_tz(self):
|
||||
"""
|
||||
Test that the work entries of the previous month are not affected when regenerating the next month work entries
|
||||
no matter what's the timezone of the employee
|
||||
"""
|
||||
self.employee_a.tz = 'Europe/Brussels'
|
||||
self.employee_a.resource_calendar_id.tz = 'Europe/Brussels'
|
||||
|
||||
january_work_entries = self.employee_a.generate_work_entries(date(2024, 1, 1), date(2024, 1, 31), force=True)
|
||||
self.employee_a.generate_work_entries(date(2024, 2, 1), date(2024, 2, 28), force=True)
|
||||
|
||||
new_january_work_entries = self.env['hr.work.entry'].search([
|
||||
('employee_id', '=', self.employee_a.id),
|
||||
('date', '>=', date(2024, 1, 1)),
|
||||
('date', '<=', date(2024, 1, 31)),
|
||||
])
|
||||
self.assertEqual(january_work_entries, new_january_work_entries)
|
||||
|
||||
def test_nullify_work_entry(self):
|
||||
"""
|
||||
Test that we correctly nullify the work entries that were previously generated when we add a new version
|
||||
"""
|
||||
january_work_entries = self.employee_a.generate_work_entries(date(2024, 1, 1), date(2024, 1, 31))
|
||||
self.assertTrue(all(we.version_id == self.employee_a_first_version for we in january_work_entries))
|
||||
|
||||
second_version = self.employee_a.create_version({
|
||||
'date_version': date(2023, 12, 1)
|
||||
})
|
||||
self.employee_a.generate_work_entries(date(2024, 1, 1), date(2024, 1, 31))
|
||||
|
||||
all_january_work_entries = self.env['hr.work.entry'].search([
|
||||
('employee_id', '=', self.employee_a.id),
|
||||
('date', '>=', date(2024, 1, 1)),
|
||||
('date', '<=', date(2024, 1, 31)),
|
||||
])
|
||||
|
||||
self.assertEqual(len(all_january_work_entries), 23)
|
||||
self.assertTrue(all(we.version_id == second_version for we in all_january_work_entries))
|
||||
|
||||
def test_work_entry_version_id(self):
|
||||
"""
|
||||
Test that we correctly set the version_id field of the work entry depending on the date
|
||||
"""
|
||||
second_version = self.employee_a.create_version({
|
||||
'date_version': date(2023, 12, 1)
|
||||
})
|
||||
|
||||
v1_we, v2_we = self.env['hr.work.entry'].create([
|
||||
{
|
||||
'date': date(2023, 10, 1),
|
||||
'employee_id': self.employee_a.id,
|
||||
},
|
||||
{
|
||||
'date': date(2024, 1, 1),
|
||||
'employee_id': self.employee_a.id,
|
||||
}
|
||||
])
|
||||
self.assertEqual(v1_we.version_id, self.employee_a_first_version)
|
||||
self.assertEqual(v2_we.version_id, second_version)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,507 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import date, datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import pytz
|
||||
|
||||
from odoo.tests.common import tagged
|
||||
from odoo.addons.hr_work_entry.tests.common import TestWorkEntryBase
|
||||
|
||||
|
||||
@tagged('work_entry')
|
||||
class TestWorkEntry(TestWorkEntryBase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.tz = pytz.timezone(cls.richard_emp.tz)
|
||||
cls.start = datetime(2015, 11, 1, 1, 0, 0)
|
||||
cls.end = datetime(2015, 11, 30, 23, 59, 59)
|
||||
cls.resource_calendar_id = cls.env['resource.calendar'].create({'name': 'My Calendar'})
|
||||
cls.richard_emp.create_version({
|
||||
'date_version': cls.start.date() - relativedelta(days=5),
|
||||
'contract_date_start': cls.start.date() - relativedelta(days=5),
|
||||
'contract_date_end': cls.end.date() + relativedelta(days=5),
|
||||
'name': 'dodo',
|
||||
'resource_calendar_id': cls.resource_calendar_id.id,
|
||||
'wage': 1000,
|
||||
'date_generated_from': cls.end.date() + relativedelta(days=5),
|
||||
})
|
||||
|
||||
def test_no_duplicate(self):
|
||||
self.richard_emp.generate_work_entries(self.start, self.end)
|
||||
pou1 = self.env['hr.work.entry'].search_count([])
|
||||
self.richard_emp.generate_work_entries(self.start, self.end)
|
||||
pou2 = self.env['hr.work.entry'].search_count([])
|
||||
self.assertEqual(pou1, pou2, "Work entries should not be duplicated")
|
||||
|
||||
def test_work_entry(self):
|
||||
self.richard_emp.generate_work_entries(self.start, self.end)
|
||||
attendance_nb = len(self.resource_calendar_id._attendance_intervals_batch(self.start.replace(tzinfo=pytz.utc), self.end.replace(tzinfo=pytz.utc))[False])
|
||||
work_entry_nb = self.env['hr.work.entry'].search_count([
|
||||
('employee_id', '=', self.richard_emp.id),
|
||||
('date', '>=', self.start),
|
||||
('date', '<=', self.end)])
|
||||
self.assertEqual(attendance_nb / 2, work_entry_nb, "One work_entry should be generated for each pair of calendar attendance per day")
|
||||
|
||||
def test_validate_undefined_work_entry(self):
|
||||
work_entry1 = self.env['hr.work.entry'].create({
|
||||
'name': '1',
|
||||
'employee_id': self.richard_emp.id,
|
||||
'version_id': self.richard_emp.version_id.id,
|
||||
'date': self.start.date(),
|
||||
'duration': 4,
|
||||
})
|
||||
work_entry1.work_entry_type_id = False
|
||||
self.assertFalse(work_entry1.action_validate(), "It should not validate work_entries without a type")
|
||||
self.assertEqual(work_entry1.state, 'conflict', "It should change to conflict state")
|
||||
work_entry1.work_entry_type_id = self.work_entry_type
|
||||
self.assertTrue(work_entry1.action_validate(), "It should validate work_entries")
|
||||
|
||||
def test_outside_calendar(self):
|
||||
""" Test leave work entries outside schedule are conflicting """
|
||||
work_entries = self.create_work_entries([
|
||||
# Outside but not a leave
|
||||
(datetime(2018, 10, 13, 3, 0), datetime(2018, 10, 13, 4, 0)),
|
||||
# Outside and a leave
|
||||
(datetime(2018, 10, 13, 1, 0), datetime(2018, 10, 13, 2, 0), self.work_entry_type_leave),
|
||||
])
|
||||
work_entries._mark_leaves_outside_schedule()
|
||||
self.assertEqual(len(work_entries), 1, "The second work entry should not be generated. As it is a leave outside of the working schedule")
|
||||
self.assertNotEqual(work_entries.state, 'conflict', "It should not conflict")
|
||||
|
||||
def test_work_entry_timezone(self):
|
||||
""" Test work entries with different timezone """
|
||||
hk_resource_calendar_id = self.env['resource.calendar'].create({
|
||||
'name': 'HK Calendar',
|
||||
'tz': 'Asia/Hong_Kong',
|
||||
'hours_per_day': 8,
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Tuesday Afternoon', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'})
|
||||
]
|
||||
})
|
||||
hk_employee = self.env['hr.employee'].create({
|
||||
'name': 'HK Employee',
|
||||
'resource_calendar_id': hk_resource_calendar_id.id,
|
||||
'date_version': datetime(2023, 8, 1),
|
||||
'contract_date_start': datetime(2023, 8, 1),
|
||||
'contract_date_end': False,
|
||||
'wage': 1000,
|
||||
})
|
||||
self.env['resource.calendar.leaves'].create({
|
||||
'date_from': pytz.timezone('Asia/Hong_Kong').localize(datetime(2023, 8, 2, 0, 0, 0)).astimezone(pytz.utc).replace(tzinfo=None),
|
||||
'date_to': pytz.timezone('Asia/Hong_Kong').localize(datetime(2023, 8, 2, 23, 59, 59)).astimezone(pytz.utc).replace(tzinfo=None),
|
||||
'calendar_id': hk_resource_calendar_id.id,
|
||||
'work_entry_type_id': self.work_entry_type_leave.id,
|
||||
})
|
||||
self.env.company.resource_calendar_id = hk_resource_calendar_id
|
||||
hk_employee.generate_work_entries(datetime(2023, 8, 1), datetime(2023, 8, 2))
|
||||
work_entries = self.env['hr.work.entry'].search([('employee_id', '=', hk_employee.id)])
|
||||
self.assertEqual(len(work_entries), 2)
|
||||
self.assertEqual(work_entries[0].date, date(2023, 8, 1))
|
||||
self.assertEqual(work_entries[0].duration, 8)
|
||||
self.assertEqual(work_entries[1].date, date(2023, 8, 2))
|
||||
self.assertEqual(work_entries[1].duration, 8)
|
||||
|
||||
def test_separate_overlapping_work_entries_by_type(self):
|
||||
calendar = self.env['resource.calendar'].create({'name': 'Calendar', 'tz': 'Europe/Brussels'})
|
||||
employee = self.env['hr.employee'].create({
|
||||
'name': 'Test',
|
||||
'resource_calendar_id': calendar.id,
|
||||
'date_version': datetime(2024, 9, 1),
|
||||
'contract_date_start': datetime(2024, 9, 1),
|
||||
'contract_date_end': datetime(2024, 9, 30),
|
||||
'wage': 5000.0,
|
||||
})
|
||||
calendar.attendance_ids -= calendar.attendance_ids.filtered(lambda attendance: attendance.dayofweek == '0')
|
||||
|
||||
entry_type_1, entry_type_2 = self.env['hr.work.entry.type'].create([
|
||||
{'name': 'Work type 1', 'is_leave': False, 'code': 'ENTRY_TYPE1'},
|
||||
{'name': 'Work type 2', 'is_leave': False, 'code': 'ENTRY_TYPE2'},
|
||||
])
|
||||
|
||||
self.env['resource.calendar.attendance'].create([
|
||||
{
|
||||
'calendar_id': calendar.id,
|
||||
'dayofweek': '0',
|
||||
'name': 'Same type 1',
|
||||
'hour_from': 8,
|
||||
'hour_to': 11,
|
||||
'day_period': 'morning',
|
||||
'work_entry_type_id': entry_type_1.id,
|
||||
},
|
||||
{
|
||||
'calendar_id': calendar.id,
|
||||
'dayofweek': '0',
|
||||
'name': 'Same type 2',
|
||||
'hour_from': 11,
|
||||
'hour_to': 12,
|
||||
'day_period': 'morning',
|
||||
'work_entry_type_id': entry_type_1.id,
|
||||
},
|
||||
{
|
||||
'calendar_id': calendar.id,
|
||||
'dayofweek': '0',
|
||||
'name': 'Different types 1',
|
||||
'hour_from': 13,
|
||||
'hour_to': 16,
|
||||
'day_period': 'afternoon',
|
||||
'work_entry_type_id': entry_type_1.id,
|
||||
},
|
||||
{
|
||||
'calendar_id': calendar.id,
|
||||
'dayofweek': '0',
|
||||
'name': 'Different types 2',
|
||||
'hour_from': 16,
|
||||
'hour_to': 17,
|
||||
'day_period': 'afternoon',
|
||||
'work_entry_type_id': entry_type_2.id,
|
||||
},
|
||||
])
|
||||
|
||||
employee.generate_work_entries(datetime(2024, 9, 2), datetime(2024, 9, 2))
|
||||
result_entries = self.env['hr.work.entry'].search([('employee_id', '=', employee.id)])
|
||||
work_entry_types = [entry.work_entry_type_id for entry in result_entries]
|
||||
self.assertEqual(len(result_entries), 2, 'A shift should be created for each pair of attendance by day')
|
||||
self.assertEqual(work_entry_types, [entry_type_1, entry_type_2])
|
||||
|
||||
def test_work_entry_duration(self):
|
||||
""" Test the duration of a work entry is rounded to the nearest minute and correctly calculated """
|
||||
vals_list = [{
|
||||
'name': 'Test Work Entry',
|
||||
'employee_id': self.richard_emp.id,
|
||||
'version_id': self.richard_emp.version_id.id,
|
||||
'date_start': datetime(2023, 10, 1, 9, 0, 0),
|
||||
'date_stop': datetime(2023, 10, 1, 9, 59, 59, 999999),
|
||||
'work_entry_type_id': self.work_entry_type.id,
|
||||
}]
|
||||
vals_list = self.env['hr.version']._generate_work_entries_postprocess(vals_list)
|
||||
work_entry = self.env['hr.work.entry'].create(vals_list)
|
||||
self.assertEqual(work_entry.duration, 1, "The duration should be 1 hour")
|
||||
|
||||
def test_work_entry_different_calendars(self):
|
||||
""" Test work entries are correctly created for employees with versions that have different calendar types. """
|
||||
flexible_calendar = self.env['resource.calendar'].create({
|
||||
'name': 'flexible calendar',
|
||||
'flexible_hours': True,
|
||||
'full_time_required_hours': 21,
|
||||
'hours_per_day': 3,
|
||||
'hours_per_week': 21,
|
||||
})
|
||||
# create 4 employees that have versions corresponding to these 4 cases:
|
||||
# flexible calendar then standard calendar
|
||||
# standard calendar then flexible calendar
|
||||
# no calendar (fully flexible) then standard calendar
|
||||
# standard calendar then no calendar (fully flexible)
|
||||
# the cases of flexible then fully flexible and fully flexible then flexible are similar in logic to the last 2
|
||||
# so they should work if last 2 are working properly
|
||||
emp_flex_std, emp_std_flex, emp_fullyflex_std, emp_std_fullyflex = self.env['hr.employee'].create([
|
||||
{'name': 'emp flex std'},
|
||||
{'name': 'emp std flex'},
|
||||
{'name': 'emp fullyflex std'},
|
||||
{'name': 'emp fullyflex std'},
|
||||
])
|
||||
self.env['hr.version'].create([{
|
||||
'employee_id': emp_flex_std.id,
|
||||
'resource_calendar_id': flexible_calendar.id,
|
||||
'date_version': datetime(2025, 9, 1),
|
||||
'contract_date_start': datetime(2025, 9, 1),
|
||||
'contract_date_end': datetime(2025, 9, 15),
|
||||
'name': 'Flex Contract',
|
||||
'wage': 5000.0,
|
||||
'active': True,
|
||||
},
|
||||
{
|
||||
'employee_id': emp_flex_std.id,
|
||||
'resource_calendar_id': self.resource_calendar_id.id,
|
||||
'date_version': datetime(2025, 9, 16),
|
||||
'contract_date_start': datetime(2025, 9, 16),
|
||||
'contract_date_end': datetime(2025, 9, 30),
|
||||
'name': 'Std Contract',
|
||||
'wage': 5000.0,
|
||||
'active': True,
|
||||
},
|
||||
{
|
||||
'employee_id': emp_std_flex.id,
|
||||
'resource_calendar_id': self.resource_calendar_id.id,
|
||||
'date_version': datetime(2025, 9, 1),
|
||||
'contract_date_start': datetime(2025, 9, 1),
|
||||
'contract_date_end': datetime(2025, 9, 15),
|
||||
'name': 'Std Contract',
|
||||
'wage': 5000.0,
|
||||
'active': True,
|
||||
},
|
||||
{
|
||||
'employee_id': emp_std_flex.id,
|
||||
'resource_calendar_id': flexible_calendar.id,
|
||||
'date_version': datetime(2025, 9, 16),
|
||||
'contract_date_start': datetime(2025, 9, 16),
|
||||
'contract_date_end': datetime(2025, 9, 30),
|
||||
'name': 'Flex Contract',
|
||||
'wage': 5000.0,
|
||||
'active': True,
|
||||
},
|
||||
{
|
||||
'employee_id': emp_fullyflex_std.id,
|
||||
'resource_calendar_id': False,
|
||||
'date_version': datetime(2025, 9, 1),
|
||||
'contract_date_start': datetime(2025, 9, 1),
|
||||
'contract_date_end': datetime(2025, 9, 15),
|
||||
'name': 'FullyFlex Contract',
|
||||
'wage': 5000.0,
|
||||
'active': True,
|
||||
},
|
||||
{
|
||||
'employee_id': emp_fullyflex_std.id,
|
||||
'resource_calendar_id': self.resource_calendar_id.id,
|
||||
'date_version': datetime(2025, 9, 16),
|
||||
'contract_date_start': datetime(2025, 9, 16),
|
||||
'contract_date_end': datetime(2025, 9, 30),
|
||||
'name': 'Std Contract',
|
||||
'wage': 5000.0,
|
||||
'active': True,
|
||||
},
|
||||
{
|
||||
'employee_id': emp_std_fullyflex.id,
|
||||
'resource_calendar_id': self.resource_calendar_id.id,
|
||||
'date_version': datetime(2025, 9, 1),
|
||||
'contract_date_start': datetime(2025, 9, 1),
|
||||
'contract_date_end': datetime(2025, 9, 15),
|
||||
'name': 'Std Contract',
|
||||
'wage': 5000.0,
|
||||
'active': True,
|
||||
},
|
||||
{
|
||||
'employee_id': emp_std_fullyflex.id,
|
||||
'resource_calendar_id': False,
|
||||
'date_version': datetime(2025, 9, 16),
|
||||
'contract_date_start': datetime(2025, 9, 16),
|
||||
'contract_date_end': datetime(2025, 9, 30),
|
||||
'name': 'FullyFlex Contract',
|
||||
'wage': 5000.0,
|
||||
'active': True,
|
||||
}])
|
||||
|
||||
half1_date_start = date(2025, 9, 1)
|
||||
half1_date_end = date(2025, 9, 15)
|
||||
half2_date_start = date(2025, 9, 16)
|
||||
half2_date_end = date(2025, 9, 30)
|
||||
|
||||
# generate work entries for the 4 employees between (2025, 9, 1) and (2025, 9, 30)
|
||||
# then split them into 2 halves (each half corresponding to the work entries generated by 1 contract)
|
||||
# the timezones are considered in the split
|
||||
all_work_entries = (emp_flex_std + emp_std_flex + emp_fullyflex_std + emp_std_fullyflex).generate_work_entries(date(2025, 9, 1), date(2025, 9, 30))
|
||||
flex_std_work_entries = all_work_entries.filtered(lambda e: e.employee_id == emp_flex_std)
|
||||
self.assertEqual(len(flex_std_work_entries), 26)
|
||||
half1_entries = flex_std_work_entries.filtered(lambda e:
|
||||
e.date >= half1_date_start
|
||||
and e.date <= half1_date_end)
|
||||
half2_entries = flex_std_work_entries.filtered(lambda e:
|
||||
e.date >= half2_date_start
|
||||
and e.date <= half2_date_end)
|
||||
self.assertEqual(len(half1_entries), 15) # 1 work entry per day (including weekend)
|
||||
self.assertTrue(all(entry.duration == 3 for entry in half1_entries))
|
||||
self.assertTrue(all(entry.version_id.name == 'Flex Contract' for entry in half1_entries))
|
||||
self.assertEqual(len(half2_entries), 11) # 1 work entries per day, no work entries for weekend
|
||||
self.assertTrue(all(entry.duration == 8 for entry in half2_entries))
|
||||
self.assertTrue(all(entry.version_id.name == 'Std Contract' for entry in half2_entries))
|
||||
|
||||
std_flex_work_entries = all_work_entries.filtered(lambda e: e.employee_id == emp_std_flex)
|
||||
self.assertEqual(len(std_flex_work_entries), 26)
|
||||
half1_entries = std_flex_work_entries.filtered(lambda e:
|
||||
e.date >= half1_date_start
|
||||
and e.date <= half1_date_end)
|
||||
half2_entries = std_flex_work_entries.filtered(lambda e:
|
||||
e.date >= half2_date_start
|
||||
and e.date <= half2_date_end)
|
||||
self.assertEqual(len(half1_entries), 11) # 1 work entries per day, no work entries for weekend
|
||||
self.assertTrue(all(entry.duration == 8 for entry in half1_entries))
|
||||
self.assertTrue(all(entry.version_id.name == 'Std Contract' for entry in half1_entries))
|
||||
self.assertEqual(len(half2_entries), 15) # 1 work entry per day (including weekend)
|
||||
self.assertTrue(all(entry.duration == 3 for entry in half2_entries))
|
||||
self.assertTrue(all(entry.version_id.name == 'Flex Contract' for entry in half2_entries))
|
||||
|
||||
fullyflex_std_work_entries = all_work_entries.filtered(lambda e: e.employee_id == emp_fullyflex_std)
|
||||
self.assertEqual(len(fullyflex_std_work_entries), 26)
|
||||
half1_entries = fullyflex_std_work_entries.filtered(lambda e:
|
||||
e.date >= half1_date_start
|
||||
and e.date <= half1_date_end)
|
||||
half2_entries = fullyflex_std_work_entries.filtered(lambda e:
|
||||
e.date >= half2_date_start
|
||||
and e.date <= half2_date_end)
|
||||
self.assertEqual(len(half1_entries), 15) # work entries cover the entire duration
|
||||
self.assertTrue(all(entry.duration == 24 for entry in half1_entries))
|
||||
self.assertTrue(all(entry.version_id.name == 'FullyFlex Contract' for entry in half1_entries))
|
||||
self.assertEqual(len(half2_entries), 11) # 1 work entries per day, no work entries for weekend
|
||||
self.assertTrue(all(entry.duration == 8 for entry in half2_entries))
|
||||
self.assertTrue(all(entry.version_id.name == 'Std Contract' for entry in half2_entries))
|
||||
|
||||
std_fullyflex_work_entries = all_work_entries.filtered(lambda e: e.employee_id == emp_std_fullyflex)
|
||||
self.assertEqual(len(std_fullyflex_work_entries), 26)
|
||||
half1_entries = std_fullyflex_work_entries.filtered(lambda e:
|
||||
e.date >= half1_date_start
|
||||
and e.date <= half1_date_end)
|
||||
half2_entries = std_fullyflex_work_entries.filtered(lambda e:
|
||||
e.date >= half2_date_start
|
||||
and e.date <= half2_date_end)
|
||||
self.assertEqual(len(half1_entries), 11) # 1 work entries per day, no work entries for weekend
|
||||
self.assertTrue(all(entry.duration == 8 for entry in half1_entries))
|
||||
self.assertTrue(all(entry.version_id.name == 'Std Contract' for entry in half1_entries))
|
||||
self.assertEqual(len(half2_entries), 15) # work entries cover the entire duration
|
||||
self.assertTrue(all(entry.duration == 24 for entry in half2_entries))
|
||||
self.assertTrue(all(entry.version_id.name == 'FullyFlex Contract' for entry in half2_entries))
|
||||
|
||||
def test_work_entry_version_changed_after_generation(self):
|
||||
"""
|
||||
When you generate work entries for a version, and you add a new version to the employee starting during the period of already generated work entries,
|
||||
The previous version work entries date generation to should be updated to the new version date and new work entries should be generated.
|
||||
Previous ones should be deleted
|
||||
"""
|
||||
calendar_40h = self.env['resource.calendar'].create({
|
||||
'name': '40h Calendar',
|
||||
'tz': 'Europe/Brussels',
|
||||
'hours_per_day': 8,
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Tuesday Afternoon', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'})
|
||||
]
|
||||
})
|
||||
calendar_35h = self.env['resource.calendar'].create({
|
||||
'name': '35h Calendar',
|
||||
'tz': 'Europe/Brussels',
|
||||
'hours_per_day': 7,
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Tuesday Afternoon', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'})
|
||||
]
|
||||
})
|
||||
|
||||
# first version with a 40h calendar
|
||||
employee = self.env['hr.employee'].create({
|
||||
'name': 'Test',
|
||||
'resource_calendar_id': calendar_40h.id,
|
||||
'date_version': datetime(2025, 1, 1),
|
||||
'contract_date_start': datetime(2025, 1, 1),
|
||||
})
|
||||
employee.generate_work_entries(datetime(2025, 1, 1), datetime(2025, 1, 31))
|
||||
work_entries = self.env['hr.work.entry'].search([('employee_id', '=', employee.id)])
|
||||
self.assertEqual(len(work_entries), 23, "23 attendance")
|
||||
self.assertEqual(sum(work_entries.mapped("duration")), 184, "23 * 8h")
|
||||
|
||||
# new version with a different calendar (35h) set in the tier of the month
|
||||
employee.create_version({
|
||||
'resource_calendar_id': calendar_35h.id,
|
||||
'date_version': datetime(2025, 1, 10),
|
||||
})
|
||||
employee.generate_work_entries(datetime(2025, 1, 1), datetime(2025, 1, 31))
|
||||
work_entries = self.env['hr.work.entry'].search([('employee_id', '=', employee.id)])
|
||||
self.assertEqual(len(work_entries), 23, "23 attendance")
|
||||
self.assertEqual(sum(work_entries.mapped("duration")), 168, "7 * 8h + 16 * 7h")
|
||||
|
||||
# new version with a different calendar (40h) set in the second tier of the month
|
||||
employee.create_version({
|
||||
'resource_calendar_id': calendar_40h.id,
|
||||
'date_version': datetime(2025, 1, 20),
|
||||
})
|
||||
employee.generate_work_entries(datetime(2025, 1, 1), datetime(2025, 1, 31))
|
||||
work_entries = self.env['hr.work.entry'].search([('employee_id', '=', employee.id)])
|
||||
self.assertEqual(len(work_entries), 23, "23 attendance")
|
||||
self.assertEqual(sum(work_entries.mapped("duration")), 178, "7 * 8h + 6 * 7h + 10 * 8h")
|
||||
|
||||
def test_work_entry_version_changed_after_generation2(self):
|
||||
"""
|
||||
When you generate work entries for a version, and you add a new version to the employee starting during the period of already generated work entries,
|
||||
The previous version work entries date generation to should be updated to the new version date and new work entries should be generated.
|
||||
Previous ones should be deleted
|
||||
"""
|
||||
calendar_40h = self.env['resource.calendar'].create({
|
||||
'name': '40h Calendar',
|
||||
'tz': 'Europe/Brussels',
|
||||
'hours_per_day': 8,
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Tuesday Afternoon', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'})
|
||||
]
|
||||
})
|
||||
calendar_35h = self.env['resource.calendar'].create({
|
||||
'name': '35h Calendar',
|
||||
'tz': 'Europe/Brussels',
|
||||
'hours_per_day': 7,
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Tuesday Afternoon', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
|
||||
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 7, 'hour_to': 11, 'day_period': 'morning'}),
|
||||
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'})
|
||||
]
|
||||
})
|
||||
|
||||
# first version with a 40h calendar
|
||||
employee = self.env['hr.employee'].create({
|
||||
'name': 'Test',
|
||||
'resource_calendar_id': calendar_40h.id,
|
||||
'date_version': datetime(2025, 1, 1),
|
||||
'contract_date_start': datetime(2025, 1, 1),
|
||||
})
|
||||
employee.generate_work_entries(datetime(2025, 1, 1), datetime(2025, 1, 31))
|
||||
work_entries = self.env['hr.work.entry'].search([('employee_id', '=', employee.id)])
|
||||
self.assertEqual(len(work_entries), 23, "23 attendance")
|
||||
self.assertEqual(sum(work_entries.mapped("duration")), 184, "23 * 8h")
|
||||
|
||||
# new version with a different calendar (40h) set in the tier of the month
|
||||
employee.create_version({
|
||||
'resource_calendar_id': calendar_40h.id,
|
||||
'date_version': datetime(2025, 1, 20),
|
||||
})
|
||||
employee.generate_work_entries(datetime(2025, 1, 1), datetime(2025, 1, 31))
|
||||
work_entries = self.env['hr.work.entry'].search([('employee_id', '=', employee.id)])
|
||||
self.assertEqual(len(work_entries), 23, "23 attendance")
|
||||
self.assertEqual(sum(work_entries.mapped("duration")), 184, "13 * 8h + 10 * 8h")
|
||||
|
||||
# new version with a different calendar (35h) set in the second tier of the month
|
||||
employee.create_version({
|
||||
'resource_calendar_id': calendar_35h.id,
|
||||
'date_version': datetime(2025, 1, 10),
|
||||
})
|
||||
employee.generate_work_entries(datetime(2025, 1, 1), datetime(2025, 1, 31))
|
||||
work_entries = self.env['hr.work.entry'].search([('employee_id', '=', employee.id)])
|
||||
self.assertEqual(len(work_entries), 23, "23 attendance")
|
||||
self.assertEqual(sum(work_entries.mapped("duration")), 178, "7 * 8h + 6 * 7h + 10 * 8h")
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.release import version_info
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
@tagged('-at_install', 'post_install', 'post_install_l10n')
|
||||
class TestWorkEntryTypeData(TransactionCase):
|
||||
|
||||
def test_ensure_work_entry_type_definition(self):
|
||||
# Make sure work entry types are defined in hr_work_entry in master (and not in other modules)
|
||||
# In the case this tests breaks during a forward port, move the work entry type definition
|
||||
# to hr_work_entry and make a upgrade script accordingly.
|
||||
if version_info[3] != 'alpha':
|
||||
return
|
||||
work_entry_types_xmlids = self.env['hr.work.entry.type'].search([])._get_external_ids()
|
||||
invalid_xmlids = []
|
||||
for xmlids in work_entry_types_xmlids.values():
|
||||
for xmlid in xmlids:
|
||||
module = xmlid.split('.')[0]
|
||||
if module not in ['hr_work_entry', '__export__', '__custom__'] and not module.startswith('test_'):
|
||||
invalid_xmlids.append(xmlid)
|
||||
if invalid_xmlids:
|
||||
raise ValidationError("Some work entry types are defined outside of module hr_work_entry.\n%s" % '\n'.join(invalid_xmlids))
|
||||
Loading…
Add table
Add a link
Reference in a new issue