odex30_standard/exp_hr_payroll/tests/test_payroll_rules.py

224 lines
8.2 KiB
Python

# -*- coding: utf-8 -*-
from odoo.tests.common import TransactionCase
from odoo.exceptions import UserError, ValidationError
from odoo import fields
from datetime import date, datetime, timedelta
class TestPayrollRules(TransactionCase):
def setUp(self):
super(TestPayrollRules, self).setUp()
self.env.user.tz = 'UTC'
self.company = self.env.ref('base.main_company')
self.category_basic = self.env['hr.salary.rule.category'].create({
'name': 'Basic',
'code': 'BASIC',
})
self.structure = self.env['hr.payroll.structure'].create({
'name': 'Test Structure',
'code': 'TEST_STRUCT',
'company_id': self.company.id,
})
attendances = []
for day in range(5): # 0=Monday to 4=Friday
attendances.append((0, 0, {
'name': 'Morning',
'dayofweek': str(day),
'hour_from': 8,
'hour_to': 12,
'day_period': 'morning',
}))
attendances.append((0, 0, {
'name': 'Afternoon',
'dayofweek': str(day),
'hour_from': 13,
'hour_to': 17,
'day_period': 'afternoon',
}))
self.calendar = self.env['resource.calendar'].create({
'name': 'Standard 40 Hours UTC',
'tz': 'UTC',
'hours_per_day': 8.0,
'attendance_ids': attendances,
'company_id': self.company.id,
})
self.employee = self.env['hr.employee'].create({
'name': 'Test Employee Payroll',
'company_id': self.company.id,
'resource_calendar_id': self.calendar.id,
})
if self.employee.resource_id:
self.employee.resource_id.write({
'calendar_id': self.calendar.id,
'tz': 'UTC',
})
self.contract = self.env['hr.contract'].create({
'name': 'Contract for Test',
'employee_id': self.employee.id,
'struct_id': self.structure.id,
'wage': 5000.0,
'state': 'open',
'date_start': date.today() - timedelta(days=100),
'resource_calendar_id': self.calendar.id,
'schedule_pay': 'monthly',
'company_id': self.company.id,
})
self.payslip = self.env['hr.payslip'].create({
'employee_id': self.employee.id,
'contract_id': self.contract.id,
'struct_id': self.structure.id,
'date_from': date.today().replace(day=1),
'date_to': (date.today().replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1),
'company_id': self.company.id,
})
def test_satisfy_condition_python(self):
rule = self.env['hr.salary.rule'].create({
'name': 'Python Condition Rule',
'sequence': 10,
'code': 'PY_COND',
'category_id': self.category_basic.id,
'condition_select': 'python',
'condition_python': 'result = contract.wage > 3000',
'amount_select': 'fix',
'amount_fix': 100.0,
})
localdict = {'contract': self.contract, 'employee': self.employee}
self.assertTrue(rule._satisfy_condition(localdict))
rule.condition_python = 'result = contract.wage > 6000'
self.assertFalse(rule._satisfy_condition(localdict))
def test_satisfy_condition_range(self):
rule = self.env['hr.salary.rule'].create({
'name': 'Range Condition Rule',
'sequence': 10,
'code': 'RANGE_COND',
'category_id': self.category_basic.id,
'condition_select': 'range',
'condition_range': 'contract.wage',
'condition_range_min': 1000,
'condition_range_max': 6000,
'amount_select': 'fix',
'amount_fix': 100.0,
})
localdict = {'contract': self.contract}
self.assertTrue(rule._satisfy_condition(localdict))
self.contract.wage = 8000
self.assertFalse(rule._satisfy_condition(localdict))
def test_compute_rule_percentage(self):
rule = self.env['hr.salary.rule'].create({
'name': 'Percentage Rule',
'sequence': 10,
'code': 'PERCENT',
'category_id': self.category_basic.id,
'amount_select': 'percentage',
'amount_percentage_base': 'contract.wage',
'amount_percentage': 10.0,
'quantity': '1.0',
})
localdict = {'contract': self.contract}
amount, qty, rate = rule._compute_rule(localdict)
self.assertEqual(amount, 5000.0)
self.assertEqual(amount * qty * rate / 100.0, 500.0)
def test_compute_rule_python_code(self):
rule = self.env['hr.salary.rule'].create({
'name': 'Python Code Rule',
'sequence': 10,
'code': 'PY_CODE',
'category_id': self.category_basic.id,
'amount_select': 'code',
'amount_python_compute': 'result = contract.wage + 500',
})
localdict = {'contract': self.contract}
amount, qty, rate = rule._compute_rule(localdict)
self.assertEqual(amount, 5500.0)
def test_get_contract(self):
old_contract = self.env['hr.contract'].create({
'name': 'Old Contract',
'employee_id': self.employee.id,
'wage': 4000,
'state': 'close',
'date_start': date.today() - timedelta(days=400),
'date_end': date.today() - timedelta(days=200),
'resource_calendar_id': self.calendar.id,
'struct_id': self.structure.id,
})
date_from = date.today().replace(day=1)
date_to = (date.today().replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
contract_ids = self.env['hr.payslip'].get_contract(self.employee, date_from, date_to)
self.assertIn(self.contract.id, contract_ids)
self.assertNotIn(old_contract.id, contract_ids)
def test_get_worked_day_lines(self):
today = date.today()
days_ahead = 0 - today.weekday()
if days_ahead <= 0:
days_ahead += 7
next_monday = today + timedelta(days=days_ahead)
date_from = next_monday
date_to = next_monday + timedelta(days=4)
try:
worked_days = self.env['hr.payslip'].get_worked_day_lines(self.contract, date_from, date_to)
work_entry = next((item for item in worked_days if item['code'] == 'WORK100'), None)
self.assertIsNotNone(work_entry, "WORK100 entry not found in result")
except AttributeError as e:
print(f"Skipping test_get_worked_day_lines due to missing dependency: {e}")
def test_payslip_line_compute_total(self):
line = self.env['hr.payslip.line'].create({
'slip_id': self.payslip.id,
'name': 'Test Line',
'code': 'TEST',
'contract_id': self.contract.id,
'salary_rule_id': self.env['hr.salary.rule'].search([], limit=1).id,
'employee_id': self.employee.id,
'quantity': 2.0,
'amount': 500.0,
'rate': 50.0,
'category_id': self.category_basic.id,
})
self.assertEqual(line.total, 500.0)
def test_get_inputs(self):
rule_with_input = self.env['hr.salary.rule'].create({
'name': 'Rule with Input',
'code': 'INPUT_RULE',
'category_id': self.category_basic.id,
'amount_select': 'fix',
'amount_fix': 0.0,
'sequence': 50,
})
self.env['hr.rule.input'].create({
'name': 'Commission Input',
'code': 'COMMISSION',
'input_id': rule_with_input.id,
})
self.structure.write({'rule_ids': [(4, rule_with_input.id)]})
date_from = date.today()
date_to = date.today()
inputs = self.env['hr.payslip'].get_inputs(self.contract, date_from, date_to)
found_input = next((i for i in inputs if i['code'] == 'COMMISSION'), None)
self.assertIsNotNone(found_input)
self.assertEqual(found_input['contract_id'], self.contract.id)