Files
odoo-at-payroll/addons/l10n_at_hr_payroll_private/models/nachtschwerarbeit.py
T
fegger ec33dfacf2 [IMP] l10n_at_hr_payroll(_private): Meldewesen-Reste (AP17) und Status-Sonderfälle (AP18/AP19)
AP17 — Lohnnachweis L17, Finanz-Mitteilungen § 109a/§ 109b, GfB-Jahreszahlung:
- L17 (DM-ORG E.24, BEST LF, SART A1/1100, Version 28): je
  Lohnzahlungszeitraum je DN aus den GP3-Kennzahlen-Flags; Prüfkatalog-
  Semantik (KZ 350 = Brutto gesamt, 351/352/354 Teilbeträge) und formale
  Prüfungen (350-Formel, 357/347-Caps, aliquotierte 354/HOPA-Caps);
  ODL-PDF-Extraktion der Kapitel E.24/E.16/E.26 (txt feldversetzt)
- Finanz-Mitteilungen § 109a (W1, E.16) und § 109b (B1, E.26): Modelle
  je Leistungserbringer/Auftragnehmer, Schwellen als hr.rule.parameter
  (450/900 — § 109a-VO; 100.000 — § 109b Abs 4 lit a, RIS NOR40263383),
  AL31/32/33, LKZ1-7, UID, bis 3 maßgebliche natürliche Personen,
  KORR K/S; Unter-Schwellen-Zeilen entfallen mit Protokollhinweis
- mBGM: geringfügig Beschäftigte (BSGR B010/B030) — T01 § 53a-UV-
  Pauschale + V01 BMSVG 1,53 %, kein T02 (GfB-SZ beitragsfrei,
  § 49 Abs 3); JAGB-Pakettrennung für die jährliche Abrechnung
  (§ 58 Abs 8 ASVG iVm § 6 Abs 2a BMSVG, DM-ORG D.52) mit
  2,5 vH-Zuschlag (Z04) in der GfB-Jahresabrechnung (Fälligkeit
  15. 1. Folgejahr)
- Fristenkalender: L17- und § 109b-Fristarten (Ende Februar;
  § 109a/§ 109b EStG und § 58 Abs 8 ASVG RIS-verifiziert)

AP18 — Schwerarbeit/NSchG (Beschaffungsgate erledigt, RIS):
- NSchG (RIS 10008502, BGBl 1981/354) Art XI Abs 3 (2 vH Stammnorm,
  3,80 % via Sistierung) und Abs 6 (Nachtschwerarbeitsmonat: 6-Tage-
  Kriterium, Rückblick-Fenster 12/18, Randmonat); ASchV (20004642)
  § 1/§ 4/§ 5; DM-ORG E.22.2-Erstellvorschriften (Z 1 analog NSchG,
  Z 2/4/5 ≥ 15 Tage, Z 3/GfB nicht melden)
- Kern: Schwerarbeitsmeldung (BEST SM, SART 65/66, Länge 800,
  Tätigkeitsblöcke 26 × 10) mit Altersfilter- und Erstellvorschrift-
  Prüfungen
- Privat: Nachtschwerarbeitsmonat-Zähler (WET ATP_NACHTSCHWER,
  Art-XI-Abs-6-Fenster inkl. Randmonat-Proxy) als stored Flag am Lauf

AP19 — Status- und Verhinderungs-Sonderfälle:
- hr.version-Status (Organ ≤/≥ 25 %, lb-vst-03): Organ ≥ 25 % — kein
  SV-Verhältnis (SVDN/SVDG 0 via SV-Satz-Override, mBGM-Ausschluss,
  LSt läuft weiter); Ferialpraktikanten-Flag (dokumentativ — BMSVG § 6
  nennt keinen Ausschluss, Entgelt-/SV-Logik bleibt normal)
- Präsenz-/Ausbildungs-/Zivildienst-Fiktion (§ 7 Abs 1/2 BMSVG):
  fiktive BV-Bemessungsgrundlage 435,90 € (KBGG § 3 Abs 1 idF vor
  BGBl I 53/2016, lb-vor-04) aliquotiert auf ATP_PRD_TAGE
- Dienstverhinderungs-Sonderfälle bleiben dokumentiert offen
  (lb-dvh-01/04, KB-); Feiertags-EFZ ist durch das AP4-WET-Modell
  abgedeckt

Tests: 21 neue (L17-Positionen/Prüfkatalog, W1/B1-Schwellen, GfB-mBGM/
JAGB/Jahresabrechnung, NSchM-Fenster/Randmonat, SM-Fixsatz, Organ-Sperre,
PRD-Fiktion); Suite 252/252 grün auf frischer -i-DB (85 Kern, 18 GemBG,
213 Privat, 10 Dokumente). Dokumentierte Reste: DZR-36-Fenster,
Randmonat-Proxy und UV-Pauschale-vs-mBGM im Parallellauf (GP8),
fallweise mBGM (G3/G4), 2027er-Schwellen (C7).
2026-09-16 19:12:08 +02:00

102 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Part of the odoo-at-payroll project. License: LGPL-3.
"""AP18: Nachtschwerarbeitsmonat-Zähler (NSchG Art XI Abs 6) —
RIS-verifiziert 2026-09-16 (NOR40144608, RIS GesNr 10008502, BGBl
1981/354):
- **≥ 6 Arbeitstage** Nachtschwerarbeit im Kalendermonat → Nachtschwer-
arbeitsmonat;
- **< 6 Tage**: Rückblick-Fenster — Monat + 1 Vormonat ≥ **12** Tage bzw.
Monat + 2 Vormonate ≥ **18** Tage;
- (DZR > 3 Monate: Monat + 5 Vormonate ≥ 36 Tage — dokumentierter Rest,
kein Durchrechnungszeitraum-Datenmodell);
- **Randmonat**: die 6 erwarteten Nachtschwerarbeitstage werden nur
deswegen nicht erreicht, weil die Arbeit nicht am Monats-Ersten begonnen
bzw. am Letzten geendet hat — v1 mit Pro-rata-Proxy (Tage ≥ 6 × belegte
Monatskalendertage / Monatskalendertage, aufgerundet) implementiert ⚠
(Arbeitszeiteinteilung der Muster im Parallellauf verifizieren);
- Arbeitsunterbrechungen bleiben außer Betracht, solange die PV-Pflicht-
versicherung weiterbesteht.
Datenbasis: Work Entries des Typs ``ATP_NACHTSCHWER`` (mandantenseitige
Klassifikation der Nachtschwerarbeit nach NSchG Art VII Abs 2/4 bzw. ASchV
§ 1 — die Katalog-Kriterien kann die Engine nicht ableiten). Abgleich mit
der E01-Belegung (mBGM-Ergb, AP0/TASY) als Protokoll-Hinweis in der
mBGM-Generierung."""
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models
_NACHTSCHWER_WET = 'ATP_NACHTSCHWER'
class HrVersion(models.Model):
_inherit = 'hr.version'
def _l10n_at_nachtschwer_tage(self, monat_erster, monat_letzter):
"""Tage mit Nachtschwerarbeit-WETs im (Teil-)Monat."""
self.ensure_one()
eintraege = self.env['hr.work.entry'].search([
('employee_id', '=', self.employee_id.id),
('date', '>=', monat_erster),
('date', '<=', monat_letzter),
('state', '!=', 'cancelled'),
('work_entry_type_id.code', '=', _NACHTSCHWER_WET),
])
return len({eintrag.date for eintrag in eintraege})
class HrPayslip(models.Model):
_inherit = 'hr.payslip'
l10n_at_nachtschwerarbeitsmonat = fields.Boolean(
string='AT Nachtschwerarbeitsmonat',
compute='_compute_l10n_at_nachtschwerarbeitsmonat',
store=True,
help='NSchG Art XI Abs 6 (RIS NOR40144608): ≥ 6 Nachtschwerarbeits-'
'tage im Monat bzw. Rückblick-Fenster (12/18; 36 bei DZR > '
'3 Monate — dokumentierter Rest) bzw. Randmonat (Pro-rata-'
'Proxy ⚠). Grundlage NSchAB 3,80 % (Art XI Abs 3 iVm '
'Sistierung; TASY-ERGB E01).')
@api.depends('date_from', 'date_to', 'version_id')
def _compute_l10n_at_nachtschwerarbeitsmonat(self):
for slip in self:
slip.l10n_at_nachtschwerarbeitsmonat = \
slip._l10n_at_nachtschwerarbeitsmonat(slip.date_from)
def _l10n_at_nachtschwerarbeitsmonat(self, stichtag):
"""Art XI Abs 6: 6/12/18-Fenster + Randmonat-Proxy."""
self.ensure_one()
version = self.version_id
if not version:
return False
erster = stichtag.replace(day=1)
letzter = (erster + relativedelta(months=1)) \
- relativedelta(days=1)
monatstage = (letzter - erster).days + 1
tage = version._l10n_at_nachtschwer_tage(erster, letzter)
if tage >= 6:
return True
# Randmonat (Art XI Abs 6 letzter Satz): die sechs erwarteten
# Nachtschwerarbeitstage werden nur deswegen nicht erreicht,
# weil die Arbeit nicht am Monats-Ersten begonnen bzw. am
# Letzten geendet hat — v1 Pro-rata-Proxy.
beginn = max(erster, self.date_from)
ende = min(letzter, self.date_to)
if (beginn, ende) != (erster, letzter):
belegte = (ende - beginn).days + 1
erforderlich = int(-(-6 * belegte // monatstage)) # ceil
if tage >= erforderlich:
return True
# Rückblick-Fenster (12/18): Monat + 1 bzw. + 2 Vormonate.
tage_1 = version._l10n_at_nachtschwer_tage(
erster - relativedelta(months=1),
erster - relativedelta(days=1))
if tage + tage_1 >= 12:
return True
tage_2 = version._l10n_at_nachtschwer_tage(
erster - relativedelta(months=2),
erster - relativedelta(days=1))
if tage + tage_1 + tage_2 >= 18:
return True
return False