diff --git a/.agents/MEMORY.md b/.agents/MEMORY.md
index 7ac529e..f4317c8 100644
--- a/.agents/MEMORY.md
+++ b/.agents/MEMORY.md
@@ -2,6 +2,77 @@
## Current focus
+**Modul l10n_at_payroll_dokumente (Dokumentgenerierung) umgesetzt — 236/236 Tests grün**
+(2026-09-16, uncommittet bis Nutzerfreigabe; Modul **19.0.1.0.0**):
+
+- **Anforderung (Nutzer):** Muster → Dokumente aus Stammdaten (Dienstvertrag,
+ Kündigung, DSE …). Nutzer-Entscheidungen: neues Modul; DSE = vorhandene
+ Pfändungs-DSE (kein Neubau); **eigene Texte nach Muster-Struktur** (kb_ref/
+ quell_stand je Vorlage dokumentiert, kein Lexis-Volltext im Repo —
+ Lizenzthema damit fürs Produkt gelöst; Muster werden laufend ergänzt,
+ kein Warten nötig: neue Vorlagen = Datenarbeit).
+- **Bau:** Modell `l10n.at.payroll.dokument.vorlage` (+ feld): eigener Text
+ `inhalt_html` (Html, sanitize=False), Feldliste (auto/manuell, pflicht),
+ kb_ref/quell_stand/rechtsstatus (entwurf|geprueft), company + Rule.
+ Wizard `l10n.at.payroll.dokument.wizard` (+ Zeilen-Transient): Stichtag →
+ hr.version (date_version <= Stichtag!), Auto-Resolver (firma/firma_strasse/
+ firma_plz/firma_ort/mitarbeiter/mitarbeiter_strasse/plz/ort/ead/funktion/
+ geboren), Manuell-Eingaben, Pflicht-UserError, Vorschau, PDF via
+ `ir.actions.report._render_qweb_pdf` **mit HTML-Fallback** ohne
+ wkhtmltopdf (Anhang am hr.employee). Generisches QWeb-Print-Layout
+ (AbstractModel + data['body'] als Markup, wie DSE-Muster).
+- **⚠️ Rendering-Weg (wichtig, abweichend vom Plan):** NICHT
+ `mail.render.mixin._render_template` (engine inline_template) — deren
+ Ausdrucks-Whitelist (`mail_allowed_qweb_expressions`, nur object.name u.ä.)
+ sperrt `werte['…']`-Ausdrücke für Nicht-Template-Editoren (AccessError).
+ Stattdessen: `rendering_tools.convert_inline_template_to_qweb` →
+ `ir.qweb._render(lxml html.fragment_fromstring(src, create_parent='div'), …)`
+ + Wrapper-[5:-6]-Strip (Muster `_render_template_qweb`). Autor-Syntax
+ bleibt identisch; **t-out escapt Werte automatisch** (kein manuelles
+ Escaping). t-if-Blöcke für optionale Absätze sind möglich (QWeb direkt).
+- **Pilotvorlagen (eigen formuliert, Rechtsstatus 'entwurf'):** DV
+ Angestellte (lb-bes-09), Kündigung DG (lb-bnd-55), einvernehmliche
+ Auflösung (lb-bnd-52/62), Vordienstzeitenbestätigung (lb-end-35).
+ §-Verifikation: § 27 AngG (wichtiger Grund) RIS ✅; **§ 34 AngG =
+ Verjährung** (nicht Auflösung!) — Auflösungstexte zitieren bewusst keine §§.
+- **Tests 8** (Auto-Werte, Platzhalter-Ersetzung, Pflicht-UserError,
+ Stichtags-Versionen, Anhang PDF/HTML, generisches Layout via
+ `_render_qweb_html` ohne wkhtmltopdf, ACL hr.group_hr_user vs. base,
+ Pilotvorlagen E2E). Suite **236/236** (73 Kern + 18 GemBG + 199 Privat
+ + 10 Dokumente) frischer -i-Lauf.
+- Offen: DSE-Pfändung-Link ins Dokumente-Menü (kosmetisch), mehr Vorlagen
+ nach Nutzermustererweiterung, Produktivsetzung erst nach rechtlicher
+ Prüfung (rechtsstatus je Vorlage).
+
+**Erneuter Abgleich Modul ↔ Wissensbasis (2026-09-16, Read-only, Grep-Verifikation am Code):**
+Basis PLAN-Restluecken-AP11 (Abgleich 2026-09-12, 601 Einträge) + Zwischenstand AP8/AP11–AP16.
+Befund:
+- **Geplante Reste unverändert offen (0 Code-Treffer je Thema):** AP17 (L17, § 109a/
+ § 109b-Meldung, mBGM Geringfügigen-Jahreszahlung 2,5 %), AP18 (NSchG-Monatszähler,
+ Schwerarbeitsmeldung — ASchV/NSchG-Beschaffungsgate), AP19 (GF/Vorstand-Flag,
+ Ferialpraktikanten, DVH-Sonderfälle, Präsenzdienst-BV-Fiktion), AP20+-Optionen
+ (ATZ, Kurzarbeit, Betriebspension/Beteiligung, Entsendung), Quer-LSt: FB+/ANV-
+ Automatik, Prämien-Anspruchsprinzip (A3-blockiert), 2027-Werte.
+- **Zwischenzeitlich ✅ (Code-verifiziert):** All-in § 2g AVRAG (GP2-Deckungsrechnung,
+ payslip_private `_at_allin_deckung`), Fallweise-Felder + mBGM G3/G4 tagesgenau,
+ AVAB/AVB-Selection, Nachzahlungspfade (SV/LSt/Endabrechnung), Tod des DN =
+ Abgangsursache 13, §§ 23f/§ 47-Übertritte in abfertigung_private.
+- **1 NEUER Restpunkt aus Batch 10:** **Ausbildungskostenrückersatz** (lb-end-27/28,
+ Checkliste + Muster) — 0 Code-Treffer, auch nicht im AP11-Plan erfasst →
+ als Zusatzpunkt in AP14/Endabrechnung (Scope-Gate Pilotmandant) aufnehmen.
+- Batch 10 sonst: keine neuen Cluster, keine neuen Berechnungslogiken (Muster/
+ Checklisten/Übersichten); lb-end-30/31 (freiwillige Abf./Voll-Übertritt) und
+ lb-end-29 (Zeitschulden) abgedeckt; lb-grz-09..11/lb-swa-06 stützen AP18/AP20.
+- KB-interne offene Punkte unverändert: A3 „Formel 7“, A4 All-In-Oberwert,
+ A7-2026-GFG, C7-2027-Werte, B3 Pensionisten (VwGH), ASchV/NSchG-Beschaffung.
+- **Nachgetragen 2026-09-16 (Nutzer):** Ausbildungskostenrückersatz in
+ `PLAN-Restluecken-AP11.md` (AP14-Umsetzung/Rechtsanker + Lücken-Liste 2.4).
+- **Neue Anfrage (2026-09-16, ERLEDIGT — siehe Modul-Block oben):**
+ `.lexis360/muster/` für Dokumente in Odoo nutzen → Modul
+ `l10n_at_payroll_dokumente` umgesetzt; Nutzer entschieden: eigene Texte
+ nach Muster-Struktur (kein Lexis-Volltext im Repo), Lizenz-Redistribution
+ damit fürs Produkt gelöst; Sammlung wird laufend ergänzt (kein Warten).
+
**Wissensbasis Batch 10 (3 neue Lexis-Subordner) ABGESCHLOSSEN — 64/64 kuratiert, `--registry` + `--check` grün**
(2026-09-16, Nutzerfreigabe "bitte zur wissensbasis hinzufuegen"):
diff --git a/README.md b/README.md
index bd3ff3f..9da195c 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@ seit 2026-09-09 — Überführung aus `gem360-git` per History-Import; siehe
|---|---|
| `l10n_at_hr_payroll` | **Bundes-Kern** (sektor-neutral): SV-Werte 2026 als `hr.rule.parameter`-Seed, TASY-Import-Wizard; folgen: Lohnsteuer (AP3), Meldewesen L16/eSV (AP5), Belege (AP6) |
| `l10n_at_gemeinde_payroll` | **Bgld. GemBG 2014**: Katalogmodell (AP1), Entgelt-Engine (AP2); AP3+ gemäß `personalverrechnung/IMPLEMENTIERUNGSPLAN-Bgld.md` |
+| `l10n_at_payroll_dokumente` | **Dokumente aus Vorlagen**: Dokumentgenerierung (Dienstvertrag, Kündigung, Bescheinigungen …) aus hr-Stammdaten; eigene Texte, Struktur-Referenz (kb_ref) dokumentiert; Wizard mit Auto-/Manuellfeldern, Vorschau, PDF/HTML-Ablage |
| `l10n_at_hr_payroll_private` | **General-AT** (KV-basierte Privatwirtschaft) — Gerüst; Implementierungsplan freigegeben ([`IMPLEMENTIERUNGSPLAN-Privat.md`](personalverrechnung/IMPLEMENTIERUNGSPLAN-Privat.md)), Umsetzung ab M1 (GP0) |
VRV-Buchung für Gemeinden (Anlage 3b, Ansatz/MVAG, EHH/FHH) läuft über
diff --git a/addons/l10n_at_payroll_dokumente/__init__.py b/addons/l10n_at_payroll_dokumente/__init__.py
new file mode 100644
index 0000000..ecc9fab
--- /dev/null
+++ b/addons/l10n_at_payroll_dokumente/__init__.py
@@ -0,0 +1,3 @@
+# Part of the odoo-at-payroll project. License: LGPL-3.
+from . import models
+from . import tests
\ No newline at end of file
diff --git a/addons/l10n_at_payroll_dokumente/__manifest__.py b/addons/l10n_at_payroll_dokumente/__manifest__.py
new file mode 100644
index 0000000..169d566
--- /dev/null
+++ b/addons/l10n_at_payroll_dokumente/__manifest__.py
@@ -0,0 +1,33 @@
+# Part of the odoo-at-payroll project. License: LGPL-3.
+{
+ 'name': 'AT Payroll: Dokumente aus Vorlagen',
+ 'version': '19.0.1.0.0',
+ 'category': 'Human Resources/Payroll',
+ 'summary': 'Dokumentgenerierung aus Vorlagen mit hr-Stammdaten (eigene Texte)',
+ 'description': """
+Dokumente (Dienstvertrag, Kündigung, Bescheinigungen, ...) aus Vorlagen,
+befüllt aus hr-Stammdaten und Wizard-Eingaben.
+
+- Vorlagen enthalten ausschließlich eigenen Text; Struktur-Referenz und
+ Quell-Stand sind pro Vorlage dokumentiert (kb_ref/quell_stand).
+- Platzhalter-Syntax des Standard-Inline-Renderers von mail.render.mixin:
+ {{ werte['key'] }}, {{ object.feld }}, {{ format_date(...) }}.
+- PDF-Erzeugung über ir.actions.report (wkhtmltopdf); ohne PDF-Engine
+ wird das gerenderte HTML abgelegt.
+""",
+ 'author': 'odoo-at-payroll',
+ 'website': 'https://example.com/odoo-at-payroll',
+ 'license': 'LGPL-3',
+ 'depends': ['hr', 'mail'],
+ 'data': [
+ 'security/ir.model.access.csv',
+ 'security/security_rules.xml',
+ 'data/vorlagen_pilot.xml',
+ 'views/dokument_vorlage_views.xml',
+ 'views/wizard_views.xml',
+ 'report/report_dokument.xml',
+ ],
+ 'demo': [],
+ 'installable': True,
+ 'application': False,
+}
\ No newline at end of file
diff --git a/addons/l10n_at_payroll_dokumente/data/vorlagen_pilot.xml b/addons/l10n_at_payroll_dokumente/data/vorlagen_pilot.xml
new file mode 100644
index 0000000..719c4b6
--- /dev/null
+++ b/addons/l10n_at_payroll_dokumente/data/vorlagen_pilot.xml
@@ -0,0 +1,232 @@
+
+ {{ werte['firma'] }} zwischen {{ werte['firma'] }}, {{ werte['firma_strasse'] }}, {{ werte['firma_plz'] }} {{ werte['firma_ort'] }} — im Folgenden „der Dienstgeber“ — und {{ werte['mitarbeiter'] }}, {{ werte['mitarbeiter_strasse'] }}, {{ werte['mitarbeiter_plz'] }} {{ werte['mitarbeiter_ort'] }} — im Folgenden „der Dienstnehmer“. 1. Der Dienstnehmer wird ab {{ werte['ead'] }} als {{ werte['funktion'] }} angestellt. Übertragen werden ihm insbesondere folgende Tätigkeiten: 2. Der Dienstnehmer hat die übertragenen Tätigkeiten mit der Sorgfalt eines ordentlichen Dienstnehmers auszuüben; im Bedarfsfall sind auch verwandte Tätigkeiten nach Weisung des Dienstgebers zu verrichten. Dienstort ist {{ werte['dienstort'] }}. Der Dienstnehmer verpflichtet sich, im Interesse des Dienstgebers auch außerhalb des Dienstortes vorübergehend tätig zu werden, wenn dies die Tätigkeit erfordert. Die Einstufung erfolgt gemäß den anwendbaren kollektivvertraglichen Bestimmungen: {{ werte['einstufung'] }}. 1. Für die geleisteten Dienste gebührt dem Dienstnehmer ein Monatsentgelt von EUR {{ werte['entgelt'] }} brutto, zahlbar monatlich nach Maßgabe der kollektivvertraglichen Bestimmungen ({{ werte['kv_verweis'] }}). 2. Sonderzahlungen gebühren gemäß den anwendbaren kollektivvertraglichen Bestimmungen; die Abrechnung erfolgt nach den jeweils geltenden lohnsteuerlichen Vorgaben. 1. Die regelmäßige Dienstzeit beträgt {{ werte['arbeitszeit'] }} je Woche, verteilt auf fünf Arbeitstage von Montag bis Freitag. Die Lage der Tagesarbeitszeit wird mit dem Dienstgeber vereinbart. 2. Mehr- und Überstunden sind nach den Bestimmungen des Arbeitszeitgesetzes zu leisten; der Abgeltung liegen die anwendbaren kollektivvertraglichen Bestimmungen zugrunde. Spesen im Zusammenhang mit der Dienstausübung werden nach den geltenden Regelungen des Dienstgebers abgerechnet. Der Dienstnehmer hat Anspruch auf bezahlten Urlaub im Ausmaß von {{ werte['urlaub_tage'] }} Arbeitstagen je Dienstjahr; im Übrigen gelten die Bestimmungen des Urlaubs- und Abfertigungsgesetzes. Bei Dienstverhinderung gelten die gesetzlichen Bestimmungen über die Entgeltfortzahlung. 1. Das Dienstverhältnis beginnt am {{ werte['ead'] }} und wird auf unbestimmte Zeit geschlossen. 2. Das Dienstverhältnis kann von beiden Vertragsparteien unter Einhaltung der gesetzlichen bzw. kollektivvertraglich vereinbarten Kündigungsfristen ordentlich gekündigt werden; geltend ist die Frist {{ werte['kuendigung_frist'] }}. {{ werte['geheimhaltung'] }} {{ werte['konkurrenzklausel'] }} 1. Abfertigungsansprüche richten sich nach den Bestimmungen des BMSVG. 2. Nebenabreden und Änderungen dieses Vertrages bedürfen der Schriftform; mündliche Nebenabreden bestehen nicht. 3. Sollte eine Bestimmung dieses Vertrages unwirksam sein, bleibt die Wirksamkeit der übrigen Bestimmungen unberührt; an deren Stelle tritt eine wirksame Bestimmung mit gleichem wirtschaftlichem Gehalt. Ort, Datum: {{ werte['ort_datum'] }} {{ werte['firma'] }} An {{ werte['anrede'] }} {{ werte['mitarbeiter'] }} {{ werte['ort_datum'] }} {{ werte['anrede'] }}, leider sehen wir uns gezwungen, das mit Ihnen bestehende Dienstverhältnis ordentlich, fristgerecht aufzukündigen. Es endet demnach am {{ werte['beendigungstermin'] }}. Die Kündigung erfolgt unter Einhaltung der für Ihr Dienstverhältnis geltenden Kündigungsfrist von {{ werte['kuendigung_frist'] }}. Hinsichtlich Ihres bestehenden Resturlaubs bieten wir an, diesen in der Zeit von {{ werte['urlaub_rest'] }} zu verbrauchen. Weiters teilen wir mit, dass wir Sie in der Zeit von {{ werte['freistellung'] }} bezahlt vom Dienst freistellen. Um den Erhalt dieses Schreibens zu bestätigen, ersuchen wir Sie, die beiliegende Kopie zu unterfertigen und zurückzusenden. {{ werte['firma'] }} Erhalten am: ____________ {{ werte['firma'] }}, {{ werte['firma_strasse'] }}, {{ werte['firma_plz'] }} {{ werte['firma_ort'] }} — im Folgenden „der Dienstgeber“ — und {{ werte['mitarbeiter'] }}, {{ werte['mitarbeiter_strasse'] }}, {{ werte['mitarbeiter_plz'] }} {{ werte['mitarbeiter_ort'] }} — im Folgenden „die Dienstnehmerin/der Dienstnehmer“ — Die Parteien lösen das seit {{ werte['seit'] }} bestehende Dienstverhältnis einvernehmlich zum {{ werte['beendigungstermin'] }} auf. Mit diesem Tag endet das Dienstverhältnis; dieser Tag ist auch der letzte Arbeitstag. Ein offenes Zeitguthaben von {{ werte['zeitguthaben'] }} wird in der Zeit von {{ werte['zeitguthaben_zeit'] }} verbraucht. Offener Urlaub im Ausmaß von {{ werte['urlaub_rest'] }} wird in der Zeit von {{ werte['urlaub_zeit'] }} aufgebraucht. Die Dienstnehmerin/der Dienstnehmer wird in der Zeit von {{ werte['freistellung'] }} bezahlt vom Dienst freigestellt. Die letzte Entgeltabrechnung erfolgt zur gebührenden Ausfolgung mit der Beendigung; Urlaubsersatzleistungen und ausständige Beträge werden mit der Endabrechnung ausgewiesen. Die Dienstnehmerin/der Dienstnehmer verpflichtet sich, sämtliche Betriebsgegenstände, Dokumente und Zugänge bis zum Ende des Dienstverhältnisses zurückzustellen. Sämtliche gegenseitigen Ansprüche aus dem Dienstverhältnis — soweit gesetzlich zulässig und abweichend nicht geregelt — gelten mit diesem Tag als abgegolten. Änderungen dieser Vereinbarung bedürfen der Schriftform. Ort, Datum: {{ werte['ort_datum'] }} {{ werte['firma'] }}, {{ werte['firma_strasse'] }}, {{ werte['firma_plz'] }} {{ werte['firma_ort'] }} Wir, {{ werte['firma'] }}, bestätigen, dass {{ werte['mitarbeiter'] }}, geboren am {{ werte['geboren'] }}, in der Zeit von {{ werte['von'] }} bis {{ werte['bis'] }} bei uns beschäftigt war und anlässlich der Beendigung des Dienstverhältnisses: Die Bestätigung dient der Anrechnung von Vordienstzeiten für die Einstufung beim neuen Dienstgeber. Datum: {{ werte['ort_datum'] }} firmenmäßige Zeichnung: ________________________
{{ werte['firma_strasse'] }}
{{ werte['firma_plz'] }} {{ werte['firma_ort'] }}Dienstvertrag
+ I. Tätigkeitsbereich
+
{{ werte['taetigkeit'] }}II. Dienstort
+ III. Einstufung
+ IV. Entgelt
+ V. Arbeitszeit, Mehr- und Überstunden
+ VI. Spesen
+ VII. Urlaub
+ VIII. Entgeltfortzahlung
+ IX. Dauer
+ X. Geheimhaltung
+ XI. Nebentätigkeit/Konkurrenzklausel
+ XII. Schlussbestimmungen
+
Dienstgeber: ________________________
Dienstnehmer: ______________________
{{ werte['firma_strasse'] }}
{{ werte['firma_plz'] }} {{ werte['firma_ort'] }}
{{ werte['mitarbeiter_strasse'] }}
{{ werte['mitarbeiter_plz'] }} {{ werte['mitarbeiter_ort'] }}Kündigung des Dienstverhältnisses
+
______________________
Dienstgeber
Unterschrift Dienstnehmer:in: ______________________Vereinbarung über die einvernehmliche Auflösung des Dienstverhältnisses
+
Dienstgeber: ________________________
Dienstnehmer:in: ______________________Bestätigung über Vordienstzeiten
+
+
+
Firma: {{ werte[\'firma\'] }}
' + 'Mitarbeiter: {{ werte[\'mitarbeiter\'] }}
' + 'Funktion: {{ werte[\'funktion\'] }}
' + 'EAD: {{ werte[\'ead\'] }}
' + 'Zusatz: {{ werte[\'zusatz\'] }}
', + 'feld_ids': [ + (0, 0, {'sequence': 1, 'key': 'zusatz', + 'quelle': 'manuell', 'pflicht': True, + 'bezeichnung': 'Zusatzangabe'}), + (0, 0, {'sequence': 2, 'key': 'firma', 'quelle': 'auto', + 'pflicht': True}), + (0, 0, {'sequence': 3, 'key': 'mitarbeiter', + 'quelle': 'auto', 'pflicht': True}), + (0, 0, {'sequence': 4, 'key': 'funktion', 'quelle': 'auto', + 'pflicht': False}), + (0, 0, {'sequence': 5, 'key': 'ead', 'quelle': 'auto', + 'pflicht': False}), + ], + }) + + def _wizard(self): + wizard = self.env['l10n.at.payroll.dokument.wizard'].create({ + 'vorlage_id': self.vorlage.id, + 'employee_id': self.employee.id, + 'datum': datetime.date(2026, 1, 15), + }) + wizard.action_befuellen() + return wizard + + def test_01_auto_werte(self): + wizard = self._wizard() + wizard.feld_wert_ids.filtered( + lambda l: l.key == 'zusatz').wert = 'X' + werte = wizard._at_werte() + self.assertEqual(werte['firma'], 'Musterwerkstatt GmbH') + self.assertEqual(werte['mitarbeiter'], 'Dokument Test') + self.assertEqual(werte['funktion'], 'Techniker') + self.assertTrue(werte['ead']) + + def test_02_vorschau_ersetzt_platzhalter(self): + wizard = self._wizard() + wizard.feld_wert_ids.filtered( + lambda l: l.key == 'zusatz').wert = 'Projekt Alpha' + wizard.action_vorschau() + vorschau = wizard.vorschau_html + self.assertIn('Musterwerkstatt GmbH', vorschau) + self.assertIn('Dokument Test', vorschau) + self.assertIn('Projekt Alpha', vorschau) + self.assertNotIn('{{', vorschau) + + def test_03_pflichtfeld_leist_user_error(self): + wizard = self._wizard() + with self.assertRaises(UserError): + wizard._at_werte() + + def test_04_version_am_stichtag(self): + self.env['hr.version'].create({ + 'employee_id': self.employee.id, + 'date_version': datetime.date(2026, 3, 1), + 'job_title': 'Senior Techniker', + }) + wizard = self._wizard() + self.assertEqual(wizard.version_id.job_title, 'Techniker') + wizard.datum = datetime.date(2026, 6, 1) + wizard._compute_version_id() + self.assertEqual(wizard.version_id.job_title, 'Senior Techniker') + + def test_05_pdf_ablegt_anhang(self): + wizard = self._wizard() + wizard.feld_wert_ids.filtered( + lambda l: l.key == 'zusatz').wert = 'Fall 5' + wizard.action_pdf() + anh = self.env['ir.attachment'].search( + [('res_model', '=', 'hr.employee'), + ('res_id', '=', self.employee.id)]) + self.assertEqual(len(anh), 1) + self.assertIn(anh.mimetype, ('application/pdf', 'text/html')) + if anh.mimetype == 'text/html': + html = base64.b64decode(anh.datas).decode('utf-8') + self.assertIn('Fall 5', html) + + def test_06_report_values_generic(self): + wizard = self._wizard() + report = self.env[ + 'report.l10n_at_payroll_dokumente' + '.report_dokument_generisch'] + values = report._get_report_values( + wizard.ids, data={'titel': 'T', 'body': 'Body
'}) + self.assertEqual(str(values['body']), 'Body
') + html_content, _typ = self.env['ir.actions.report']._render_qweb_html( + 'l10n_at_payroll_dokumente.action_report_dokument_generisch', + wizard.ids, data={'titel': 'T', 'body': values['body']}) + self.assertIn('Body', str(html_content)) + + def test_07_access_hr_user_lesen_manager_schreiben(self): + hr_user = self.env['res.users'].create({ + 'name': 'Dokument Lesetest', + 'login': 'dok_lesetest', + 'group_ids': [(4, self.env.ref('hr.group_hr_user').id)], + }) + umgebung = self.env(user=hr_user.id) + self.assertTrue( + umgebung['l10n.at.payroll.dokument.vorlage'].browse( + self.vorlage.id).name) + kein_hr = self.env['res.users'].create({ + 'name': 'Dokument Ohne HR', + 'login': 'dok_ohne_hr', + 'group_ids': [(4, self.env.ref('base.group_user').id)], + }) + ohne = self.env(user=kein_hr.id) + with self.assertRaises(AccessError): + ohne['l10n.at.payroll.dokument.vorlage'].browse( + self.vorlage.id).name + + def test_08_pilot_vorlagen_installiert(self): + for xmlid in ('vorlage_dienstvertrag_angestellte', + 'vorlage_kuendigung_dienstgeber', + 'vorlage_einvernehmliche_aufloesung', + 'vorlage_vordienstzeiten'): + vorlage = self.env.ref( + 'l10n_at_payroll_dokumente.%s' % xmlid) + self.assertTrue(vorlage.inhalt_html) + self.assertEqual(vorlage.rechtsstatus, 'entwurf') + kuendigung = self.env.ref( + 'l10n_at_payroll_dokumente.vorlage_kuendigung_dienstgeber') + wizard = self.env['l10n.at.payroll.dokument.wizard'].create({ + 'vorlage_id': kuendigung.id, + 'employee_id': self.employee.id, + 'datum': datetime.date(2026, 9, 1), + }) + wizard.action_befuellen() + wizard.feld_wert_ids.filtered( + lambda l: l.key == 'anrede').wert = 'Sehr geehrter Herr' + wizard.feld_wert_ids.filtered( + lambda l: l.key == 'kuendigung_frist').wert = '6 Wochen' + wizard.feld_wert_ids.filtered( + lambda l: l.key == 'beendigungstermin').wert = '31.10.2026' + wizard.feld_wert_ids.filtered( + lambda l: l.key == 'ort_datum').wert = 'Wien, 1.9.2026' + wizard.action_vorschau() + self.assertIn('31.10.2026', wizard.vorschau_html) + self.assertIn('Musterwerkstatt GmbH', wizard.vorschau_html) \ No newline at end of file diff --git a/addons/l10n_at_payroll_dokumente/views/dokument_vorlage_views.xml b/addons/l10n_at_payroll_dokumente/views/dokument_vorlage_views.xml new file mode 100644 index 0000000..b5e2a7e --- /dev/null +++ b/addons/l10n_at_payroll_dokumente/views/dokument_vorlage_views.xml @@ -0,0 +1,92 @@ + ++ Erste Dokumentvorlage anlegen +
++ Eigener Text mit Platzhaltern {{ werte['key'] }}; die + Befüllfelder steuern, was der Generierungs-Wizard abfragt. +
+