[ADD] l10n_at_hr_payroll_private: KV framework (GP1)

GP1 of the approved General-AT implementation plan: the KV
framework for the Austrian private economy on the Odoo 19
hr_payroll engine.

- l10n.at.payroll.kv: collective agreement master data with chamber,
  union, validity date and a trace link to the KV library
  (personalverrechnung/quellen/kv/)
- l10n.at.payroll.kv.wert: versioned KV parameters following the
  hr.rule.parameter.value pattern (Python literal, unique per
  KV/code/date); consumed via employee.kv_id._wert(code, date)
- l10n.at.payroll.kv.gruppe / .stufe: Verwendungsgruppen with
  Erfahrungsstufen year tables, unique(gruppe, stufe, gueltig_ab),
  Stichtag lookup
- hr.version / hr.employee contract fields: kv_id, kv_gruppe_id,
  erfahrungsstufe, ueberzahlung
- import wizard for KV intake and yearly updates: table paste
  (Gruppe;Stufe;Gehalt[;Bezeichnung]), preview, >10% jump warning
  (warn lines never applied automatically), new gueltig_ab versions,
  historical values untouched
- seed D2 (SI-2203 Handwerk und Gewerbe, SI-2748 Metallgewerbe):
  wage tables from 1. 1. 2026 curated from the KV library texts -
  18 groups, 131 stage values, 27 parameters, including the special
  progression groups IV-M / V-OM (SI-2748) and the discontinued
  VG I (SI-2203)
- tests: test_kv_katalog (seed lookups, Stichtag behaviour,
  versioning, parameters, wizard, contract fields)

Statically validated (py_compile, XML well-formedness, CSV
consistency, wizard logic simulation); runtime acceptance pending
PostgreSQL on the dev host.
This commit is contained in:
2026-09-09 22:10:26 +02:00
parent 6e444b088a
commit 67374611c6
16 changed files with 1274 additions and 12 deletions
@@ -0,0 +1,270 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="kv_list_view" model="ir.ui.view">
<field name="name">l10n.at.payroll.kv.list</field>
<field name="model">l10n.at.payroll.kv</field>
<field name="arch" type="xml">
<list string="Kollektivverträge">
<field name="code"/>
<field name="name"/>
<field name="arbeitgeberkammer"/>
<field name="gewerkschaft"/>
<field name="gueltig_ab"/>
<field name="active" column_invisible="1"/>
</list>
</field>
</record>
<record id="kv_form_view" model="ir.ui.view">
<field name="name">l10n.at.payroll.kv.form</field>
<field name="model">l10n.at.payroll.kv</field>
<field name="arch" type="xml">
<form string="Kollektivvertrag">
<sheet>
<group>
<group>
<field name="name"/>
<field name="code"/>
<field name="arbeitgeberkammer"/>
<field name="gewerkschaft"/>
</group>
<group>
<field name="gueltig_ab"/>
<field name="library_variant_id"/>
<field name="quelle_url" widget="url"/>
<field name="active" widget="boolean_toggle"/>
</group>
</group>
<notebook>
<page string="Verwendungsgruppen" name="gruppen">
<field name="gruppe_ids">
<list editable="bottom">
<field name="code"/>
<field name="name"/>
<field name="lohn_basis"/>
<field name="active" widget="boolean_toggle"/>
</list>
</field>
</page>
<page string="KV-Eckwerte" name="werte">
<field name="wert_ids">
<list editable="bottom">
<field name="code"/>
<field name="name"/>
<field name="parameter_value"/>
<field name="date_from"/>
</list>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="kv_gruppe_form_view" model="ir.ui.view">
<field name="name">l10n.at.payroll.kv.gruppe.form</field>
<field name="model">l10n.at.payroll.kv.gruppe</field>
<field name="arch" type="xml">
<form string="KV-Verwendungsgruppe">
<sheet>
<group>
<group>
<field name="kv_id"/>
<field name="code"/>
<field name="name"/>
</group>
<group>
<field name="lohn_basis"/>
<field name="active" widget="boolean_toggle"/>
</group>
</group>
<notebook>
<page string="Erfahrungsstufen (Jahrestabellen)" name="stufen">
<field name="stufe_ids">
<list editable="bottom">
<field name="stufe"/>
<field name="bezeichnung"/>
<field name="gehalt"/>
<field name="gueltig_ab"/>
</list>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="kv_gruppe_list_view" model="ir.ui.view">
<field name="name">l10n.at.payroll.kv.gruppe.list</field>
<field name="model">l10n.at.payroll.kv.gruppe</field>
<field name="arch" type="xml">
<list string="KV-Verwendungsgruppen">
<field name="kv_id"/>
<field name="code"/>
<field name="name"/>
<field name="lohn_basis"/>
</list>
</field>
</record>
<record id="kv_wert_list_view" model="ir.ui.view">
<field name="name">l10n.at.payroll.kv.wert.list</field>
<field name="model">l10n.at.payroll.kv.wert</field>
<field name="arch" type="xml">
<list string="KV-Eckwerte" multi_edit="1">
<field name="kv_id"/>
<field name="code"/>
<field name="name"/>
<field name="parameter_value"/>
<field name="date_from"/>
</list>
</field>
</record>
<record id="kv_gruppe_stufe_list_view" model="ir.ui.view">
<field name="name">l10n.at.payroll.kv.gruppe.stufe.list</field>
<field name="model">l10n.at.payroll.kv.gruppe.stufe</field>
<field name="arch" type="xml">
<list string="KV-Monatsgehälter">
<field name="gruppe_id"/>
<field name="stufe"/>
<field name="bezeichnung"/>
<field name="gehalt" sum="Summe"/>
<field name="gueltig_ab"/>
</list>
</field>
</record>
<record id="action_kv" model="ir.actions.act_window">
<field name="name">Kollektivverträge</field>
<field name="res_model">l10n.at.payroll.kv</field>
<field name="view_mode">list,form</field>
</record>
<record id="action_kv_gruppe" model="ir.actions.act_window">
<field name="name">KV-Verwendungsgruppen</field>
<field name="res_model">l10n.at.payroll.kv.gruppe</field>
<field name="view_mode">list,form</field>
</record>
<record id="action_kv_wert" model="ir.actions.act_window">
<field name="name">KV-Eckwerte</field>
<field name="res_model">l10n.at.payroll.kv.wert</field>
<field name="view_mode">list</field>
<field name="context">{'search_default_groupby_kv_id': 1}</field>
</record>
<record id="action_kv_gruppe_stufe" model="ir.actions.act_window">
<field name="name">KV-Monatsgehälter (Stufen)</field>
<field name="res_model">l10n.at.payroll.kv.gruppe.stufe</field>
<field name="view_mode">list</field>
<field name="context">{'search_default_groupby_gruppe_id': 1}</field>
</record>
<!-- KV-Einstufung am Mitarbeitervertrag (Muster hr_version_bgld) -->
<record id="payroll_hr_employee_view_form_kv" model="ir.ui.view">
<field name="name">hr.employee.form.kv</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr_payroll.payroll_hr_employee_view_form"/>
<field name="arch" type="xml">
<group name="payroll_group" position="inside">
<group name="kv_einstufung" string="KV-Einstufung"
groups="hr_payroll.group_hr_payroll_user">
<field name="kv_id"/>
<field name="kv_gruppe_id"
domain="[('kv_id', '=', kv_id)]"
invisible="not kv_id"/>
<field name="erfahrungsstufe"
invisible="not kv_gruppe_id"/>
<field name="ueberzahlung"
invisible="not kv_gruppe_id"/>
</group>
</group>
</field>
</record>
<!-- KV-Katalog-Import -->
<record id="kv_import_wizard_form_view" model="ir.ui.view">
<field name="name">l10n.at.payroll.kv.import.wizard.form</field>
<field name="model">l10n.at.payroll.kv.import.wizard</field>
<field name="arch" type="xml">
<form string="KV-Katalog importieren (Aufnahme/Jahresupdate)">
<group>
<group>
<field name="kv_id"/>
<field name="gueltig_ab"/>
</group>
</group>
<field name="eingabe" placeholder="Gruppe;Stufe;Gehalt[;Bezeichnung] — z. B. III;1;2528,04;im 1. u 2. VWGJ"/>
<notebook>
<page string="Vorschau" name="vorschau">
<field name="line_ids">
<list editable="bottom" create="0" delete="0">
<field name="uebernehmen" widget="boolean_toggle"/>
<field name="gruppe_code"/>
<field name="gruppe_name"/>
<field name="stufe"/>
<field name="bezeichnung"/>
<field name="alter_wert"/>
<field name="neuer_wert"/>
<field name="currency_id" column_invisible="1"/>
<field name="warnung" decoration-danger="warnung"/>
</list>
</field>
</page>
<page string="Protokoll" name="protokoll">
<field name="protokoll"/>
</page>
</notebook>
<footer>
<button string="1) Tabelle analysieren" name="action_parse"
type="object" class="btn-secondary"/>
<button string="2) Ausgewählte Werte übernehmen"
name="action_apply" type="object"
class="btn-primary" invisible="not line_ids"/>
<button string="Abbrechen" class="btn-secondary"
special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_kv_import_wizard" model="ir.actions.act_window">
<field name="name">KV-Katalog importieren</field>
<field name="res_model">l10n.at.payroll.kv.import.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="menu_l10n_at_payroll_private_root"
name="AT-Payroll (Privat)"
parent="hr_work_entry_enterprise.menu_hr_payroll_root"
sequence="95"/>
<menuitem id="menu_l10n_at_payroll_private_kv"
name="Kollektivverträge"
parent="menu_l10n_at_payroll_private_root"
action="action_kv" sequence="10"/>
<menuitem id="menu_l10n_at_payroll_private_gruppen"
name="KV-Verwendungsgruppen"
parent="menu_l10n_at_payroll_private_root"
action="action_kv_gruppe" sequence="15"/>
<menuitem id="menu_l10n_at_payroll_private_werte"
name="KV-Eckwerte"
parent="menu_l10n_at_payroll_private_root"
action="action_kv_wert" sequence="20"/>
<menuitem id="menu_l10n_at_payroll_private_stufen"
name="KV-Monatsgehälter (Stufen)"
parent="menu_l10n_at_payroll_private_root"
action="action_kv_gruppe_stufe" sequence="30"/>
<menuitem id="menu_l10n_at_payroll_private_import"
name="KV-Katalog importieren"
parent="menu_l10n_at_payroll_private_root"
action="action_kv_import_wizard" sequence="40"/>
</odoo>