355 lines
13 KiB
Python
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
|
|
)
|