# Part of the odoo-at-payroll project. License: LGPL-3. """AP16: Karenz-/Familien-Freistellungen — unbezahlte Karenz-Arten (Elternkarenz generisch, Bildungs-, Familienhospiz-, Kinderrehabilita- tions- und Pflegekarenz, Papa-Monat) mit Entgelt-Stopp, eSV-An- und Abmeldeereignissen und der BMSVG-§-7-Brücke. Am Originalwortlaut verifiziert (.ris/, 8.13 freigegeben 2026-09-15): - Alle Voll-Freistellungen sind entgeltlos (AVRAG §§ 11, 14a, 14b, 14e, 14c; VKG § 1a) — Entgelt-Stopp je Arbeitstag über die negative Regel ``KARENZ_ENTGELT`` (Muster MSCH_ENTGELT, AP7). - eSV: Abmeldung zum Ende des Entgeltanspruchs (Tag vor dem Karenzbeginn), Anmeldung zum ersten Arbeitstag nach dem Ende; Papamonat/Familienzeit: Abmeldung am Tag vor Beginn (§ 11 Abs 3 lit a ASVG, lb-pap-01). Karenzart-Strings der Sonderformate „Familienhospizkarenz/Pflegekarenz An-/Abmeldung" (lb-kzs-05) laufen als Protokoll-Info — erweiterte eSV-Sonderformate = GP7-Rest. - BV: Elternkarenz/KBG zu Lasten FLAF (§ 7 Abs 5 BMSVG), Familien- hospiz-/Pflegekarenz zu Lasten des Bundes (§ 7 Abs 6 BMSVG, Fiktivgrundlage KBG § 5b Abs 1 KBGG idF vor BGBl I 53/2016); Pflegeteilzeit: AG-Beitrag auf Vor-Reduzierungs-Entgelt (§ 6 Abs 4 BMSVG, Feld l10n_at_bv_vor_entgelt). - Dienstzeit: Papamonat ist ANZURECHNEN (§ 1a Abs 7 VKG iVm § 15f MSchG), Bildungs-/Pflegekarenz grundsätzlich NICHT (§ 11 Abs 2, § 14c/14d AVRAG) — Wizard-bestätigte Dienstzeiten, dokumentiert. """ from datetime import timedelta from odoo import fields, models # Unbezahlte Karenz-WETs (generisch + AP16-Spezies) _KARENZ_WET = 'ATP_KARENZ' _BILDUNGSKARENZ_WET = 'ATP_BILDUNGSKARENZ' _HOSPIZKARENZ_WET = 'ATP_HOSPIZKARENZ' _KINDER_KRANK_WET = 'ATP_KINDERKRANK' _KINDER_REHAB_WET = 'ATP_KINDERREHAB' _PFLEGEKARENZ_WET = 'ATP_PFLEGEKARENZ' _PAPAMONAT_WET = 'ATP_PAPAMONAT' KARENZ_ARTEN = { _KARENZ_WET: 'Elternkarenz (MSchG/VKG)', _BILDUNGSKARENZ_WET: 'Bildungskarenz (§ 11 AVRAG)', _HOSPIZKARENZ_WET: 'Familienhospizkarenz — Sterbebegleitung ' '(§ 14a AVRAG)', _KINDER_KRANK_WET: 'Familienhospizkarenz — Begleitung schwerst ' 'erkrankter Kinder (§ 14b AVRAG)', _KINDER_REHAB_WET: 'Freistellung Kinderrehabilitation ' '(§ 14e AVRAG)', _PFLEGEKARENZ_WET: 'Pflegekarenz (§ 14c AVRAG)', _PAPAMONAT_WET: 'Papa-Monat/Familienzeit (§ 1a VKG / FamZeitbG)', } class HrPayslip(models.Model): _inherit = 'hr.payslip' def _at_karenz_wet_codes(self): """Codes der unbezahlten Karenz-Freistellungen (inkl. generisch und AP16-Spezies).""" self.ensure_one() return list(KARENZ_ARTEN) def _at_karenz_leaves(self): """Validierte Karenz-Freistellungen: [(von, bis, wett_code)] chronologisch.""" self.ensure_one() typen = self.env['hr.leave.type'].search([ ('work_entry_type_id.code', 'in', self._at_karenz_wet_codes()) ]) leaves = self.env['hr.leave'].search([ ('employee_id', '=', self.employee_id.id), ('holiday_status_id', 'in', typen.ids), ('state', 'in', ('validate', 'validate1')), ]) ergebnis = [] for leave in leaves: wett = leave.holiday_status_id.work_entry_type_id.code ergebnis.append((leave.request_date_from, leave.request_date_to, wett)) return [(von, bis, wett) for von, bis, wett in ergebnis if von and bis] def _at_karenz_status(self): """Karenz-Tage je Abrechnungsperiode über alle unbezahlten Karenz-Arten: {'kalendertage', 'arbeitstage', 'arten'} — None ohne Freistellung im Zeitraum (Muster _at_msch_status).""" self.ensure_one() codes = set(self._at_karenz_wet_codes()) tage = {} tag_art = {} for von, bis, wett in self._at_karenz_leaves(): tag = fields.Date.to_date(von) ende = fields.Date.to_date(bis) while tag <= ende: tage[tag] = True tag_art[tag] = wett tag += timedelta(days=1) in_periode = sorted( tag for tag in tage if self.date_from <= tag <= self.date_to) if not in_periode: return None eintraege = self.env['hr.work.entry'].search([ ('employee_id', '=', self.employee_id.id), ('date', '>=', self.date_from), ('date', '<=', self.date_to), ('state', '!=', 'cancelled'), ('work_entry_type_id.code', 'in', list(codes)), ]) arten_aktuell = {tag_art[tag] for tag in in_periode} return { 'kalendertage': in_periode, 'arbeitstage': sorted({e.date for e in eintraege}), 'arten': sorted(KARENZ_ARTEN[c] for c in arten_aktuell), } def _at_karenz_entgelt_tage(self, result_rules=None): """Arbeitstage der unbezahlten Karenz im Abrechnungszeitraum (Entgelt-Stopp-Basis der Regel KARENZ_ENTGELT).""" self.ensure_one() status = self._at_karenz_status() if not status: return 0 return len(status['arbeitstage']) class HrVersion(models.Model): _inherit = 'hr.version' l10n_at_bv_vor_entgelt = fields.Monetary( string='BV-Basis vor Arbeitszeit-Reduktion (§ 6 Abs 4 BMSVG)', currency_field='currency_id', help='Monatsentgelt vor der Reduzierung (z. B. Pflegeteilzeit ' '§ 14d AVRAG): der BV-Beitrag läuft während der Maßnahme ' 'auf Grundlage der Arbeitszeit vor Herabsetzung ' '(§ 6 Abs 4 BMSVG). Leer = laufende Basis.')