[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
+52
View File
@@ -2,6 +2,58 @@
## Current focus
**AP15-C Vergleichssummen (§ 67 Abs 8 lit a) umgesetzt — Kern 73/73, Privat 188/188 Tests grün**
(2026-09-15, uncommittet bis Nutzerfreigabe; Privat **19.0.15.0.0**):
- **Recht (RIS-Wortlaut § 67 Abs 8 lit a verifiziert, lb-end-21/22):**
Vergleichssummen (gerichtl./außergerichtl. Vergleiche, Nachzahlungen aus
Urteilen/Bescheiden, Kündigungsanfechtung) — soweit nicht Abs 3/6: Abs-10-
Tarif im Zuflussmonat; nach §-62-Z-3/4/5-Abzug ist 1/5 steuerfrei (Deckel
1/5 × 9 × mHBG = 12.474), Abs 2 (Sechstel) nicht anzuwenden;
BV-Anwartschafts-Teil bis 7.500 € mit 6 % (parametrisiert
`at_lst_67_abs8_vergleich_bv` — § 67 Abs 8 ist §-33a/§-124b-indexiert),
Überhang fällt zurück ins Fünftel; LNK-PFLICHTIG (§ 41 Abs 4 lit b FLAG
nennt nur Abs 3/6); SV-PFLICHTIG (Zuflussmonat; Aufrollung je Beitragsmonat
via Kern-`l10n_at_beitragsmonat` bzw. PV-Verlängerung, lb-end-22/E-MVB
011-02-00-001); Widmungen nur bei Strittigkeit anerkannt (VwGH);
ausdrücklich vereinbarte gesetzl. Abfertigung → gesamt Abs 3 (VwGH
2013/13/0001 = ARD 6490/20/2016); lit e (Pensionsabfindung)/lit f
(Sozialplan) gehören NICHT zu lit a. Deckel-Reihenfolge: §-62-Abzug ERST,
dann Fünftel — das 70.000-€-Quellenbeispiel meint die Bemessungsgrundlage,
der Cap greift brutto-abhängig erst ab ~76.200 €.
- **Privat (19.0.15.0.0):** Regeln `VERGLEICH` (seq 33, neutral/lauend,
`l10n_at_s67_fuenftel`) + `VERGLEICH_BV` (seq 34, neutral/lauend, neues
Regel-Flag `l10n_at_vergleich_bv`, KEIN `s67_abs` — sonst fälschlich
LNK-frei), `LST_VERGLEICH_BV` (seq 74, 6 %); Eingaben
ATP_VERGLEICH/ATP_VERGLEICH_BV; Helfer in endabrechnung.py:
`_at_vergleich_bv_total/_beguenstigt/_ueberhang/_lst_6`,
`_at_fuenftel_frei_betr`; `_at_fuenftel_total` zieht den BV-Überhang ins
Fünftel, `_at_lnk_basis` + BV-begünstigter Teil (Pin-Kommentar
aktualisiert); Konten 6200/6000 bzw. 3540 (vorläufig wie Abf);
Wizard-Abschnitt (Bestätigungspflichten Aufgliederung/Strittigkeit +
BV-Anwartschaft, BV ≤ Deckel erzwungen, Vorschau Fünftel/Tarif/BV-LSt);
Payslip-Feld `l10n_at_vergleich_nachweis` + Tab.
- **Tests:** endabrechnung 21 (RF-VGL-1..4: Rest-Fünftel 9.000 €, BV 9.000 €
mit 7.500/1.500-Split und anteiliger Beitragszuordnung Rz 1102b, Deckel
100.000 € brutto, Wizard-E2E + 3 UserError-Fälle); Suite **205/205** (73
Kern + 188 Privat) auf Wegwerf-DB `ap15c_test5`.
- **Verifikationsreste (dokumentiert, nicht geblockt):** KZ-Positionierung
der lit-a-Tarif-Teile (laufend über LST_LFD) + §-291d-Zuordnung von
`VERGLEICH`/`VERGLEICH_BV` (wie ABGANG ohne Pfändungs-Flag) gegen LStR
Rz 1087 ff/§ 291d EO; Fünftel-Deckel-Pooling über ALLE Fünftel-Regeln
(ABGANG + VERGLEICH im selben Lauf minimal konservativ);
SV-Aufrollung aktiver Ansprüche nicht automatisiert; gesonderter
Lohnzettel bei Zahlung nach dem Beendigungsmonat (LStR Rz 911a, GP7-Rest).
- **Umgebung (wichtig für künftige Läufe):** nach dem Repo-Umzug war `.venv`
tot (editable-Pfade ohne `odoo-projects`-Komponente, Shebangs auf alten
python3.14-Pfad); repariert via sed über
`__editable___odoo_19_0_e_20260910_finder.py`, `direct_url.json` und
`.venv/bin/*`-Skripte. Aufruf `.venv/bin/python -m odoo` — im Baum fehlt
`odoo/cli/main.py`, `-m odoo` geht über `__main__.py``cli.command`;
setuptools fehlt im venv (pip install -e nicht möglich).
- **Offen:** AP14-B (Prämien-Beendigung Feinschliff), AP16 Karenz-Reste
(Gate 8.13). Nicht committen ohne Nutzeranforderung.
**AP15-B freiwillige Abfertigung (§ 67 Abs 6) umgesetzt — Kern 55/55, Privat 146/146 Tests grün**
(2026-09-15, uncommittet bis Nutzerfreigabe; Privat **19.0.14.0.0**, Kern **19.0.10.0.0**):
@@ -1,7 +1,7 @@
# Part of the odoo-at-payroll project. License: LGPL-3.
{
'name': 'Österreich - Privatwirtschaft Personalverrechnung (General-AT)',
'version': '19.0.14.0.0',
'version': '19.0.15.0.0',
'author': 'Florian Egger',
'website': 'https://gem360.at',
'category': 'Human Resources/Payroll',
@@ -39,4 +39,12 @@
<field name="name">Freiwillige Abfertigung (Brutto)</field>
<field name="code">ATP_ABF_FREI</field>
</record>
<record id="input_type_atp_vergleich" model="hr.payslip.input.type">
<field name="name">Vergleichssumme — Rest (Brutto, Fünftelregelung)</field>
<field name="code">ATP_VERGLEICH</field>
</record>
<record id="input_type_atp_vergleich_bv" model="hr.payslip.input.type">
<field name="name">Vergleichssumme — BV-Anwartschafts-Teil (Brutto)</field>
<field name="code">ATP_VERGLEICH_BV</field>
</record>
</odoo>
@@ -14,4 +14,16 @@
<field name="date_from">2026-01-01</field>
<field name="parameter_value">{'divisor_werktage': 26.0, 'divisor_arbeitstage': 22.0, 'abfertigung_alt_staffel': [[36, 2.0], [60, 3.0], [120, 4.0], [180, 6.0], [240, 9.0], [300, 12.0]], 'abfertigung_steuersatz': 6.0}</field>
</record>
<!-- AP15-C: §-67-Abs-8-lit-a-BV-Deckel; § 67 Abs 8 unterliegt der
Inflationsanpassung (§ 33a/§ 124b EStG), daher Parameter. -->
<record id="hr_rule_parameter_at_lst_67_abs8_vergleich_bv" model="hr.rule.parameter">
<field name="name">§ 67 Abs 8 lit a — Vergleich BV-Anwartschafts-Teil Deckel</field>
<field name="code">at_lst_67_abs8_vergleich_bv</field>
<field name="country_id" ref="base.at"/>
</record>
<record id="hr_rule_parameter_value_at_lst_67_abs8_vergleich_bv" model="hr.rule.parameter.value">
<field name="rule_parameter_id" ref="hr_rule_parameter_at_lst_67_abs8_vergleich_bv"/>
<field name="date_from">2026-01-01</field>
<field name="parameter_value">7500.0</field>
</record>
</odoo>
@@ -11,6 +11,10 @@
<!-- Fünftel-Override; SV-pflichtig mit Umlegung auf die -->
<!-- Kündigungsfrist; LNK-pflichtig (FLAG § 41 Abs 4 nennt nur -->
<!-- § 67 Abs 3 und 6). -->
<!-- Vergleich: § 67 Abs 8 lit a (AP15-C) — Rest über Fünftel- -->
<!-- Override, BV-Anwartschafts-Teil bis 7.500 € mit 6 %; beide -->
<!-- SV-pflichtig (Zuflussmonat; Aufrollung je Beitragsmonat bzw. -->
<!-- PV-Verlängerung siehe lb-end-22) und LNK-pflichtig. -->
<!-- ============================================================ -->
<!-- Urlaubsersatzleistung — laufender Anteil (§ 67 Abs 8 lit d). -->
@@ -130,6 +134,45 @@ result = payslip._at_abf_frei_ueberhang(result_rules)
]]></field>
</record>
<!-- Vergleichssumme — Rest (§ 67 Abs 8 lit a, Fünftelregelung). -->
<record id="rule_vergleich" model="hr.salary.rule">
<field name="name">Vergleichssumme — Rest (§ 67 Abs 8 lit a)</field>
<field name="code">VERGLEICH</field>
<field name="sequence" eval="33"/>
<field name="category_id" ref="l10n_at_hr_payroll_private.category_atp_brutto"/>
<field name="struct_id" ref="l10n_at_hr_payroll_private.structure_at_privat"/>
<field name="condition_select">python</field>
<field name="condition_python">result = 'ATP_VERGLEICH' in inputs and inputs['ATP_VERGLEICH'].amount</field>
<field name="l10n_at_bemessung">neutral</field>
<field name="l10n_at_sv_art">laufend</field>
<field name="l10n_at_s67_fuenftel" eval="True"/>
<field name="amount_select">code</field>
<field name="amount_python_compute"><![CDATA[
result = inputs['ATP_VERGLEICH'].amount
]]></field>
</record>
<!-- Vergleichssumme — BV-Anwartschafts-Teil (§ 67 Abs 8 lit a
letzter Satz): bis 7.500 € mit 6 % (LST_VERGLEICH_BV), Überhang
fällt in die Fünftelregelung zurück. Erkennbare Abfertigungs-
anteile werden getrennt als ABF_ALT/ABF_FREI erfasst. -->
<record id="rule_vergleich_bv" model="hr.salary.rule">
<field name="name">Vergleichssumme — BV-Anwartschafts-Teil (§ 67 Abs 8 lit a)</field>
<field name="code">VERGLEICH_BV</field>
<field name="sequence" eval="34"/>
<field name="category_id" ref="l10n_at_hr_payroll_private.category_atp_brutto"/>
<field name="struct_id" ref="l10n_at_hr_payroll_private.structure_at_privat"/>
<field name="condition_select">python</field>
<field name="condition_python">result = 'ATP_VERGLEICH_BV' in inputs and inputs['ATP_VERGLEICH_BV'].amount</field>
<field name="l10n_at_bemessung">neutral</field>
<field name="l10n_at_sv_art">laufend</field>
<field name="l10n_at_vergleich_bv" eval="True"/>
<field name="amount_select">code</field>
<field name="amount_python_compute"><![CDATA[
result = inputs['ATP_VERGLEICH_BV'].amount
]]></field>
</record>
<!-- Zeitguthaben an Normalarbeitszeit (§ 19e Abs 2 AZG: + 50 %). -->
<record id="rule_zeit_guthaben" model="hr.salary.rule">
<field name="name">Zeitguthaben Normalarbeitszeit + 50 % (§ 19e Abs 2 AZG)</field>
@@ -134,4 +134,19 @@ result = payslip._at_abf_alt_lohnsteuer(result_rules)
result = payslip._at_abf_frei_lst_6(result_rules)
]]></field>
</record>
<record id="rule_lst_vergleich_bv" model="hr.salary.rule">
<field name="name">Lohnsteuer Vergleich — BV-Anwartschafts-Teil (§ 67 Abs 8 lit a)</field>
<field name="code">LST_VERGLEICH_BV</field>
<field name="sequence" eval="74"/>
<field name="category_id" ref="l10n_at_hr_payroll_private.category_atp_abzug"/>
<field name="struct_id" ref="l10n_at_hr_payroll_private.structure_at_privat"/>
<field name="condition_select">python</field>
<field name="condition_python">result = payslip._at_vergleich_bv_lst_6(result_rules) > 0</field>
<field name="amount_select">code</field>
<field name="l10n_at_bemessung">neutral</field>
<field name="l10n_at_sv_art">keine</field>
<field name="amount_python_compute"><![CDATA[
result = payslip._at_vergleich_bv_lst_6(result_rules)
]]></field>
</record>
</odoo>
@@ -1,4 +1,4 @@
# Endabrechnungs-Zyklus — Rechenfälle AP14-A / AP15-A
# Endabrechnungs-Zyklus — Rechenfälle AP14-A / AP15-A / AP15-C
Stand: 2026-09. AP14-A bildet die Beendigungs-Abrechnung auf der
privaten Structure ab: Urlaubsersatzleistung (UEL), Abgangsentschädigung,
@@ -166,15 +166,84 @@ HBG), begünstigt sind also höchstens 187.110 €.
bestätigt (lückenlose Vordienstzeiten zum Lohnkonto, § 76 EStG,
keine Anspruchsumwandlung, lb-end-15).
## Offene Punkte (AP15-C und Verifikationsreste)
## RF-VGL-1 — Vergleichssumme Rest, Fünftelregelung (§ 67 Abs 8 lit a)
Außergerichtlicher Vergleich 9.000 € brutto für nachgeforderte
Mehleistungen (lb-end-21 Beispiel 1; kein erkennbarer Abfertigungs-
anteil, Ansprüche strittig):
- `VERGLEICH` (bemessung neutral, `l10n_at_s67_fuenftel`): nach Abzug
der §-62-DN-Beiträge (Beispiel: 18,07 % → 1.626,30 €) ist 1/5 der
Bemessung steuerfrei (1.474,74 €), Deckel 12.474 € (= 1/5 × 9 ×
HBG) greift hier nicht;
- 4/5 (5.898,96 € im Beispiel) laufen tarifisch im Zuflussmonat
(LST_LFD), ohne Jahressechstel-Erhöhung (Abs 2 nicht anzuwenden);
bei Zahlung Monate nach dem DV-Ende ohne weitere laufende Bezüge
ist die Bemessungsgrundlage nur der Vergleichsbetrag;
- SV-pflichtig im Zuflussmonat (Pauschalvergleich im Zweifel
beitragspflichtig, E-MVB 011-02-00-001); Ansprüche aus der aktiven
DV-Zeit sind je Beitragsmonat aufzurollen (Kern-Feld
`l10n_at_beitragsmonat`), Ansprüche nach DV-Ende verlängern die
Pflichtversicherung (lb-end-22);
- voll LNK-pflichtig (§ 41 Abs 4 lit b FLAG nennt nur Abs 3 und 6).
## RF-VGL-2 — BV-Anwartschafts-Teil (6 %, Deckel 7.500 €)
Vergleichssumme 9.000 €, davon Anteil für Zeiträume mit
BV-Kassen-Anwartschaft (lb-end-21 Beispiel 2):
- erste 7.500 € (`VERGLEICH_BV`): nach anteiligem §-62-Abzug
(83,33 % der Beiträge) mit 6 % = `LST_VERGLEICH_BV`;
- Überhang 1.500 € (16,67 % der Beiträge) fällt in die
Fünftelregelung zurück (1/5 steuerfrei, 4/5 tarifisch);
- SV und LNK zur Gänze pflichtig; Deckel parametrisiert
(`at_lst_67_abs8_vergleich_bv` — § 67 Abs 8 unterliegt der
Inflationsanpassung § 33a/§ 124b EStG);
- beim Übertritt Alt→Neu gilt der 6-%-Teil nur für übertragene
Zeiträume; eingefrorene Zeiträume laufen über die Fünftelregelung
(lb-end-21 Hinweis).
## RF-VGL-3 — Deckelfälle
- Rest mit Bemessungsgrundlage 70.000 € (lb-end-21 Deckelbeispiel;
das ist bereits die §-62-gekürzte Grundlage): Fünftel an der Grenze
12.474 € (9 × HBG/5), Rest tarifisch. Da die Engine erst den
§-62-Abzug ansetzt und DANACH das Fünftel deckelt, greift der Deckel
brutto-abhängig ab ca. 76.200 € (Testfall 100.000 € brutto);
- BV-Teil 10.000 €: begünstigt 7.500 € mit 6 %, Überhang 2.500 € in
die Fünftelregelung.
## RF-VGL-4 — Wizard, Aufteilung und Pfändung
- Erkennbare Abfertigungsanteile werden getrennt erfasst: gesetzliche
Abfertigung über den Abf-Alt-Abschnitt (§ 67 Abs 3; ausdrücklich
vereinbarte Abfertigung unterhalb der Klagsforderung → gesamt § 67
Abs 3, VwGH 2013/13/0001 = ARD 6490/20/2016), freiwillige über den
Abf-Frei-Abschnitt (§ 67 Abs 6); der Rest über den Vergleichs-
abschnitt. Widmungen sind nur anzuerkennen, wenn die Ansprüche
strittig waren (lb-end-22); beim Pauschalvergleich ist der
Verhältnisfaktor Forderung : Vergleichssumme zu dokumentieren
(E-MVB 011-02-00-001); Pensionsabfindungen (lit e) und
Sozialplan-Zahlungen (lit f) gehören nicht in lit a.
- Wizard-Bestätigungspflichten: Aufgliederung/Strittigkeit,
BV-Anwartschaft je betroffenem Zeitraum, BV-Teil ≤ Deckel (über-
steigender Betrag als Rest erfassen). Vergleichs-Nachweis landet
auf dem Lauf (Payslip-Tab) und ist für den gesonderten Lohnzettel
bei Zahlung nach dem Beendigungsmonat aufzubereiten (LStR Rz 911a,
GP7-Rest).
- `VERGLEICH`/`VERGLEICH_BV` laufen — wie `ABGANG` — NICHT über den
§-291d-Beendigungstopf (offener Verifikationspunkt, s. u.); der
Fünftel-Tarifteil ist über die laufende Bemessung pfändbar, seine
Lohnsteuer steckt in `LST_LFD`.
## Offene Punkte (Verifikationsreste)
- **Vergleich (§ 67 Abs 8 lit a)** → AP15-C mit rollierender
12-Monats-Basis und Alt-/Neu-Aufteilung (freiwillige Abfertigung
§ 67 Abs 6 ist mit AP15-B umgesetzt).
- KZ-Positionierung der Abs-6-Bezüge (außerhalb KZ 210/220, LSt in
KZ 260 — GP3-Konvention wie Abs 3) und die Zuordnung des Z-6-Überhangs
zum §-291d-EO-Topf sind gegen LStR Rz 1087 ff / § 291d EO zu
verifizieren, bevor der MVP freigegeben wird.
verifizieren, bevor der MVP freigegeben wird. Dasselbe gilt für die
KZ-Positionierung der lit-a-Tarif-Teile (laufend über LST_LFD) und
die §-291d-Zuordnung von `VERGLEICH`/`VERGLEICH_BV`.
- Geminderte Bezüge in der 12-Monats-Basis: die LStR-Rückrechnungs-
praxis (zwölf Monate voller Bezüge) widerspricht dem VwGH
(Krankengeld 6/7 einbeziehen) — bewusst ohne Automatik, Basis ist
@@ -70,6 +70,7 @@ L10N_AT_BUCHUNGSMATRIX = {
'rule_lst_sz': {'credit': ('3540',)},
'rule_lst_abf': {'credit': ('3540',)},
'rule_lst_abf_frei': {'credit': ('3540',)},
'rule_lst_vergleich_bv': {'credit': ('3540',)},
# Gesetzliche Abfertigung Alt: bis zur Referenzbuchhaltungs-
# Fixierung allgemeiner Gehalts-/Lohnaufwand, company-dependent
# Regelkonto bleibt übersteuerbar.
@@ -78,6 +79,10 @@ L10N_AT_BUCHUNGSMATRIX = {
# tarifischer Überhang — gleiche vorläufige Aufwandskonten.
'rule_abf_frei': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
'rule_abf_frei_tarif': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
# Vergleichssumme (§ 67 Abs 8 lit a): Rest und BV-Anwartschafts-
# Teil — gleiche vorläufige Aufwandskonten wie die Abfertigungen.
'rule_vergleich': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
'rule_vergleich_bv': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
# Nettoauszahlung (reconcilable, s. o.)
'rule_netto': {'credit': ('3850',)},
# DG-Beiträge (650655 SV Arbeiter · 656659 SV Angestellte)
@@ -2,6 +2,7 @@
"""AP14-A: Endabrechnungs-Zyklus — Urlaubsersatzleistung (UEL),
Abgangsentschädigung (§ 67 Abs 8 lit b), Aufrechnung offener Vorschüsse
und Zeitguthaben/-schulden (§ 19e AZG).
AP15-C: Vergleichssummen (§ 67 Abs 8 lit a).
Am Originalwortlaut verifiziert (.ris/, Stand 2026-09-14):
- § 11 Abs 2 ASVG: die Pflichtversicherung besteht für die Zeit des
@@ -25,6 +26,21 @@ Am Originalwortlaut verifiziert (.ris/, Stand 2026-09-14):
- § 19e Abs 2 AZG: Guthaben an Normalarbeitszeit + 50 % Zuschlag
(Entfall bei unberechtigtem vorzeitigem Austritt; KV kann
abweichend regeln).
- § 67 Abs 8 lit a EStG (AP15-C, Stand 2026-09-15): Vergleichssummen
sind, SOWEIT sie nicht nach Abs 3, 6 oder dem letzten Satz mit dem
festen Steuersatz zu versteuern sind, nach Abs 10 im Kalendermonat
der Zahlung zu erfassen; nach Abzug der §-62-Z-3/4/5-Beiträge ist
ein Fünftel steuerfrei (Deckel ein Fünftel des Neunfachen der
monatlichen HBG), Abs 2 (Sechstel) ist nicht anzuwenden. Erkennbare
Abfertigungsanteile laufen getrennt über Abs 3 (VwGH
2013/13/0001 = ARD 6490/20/2016: ausdrücklich vereinbarte
gesetzliche Abfertigung → gesamt Abs 3) bzw. Abs 6. Fallen die
Vergleichssummen bei oder nach Beendigung an UND betreffen sie
Zeiträume mit BV-Kassen-Anwartschaft, sind sie bis 7 500 € mit 6 %
zu versteuern (parametrisiert, §-33a-Indexkette); der übersteigende
Teil fällt in die Fünftelregelung zurück. SV-Aufrollung aktiver
Ansprüche je Beitragsmonat bzw. PV-Verlängerung: lb-end-22
(E-MVB 011-02-00-001), Kern-Mechanismus l10n_at_beitragsmonat.
"""
from datetime import timedelta
@@ -53,6 +69,13 @@ class HrSalaryRule(models.Model):
'(Deckel: ein Fünftel des Neunfachen der monatlichen HBG), '
'der Rest läuft tarifisch im Zuflussmonat — ohne '
'Jahressechstel-Erhöhung (Abs 2 nicht anzuwenden).')
l10n_at_vergleich_bv = fields.Boolean(
string='AT § 67 Abs 8 lit a — BV-Anwartschafts-Teil',
help='Teil einer Vergleichssumme, der bei oder nach Beendigung '
'für Zeiträume mit BV-Kassen-Anwartschaft ausbezahlt wird: '
'bis zum Deckel (at_lst_67_abs8_vergleich_bv, 2026: 7 500 €) '
'mit 6 %, der übersteigende Teil fällt in die '
'Fünftelregelung zurück. SV-pflichtig und LNK-pflichtig.')
l10n_at_s26_z4_reise = fields.Boolean(
string='AT § 26 Z 4 Reisevergütung',
help='§-26-Z-4-Reisevergütungen zählen nicht in die '
@@ -115,6 +138,13 @@ class HrPayslip(models.Model):
l10n_at_abf_frei_nachweis = fields.Text(
string='AT Freiwillige Abfertigung — Nachweis/Begründung',
copy=False)
l10n_at_vergleich_nachweis = fields.Text(
string='AT Vergleich — Nachweis/Begründung', copy=False,
help='Aufgliederung der Vergleichsvereinbarung (lb-end-21): '
'strittige Ansprüche, erkennbare Abfertigungsanteile, '
'BV-Anwartschafts-Zeiträume; beim Pauschalvergleich der '
'Verhältnisfaktor Forderungsbetrag : Vergleichssumme '
'(E-MVB 011-02-00-001).')
# ------------------------------------------------------------------
# SV-Tage-Umrechnung und Verlängerungsmonate (§ 11 Abs 2 ASVG)
@@ -401,6 +431,9 @@ class HrPayslip(models.Model):
else:
linie = self.line_ids.filtered(lambda l: l.code == rule.code)
total += sum(linie.mapped('total'))
# § 67 Abs 8 lit a: der über den BV-6-%-Deckel hinausgehende
# Teil der Vergleichssumme fällt in die Fünftelregelung zurück.
total += self._at_vergleich_bv_ueberhang(result_rules)
return total
def _at_fuenftel_tarif_basis(self, result_rules=None):
@@ -425,6 +458,77 @@ class HrPayslip(models.Model):
frei = min(bemessung / 5.0, deckel)
return bemessung - frei
# ------------------------------------------------------------------
# Vergleichssumme — § 67 Abs 8 lit a (Rest, BV-Anwartschafts-Teil)
# ------------------------------------------------------------------
def _at_vergleich_bv_total(self, result_rules=None):
"""Summe der als BV-Anwartschafts-Teil gekennzeichneten
Vergleichs-Zeilen (Zeiträume mit BV-Kassen-Anwartschaft,
§ 67 Abs 8 lit a letzter Satz)."""
self.ensure_one()
total = 0.0
for rule in self.struct_id.rule_ids:
if not rule.l10n_at_vergleich_bv:
continue
if result_rules is not None:
if rule.code in result_rules:
total += result_rules[rule.code]['total']
else:
total += sum(self.line_ids.filtered(
lambda l, c=rule.code: l.code == c).mapped('total'))
return total
def _at_vergleich_bv_beguenstigt(self, result_rules=None):
"""Bis zum Deckel (2026: 7 500 €) begünstigter Teil — 6 %-Fahrspur
(parametrisiert: § 67 Abs 8 unterliegt der Inflationsanpassung
§ 33a/§ 124b EStG)."""
self.ensure_one()
deckel = float(self._l10n_at_param('at_lst_67_abs8_vergleich_bv'))
return min(self._at_vergleich_bv_total(result_rules), deckel)
def _at_vergleich_bv_ueberhang(self, result_rules=None):
"""Über den BV-Deckel hinausgehender Teil — fällt in die
Fünftelregelung zurück (erster Satz des lit a)."""
self.ensure_one()
deckel = float(self._l10n_at_param('at_lst_67_abs8_vergleich_bv'))
return max(self._at_vergleich_bv_total(result_rules) - deckel, 0.0)
def _at_vergleich_bv_lst_6(self, result_rules=None):
"""6 % auf den begünstigten BV-Teil nach anteiligem §-62-Abzug
(LStR Rz 1102b: die SV-Beiträge sind den Teilbeträgen
anteilsmäßig zuzuordnen — approximiert über den effektiven
DN-Satz der laufenden Basis, wie im Fünftelpfad)."""
self.ensure_one()
beguenstigt = self._at_vergleich_bv_beguenstigt(result_rules)
if beguenstigt <= 0:
return 0.0
satz = sum(self._l10n_at_sv_satz(
'dn', komponente,
staffel_basis=self._l10n_at_sv_basis_roh(result_rules))
for komponente in ('kv', 'pv', 'av', 'ak', 'wf'))
bemessung = beguenstigt * (1.0 - satz / 100.0)
steuersatz = float(self._l10n_at_param(
'at_endabrechnung')['abfertigung_steuersatz'])
return bemessung * steuersatz / 100.0
def _at_fuenftel_frei_betr(self, result_rules=None):
"""Steuerfreies Fünftel der Fünftel-Bezüge (inkl. BV-Überhang),
gedeckelt mit einem Fünftel des Neunfachen der monatlichen HBG
(lb-end-21: 2026 6.930 × 9/5 = 12.474) — getrennt vom
tarifischen Rest für die Wizard-Vorschau."""
self.ensure_one()
total = self._at_fuenftel_total(result_rules)
if total <= 0:
return 0.0
satz = sum(self._l10n_at_sv_satz(
'dn', komponente,
staffel_basis=self._l10n_at_sv_basis_roh(result_rules))
for komponente in ('kv', 'pv', 'av', 'ak', 'wf'))
bemessung = max(total * (1.0 - satz / 100.0), 0.0)
deckel = float(self._l10n_at_param('at_sv_hbg_monatlich')) \
* 9.0 / 5.0
return min(bemessung / 5.0, deckel)
# ------------------------------------------------------------------
# Engine-Anbindung: Tarif-Teil ohne Sechstel, LNK-Pflicht, SV-Umlegung
# ------------------------------------------------------------------
@@ -438,11 +542,12 @@ class HrPayslip(models.Model):
def _at_lnk_basis(self, steuer, result_rules=None):
"""Upstream-Überschreibung (Muster account_posting_private;
Vorlage payslip_private._at_lnk_basis — bei Änderungen dort
gegen diesen Pin neu abgleichen): Kündigungsentschädigungen
sind Arbeitslöhne iSd § 41 Abs 3 FLAG und unterliegen NICHT
den Abs-4-Ausschlüssen (lit b nennt nur § 67 Abs 3 und 6) —
sie sind VOR der Freibetragsstaffel in die LNK-Basis
aufzunehmen."""
gegen diesen Pin neu abgleichen): Kündigungsentschädigungen und
Vergleichssummen sind Arbeitslöhne iSd § 41 Abs 3 FLAG und
unterliegen NICHT den Abs-4-Ausschlüssen (lit b nennt nur
§ 67 Abs 3 und 6 — der lit-a-BV-Teil ist ebenfalls nicht
ausgenommen) — sie sind VOR der Freibetragsstaffel in die
LNK-Basis aufzunehmen."""
self.ensure_one()
basis = (self._l10n_at_brutto('laufend', result_rules)
+ self._l10n_at_brutto('sonstig', result_rules)
@@ -457,6 +562,10 @@ class HrPayslip(models.Model):
lambda l: l.code == rule.code)
basis -= sum(linie.mapped('total'))
basis += self._at_fuenftel_total(result_rules)
# BV-Anwartschafts-Teil: begünstigter ≤-Deckel-Teil hier, der
# Überhang läuft bereits über _at_fuenftel_total — zusammen
# die volle Vergleichssumme, LNK-pflichtig (lb-end-20).
basis += self._at_vergleich_bv_beguenstigt(result_rules)
basis = max(basis, 0.0)
if steuer in ('flaf', 'dz'):
version = self.version_id
@@ -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)
@@ -65,6 +65,22 @@
<field name="abf_frei_netto_vorschau"/>
</group>
</group>
<group string="Vergleichssumme (§ 67 Abs 8 lit a EStG)">
<field name="vergleich_aktiv"/>
<group invisible="not vergleich_aktiv">
<field name="vergleich_rest_betrag"/>
<field name="vergleich_bv_betrag"/>
<field name="vergleich_bv_anwartschaft_bestaetigt"
invisible="not vergleich_bv_betrag"/>
<field name="vergleich_nachweis" placeholder="Aufgliederung der Vergleichsvereinbarung, strittige Ansprüche, BV-Zeiträume, Pauschalvergleich: Verhältnisfaktor"/>
<field name="vergleich_aufteilung_bestaetigt"/>
</group>
<group invisible="not vergleich_aktiv">
<field name="vergleich_fuenftel_frei_vorschau"/>
<field name="vergleich_tarif_basis_vorschau"/>
<field name="vergleich_bv_lst_vorschau"/>
</group>
</group>
<group string="Vorschau (§ 10 UrlG, § 11 Abs 2 ASVG)">
<group>
<field name="uel_lfd_vorschau"/>
@@ -135,6 +151,24 @@
</field>
</record>
<record id="hr_payslip_view_form_vergleich" model="ir.ui.view">
<field name="name">hr.payslip.form.vergleich</field>
<field name="model">hr.payslip</field>
<field name="inherit_id" ref="hr_payroll.view_hr_payslip_form"/>
<field name="arch" type="xml">
<xpath expr="//notebook" position="inside">
<page string="Vergleich (§ 67 Abs 8 lit a)"
name="l10n_at_vergleich"
invisible="not l10n_at_vergleich_nachweis">
<group>
<field name="l10n_at_vergleich_nachweis"
readonly="state != 'draft'"/>
</group>
</page>
</xpath>
</field>
</record>
<record id="action_endabrechnung_wizard" model="ir.actions.act_window">
<field name="name">Endabrechnung (Beendigung)</field>
<field name="res_model">l10n.at.payroll.endabrechnung.wizard</field>
@@ -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)