# Part of the odoo-at-payroll project. License: LGPL-3. """Wiener Dienstgeberabgabe („U-Bahn-Steuer") — Wr. DAG, RIS LrW Gesetzesnummer 20000133, geltende Fassung 12. 09. 2026 (verifiziert, Quelle .firecrawl/ris/wien/WDGAG_*.html; § 9: die Einzahlungen fließen der Stadt Wien zu und sind zur Errichtung einer Untergrundbahn zu verwenden): - **§ 5:** 2 € je Dienstnehmer:in und je angefangene Woche eines bestehenden Dienstverhältnisses; **§ 2:** Beschäftigungsort Wien (feste Arbeitsstätte, sonst Wohnsitz des Dienstnehmers; Bau- ausführungen > 6 Monate). - **§ 3 Befreiungen:** Gebietskörperschaften; Überschreiten des 55. Lebensjahres; Behinderte/Opferfürsorge/BEinstG; Lehrverhältnisse (BAG); ≤ 10 Wochenstunden; Hausbesorger; gesetzliche Mutter- schaftsverbote und Karenzurlaub auf gesetzlichem Anspruch; Präsenzdienst/Zivildienst. - **§ 6:** Selbstberechnung — Vormonatsschuld bis 15. des Folgemonats an die Stadtkasse; Jahreserklärung bis 31. 3. inklusive befreiter Dienstverhältnisse (Fristenkalender-Arten wien_dag/wien_dag_jahres). Wochenlogik (Praxis-Annahme, im Parallellauf gegen die Magistrats- Praxis zu verifizieren): „angefangene Woche" = Kalenderwoche, deren Montag im Abrechnungsmonat liegt; abgabepflichtig, wenn das Dienst- verhältnis an mindestens einem Tag der Woche besteht. Karenz-Wochen (validierte ATP_KARENZ-Work Entries) sind befreit. Nicht abgebildet (bis AP 7): Mutterschaftsverbote, Präsenzdienst/Zivildienst, Haus- besorger, Behinderten-Status — manuelle Prüfung, Rest dokumentiert. """ from datetime import timedelta from dateutil.relativedelta import relativedelta from odoo import models class HrPayslip(models.Model): _inherit = 'hr.payslip' def _at_wien_dag(self): """Wr. DAG je Beitragsmonat: {'wochen', 'satz', 'betrag', 'info'} — None, wenn die Company nicht erfasst ist; 0-Wochen bei Befreiung. Kopfpauschale, nicht lohnabhängig (§ 5).""" self.ensure_one() if not self.company_id.l10n_at_wien_dag: return None version = self.version_id employee = self.employee_id monat_start = self.date_from monat_ende = self.date_to info = [] # Befreiungen § 3 (monatsweise Bewertung) if version.l10n_at_lehrling: return {'wochen': 0, 'satz': 0.0, 'betrag': 0.0, 'info': 'Befreit: Lehrverhältnis (§ 3 lit d).'} if employee.birthday: vollendet55 = employee.birthday + relativedelta(years=55) if vollendet55 <= monat_ende: return {'wochen': 0, 'satz': 0.0, 'betrag': 0.0, 'info': 'Befreit: 55. Lebensjahr überschritten ' '(§ 3 lit b, %s).' % vollendet55} kalender = version.resource_calendar_id wochenstunden = sum( (att.hour_to or 0.0) - (att.hour_from or 0.0) for att in kalender.attendance_ids) \ if kalender else 0.0 if wochenstunden <= 10.0: return {'wochen': 0, 'satz': 0.0, 'betrag': 0.0, 'info': 'Befreit: ≤ 10 Wochenstunden (§ 3 lit e).'} # Dienstverhältnis-Bestand im Monat (§ 1) von = max(monat_start, version.contract_date_start or monat_start) bis = min(monat_ende, version.contract_date_end or monat_ende) if von > bis: return {'wochen': 0, 'satz': 0.0, 'betrag': 0.0, 'info': 'Kein bestehendes Dienstverhältnis im ' 'Abrechnungsmonat.'} # Karenz-Tage des Monats (§ 3 lit g — Rest via WET ATP_KARENZ) karenz_tage = set() if self.env['hr.work.entry']._fields.get('leave_id'): eintraege = self.env['hr.work.entry'].search([ ('employee_id', '=', employee.id), ('date', '>=', monat_start), ('date', '<=', monat_ende), ('state', '!=', 'cancelled'), ('work_entry_type_id.code', '=', 'ATP_KARENZ'), ]) karenz_tage = {e.date for e in eintraege} # Wochen mit Montag im Monat; abgabepflichtig, wenn das # Dienstverhältnis an mindestens einem Tag der Woche besteht # (Schnittmenge [DV] ∩ [Woche] nicht leer). wochen = 0 tag = monat_start + timedelta( days=(7 - monat_start.weekday()) % 7) while tag <= monat_ende: woche_ende = tag + timedelta(days=6) if von <= woche_ende and bis >= tag: karenz_in_woche = any( tag + timedelta(days=i) in karenz_tage for i in range((woche_ende - tag).days + 1) if tag + timedelta(days=i) <= monat_ende) if karenz_in_woche: info.append('Karenz-Woche ab %s befreit (§ 3 lit g)' % tag) else: wochen += 1 tag += timedelta(days=7) satz = float(self.env['hr.rule.parameter'] ._get_parameter_from_code( 'at_wien_dag_satz', monat_start, raise_if_not_found=False) or 0.0) return {'wochen': wochen, 'satz': satz, 'betrag': wochen * satz, 'info': '; '.join(info)}