# Part of the gem360 onboarding. See LICENSE / project docs for details. from datetime import date from odoo.tests import TransactionCase, tagged @tagged('post_install', '-at_install') class EntgeltTest(TransactionCase): """AP2 Rechenfälle: Monatsentgelt, Kinderzulage, Funktionszulage, Sonderzahlung (quartalsweise), Ausbildungsphase.""" def setUp(self): super().setUp() self.structure = self.env.ref( 'l10n_at_gemeinde_payroll.structure_gembg_bgld') self.gruppe_av1 = self.env.ref( 'l10n_at_gemeinde_payroll.bgld_grp_av_av1') self.parameter = self.env['hr.rule.parameter'] def _create_employee_with_payslip(self, month=None, **kwargs): employee = self.env['hr.employee'].create({ 'name': 'Test GemBG Entgelt', }) version = self.env['hr.version'].search( [('employee_id', '=', employee.id)], limit=1) if not version: version = self.env['hr.version'].create({ 'employee_id': employee.id, 'date_start': date(2020, 1, 1), }) version_vals = { 'entlohnungsgruppe_id': self.gruppe_av1.id, 'entlohnungsstufe': kwargs.get('stufe', 1), } version_vals.update(kwargs.get('version_vals', {})) version.write(version_vals) # Ausbildungsphase und Zulagen direkt auf Version if 'ausbildungsphase' in kwargs: version.ausbildungsphase = kwargs['ausbildungsphase'] if 'funktionszulage' in kwargs: version.funktionszulage = kwargs['funktionszulage'] if 'kinder_anzahl' in kwargs: version.kinder_anzahl = kwargs['kinder_anzahl'] slip_month = month or 7 slip = self.env['hr.payslip'].create({ 'employee_id': employee.id, 'struct_id': self.structure.id, 'date_from': date(2026, slip_month, 1), 'date_to': date(2026, slip_month, 28), }) slip.compute_sheet() return employee, slip def _get_rule_total(self, slip, code): line = slip.line_ids.filtered( lambda l: l.code == code) return line.total if line else 0.0 def test_01_monatsentgelt_av1_stufe1(self): """Vollzeit av1 Stufe 1 = 7.135,20 € (Wert 1.7.2026).""" _, slip = self._create_employee_with_payslip(month=7) self.assertAlmostEqual( self._get_rule_total(slip, 'ME'), 7135.20, places=2) def test_02_kinderzulage_ungekuerzt_bei_teilzeit(self): """Kinderzulage: 2 Kinder = 31,20 €, auch bei Teilzeit.""" _, slip = self._create_employee_with_payslip( month=7, kinder_anzahl=2) # 2 × 15,60 = 31,20 self.assertAlmostEqual( self._get_rule_total(slip, 'KIZU'), 31.20, places=2) def test_03_funktionszulage(self): """Funktionszulage: 200 € am Vertrag.""" _, slip = self._create_employee_with_payslip( month=7, funktionszulage=200.0) self.assertAlmostEqual( self._get_rule_total(slip, 'FUZU'), 200.0, places=2) def test_04_ausbildungsphase_5_prozent_abzug(self): """§ 133h: 5 % Abzug auf Monatsentgelt.""" _, slip = self._create_employee_with_payslip( month=7, ausbildungsphase=True) # 7.135,20 × 0,95 = 6.778,44 self.assertAlmostEqual( self._get_rule_total(slip, 'ME'), 6778.44, places=2) def test_05_sonderzahlung_quartalsende(self): """SZ in September (Q3-Ende) = 50 % × (ME + KIZU).""" _, slip = self._create_employee_with_payslip( month=9, kinder_anzahl=1) me = self._get_rule_total(slip, 'ME') kizu = self._get_rule_total(slip, 'KIZU') sz = self._get_rule_total(slip, 'SZQ') self.assertAlmostEqual(sz, (me + kizu) * 0.5, places=2) def test_06_sonderzahlung_kein_quartalsende(self): """Kein SZ außerhalb der Quartalsendmonate.""" _, slip = self._create_employee_with_payslip(month=7) self.assertEqual(self._get_rule_total(slip, 'SZQ'), 0.0) def test_07_netto_ohne_abzuege(self): """R1: Netto = Brutto (AP3/AP4 Abzüge noch nicht implementiert).""" _, slip = self._create_employee_with_payslip( month=7, kinder_anzahl=1, funktionszulage=100.0) brutto = self._get_rule_total(slip, 'ME') \ + self._get_rule_total(slip, 'KIZU') \ + self._get_rule_total(slip, 'FUZU') netto = self._get_rule_total(slip, 'NETTO') self.assertAlmostEqual(netto, brutto, places=2) def test_08_stufe_12_max(self): """Stufe 12 von av1 = 8.712,50 €.""" _, slip = self._create_employee_with_payslip(month=7, stufe=12) self.assertAlmostEqual( self._get_rule_total(slip, 'ME'), 8712.50, places=2)