# Part of the odoo-at-payroll project. License: LGPL-3. """GP8 Kern: Fristenkalender (Auto-Erzeugung, Frist-Typen, Überfällig- Logik), Jahres-Retro (Kontrollsechstel-Prüfung), Mitteilungsfile-Parser.""" from datetime import date from odoo.tests import TransactionCase, tagged from odoo.addons.l10n_at_hr_payroll.models.fristenkalender import ( FRISTART_DEFINITIONEN, ) @tagged('post_install', '-at_install') class FristenTest(TransactionCase): def test_01_frist_definitionen(self): """Alle Fristarten sind definiert mit Name/Deadline-Logik.""" for art, definition in FRISTART_DEFINITIONEN.items(): self.assertIn('name', definition) self.assertIn('hilfetext', definition) self.assertTrue( 'monatlich' in definition or 'monat' in definition, 'Fristart %s ohne Fälligkeits-Logik' % art) def test_02_cron_erzeugt_fristen(self): """Cron erzeugt monatliche SV/DB-Fristen idempotent + jährliche Fristen am 1. Jänner.""" frist = self.env['l10n.at.payroll.frist'] company = self.env.company # Manueller Cron-Lauf (heute ist ein Tag im Jahr). frist._cron_fristen_erzeugen() # Monatliche Fristen existieren für den Vormonat. heute = date.today() vormonat = (heute.replace(day=1) - __import__('datetime') .timedelta(days=1)) monatliche = frist.search([ ('company_id', '=', company.id), ('fristart', 'in', ('sv_mbgm', 'db_dz_kommst')), ('jahr', '=', vormonat.year), ('monat', '=', vormonat.month)]) self.assertEqual(len(monatliche), 2) # Idempotenz: zweiter Lauf erzeugt keine Duplikate. frist._cron_fristen_erzeugen() monatliche2 = frist.search([ ('company_id', '=', company.id), ('fristart', 'in', ('sv_mbgm', 'db_dz_kommst')), ('jahr', '=', vormonat.year), ('monat', '=', vormonat.month)]) self.assertEqual(len(monatliche2), 2) def test_03_state_ueberfaellig(self): """Überfällige Fristen markieren sich nach Deadline- Überschreitung; action_erledigt setzt erledigt.""" frist = self.env['l10n.at.payroll.frist'].create({ 'company_id': self.env.company.id, 'fristart': 'l16', 'jahr': 2025, 'monat': 0, 'deadline': '2026-01-01', }) self.assertEqual(frist.state, 'ueberfaellig') frist.action_erledigt() self.assertEqual(frist.state, 'erledigt') self.assertTrue(frist.erledigt_am) @tagged('post_install', '-at_install') class MitteilungsfileTest(TransactionCase): def test_01_parse_mitteilungsfile(self): """XML-Parser extrahiert Fehler-/Warnung-Elemente.""" wizard = self.env['l10n.at.payroll.mitteilungsfile.wizard'] xml = """ """ zeilen = wizard._parse_mitteilungsfile(xml) self.assertIn('Sendungsstatus: ok', zeilen) self.assertTrue(any('F0100' in z for z in zeilen)) self.assertTrue(any('W0102' in z for z in zeilen)) self.assertTrue(any('STEUERNUMMER' in z for z in zeilen)) def test_02_import_ohne_datei(self): """Import ohne Datei löst UserError.""" from odoo.exceptions import UserError wizard = self.env['l10n.at.payroll.mitteilungsfile.wizard'] \ .create({'company_id': self.env.company.id}) with self.assertRaises(UserError): wizard.action_importieren() @tagged('post_install', '-at_install') class JahresretroTest(TransactionCase): def test_01_wizard_ohne_daten(self): """Wizard ohne Läufe im Jahr: leeres Ergebnis, keine Fehler.""" wizard = self.env['l10n.at.payroll.jahresretro.wizard'].create({ 'company_id': self.env.company.id, 'jahr': 1999, # weit in der Vergangenheit }) wizard.action_pruefen() self.assertFalse(wizard.ergebnis_ids) self.assertIn('1999', wizard.zusammenfassung)