[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:
2026-09-15 12:38:19 +02:00
parent 4b86bcb790
commit 472b19a4b2
12 changed files with 660 additions and 15 deletions
@@ -4,7 +4,9 @@ Beendigungs-Abrechnung (Urlaubsersatzleistung, Abgangsentschädigung,
Zeitguthaben/-schulden, offene Vorschüsse) und legt den
Endabrechnungs-Lauf mit vorbefüllten Eingaben an. Reiner
Sammel-/Anlageprozess; die BV-Anwartschaft läuft über den eigenen
BV-Wizard (GP5), die Pfändung über die AP11-Maschine."""
BV-Wizard (GP5), die Pfändung über die AP11-Maschine.
AP15-C: Vergleichssumme (§ 67 Abs 8 lit a) — Rest (Fünftelregelung)
und BV-Anwartschafts-Teil (bis 7.500 € mit 6 %)."""
from datetime import timedelta
from dateutil.relativedelta import relativedelta
@@ -138,6 +140,49 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
help='Vordienstzeiten-Nachweis (Lohnkonto § 76 EStG), erhaltene '
'Abfertigungen, Basis-Abweichungen und Anspruchsgrundlage '
'dokumentieren.')
vergleich_aktiv = fields.Boolean(
string='Vergleich (§ 67 Abs 8 lit a)',
help='Auf gerichtlichen oder außergerichtlichen Vergleichen '
'beruhende Vergleichssummen sowie Bereinigungen/Nachzahlungen '
'aus Urteilen/Bescheiden und Zahlungen bei '
'Kündigungsanfechtung (lb-end-21). Erkennbare '
'Abfertigungsanteile werden getrennt über die Abschnitte '
'Abfertigung Alt (§ 67 Abs 3) bzw. freiwillige Abfertigung '
'(§ 67 Abs 6) erfasst; Pensionsabfindungen (lit e) und '
'Sozialplan-Zahlungen (lit f) gehören nicht hierher.')
vergleich_rest_betrag = fields.Monetary(
string='Vergleichssumme — Rest (Fünftelregelung)',
currency_field='currency_id',
help='Nach Abzug der §-62-Beiträge ist ein Fünftel steuerfrei '
'(Deckel 1/5 × 9 × monatliche HBG), 4/5 laufen tarifisch im '
'Zuflussmonat — ohne Jahressechstel-Effekt (§ 67 Abs 8 lit '
'a iVm Abs 10).')
vergleich_bv_betrag = fields.Monetary(
string='Vergleichssumme — BV-Anwartschafts-Teil',
currency_field='currency_id',
help='Anteil für Zeiträume mit BV-Kassen-Anwartschaft: bis zum '
'Deckel (2026: 7 500 €) mit 6 %, der übersteigende Teil '
'fällt in die Fünftelregelung zurück. Der Alt-/Neu-Übertritt '
'steuert die Anwendung (lb-end-21: eingefrorene Zeiträume '
'kein 6 %-Teil).')
vergleich_bv_anwartschaft_bestaetigt = fields.Boolean(
string='BV-Anwartschaft für die betroffenen Zeiträume',
help='Voraussetzung des 6-%-Teils: die Vergleichssumme wird für '
'Zeiträume ausbezahlt, für die eine Anwartschaft gegenüber '
'einer BV-Kasse besteht (§ 67 Abs 8 lit a letzter Satz).')
vergleich_aufteilung_bestaetigt = fields.Boolean(
string='Aufgliederung und Strittigkeit bestätigt',
help='Bestätigung der Aufgliederung in der Vergleichsvereinbarung '
'(Praxistipp lb-end-21): Widmungen sind abgabenrechtlich nur '
'anerkannt, wenn die Ansprüche strittig waren (lb-end-22, '
'VwGH); beim Pauschalvergleich ist der Verhältnisfaktor '
'Forderungsbetrag : Vergleichssumme zu dokumentieren '
'(E-MVB 011-02-00-001).')
vergleich_nachweis = fields.Text(
string='Nachweis/Begründung',
help='Vergleichstext, strittige Ansprüche, erkennbare '
'Abfertigungsanteile, BV-Zeiträume und allfälliger '
'Verhältnisfaktor dokumentieren.')
currency_id = fields.Many2one(
'res.currency', default=lambda self: self.env.company.currency_id)
@@ -186,6 +231,15 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
abf_frei_netto_vorschau = fields.Monetary(
string='Begünstigter Teil netto (Vorschau)',
currency_field='currency_id', compute='_compute_vorschau')
vergleich_fuenftel_frei_vorschau = fields.Monetary(
string='Steuerfreies Fünftel (Vorschau)', currency_field='currency_id',
compute='_compute_vorschau')
vergleich_tarif_basis_vorschau = fields.Monetary(
string='Fünftel-Bezüge tarifischer Teil (Vorschau)',
currency_field='currency_id', compute='_compute_vorschau')
vergleich_bv_lst_vorschau = fields.Monetary(
string='LSt 6 % BV-Teil (Vorschau)', currency_field='currency_id',
compute='_compute_vorschau')
@api.onchange('employee_id')
def _onchange_employee(self):
@@ -250,7 +304,9 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
'abf_frei_aktiv', 'abf_frei_betrag', 'abf_frei_basis_12',
'abf_frei_dienstzeit_monate',
'abf_frei_erhaltene_abfertigungen',
'abf_frei_gesetzlicher_anspruch')
'abf_frei_gesetzlicher_anspruch',
'vergleich_aktiv', 'vergleich_rest_betrag',
'vergleich_bv_betrag')
def _compute_vorschau(self):
for wizard in self:
wizard.uel_lfd_vorschau = 0.0
@@ -268,6 +324,9 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
wizard.abf_frei_ueberhang_vorschau = 0.0
wizard.abf_frei_lst_vorschau = 0.0
wizard.abf_frei_netto_vorschau = 0.0
wizard.vergleich_fuenftel_frei_vorschau = 0.0
wizard.vergleich_tarif_basis_vorschau = 0.0
wizard.vergleich_bv_lst_vorschau = 0.0
if not wizard.employee_id or not wizard.austrittsdatum:
continue
slip = wizard._vorschau_payslip()
@@ -300,6 +359,16 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
split['beguenstigt'] * satz / 100.0
wizard.abf_frei_netto_vorschau = \
split['beguenstigt'] - wizard.abf_frei_lst_vorschau
if wizard.vergleich_aktiv:
# Der tarifische Fünftel-Teil läuft über die laufende
# Bemessung (LST_LFD); die Vorschau zeigt die Pfade
# getrennt (Fünftel-Pool inkl. ABGANG, falls erfasst).
wizard.vergleich_fuenftel_frei_vorschau = \
slip._at_fuenftel_frei_betr()
wizard.vergleich_tarif_basis_vorschau = \
slip._at_fuenftel_tarif_basis()
wizard.vergleich_bv_lst_vorschau = \
slip._at_vergleich_bv_lst_6()
def _vorschau_payslip(self):
"""Flüchtiger Payslip-Kontext für die Vorschau-Berechnung (kein
@@ -335,6 +404,7 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
'l10n_at_abf_frei_gesetzlicher_anspruch':
self.abf_frei_gesetzlicher_anspruch,
'l10n_at_abf_frei_nachweis': self.abf_frei_nachweis,
'l10n_at_vergleich_nachweis': self.vergleich_nachweis,
})
eingaben = [
('ATP_UEL_TAGE', self.uel_tage),
@@ -342,6 +412,10 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
* self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0),
('ATP_ABF_FREI', self.abf_frei_betrag
if self.abf_frei_aktiv else 0.0),
('ATP_VERGLEICH', self.vergleich_rest_betrag
if self.vergleich_aktiv else 0.0),
('ATP_VERGLEICH_BV', self.vergleich_bv_betrag
if self.vergleich_aktiv else 0.0),
]
slip.input_line_ids = [
(0, 0, {
@@ -366,6 +440,10 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
* self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0),
('ATP_ABF_FREI', self.abf_frei_betrag
if self.abf_frei_aktiv else 0.0),
('ATP_VERGLEICH', self.vergleich_rest_betrag
if self.vergleich_aktiv else 0.0),
('ATP_VERGLEICH_BV', self.vergleich_bv_betrag
if self.vergleich_aktiv else 0.0),
]
def _abf_alt_validieren(self):
@@ -427,12 +505,43 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
'gesetzlicher Anspruch und Dienstzeit dürfen '
'nicht negativ sein.'))
def _vergleich_validieren(self):
self.ensure_one()
if not self.vergleich_aktiv:
return
if not self.vergleich_aufteilung_bestaetigt:
raise UserError(_('Bitte die Aufgliederung der Vergleichs-'
'summe und die Strittigkeit der Ansprüche '
'bestätigen (lb-end-21/22).'))
if self.vergleich_rest_betrag < 0 or self.vergleich_bv_betrag < 0:
raise UserError(_('Vergleichsbeträge dürfen nicht negativ '
'sein.'))
if not self.vergleich_rest_betrag and not self.vergleich_bv_betrag:
raise UserError(_('Bitte den Rest der Vergleichssumme oder '
'den BV-Anwartschafts-Teil erfassen; '
'erkennbare Abfertigungsanteile gehören in '
'die Abfertigungs-Abschnitte.'))
slip = self._vorschau_payslip()
deckel = float(slip._l10n_at_param('at_lst_67_abs8_vergleich_bv'))
if self.vergleich_bv_betrag > deckel:
raise UserError(_(
'Der BV-Anwartschafts-Teil ist mit %.2f € gedeckelt '
'(§ 67 Abs 8 lit a letzter Satz); den übersteigenden '
'Betrag als Rest (Fünftelregelung) erfassen.') % deckel)
if self.vergleich_bv_betrag > 0 \
and not self.vergleich_bv_anwartschaft_bestaetigt:
raise UserError(_('Der 6-%-Teil setzt eine bestätigte '
'BV-Anwartschaft für die betroffenen '
'Zeiträume voraus (§ 67 Abs 8 lit a letzter '
'Satz).'))
def action_payslip(self):
"""Endabrechnungs-Lauf im Austrittsmonat anlegen und die
gesammelten offenen Posten als Eingaben vorbefüllen."""
self.ensure_one()
self._abf_alt_validieren()
self._abf_frei_validieren()
self._vergleich_validieren()
erster = self.austrittsdatum.replace(day=1)
letzter = (erster + timedelta(days=32)).replace(day=1) \
- timedelta(days=1)
@@ -476,6 +585,8 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
if self.abf_frei_aktiv else 0.0,
'l10n_at_abf_frei_nachweis':
self.abf_frei_nachweis if self.abf_frei_aktiv else False,
'l10n_at_vergleich_nachweis':
self.vergleich_nachweis if self.vergleich_aktiv else False,
})
typen = {code: self.env['hr.payslip.input.type'].search(
[('code', '=', code)], limit=1)