Files
odoo-at-payroll/addons/l10n_at_hr_payroll/models/meldewesen.py
T
fegger 3c85cc6790 [IMP] l10n_at_hr_payroll: TASY-Tarifsystem-Katalog, AGRD-Auswahl, DG-Kosten-/Lohnkonten-Reports, Wr.-DAG-Grundlagen (AP0-AP3)
AP0 Variante b — TASY-Tarifsystem-Katalog:
- Neue Katalogmodelle (BSGR/ERGB/Dienstgebergruppen/Tarifgruppen/
  Tarifsets/Tarife/Zuordnungen/Zu-Abschläge inkl. Steuerung),
  models/tasy_katalog.py — Auflösung Tarifgruppe (BSGR+ERGB+DGG)
  -> Sätze je Verrechnungsbasis
- Import-Wizard l10n.at.payroll.tasy.katalog.wizard (alle Träger,
  sektionsscharf, idempotent), Views/Menüs, Security
- Realexport-Test gegen TASY-LSWH-Export (B001/B002 = 39,05/37,55 %)

AP1 — eSV-Abmeldegründe (DM-ORG D.22):
- l10n_at_agrd Char -> vollständige Selection (33 Codes),
  Seed der Standard-Abgangsursachen (noupdate, hr-Defaults vorverbunden),
  Form-/Listen-Erbe

AP2a-c — Auswertungen:
- Monatsjournal: eigener Dienstgeberanteile-Block (ATP_DG vorher
  still ausgefiltert); Fix: models/monatsreports.py war nie in
  models/__init__.py importiert (GP7-Reports waren toter Code)
- Neuer Report Dienstgeber-Gesamtkosten (Brutto + LNK aufgeschlüsselt/
  kumuliert je AN + Laufsummen, Spalten FLAF/KommSt/DZ/BV/Wr. DAG)
- Jahreslohnkonto je DN + Betriebsjahreslohnkonto (Jahresbericht-
  Wizard, Monatsmatrix je Lohnart), report/jahresreports.xml

AP3 — Wr. Dienstgeberabgabe (RIS LrW GesNr 20000133 verifiziert):
- Company-Flag l10n_at_wien_dag (Kern), Fristenarten wien_dag/
  wien_dag_jahres (cron-geflaggt, 15./31. 3.), Company-View-Feld,
  Wr.-DAG-Spalte im DG-Kosten-Report
2026-09-12 23:17:00 +02:00

151 lines
7.2 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.
"""Meldewesen-Stammdaten (GP7/AP5): ELDA-/FinOnl-Identifikation der
Dienstgeberin und der Arbeitsstätten.
- ``res.company``: Beitragskontonummer (BKNR — ELDA-Feld, Präfix =
KV-Träger) und Lohnsteuernummer (9-stellig: 2 Stellen Finanzamt + 7
Stellen Nummer; L16-I1 STNRA/STNRL, Arbeitsstättenmeldung STNR).
- ``res.partner``: österreichische Gemeindekennziffer (AGKZ) für die
Arbeitsstättenmeldung nach § 34 Abs 6 ASVG — Odoo hält keine GKZ, das
Feld ist mandantenseitig zu pflegen (Warnung des L16-Laufs, wenn es am
Dienstort-Partner fehlt).
- ``hr.version``: Kennzeichen fallweise Beschäftigung (§ 33 Abs 1a
Z 1 ASVG — tagesgenaue vereinfachte Anmeldung vor Arbeitsantritt,
DM-ORG BEST MA) und VSNR-Formatprüfung (10-stellig LLLPTTMMJJ;
Prüfzifferalgorithmus der SVS ist nicht beschafft → nur Format/
Plausibilität, Rest dokumentiert).
- ``hr.departure.reason``: Mapping auf den eSV-Abmeldegrund (AGRD,
DM-ORG D.22 — vollständige Code-Liste als Selection, Standard
``00`` sonstiger Grund mit Ende des Beschäftigungsverhältnisses;
die üblichen Abgangsursachen sind im Seed vorverbunden,
noupdate — mandantenseitig ergänzte Ursachen bleiben unberührt)."""
from odoo import api, fields, models
from odoo.exceptions import ValidationError
# eSV-Abmeldegründe, DM-ORG 42.7.0 Kapitel D.22 (AGRD Abmeldegrund,
# Code) — verifiziert gegen .firecrawl/ris/elda/DM-ORG_v42.7.0.txt
# (42. Ergänzung 07/2026). Codes 26/28 existieren nicht (Lücken im
# Katalog), Code 00 = sonstiger Grund mit Ende des DV.
L10N_AT_AGRD = [
('01', '01 — Kündigung durch den Dienstgeber'),
('02', '02 — Kündigung durch den Dienstnehmer'),
('03', '03 — Einvernehmliche Lösung'),
('04', '04 — Zeitablauf'),
('05', '05 — Berechtigter vorzeitiger Austritt'),
('06', '06 — Fristlose Entlassung'),
('07', '07 — Karenz nach MSchG / VKG'),
('08', '08 — Präsenzdienstleistung im Bundesheer'),
('09', '09 — Zivildienst'),
('10', '10 — Pragmatisierung'),
('11', '11 — Länger als 1 Monat währender unbezahlter Urlaub'),
('12', '12 — Ummeldung'),
('13', '13 — Tod des Dienstnehmers'),
('14', '14 — Änderung der SV-Pflicht'),
('15', '15 — Truppenübung'),
('16', '16 — Pensionierung'),
('17', '17 — Ende freier Dienstvertrag (§ 4 Abs 4 ASVG)'),
('18', '18 — Enthebung von der Gerichtspraxis'),
('19', '19 — Unterbrechung der Gerichtspraxis'),
('20', '20 — Entlassung aus der Bundesbetreuung'),
('21', '21 — Kündigung durch DN während Elternteilzeit (MSchG/VKG)'),
('22', '22 — Unberechtigter vorzeitiger Austritt'),
('23', '23 — Bildungskarenz gemäß § 11 AVRAG'),
('24', '24 — Vorzeitiger Austritt gem. § 25 IO durch Dienstnehmer'),
('25', '25 — Kündigung gem. § 25 IO durch Insolvenzverwalter:in'),
('27', '27 — Kündigung gem. § 25 IO durch Dienstgeber'),
('29', '29 — SV-Ende Beschäftigung aufrecht'),
('30', '30 — Lösung in der Probezeit durch Dienstgeber'),
('31', '31 — Pflegekarenz (interner SV-Abmeldegrund)'),
('32', '32 — Bildungskarenz gemäß § 12 AVRAG'),
('33', '33 — Familienhospizkarenz (interner SV-Abmeldegrund)'),
('34', '34 — Lösung in der Probezeit durch Dienstnehmer'),
('00', '00 — Sonstiger Grund mit Ende des DV'),
]
class ResCompany(models.Model):
_inherit = 'res.company'
l10n_at_beitragskontonummer = fields.Char(
string='AT Beitragskontonummer (BKNR)',
help='eSV-Beitragskontonummer des Dienstgebers (10 Stellen;\n'
'die ersten Stellen codieren den KV-Träger). Pflichtfeld\n'
'jeder ELDA-Meldung (mBGM-Paket BKNR, Versichertenmeldung,\n'
'Arbeitsstättenmeldung, fallweise Anmeldung).')
l10n_at_lohnsteuernummer = fields.Char(
string='AT Lohnsteuernummer',
help='9-stellig: 2 Stellen Finanzamtsnummer + 7 Stellen\n'
'Steuernummer (Lohnzettel Finanz I1 STNRA/STNRL;\n'
'Arbeitsstättenmeldung STNR).')
l10n_at_wien_dag = fields.Boolean(
string='AT Beschäftigungsort Wien (Wr. DAG)',
help='Wiener Dienstgeberabgabe („U-Bahn-Steuer“, Wr. DAG,\n'
'RIS LrW GesNr 20000133): 2 € je Dienstnehmer:in und\n'
'angefangene Woche je Bestehen eines Dienstverhältnisses\n'
'mit Beschäftigungsort Wien (§§ 1, 2, 5); Befreiungen § 3\n'
'(z. B. Überschreiten des 55. Lebensjahres, Lehrlinge,\n'
'≤ 10 Wochenstunden, Mutterschaftsverbote/Karenz,\n'
'Präsenzdienst, Gebietskörperschaften); Selbstberechnung\n'
'15. des Folgemonats, Jahreserklärung bis 31. 3. (§ 6).')
class ResPartner(models.Model):
_inherit = 'res.partner'
l10n_at_gemeindekennziffer = fields.Char(
string='AT Gemeindekennziffer (GKZ)',
help='5-stellige österreichische Gemeindekennzahl für die\n'
'Arbeitsstättenmeldung nach § 34 Abs 6 ASVG (Feld AGKZ).\n'
'Am Dienstort-Partner des Mitarbeiters pflegen.')
class HrVersion(models.Model):
_inherit = 'hr.version'
l10n_at_fallweise = fields.Boolean(
string='AT Fallweise Beschäftigung',
groups="hr_payroll.group_hr_payroll_user", tracking=True,
help='Fallweise Beschäftigung (§ 33 Abs 1a Z 1 ASVG): je\n'
'Beschäftigungstag ist die vereinfachte Anmeldung vor\n'
'Arbeitsantritt zu übermitteln (ELDA BEST MA, Satzarten\n'
'32/33); An-/Abmeldung laufen über die mBGM (G3/G4).')
@api.constrains('ssnid')
def _l10n_at_vsnr_format(self):
"""VSNR-Formatprüfung LLLPTTMMJJ (10 Stellen, Ziffern, plausibles
Geburtsdatum TTMMJJ an den Stellen 510). Der
Prüfzifferalgorithmus der SVS ist nicht beschafft → nur
Format/Plausibilität (Rest dokumentiert; die Meldungsgeneratoren
listen ungültige VSNR listenweise als UserError)."""
for version in self:
if not version.ssnid:
continue
roh = version.ssnid.strip()
if len(roh) != 10 or not roh.isdigit():
raise ValidationError(
'Versicherungsnummer %r: 10 Ziffern im Format LLLPTTMMJJ '
'erwartet.' % version.ssnid)
try:
tag = int(roh[4:6])
monat = int(roh[6:8])
if not 1 <= tag <= 31 or not 1 <= monat <= 12:
raise ValueError()
except ValueError:
raise ValidationError(
'Versicherungsnummer %r enthält kein plausibles '
'Geburtsdatum (TTMMJJ an den Stellen 510).'
% version.ssnid)
class HrDepartureReason(models.Model):
_inherit = 'hr.departure.reason'
l10n_at_agrd = fields.Selection(
L10N_AT_AGRD,
string='AT eSV-Abmeldegrund (AGRD)',
help='2-stelliger Abmeldegrund-Code der Versichertenmeldung '
'(DM-ORG D.22); Standard 00 „Sonstiger Grund mit Ende des '
'Beschäftigungsverhältnisses“. Die Abmeldung M4 liest das '
'Mapping dieser Abgangsursache.')