[IMP] l10n_at_hr_payroll_private: Wr. DAG, Buchungsbeleg, VWGJ-Einstufung, EFZG-Teilentgelt mit fiktiver BV (AP2d+AP3+AP9+AP4)

AP3 — Wiener Dienstgeberabgabe (U-Bahn-Steuer, RIS LrW GesNr
20000133 verifiziert): Regel WIEN_DAG (Kopfpauschale 2 Euro je DN
und angefangene Woche, Wochenlogik Montag-im-Monat, Befreiungen
Lehrling/55+/<=10 WStd/Karenz-Woche), Company-Flag-Verwertung,
Parameter at_wien_dag_satz, FI 6663/3560 (Referenz-Rest)

AP2d — Buchungsbeleg-Report am Lohnlauf (Konto/Belegtext/Soll/Haben
der FI-Buchung, balancierte Summen; test_account_private-Erweiterung)

AP9 — Vordienstzeiten -> Einstufung: Stufen-Schwelle vwgj_ab an
l10n.at.payroll.kv.gruppe.stufe (aus Labels 'nach N VWGJ'; -1 =
nicht gepflegt, ORM liest Integer-NULL als 0), CSV-Seed,
_get_stufe_fuer_vwgj/_get_naechste_vwgj, Vertragsfeld
l10n_at_vordienstzeit_monate + VWGJ-Vorschlag + Vorrueckungstermin
(S 17 Abs 5 Rahmen-KV, Erster des Erreichungsmonats) + Uebernahme-
Button (manueller Verwaltungsakt)

AP4 — EFZG/Teilentgelt (AngG S 8/EFZG S 2 verifiziert, Gleichlauf
6/8/10/12+4 Wochen; lb-krs-07/08): EFZ-Phasenmaschine models/efzg.py
(Kalendertage-Kontingente je Arbeitsjahr, Krank-/AU-Topf getrennt,
AU-Urlaubsart ATP_AU), Regeln TEIL_ENTGELT_HALB/-50 % und
KRANKENTGELT_PHASE/-100 % je Arbeitstag (Tagesatz aus unreduzierter
Basis), fiktive BV-Grundlage S 7 Abs 3 BMSVG im _at_bv_basis_laufen-
Hook (50 % Vormonatsentgelt x Bezugs-KT/30), Parameter at_efz_stufen;
Krankengeldumlage S 62 ASVG = Falsch-Praemise (kein Baustein);
Rechenfaelle docs/rechenfaelle/efzg.md
This commit is contained in:
2026-09-12 23:17:57 +02:00
parent 34e6750fe3
commit 9b4221fcef
22 changed files with 1596 additions and 144 deletions
@@ -176,6 +176,42 @@ class L10nAtPayrollKvGruppe(models.Model):
('gueltig_ab', '<=', datum)],
order='gueltig_ab desc', limit=1)
def _get_stufe_fuer_vwgj(self, vwgj_jahre, datum=None):
"""Erfahrungsstufe für vollendete Verwendungsgruppenjahre
(VWGJ) zum Stichtag — AP9. Basis: vwgj_ab der Stufenzeilen
(„nach N VWGJ"; 0 = ab Beginn). Gibt die höchste Stufe mit
vwgj_ab <= vwgj_jahre zurück; 0, wenn die Gruppe keine
gepflegten Schwellen hat (manuelle Einstufung maßgeblich).
Rahmen-KV § 17 Abs 3-5 (Biennal-/Triennalsprünge, Vorrückung
am Ersten des Erreichungsmonats)."""
self.ensure_one()
datum = datum or fields.Date.context_today(self)
# -1 = Schwelle nicht gepflegt (ORM liest Integer-NULL als 0 —
# deshalb Konvention -1 statt NULL; Domain > -1 filtert beides).
zeilen = self.env['l10n.at.payroll.kv.gruppe.stufe'].search(
[('gruppe_id', '=', self.id),
('gueltig_ab', '<=', datum),
('vwgj_ab', '>', -1)])
beste = zeilen.filtered(lambda z: z.vwgj_ab <= vwgj_jahre)
if not beste:
return 0
return max(beste.mapped('stufe'))
def _get_naechste_vwgj(self, vwgj_jahre, datum=None):
"""Nächste VWGJ-Schwelle oberhalb der erreichten Jahre (für
den Vorrückungstermin, § 17 Abs 5) — None an der Höchststufe."""
self.ensure_one()
datum = datum or fields.Date.context_today(self)
zeilen = self.env['l10n.at.payroll.kv.gruppe.stufe'].search(
[('gruppe_id', '=', self.id),
('gueltig_ab', '<=', datum),
('vwgj_ab', '>', -1)])
schwellen = sorted(set(zeilen.mapped('vwgj_ab')))
for schwelle in schwellen:
if schwelle > vwgj_jahre:
return schwelle
return None
def _max_stufe(self, datum=None):
"""Höchste Stufe mit gültigem Monatsgehalt zum Stichtag."""
self.ensure_one()
@@ -202,6 +238,13 @@ class L10nAtPayrollKvGruppeStufe(models.Model):
bezeichnung = fields.Char(
help="Stufen-Label der KV-Tabelle, z. B. 'im 1. u 2. VWGJ' "
"oder 'nach 15 VWGJ'.")
vwgj_ab = fields.Integer(
string='Ab (vollendete) VWGJ', index=True, default=-1,
help="Vollendete Verwendungsgruppenjahre, ab denen die Stufe "
"gebührt — aus dem Stufen-Label (§ 17 Abs 3-5 "
"Rahmen-KV: Biennal-/Triennalsprünge). 0 = ab Beginn; "
"-1 = Schwelle nicht gepflegt → kein Einstufungs-"
"Vorschlag (manuelle Einstufung maßgeblich). AP9.")
gehalt = fields.Monetary(currency_field='currency_id')
currency_id = fields.Many2one(
'res.currency', default=lambda self: self.env.company.currency_id)