182 lines
6.4 KiB
Python
182 lines
6.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo.tests.common import TransactionCase, Form
|
|
from odoo.exceptions import UserError
|
|
from odoo.tests import tagged
|
|
from datetime import date, datetime, timedelta
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
|
|
class TestPayrollAdvanceFlow(TransactionCase):
|
|
|
|
def setUp(cls):
|
|
super(TestPayrollAdvanceFlow, cls).setUp()
|
|
|
|
cls.company = cls.env.company
|
|
|
|
cls.account_salary = cls.env['account.account'].create({
|
|
'name': 'Basic Salary Account',
|
|
'code': '600001',
|
|
'account_type': 'expense',
|
|
'reconcile': True,
|
|
})
|
|
|
|
cls.account_payable = cls.env['account.account'].create({
|
|
'name': 'Salaries Payable',
|
|
'code': '200001',
|
|
'account_type': 'liability_payable',
|
|
'reconcile': True,
|
|
})
|
|
|
|
cls.journal = cls.env['account.journal'].create({
|
|
'name': 'Salary Journal',
|
|
'type': 'general',
|
|
'code': 'SAL',
|
|
'default_account_id': cls.account_payable.id,
|
|
})
|
|
|
|
cls.rule_basic = cls.env['hr.salary.rule'].create({
|
|
'name': 'Basic Salary',
|
|
'sequence': 1,
|
|
'code': 'BASIC',
|
|
'category_id': cls.env.ref('exp_hr_payroll.ALW').id,
|
|
'condition_select': 'none',
|
|
'amount_select': 'code',
|
|
'amount_python_compute': 'result = contract.wage',
|
|
'rule_debit_account_id': cls.account_salary.id,
|
|
})
|
|
|
|
cls.rule_net = cls.env['hr.salary.rule'].create({
|
|
'name': 'Net Salary',
|
|
'sequence': 100,
|
|
'code': 'NET',
|
|
'category_id': cls.env.ref('exp_hr_payroll.DED').id,
|
|
'condition_select': 'none',
|
|
'amount_select': 'code',
|
|
'amount_python_compute': 'result = categories.BASIC + categories.ALW + categories.DED',
|
|
'rule_credit_account_id': cls.account_payable.id,
|
|
})
|
|
|
|
cls.structure = cls.env['hr.payroll.structure'].create({
|
|
'name': 'Standard Structure',
|
|
'type': 'scale',
|
|
'code': 'STRUCT_001',
|
|
'rule_ids': [(4, cls.rule_basic.id), (4, cls.rule_net.id)],
|
|
'transfer_type': 'one_by_one',
|
|
})
|
|
|
|
cls.employee = cls.env['hr.employee'].create({
|
|
'name': 'Test Employee Payroll',
|
|
'first_hiring_date': date.today() - relativedelta(years=1),
|
|
'state': 'open',
|
|
})
|
|
|
|
cls.contract = cls.env['hr.contract'].create({
|
|
'name': 'Contract For Test',
|
|
'employee_id': cls.employee.id,
|
|
'state': 'program_directory',
|
|
'wage': 5000.0,
|
|
'salary_scale': cls.structure.id,
|
|
'journal_id': cls.journal.id,
|
|
'date_start': date.today() - relativedelta(years=1),
|
|
})
|
|
def test_01_payslip_compute_and_transfer(self):
|
|
|
|
date_from = date.today().replace(day=1)
|
|
date_to = date.today() + relativedelta(months=+1, day=1, days=-1)
|
|
|
|
payslip = self.env['hr.payslip'].create({
|
|
'name': 'Test Payslip',
|
|
'employee_id': self.employee.id,
|
|
'date_from': date_from,
|
|
'date_to': date_to,
|
|
'contract_id': self.contract.id,
|
|
'struct_id': self.structure.id
|
|
})
|
|
|
|
payslip.compute_sheet()
|
|
|
|
self.assertEqual(payslip.state, 'computed', "State should be 'computed' after computing sheet")
|
|
|
|
basic_line = payslip.line_ids.filtered(lambda l: l.code == 'BASIC')
|
|
self.assertEqual(basic_line.total, 5000.0, "Basic salary should be 5000")
|
|
|
|
payslip.compute_totals()
|
|
self.assertEqual(payslip.total_allowances, 5000.0, "Total allowances should be calculated correctly")
|
|
|
|
payslip.confirm()
|
|
self.assertEqual(payslip.state, 'confirmed')
|
|
|
|
payslip.transfer()
|
|
self.assertEqual(payslip.state, 'transfered')
|
|
self.assertTrue(payslip.move_id, "Journal Entry should be created")
|
|
self.assertEqual(payslip.move_id.state, 'draft', "Move should be created in draft state initially")
|
|
|
|
def test_02_payslip_loans_integration(self):
|
|
|
|
payslip = self.env['hr.payslip'].create({
|
|
'name': 'Loan Payslip',
|
|
'employee_id': self.employee.id,
|
|
'date_from': date.today().replace(day=1),
|
|
'date_to': date.today() + relativedelta(months=+1, day=1, days=-1),
|
|
})
|
|
|
|
self.env['payslip.loans'].create({
|
|
'payslip_loan': payslip.id,
|
|
'name': 'Car Loan',
|
|
'code': 'LOAN01',
|
|
'amount': 500.0,
|
|
'date': date.today(),
|
|
'account_id': self.account_payable.id,
|
|
})
|
|
|
|
payslip.compute_totals()
|
|
self.assertEqual(payslip.total_loans, 500.0, "Total loans field should calculate sum of loan lines")
|
|
|
|
|
|
self.assertEqual(payslip.total_sum, 500.0, "Total sum logic check (depends on allowances setup)")
|
|
|
|
def test_03_payslip_run_batch_process(self):
|
|
|
|
date_start = date.today().replace(day=1)
|
|
date_end = date.today() + relativedelta(months=+1, day=1, days=-1)
|
|
|
|
payslip_run = self.env['hr.payslip.run'].create({
|
|
'name': 'Monthly Run',
|
|
'date_start': date_start,
|
|
'date_end': date_end,
|
|
'salary_scale': self.structure.id,
|
|
})
|
|
|
|
payslip_run.check_date_start()
|
|
self.assertEqual(payslip_run.date_end, date_end)
|
|
|
|
payslip_run.compute_sheet()
|
|
|
|
self.assertTrue(payslip_run.slip_ids, "Payslips should be generated for eligible employees")
|
|
generated_slip = payslip_run.slip_ids[0]
|
|
self.assertEqual(generated_slip.employee_id, self.employee)
|
|
self.assertEqual(generated_slip.state, 'computed')
|
|
|
|
payslip_run.confirm()
|
|
self.assertEqual(generated_slip.state, 'confirmed')
|
|
|
|
|
|
payslip_run.transfer()
|
|
self.assertEqual(payslip_run.state, 'transfered')
|
|
self.assertTrue(payslip_run.move_id or generated_slip.move_id, "Accounting move should be generated")
|
|
|
|
def test_04_payslip_withdraw_and_reset(self):
|
|
|
|
payslip = self.env['hr.payslip'].create({
|
|
'name': 'Withdraw Test',
|
|
'employee_id': self.employee.id,
|
|
'date_from': date.today(),
|
|
'date_to': date.today(),
|
|
})
|
|
payslip.compute_sheet()
|
|
payslip.confirm()
|
|
|
|
payslip.withdraw()
|
|
|
|
self.assertEqual(payslip.state, 'draft', "State should return to draft after withdraw")
|
|
self.assertFalse(payslip.move_id, "Account move should be unlinked/deleted") |