mirror of
http://100.103.83.12:3003/fegger/odoo-at-payroll.git
synced 2026-09-17 16:56:42 +00:00
0abc1383d1
AP10 — Latenzfehler des nie installierten Vorlaufs: - regular_pay auf hr.payroll.structure entfernt (Feld existiert nicht) - is_paid/round_days/round_days_type von WET-Records entfernt - Falscher XML-ID-Praefix payroll_structure_bgld. -> Modul-Referenzen - amount_select 'python' -> 'code' (Selection) - import in Regelcode entfernt (safe_eval verbietet IMPORT_NAME) - rules['ME'].total -> result_rules['ME']['total'] (Odoo 19 befuellt rules nie; SZQ-Sonderzahlung rechnete gegen Null) - categories.X -> categories['X'] (NETTO-Regel) - work_time_rate /100 entfernt (Odoo 19 speichert Bruchteil 0..1) - nie gelaufene Tests: Payslip-name-Pflichtfeld, Stichtag vor Katalog-Gueltigkeit (Wizard-Skip korrekt), date_start ist Compute aus contract_date_start AP9 — BDA-Vordienstzeiten (GemBG S 67 Abs 1-3, RIS LrB GesNr 20001002 verifiziert): Feld vordienstzeiten_monate (Help dokumentiert Anrechnungskatalog inkl. Obergrenzen), Compute bda_vorschlag (Vertragsbeginn - Monate), Uebernahme-Button als Verwaltungsakt, View-Erweiterung
118 lines
4.8 KiB
Python
118 lines
4.8 KiB
Python
# 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({
|
||
'name': 'GemBG-Test %d/2026' % slip_month,
|
||
'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) |