1023 lines
40 KiB
Python
1023 lines
40 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
from datetime import date
|
|
|
|
from odoo import fields
|
|
from odoo.tests import tagged
|
|
from .common import TestPayrollCommon
|
|
|
|
|
|
@tagged("post_install_l10n", "post_install", "-at_install", "l10n_au_hr_payroll")
|
|
class TestPayrollUnusedLeaves(TestPayrollCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.default_payroll_structure = cls.env.ref("l10n_au_hr_payroll.hr_payroll_structure_au_regular")
|
|
cls.tax_treatment_category = 'R'
|
|
cls.long_service = cls.env['hr.leave.type'].create({
|
|
'name': 'Long Service Leave',
|
|
'company_id': cls.australian_company.id,
|
|
'l10n_au_leave_type': 'long_service',
|
|
'leave_validation_type': 'no_validation',
|
|
'work_entry_type_id': cls.env.ref('hr_work_entry.l10n_au_work_entry_type_long_service_leave').id,
|
|
})
|
|
cls.annual = cls.env['hr.leave.type'].create({
|
|
'name': 'Annual Leave',
|
|
'company_id': cls.australian_company.id,
|
|
'l10n_au_leave_type': 'annual',
|
|
'leave_validation_type': 'no_validation',
|
|
'work_entry_type_id': cls.env.ref('hr_work_entry.l10n_au_work_entry_type_paid_time_off').id,
|
|
})
|
|
|
|
# Unused leaves tests
|
|
def get_unused_leaves_employee(self, birthday, date_start, date_end, leave_loading=('once', 0), tfn_provided=True, resident=True):
|
|
employee, contract = self._create_employee(contract_info={
|
|
'employee': 'Test Employee',
|
|
'employment_basis_code': 'F',
|
|
'leave_loading': leave_loading[0],
|
|
'leave_loading_rate': leave_loading[1],
|
|
'salary_sacrifice_superannuation': 0,
|
|
'salary_sacrifice_other': 0,
|
|
'schedule_pay': 'monthly',
|
|
'wage': 7000,
|
|
'casual_loading': 0,
|
|
# 'tax_treatment_category': 'V',
|
|
'birthday': fields.Date.to_date(birthday),
|
|
'contract_date_start': fields.Date.to_date(date_start),
|
|
'contract_date_end': fields.Date.to_date(date_end),
|
|
'tfn': 999999661,
|
|
'tfn_declaration': 'provided' if tfn_provided else '000000000',
|
|
'non_resident': not resident,
|
|
'l10n_au_tax_free_threshold': resident
|
|
})
|
|
employee.is_non_resident = not resident
|
|
return employee, contract
|
|
|
|
def create_leaves(self, employee, contract, leaves):
|
|
""" Creates Allocations and Leaves
|
|
|
|
Args:
|
|
employee (hr.employee)
|
|
leaves (dict): {
|
|
"annual": {
|
|
"pre_1993": unused_leaves,
|
|
"post_1993": unused_leaves,
|
|
},
|
|
"long_service": {
|
|
"pre_1978": unused_leaves,
|
|
"pre_1993": unused_leaves,
|
|
"post_1993": unused_leaves,
|
|
},
|
|
}
|
|
"""
|
|
dates = {
|
|
"pre_1978": {"start": date(1976, 1, 1), "end": date(1978, 8, 15)},
|
|
"pre_1993": {"start": date(1978, 8, 17), "end": date(1993, 8, 16)},
|
|
"post_1993": {"start": date(1993, 8, 19), "end": max(contract.date_end, date.today())},
|
|
}
|
|
for leave_type, amount in leaves.items():
|
|
leave_type_id = self.annual if leave_type == 'annual' else self.long_service
|
|
for period, number_of_days in amount.items():
|
|
start_date = dates[period]['start']
|
|
end_date = max(dates[period]['end'], contract.date_end or dates[period]['end'])
|
|
|
|
# Allocate Holidays
|
|
allocation = self.env['hr.leave.allocation'].create([{
|
|
'name': f'{leave_type_id.name} Allocation',
|
|
'holiday_status_id': leave_type_id.id,
|
|
'number_of_days': number_of_days,
|
|
'employee_id': employee.id,
|
|
'state': 'confirm',
|
|
'date_from': start_date,
|
|
'date_to': end_date,
|
|
}])
|
|
allocation.action_approve()
|
|
|
|
self.assertAlmostEqual(allocation.number_of_days, number_of_days)
|
|
|
|
# AL only + non-genuine + TFN
|
|
def test_01_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12')
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"annual": {
|
|
"post_1993": 14.84,
|
|
}
|
|
},
|
|
)
|
|
|
|
self.assertFalse(employee.is_non_resident)
|
|
self.assertEqual(employee.l10n_au_tfn_declaration, 'provided')
|
|
|
|
expected_gross = 4794.45
|
|
expected_withhold = -1668
|
|
normal_withholding = -247.0
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
def test_02_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1976-01-01', '1992-08-17', '2024-03-12')
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
leaves={
|
|
"annual": {
|
|
"pre_1993": 20,
|
|
"post_1993": 10.42,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 9827.97
|
|
expected_withhold = -3207.69
|
|
normal_withholding = -247.0
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# AL only + genuine + TFN
|
|
def test_03_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1976-01-01', '1992-08-17', '2024-03-12')
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
leaves={
|
|
"annual": {
|
|
"pre_1993": 20,
|
|
"post_1993": 10.42,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 9827.97
|
|
expected_withhold = -3144.95
|
|
normal_withholding = -247.0
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="genuine"
|
|
)
|
|
|
|
# AL only + non-genuine + TFN + loading
|
|
def test_04_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12', ('regular', 17.5))
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"annual": {
|
|
"post_1993": 14.84,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 5633.48
|
|
expected_withhold = -1920
|
|
normal_withholding = -247.0
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# AL only + non-genuine + TFN + loading
|
|
def test_05_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1976-01-01', '1992-01-01', '2024-03-12', ('regular', 17.5))
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
leaves={
|
|
"annual": {
|
|
"pre_1993": 20,
|
|
"post_1993": 10.42,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 11547.87
|
|
expected_withhold = -3785.53
|
|
normal_withholding = -247.0
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# AL only + genuine + TFN + loading
|
|
def test_06_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1976-01-01', '1992-08-01', '2024-03-12', ('regular', 17.5))
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
leaves={
|
|
"annual": {
|
|
"pre_1993": 20,
|
|
"post_1993": 10.42,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 11547.87
|
|
expected_withhold = -3695.32
|
|
normal_withholding = -247.0
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="genuine"
|
|
)
|
|
|
|
# < $300 + > 1993 + 32% is smaller
|
|
def test_07_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12')
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"annual": {
|
|
"post_1993": 0.5,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 161.54
|
|
expected_withhold = -48
|
|
normal_withholding = -247.0
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# < $300 + > 1993 + standard is smaller
|
|
def test_08_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12')
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"annual": {
|
|
"post_1993": 0.25,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 80.77
|
|
expected_withhold = 0
|
|
normal_withholding = -247.0
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# No TFN + Resident
|
|
def test_09_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12', tfn_provided=False)
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"annual": {
|
|
"post_1993": 14.84,
|
|
}
|
|
},
|
|
)
|
|
|
|
employee.l10n_au_tax_free_threshold = False
|
|
self.assertFalse(employee.is_non_resident)
|
|
self.assertEqual(employee.l10n_au_tfn_declaration, '000000000')
|
|
|
|
expected_gross = 4794.45
|
|
expected_withhold = -2253.39
|
|
normal_withholding = -1213.85
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# No TFN + Foreign Resident
|
|
def test_10_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12', tfn_provided=False, resident=False)
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"annual": {
|
|
"post_1993": 14.84,
|
|
}
|
|
},
|
|
)
|
|
|
|
self.assertTrue(employee.is_non_resident)
|
|
self.assertEqual(employee.l10n_au_tfn_declaration, '000000000')
|
|
|
|
expected_gross = 4794.45
|
|
expected_withhold = -2157.5
|
|
normal_withholding = -1163
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# Withholding Var. + impact leaves
|
|
def test_11_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1976-01-01', '1992-08-1992', '2024-03-12')
|
|
employee.l10n_au_withholding_variation = "leaves"
|
|
employee.l10n_au_withholding_variation_amount = 30
|
|
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
leaves={
|
|
"annual": {
|
|
"post_1993": 14.84,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 4794.45
|
|
expected_withhold = -1438.33
|
|
normal_withholding = -775.38
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# Withholding Var. + does not impact leaves
|
|
def test_12_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1976-01-01', '1992-08-1992', '2024-03-12')
|
|
employee.l10n_au_withholding_variation = "salaries"
|
|
employee.l10n_au_withholding_variation_amount = 30
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
leaves={
|
|
"annual": {
|
|
"post_1993": 14.84,
|
|
}
|
|
},
|
|
)
|
|
|
|
expected_gross = 4794.45
|
|
expected_withhold = -1668
|
|
normal_withholding = -775.38
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 8.0, 60.8, 2584.61),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 2584.61),
|
|
("OTE", 2584.61),
|
|
("GROSS", 2584.61),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 2584.61 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 284),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# LSL only + non-genuine + > 1993
|
|
def test_13_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1980-01-01', '2002-01-01', '2024-01-01')
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"long_service": {
|
|
"post_1993": 112,
|
|
}
|
|
},
|
|
)
|
|
|
|
self.assertFalse(employee.is_non_resident)
|
|
self.assertEqual(employee.l10n_au_tfn_declaration, 'provided')
|
|
|
|
expected_gross = 36184.51
|
|
expected_withhold = -12480
|
|
normal_withholding = 0
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 1.0, 7.6, 323.08),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 323.08),
|
|
("OTE", 323.08),
|
|
("GROSS", 323.08),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 323.08 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 35.54),
|
|
],
|
|
payslip_date_from=contract.date_end.replace(day=1),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
# LSL ATO > 93
|
|
def test_23_termination_unused_leaves(self):
|
|
# TODO: Check rule parameter
|
|
employee, contract = self.get_unused_leaves_employee('1958-01-01', '2005-01-01', '2015-01-14')
|
|
contract.schedule_pay = "weekly"
|
|
contract.wage = 1000
|
|
self.env.ref("l10n_au_hr_payroll.rule_parameter_withholding_schedule_1_2023").date_from = fields.Date.from_string("2014-01-01")
|
|
self.env.ref("l10n_au_hr_payroll.rule_parameter_study_loan_coefficients_2023").date_from = fields.Date.from_string("2014-01-01")
|
|
self.env.ref("l10n_au_hr_payroll.rule_parameter_super_2023").date_from = fields.Date.from_string("2014-01-01")
|
|
|
|
self.env['hr.rule.parameter.value'].create({
|
|
"rule_parameter_id": self.env.ref("l10n_au_hr_payroll.rule_parameter_leave_withholding").id,
|
|
"date_from": fields.Date.from_string("2014-01-01"),
|
|
"parameter_value": 32,
|
|
})
|
|
self.env['hr.rule.parameter.value'].create({
|
|
"rule_parameter_id": self.env.ref("l10n_au_hr_payroll.rule_parameter_leaves_low_threshold").id,
|
|
"date_from": fields.Date.from_string("2014-01-01"),
|
|
"parameter_value": 300,
|
|
})
|
|
self.env['hr.rule.parameter.value'].create({
|
|
"rule_parameter_id": self.env.ref("l10n_au_hr_payroll.rule_parameter_leaves_low_withhold").id,
|
|
"date_from": fields.Date.from_string("2014-01-01"),
|
|
"parameter_value": 32,
|
|
})
|
|
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"long_service": {
|
|
"pre_1993": 40,
|
|
}
|
|
},
|
|
)
|
|
|
|
self.assertFalse(employee.is_non_resident)
|
|
self.assertEqual(employee.l10n_au_tfn_declaration, 'provided')
|
|
|
|
expected_gross = 8000
|
|
expected_withhold = -2560
|
|
normal_withholding = -58
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 3.0, (7.6 * 3), 600.1),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 600.1),
|
|
("OTE", 600.1),
|
|
("GROSS", 600.1),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", 0),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold),
|
|
("NET", 600.1 + expected_gross + (normal_withholding + expected_withhold)),
|
|
("SUPER", 66.01),
|
|
],
|
|
payslip_date_from=fields.Date.from_string("2015-01-12"),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="genuine"
|
|
)
|
|
|
|
# https://www.ato.gov.au/forms-and-instructions/employment-termination-payments-withholding-from-unused-leave-payments/unused-long-service-leave/examples
|
|
# Matt's Retirement
|
|
def test_24_termination_unused_leaves(self):
|
|
# TODO: Check rule parameter
|
|
employee, contract = self.get_unused_leaves_employee('1958-01-01', '1977-01-01', '2014-12-31')
|
|
contract.schedule_pay = "weekly"
|
|
contract.wage = 1200
|
|
# Tax tables 2014
|
|
# https://softwaredevelopers.ato.gov.au/sites/default/files/resource-attachments/NAT_1004.pdf
|
|
# Payg
|
|
self.env["hr.rule.parameter.value"].create(
|
|
{
|
|
"rule_parameter_id": self.env.ref("l10n_au_hr_payroll.rule_parameter_withholding_schedule_1").id,
|
|
"date_from": date(2014, 7, 1),
|
|
"parameter_value": {
|
|
"tax-free": [
|
|
(355, 0.0, 0.0),
|
|
(395, 0.1900, 67.4635),
|
|
(493, 0.2900, 106.9673),
|
|
(711, 0.2100, 67.4642),
|
|
(1282, 0.3477, 165.4431),
|
|
(1538, 0.3450, 161.9815),
|
|
(3461, 0.3900, 231.2123),
|
|
("inf", 0.4900, 577.3662),
|
|
],
|
|
"medicare": {
|
|
"tax-free": {
|
|
"WEST": 548,
|
|
"MLFT": 38474,
|
|
"WFTD": 52,
|
|
"ADDC": 3533,
|
|
"SOPM": 0.1000,
|
|
"SOPD": 0.0800,
|
|
"WLA": 438.4800,
|
|
"ML": 0.0200,
|
|
},
|
|
"half-exemption": {
|
|
"WEST": 924,
|
|
"MLFT": 38474,
|
|
"WFTD": 52,
|
|
"ADDC": 3533,
|
|
"SOPM": 0.0500,
|
|
"SOPD": 0.0400,
|
|
"WLA": 739.8800,
|
|
"ML": 0.010,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
self.env.ref("l10n_au_hr_payroll.rule_parameter_study_loan_coefficients_2023").date_from = fields.Date.from_string("2014-01-01")
|
|
self.env["hr.rule.parameter.value"].create(
|
|
{
|
|
"rule_parameter_id": self.env.ref("l10n_au_hr_payroll.rule_parameter_super").id,
|
|
"date_from": date(2014, 7, 1),
|
|
"parameter_value": 9.50,
|
|
}
|
|
)
|
|
self.env['hr.rule.parameter.value'].create({
|
|
"rule_parameter_id": self.env.ref("l10n_au_hr_payroll.rule_parameter_leave_withholding").id,
|
|
"date_from": fields.Date.from_string("2014-01-01"),
|
|
"parameter_value": 32,
|
|
})
|
|
self.env['hr.rule.parameter.value'].create({
|
|
"rule_parameter_id": self.env.ref("l10n_au_hr_payroll.rule_parameter_leaves_low_threshold").id,
|
|
"date_from": fields.Date.from_string("2014-01-01"),
|
|
"parameter_value": 300,
|
|
})
|
|
self.env['hr.rule.parameter.value'].create({
|
|
"rule_parameter_id": self.env.ref("l10n_au_hr_payroll.rule_parameter_leaves_low_withhold").id,
|
|
"date_from": fields.Date.from_string("2014-01-01"),
|
|
"parameter_value": 32,
|
|
})
|
|
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
{
|
|
"long_service": {
|
|
"pre_1993": 106,
|
|
"post_1993": 151,
|
|
"pre_1978": 13,
|
|
}
|
|
},
|
|
)
|
|
|
|
self.assertFalse(employee.is_non_resident)
|
|
self.assertEqual(employee.l10n_au_tfn_declaration, 'provided')
|
|
self.assertEqual(employee.l10n_au_tax_free_threshold, True)
|
|
|
|
expected_gross = 80000 # manual amount
|
|
expected_withhold = -26794
|
|
normal_withholding = -252
|
|
|
|
payslip = self.env["hr.payslip"].create({
|
|
"name": "payslip",
|
|
"employee_id": employee.id,
|
|
"version_id": contract.id,
|
|
"struct_id": self.default_payroll_structure.id,
|
|
"date_from": fields.Date.from_string("2014-12-25"),
|
|
"date_to": contract.date_end,
|
|
"l10n_au_termination_type": "normal",
|
|
})
|
|
payslip.input_line_ids.filtered(lambda x: x.code == 'LSL').amount = expected_gross
|
|
payslip.compute_sheet()
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
payslip=payslip,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 5, (7.6 * 5), 1200),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 1200),
|
|
("OTE", 1200),
|
|
("GROSS", 1200),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", -24),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold - 24),
|
|
("NET", 1200 + expected_gross + (normal_withholding + expected_withhold - 24)),
|
|
("SUPER", 114),
|
|
],
|
|
)
|
|
payslip.action_payslip_draft()
|
|
# Recompute the gross
|
|
payslip.action_refresh_from_work_entries()
|
|
|
|
expected_gross = 64800.0 # Recomputed Amount
|
|
expected_withhold = -21557.0
|
|
normal_withholding = -252
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
payslip=payslip,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 5, (7.6 * 5), 1200),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 1200),
|
|
("OTE", 1200),
|
|
("GROSS", 1200),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", -24),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold - 24),
|
|
("NET", 1200 + expected_gross + (normal_withholding + expected_withhold - 24)),
|
|
("SUPER", 114),
|
|
],
|
|
)
|
|
|
|
# Causal Employee + Casual Loading
|
|
def test_25_termination_unused_leaves(self):
|
|
employee, contract = self.get_unused_leaves_employee('1976-01-01', '2010-01-01', '2024-03-15')
|
|
contract.schedule_pay = 'weekly'
|
|
contract.wage_type = 'hourly'
|
|
contract.hourly_wage = 40
|
|
contract.l10n_au_casual_loading = 0.25
|
|
|
|
self.create_leaves(
|
|
employee,
|
|
contract,
|
|
leaves={
|
|
"long_service": {
|
|
"post_1993": 40,
|
|
}
|
|
},
|
|
)
|
|
|
|
# Days * Hours/day * Hourly wage * casual loading
|
|
expected_gross = 40 * 7.6 * 40 * 1.25
|
|
expected_withhold = -5252
|
|
normal_withholding = -473
|
|
|
|
self._test_payslip(
|
|
employee,
|
|
contract,
|
|
expected_worked_days=[
|
|
# (work_entry_type_id.id, number_of_day, number_of_hours, amount)
|
|
(self.work_entry_types["WORK100"].id, 5, 38, 1900),
|
|
],
|
|
expected_lines=[
|
|
# (code, total)
|
|
("BASIC", 1900),
|
|
("OTE", 1900),
|
|
("GROSS", 1900),
|
|
("ETP.LEAVE.GROSS", expected_gross),
|
|
("WITHHOLD", normal_withholding),
|
|
("WITHHOLD.STUDY", -114),
|
|
("MEDICARE", 0),
|
|
("ETP.LEAVE.WITHHOLD", expected_withhold),
|
|
("WITHHOLD.TOTAL", normal_withholding + expected_withhold - 114),
|
|
("NET", 1900 + expected_gross + (normal_withholding + expected_withhold - 114)),
|
|
("SUPER", 209),
|
|
],
|
|
payslip_date_from=fields.Date.from_string('2024-03-11'),
|
|
payslip_date_to=contract.date_end,
|
|
termination_type="normal"
|
|
)
|
|
|
|
def test_26_unused_leaves_on_batch_payslip_create(self):
|
|
"""Ensure each termination payslip gets its own unused leave when created in batch.
|
|
|
|
Creating several payslips at once runs unused-leave computation on a multi-recordset.
|
|
Each slip must still receive the leave amounts for its employee only.
|
|
"""
|
|
employee_a, contract_a = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12')
|
|
employee_b, contract_b = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12')
|
|
self.create_leaves(employee_a, contract_a, {"annual": {"post_1993": 10}})
|
|
self.create_leaves(employee_b, contract_b, {"annual": {"post_1993": 5}})
|
|
|
|
payslips = self.env["hr.payslip"].create([{
|
|
"name": "payslip",
|
|
"employee_id": employee.id,
|
|
"version_id": contract.id,
|
|
"struct_id": self.default_payroll_structure.id,
|
|
"date_from": contract.date_end.replace(day=1),
|
|
"date_to": contract.date_end,
|
|
"l10n_au_termination_type": "normal",
|
|
} for employee, contract in ((employee_a, contract_a), (employee_b, contract_b))])
|
|
|
|
payslip_a = payslips.filtered(lambda p: p.employee_id == employee_a)
|
|
payslip_b = payslips.filtered(lambda p: p.employee_id == employee_b)
|
|
self.assertAlmostEqual(
|
|
payslip_a._get_input_line_amount('AL'),
|
|
10 * payslip_a._get_daily_wage(),
|
|
2,
|
|
"Employee A should keep their 10 unused annual leave days on the batch-created payslip",
|
|
)
|
|
self.assertAlmostEqual(
|
|
payslip_b._get_input_line_amount('AL'),
|
|
5 * payslip_b._get_daily_wage(),
|
|
2,
|
|
"Employee B should keep their 5 unused annual leave days on the batch-created payslip",
|
|
)
|
|
|
|
def test_27_unused_leaves_on_batch_payslip_create_without_allocation(self):
|
|
"""Ensure a termination payslip whose employee has no allocation does not break the batch.
|
|
|
|
Unused leave totals are only keyed on the payslips having a matching allocation, so a
|
|
batch mixing employees with and without allocations must still resolve to 0 for the latter.
|
|
"""
|
|
employee_a, contract_a = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12')
|
|
employee_b, contract_b = self.get_unused_leaves_employee('1995-06-08', '2022-01-03', '2024-03-12')
|
|
self.create_leaves(employee_a, contract_a, {"annual": {"post_1993": 10}})
|
|
|
|
payslips = self.env["hr.payslip"].create([{
|
|
"name": "payslip",
|
|
"employee_id": employee.id,
|
|
"version_id": contract.id,
|
|
"struct_id": self.default_payroll_structure.id,
|
|
"date_from": contract.date_end.replace(day=1),
|
|
"date_to": contract.date_end,
|
|
"l10n_au_termination_type": "normal",
|
|
} for employee, contract in ((employee_a, contract_a), (employee_b, contract_b))])
|
|
|
|
payslip_a = payslips.filtered(lambda p: p.employee_id == employee_a)
|
|
payslip_b = payslips.filtered(lambda p: p.employee_id == employee_b)
|
|
self.assertAlmostEqual(
|
|
payslip_a._get_input_line_amount('AL'),
|
|
10 * payslip_a._get_daily_wage(),
|
|
2,
|
|
"Employee A should keep their 10 unused annual leave days on the batch-created payslip",
|
|
)
|
|
self.assertFalse(
|
|
payslip_b.input_line_ids.filtered(lambda x: x.code in ('AL', 'LSL')),
|
|
"Employee B has no allocation and should not get any unused leave input line",
|
|
)
|
|
self.assertEqual(
|
|
payslips._l10n_au_get_unused_leave_totals()[payslip_b.id],
|
|
{"annual": 0.0, "long_service": 0.0},
|
|
"A payslip without allocation should default to 0 instead of being missing from the totals",
|
|
)
|