diff --git a/hr_payroll_payment/__manifest__.py b/hr_payroll_payment/__manifest__.py index 5281bcac..31514164 100755 --- a/hr_payroll_payment/__manifest__.py +++ b/hr_payroll_payment/__manifest__.py @@ -3,7 +3,7 @@ { 'name': 'Payroll Payments', 'author': 'Hibou Corp. ', - 'version': '13.0.1.0.0', + 'version': '13.0.1.1.0', 'category': 'Human Resources', 'sequence': 95, 'summary': 'Register payments for Payroll Payslips', diff --git a/hr_payroll_payment/models/hr_payslip.py b/hr_payroll_payment/models/hr_payslip.py index 0de752a3..b68514a1 100644 --- a/hr_payroll_payment/models/hr_payslip.py +++ b/hr_payroll_payment/models/hr_payslip.py @@ -5,6 +5,13 @@ from odoo.exceptions import UserError, ValidationError from odoo.tools import float_compare, float_is_zero +class HrContract(models.Model): + _inherit = 'hr.contract' + + payroll_fiscal_position_id = fields.Many2one('account.fiscal.position', 'Payroll Fiscal Position', domain="[('company_id', '=', company_id)]", + help="Used for mapping accounts when processing payslip journal entries.") + + class HrPayslipRun(models.Model): _inherit = 'hr.payslip.run' @@ -140,6 +147,7 @@ class HrPayslip(models.Model): # payslips_to_post} # Hibou Customization: group with journal itself so that journal behavior can be derived. # Hibou Customization: prefer slip's `date` over end of month + # Hibou Customization: add an account mapping based on fiscal position slip_mapped_data = { slip.struct_id.journal_id: {slip.date or fields.Date().end_of(slip.date_to, 'month'): self.env['hr.payslip']} for slip in @@ -147,6 +155,8 @@ class HrPayslip(models.Model): for slip in payslips_to_post: slip_mapped_data[slip.struct_id.journal_id][slip.date or fields.Date().end_of(slip.date_to, 'month')] |= slip + account_map = payslips_to_post._generate_account_map() + for journal in slip_mapped_data: # For each journal_id. """ All methods to generate journal entry should generate one or more @@ -154,9 +164,9 @@ class HrPayslip(models.Model): """ for slip_date in slip_mapped_data[journal]: # For each month. if hasattr(self, '_generate_move_' + str(journal.payroll_entry_type)): - getattr(self, '_generate_move_' + str(journal.payroll_entry_type))(slip_mapped_data, journal, slip_date) + getattr(self, '_generate_move_' + str(journal.payroll_entry_type))(slip_mapped_data, journal, slip_date, account_map) else: - self._generate_move_original(slip_mapped_data, journal, slip_date) + self._generate_move_original(slip_mapped_data, journal, slip_date, account_map) def _check_slips_employee_home_address(self): employees_missing_partner = self.mapped('employee_id').filtered(lambda e: not e.address_home_id) @@ -167,7 +177,17 @@ class HrPayslip(models.Model): if len(address_ap) > 1: raise UserError(_('Employee\'s private address account payable not the same for all addresses.')) - def _process_journal_lines_grouped(self, line_ids, date, precision): + def _generate_account_map(self): + account_map = {} + rules = self.mapped('line_ids.salary_rule_id') + base_account_map = {a: a for a in (rules.mapped('account_debit') | rules.mapped('account_credit'))} + account_map[self.env['account.fiscal.position']] = base_account_map + fiscal_positions = self.mapped('contract_id.payroll_fiscal_position_id') + for fp in fiscal_positions: + account_map[fp] = fp.map_accounts(base_account_map.copy()) + return account_map + + def _process_journal_lines_grouped(self, line_ids, date, precision, account_map): slip = self employee_partner_id = slip.employee_id.address_home_id.id for line in slip.line_ids.filtered(lambda l: l.category_id): @@ -181,8 +201,10 @@ class HrPayslip(models.Model): amount += abs(tmp_line.total) if float_is_zero(amount, precision_digits=precision): continue - debit_account_id = line.salary_rule_id.account_debit.id - credit_account_id = line.salary_rule_id.account_credit.id + debit_account = line.salary_rule_id.account_debit + debit_account_id = account_map[debit_account].id if debit_account else False + credit_account = line.salary_rule_id.account_credit + credit_account_id = account_map[credit_account].id if credit_account else False partner_id = line.salary_rule_id.partner_id.id or employee_partner_id if debit_account_id: # If the rule has a debit account. @@ -247,7 +269,7 @@ class HrPayslip(models.Model): credit_line['debit'] += debit credit_line['credit'] += credit - def _generate_move_grouped(self, slip_mapped_data, journal, slip_date): + def _generate_move_grouped(self, slip_mapped_data, journal, slip_date, account_map): slip_mapped_data[journal][slip_date]._check_slips_employee_home_address() precision = self.env['decimal.precision'].precision_get('Payroll') @@ -263,9 +285,10 @@ class HrPayslip(models.Model): } for slip in slip_mapped_data[journal][slip_date]: + slip_accounts = account_map[slip.contract_id.payroll_fiscal_position_id] move_dict['narration'] += slip.number or '' + ' - ' + slip.employee_id.name or '' move_dict['narration'] += '\n' - slip._process_journal_lines_grouped(line_ids, date, precision) + slip._process_journal_lines_grouped(line_ids, date, precision, slip_accounts) for line_id in line_ids: # Get the debit and credit sum. debit_sum += line_id['debit'] @@ -327,12 +350,13 @@ class HrPayslip(models.Model): for slip in slip_mapped_data[journal][slip_date]: slip.write({'move_id': move.id, 'date': date}) - def _generate_move_slip(self, slip_mapped_data, journal, slip_date): + def _generate_move_slip(self, slip_mapped_data, journal, slip_date, account_map): slip_mapped_data[journal][slip_date]._check_slips_employee_home_address() precision = self.env['decimal.precision'].precision_get('Payroll') for slip in slip_mapped_data[journal][slip_date]: + slip_accounts = account_map[slip.contract_id.payroll_fiscal_position_id] line_ids = [] debit_sum = 0.0 credit_sum = 0.0 @@ -346,7 +370,7 @@ class HrPayslip(models.Model): move_dict['narration'] += slip.number or '' + ' - ' + slip.employee_id.name or '' move_dict['narration'] += '\n' - slip._process_journal_lines_grouped(line_ids, date, precision) + slip._process_journal_lines_grouped(line_ids, date, precision, slip_accounts) for line_id in line_ids: # Get the debit and credit sum. debit_sum += line_id['debit'] @@ -407,7 +431,7 @@ class HrPayslip(models.Model): move = self.env['account.move'].create(move_dict) slip.write({'move_id': move.id, 'date': date}) - def _generate_move_original(self, slip_mapped_data, journal, slip_date): + def _generate_move_original(self, slip_mapped_data, journal, slip_date, account_map): """ Odoo's original version. Fixed bug with 'matching' credit line @@ -425,6 +449,7 @@ class HrPayslip(models.Model): } for slip in slip_mapped_data[journal][slip_date]: + slip_accounts = account_map[slip.contract_id.payroll_fiscal_position_id] move_dict['narration'] += slip.number or '' + ' - ' + slip.employee_id.name or '' move_dict['narration'] += '\n' for line in slip.line_ids.filtered(lambda l: l.category_id): @@ -439,8 +464,10 @@ class HrPayslip(models.Model): if float_is_zero(amount, precision_digits=precision): continue - debit_account_id = line.salary_rule_id.account_debit.id - credit_account_id = line.salary_rule_id.account_credit.id + debit_account = line.salary_rule_id.account_debit + debit_account_id = slip_accounts[debit_account].id if debit_account else False + credit_account = line.salary_rule_id.account_credit + credit_account_id = slip_accounts[credit_account].id if credit_account else False if debit_account_id: # If the rule has a debit account. debit = amount if amount > 0.0 else 0.0 diff --git a/hr_payroll_payment/tests/test_hr_payroll_account.py b/hr_payroll_payment/tests/test_hr_payroll_account.py index 22ae94e6..d57cdddf 100644 --- a/hr_payroll_payment/tests/test_hr_payroll_account.py +++ b/hr_payroll_payment/tests/test_hr_payroll_account.py @@ -15,8 +15,26 @@ class TestHrPayrollAccount(TestBase): }) # This rule has a partner, and is the only one with any accounting side effects. # Remove partner to use the home address... - rule = self.env.ref('hr_payroll.hr_salary_rule_houserentallowance1') - rule.partner_id = False + self.rule = self.env.ref('hr_payroll.hr_salary_rule_houserentallowance1') + self.rule.partner_id = False + + def _setup_fiscal_position(self): + account_rule_debit = self.rule.account_debit + self.assertTrue(account_rule_debit) + account_other = self.env['account.account'].search([('id', '!=', account_rule_debit.id)], limit=1) + self.assertTrue(account_other) + fp = self.env['account.fiscal.position'].create({ + 'name': 'Salary Remap 1', + 'account_ids': [(0, 0, { + 'account_src_id': account_rule_debit.id, + 'account_dest_id': account_other.id, + })] + }) + self.hr_contract_john.payroll_fiscal_position_id = fp + + def _setup_fiscal_position_empty(self): + self._setup_fiscal_position() + self.hr_contract_john.payroll_fiscal_position_id.write({'account_ids': [(5, 0, 0)]}) def test_00_hr_payslip_run(self): # Original method groups but has no partners. @@ -26,6 +44,16 @@ class TestHrPayrollAccount(TestBase): self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id')), 1) self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.partner_id')), 0) + def test_00_fiscal_position(self): + self._setup_fiscal_position() + self.test_00_hr_payslip_run() + self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.account_id')), 2) + + def test_00_fiscal_position_empty(self): + self._setup_fiscal_position_empty() + self.test_00_hr_payslip_run() + self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.account_id')), 1) + def test_01_hr_payslip_run(self): # Grouped method groups but has partners. self.account_journal.payroll_entry_type = 'grouped' @@ -34,6 +62,16 @@ class TestHrPayrollAccount(TestBase): self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id')), 1) self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.partner_id')), 2) + def test_01_fiscal_position(self): + self._setup_fiscal_position() + self.test_01_hr_payslip_run() + self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.account_id')), 2) + + def test_01_fiscal_position_empty(self): + self._setup_fiscal_position_empty() + self.test_01_hr_payslip_run() + self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.account_id')), 1) + def test_01_2_hr_payslip_run(self): # Payslip method makes an entry per payslip self.account_journal.payroll_entry_type = 'slip' @@ -42,3 +80,13 @@ class TestHrPayrollAccount(TestBase): self.assertEqual(len(self.payslip_run.slip_ids), 3) self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id')), 3) self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.partner_id')), 2) + + def test_01_2_fiscal_position(self): + self._setup_fiscal_position() + self.test_01_2_hr_payslip_run() + self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.account_id')), 2) + + def test_01_2_fiscal_position_empty(self): + self._setup_fiscal_position_empty() + self.test_01_2_hr_payslip_run() + self.assertEqual(len(self.payslip_run.slip_ids.mapped('move_id.line_ids.account_id')), 1) diff --git a/hr_payroll_payment/views/hr_payslip_views.xml b/hr_payroll_payment/views/hr_payslip_views.xml index 1bcc0deb..d46e3895 100644 --- a/hr_payroll_payment/views/hr_payslip_views.xml +++ b/hr_payroll_payment/views/hr_payslip_views.xml @@ -60,4 +60,16 @@ + + + hr.contract.view.form.inherit + hr.contract + + + + + + + + \ No newline at end of file