Files
enterprise-addons/hr_payroll/tests/common.py
T

314 lines
17 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from odoo.fields import Command, Date
from odoo.tests.common import TransactionCase
from dateutil.relativedelta import relativedelta
class TestPayslipBase(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
payroll_manager = cls.env.ref('hr_payroll.group_hr_payroll_manager')
cls.env.user.group_ids |= payroll_manager
cls.company_us = cls.env['res.company'].create({
'name': 'Company US',
'country_id': cls.env.ref('base.us').id,
})
cls.env = cls.env(context=dict(cls.env.context, allowed_company_ids=cls.company_us.ids))
cls.env.company.resource_calendar_id.tz = 'Europe/Brussels'
cls.env.user.tz = 'Europe/Brussels'
cls.dep_rd = cls.env['hr.department'].sudo().create({
'name': 'Research & Development - Test',
}).sudo(False)
cls.structure_type = cls.env['hr.payroll.structure.type'].create({
'name': 'Test - Developer',
})
cls.richard_emp = cls.env['hr.employee'].create({
'name': 'Richard',
'sex': 'male',
'birthday': '1984-05-01',
'country_id': cls.env.ref('base.us').id,
'department_id': cls.dep_rd.id,
'date_version': Date.to_date('2018-01-01'),
'contract_date_start': Date.to_date('2018-01-01'),
'contract_date_end': Date.today() + relativedelta(years=2),
'wage': 5000.33,
'structure_type_id': cls.structure_type.id,
})
cls.jules_emp = cls.env['hr.employee'].create({
'name': 'Jules',
'sex': 'male',
'birthday': '1984-05-01',
'country_id': cls.env.ref('base.us').id,
'department_id': cls.dep_rd.id,
})
cls.richard_contract = cls.richard_emp.version_id
cls.work_entry_type = cls.env['hr.work.entry.type'].create({
'name': 'Extra attendance',
'is_leave': False,
'code': 'WORKTEST200',
})
cls.work_entry_type_unpaid = cls.env['hr.work.entry.type'].create({
'name': 'Unpaid Leave',
'is_leave': True,
'code': 'LEAVETEST300',
'round_days': 'HALF',
'round_days_type': 'DOWN',
})
cls.work_entry_type_leave = cls.env['hr.work.entry.type'].create({
'name': 'Leave',
'is_leave': True,
'code': 'LEAVETEST100'
})
# I create a work entry type with work rate
cls.work_entry_type_overtime_duty = cls.env['hr.work.entry.type'].create({
'name': 'Overtime Duty',
'is_leave': False,
'code': 'WORKRATETEST400',
'amount_rate': 0.5,
'is_extra_hours': True
})
# I create a salary structure for "Software Developer"
cls.developer_pay_structure = cls.env['hr.payroll.structure'].create({
'name': 'Salary Structure for Software Developer',
'type_id': cls.structure_type.id,
'unpaid_work_entry_type_ids': [(4, cls.work_entry_type_unpaid.id, False)]
})
cls.hra_rule = cls.env['hr.salary.rule'].create({
'name': 'House Rent Allowance',
'sequence': 5,
'amount_select': 'percentage',
'amount_percentage': 40.0,
'amount_percentage_base': 'version.wage',
'code': 'HRA',
'category_id': cls.env.ref('hr_payroll.ALW').id,
'struct_id': cls.developer_pay_structure.id,
})
cls.conv_rule = cls.env['hr.salary.rule'].create({
'name': 'Conveyance Allowance',
'sequence': 10,
'amount_select': 'fix',
'amount_fix': 800.0,
'code': 'CA',
'category_id': cls.env.ref('hr_payroll.ALW').id,
'struct_id': cls.developer_pay_structure.id,
})
cls.mv_rule = cls.env['hr.salary.rule'].create({
'name': 'Meal Voucher',
'sequence': 16,
'amount_select': 'fix',
'amount_fix': 10,
'quantity': "'WORK100' in worked_days and worked_days['WORK100'].number_of_days",
'code': 'MA',
'category_id': cls.env.ref('hr_payroll.ALW').id,
'struct_id': cls.developer_pay_structure.id,
})
cls.sum_of_alw = cls.env['hr.salary.rule'].create({
'name': 'Sum of Allowance category',
'sequence': 99,
'amount_select': 'code',
'amount_python_compute': "result = payslip._sum_category('ALW', payslip.date_from, to_date=payslip.date_to)",
'quantity': "'WORK100' in worked_days and worked_days['WORK100'].number_of_days",
'code': 'SUMALW',
'category_id': cls.env.ref('hr_payroll.ALW').id,
'struct_id': cls.developer_pay_structure.id,
})
cls.pf_rule = cls.env['hr.salary.rule'].create({
'name': 'Provident Fund',
'sequence': 120,
'amount_select': 'percentage',
'amount_percentage': -12.5,
'amount_percentage_base': 'version.wage',
'code': 'PF',
'category_id': cls.env.ref('hr_payroll.DED').id,
'struct_id': cls.developer_pay_structure.id,
})
cls.prof_tax_rule = cls.env['hr.salary.rule'].create({
'name': 'Professional Tax',
'sequence': 150,
'amount_select': 'fix',
'amount_fix': -200.0,
'code': 'PT',
'category_id': cls.env.ref('hr_payroll.DED').id,
'struct_id': cls.developer_pay_structure.id,
})
cls.structure_type.default_struct_id = cls.developer_pay_structure
cls.env.user.write({'group_ids': [
Command.unlink(payroll_manager.id),
Command.link(cls.env.ref('hr_payroll.group_hr_payroll_user').id),
]})
def create_work_entry(self, start, stop, work_entry_type=None):
work_entry_type = work_entry_type or self.work_entry_type
work_entry_vals = [{
'version_id': self.richard_emp.version_ids[0].id,
'name': "Work entry %s-%s" % (start, stop),
'date_start': start,
'date_stop': stop,
'employee_id': self.richard_emp.id,
'work_entry_type_id': work_entry_type.id,
}]
work_entry_vals = self.env['hr.version']._generate_work_entries_postprocess(work_entry_vals)
return self.env['hr.work.entry'].create(work_entry_vals)
class TestPayslipContractBase(TestPayslipBase):
@classmethod
def setUpClass(cls):
super(TestPayslipContractBase, cls).setUpClass()
cls.calendar_richard = cls.env['resource.calendar'].create({'name': 'Calendar of Richard'})
cls.calendar_40h = cls.env['resource.calendar'].create({'name': 'Default calendar'})
cls.calendar_38h = cls.env['resource.calendar'].create({
'name': 'Standard 38 hours/week',
'tz': 'Europe/Brussels',
'company_id': False,
'hours_per_day': 7.6,
'attendance_ids': [(5, 0, 0),
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Monday Lunch', 'dayofweek': '0', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 16.6, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Tuesday Lunch', 'dayofweek': '1', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Tuesday Afternoon', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 16.6, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Wednesday Lunch', 'dayofweek': '2', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 16.6, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Thursday Lunch', 'dayofweek': '3', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 16.6, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Lunch', 'dayofweek': '4', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 16.6, 'day_period': 'afternoon'})
],
})
cls.calendar_35h = cls.env['resource.calendar'].create({
'name': '35h calendar',
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Monday Lunch', 'dayofweek': '0', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Monday Evening', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Tuesday Lunch', 'dayofweek': '1', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Tuesday Evening', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Wednesday Lunch', 'dayofweek': '2', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Wednesday Evening', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Thursday Lunch', 'dayofweek': '3', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Thursday Evening', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Lunch', 'dayofweek': '4', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Friday Evening', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'})
]
})
cls.calendar_2_weeks = cls.env['resource.calendar'].create({
'name': 'Week 1: 30 Hours - Week 2: 16 Hours',
'two_weeks_calendar': True,
'attendance_ids': [
(0, 0, {'name': 'Monday', 'sequence': '1', 'week_type': '0', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 16}),
(0, 0, {'name': 'Monday', 'sequence': '26', 'week_type': '1', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 16}),
(0, 0, {'name': 'Tuesday', 'sequence': '2', 'week_type': '0', 'dayofweek': '1', 'hour_from': 9, 'hour_to': 17}),
(0, 0, {'name': 'Wednesday', 'sequence': '27', 'week_type': '1', 'dayofweek': '2', 'hour_from': 7, 'hour_to': 15}),
(0, 0, {'name': 'Thursday', 'sequence': '28', 'week_type': '1', 'dayofweek': '3', 'hour_from': 8, 'hour_to': 16}),
(0, 0, {'name': 'Friday', 'sequence': '29', 'week_type': '1', 'dayofweek': '4', 'hour_from': 10, 'hour_to': 18}),
(0, 0, {'name': 'Even week', 'dayofweek': '0', 'sequence': '0', 'hour_from': 0, 'day_period': 'morning', 'week_type': '0', 'hour_to': 0, 'display_type': 'line_section'}),
(0, 0, {'name': 'Odd week', 'dayofweek': '0', 'sequence': '25', 'hour_from': 0, 'day_period': 'morning', 'week_type': '1', 'hour_to': 0, 'display_type': 'line_section'}),
]
})
cls.richard_emp.resource_calendar_id = cls.calendar_richard
cls.jules_emp.resource_calendar_id = cls.calendar_2_weeks
cls.calendar_16h = cls.env['resource.calendar'].create({
'name': '16h calendar',
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 11.5, 'day_period': 'morning'}),
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 8, 'hour_to': 11.5, 'day_period': 'morning'}),
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 8, 'hour_to': 11.5, 'day_period': 'morning'}),
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 9, 'hour_to': 12.5, 'day_period': 'morning', 'duration_days': 3.5/5.5}),
(0, 0, {'name': 'Thursday Lunch', 'dayofweek': '3', 'hour_from': 12.5, 'hour_to': 13.5, 'day_period': 'lunch'}),
(0, 0, {'name': 'Thursday Evening', 'dayofweek': '3', 'hour_from': 13.5, 'hour_to': 15.5, 'day_period': 'afternoon', 'duration_days': 2/5.5}),
]
})
cls.calendar_38h_friday_light = cls.env['resource.calendar'].create({
'name': '38 calendar Friday light',
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning', 'duration_days': 4/8.5}),
(0, 0, {'name': 'Monday Lunch', 'dayofweek': '0', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Monday Evening', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 17.5, 'day_period': 'afternoon', 'duration_days': 4.5/8.5}),
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning', 'duration_days': 4/8.5}),
(0, 0, {'name': 'Tuesday Lunch', 'dayofweek': '1', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Tuesday Evening', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 17.5, 'day_period': 'afternoon', 'duration_days': 4.5/8.5}),
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning', 'duration_days': 4/8.5}),
(0, 0, {'name': 'Wednesday Lunch', 'dayofweek': '2', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Wednesday Evening', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 17.5, 'day_period': 'afternoon', 'duration_days': 4.5/8.5}),
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning', 'duration_days': 4/8.5}),
(0, 0, {'name': 'Thursday Lunch', 'dayofweek': '3', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Thursday Evening', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 17.5, 'day_period': 'afternoon', 'duration_days': 4.5/8.5}),
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning', 'duration_days': 1}),
]
})
# This contract ends at the 15th of the month
cls.contract_cdd = cls.richard_emp.sudo().create_version({ # Fixed term contract
'contract_date_end': datetime.strptime('2015-11-15', '%Y-%m-%d'),
'contract_date_start': datetime.strptime('2015-01-01', '%Y-%m-%d'),
'date_version': datetime.strptime('2015-01-01', '%Y-%m-%d'),
'resource_calendar_id': cls.calendar_40h.id,
'wage': 5000.33,
'structure_type_id': cls.structure_type.id,
'date_generated_from': datetime.strptime('2015-11-16', '%Y-%m-%d'),
'date_generated_to': datetime.strptime('2015-11-16', '%Y-%m-%d'),
})
# This contract starts the next day
cls.contract_cdi = cls.richard_contract
cls.richard_contract.sudo().write({
'contract_date_start': datetime.strptime('2015-11-16', '%Y-%m-%d'),
'contract_date_end': False,
'date_version': datetime.strptime('2015-11-16', '%Y-%m-%d'),
'resource_calendar_id': cls.calendar_35h.id,
'wage': 5000.33,
'structure_type_id': cls.structure_type.id,
'date_generated_from': datetime.strptime('2015-11-15', '%Y-%m-%d'),
'date_generated_to': datetime.strptime('2015-11-15', '%Y-%m-%d'),
})
# Contract for Jules
cls.jules_emp.version_id.sudo().write({
'contract_date_start': datetime.strptime('2015-01-01', '%Y-%m-%d'),
'date_version': datetime.strptime('2015-01-01', '%Y-%m-%d'),
'name': 'Contract for Jules',
'resource_calendar_id': cls.calendar_2_weeks.id,
'wage': 5000.33,
'employee_id': cls.jules_emp.id,
'structure_type_id': cls.developer_pay_structure.type_id.id,
})
cls.contract_jules = cls.jules_emp.version_id