[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:
@@ -1,7 +1,7 @@
|
||||
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||||
{
|
||||
'name': 'Österreich - Personalverrechnung Kern (AT Payroll Core)',
|
||||
'version': '19.0.9.0.0',
|
||||
'version': '19.0.10.0.0',
|
||||
'author': 'Florian Egger',
|
||||
'website': 'https://gem360.at',
|
||||
'category': 'Human Resources/Payroll',
|
||||
|
||||
@@ -70,6 +70,15 @@ class HrSalaryRule(models.Model):
|
||||
'abgezogen; Grenzen als Jahres-Kumulative je Dienstnehmer '
|
||||
'(at_st_grenzen). Nur der übersteigende Teil ist '
|
||||
'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):
|
||||
@@ -351,11 +360,32 @@ class HrPayslip(models.Model):
|
||||
|
||||
def _l10n_at_brutto_laufen_ytd(self, result_rules=None):
|
||||
"""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()
|
||||
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():
|
||||
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
|
||||
|
||||
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);
|
||||
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 +
|
||||
226; 260/BIEL = LST_LFD + LST_SZ + LST_ABF."""
|
||||
226; 260/BIEL = LST_LFD + LST_SZ + LST_ABF + LST_ABF_FREI."""
|
||||
self.ensure_one()
|
||||
salden = dict.fromkeys(
|
||||
('kz210', 'kz215', 'kz220', 'kz225', 'kz226', 'kz230',
|
||||
@@ -411,7 +411,8 @@ class L10nAtPayrollL16Line(models.Model):
|
||||
elif line.code in ('SVDN_KV', 'SVDN_PV', 'SVDN_AV',
|
||||
'SVDN_AK', 'SVDN_WF'):
|
||||
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
|
||||
freibe = slip._l10n_at_freibetraege_68()
|
||||
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),
|
||||
types.SimpleNamespace(
|
||||
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},
|
||||
)
|
||||
@@ -243,7 +246,7 @@ class L16GeneratorTest(TransactionCase):
|
||||
|
||||
self.assertEqual(salden['kz210'], 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):
|
||||
"""§ 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)})
|
||||
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)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user