Files
Odoo-Modules/fusion_accounting_hr_payroll/tests/test_payslip_to_move.py
gsinghpal a730942d24 feat(fusion_accounting_hr_payroll): payroll -> GL bridge
Replaces Enterprise's hr_payroll_account with a Fusion-native bridge:
- Adds account_debit / account_credit / fusion_analytic_account_id /
  not_computed_in_net to hr.salary.rule (company-dependent GL mapping)
- Adds move_id + move_state + journal_id + _fusion_create_account_move
  to hr.payslip (validated payslip -> balanced account.move)
- Adds move_id + move_state + action_open_move to hr.payslip.run
- Adds journal_id (company-dependent) to hr.payroll.structure
- Adds is_payroll_journal flag to account.journal
- Adds payslip_ids / payslip_count + action_open_payslip on account.move
- Adds payslip_id reverse link on account.move.line
- Adds move_line_id reverse link on hr.payslip.line
- Adds fusion_payroll_journal_id + fusion_payroll_auto_post to res.company
  (with res.config.settings exposure)

Coexistence: detects Enterprise hr_payroll_account at runtime via
ir.module.module and yields move creation to it while both modules are
installed, so payslips do not get duplicate entries. Once the Enterprise
module is uninstalled, this module owns the bridge.

Auto-installs whenever both hr_payroll and fusion_accounting_core are
present on the database.

10 smoke tests verifying field surface + bridge entrypoints all pass on
westin-v19. Full payslip-to-move integration test deferred (needs
seeded payroll structure).

Removes Westin's last payroll-accounting dependency on Enterprise's
accountant umbrella module (Phase 6b of the Fusion Accounting suite).

Made-with: Cursor
2026-04-20 00:18:08 -04:00

109 lines
3.8 KiB
Python

from odoo.tests import tagged
from odoo.tests.common import TransactionCase
@tagged('post_install', '-at_install')
class TestFusionPayrollBridge(TransactionCase):
"""Smoke tests for the Fusion payroll bridge.
Verifies that the field surface required to replace Enterprise's
``hr_payroll_account`` is present after the module installs.
Full payslip-to-move integration is exercised in a separate
integration test that needs a seeded payroll structure.
"""
def test_module_installed(self):
module = self.env['ir.module.module'].sudo().search(
[('name', '=', 'fusion_accounting_hr_payroll')], limit=1,
)
self.assertTrue(module, "Module record must exist")
self.assertEqual(
module.state, 'installed',
"Module should be in 'installed' state for these tests to run",
)
def test_salary_rule_has_account_fields(self):
rule_model = self.env['hr.salary.rule']
for fname in (
'account_debit',
'account_credit',
'fusion_analytic_account_id',
'not_computed_in_net',
):
self.assertIn(
fname, rule_model._fields,
f"hr.salary.rule must expose '{fname}'",
)
def test_payslip_has_move_link(self):
slip_model = self.env['hr.payslip']
for fname in ('move_id', 'move_state', 'journal_id'):
self.assertIn(
fname, slip_model._fields,
f"hr.payslip must expose '{fname}'",
)
self.assertTrue(
hasattr(slip_model, '_fusion_create_account_move'),
"hr.payslip must expose the _fusion_create_account_move bridge",
)
self.assertTrue(
hasattr(slip_model, '_fusion_enterprise_bridge_active'),
"hr.payslip must expose the Enterprise-bridge detector",
)
def test_payslip_run_has_move_link(self):
run_model = self.env['hr.payslip.run']
for fname in ('move_id', 'move_state'):
self.assertIn(
fname, run_model._fields,
f"hr.payslip.run must expose '{fname}'",
)
def test_company_payroll_journal_field(self):
co_model = self.env['res.company']
for fname in ('fusion_payroll_journal_id', 'fusion_payroll_auto_post'):
self.assertIn(
fname, co_model._fields,
f"res.company must expose '{fname}'",
)
def test_account_move_back_links(self):
move_model = self.env['account.move']
for fname in ('payslip_ids', 'payslip_count'):
self.assertIn(
fname, move_model._fields,
f"account.move must expose '{fname}'",
)
line_model = self.env['account.move.line']
self.assertIn(
'payslip_id', line_model._fields,
"account.move.line must expose 'payslip_id'",
)
def test_payslip_line_has_move_line_link(self):
line_model = self.env['hr.payslip.line']
self.assertIn(
'move_line_id', line_model._fields,
"hr.payslip.line must expose 'move_line_id'",
)
def test_enterprise_bridge_detector_returns_bool(self):
slip_model = self.env['hr.payslip']
self.assertIsInstance(
slip_model._fusion_enterprise_bridge_active(), bool,
)
def test_account_journal_payroll_flag(self):
journal_model = self.env['account.journal']
self.assertIn(
'is_payroll_journal', journal_model._fields,
"account.journal must expose 'is_payroll_journal'",
)
def test_payroll_structure_journal_field(self):
struct_model = self.env['hr.payroll.structure']
self.assertIn(
'journal_id', struct_model._fields,
"hr.payroll.structure must expose 'journal_id'",
)