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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user