odex30_standard/attendances/tests/test_attendance_report_calc...

355 lines
13 KiB
Python

from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError
from datetime import date
from unittest.mock import MagicMock
class TestHrAttendanceReport(TransactionCase):
def setUp(self):
super(TestHrAttendanceReport, 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': 'Standard 8h',
'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.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': '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,
})
def test_01_generate_report_deduction_logic(self):
common_vals = {
'employee_id': self.employee.id,
'calendar_id': self.calendar.id,
'attending_type': 'in_cal',
'sequence': 1,
'approve_lateness': True,
'approve_exit_out': True,
}
trans1 = self.env['hr.attendance.transaction'].create({
**common_vals, 'date': date(2023, 10, 1), 'plan_hours': 8.0, 'is_absent': True,
})
trans2 = self.env['hr.attendance.transaction'].create({
**common_vals, 'date': date(2023, 10, 2), 'plan_hours': 8.0, 'official_hours': 6.0, 'lateness': 2.0,
'is_absent': False,
})
type(trans1).public_holiday = property(lambda self: False)
type(trans1).normal_leave = property(lambda self: False)
# ------------------------------------------
# 5. توليد التقرير
report = self.env['hr.attendance.report'].create({
'name': 'Report',
'date_from': date(2023, 10, 1),
'date_to': date(2023, 10, 5),
'selected_employee_ids': [(4, self.employee.id)]
})
report.generate_report()
self.assertTrue(report.line_ids, "No record")
line = report.line_ids[0]
self.assertAlmostEqual(line.total_hours, 10.0, msg="fild hours")
self.assertAlmostEqual(line.total_deduction, 1000.0, msg="mins")
self.assertEqual(report.state, 'generated')
from odoo.tests.common import TransactionCase
from datetime import date
from unittest.mock import MagicMock
class TestFlexibleAttendanceReport(TransactionCase):
def setUp(self):
super(TestFlexibleAttendanceReport, self).setUp()
self.manager = self.env['hr.employee'].create({'name': 'Manager'})
self.dept = self.env['hr.department'].create({'name': 'IT', 'manager_id': self.manager.id})
self.calendar_flex = self.env['resource.calendar'].create({
'name': 'Flexible 40h',
'is_flexible': True,
'is_full_day': True,
'number_of_flexi_days': 5,
'working_hours': 8.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,
'state': 'confirm',
})
self.employee = self.env['hr.employee'].create({
'name': 'Flex Employee',
'department_id': self.dept.id,
'resource_calendar_id': self.calendar_flex.id,
'finger_print': True,
'state': 'open'
})
def test_flexible_calculation_logic(self):
def create_mock_transaction(plan, office, is_absent=False, sign_in=True, sign_out=True):
mock = MagicMock()
mock.plan_hours = plan
mock.office_hours = office
mock.is_absent = is_absent
mock.public_holiday = False
mock.normal_leave = False
mock.personal_permission_id = False
mock.official_id = False
mock.approve_personal_permission = False
mock.total_permission_hours = 0.0
mock.total_leave_hours = 0.0
mock.total_mission_hours = 0.0
mock.sign_in = sign_in
mock.sign_out = sign_out
mock.early_exit = 0.0
mock.lateness = 0.0
mock.break_duration = 0.0
mock.approve_exit_out = False
mock.approve_lateness = False
return mock
all_trans_list = [
create_mock_transaction(8.0, 6.0),
create_mock_transaction(8.0, 0.0, is_absent=True),
create_mock_transaction(8.0, 4.0, sign_out=False)
]
def create_mock_recordset(items):
m = MagicMock()
m.__iter__.return_value = iter(items)
m.filtered.side_effect = lambda func: create_mock_recordset([i for i in items if func(i)])
m.mapped.side_effect = lambda name: [getattr(i, name) for i in items]
m.__len__.return_value = len(items)
return m
transactions = create_mock_recordset(all_trans_list)
report = self.env['hr.attendance.report'].new()
result = report.calcualte_flexible_transaction(transactions)
self.assertAlmostEqual(result['missed_hours'], 14.0, msg="Missed hours calculation failed")
self.assertEqual(result['actual_absent_days'], 1, msg="Absent days count failed")
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
)