# 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 5–10). 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 5–10).' % 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.')