[IMP] l10n_at_hr_payroll_private: GP8 Vertragsstichtage-UI, All-in-Deckungsrechnung, DAG-Ausweis, Frist-mBGM-Verlinkung

Vertragsstichtage-UI (views/vertragsfelder_views.xml): GP4-Felder (ALV-Entfall, UV-Entfall, PV-Bonusphase, LNK-frei) + Status (Lehrling, fallweise, Familienabsetzbetrag, ueberw. Nachtarbeit) als gruppierte Payroll-Seite am Mitarbeiterformular (Muster: KV-Einstufung + BV-Gruppe).

All-in-Deckungsrechnung (report/gp8_reports.xml — QWeb auf hr.payslip): GP2-_at_allin_deckung als Ausweis (Pauschale vs. Bezuege, Rest = Über-/Unterdeckung; § 2g AVRAG). DAG-Ausweis (QWeb auf hr.payslip.run): § 1 DAG je Monat — Lohnsumme der Geringfuegigen, Schwelle (1,5 × GFG), Abgabe 19,4 % (GP4 _l10n_at_dag).

Frist-mBGM-Verlinkung (models/fristen_private.py): ref_mbgm_id-Feld am Fristenkalender (Kernmodell kennt mBGM nicht) + action_zum_objekt-Super-Chain; _l10n_at_verlinke_deklarationen setzt Sprungziele fuer offene L16- und mBGM-Fristen.

19.0.8.0.0. Tests: GP8-Kernsuite 6 (100/100 gesamt).
This commit is contained in:
2026-09-12 19:59:03 +02:00
parent c843701d1a
commit 57522b5be3
5 changed files with 234 additions and 2 deletions
@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ============================================================ -->
<!-- GP8: All-in-Deckungsrechnung (QWeb auf hr.payslip) und -->
<!-- DAG-Ausweis (QWeb auf hr.payslip.run). -->
<!-- ============================================================ -->
<record id="action_report_allin_deckung" model="ir.actions.report">
<field name="name">All-in-Deckungsrechnung (§ 2g AVRAG)</field>
<field name="model">hr.payslip</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">l10n_at_hr_payroll_private.report_allin_deckung</field>
<field name="report_file">l10n_at_hr_payroll_private.report_allin_deckung</field>
<field name="paperformat_id" ref="hr_payroll.paperformat_euro_light"/>
<field name="binding_model_id" ref="hr_payroll.model_hr_payslip"/>
<field name="binding_type">report</field>
</record>
<record id="action_report_dag_ausweis" model="ir.actions.report">
<field name="name">DAG-Ausweis (§ 1 DAG)</field>
<field name="model">hr.payslip.run</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">l10n_at_hr_payroll_private.report_dag_ausweis</field>
<field name="report_file">l10n_at_hr_payroll_private.report_dag_ausweis</field>
<field name="paperformat_id" ref="hr_payroll.paperformat_euro_light"/>
<field name="binding_model_id" ref="hr_payroll.model_hr_payslip_run"/>
<field name="binding_type">report</field>
</record>
<!-- All-in-Deckungsrechnung: GP2 `_at_allin_deckung()` als
Ausweis — wie viel der Pauschale von welchen Bezügen gedeckt
ist; Rest = Über-/Unterdeckung. -->
<template id="report_allin_deckung">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="slip">
<t t-call="web.external_layout">
<div class="page">
<h2>All-in-Deckungsrechnung</h2>
<table class="table table-sm">
<tr>
<td><strong>Mitarbeiter:in</strong></td>
<td><t t-out="slip.employee_id.name"/></td>
<td><strong>Periode</strong></td>
<td><t t-out="slip.date_from"/> <t t-out="slip.date_to"/></td>
</tr>
<tr>
<td><strong>All-in-Pauschale</strong></td>
<td>
<span t-out="slip.version_id.allin_pauchale"
t-options='{"widget": "monetary", "display_currency": slip.currency_id}'/>
</td>
<td><strong>Grundlohn (KV)</strong></td>
<td>
<span t-out="slip.version_id.allin_grundlohn"
t-options='{"widget": "monetary", "display_currency": slip.currency_id}'/>
</td>
</tr>
</table>
<h3>Bezüge vs. Pauschale</h3>
<table class="table table-sm">
<thead>
<tr>
<th>Bezug</th>
<th class="text-end">Betrag</th>
</tr>
</thead>
<tbody>
<tr t-foreach="slip.line_ids.filtered(lambda l: l.total and l.salary_rule_id.l10n_at_bemessung != 'neutral' and l.salary_rule_id.category_id.code == 'ATP_BRUTTO')" t-as="line">
<td><t t-out="line.name"/></td>
<td class="text-end">
<span t-out="line.total" t-options='{"widget": "monetary", "display_currency": slip.currency_id}'/>
</td>
</tr>
</tbody>
</table>
<t t-set="deckung" t-value="slip._at_allin_deckung()"/>
<t t-if="deckung and deckung.get('rest') is not None">
<p class="h4 text-end">
<strong>Rest:</strong>
<span t-out="deckung['rest']"
t-options='{"widget": "monetary", "display_currency": slip.currency_id}'/>
<t t-if="deckung['rest'] > 0">
<span class="text-warning">(Überdeckung — Pauschale übersteigt die Bezüge)</span>
</t>
<t t-if="deckung['rest'] &lt; 0">
<span class="text-danger">(Unterdeckung — Bezüge übersteigen die Pauschale)</span>
</t>
</p>
</t>
</div>
</t>
</t>
</t>
</template>
<!-- DAG-Ausweis: § 1 DAG je Monat — Lohnsumme der Geringfügigen,
Schwelle, Abgabe. -->
<template id="report_dag_ausweis">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="run">
<t t-call="web.external_layout">
<div class="page">
<h2>DAG-Ausweis (§ 1 DAG) — <t t-out="run.name"/></h2>
<t t-set="dag" t-value="run.company_id._l10n_at_dag(run.slip_ids[:1].date_from if run.slip_ids else None)"/>
<table class="table table-sm">
<thead>
<tr>
<th>Kennzahl</th>
<th class="text-end">Wert</th>
</tr>
</thead>
<tbody>
<tr>
<td>Anzahl geringfügig Beschäftigte</td>
<td class="text-end"><t t-out="dag and dag.get('anzahl', 0) or 0"/></td>
</tr>
<tr>
<td>Lohnsumme (ohne SZ)</td>
<td class="text-end">
<span t-out="dag and dag.get('lohnsumme', 0.0) or 0.0"
t-options='{"widget": "monetary", "display_currency": run.company_id.currency_id}'/>
</td>
</tr>
<tr>
<td>Schwelle (1,5 × GFG)</td>
<td class="text-end">
<span t-out="dag and dag.get('schwelle', 0.0) or 0.0"
t-options='{"widget": "monetary", "display_currency": run.company_id.currency_id}'/>
</td>
</tr>
<tr>
<td><strong>Dienstgeberabgabe (19,4 %)</strong></td>
<td class="text-end">
<strong><span t-out="dag and dag.get('abgabe', 0.0) or 0.0"
t-options='{"widget": "monetary", "display_currency": run.company_id.currency_id}'/></strong>
</td>
</tr>
</tbody>
</table>
<p class="small text-muted">
Voraussetzungen: mindestens 2 geringfügig Beschäftigte
und Lohnsumme über der Schwelle (1,5 × GFG).
</p>
</div>
</t>
</t>
</t>
</template>
</odoo>