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 settlement payments under § 67 Abs 8 lit a (AP15-C)
Complete the termination sequence with the settlement-sum path: comparison sums from court or out-of-court settlements, judgment/decision arrears and dismissal-objection payments are split between the statutory-severance and voluntary-severance rules and the settlement remainder. The remainder (VERGLEICH, bemessung neutral, sv_art laufend) reuses the lit-a/b fifth rule: after deducting the § 62 employee-rate contributions, one fifth stays tax-free capped at one fifth of nine times the monthly HBG (12 474 EUR 2026), and the remaining four fifths run with the payment-month tariff without touching the annual sixth. A new rule flag l10n_at_vergleich_bv marks the part paid for periods with a BV-Kasse entitlement: up to the parameterised cap at_lst_67_abs8_vergleich_bv (7 500 EUR 2026; § 67 Abs 8 is § 33a/§ 124b indexed) it is taxed at the flat 6 % rate with the contributions allocated pro rata (LStR Rz 1102b), while the excess falls back into the fifth rule. Both settlement rules stay payroll-levy liable (§ 41 Abs 4 lit b FLAG exempts only § 67 Abs 3 and 6) and SV-liable in the payment month, with per-Beitragsmonat roll-forward and insurance-period extension remaining documented manual options (lb-end-22, E-MVB 011-02-00-001). Identifiable severance components keep running through the existing statutory and voluntary severance machinery; a settlement expressly agreed as statutory severance is taxed in full under § 67 Abs 3 (VwGH 2013/13/0001 = ARD 6490/20/2016), and pension buy-outs (lit e) and social-plan payments (lit f) are out of scope. The wizard section requires confirmation of the settlement's itemisation and contested-claim status plus the BV entitlement, enforces the BV cap with the excess captured as remainder, and previews the free fifth, tariff basis and 6 % tax; the settlement memo lands on the payslip for the separate Lohnzettel workflow (LStR Rz 911a). The account matrix posts both settlement rules to the provisional 6200/6000 (workers 6000) and the new tax rule to 3540. Verified against the original statute text in .ris/ (EStG § 67 Abs 8 lit a) and the knowledge-base sources lb-end-21/22; KZ positioning of the lit-a tariff parts and their § 291d pot allocation remain documented verification points against LStR Rz 1087 ff. Version 19.0.15.0.0 (private)
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
"""AP14-A: Endabrechnungs-Zyklus — UEL-Zweikomponenten (§ 67 Abs 8
|
||||
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)."""
|
||||
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."""
|
||||
from datetime import date, timedelta
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
@@ -611,3 +613,188 @@ class EndabrechnungPrivateTest(TransactionCase):
|
||||
self.assertEqual(slip.l10n_at_abf_frei_dienstzeit_monate, 180)
|
||||
self.assertEqual(slip.l10n_at_abf_frei_nachweis,
|
||||
'Vordienstzeiten zum Lohnkonto nachgewiesen')
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# RF-VGL-1: Vergleichssumme Rest (§ 67 Abs 8 lit a, Fünftelregelung)
|
||||
# ------------------------------------------------------------------
|
||||
def test_18_vergleich_rest_fuenftel(self):
|
||||
"""9.000 € Vergleich-Rest (lb-end-21 Beispiel 1): nach
|
||||
§-62-Abzug ist 1/5 steuerfrei (Deckel 12.474 €), 4/5 laufen
|
||||
tarifisch im Zuflussmonat OHNE Sechstel-Effekt; SV-pflichtig im
|
||||
Zuflussmonat, voll LNK-pflichtig."""
|
||||
emp_mit = self._employee(ueberzahlung=3000.0)
|
||||
emp_ohne = self._employee(ueberzahlung=3000.0)
|
||||
slip_mit = self._slip(emp_mit)
|
||||
slip_ohne = self._slip(emp_ohne)
|
||||
self._input(slip_mit, 'ATP_VERGLEICH', 9000.0)
|
||||
|
||||
self.assertAlmostEqual(self._total(slip_mit, 'VERGLEICH'), 9000.0,
|
||||
places=2)
|
||||
# Sechstel unverändert (Abs 2 nicht anzuwenden)
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._l10n_at_sechstel() - slip_ohne._l10n_at_sechstel(),
|
||||
0.0, places=2)
|
||||
satz = sum(slip_mit._l10n_at_sv_satz(
|
||||
'dn', k, staffel_basis=slip_mit._l10n_at_sv_basis_roh())
|
||||
for k in ('kv', 'pv', 'av', 'ak', 'wf'))
|
||||
bemessung = 9000.0 * (1.0 - satz / 100.0)
|
||||
deckel = float(slip_mit._l10n_at_param('at_sv_hbg_monatlich')) \
|
||||
* 9.0 / 5.0
|
||||
frei = min(bemessung / 5.0, deckel)
|
||||
self.assertAlmostEqual(slip_mit._at_fuenftel_frei_betr(), frei,
|
||||
places=2)
|
||||
self.assertAlmostEqual(slip_mit._at_fuenftel_tarif_basis(),
|
||||
bemessung - frei, places=2)
|
||||
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,
|
||||
bemessung - frei, places=2)
|
||||
# LNK-Basis um die volle Vergleichssumme erhöht
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._at_lnk_basis('flaf')
|
||||
- slip_ohne._at_lnk_basis('flaf'), 9000.0, places=2)
|
||||
# SV-pflichtig im Zuflussmonat (rohe Basis vor HBG-Cap)
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._l10n_at_sv_basis_roh()
|
||||
- slip_ohne._l10n_at_sv_basis_roh(), 9000.0, places=2)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# RF-VGL-2: BV-Anwartschafts-Teil (§ 67 Abs 8 lit a, 6 %/7.500 €)
|
||||
# ------------------------------------------------------------------
|
||||
def test_19_vergleich_bv_sechs_prozent(self):
|
||||
"""9.000 € Vergleichssumme mit BV-Anwartschaft (lb-end-21
|
||||
Beispiel 2): erste 7.500 € nach anteiligem §-62-Abzug mit 6 %,
|
||||
der Überhang von 1.500 € fällt in die Fünftelregelung zurück
|
||||
(anteilige Beitragszuordnung, LStR Rz 1102b)."""
|
||||
emp_mit = self._employee(ueberzahlung=3000.0)
|
||||
emp_ohne = self._employee(ueberzahlung=3000.0)
|
||||
slip_mit = self._slip(emp_mit)
|
||||
slip_ohne = self._slip(emp_ohne)
|
||||
self._input(slip_mit, 'ATP_VERGLEICH_BV', 9000.0)
|
||||
|
||||
self.assertAlmostEqual(self._total(slip_mit, 'VERGLEICH_BV'),
|
||||
9000.0, places=2)
|
||||
satz = sum(slip_mit._l10n_at_sv_satz(
|
||||
'dn', k, staffel_basis=slip_mit._l10n_at_sv_basis_roh())
|
||||
for k in ('kv', 'pv', 'av', 'ak', 'wf'))
|
||||
steuersatz = float(slip_mit._l10n_at_param(
|
||||
'at_endabrechnung')['abfertigung_steuersatz'])
|
||||
self.assertAlmostEqual(
|
||||
self._total(slip_mit, 'LST_VERGLEICH_BV'),
|
||||
7500.0 * (1.0 - satz / 100.0) * steuersatz / 100.0, places=2)
|
||||
# Überhang in die Fünftelregelung zurück
|
||||
self.assertAlmostEqual(slip_mit._at_fuenftel_total(), 1500.0,
|
||||
places=2)
|
||||
deckel = float(slip_mit._l10n_at_param('at_sv_hbg_monatlich')) \
|
||||
* 9.0 / 5.0
|
||||
ueberhang_bem = 1500.0 * (1.0 - satz / 100.0)
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._at_fuenftel_frei_betr(),
|
||||
min(ueberhang_bem / 5.0, deckel), places=2)
|
||||
# Sechstel unverändert; LNK und SV über die volle Summe
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._l10n_at_sechstel() - slip_ohne._l10n_at_sechstel(),
|
||||
0.0, places=2)
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._at_lnk_basis('flaf')
|
||||
- slip_ohne._at_lnk_basis('flaf'), 9000.0, places=2)
|
||||
self.assertAlmostEqual(
|
||||
slip_mit._l10n_at_sv_basis_roh()
|
||||
- slip_ohne._l10n_at_sv_basis_roh(), 9000.0, places=2)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# RF-VGL-3: Deckel — Fünftel an 9 × HBG/5, BV-Teil an 7.500 €
|
||||
# ------------------------------------------------------------------
|
||||
def test_20_vergleich_deckel(self):
|
||||
"""Deckelfälle (lb-end-21): der Fünftel-Deckel greift, wenn die
|
||||
§-62-gekürzte Bemessung 5 × 12.474 € übersteigt — bei Brutto
|
||||
100.000 € ist das der Fall; das 70.000-€-Beispiel der Quelle
|
||||
meint die bereits gekürzte Bemessungsgrundlage. BV-Teil
|
||||
10.000 € → 7.500 € begünstigt, 2.500 € zurück in die
|
||||
Fünftelregelung."""
|
||||
emp = self._employee(ueberzahlung=3000.0)
|
||||
slip = self._slip(emp)
|
||||
self._input(slip, 'ATP_VERGLEICH', 100000.0)
|
||||
satz = sum(slip._l10n_at_sv_satz(
|
||||
'dn', k, staffel_basis=slip._l10n_at_sv_basis_roh())
|
||||
for k in ('kv', 'pv', 'av', 'ak', 'wf'))
|
||||
bemessung = 100000.0 * (1.0 - satz / 100.0)
|
||||
deckel = float(slip._l10n_at_param('at_sv_hbg_monatlich')) \
|
||||
* 9.0 / 5.0
|
||||
self.assertGreater(bemessung / 5.0, deckel)
|
||||
self.assertAlmostEqual(slip._at_fuenftel_frei_betr(), deckel,
|
||||
places=2)
|
||||
self.assertAlmostEqual(
|
||||
slip._at_fuenftel_tarif_basis(), bemessung - deckel, places=2)
|
||||
|
||||
slip.input_line_ids.filtered(
|
||||
lambda i: i.input_type_id.code == 'ATP_VERGLEICH').write(
|
||||
{'amount': 0.0})
|
||||
self._input(slip, 'ATP_VERGLEICH_BV', 10000.0)
|
||||
self.assertAlmostEqual(slip._at_vergleich_bv_beguenstigt(), 7500.0,
|
||||
places=2)
|
||||
self.assertAlmostEqual(slip._at_vergleich_bv_ueberhang(), 2500.0,
|
||||
places=2)
|
||||
self.assertAlmostEqual(slip._at_fuenftel_total(), 2500.0,
|
||||
places=2)
|
||||
steuersatz = float(slip._l10n_at_param(
|
||||
'at_endabrechnung')['abfertigung_steuersatz'])
|
||||
self.assertAlmostEqual(
|
||||
self._total(slip, 'LST_VERGLEICH_BV'),
|
||||
7500.0 * (1.0 - satz / 100.0) * steuersatz / 100.0, places=2)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# RF-VGL-4: Wizard-E2E und Validierungen (Bestätigungspflichten)
|
||||
# ------------------------------------------------------------------
|
||||
def test_21_vergleich_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,
|
||||
'vergleich_aktiv': True,
|
||||
'vergleich_rest_betrag': 9000.0,
|
||||
'vergleich_nachweis':
|
||||
'Außergerichtlicher Vergleich, Ansprüche strittig',
|
||||
}
|
||||
wizard = self.env['l10n.at.payroll.endabrechnung.wizard'].create(
|
||||
dict(basis))
|
||||
with self.assertRaises(UserError):
|
||||
wizard.action_payslip() # Aufgliederung nicht bestätigt
|
||||
wizard.write({'vergleich_aufteilung_bestaetigt': True,
|
||||
'vergleich_bv_betrag': 8000.0,
|
||||
'vergleich_bv_anwartschaft_bestaetigt': True})
|
||||
with self.assertRaises(UserError):
|
||||
wizard.action_payslip() # BV-Teil über 7.500 €
|
||||
wizard.write({'vergleich_bv_betrag': 5000.0,
|
||||
'vergleich_bv_anwartschaft_bestaetigt': False})
|
||||
with self.assertRaises(UserError):
|
||||
wizard.action_payslip() # BV-Anwartschaft nicht bestätigt
|
||||
wizard.write({'vergleich_bv_betrag': 7500.0,
|
||||
'vergleich_bv_anwartschaft_bestaetigt': True})
|
||||
ergebnis = wizard.action_payslip()
|
||||
slip = self.env['hr.payslip'].browse(ergebnis['res_id'])
|
||||
|
||||
self.assertAlmostEqual(self._total(slip, 'VERGLEICH'), 9000.0,
|
||||
places=2)
|
||||
self.assertAlmostEqual(self._total(slip, 'VERGLEICH_BV'), 7500.0,
|
||||
places=2)
|
||||
self.assertEqual(
|
||||
slip.l10n_at_vergleich_nachweis,
|
||||
'Außergerichtlicher Vergleich, Ansprüche strittig')
|
||||
satz = sum(slip._l10n_at_sv_satz(
|
||||
'dn', k, staffel_basis=slip._l10n_at_sv_basis_roh())
|
||||
for k in ('kv', 'pv', 'av', 'ak', 'wf'))
|
||||
steuersatz = float(slip._l10n_at_param(
|
||||
'at_endabrechnung')['abfertigung_steuersatz'])
|
||||
self.assertAlmostEqual(
|
||||
self._total(slip, 'LST_VERGLEICH_BV'),
|
||||
7500.0 * (1.0 - satz / 100.0) * steuersatz / 100.0, places=2)
|
||||
|
||||
Reference in New Issue
Block a user