mirror of
http://100.103.83.12:3003/fegger/odoo-at-payroll.git
synced 2026-09-17 08:52:45 +00:00
[IMP] l10n_at_hr_payroll_private: add premiums at termination under § 16 AngG (AP14-B)
Close the premium-at-termination gap of the end-of-employment cycle: an aliquote periodic premium (annual, sales, bonus, 15th payment) whose entitlement period outlasts the termination is covered by § 16 AngG — the pro-rata amount follows the ratio of the elapsed service to the entitlement period, is due for employees regardless of the termination ground (loss clauses void, 9 ObA 82/13v), while performance-linked premiums for workers may validly hinge on non-fault grounds and premiums tied to a specific service (e.g. Bilanzgeld) are not aliquote without the service (lb-end-18). Two routes: PRAM_END (bemessung sonstig) covers premiums paid with the end-of-employment run — a special payment inside the annual sixth at the flat 6 % rate with the 620 EUR free amount and 2 615 EUR free threshold checked by the core, SV as special-payment contributions (KV/PV/AV without AK/WF) against the monthly HBG and the annual SZ cap, fully payroll-levy liable and BV-contributory at the uncapped 1.53 % rate (§ 6 Abs 1 iVm Abs 5 BMSVG). PRAM_END_TARIF (bemessung laufend plus the core l10n_at_s67_abs6_ueberhang flag) covers premiums due at a pre-agreed maturity because their amount only becomes determinable after the entitlement period ends (e.g. balance-sheet premiums): taxed like running pay with the payment-month tariff without touching the annual sixth (§ 67 Abs 10, not a § 67 Abs 8 lit c case per 98/14/0009 = ARD 5483/14/2004) — the SV contribution month rolls back into the termination year via a new payslip field consumed by an extended branch of the existing SV-basis-by-Beitragsmonat override (historical caps and rates, E-MVB 044-01-00-006), while the LSt stays in the payment month. The wizard section previews the § 16 pro-rata amount from the full premium, entitlement period and elapsed service, keeps the payable amount confirmable (KB agreement), requires the service/claim-basis confirmation, enforces the contribution month for the deferred case, and lands the memo on the payslip for the separate Lohnzettel workflow (LStR Rz 911a); the existing manual PRAM rule is untouched. The account matrix posts both rules to 6230. Verified against the original statute text in .ris/ (AngG § 16, BMSVG § 6 Abs 5) and the knowledge-base source lb-end-18; the full SZ roll-forward (storno plus recomputation against the termination year's SZ annual cap) and the mBGM storno/re-transmission remain open in the GP7 payroll-reporting track, and the BV attribution of the deferred premium remains in the payment month as a documented approximation. Version 19.0.16.0.0 (private)
This commit is contained in:
@@ -4,7 +4,9 @@ lit d), SV-Verlängerung (§ 11 Abs 2 ASVG, sequentielle Fenster),
|
||||
Abgangsentschädigung (§ 67 Abs 8 lit b Fünftel), Aufrechnung offener
|
||||
Vorschüsse (§ 293 Abs 3 EO) und Zeitguthaben (§ 19e Abs 2 AZG).
|
||||
AP15-C: Vergleichssummen (§ 67 Abs 8 lit a) — Rest-Fünftel,
|
||||
BV-Anwartschafts-Teil mit 6 %/7.500-€-Deckel, Wizard."""
|
||||
BV-Anwartschafts-Teil mit 6 %/7.500-€-Deckel, Wizard.
|
||||
AP14-B: Prämien bei Beendigung (§ 16 AngG-Aliquot, lb-end-18) —
|
||||
sonstiger Bezug mit Endabrechnung, § 67 Abs 10 mit Rollung."""
|
||||
from datetime import date, timedelta
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
@@ -798,3 +800,153 @@ class EndabrechnungPrivateTest(TransactionCase):
|
||||
self.assertAlmostEqual(
|
||||
self._total(slip, 'LST_VERGLEICH_BV'),
|
||||
7500.0 * (1.0 - satz / 100.0) * steuersatz / 100.0, places=2)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# RF-PRM-1: Prämie mit Endabrechnung (§ 16 AngG, sonstiger Bezug)
|
||||
# ------------------------------------------------------------------
|
||||
def test_22_pram_end_mit_endabrechnung(self):
|
||||
"""3.000 € aliquote Prämie, mit der Endabrechnung ausgezahlt
|
||||
(lb-end-18): sonstiger Bezug im Jahressechstel (6 %-Band,
|
||||
Sechstel unverändert), SZ-SV (ohne AK/WF), voll LNK-pflichtig,
|
||||
BV-Beitrag 1,53 % ungecappt (§ 6 Abs 5 BMSVG)."""
|
||||
emp_mit = self._employee(ueberzahlung=3000.0)
|
||||
emp_ohne = self._employee(ueberzahlung=3000.0)
|
||||
for emp in (emp_mit, emp_ohne):
|
||||
emp.version_id.write({'l10n_at_abfertigung_neu': True})
|
||||
slip_mit = self._slip(emp_mit)
|
||||
slip_ohne = self._slip(emp_ohne)
|
||||
self._input(slip_mit, 'ATP_PRAM_END', 3000.0)
|
||||
|
||||
self.assertAlmostEqual(self._total(slip_mit, 'PRAM_END'), 3000.0,
|
||||
places=2)
|
||||
# Sonstiger Bezug erhöht das Jahressechstel nicht
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._l10n_at_sechstel() - slip_ohne._l10n_at_sechstel(),
|
||||
0.0, places=2)
|
||||
# SZ-Bemessung enthält die Prämie (SV-DN nach § 67 Abs 12
|
||||
# abziehen, um den Brutto-Anteil zu isolieren)
|
||||
svdn_sz_diff = (slip_mit._l10n_at_svdn_sz()
|
||||
- slip_ohne._l10n_at_svdn_sz())
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._l10n_at_sz_bemessung()
|
||||
- slip_ohne._l10n_at_sz_bemessung() + svdn_sz_diff,
|
||||
3000.0, places=2)
|
||||
# SZ-SV: KV/PV/AV, ohne AK/WF (§ 62 Z 3/Z 5)
|
||||
satz_sz = sum(slip_mit._l10n_at_sv_satz(
|
||||
'dn', k, staffel_basis=slip_mit._l10n_at_sv_basis_roh())
|
||||
for k in ('kv', 'pv', 'av'))
|
||||
self.assertAlmostEqual(svdn_sz_diff, 3000.0 * satz_sz / 100.0,
|
||||
places=2)
|
||||
# LNK über die volle Prämie
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._at_lnk_basis('flaf')
|
||||
- slip_ohne._at_lnk_basis('flaf'), 3000.0, places=2)
|
||||
# BV 1,53 % ungecappt (§ 6 Abs 1 iVm Abs 5 BMSVG)
|
||||
satz_bv = float(slip_mit._l10n_at_param('at_sv_bv_dg'))
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._at_bv_beitrag() - slip_ohne._at_bv_beitrag(),
|
||||
3000.0 * satz_bv / 100.0, places=2)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# RF-PRM-2: Später fällige Prämie (§ 67 Abs 10) mit SV-Rollung
|
||||
# ------------------------------------------------------------------
|
||||
def test_23_pram_end_tarif_und_rollung(self):
|
||||
"""3.000 € anteilige Prämie für Leistungen im Austrittsjahr 2025,
|
||||
fällig und ausgezahlt im März 2026 (lb-end-18): tarifisch im
|
||||
Zuflussmonat OHNE Sechstel-Erhöhung (§ 67 Abs 10); SV-Rollung
|
||||
auf den Beitragsmonat im Austrittsjahr mit historischen Sätzen
|
||||
und HBG (E-MVB 044)."""
|
||||
emp_mit = self._employee(ueberzahlung=3000.0,
|
||||
ende=date(2025, 12, 31))
|
||||
emp_ohne = self._employee(ueberzahlung=3000.0,
|
||||
ende=date(2025, 12, 31))
|
||||
slip_mit = self._slip(emp_mit, monat=3, jahr=2026)
|
||||
slip_ohne = self._slip(emp_ohne, monat=3, jahr=2026)
|
||||
self._input(slip_mit, 'ATP_PRAM_END_TARIF', 3000.0)
|
||||
|
||||
self.assertAlmostEqual(self._total(slip_mit, 'PRAM_END_TARIF'),
|
||||
3000.0, places=2)
|
||||
# Sechstel unverändert (§ 67 Abs 10: kein Jahressechstel-Effekt)
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._l10n_at_sechstel() - slip_ohne._l10n_at_sechstel(),
|
||||
0.0, places=2)
|
||||
# Tarifisch in der laufenden Bemessung des Zuflussmonats
|
||||
svdn_diff = (slip_mit._l10n_at_svdn_gesamt()
|
||||
- slip_ohne._l10n_at_svdn_gesamt())
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._l10n_at_bemessung_laufen()
|
||||
- slip_ohne._l10n_at_bemessung_laufen() + svdn_diff,
|
||||
3000.0, places=2)
|
||||
# LNK über die volle Prämie
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._at_lnk_basis('flaf')
|
||||
- slip_ohne._at_lnk_basis('flaf'), 3000.0, places=2)
|
||||
# Rollung: SV-Beitragsmonat auf dem Lauf (Austrittsjahr 2025);
|
||||
# historische HBG (2025: 6.450 €) und Sätze des Rollmonats
|
||||
slip_mit.write({'l10n_at_pram_beitragsmonat': date(2025, 6, 1)})
|
||||
slip_mit.compute_sheet()
|
||||
basis = self._basis_monate(slip_mit)
|
||||
self.assertAlmostEqual(basis[date(2025, 6, 1)], 3000.0, places=2)
|
||||
# Im Zuflussmonat bleibt die Prämie außer Ansatz (§ 54 ASVG:
|
||||
# Zuordnung zum Leistungszeitraum) — die Basis entspricht der
|
||||
# eines Laufs ohne Prämie.
|
||||
basis_ohne = self._basis_monate(slip_ohne)
|
||||
self.assertAlmostEqual(basis[date(2026, 3, 1)],
|
||||
basis_ohne[date(2026, 3, 1)], places=2)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# RF-PRM-3: Wizard-E2E und Validierungen (§-16-Aliquot, Rollung)
|
||||
# ------------------------------------------------------------------
|
||||
def test_24_pram_wizard(self):
|
||||
emp = self._employee()
|
||||
emp.version_id.write({
|
||||
'structure_type_id': self.env.ref(
|
||||
'l10n_at_hr_payroll_private.structure_type_at_privat').id,
|
||||
'l10n_at_abfertigung_neu': False,
|
||||
})
|
||||
basis = {
|
||||
'employee_id': emp.id,
|
||||
'austrittsdatum': date(2026, 3, 15),
|
||||
'departure_reason_id': self.env.ref(
|
||||
'l10n_at_hr_payroll.departure_reason_einvernehmlich').id,
|
||||
'pram_aktiv': True,
|
||||
'pram_voller_betrag': 6000.0,
|
||||
'pram_anspruchszeitraum_monate': 12,
|
||||
'pram_dienstzeit_monate': 3,
|
||||
'pram_nachweis': 'KV-Prämienvereinbarung, Leistungszeitraum',
|
||||
}
|
||||
wizard = self.env['l10n.at.payroll.endabrechnung.wizard'].create(
|
||||
dict(basis))
|
||||
self.assertAlmostEqual(wizard.pram_aliquot_vorschau, 1500.0,
|
||||
places=2)
|
||||
with self.assertRaises(UserError):
|
||||
wizard.action_payslip() # Leistungsgrundlage nicht bestätigt
|
||||
wizard.write({'pram_leistung_bestaetigt': True,
|
||||
'pram_betrag': 1000.0})
|
||||
ergebnis = wizard.action_payslip()
|
||||
slip = self.env['hr.payslip'].browse(ergebnis['res_id'])
|
||||
self.assertAlmostEqual(self._total(slip, 'PRAM_END'), 1000.0,
|
||||
places=2)
|
||||
self.assertEqual(
|
||||
slip.l10n_at_pram_nachweis,
|
||||
'KV-Prämienvereinbarung, Leistungszeitraum')
|
||||
|
||||
# Später fällig: Beitragsmonat der Rollung erforderlich
|
||||
wizard2 = self.env[
|
||||
'l10n.at.payroll.endabrechnung.wizard'].create({
|
||||
**basis,
|
||||
'pram_leistung_bestaetigt': True,
|
||||
'pram_betrag': 1000.0,
|
||||
'pram_zahlungsart': 'spaeter_faellig',
|
||||
})
|
||||
with self.assertRaises(UserError):
|
||||
wizard2.action_payslip() # Rollungs-Beitragsmonat fehlt
|
||||
wizard2.write({'pram_beitragsmonat': date(2026, 1, 1)})
|
||||
ergebnis = wizard2.action_payslip()
|
||||
slip2 = self.env['hr.payslip'].browse(ergebnis['res_id'])
|
||||
self.assertAlmostEqual(self._total(slip2, 'PRAM_END_TARIF'),
|
||||
1000.0, places=2)
|
||||
self.assertEqual(slip2.l10n_at_pram_beitragsmonat,
|
||||
date(2026, 1, 1))
|
||||
basis = self._basis_monate(slip2)
|
||||
self.assertIn(date(2026, 1, 1), basis)
|
||||
|
||||
Reference in New Issue
Block a user