[IMP] l10n_at_hr_payroll_private: Sachbezüge (AP12)

This commit is contained in:
2026-09-14 12:22:15 +02:00
parent 018554b215
commit 8efea77b6c
20 changed files with 1606 additions and 23 deletions
@@ -37,6 +37,18 @@ from odoo.tools.safe_eval import safe_eval
class HrSalaryRule(models.Model):
_inherit = 'hr.salary.rule'
l10n_at_sv_art = fields.Selection(
[('folgt', 'Folgt AT LSt-Bemessungsart'),
('laufend', 'Laufender SV-Bezug'),
('sonstig', 'Sonstiger SV-Bezug'),
('keine', 'Kein SV-Bezug')],
string='AT SV-Bemessungsart',
default='folgt',
help='Steuert ausschließlich die SV-Zuordnung. Standard „Folgt“ '
'übernimmt die AT LSt-Bemessungsart und ist damit '
'rückwärtskompatibel. Abweichung für Drittlohn oder '
'abweichende LSt-/SV-Zuordnung, z. B. Bonusmeilen oder '
'Hardware-Verkauf.')
l10n_at_sv49_frei = fields.Selection(
[('keine', 'Keine §-49-Abs-3-Befreiung'),
('mahlzeit', 'Mahlzeiten-Gutschein (§ 49 Abs 3 Z 12; 8 €/AT)'),
@@ -254,7 +266,7 @@ class HrPayslip(models.Model):
for rule in self.struct_id.rule_ids:
kategorie = rule.l10n_at_sv49_frei
if (not kategorie or kategorie == 'keine'
or rule.l10n_at_bemessung != 'laufend'):
or self._l10n_at_sv_art(rule) != 'laufend'):
continue
werte = None
if result_rules is not None:
@@ -297,11 +309,33 @@ class HrPayslip(models.Model):
# ------------------------------------------------------------------
# Laufende Beitragsgrundlage — je Beitragsmonat (Anspruchsprinzip)
# ------------------------------------------------------------------
def _l10n_at_sv_art(self, rule):
"""Effektive SV-Art einer Regel; Standard folgt der LSt-Art."""
self.ensure_one()
return (rule.l10n_at_bemessung if rule.l10n_at_sv_art == 'folgt'
else rule.l10n_at_sv_art)
def _l10n_at_sv_brutto(self, art, result_rules=None):
"""SV-Brutto je Art; abweichende SV-Zuordnung bleibt von der
LSt-Bemessungsart getrennt (Drittlohn/Sonderfälle)."""
self.ensure_one()
total = 0.0
for rule in self.struct_id.rule_ids:
if self._l10n_at_sv_art(rule) != art:
continue
if result_rules is not None:
if rule.code in result_rules:
total += result_rules[rule.code].get('total', 0.0)
else:
total += sum(self.line_ids.filtered(
lambda l: l.code == rule.code).mapped('total'))
return total
def _l10n_at_sv_basis_roh(self, result_rules=None):
"""Laufender Arbeitslohn minus beitragsfreie §-49-Anteile
"""Laufendes SV-Brutto minus beitragsfreie §-49-Anteile
(vor HBG-Cap; Geringfügigkeits-/Staffel-Basis)."""
self.ensure_one()
roh = self._l10n_at_brutto('laufend', result_rules) \
roh = self._l10n_at_sv_brutto('laufend', result_rules) \
- self._l10n_at_sv49_freie_laufen(result_rules)
return max(roh, 0.0)
@@ -312,7 +346,7 @@ class HrPayslip(models.Model):
self.ensure_one()
gruppen = {}
for rule in self.struct_id.rule_ids:
if rule.l10n_at_bemessung != 'laufend':
if self._l10n_at_sv_art(rule) != 'laufend':
continue
werte = None
if result_rules is not None: