[IMP] l10n_at_hr_payroll_private: add voluntary severance under § 67 Abs 6 (AP15-B)
Split the voluntary severance into its privileged part and a tariff remainder on the exit run: the privileged part combines the quarter rule (1/4 of the last twelve months' running pay, capped at nine times the monthly HBG) with the twelfth rule (2/12 to 12/12 by proven service, capped at n × 3 × HBG), reduced per Z 3 by severance already received and the statutory claim due at this termination, all taxed at the flat 6 % rate. The excess runs as its own rule flagged l10n_at_s67_abs6_ueberhang: taxed with the running tariff of the payment month but excluded from the annual sixth, since Z 5 exempts only the Z 1/Z 2 amounts and the excess is a special payment, not running pay. The twelve-month basis aggregates validated prior runs plus own lines, excluding the flagged excess and § 26 Z 4 travel overhang via a dedicated rule flag. Free of SV (§ 49 Abs 3 Z 7 ASVG), payroll levies regardless of the 6 %/tarif split (§ 41 Abs 4 lit b FLAG, § 122 Abs 8 WKG, § 5 Abs 2 lit b KommStG) and BV contributions; the former BV-Anwartschaft exclusion Z 7 is repealed (BGBl I 118/2015). The wizard proposes the rolling basis and the statutory claim, previews Z 1/Z 2/reduction/privileged/excess/tax and requires explicit confirmation against claim-conversion risk. The § 291d EO termination pot nets both severance wage-tax rules; key 260 now includes LST_ABF_FREI. Verified against the original statute text in .ris/ (EStG § 67 Abs 6) and the knowledge-base sources lb-end-12/13/15; KZ positioning of Abs-6 amounts and the excess's § 291d pot allocation remain documented verification points against LStR Rz 1087 ff. Version 19.0.14.0.0 (private), 19.0.10.0.0 (core)
This commit is contained in:
+46
-1
@@ -2,8 +2,53 @@
|
|||||||
|
|
||||||
## Current focus
|
## Current focus
|
||||||
|
|
||||||
|
**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**):
|
||||||
|
|
||||||
|
- **Recht (RIS-Wortlaut § 67 Abs 6 verifiziert, lb-end-12/13/15):**
|
||||||
|
Z 1 Viertelregelung (¼ der letzten-12-Monats-Bezüge, Deckel 9×HBG)
|
||||||
|
+ Z 2 Zwölftelregelung (Staffel 3→2/12 … 25→12/12 = §-23-Grenzen,
|
||||||
|
Deckel n × 3 × HBG), Z 3 Kürzung um erhaltene Abfertigungen (Abs 3
|
||||||
|
ODER 6) und bestehenden gesetzlichen Anspruch am aktuellen Ende,
|
||||||
|
Z 5 Sechstel-Exklusion nur für die 6 %-Beträge, Z 6 Überhang
|
||||||
|
„wie ein laufender Bezug“ zum Zuflussmonat-Tarif, Z 7 (BV-Ausschluss)
|
||||||
|
seit BGBl I 118/2015 AUFGEHOBEN. SV-frei § 49 Abs 3 Z 7, LNK-frei
|
||||||
|
(§ 41 Abs 4 lit b FLAG, § 122 Abs 8 WKG, § 5 Abs 2 lit b KommStG)
|
||||||
|
UNABHÄNGIG von 6 % vs Tarif, BV-frei (§ 6 Abs 5 BMSVG).
|
||||||
|
- **Kern (19.0.10.0.0):** neuer Regel-Flag `l10n_at_s67_abs6_ueberhang`
|
||||||
|
(lohnsteuer.py); `_l10n_at_brutto_laufen_ytd` zieht Flag-Regeln aus
|
||||||
|
der Sechstel-Basis ab (Helfer `_l10n_at_abs6_ueberhang_total`, auch
|
||||||
|
je YTD-Lauf) — der Überhang läuft über bemessung='laufend' in die
|
||||||
|
laufende LSt-Bemessung und KZ 210, aber NICHT ins Sechstel;
|
||||||
|
`LST_ABF_FREI` in KZ-260-Salden. Test test_20 + L16-Test erweitert.
|
||||||
|
- **Privat:** Regeln `ABF_FREI` (seq 31, neutral/keine/abs6/
|
||||||
|
pfandung_beendigung — begünstigter Teil), `ABF_FREI_TARIF` (seq 32,
|
||||||
|
laufend/keine/abs6 + Überhang-Flag — Tarifrest), `LST_ABF_FREI`
|
||||||
|
(seq 73, 6 %); Eingabe ATP_ABF_FREI; Helfer in endabrechnung.py:
|
||||||
|
`_at_bezuege_12_monate` (validierte Vormonats-Läufe + eigene Zeilen,
|
||||||
|
ohne Überhang-/§-26-Z-4-Regeln — neues privates Regel-Flag
|
||||||
|
`l10n_at_s26_z4_reise` an REISE_STEUERPFLICHTIG), `_at_abf_frei_split`
|
||||||
|
(Z 1/Z 2/Deckel aus at_sv_hbg_monatlich/Z-3-Kürzung),
|
||||||
|
`_at_abf_frei_lst_6`. Wizard-Abschnitt mit auto 12-Monats-Basis +
|
||||||
|
gesetzlicher Anspruch aus ABF_ALT, Vorschau Z 1/Z 2/Kürzung/
|
||||||
|
begünstigt/Überhang/6 %/Netto, Bestätigungspflicht (Anspruchs-
|
||||||
|
umwandlungs-Hinweis lb-end-15). Pfändungs-Beendigungstopf zieht
|
||||||
|
LST_ABF + LST_ABF_FREI ab (test_09c). Konten: rule_abf_frei(_tarif)
|
||||||
|
6200/6000 vorläufig, rule_lst_abf_frei 3540. RF-ABF-4…6 + offene
|
||||||
|
Punkte in docs/rechenfaelle/endabrechnung.md.
|
||||||
|
- **Tests:** endabrechnung 17 (Z 1/Z 2, Überhang ohne Sechstel mit
|
||||||
|
SV/LNK/BV/LST_LFD-Asserts, Kürzung+Deckel, Wizard-E2E), pfändung 13,
|
||||||
|
Kern-Suite 55/55, Privat-Suite 146/146 (ap13a_test); ein Testfehler
|
||||||
|
(zweite `_input`-Eingabezeile statt Update) korrigiert.
|
||||||
|
- **Verifikationsreste (dokumentiert, nicht geblockt):** KZ-Positionierung
|
||||||
|
der Abs-6-Bezüge und §-291d-Zuordnung des Überhangs gegen LStR
|
||||||
|
Rz 1087 ff; geminderte Bezüge in der 12-Monats-Basis (LStR vs VwGH)
|
||||||
|
bewusst ohne Automatik.
|
||||||
|
- **Offen:** AP15-C (§ 67 Abs 8 lit a Vergleichssummen). Nicht
|
||||||
|
committen ohne Nutzeranforderung.
|
||||||
|
|
||||||
**AP15-A gesetzliche Abfertigung Alt umgesetzt — Privat 141/141, Kern 54/54 Tests grün**
|
**AP15-A gesetzliche Abfertigung Alt umgesetzt — Privat 141/141, Kern 54/54 Tests grün**
|
||||||
(2026-09-15, uncommittet bis Nutzerfreigabe; Privat **19.0.13.0.0**, Kern **19.0.9.0.0**):
|
(2026-09-15, Commit **`9add58f`** nach Nutzerfreigabe):
|
||||||
|
|
||||||
- **Recht am Originalwortlaut verifiziert (.ris/):** § 23a Abs 3 AngG
|
- **Recht am Originalwortlaut verifiziert (.ris/):** § 23a Abs 3 AngG
|
||||||
verlangt für den Elternaustritt ein **ununterbrochen fünfjähriges**
|
verlangt für den Elternaustritt ein **ununterbrochen fünfjähriges**
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Part of the odoo-at-payroll project. License: LGPL-3.
|
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||||||
{
|
{
|
||||||
'name': 'Österreich - Personalverrechnung Kern (AT Payroll Core)',
|
'name': 'Österreich - Personalverrechnung Kern (AT Payroll Core)',
|
||||||
'version': '19.0.9.0.0',
|
'version': '19.0.10.0.0',
|
||||||
'author': 'Florian Egger',
|
'author': 'Florian Egger',
|
||||||
'website': 'https://gem360.at',
|
'website': 'https://gem360.at',
|
||||||
'category': 'Human Resources/Payroll',
|
'category': 'Human Resources/Payroll',
|
||||||
|
|||||||
@@ -70,6 +70,15 @@ class HrSalaryRule(models.Model):
|
|||||||
'abgezogen; Grenzen als Jahres-Kumulative je Dienstnehmer '
|
'abgezogen; Grenzen als Jahres-Kumulative je Dienstnehmer '
|
||||||
'(at_st_grenzen). Nur der übersteigende Teil ist '
|
'(at_st_grenzen). Nur der übersteigende Teil ist '
|
||||||
'steuerpflichtig. Menge = Arbeitstage (Z 17/Z 9).')
|
'steuerpflichtig. Menge = Arbeitstage (Z 17/Z 9).')
|
||||||
|
l10n_at_s67_abs6_ueberhang = fields.Boolean(
|
||||||
|
string='AT § 67 Abs 6 Z 6 — Überhang',
|
||||||
|
help='Übersteigender Teil einer freiwilligen Abfertigung/Abfindung '
|
||||||
|
'(§ 67 Abs 6 Z 6 EStG): wird wie ein laufender Bezug zum '
|
||||||
|
'Tarif des Zuflussmonats versteuert, erhöht aber das '
|
||||||
|
'Jahressechstel nicht — Abs 2 ist nur auf die mit 6 % '
|
||||||
|
'versteuerten Z-1/Z-2-Beträge nicht anzuwendbar (Z 5), der '
|
||||||
|
'Überhang ist ein sonstiger Bezug, kein laufender. LNK-frei '
|
||||||
|
'über § 67 Abs 6 (lb-end-12), SV-frei über § 49 Abs 3 Z 7.')
|
||||||
|
|
||||||
|
|
||||||
class HrVersion(models.Model):
|
class HrVersion(models.Model):
|
||||||
@@ -351,11 +360,32 @@ class HrPayslip(models.Model):
|
|||||||
|
|
||||||
def _l10n_at_brutto_laufen_ytd(self, result_rules=None):
|
def _l10n_at_brutto_laufen_ytd(self, result_rules=None):
|
||||||
"""Kumulierte laufende Bruttobezüge des Jahres (Sechstel-Basis
|
"""Kumulierte laufende Bruttobezüge des Jahres (Sechstel-Basis
|
||||||
ist Brutto, § 67 Abs 2 — inkl. Auszahlungsmonat-Laufendem)."""
|
ist Brutto, § 67 Abs 2 — inkl. Auszahlungsmonat-Laufendem).
|
||||||
|
Der §-67-Abs-6-Überhang (Flag) läuft tarifisch im Zuflussmonat,
|
||||||
|
ist aber ein sonstiger Bezug und erhöht das Jahressechstel
|
||||||
|
nicht."""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
total = self._l10n_at_brutto('laufend', result_rules)
|
total = self._l10n_at_brutto('laufend', result_rules) \
|
||||||
|
- self._l10n_at_abs6_ueberhang_total(result_rules)
|
||||||
for slip in self._l10n_at_ytd_slaeufe():
|
for slip in self._l10n_at_ytd_slaeufe():
|
||||||
total += slip._l10n_at_brutto('laufend')
|
total += slip._l10n_at_brutto('laufend') \
|
||||||
|
- slip._l10n_at_abs6_ueberhang_total()
|
||||||
|
return total
|
||||||
|
|
||||||
|
def _l10n_at_abs6_ueberhang_total(self, result_rules=None):
|
||||||
|
"""Summe der als §-67-Abs-6-Z-6-Überhang gekennzeichneten
|
||||||
|
Regel-Zeilen (tarifisch im Zuflussmonat, ohne Sechstel-Effekt)."""
|
||||||
|
self.ensure_one()
|
||||||
|
total = 0.0
|
||||||
|
for rule in self.struct_id.rule_ids:
|
||||||
|
if not rule.l10n_at_s67_abs6_ueberhang:
|
||||||
|
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
|
return total
|
||||||
|
|
||||||
def _l10n_at_sechstel(self, result_rules=None):
|
def _l10n_at_sechstel(self, result_rules=None):
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ class L10nAtPayrollL16Line(models.Model):
|
|||||||
GP3-Kerns (Monats-Caps 400/600 und ÜStd 15/170 eingerechnet);
|
GP3-Kerns (Monats-Caps 400/600 und ÜStd 15/170 eingerechnet);
|
||||||
220 = sonstige § 67 Abs 1/2/5 ohne Abs-3/6; 225 = SV-DN auf
|
220 = sonstige § 67 Abs 1/2/5 ohne Abs-3/6; 225 = SV-DN auf
|
||||||
KZ 220; 230 = laufende SV-DN + AK + WF; VIEB = 230 + 225 +
|
KZ 220; 230 = laufende SV-DN + AK + WF; VIEB = 230 + 225 +
|
||||||
226; 260/BIEL = LST_LFD + LST_SZ + LST_ABF."""
|
226; 260/BIEL = LST_LFD + LST_SZ + LST_ABF + LST_ABF_FREI."""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
salden = dict.fromkeys(
|
salden = dict.fromkeys(
|
||||||
('kz210', 'kz215', 'kz220', 'kz225', 'kz226', 'kz230',
|
('kz210', 'kz215', 'kz220', 'kz225', 'kz226', 'kz230',
|
||||||
@@ -411,7 +411,8 @@ class L10nAtPayrollL16Line(models.Model):
|
|||||||
elif line.code in ('SVDN_KV', 'SVDN_PV', 'SVDN_AV',
|
elif line.code in ('SVDN_KV', 'SVDN_PV', 'SVDN_AV',
|
||||||
'SVDN_AK', 'SVDN_WF'):
|
'SVDN_AK', 'SVDN_WF'):
|
||||||
salden['kz230'] += line.total
|
salden['kz230'] += line.total
|
||||||
elif line.code in ('LST_LFD', 'LST_SZ', 'LST_ABF'):
|
elif line.code in ('LST_LFD', 'LST_SZ', 'LST_ABF',
|
||||||
|
'LST_ABF_FREI'):
|
||||||
salden['lohnsteuer'] += line.total
|
salden['lohnsteuer'] += line.total
|
||||||
freibe = slip._l10n_at_freibetraege_68()
|
freibe = slip._l10n_at_freibetraege_68()
|
||||||
salden['kz215'] += freibe['szfn'] + freibe['ue_std']
|
salden['kz215'] += freibe['szfn'] + freibe['ue_std']
|
||||||
|
|||||||
@@ -235,6 +235,9 @@ class L16GeneratorTest(TransactionCase):
|
|||||||
salary_rule_id=abs3_rule, code='ABF_ALT', total=12000.0),
|
salary_rule_id=abs3_rule, code='ABF_ALT', total=12000.0),
|
||||||
types.SimpleNamespace(
|
types.SimpleNamespace(
|
||||||
salary_rule_id=lst_rule, code='LST_ABF', total=720.0),
|
salary_rule_id=lst_rule, code='LST_ABF', total=720.0),
|
||||||
|
types.SimpleNamespace(
|
||||||
|
salary_rule_id=lst_rule, code='LST_ABF_FREI',
|
||||||
|
total=300.0),
|
||||||
],
|
],
|
||||||
_l10n_at_freibetraege_68=lambda: {'szfn': 0.0, 'ue_std': 0.0},
|
_l10n_at_freibetraege_68=lambda: {'szfn': 0.0, 'ue_std': 0.0},
|
||||||
)
|
)
|
||||||
@@ -243,7 +246,7 @@ class L16GeneratorTest(TransactionCase):
|
|||||||
|
|
||||||
self.assertEqual(salden['kz210'], 0.0)
|
self.assertEqual(salden['kz210'], 0.0)
|
||||||
self.assertEqual(salden['kz220'], 0.0)
|
self.assertEqual(salden['kz220'], 0.0)
|
||||||
self.assertEqual(salden['lohnsteuer'], 720.0)
|
self.assertEqual(salden['lohnsteuer'], 1020.0)
|
||||||
|
|
||||||
def test_02_arbeitsstaette(self):
|
def test_02_arbeitsstaette(self):
|
||||||
"""§ 34 Abs 6 ASVG: je AN ein Satz 45 (Länge 300) mit BKNR,
|
"""§ 34 Abs 6 ASVG: je AN ein Satz 45 (Länge 300) mit BKNR,
|
||||||
|
|||||||
@@ -125,6 +125,27 @@ class LohnsteuerTest(TransactionCase):
|
|||||||
'contract_date_end': date(2026, 1, 10)})
|
'contract_date_end': date(2026, 1, 10)})
|
||||||
self.assertEqual(slip._l10n_at_lohnsteuertage(), 10)
|
self.assertEqual(slip._l10n_at_lohnsteuertage(), 10)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# § 67 Abs 6 Z 6 — Überhang (tarifisch, ohne Sechstel-Effekt)
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
def test_20_abs6_ueberhang_ohne_sechstel(self):
|
||||||
|
"""Der gekennzeichnete Überhang läuft tarifisch in der laufenden
|
||||||
|
Bemessung, erhöht aber das Jahressechstel nicht."""
|
||||||
|
employee = self._employee()
|
||||||
|
slip_ohne = self._slip(employee, 1)
|
||||||
|
regel = self._regel('T_ABS6_UEB', 1000.0, sv_art='keine')
|
||||||
|
regel.l10n_at_s67_abs6_ueberhang = True
|
||||||
|
slip_mit = self._slip(employee, 2)
|
||||||
|
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._l10n_at_abs6_ueberhang_total(), 1000.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._l10n_at_bemessung_laufen()
|
||||||
|
- slip_ohne._l10n_at_bemessung_laufen(), 1000.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._l10n_at_sechstel() - slip_ohne._l10n_at_sechstel(),
|
||||||
|
0.0, places=2)
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# § 68 Freibeträge (Buckets über Regel-Flags)
|
# § 68 Freibeträge (Buckets über Regel-Flags)
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Part of the odoo-at-payroll project. License: LGPL-3.
|
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||||||
{
|
{
|
||||||
'name': 'Österreich - Privatwirtschaft Personalverrechnung (General-AT)',
|
'name': 'Österreich - Privatwirtschaft Personalverrechnung (General-AT)',
|
||||||
'version': '19.0.13.0.0',
|
'version': '19.0.14.0.0',
|
||||||
'author': 'Florian Egger',
|
'author': 'Florian Egger',
|
||||||
'website': 'https://gem360.at',
|
'website': 'https://gem360.at',
|
||||||
'category': 'Human Resources/Payroll',
|
'category': 'Human Resources/Payroll',
|
||||||
|
|||||||
@@ -35,4 +35,8 @@
|
|||||||
<field name="name">Gesetzliche Abfertigung Alt (Brutto)</field>
|
<field name="name">Gesetzliche Abfertigung Alt (Brutto)</field>
|
||||||
<field name="code">ATP_ABF_ALT</field>
|
<field name="code">ATP_ABF_ALT</field>
|
||||||
</record>
|
</record>
|
||||||
|
<record id="input_type_atp_abf_frei" model="hr.payslip.input.type">
|
||||||
|
<field name="name">Freiwillige Abfertigung (Brutto)</field>
|
||||||
|
<field name="code">ATP_ABF_FREI</field>
|
||||||
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -91,6 +91,45 @@ result = inputs['ATP_ABF_ALT'].amount
|
|||||||
]]></field>
|
]]></field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- Freiwillige Abfertigung (§ 67 Abs 6 EStG): begünstigter Teil
|
||||||
|
(Viertel-/Zwölftelregelung mit 6 %) und tarifischer Überhang
|
||||||
|
(Z 6) als getrennte Zeilen. -->
|
||||||
|
<record id="rule_abf_frei" model="hr.salary.rule">
|
||||||
|
<field name="name">Freiwillige Abfertigung — begünstigter Teil (§ 67 Abs 6)</field>
|
||||||
|
<field name="code">ABF_FREI</field>
|
||||||
|
<field name="sequence" eval="31"/>
|
||||||
|
<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_ABF_FREI' in inputs and inputs['ATP_ABF_FREI'].amount</field>
|
||||||
|
<field name="l10n_at_bemessung">neutral</field>
|
||||||
|
<field name="l10n_at_sv_art">keine</field>
|
||||||
|
<field name="l10n_at_s67_abs">abs6</field>
|
||||||
|
<field name="l10n_at_pfandung_beendigung" eval="True"/>
|
||||||
|
<field name="amount_select">code</field>
|
||||||
|
<field name="amount_python_compute"><![CDATA[
|
||||||
|
result = payslip._at_abf_frei_beguenstigt(result_rules)
|
||||||
|
]]></field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="rule_abf_frei_tarif" model="hr.salary.rule">
|
||||||
|
<field name="name">Freiwillige Abfertigung — Überhang (§ 67 Abs 6 Z 6)</field>
|
||||||
|
<field name="code">ABF_FREI_TARIF</field>
|
||||||
|
<field name="sequence" eval="32"/>
|
||||||
|
<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 = payslip._at_abf_frei_ueberhang(result_rules) > 0</field>
|
||||||
|
<field name="l10n_at_bemessung">laufend</field>
|
||||||
|
<field name="l10n_at_sv_art">keine</field>
|
||||||
|
<field name="l10n_at_s67_abs">abs6</field>
|
||||||
|
<field name="l10n_at_s67_abs6_ueberhang" eval="True"/>
|
||||||
|
<field name="amount_select">code</field>
|
||||||
|
<field name="amount_python_compute"><![CDATA[
|
||||||
|
result = payslip._at_abf_frei_ueberhang(result_rules)
|
||||||
|
]]></field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<!-- Zeitguthaben an Normalarbeitszeit (§ 19e Abs 2 AZG: + 50 %). -->
|
<!-- Zeitguthaben an Normalarbeitszeit (§ 19e Abs 2 AZG: + 50 %). -->
|
||||||
<record id="rule_zeit_guthaben" model="hr.salary.rule">
|
<record id="rule_zeit_guthaben" model="hr.salary.rule">
|
||||||
<field name="name">Zeitguthaben Normalarbeitszeit + 50 % (§ 19e Abs 2 AZG)</field>
|
<field name="name">Zeitguthaben Normalarbeitszeit + 50 % (§ 19e Abs 2 AZG)</field>
|
||||||
|
|||||||
@@ -119,4 +119,19 @@ result = payslip._l10n_at_lst_sonstige(result_rules)
|
|||||||
result = payslip._at_abf_alt_lohnsteuer(result_rules)
|
result = payslip._at_abf_alt_lohnsteuer(result_rules)
|
||||||
]]></field>
|
]]></field>
|
||||||
</record>
|
</record>
|
||||||
|
<record id="rule_lst_abf_frei" model="hr.salary.rule">
|
||||||
|
<field name="name">Lohnsteuer freiwillige Abfertigung (§ 67 Abs 6)</field>
|
||||||
|
<field name="code">LST_ABF_FREI</field>
|
||||||
|
<field name="sequence" eval="73"/>
|
||||||
|
<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_abf_frei_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_abf_frei_lst_6(result_rules)
|
||||||
|
]]></field>
|
||||||
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -33,6 +33,7 @@ result = inputs['EXPENSES'].amount
|
|||||||
<field name="condition_select">python</field>
|
<field name="condition_select">python</field>
|
||||||
<field name="condition_python">result = 'ATP_REISE_STEUERPFLICHTIG' in inputs and inputs['ATP_REISE_STEUERPFLICHTIG'].amount</field>
|
<field name="condition_python">result = 'ATP_REISE_STEUERPFLICHTIG' in inputs and inputs['ATP_REISE_STEUERPFLICHTIG'].amount</field>
|
||||||
<field name="l10n_at_bemessung">laufend</field>
|
<field name="l10n_at_bemessung">laufend</field>
|
||||||
|
<field name="l10n_at_s26_z4_reise" eval="True"/>
|
||||||
<field name="amount_select">code</field>
|
<field name="amount_select">code</field>
|
||||||
<field name="amount_python_compute"><![CDATA[
|
<field name="amount_python_compute"><![CDATA[
|
||||||
result = inputs['ATP_REISE_STEUERPFLICHTIG'].amount
|
result = inputs['ATP_REISE_STEUERPFLICHTIG'].amount
|
||||||
|
|||||||
@@ -123,11 +123,62 @@ Durchschnittsbezügen, Lehrzeiten, Teilübertritten und §-23a-Sonderfällen
|
|||||||
müssen Anspruch, Basis und Nachweis vor Anlage des Laufs bestätigt werden.
|
müssen Anspruch, Basis und Nachweis vor Anlage des Laufs bestätigt werden.
|
||||||
Die geprüften Angaben werden am Payslip gespeichert.
|
Die geprüften Angaben werden am Payslip gespeichert.
|
||||||
|
|
||||||
## Offene Punkte (AP15-B/AP15-C)
|
## RF-ABF-4 — Freiwillige Abfertigung, Viertel-/Zwölftelregelung
|
||||||
|
|
||||||
- **Vergleich (§ 67 Abs 8 lit a)** und **freiwillige Abfertigung/
|
15 nachgewiesene Dienstjahre (6/12), 12-Monats-Basis 36.000 € (alle
|
||||||
Abfindung (§ 67 Abs 6 6 %-Bänder)** → AP15-B/C mit rollierender
|
steuerbaren Bezugsteile inklusive steuerfreier Zuschläge und Sachbezüge,
|
||||||
12-Monats-Basis, Dienstzeit-Nachweisen und Alt-/Neu-Aufteilung.
|
ohne Sonderzahlungen und ohne §-26-Z-4-Reisevergütungen), Brutto
|
||||||
|
40.000 €:
|
||||||
|
|
||||||
|
- Z 1 Viertelregelung: 36.000 / 4 = **9.000 €** (Deckel 9 × HBG =
|
||||||
|
62.370 € nicht greifend);
|
||||||
|
- Z 2 Zwölftelregelung: 36.000 × 6/12 = **18.000 €** (Deckel
|
||||||
|
6 × 3 × HBG = 124.740 € nicht greifend);
|
||||||
|
- begünstigter Teil: min(40.000, 9.000 + 18.000) = **27.000 €** mit
|
||||||
|
6 % = **1.620 €** Lohnsteuer (`ABF_FREI`/`LST_ABF_FREI`);
|
||||||
|
- Überhang **13.000 €** als `ABF_FREI_TARIF`: tarifisch in der
|
||||||
|
LSt-Bemessung des Zuflussmonats (LST_LFD), ohne Jahressechstel-Erhöhung
|
||||||
|
(Kern-Flag `l10n_at_s67_abs6_ueberhang`);
|
||||||
|
- SV-frei (§ 49 Abs 3 Z 7 ASVG), LNK-frei unabhängig von der
|
||||||
|
Besteuerungsart (§ 41 Abs 4 lit b FLAG, § 122 Abs 8 WKG,
|
||||||
|
§ 5 Abs 2 lit b KommStG), BV-frei (§ 6 Abs 5 BMSVG); Z 7 (BV-
|
||||||
|
Anwartschafts-Ausschluss) ist seit BGBl I 118/2015 aufgehoben.
|
||||||
|
|
||||||
|
## RF-ABF-5 — Z-3-Kürzung und Deckel
|
||||||
|
|
||||||
|
4.000 € bereits erhaltene Abfertigungen plus 9.000 € gesetzlicher
|
||||||
|
Anspruch am aktuellen Ende kürzen das Z-2-Ausmaß von 18.000 € auf
|
||||||
|
5.000 €; begünstigt sind 9.000 + 5.000 = 14.000 € von 20.000 € Brutto,
|
||||||
|
der Rest läuft zum Tarif. Bei einer 12-Monats-Basis von 12.000.000 €
|
||||||
|
begrenzen die Deckel auf 62.370 € (Z 1) plus 124.740 € (Z 2, 6 × 3 ×
|
||||||
|
HBG), begünstigt sind also höchstens 187.110 €.
|
||||||
|
|
||||||
|
## RF-ABF-6 — Pfändung und Wizard
|
||||||
|
|
||||||
|
- `ABF_FREI` (begünstigter Teil) läuft über den §-291d-Beendigungstopf,
|
||||||
|
vermindert um `LST_ABF` und `LST_ABF_FREI`; der Überhang
|
||||||
|
(`ABF_FREI_TARIF`) bleibt über die laufende Bemessung pfändbar, seine
|
||||||
|
Lohnsteuer steckt bereits in `LST_LFD`.
|
||||||
|
- Der Wizard schlägt die 12-Monats-Basis aus den letzten zwölf
|
||||||
|
validierten Läufen vor (ohne Überhang- und Reise-Regeln, geminderte
|
||||||
|
Bezüge nicht automatisch zurückgerechnet) und den gesetzlichen
|
||||||
|
Anspruch aus der Alt-Abfertigung; Prüfung und Nachweise werden
|
||||||
|
bestätigt (lückenlose Vordienstzeiten zum Lohnkonto, § 76 EStG,
|
||||||
|
keine Anspruchsumwandlung, lb-end-15).
|
||||||
|
|
||||||
|
## Offene Punkte (AP15-C und 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.
|
||||||
|
- 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
|
||||||
|
bestätigbar (lb-end-13 ⚠).
|
||||||
- Prämien-Beendigung (§ 16 AngG-Aliquotierung, Rollung) — PRAM/SZ-Regeln
|
- Prämien-Beendigung (§ 16 AngG-Aliquotierung, Rollung) — PRAM/SZ-Regeln
|
||||||
vorhanden; Feinschliff AP14-B.
|
vorhanden; Feinschliff AP14-B.
|
||||||
- Meldewesen-Schnittstellen: „Ende des Entgeltanspruches" in mBGM/
|
- Meldewesen-Schnittstellen: „Ende des Entgeltanspruches" in mBGM/
|
||||||
|
|||||||
@@ -69,10 +69,15 @@ L10N_AT_BUCHUNGSMATRIX = {
|
|||||||
'rule_lst_lfd': {'credit': ('3540',)},
|
'rule_lst_lfd': {'credit': ('3540',)},
|
||||||
'rule_lst_sz': {'credit': ('3540',)},
|
'rule_lst_sz': {'credit': ('3540',)},
|
||||||
'rule_lst_abf': {'credit': ('3540',)},
|
'rule_lst_abf': {'credit': ('3540',)},
|
||||||
|
'rule_lst_abf_frei': {'credit': ('3540',)},
|
||||||
# Gesetzliche Abfertigung Alt: bis zur Referenzbuchhaltungs-
|
# Gesetzliche Abfertigung Alt: bis zur Referenzbuchhaltungs-
|
||||||
# Fixierung allgemeiner Gehalts-/Lohnaufwand, company-dependent
|
# Fixierung allgemeiner Gehalts-/Lohnaufwand, company-dependent
|
||||||
# Regelkonto bleibt übersteuerbar.
|
# Regelkonto bleibt übersteuerbar.
|
||||||
'rule_abf_alt': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
|
'rule_abf_alt': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
|
||||||
|
# Freiwillige Abfertigung (§ 67 Abs 6): begünstigter Teil und
|
||||||
|
# tarifischer Überhang — gleiche vorläufige Aufwandskonten.
|
||||||
|
'rule_abf_frei': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
|
||||||
|
'rule_abf_frei_tarif': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
|
||||||
# Nettoauszahlung (reconcilable, s. o.)
|
# Nettoauszahlung (reconcilable, s. o.)
|
||||||
'rule_netto': {'credit': ('3850',)},
|
'rule_netto': {'credit': ('3850',)},
|
||||||
# DG-Beiträge (650–655 SV Arbeiter · 656–659 SV Angestellte)
|
# DG-Beiträge (650–655 SV Arbeiter · 656–659 SV Angestellte)
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ Am Originalwortlaut verifiziert (.ris/, Stand 2026-09-14):
|
|||||||
"""
|
"""
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
from odoo import fields, models
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
@@ -51,6 +53,11 @@ class HrSalaryRule(models.Model):
|
|||||||
'(Deckel: ein Fünftel des Neunfachen der monatlichen HBG), '
|
'(Deckel: ein Fünftel des Neunfachen der monatlichen HBG), '
|
||||||
'der Rest läuft tarifisch im Zuflussmonat — ohne '
|
'der Rest läuft tarifisch im Zuflussmonat — ohne '
|
||||||
'Jahressechstel-Erhöhung (Abs 2 nicht anzuwenden).')
|
'Jahressechstel-Erhöhung (Abs 2 nicht anzuwenden).')
|
||||||
|
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 '
|
||||||
|
'12-Monats-Basis der §-67-Abs-6-Begünstigung (lb-end-13); '
|
||||||
|
'Sonderzahlungen sind ohnehin nicht bemessung „laufend“.')
|
||||||
|
|
||||||
|
|
||||||
class HrPayslip(models.Model):
|
class HrPayslip(models.Model):
|
||||||
@@ -83,6 +90,31 @@ class HrPayslip(models.Model):
|
|||||||
string='AT Abfertigung Alt — Anspruchsfaktor', copy=False)
|
string='AT Abfertigung Alt — Anspruchsfaktor', copy=False)
|
||||||
l10n_at_abf_alt_nachweis = fields.Text(
|
l10n_at_abf_alt_nachweis = fields.Text(
|
||||||
string='AT Abfertigung Alt — Nachweis/Begründung', copy=False)
|
string='AT Abfertigung Alt — Nachweis/Begründung', copy=False)
|
||||||
|
l10n_at_abf_frei_basis_12 = fields.Float(
|
||||||
|
string='AT Freiwillige Abfertigung — 12-Monats-Basis', copy=False,
|
||||||
|
help='Laufende Bezüge der letzten zwölf Monate (§ 67 Abs 6 Z 1/2 '
|
||||||
|
'EStG): vom Wizard bestätigt — alle steuerbaren Bezugsteile '
|
||||||
|
'inklusive steuerfreier Zuschläge und Sachbezüge, ohne '
|
||||||
|
'Sonderzahlungen und ohne §-26-Z-4-Reisevergütungen; keine '
|
||||||
|
'Bezüge anderer Arbeitgeber, keine Hochrechnung kurzer DV.')
|
||||||
|
l10n_at_abf_frei_dienstzeit_monate = fields.Integer(
|
||||||
|
string='AT Freiwillige Abfertigung — nachgewiesene Dienstzeit '
|
||||||
|
'(Monate)', copy=False)
|
||||||
|
l10n_at_abf_frei_erhaltene_abfertigungen = fields.Float(
|
||||||
|
string='AT Freiwillige Abfertigung — erhaltene Abfertigungen',
|
||||||
|
copy=False,
|
||||||
|
help='Während der nachgewiesenen Dienstzeit bereits erhaltene '
|
||||||
|
'Abfertigungen nach § 67 Abs 3 oder Abs 6 EStG — kürzen das '
|
||||||
|
'Z-2-Ausmaß (§ 67 Abs 6 Z 3).')
|
||||||
|
l10n_at_abf_frei_gesetzlicher_anspruch = fields.Float(
|
||||||
|
string='AT Freiwillige Abfertigung — bestehender gesetzlicher '
|
||||||
|
'Anspruch', copy=False,
|
||||||
|
help='Bestehender Anspruch auf eine gesetzliche Abfertigung am '
|
||||||
|
'aktuellen Dienstverhältnis-Ende (§ 67 Abs 6 Z 3 EStG) — '
|
||||||
|
'kürzt das Z-2-Ausmaß.')
|
||||||
|
l10n_at_abf_frei_nachweis = fields.Text(
|
||||||
|
string='AT Freiwillige Abfertigung — Nachweis/Begründung',
|
||||||
|
copy=False)
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# SV-Tage-Umrechnung und Verlängerungsmonate (§ 11 Abs 2 ASVG)
|
# SV-Tage-Umrechnung und Verlängerungsmonate (§ 11 Abs 2 ASVG)
|
||||||
@@ -232,6 +264,87 @@ class HrPayslip(models.Model):
|
|||||||
return min(self._at_abf_alt_steuer_vervielfachung(result_rules),
|
return min(self._at_abf_alt_steuer_vervielfachung(result_rules),
|
||||||
self._at_abf_alt_steuer_6(result_rules))
|
self._at_abf_alt_steuer_6(result_rules))
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Freiwillige Abfertigung — § 67 Abs 6 EStG (Viertel-/Zwölftelregelung)
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
def _at_bezuege_12_monate(self):
|
||||||
|
"""Laufende Bezüge der letzten zwölf Monate (§ 67 Abs 6 Z 1/2):
|
||||||
|
validierte Vormonats-Läufe plus eigene Zeilen — ohne den als
|
||||||
|
Abs-6-Überhang gekennzeichneten Betrag (das ist ein sonstiger
|
||||||
|
Bezug, kein laufender) und ohne §-26-Z-4-Reisevergütungen;
|
||||||
|
Sonderzahlungen sind ohnehin nicht bemessung „laufend“
|
||||||
|
(lb-end-13)."""
|
||||||
|
self.ensure_one()
|
||||||
|
start = (self.date_from - relativedelta(months=11)).replace(day=1)
|
||||||
|
vor_slips = self.env['hr.payslip'].search([
|
||||||
|
('employee_id', '=', self.employee_id.id),
|
||||||
|
('id', '!=', self.id),
|
||||||
|
('date_from', '>=', start),
|
||||||
|
('date_from', '<', self.date_from.replace(day=1)),
|
||||||
|
]).filtered(lambda p: p.state not in ('draft', 'cancel'))
|
||||||
|
total = 0.0
|
||||||
|
for slip in list(vor_slips) + [self]:
|
||||||
|
for line in slip.line_ids:
|
||||||
|
rule = line.salary_rule_id
|
||||||
|
if rule.l10n_at_bemessung != 'laufend':
|
||||||
|
continue
|
||||||
|
if (rule.l10n_at_s67_abs6_ueberhang
|
||||||
|
or rule.l10n_at_s26_z4_reise):
|
||||||
|
continue
|
||||||
|
total += line.total
|
||||||
|
return total
|
||||||
|
|
||||||
|
def _at_abf_frei_zwoelftel(self):
|
||||||
|
"""Zwölftel-Anzahl nach § 67 Abs 6 Z 2: die Dienstzeitstaffel
|
||||||
|
entspricht den §-23-Grenzen (36→2/12 … 300→12/12)."""
|
||||||
|
self.ensure_one()
|
||||||
|
return self._at_abf_alt_staffel(
|
||||||
|
self.l10n_at_abf_frei_dienstzeit_monate)
|
||||||
|
|
||||||
|
def _at_abf_frei_split(self, result_rules=None):
|
||||||
|
"""§ 67 Abs 6: begünstigter Teil (Viertel- und Zwölftelregelung,
|
||||||
|
gedeckelt 9 × bzw. n × 3 × monatliche HBG, Z-3-Kürzung um
|
||||||
|
erhaltene Abfertigungen und den bestehenden gesetzlichen
|
||||||
|
Anspruch) und der tarifische Überhang (Z 6)."""
|
||||||
|
self.ensure_one()
|
||||||
|
brutto = max(self._at_input_amount('ATP_ABF_FREI'), 0.0)
|
||||||
|
basis = self.l10n_at_abf_frei_basis_12
|
||||||
|
if basis <= 0:
|
||||||
|
basis = self._at_bezuege_12_monate()
|
||||||
|
basis = max(basis, 0.0)
|
||||||
|
hbg = float(self._l10n_at_param('at_sv_hbg_monatlich'))
|
||||||
|
z1 = min(basis / 4.0, 9.0 * hbg)
|
||||||
|
zwoelftel = self._at_abf_frei_zwoelftel()
|
||||||
|
z2 = min(basis * zwoelftel / 12.0, zwoelftel * 3.0 * hbg)
|
||||||
|
kuerzung = max(
|
||||||
|
self.l10n_at_abf_frei_erhaltene_abfertigungen
|
||||||
|
+ self.l10n_at_abf_frei_gesetzlicher_anspruch, 0.0)
|
||||||
|
z2 = max(z2 - kuerzung, 0.0)
|
||||||
|
beguenstigt = min(brutto, z1 + z2)
|
||||||
|
return {
|
||||||
|
'basis': basis,
|
||||||
|
'z1': z1,
|
||||||
|
'z2': z2,
|
||||||
|
'kuerzung': kuerzung,
|
||||||
|
'beguenstigt': beguenstigt,
|
||||||
|
'ueberhang': brutto - beguenstigt,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _at_abf_frei_beguenstigt(self, result_rules=None):
|
||||||
|
self.ensure_one()
|
||||||
|
return self._at_abf_frei_split(result_rules)['beguenstigt']
|
||||||
|
|
||||||
|
def _at_abf_frei_ueberhang(self, result_rules=None):
|
||||||
|
self.ensure_one()
|
||||||
|
return self._at_abf_frei_split(result_rules)['ueberhang']
|
||||||
|
|
||||||
|
def _at_abf_frei_lst_6(self, result_rules=None):
|
||||||
|
"""6 % auf den begünstigten Teil (§ 67 Abs 6, fester Steuersatz)."""
|
||||||
|
self.ensure_one()
|
||||||
|
satz = float(self._l10n_at_param(
|
||||||
|
'at_endabrechnung')['abfertigung_steuersatz'])
|
||||||
|
return self._at_abf_frei_beguenstigt(result_rules) * satz / 100.0
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# Urlaubsersatzleistung — § 67 Abs 8 lit d, lb-url-15/16
|
# Urlaubsersatzleistung — § 67 Abs 8 lit d, lb-url-15/16
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
@@ -386,7 +386,8 @@ class HrPayslip(models.Model):
|
|||||||
linie = self.line_ids.filtered(
|
linie = self.line_ids.filtered(
|
||||||
lambda l, c=rule.code: l.code == c)
|
lambda l, c=rule.code: l.code == c)
|
||||||
total += sum(linie.mapped('total'))
|
total += sum(linie.mapped('total'))
|
||||||
steuer = self._at_pfa_rule_amount(result_rules, 'LST_ABF')
|
steuer = sum(self._at_pfa_rule_amount(result_rules, c)
|
||||||
|
for c in ('LST_ABF', 'LST_ABF_FREI'))
|
||||||
return round(max(0.0, total - steuer), 2)
|
return round(max(0.0, total - steuer), 2)
|
||||||
raise UserError('Unbekannter Pfändungstopf: %s' % topf)
|
raise UserError('Unbekannter Pfändungstopf: %s' % topf)
|
||||||
|
|
||||||
|
|||||||
@@ -479,3 +479,135 @@ class EndabrechnungPrivateTest(TransactionCase):
|
|||||||
})
|
})
|
||||||
with self.assertRaises(UserError):
|
with self.assertRaises(UserError):
|
||||||
wizard.action_payslip()
|
wizard.action_payslip()
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# AP15-B: freiwillige Abfertigung (§ 67 Abs 6)
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
def test_14_abf_frei_viertel_und_zwoelftel(self):
|
||||||
|
"""15 Jahre (6/12), Basis 36.000: Z 1 9.000 + Z 2 18.000; Brutto
|
||||||
|
12.000 → voll begünstigt, 6 % = 720; kein Überhang."""
|
||||||
|
emp = self._employee()
|
||||||
|
slip = self._slip(emp)
|
||||||
|
slip.write({
|
||||||
|
'l10n_at_abf_frei_basis_12': 36000.0,
|
||||||
|
'l10n_at_abf_frei_dienstzeit_monate': 180,
|
||||||
|
})
|
||||||
|
self._input(slip, 'ATP_ABF_FREI', 12000.0)
|
||||||
|
|
||||||
|
split = slip._at_abf_frei_split()
|
||||||
|
self.assertAlmostEqual(split['z1'], 9000.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['z2'], 18000.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['beguenstigt'], 12000.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['ueberhang'], 0.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
self._total(slip, 'ABF_FREI'), 12000.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
self._total(slip, 'LST_ABF_FREI'), 720.0, places=2)
|
||||||
|
self.assertFalse(self._total(slip, 'ABF_FREI_TARIF'))
|
||||||
|
|
||||||
|
def test_15_abf_frei_ueberhang_tarif_ohne_sechstel(self):
|
||||||
|
"""Brutto 40.000: begünstigt 27.000 (Z 1 + Z 2), Überhang 13.000
|
||||||
|
läuft tarifisch über die LSt-Bemessung, ohne das Jahressechstel
|
||||||
|
zu erhöhen; SV, LNK und BV bleiben unberührt."""
|
||||||
|
emp_mit = self._employee()
|
||||||
|
emp_ohne = self._employee()
|
||||||
|
slip_mit = self._slip(emp_mit)
|
||||||
|
slip_ohne = self._slip(emp_ohne)
|
||||||
|
slip_mit.write({
|
||||||
|
'l10n_at_abf_frei_basis_12': 36000.0,
|
||||||
|
'l10n_at_abf_frei_dienstzeit_monate': 180,
|
||||||
|
})
|
||||||
|
self._input(slip_mit, 'ATP_ABF_FREI', 40000.0)
|
||||||
|
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
self._total(slip_mit, 'ABF_FREI'), 27000.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
self._total(slip_mit, 'ABF_FREI_TARIF'), 13000.0, places=2)
|
||||||
|
lst6 = self.env.company.currency_id.round(27000.0 * 0.06)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
self._total(slip_mit, 'LST_ABF_FREI'), lst6, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._l10n_at_bemessung_laufen()
|
||||||
|
- slip_ohne._l10n_at_bemessung_laufen(), 13000.0, places=2)
|
||||||
|
self.assertGreater(
|
||||||
|
self._total(slip_mit, 'LST_LFD'), self._total(slip_ohne, 'LST_LFD'))
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._l10n_at_sechstel() - slip_ohne._l10n_at_sechstel(),
|
||||||
|
0.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._l10n_at_sv_basis_roh()
|
||||||
|
- slip_ohne._l10n_at_sv_basis_roh(), 0.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._at_lnk_basis('flaf')
|
||||||
|
- slip_ohne._at_lnk_basis('flaf'), 0.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._at_bv_basis_sonst()
|
||||||
|
- slip_ohne._at_bv_basis_sonst(), 0.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip_mit._at_pfaendung_basis(None, 'beendigung'),
|
||||||
|
27000.0 - lst6, places=2)
|
||||||
|
|
||||||
|
def test_16_abf_frei_kuerzung_und_deckel(self):
|
||||||
|
"""Z 3: erhaltene Abfertigungen plus gesetzlicher Anspruch kürzen
|
||||||
|
das Z-2-Ausmaß; bei großer Basis greifen die Deckel 9 × HBG
|
||||||
|
(Z 1) und n × 3 × HBG (Z 2)."""
|
||||||
|
emp = self._employee()
|
||||||
|
slip = self._slip(emp)
|
||||||
|
slip.write({
|
||||||
|
'l10n_at_abf_frei_basis_12': 36000.0,
|
||||||
|
'l10n_at_abf_frei_dienstzeit_monate': 180,
|
||||||
|
'l10n_at_abf_frei_erhaltene_abfertigungen': 4000.0,
|
||||||
|
'l10n_at_abf_frei_gesetzlicher_anspruch': 9000.0,
|
||||||
|
})
|
||||||
|
self._input(slip, 'ATP_ABF_FREI', 20000.0)
|
||||||
|
|
||||||
|
split = slip._at_abf_frei_split()
|
||||||
|
self.assertAlmostEqual(split['kuerzung'], 13000.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['z2'], 5000.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['beguenstigt'], 14000.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['ueberhang'], 6000.0, places=2)
|
||||||
|
|
||||||
|
slip.write({
|
||||||
|
'l10n_at_abf_frei_basis_12': 12000000.0,
|
||||||
|
'l10n_at_abf_frei_erhaltene_abfertigungen': 0.0,
|
||||||
|
'l10n_at_abf_frei_gesetzlicher_anspruch': 0.0,
|
||||||
|
})
|
||||||
|
slip.input_line_ids.filtered(
|
||||||
|
lambda i: i.input_type_id.code == 'ATP_ABF_FREI').write(
|
||||||
|
{'amount': 300000.0})
|
||||||
|
slip.compute_sheet()
|
||||||
|
split = slip._at_abf_frei_split()
|
||||||
|
self.assertAlmostEqual(split['z1'], 62370.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['z2'], 124740.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['beguenstigt'], 187110.0, places=2)
|
||||||
|
self.assertAlmostEqual(split['ueberhang'], 112890.0, places=2)
|
||||||
|
|
||||||
|
def test_17_abf_frei_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,
|
||||||
|
})
|
||||||
|
wizard = self.env['l10n.at.payroll.endabrechnung.wizard'].create({
|
||||||
|
'employee_id': emp.id,
|
||||||
|
'austrittsdatum': date(2026, 3, 15),
|
||||||
|
'departure_reason_id': self.env.ref(
|
||||||
|
'l10n_at_hr_payroll.departure_reason_einvernehmlich').id,
|
||||||
|
'abf_frei_aktiv': True,
|
||||||
|
'abf_frei_anspruch_bestaetigt': True,
|
||||||
|
'abf_frei_betrag': 20000.0,
|
||||||
|
'abf_frei_basis_12': 36000.0,
|
||||||
|
'abf_frei_dienstzeit_monate': 180,
|
||||||
|
'abf_frei_nachweis': 'Vordienstzeiten zum Lohnkonto nachgewiesen',
|
||||||
|
})
|
||||||
|
ergebnis = wizard.action_payslip()
|
||||||
|
slip = self.env['hr.payslip'].browse(ergebnis['res_id'])
|
||||||
|
|
||||||
|
self.assertAlmostEqual(self._total(slip, 'ABF_FREI'), 20000.0,
|
||||||
|
places=2)
|
||||||
|
self.assertAlmostEqual(self._total(slip, 'LST_ABF_FREI'), 1200.0,
|
||||||
|
places=2)
|
||||||
|
self.assertEqual(slip.l10n_at_abf_frei_dienstzeit_monate, 180)
|
||||||
|
self.assertEqual(slip.l10n_at_abf_frei_nachweis,
|
||||||
|
'Vordienstzeiten zum Lohnkonto nachgewiesen')
|
||||||
|
|||||||
@@ -209,6 +209,35 @@ class PfaendungPrivateTest(TransactionCase):
|
|||||||
self.assertAlmostEqual(
|
self.assertAlmostEqual(
|
||||||
self._total(slip, 'PFAENDUNG_END'), masse, places=2)
|
self._total(slip, 'PFAENDUNG_END'), masse, places=2)
|
||||||
|
|
||||||
|
def test_09c_pfaendung_abf_frei_topf(self):
|
||||||
|
"""AP15-B: begünstigter Teil der freiwilligen Abfertigung läuft
|
||||||
|
in den §-291d-Topf, abzüglich beider Abfertigungs-LSt-Arten; der
|
||||||
|
Überhang bleibt über die laufende Bemessung pfändbar."""
|
||||||
|
employee = self._employee(datetime.date(2020, 1, 1), unterhalt=0)
|
||||||
|
self._pfaendung(employee, datetime.date(2026, 2, 1))
|
||||||
|
slip = self._slip(employee, 3)
|
||||||
|
slip.write({
|
||||||
|
'l10n_at_abf_frei_basis_12': 36000.0,
|
||||||
|
'l10n_at_abf_frei_dienstzeit_monate': 180,
|
||||||
|
})
|
||||||
|
input_type = self.env.ref(
|
||||||
|
'l10n_at_hr_payroll_private.input_type_atp_abf_frei')
|
||||||
|
self.env['hr.payslip.input'].create({
|
||||||
|
'payslip_id': slip.id,
|
||||||
|
'input_type_id': input_type.id,
|
||||||
|
'amount': 40000.0,
|
||||||
|
})
|
||||||
|
slip.compute_sheet()
|
||||||
|
|
||||||
|
lst6 = self.env.company.currency_id.round(27000.0 * 0.06)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
self._total(slip, 'ABF_FREI'), 27000.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
self._total(slip, 'ABF_FREI_TARIF'), 13000.0, places=2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
slip._at_pfaendung_basis(None, 'beendigung'),
|
||||||
|
27000.0 - lst6, places=2)
|
||||||
|
|
||||||
def test_10_rang(self):
|
def test_10_rang(self):
|
||||||
"""Zwei Pfändungen → Rang 1 (früheres Einlangen) und Rang 2."""
|
"""Zwei Pfändungen → Rang 1 (früheres Einlangen) und Rang 2."""
|
||||||
employee = self._employee(datetime.date(2026, 1, 1))
|
employee = self._employee(datetime.date(2026, 1, 1))
|
||||||
|
|||||||
@@ -44,6 +44,27 @@
|
|||||||
<field name="abf_alt_netto_vorschau"/>
|
<field name="abf_alt_netto_vorschau"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
<group string="Freiwillige Abfertigung (§ 67 Abs 6 EStG)">
|
||||||
|
<field name="abf_frei_aktiv"/>
|
||||||
|
<group invisible="not abf_frei_aktiv">
|
||||||
|
<field name="abf_frei_betrag"/>
|
||||||
|
<field name="abf_frei_basis_12"/>
|
||||||
|
<field name="abf_frei_dienstzeit_monate"/>
|
||||||
|
<field name="abf_frei_erhaltene_abfertigungen"/>
|
||||||
|
<field name="abf_frei_gesetzlicher_anspruch"/>
|
||||||
|
<field name="abf_frei_nachweis" placeholder="Vordienstzeiten zum Lohnkonto (§ 76 EStG), erhaltene Abfertigungen, keine Anspruchsumwandlung"/>
|
||||||
|
<field name="abf_frei_anspruch_bestaetigt"/>
|
||||||
|
</group>
|
||||||
|
<group invisible="not abf_frei_aktiv">
|
||||||
|
<field name="abf_frei_z1_vorschau"/>
|
||||||
|
<field name="abf_frei_z2_vorschau"/>
|
||||||
|
<field name="abf_frei_kuerzung_vorschau"/>
|
||||||
|
<field name="abf_frei_beguenstigt_vorschau"/>
|
||||||
|
<field name="abf_frei_ueberhang_vorschau"/>
|
||||||
|
<field name="abf_frei_lst_vorschau"/>
|
||||||
|
<field name="abf_frei_netto_vorschau"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
<group string="Vorschau (§ 10 UrlG, § 11 Abs 2 ASVG)">
|
<group string="Vorschau (§ 10 UrlG, § 11 Abs 2 ASVG)">
|
||||||
<group>
|
<group>
|
||||||
<field name="uel_lfd_vorschau"/>
|
<field name="uel_lfd_vorschau"/>
|
||||||
@@ -90,6 +111,30 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="hr_payslip_view_form_abf_frei" model="ir.ui.view">
|
||||||
|
<field name="name">hr.payslip.form.abfertigung.frei</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="Freiwillige Abfertigung" name="l10n_at_abfertigung_frei"
|
||||||
|
invisible="not l10n_at_abf_frei_basis_12 and not l10n_at_abf_frei_dienstzeit_monate and not l10n_at_abf_frei_erhaltene_abfertigungen and not l10n_at_abf_frei_gesetzlicher_anspruch">
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="l10n_at_abf_frei_basis_12" readonly="state != 'draft'"/>
|
||||||
|
<field name="l10n_at_abf_frei_dienstzeit_monate" readonly="state != 'draft'"/>
|
||||||
|
<field name="l10n_at_abf_frei_erhaltene_abfertigungen" readonly="state != 'draft'"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="l10n_at_abf_frei_gesetzlicher_anspruch" readonly="state != 'draft'"/>
|
||||||
|
<field name="l10n_at_abf_frei_nachweis" readonly="state != 'draft'"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</page>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<record id="action_endabrechnung_wizard" model="ir.actions.act_window">
|
<record id="action_endabrechnung_wizard" model="ir.actions.act_window">
|
||||||
<field name="name">Endabrechnung (Beendigung)</field>
|
<field name="name">Endabrechnung (Beendigung)</field>
|
||||||
<field name="res_model">l10n.at.payroll.endabrechnung.wizard</field>
|
<field name="res_model">l10n.at.payroll.endabrechnung.wizard</field>
|
||||||
|
|||||||
@@ -101,6 +101,43 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
string='Nachweis/Begründung',
|
string='Nachweis/Begründung',
|
||||||
help='Quelle der Dienstzeiten, Anspruchsprüfung, Alt-/Neu-Status '
|
help='Quelle der Dienstzeiten, Anspruchsprüfung, Alt-/Neu-Status '
|
||||||
'und allfällige manuelle Abweichung dokumentieren.')
|
'und allfällige manuelle Abweichung dokumentieren.')
|
||||||
|
abf_frei_aktiv = fields.Boolean(
|
||||||
|
string='Freiwillige Abfertigung (§ 67 Abs 6)')
|
||||||
|
abf_frei_anspruch_bestaetigt = fields.Boolean(
|
||||||
|
string='Prüfung und Nachweise bestätigt',
|
||||||
|
help='Bestätigung, dass es sich um eine Beendigungsleistung ohne '
|
||||||
|
'schädliche Anspruchsumwandlung handelt (KE/UE/SZ/Zeitguthaben '
|
||||||
|
'müssen getrennt abrechnet werden — GPLB-Risiko, lb-end-15), '
|
||||||
|
'dass die (Vor-)Dienstzeiten lückenlos zum Lohnkonto '
|
||||||
|
'(§ 76 EStG) nachgewiesen sind und erhaltene Abfertigungen '
|
||||||
|
'angegeben wurden.')
|
||||||
|
abf_frei_betrag = fields.Monetary(
|
||||||
|
string='Bruttobetrag', currency_field='currency_id')
|
||||||
|
abf_frei_basis_12 = fields.Monetary(
|
||||||
|
string='Laufende Bezüge letzte 12 Monate',
|
||||||
|
currency_field='currency_id',
|
||||||
|
help='Basis der Viertel-/Zwölftelregelung: alle steuerbaren '
|
||||||
|
'Bezugsteile (auch steuerfreie Zuschläge, Sachbezüge), '
|
||||||
|
'ohne Sonderzahlungen und ohne §-26-Z-4-Reisevergütungen; '
|
||||||
|
'wird aus den letzten zwölf validierten Läufen vorgeschlagen '
|
||||||
|
'und ist bestätigbar (lb-end-13).')
|
||||||
|
abf_frei_dienstzeit_monate = fields.Integer(
|
||||||
|
string='Nachgewiesene Dienstzeit (Monate)')
|
||||||
|
abf_frei_erhaltene_abfertigungen = fields.Monetary(
|
||||||
|
string='Bereits erhaltene Abfertigungen', currency_field='currency_id',
|
||||||
|
help='In den nachgewiesenen Dienstzeiten erhaltene Abfertigungen '
|
||||||
|
'(§ 67 Abs 3 oder Abs 6 EStG) — Kürzung nach Z 3.')
|
||||||
|
abf_frei_gesetzlicher_anspruch = fields.Monetary(
|
||||||
|
string='Bestehender gesetzlicher Anspruch',
|
||||||
|
currency_field='currency_id',
|
||||||
|
help='Anspruch auf eine gesetzliche Abfertigung am aktuellen '
|
||||||
|
'Dienstverhältnis-Ende (Z 3); bei aktiver Alt-Abfertigung '
|
||||||
|
'automatisch aus dem Alt-Anspruch vorgeschlagen.')
|
||||||
|
abf_frei_nachweis = fields.Text(
|
||||||
|
string='Nachweis/Begründung',
|
||||||
|
help='Vordienstzeiten-Nachweis (Lohnkonto § 76 EStG), erhaltene '
|
||||||
|
'Abfertigungen, Basis-Abweichungen und Anspruchsgrundlage '
|
||||||
|
'dokumentieren.')
|
||||||
currency_id = fields.Many2one(
|
currency_id = fields.Many2one(
|
||||||
'res.currency', default=lambda self: self.env.company.currency_id)
|
'res.currency', default=lambda self: self.env.company.currency_id)
|
||||||
|
|
||||||
@@ -128,6 +165,27 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
abf_alt_netto_vorschau = fields.Monetary(
|
abf_alt_netto_vorschau = fields.Monetary(
|
||||||
string='Abfertigung Alt netto', currency_field='currency_id',
|
string='Abfertigung Alt netto', currency_field='currency_id',
|
||||||
compute='_compute_vorschau')
|
compute='_compute_vorschau')
|
||||||
|
abf_frei_z1_vorschau = fields.Monetary(
|
||||||
|
string='Z 1 Viertelregelung (Vorschau)', currency_field='currency_id',
|
||||||
|
compute='_compute_vorschau')
|
||||||
|
abf_frei_z2_vorschau = fields.Monetary(
|
||||||
|
string='Z 2 Zwölftelregelung (Vorschau)', currency_field='currency_id',
|
||||||
|
compute='_compute_vorschau')
|
||||||
|
abf_frei_kuerzung_vorschau = fields.Monetary(
|
||||||
|
string='Z 3 Kürzung (Vorschau)', currency_field='currency_id',
|
||||||
|
compute='_compute_vorschau')
|
||||||
|
abf_frei_beguenstigt_vorschau = fields.Monetary(
|
||||||
|
string='Begünstigter Teil 6 % (Vorschau)', currency_field='currency_id',
|
||||||
|
compute='_compute_vorschau')
|
||||||
|
abf_frei_ueberhang_vorschau = fields.Monetary(
|
||||||
|
string='Überhang zum Tarif (Vorschau)', currency_field='currency_id',
|
||||||
|
compute='_compute_vorschau')
|
||||||
|
abf_frei_lst_vorschau = fields.Monetary(
|
||||||
|
string='LSt 6 % (Vorschau)', currency_field='currency_id',
|
||||||
|
compute='_compute_vorschau')
|
||||||
|
abf_frei_netto_vorschau = fields.Monetary(
|
||||||
|
string='Begünstigter Teil netto (Vorschau)',
|
||||||
|
currency_field='currency_id', compute='_compute_vorschau')
|
||||||
|
|
||||||
@api.onchange('employee_id')
|
@api.onchange('employee_id')
|
||||||
def _onchange_employee(self):
|
def _onchange_employee(self):
|
||||||
@@ -139,12 +197,16 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
version.contract_date_end or fields.Date.today())
|
version.contract_date_end or fields.Date.today())
|
||||||
wizard.departure_reason_id = version.departure_reason_id
|
wizard.departure_reason_id = version.departure_reason_id
|
||||||
wizard._at_abf_alt_vorschlag_setzen()
|
wizard._at_abf_alt_vorschlag_setzen()
|
||||||
|
wizard._at_abf_frei_vorschlag_setzen()
|
||||||
|
|
||||||
@api.onchange('austrittsdatum', 'abf_alt_anspruchsart',
|
@api.onchange('austrittsdatum', 'abf_alt_anspruchsart',
|
||||||
'abf_alt_dienstzeit_monate')
|
'abf_alt_dienstzeit_monate', 'abf_alt_aktiv',
|
||||||
|
'abf_alt_monatsentgelt', 'abf_alt_mehrfach',
|
||||||
|
'abf_frei_aktiv', 'abf_frei_dienstzeit_monate')
|
||||||
def _onchange_abf_alt(self):
|
def _onchange_abf_alt(self):
|
||||||
for wizard in self:
|
for wizard in self:
|
||||||
wizard._at_abf_alt_vorschlag_setzen()
|
wizard._at_abf_alt_vorschlag_setzen()
|
||||||
|
wizard._at_abf_frei_vorschlag_setzen()
|
||||||
|
|
||||||
def _at_abf_alt_vorschlag_setzen(self):
|
def _at_abf_alt_vorschlag_setzen(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
@@ -168,11 +230,27 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
if vorgeschlagen or not self.abf_alt_mehrfach:
|
if vorgeschlagen or not self.abf_alt_mehrfach:
|
||||||
self.abf_alt_mehrfach = vorgeschlagen
|
self.abf_alt_mehrfach = vorgeschlagen
|
||||||
|
|
||||||
|
def _at_abf_frei_vorschlag_setzen(self):
|
||||||
|
self.ensure_one()
|
||||||
|
if not self.employee_id or not self.austrittsdatum:
|
||||||
|
return
|
||||||
|
slip = self._vorschau_payslip()
|
||||||
|
if self.abf_frei_aktiv and not self.abf_frei_basis_12:
|
||||||
|
self.abf_frei_basis_12 = slip._at_bezuege_12_monate()
|
||||||
|
if (self.abf_frei_aktiv and self.abf_alt_aktiv
|
||||||
|
and not self.abf_frei_gesetzlicher_anspruch):
|
||||||
|
self.abf_frei_gesetzlicher_anspruch = (
|
||||||
|
self.abf_alt_monatsentgelt * self.abf_alt_mehrfach)
|
||||||
|
|
||||||
@api.depends('employee_id', 'austrittsdatum', 'uel_tage',
|
@api.depends('employee_id', 'austrittsdatum', 'uel_tage',
|
||||||
'abf_alt_aktiv', 'abf_alt_monatsentgelt',
|
'abf_alt_aktiv', 'abf_alt_monatsentgelt',
|
||||||
'abf_alt_laufender_arbeitslohn', 'abf_alt_monatslohnsteuer',
|
'abf_alt_laufender_arbeitslohn', 'abf_alt_monatslohnsteuer',
|
||||||
'abf_alt_mehrfach',
|
'abf_alt_mehrfach',
|
||||||
'abf_alt_dienstzeit_monate', 'abf_alt_anspruchsart')
|
'abf_alt_dienstzeit_monate', 'abf_alt_anspruchsart',
|
||||||
|
'abf_frei_aktiv', 'abf_frei_betrag', 'abf_frei_basis_12',
|
||||||
|
'abf_frei_dienstzeit_monate',
|
||||||
|
'abf_frei_erhaltene_abfertigungen',
|
||||||
|
'abf_frei_gesetzlicher_anspruch')
|
||||||
def _compute_vorschau(self):
|
def _compute_vorschau(self):
|
||||||
for wizard in self:
|
for wizard in self:
|
||||||
wizard.uel_lfd_vorschau = 0.0
|
wizard.uel_lfd_vorschau = 0.0
|
||||||
@@ -183,6 +261,13 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
wizard.abf_alt_steuer_6_vorschau = 0.0
|
wizard.abf_alt_steuer_6_vorschau = 0.0
|
||||||
wizard.abf_alt_lohnsteuer_vorschau = 0.0
|
wizard.abf_alt_lohnsteuer_vorschau = 0.0
|
||||||
wizard.abf_alt_netto_vorschau = 0.0
|
wizard.abf_alt_netto_vorschau = 0.0
|
||||||
|
wizard.abf_frei_z1_vorschau = 0.0
|
||||||
|
wizard.abf_frei_z2_vorschau = 0.0
|
||||||
|
wizard.abf_frei_kuerzung_vorschau = 0.0
|
||||||
|
wizard.abf_frei_beguenstigt_vorschau = 0.0
|
||||||
|
wizard.abf_frei_ueberhang_vorschau = 0.0
|
||||||
|
wizard.abf_frei_lst_vorschau = 0.0
|
||||||
|
wizard.abf_frei_netto_vorschau = 0.0
|
||||||
if not wizard.employee_id or not wizard.austrittsdatum:
|
if not wizard.employee_id or not wizard.austrittsdatum:
|
||||||
continue
|
continue
|
||||||
slip = wizard._vorschau_payslip()
|
slip = wizard._vorschau_payslip()
|
||||||
@@ -202,6 +287,19 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
wizard.abf_alt_steuer_6_vorschau = steuer_6
|
wizard.abf_alt_steuer_6_vorschau = steuer_6
|
||||||
wizard.abf_alt_lohnsteuer_vorschau = steuer
|
wizard.abf_alt_lohnsteuer_vorschau = steuer
|
||||||
wizard.abf_alt_netto_vorschau = betrag - steuer
|
wizard.abf_alt_netto_vorschau = betrag - steuer
|
||||||
|
if wizard.abf_frei_aktiv:
|
||||||
|
split = slip._at_abf_frei_split()
|
||||||
|
satz = float(slip._l10n_at_param(
|
||||||
|
'at_endabrechnung')['abfertigung_steuersatz'])
|
||||||
|
wizard.abf_frei_z1_vorschau = split['z1']
|
||||||
|
wizard.abf_frei_z2_vorschau = split['z2']
|
||||||
|
wizard.abf_frei_kuerzung_vorschau = split['kuerzung']
|
||||||
|
wizard.abf_frei_beguenstigt_vorschau = split['beguenstigt']
|
||||||
|
wizard.abf_frei_ueberhang_vorschau = split['ueberhang']
|
||||||
|
wizard.abf_frei_lst_vorschau = \
|
||||||
|
split['beguenstigt'] * satz / 100.0
|
||||||
|
wizard.abf_frei_netto_vorschau = \
|
||||||
|
split['beguenstigt'] - wizard.abf_frei_lst_vorschau
|
||||||
|
|
||||||
def _vorschau_payslip(self):
|
def _vorschau_payslip(self):
|
||||||
"""Flüchtiger Payslip-Kontext für die Vorschau-Berechnung (kein
|
"""Flüchtiger Payslip-Kontext für die Vorschau-Berechnung (kein
|
||||||
@@ -229,11 +327,21 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
self.abf_alt_monatslohnsteuer,
|
self.abf_alt_monatslohnsteuer,
|
||||||
'l10n_at_abf_alt_mehrfach': self.abf_alt_mehrfach,
|
'l10n_at_abf_alt_mehrfach': self.abf_alt_mehrfach,
|
||||||
'l10n_at_abf_alt_nachweis': self.abf_alt_nachweis,
|
'l10n_at_abf_alt_nachweis': self.abf_alt_nachweis,
|
||||||
|
'l10n_at_abf_frei_basis_12': self.abf_frei_basis_12,
|
||||||
|
'l10n_at_abf_frei_dienstzeit_monate':
|
||||||
|
self.abf_frei_dienstzeit_monate,
|
||||||
|
'l10n_at_abf_frei_erhaltene_abfertigungen':
|
||||||
|
self.abf_frei_erhaltene_abfertigungen,
|
||||||
|
'l10n_at_abf_frei_gesetzlicher_anspruch':
|
||||||
|
self.abf_frei_gesetzlicher_anspruch,
|
||||||
|
'l10n_at_abf_frei_nachweis': self.abf_frei_nachweis,
|
||||||
})
|
})
|
||||||
eingaben = [
|
eingaben = [
|
||||||
('ATP_UEL_TAGE', self.uel_tage),
|
('ATP_UEL_TAGE', self.uel_tage),
|
||||||
('ATP_ABF_ALT', self.abf_alt_monatsentgelt
|
('ATP_ABF_ALT', self.abf_alt_monatsentgelt
|
||||||
* self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0),
|
* 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),
|
||||||
]
|
]
|
||||||
slip.input_line_ids = [
|
slip.input_line_ids = [
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
@@ -256,6 +364,8 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
('ATP_ABRECHNUNG_VORSCHUSS', self.vorschuss_saldo),
|
('ATP_ABRECHNUNG_VORSCHUSS', self.vorschuss_saldo),
|
||||||
('ATP_ABF_ALT', self.abf_alt_monatsentgelt
|
('ATP_ABF_ALT', self.abf_alt_monatsentgelt
|
||||||
* self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0),
|
* 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),
|
||||||
]
|
]
|
||||||
|
|
||||||
def _abf_alt_validieren(self):
|
def _abf_alt_validieren(self):
|
||||||
@@ -299,11 +409,30 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
'Entlassung. Bitte den Anspruch manuell bestätigen und '
|
'Entlassung. Bitte den Anspruch manuell bestätigen und '
|
||||||
'begründen.'))
|
'begründen.'))
|
||||||
|
|
||||||
|
def _abf_frei_validieren(self):
|
||||||
|
self.ensure_one()
|
||||||
|
if not self.abf_frei_aktiv:
|
||||||
|
return
|
||||||
|
if not self.abf_frei_anspruch_bestaetigt:
|
||||||
|
raise UserError(_('Bitte Prüfung und Nachweise der freiwilligen '
|
||||||
|
'Abfertigung bestätigen.'))
|
||||||
|
if self.abf_frei_betrag <= 0:
|
||||||
|
raise UserError(_('Der Bruttobetrag der freiwilligen '
|
||||||
|
'Abfertigung muss größer als null sein.'))
|
||||||
|
if (self.abf_frei_basis_12 < 0
|
||||||
|
or self.abf_frei_erhaltene_abfertigungen < 0
|
||||||
|
or self.abf_frei_gesetzlicher_anspruch < 0
|
||||||
|
or self.abf_frei_dienstzeit_monate < 0):
|
||||||
|
raise UserError(_('12-Monats-Basis, erhaltene Abfertigungen, '
|
||||||
|
'gesetzlicher Anspruch und Dienstzeit dürfen '
|
||||||
|
'nicht negativ sein.'))
|
||||||
|
|
||||||
def action_payslip(self):
|
def action_payslip(self):
|
||||||
"""Endabrechnungs-Lauf im Austrittsmonat anlegen und die
|
"""Endabrechnungs-Lauf im Austrittsmonat anlegen und die
|
||||||
gesammelten offenen Posten als Eingaben vorbefüllen."""
|
gesammelten offenen Posten als Eingaben vorbefüllen."""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
self._abf_alt_validieren()
|
self._abf_alt_validieren()
|
||||||
|
self._abf_frei_validieren()
|
||||||
erster = self.austrittsdatum.replace(day=1)
|
erster = self.austrittsdatum.replace(day=1)
|
||||||
letzter = (erster + timedelta(days=32)).replace(day=1) \
|
letzter = (erster + timedelta(days=32)).replace(day=1) \
|
||||||
- timedelta(days=1)
|
- timedelta(days=1)
|
||||||
@@ -335,6 +464,18 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
|||||||
self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0,
|
self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0,
|
||||||
'l10n_at_abf_alt_nachweis':
|
'l10n_at_abf_alt_nachweis':
|
||||||
self.abf_alt_nachweis if self.abf_alt_aktiv else False,
|
self.abf_alt_nachweis if self.abf_alt_aktiv else False,
|
||||||
|
'l10n_at_abf_frei_basis_12':
|
||||||
|
self.abf_frei_basis_12 if self.abf_frei_aktiv else 0.0,
|
||||||
|
'l10n_at_abf_frei_dienstzeit_monate':
|
||||||
|
self.abf_frei_dienstzeit_monate if self.abf_frei_aktiv else 0,
|
||||||
|
'l10n_at_abf_frei_erhaltene_abfertigungen':
|
||||||
|
self.abf_frei_erhaltene_abfertigungen
|
||||||
|
if self.abf_frei_aktiv else 0.0,
|
||||||
|
'l10n_at_abf_frei_gesetzlicher_anspruch':
|
||||||
|
self.abf_frei_gesetzlicher_anspruch
|
||||||
|
if self.abf_frei_aktiv else 0.0,
|
||||||
|
'l10n_at_abf_frei_nachweis':
|
||||||
|
self.abf_frei_nachweis if self.abf_frei_aktiv else False,
|
||||||
})
|
})
|
||||||
typen = {code: self.env['hr.payslip.input.type'].search(
|
typen = {code: self.env['hr.payslip.input.type'].search(
|
||||||
[('code', '=', code)], limit=1)
|
[('code', '=', code)], limit=1)
|
||||||
|
|||||||
Reference in New Issue
Block a user