This commit is contained in:
esam 2025-12-22 10:44:05 -05:00
parent 57fc66b6bc
commit 7f4b8910d6
7 changed files with 781 additions and 0 deletions

View File

@ -5,3 +5,4 @@ from . import test_signin_signout_constraints
from . import test_flexible_hours_computation
from . import test_calendar_update_flow
from . import test_attendance_report_calculations
from . import test_attendance_transaction_timing

View File

@ -163,3 +163,192 @@ class TestFlexibleAttendanceReport(TransactionCase):
self.assertAlmostEqual(result['missing_punch_hours'], 4.0, msg="Missing punch hours failed")
class TestHrAttendanceReportApproved(TransactionCase):
def setUp(self):
super(TestHrAttendanceReportApproved, self).setUp()
self.manager_user = self.env['hr.employee'].create({
'name': 'Manager',
'finger_print': False
})
self.dept = self.env['hr.department'].create({
'name': 'IT',
'manager_id': self.manager_user.id
})
self.calendar = self.env['resource.calendar'].create({
'name': 'Test Calendar',
'is_full_day': True,
'full_min_sign_in': 8.0,
'full_max_sign_in': 9.0,
'full_min_sign_out': 16.0,
'full_max_sign_out': 17.0,
'working_hours': 8.0,
'working_days': 5,
'state': 'confirm',
})
self.salary_category = self.env['hr.salary.rule.category'].create({
'name': 'Test Deductions',
'code': 'TEST_DED_CAT'
})
self.deduction_rule = self.env['hr.salary.rule'].create({
'name': 'Test Deduction Rule',
'code': 'TEST_DED',
'category_id': self.salary_category.id,
})
self.calendar.deduction_rule = self.deduction_rule
self.employee = self.env['hr.employee'].create({
'name': 'Ahmed Ali',
'department_id': self.dept.id,
'finger_print': True,
'state': 'open',
'resource_calendar_id': self.calendar.id,
})
self.contract = self.env['hr.contract'].create({
'name': 'Test Contract',
'employee_id': self.employee.id,
'total_allowance': 4000.0,
'state': 'program_directory',
'date_start': date(2023, 1, 1),
'resource_calendar_id': self.calendar.id,
})
self.employee.contract_id = self.contract
self.create_attendance_transactions()
self.report = self.env['hr.attendance.report'].create({
'name': 'Test Approved Report',
'date_from': date(2023, 10, 1),
'date_to': date(2023, 10, 5),
'deduct_date_from': date(2023, 10, 1),
'deduct_date_to': date(2023, 10, 31),
'selected_employee_ids': [(4, self.employee.id)]
})
def create_attendance_transactions(self):
self.env['hr.attendance.transaction'].create({
'employee_id': self.employee.id,
'calendar_id': self.calendar.id,
'attending_type': 'in_cal',
'sequence': 1,
'date': date(2023, 10, 1),
'plan_hours': 8.0,
'is_absent': True
})
def test_01_approved_creates_advantage_record(self):
self.report.generate_report()
line = self.report.line_ids[0]
self.assertGreater(line.total_deduction, 0.0, "Must have deduction")
self.assertFalse(line.advantage_id, "No advantage before approved")
self.report.approved()
self.assertEqual(self.report.state, 'approved', "State must be approved")
self.assertTrue(line.advantage_id, "Advantage record must be created")
advantage = line.advantage_id
self.assertEqual(advantage.employee_id, self.employee)
self.assertEqual(advantage.amount, line.total_deduction)
self.assertEqual(advantage.benefits_discounts.id, self.deduction_rule.id)
self.assertEqual(advantage.contract_advantage_id, self.contract)
self.assertEqual(advantage.date_from, self.report.deduct_date_from)
self.assertEqual(advantage.date_to, self.report.deduct_date_to)
self.assertEqual(advantage.state, 'confirm')
self.assertEqual(advantage.comments, 'Absence Deduction')
self.assertTrue(advantage.out_rule)
def test_02_approved_no_contract_no_advantage(self):
employee_no_contract = self.env['hr.employee'].create({
'name': 'No Contract Employee',
'finger_print': True,
'state': 'open',
'resource_calendar_id': self.calendar.id,
})
self.env['hr.attendance.transaction'].create({
'employee_id': employee_no_contract.id,
'calendar_id': self.calendar.id,
'attending_type': 'in_cal',
'sequence': 1,
'date': date(2023, 10, 1),
'plan_hours': 8.0,
'is_absent': True
})
report_no_contract = self.env['hr.attendance.report'].create({
'name': 'No Contract Report',
'date_from': date(2023, 10, 1),
'date_to': date(2023, 10, 5),
'deduct_date_from': date(2023, 10, 1),
'deduct_date_to': date(2023, 10, 31),
'selected_employee_ids': [(4, employee_no_contract.id)]
})
report_no_contract.generate_report()
line = report_no_contract.line_ids[0]
report_no_contract.approved()
self.assertFalse(line.advantage_id, "No advantage without contract")
def test_03_approved_no_fingerprint_no_advantage(self):
self.employee.finger_print = False
self.report.generate_report()
line = self.report.line_ids[0]
self.report.approved()
self.assertFalse(line.advantage_id, "No advantage without fingerprint")
def test_04_multiple_lines_multiple_advantages(self):
employee2 = self.env['hr.employee'].create({
'name': 'Second Employee',
'finger_print': True,
'state': 'open',
'resource_calendar_id': self.calendar.id,
'department_id': self.dept.id
})
contract2 = self.env['hr.contract'].create({
'name': 'Second Contract',
'employee_id': employee2.id,
'total_allowance': 3000.0,
'state': 'program_directory',
'resource_calendar_id': self.calendar.id,
})
employee2.contract_id = contract2
self.env['hr.attendance.transaction'].create({
'employee_id': employee2.id,
'calendar_id': self.calendar.id,
'attending_type': 'in_cal',
'sequence': 1,
'date': date(2023, 10, 2),
'plan_hours': 8.0,
'is_absent': True
})
self.report.write({'selected_employee_ids': [(4, employee2.id)]})
self.report.generate_report()
self.assertFalse(self.report.line_ids[0].advantage_id)
self.assertFalse(self.report.line_ids[1].advantage_id)
self.report.approved()
self.assertTrue(self.report.line_ids[0].advantage_id)
self.assertTrue(self.report.line_ids[1].advantage_id)
self.assertNotEqual(
self.report.line_ids[0].advantage_id.id,
self.report.line_ids[1].advantage_id.id
)

View File

@ -0,0 +1,252 @@
from odoo.tests.common import TransactionCase
from datetime import date
from odoo import fields
class TestAttendanceTransactionTiming(TransactionCase):
def setUp(self):
super(TestAttendanceTransactionTiming, self).setUp()
self.employee = self.env['hr.employee'].create({'name': 'Test Employee'})
self.calendar_full = self.env['resource.calendar'].create({
'name': 'Full Day Calendar',
'is_full_day': True,
'full_min_sign_in': 8.0,
'full_max_sign_in': 9.0,
'full_min_sign_out': 16.0,
'full_max_sign_out': 17.0,
'working_hours': 8.0,
'state': 'confirm',
})
self.calendar_shift1 = self.env['resource.calendar'].create({
'name': 'Shift 1 Calendar',
'is_full_day': False,
'shift_one_min_sign_in': 7.0,
'shift_one_max_sign_in': 8.0,
'shift_one_min_sign_out': 15.0,
'shift_one_max_sign_out': 16.0,
'shift_one_working_hours': 8.0,
'state': 'confirm',
})
self.employee.resource_calendar_id = self.calendar_full
def test_scenario1_lateness_full_day(self):
transaction = self.env['hr.attendance.transaction'].create({
'employee_id': self.employee.id,
'calendar_id': self.calendar_full.id,
'date': date(2025, 1, 1),
'sign_in': 9.5,
'sign_out': 17.0,
'sequence': 1,
})
transaction.set_lateness_and_exit(transaction)
self.assertEqual(transaction.lateness, 0.5)
self.assertTrue(transaction.approve_lateness)
self.assertFalse(transaction.approve_exit_out)
def test_scenario2_early_exit_shift1(self):
transaction = self.env['hr.attendance.transaction'].create({
'employee_id': self.employee.id,
'calendar_id': self.calendar_shift1.id,
'date': date(2025, 1, 2),
'sign_in': 7.5,
'sign_out': 14.0,
'sequence': 1,
})
transaction.set_lateness_and_exit(transaction)
self.assertEqual(transaction.early_exit, 1.5)
self.assertTrue(transaction.approve_exit_out)
self.assertFalse(transaction.approve_lateness)
class TestAttendanceAdditionalHours(TransactionCase):
def setUp(self):
super(TestAttendanceAdditionalHours, self).setUp()
self.employee = self.env['hr.employee'].sudo().create({'name': 'Test Employee'})
self.calendar = self.env['resource.calendar'].sudo().create({
'name': 'Test Calendar',
'working_hours': 0.0,
'working_days': 5,
'state': 'confirm',
})
def test_overtime_calculation(self):
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar.id,
'plan_hours': 8.0,
'office_hours': 10.0,
'sign_in': 8.0,
})
transaction.get_additional_hours()
transaction = self.env['hr.attendance.transaction'].sudo().browse(transaction.id)
expected = 2.0
self.assertEqual(transaction.additional_hours, expected)
def test_no_overtime(self):
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar.id,
'plan_hours': 8.0,
'office_hours': 7.0,
})
transaction.get_additional_hours()
transaction = self.env['hr.attendance.transaction'].sudo().browse(transaction.id)
self.assertEqual(transaction.additional_hours, 0.0)
def test_mission_hours(self):
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar.id,
'sign_in': False,
'plan_hours': 8.0,
'total_mission_hours': 9.0,
})
transaction.get_additional_hours()
transaction = self.env['hr.attendance.transaction'].sudo().browse(transaction.id)
self.assertEqual(transaction.office_hours, 9.0)
self.assertEqual(transaction.official_hours, 9.0)
self.assertEqual(transaction.additional_hours, 1.0)
def test_sign_in_zero_mission(self):
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar.id,
'sign_in': 0.0,
'plan_hours': 8.0,
'office_hours': 6.0,
})
transaction.get_additional_hours()
transaction = self.env['hr.attendance.transaction'].sudo().browse(transaction.id)
self.assertEqual(transaction.additional_hours, 0.0)
class TestDayTimingCalculation(TransactionCase):
def setUp(self):
super(TestDayTimingCalculation, self).setUp()
self.employee = self.env['hr.employee'].sudo().create({'name': 'Test Employee'})
self.calendar_full = self.env['resource.calendar'].sudo().create({
'name': 'Full Day Calendar',
'working_hours': 8.0,
'break_duration': 1.0,
'full_min_sign_in': 8.0,
'full_max_sign_in': 9.0,
'full_min_sign_out': 16.0,
'full_max_sign_out': 17.0,
'is_full_day': True,
})
self.calendar_shift = self.env['resource.calendar'].sudo().create({
'name': 'Shift Calendar',
'shift_one_working_hours': 4.0,
'shift_one_break_duration': 0.5,
'shift_one_min_sign_in': 6.0,
'shift_one_max_sign_in': 7.0,
'shift_one_min_sign_out': 10.0,
'shift_one_max_sign_out': 11.0,
'shift_two_working_hours': 4.0,
'shift_two_break_duration': 0.5,
'shift_two_min_sign_in': 14.0,
'shift_two_max_sign_in': 15.0,
'shift_two_min_sign_out': 18.0,
'shift_two_max_sign_out': 19.0,
'is_full_day': False,
})
def test_full_day_normal_timing(self):
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar_full.id,
})
result = transaction.get_day_timing(self.calendar_full, 'monday', '2025-12-22')
time_list, planed_hours = result
self.assertEqual(planed_hours, {'one': 7.0, 'two': 0})
self.assertEqual(time_list, [8.0, 9.0, 16.0, 17.0])
def test_full_day_special_timing(self):
special_day = self.env['attendance.special.days'].sudo().create({
'special_days_attendance': self.calendar_full.id,
'name': 'monday',
'working_hours': 6.0,
'start_sign_in': 7.0,
'end_sign_in': 8.0,
'start_sign_out': 13.0,
'end_sign_out': 14.0,
'date_from': fields.Date.to_date('2025-12-22'),
})
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar_full.id,
})
result = transaction.get_day_timing(self.calendar_full, 'monday', '2025-12-22')
_, planed_hours = result
self.assertEqual(planed_hours, {'one': 5.0, 'two': 0})
def test_shift_special_one_timing(self):
special_day_shift1 = self.env['attendance.special.days'].sudo().create({
'special_days_attendance': self.calendar_shift.id,
'name': 'monday',
'shift': 'one',
'working_hours': 5.0,
'start_sign_in': 5.0,
'end_sign_in': 6.0,
'start_sign_out': 10.0,
'end_sign_out': 11.0,
'date_from': fields.Date.to_date('2025-12-22'),
})
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar_shift.id,
})
result = transaction.get_day_timing(self.calendar_shift, 'monday', '2025-12-22')
_, planed_hours = result
self.assertEqual(planed_hours, {'one': 4.5, 'two': 3.5})
def test_special_day_date_range(self):
special_day = self.env['attendance.special.days'].sudo().create({
'special_days_attendance': self.calendar_full.id,
'name': 'tuesday',
'working_hours': 10.0,
'date_from': fields.Date.to_date('2025-12-23'),
'date_to': fields.Date.to_date('2025-12-25'),
})
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar_full.id,
})
result_inside = transaction.get_day_timing(self.calendar_full, 'tuesday', '2025-12-23')
_, planned_inside = result_inside
self.assertEqual(planned_inside['one'], 9.0)
def test_special_day_no_dates(self):
special_day = self.env['attendance.special.days'].sudo().create({
'special_days_attendance': self.calendar_full.id,
'name': 'wednesday',
'working_hours': 12.0,
})
transaction = self.env['hr.attendance.transaction'].sudo().create({
'employee_id': self.employee.id,
'calendar_id': self.calendar_full.id,
})
result = transaction.get_day_timing(self.calendar_full, 'wednesday', '2025-12-24')
_, planned_hours = result
self.assertEqual(planned_hours['one'], 11.0)

View File

@ -0,0 +1 @@
from . import test_employee_service_duration

View File

@ -0,0 +1,79 @@
from odoo.tests.common import TransactionCase
from datetime import date
from dateutil.relativedelta import relativedelta
from odoo.exceptions import ValidationError, UserError
class TestEmployeeServiceDuration(TransactionCase):
def setUp(self):
super(TestEmployeeServiceDuration, self).setUp()
self.employee = self.env['hr.employee'].create({
'name': 'Test Employee',
})
def test_service_duration_current(self):
self.employee.first_hiring_date = date(2023, 1, 1)
self.employee._compute_service_duration()
today = date.today()
expected = relativedelta(today, date(2023, 1, 1))
self.assertEqual(self.employee.service_year, expected.years)
self.assertEqual(self.employee.service_month, expected.months)
self.assertEqual(self.employee.service_day, expected.days)
def test_service_duration_leaving_date(self):
hire_date = date(2023, 1, 1)
leave_date = date(2024, 6, 15)
self.employee.first_hiring_date = hire_date
self.employee.leaving_date = leave_date
self.employee._compute_service_duration()
expected = relativedelta(leave_date, hire_date)
self.assertEqual(self.employee.service_year, expected.years)
self.assertEqual(self.employee.service_month, expected.months)
self.assertEqual(self.employee.service_day, expected.days)
def test_no_hiring_date(self):
self.employee.first_hiring_date = False
self.employee.leaving_date = False
self.employee._compute_service_duration()
self.assertEqual(self.employee.service_year, 0)
self.assertEqual(self.employee.service_month, 0)
self.assertEqual(self.employee.service_day, 0)
class TestEmployeeUniqueConstraints(TransactionCase):
def setUp(self):
super(TestEmployeeUniqueConstraints, self).setUp()
self.employee = self.env['hr.employee'].create({
'name': 'Test Employee',
'emp_no': 'EMP001',
})
def test_duplicate_emp_no(self):
with self.assertRaises(ValidationError):
self.env['hr.employee'].create({
'name': 'Duplicate Employee',
'emp_no': 'EMP001',
})
def test_future_birthday(self):
with self.assertRaises(UserError):
self.env['hr.employee'].create({
'name': 'Future Birthday',
'birthday': date(2026, 1, 1),
})
def test_valid_birthday(self):
employee = self.env['hr.employee'].create({
'name': 'Valid Birthday',
'birthday': date(1990, 1, 1),
})
self.assertEqual(employee.birthday, date(1990, 1, 1))

View File

@ -0,0 +1 @@
from . import test_holidays_overlap_constraint

View File

@ -0,0 +1,258 @@
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError
from datetime import datetime, timedelta
class TestHolidaysOverlapConstraint(TransactionCase):
def setUp(self):
super(TestHolidaysOverlapConstraint, self).setUp()
self.employee = self.env['hr.employee'].sudo().create({'name': 'Test Employee'})
self.leave_type = self.env['hr.holidays.status'].sudo().create({
'name': 'Annual Leave',
})
def test_overlapping_leaves_forbidden(self):
self.env['hr.holidays'].sudo().create({
'name': 'First Leave',
'employee_id': self.employee.id,
'holiday_status_id': self.leave_type.id,
'date_from': datetime(2025, 1, 10, 9, 0),
'date_to': datetime(2025, 1, 12, 18, 0),
'type': 'remove',
'state': 'confirm', # ليست cancel/refuse
})
with self.assertRaises(ValidationError, msg="Overlapping leaves should be forbidden"):
self.env['hr.holidays'].sudo().create({
'name': 'Overlapping Leave',
'employee_id': self.employee.id,
'holiday_status_id': self.leave_type.id,
'date_from': datetime(2025, 1, 11, 9, 0),
'date_to': datetime(2025, 1, 13, 18, 0),
'type': 'remove',
'state': 'confirm',
})
def test_non_overlapping_allowed(self):
self.env['hr.holidays'].sudo().create({
'name': 'First Leave',
'employee_id': self.employee.id,
'holiday_status_id': self.leave_type.id,
'date_from': datetime(2025, 1, 10, 9, 0),
'date_to': datetime(2025, 1, 12, 18, 0),
'type': 'remove',
'state': 'confirm',
})
leave2 = self.env['hr.holidays'].sudo().create({
'name': 'Second Leave',
'employee_id': self.employee.id,
'holiday_status_id': self.leave_type.id,
'date_from': datetime(2025, 1, 13, 9, 0),
'date_to': datetime(2025, 1, 15, 18, 0),
'type': 'remove',
'state': 'confirm',
})
self.assertTrue(leave2)
def test_cancelled_leave_ignored(self):
self.env['hr.holidays'].sudo().create({
'name': 'Cancelled Leave',
'employee_id': self.employee.id,
'holiday_status_id': self.leave_type.id,
'date_from': datetime(2025, 1, 10, 9, 0),
'date_to': datetime(2025, 1, 12, 18, 0),
'type': 'remove',
'state': 'cancel',
})
leave2 = self.env['hr.holidays'].sudo().create({
'name': 'New Leave',
'employee_id': self.employee.id,
'holiday_status_id': self.leave_type.id,
'date_from': datetime(2025, 1, 11, 9, 0),
'date_to': datetime(2025, 1, 13, 18, 0),
'type': 'remove',
'state': 'confirm',
})
self.assertTrue(leave2)
def test_different_type_allowed(self):
self.env['hr.holidays'].sudo().create({
'name': 'Leave Request',
'employee_id': self.employee.id,
'holiday_status_id': self.leave_type.id,
'date_from': datetime(2025, 1, 10, 9, 0),
'date_to': datetime(2025, 1, 12, 18, 0),
'type': 'remove',
'state': 'confirm',
})
allocation = self.env['hr.holidays'].sudo().create({
'name': 'Allocation',
'employee_id': self.employee.id,
'holiday_status_id': self.leave_type.id,
'date_from': datetime(2025, 1, 11, 9, 0),
'date_to': datetime(2025, 1, 13, 18, 0),
'type': 'add',
'state': 'confirm',
})
self.assertTrue(allocation)
class TestHolidaysNumberOfDays(TransactionCase):
def setUp(self):
super(TestHolidaysNumberOfDays, self).setUp()
self.leave_type = self.env['hr.holidays.status'].sudo().create({
'name': 'Annual Leave',
})
self.calendar = self.env['resource.calendar'].sudo().create({
'name': 'Standard 40h/week',
'tz': 'UTC',
'attendance_ids': [
(0, 0, {'name': 'Monday', 'dayofweek': '0', 'hour_from': 9.0, 'hour_to': 18.0}),
(0, 0, {'name': 'Tuesday', 'dayofweek': '1', 'hour_from': 9.0, 'hour_to': 18.0}),
(0, 0, {'name': 'Wednesday', 'dayofweek': '2', 'hour_from': 9.0, 'hour_to': 18.0}),
(0, 0, {'name': 'Thursday', 'dayofweek': '3', 'hour_from': 9.0, 'hour_to': 18.0}),
(0, 0, {'name': 'Friday', 'dayofweek': '4', 'hour_from': 9.0, 'hour_to': 18.0}),
]
})
self.employee = self.env['hr.employee'].sudo().create({
'name': 'Test Employee',
'resource_calendar_id': self.calendar.id,
})
def _calculate_work_days(self, date_from, date_to, calendar):
total_hours = 0.0
current_date = date_from.date()
end_date = date_to.date()
while current_date <= end_date:
dayofweek = str(current_date.weekday())
attendances = calendar.attendance_ids.filtered(
lambda a: a.dayofweek == dayofweek
)
if attendances:
hour_from_int = int(attendances[0].hour_from)
minute_from_int = int((attendances[0].hour_from % 1) * 60)
hour_to_int = int(attendances[0].hour_to)
minute_to_int = int((attendances[0].hour_to % 1) * 60)
day_start = datetime.combine(current_date, datetime.min.time()).replace(
hour=hour_from_int, minute=minute_from_int)
day_end = datetime.combine(current_date, datetime.min.time()).replace(
hour=hour_to_int, minute=minute_to_int)
work_start = max(date_from, day_start)
work_end = min(date_to, day_end)
if work_start < work_end:
hours = (work_end - work_start).total_seconds() / 3600.0
total_hours += min(hours, 8.0)
current_date += timedelta(days=1)
return total_hours / 8.0
def test_simple_datetime_diff(self):
holiday = self.env['hr.holidays'].sudo().new()
days = holiday._get_number_of_days(
datetime(2025, 1, 1, 9, 0),
datetime(2025, 1, 5, 18, 0),
False
)
self.assertEqual(days, 5.0)
def test_string_input(self):
holiday = self.env['hr.holidays'].sudo().new()
days = holiday._get_number_of_days(
'2025-01-01T09:00:00',
'2025-01-05T18:00:00',
False
)
self.assertEqual(days, 5.0)
def test_datetime_input(self):
holiday = self.env['hr.holidays'].sudo().new()
days = holiday._get_number_of_days(
datetime(2025, 1, 1, 9, 0),
datetime(2025, 1, 3, 18, 0),
False
)
self.assertEqual(days, 3.0)
def test_string_datetime_mixed(self):
holiday = self.env['hr.holidays'].sudo().new()
days = holiday._get_number_of_days(
'2025-01-01T09:00:00',
datetime(2025, 1, 2, 18, 0),
False
)
self.assertEqual(days, 2.0)
def test_isoformat_zulu_time(self):
holiday = self.env['hr.holidays'].sudo().new()
days = holiday._get_number_of_days(
'2025-01-01T09:00:00Z',
'2025-01-03T18:00:00Z',
False
)
self.assertEqual(days, 3.0)
def test_partial_day(self):
holiday = self.env['hr.holidays'].sudo().new()
days = holiday._get_number_of_days(
datetime(2025, 1, 1, 9, 0),
datetime(2025, 1, 1, 17, 0),
False
)
self.assertEqual(days, 1.0)
def test_precise_seconds(self):
holiday = self.env['hr.holidays'].sudo().new()
days = holiday._get_number_of_days(
datetime(2025, 1, 1, 9, 0, 0),
datetime(2025, 1, 1, 17, 30, 0),
False
)
self.assertEqual(days, 1.0)
def test_calendar_work_days_weekdays(self):
days = self._calculate_work_days(
datetime(2025, 1, 1, 9, 0), # Wednesday
datetime(2025, 1, 3, 18, 0), # Friday
self.calendar
)
self.assertEqual(days, 3.0)
def test_calendar_work_days_weekend(self):
days = self._calculate_work_days(
datetime(2025, 1, 4, 9, 0), # Saturday
datetime(2025, 1, 5, 18, 0), # Sunday
self.calendar
)
self.assertEqual(days, 0.0)
def test_calendar_partial_work_day(self):
days = self._calculate_work_days(
datetime(2025, 1, 1, 9, 0), # 9:00
datetime(2025, 1, 1, 12, 0), # 12:00
self.calendar
)
self.assertEqual(round(days, 2), 0.38)
def test_calendar_week_with_weekend(self):
days = self._calculate_work_days(
datetime(2025, 1, 6, 9, 0), # Monday
datetime(2025, 1, 12, 18, 0), # Sunday
self.calendar
)
self.assertEqual(days, 5.0)