30270f9877
Katalogmodell nach Implementierungsplan AP1 (freigegeben 2026-09-09): - ``gemeinde.payroll.entlohnungsgruppe`` (Code, Schema, §, Bundesland, Vorrückungszeitraum je Gruppe; § 66 Abs 2 GemBG: 4 Jahre, abweichend 2 Jahre für Betreuungspersonen-/Sondergruppen) und ``gemeinde.payroll.entlohnungsstufe`` (Stufe, Monatsentgelt, Stichtag, unique je Gruppe/Stufe/Stichtag) mit Stichtags-Lookup-Helfern. - Seed 2026: 35 Entlohnungsgruppen, 433 Werte (Schemata I/gv, II/gh, Ia/bv, IIa/bh, kb, av sowie §-Gruppen 150c/151/151c), Werte aus der konsolidierten GemBG-Fassung 09.09.2026 (Wert 1.7.2026 gemäß Artikel 4 RV 0715/XXIII. GP; 2025er-Stichtagsannahme für nicht 2026 angepasste Tabellen als AP0-Verifikationspunkt dokumentiert). Generator mit Herkunftsnachweis: personalverrechnung/tools/extract_gembg_katalog.py. - GemBG-Felder auf der Payroll-Version (hr.version) plus Employee-Spiegel nach dem Engine-Muster (related/inherited): Entlohnungsgruppe, Stufe, Besoldungsdienstalter, Vorrückungstermin — berechnet nach § 66 Abs 2 (erster Tag des Monats nach Vollendung weiterer n Jahre BDA), manuell überschreibbar für Überleitungsfälle (§§ 157a ff). - Vorrückungs-Wizard (§ 66 Abs 2): fällige Versionen zum Stichtag, Stufenerhöhung mit Höchststufen-Schutz und Ergebnis-Notification — bewusst kein stilles Mutieren im Lohnlauf (Dokumentationspflicht). - Views/Menüs (Personalverrechnung Bgld. unter Payroll), Security auf hr_payroll-Gruppen, Employee-Form-Anbindung in payroll_group. - Tests (Rechenfälle AP1): Seed-Werte inkl. Quellenanomalie kb1a/6, Stichtags-Lookup, Jahresversionierung, Vorrückungstermin (BDA 15.03.2020 -> 1.4.2028), Wizard-Anwendung mit Höchststufen-Skip. Statische Validierung grün (py_compile, XML, Manifest, CSV-Integrität); Runtime-Testlauf auf dem Dev-Host (gem360_dev) ausständig, wie im Implementierungsplan M2 vorgesehen.
98 lines
4.3 KiB
Python
98 lines
4.3 KiB
Python
# Part of the gem360 onboarding. See LICENSE / project docs for details.
|
|
from odoo import _, api, fields, models
|
|
|
|
|
|
class GemeindePayrollEntlohnungsgruppe(models.Model):
|
|
"""Entlohnungsgruppe des Bgld. GemBG 2014 (z. B. bv1, kb2, av1).
|
|
|
|
Die Entlohnungsstruktur des GemBG ist schemenbasiert (Entlohnungs-
|
|
schemata I, II, Ia, IIa, kb, av sowie Sondergruppen je §). Eine Gruppe
|
|
gehört zu genau einem Schema; die Monatsentgelte je Stufe stehen auf
|
|
``gemeinde.payroll.entlohnungsstufe`` (Jahreswerte aus den Bgld.
|
|
Bezügeanpassungs-Sammelgesetzen, siehe personalverrechnung/).
|
|
"""
|
|
_name = 'gemeinde.payroll.entlohnungsgruppe'
|
|
_description = 'GemBG Entlohnungsgruppe (Bgld.)'
|
|
_order = 'bundesland, schema, code'
|
|
|
|
code = fields.Char(required=True, index=True)
|
|
schema = fields.Char(
|
|
required=True, index=True,
|
|
help="Entlohnungsschema gemäß GemBG (z. B. I, II, Ia, IIa, kb, av "
|
|
"oder §-Kennung für Sondergruppen).")
|
|
paragraph = fields.Char(
|
|
help="Paragraf der Monatsentgelt-Tabelle im Bgld. GemBG 2014.")
|
|
bundesland = fields.Selection(
|
|
[('bgld', 'Burgenland')], required=True, default='bgld', index=True)
|
|
vorrueckungszeitraum_jahre = fields.Integer(
|
|
string='Vorrückungszeitraum (Jahre)', required=True, default=4,
|
|
help="§ 66 Abs 2 GemBG: 4 Jahre; abweichend 2 Jahre für bestimmte "
|
|
"Gruppen (§ 150c Abs 2, Betreuungspersonen nach § 150d ff).")
|
|
active = fields.Boolean(default=True)
|
|
entlohnungsstufe_ids = fields.One2many(
|
|
'gemeinde.payroll.entlohnungsstufe', 'entlohnungsgruppe_id',
|
|
string='Entlohnungsstufen')
|
|
|
|
_unique_group = models.Constraint(
|
|
'unique (bundesland, schema, code)',
|
|
"Eine Entlohnungsgruppe existiert je Schema und Bundesland nur einmal.")
|
|
|
|
@api.depends('code', 'schema')
|
|
def _compute_display_name(self):
|
|
for gruppe in self:
|
|
gruppe.display_name = f"{gruppe.code} ({gruppe.schema})"
|
|
|
|
def _get_entgelt(self, stufe, datum=None):
|
|
"""Liefert die Entlohnungsstufen-Position zum Stichtag (oder leer)."""
|
|
self.ensure_one()
|
|
datum = datum or fields.Date.context_today(self)
|
|
return self.env['gemeinde.payroll.entlohnungsstufe'].search(
|
|
[('entlohnungsgruppe_id', '=', self.id),
|
|
('stufe', '=', stufe),
|
|
('gueltig_ab', '<=', datum)],
|
|
order='gueltig_ab desc', limit=1)
|
|
|
|
def _max_stufe(self, datum=None):
|
|
"""Höchste Stufe mit gültigem Monatsentgelt zum Stichtag."""
|
|
self.ensure_one()
|
|
datum = datum or fields.Date.context_today(self)
|
|
stufe = self.env['gemeinde.payroll.entlohnungsstufe'].search(
|
|
[('entlohnungsgruppe_id', '=', self.id),
|
|
('gueltig_ab', '<=', datum)],
|
|
order='stufe desc', limit=1)
|
|
return stufe.stufe or 0
|
|
|
|
|
|
class GemeindePayrollEntlohnungsstufe(models.Model):
|
|
"""Monatsentgelt einer Entlohnungsgruppe in einer Stufe ab einem
|
|
Stichtag (Jahresversionen aus den Bezügeanpassungs-Tabellen)."""
|
|
_name = 'gemeinde.payroll.entlohnungsstufe'
|
|
_description = 'GemBG Monatsentgelt je Entlohnungsstufe (Bgld.)'
|
|
_order = 'entlohnungsgruppe_id, stufe, gueltig_ab desc'
|
|
_rec_names_search = ['entlohnungsgruppe_id']
|
|
|
|
entlohnungsgruppe_id = fields.Many2one(
|
|
'gemeinde.payroll.entlohnungsgruppe', required=True, index=True,
|
|
ondelete='cascade')
|
|
stufe = fields.Integer(required=True, index=True)
|
|
monatsentgelt = fields.Monetary(currency_field='currency_id')
|
|
currency_id = fields.Many2one(
|
|
'res.currency', default=lambda self: self.env.company.currency_id)
|
|
gueltig_ab = fields.Date(
|
|
required=True, index=True,
|
|
default=lambda self: fields.Date.today().replace(month=1, day=1))
|
|
|
|
_unique_stufe = models.Constraint(
|
|
'unique (entlohnungsgruppe_id, stufe, gueltig_ab)',
|
|
"Je Entlohnungsgruppe und Stufe gibt es nur einen Wert je Stichtag.")
|
|
|
|
@api.depends('entlohnungsgruppe_id', 'stufe', 'monatsentgelt', 'gueltig_ab')
|
|
def _compute_display_name(self):
|
|
for stufe in self:
|
|
stufe.display_name = _(
|
|
"%(gruppe)s, Stufe %(stufe)s (%(betrag)s ab %(ab)s)",
|
|
gruppe=stufe.entlohnungsgruppe_id.code,
|
|
stufe=stufe.stufe,
|
|
betrag=stufe.monatsentgelt,
|
|
ab=stufe.gueltig_ab,
|
|
) |