mirror of
http://100.103.83.12:3003/fegger/odoo-at-payroll.git
synced 2026-09-17 08:52:45 +00:00
[IMP] l10n_at_hr_payroll_private: add premiums at termination under § 16 AngG (AP14-B)
Close the premium-at-termination gap of the end-of-employment cycle: an aliquote periodic premium (annual, sales, bonus, 15th payment) whose entitlement period outlasts the termination is covered by § 16 AngG — the pro-rata amount follows the ratio of the elapsed service to the entitlement period, is due for employees regardless of the termination ground (loss clauses void, 9 ObA 82/13v), while performance-linked premiums for workers may validly hinge on non-fault grounds and premiums tied to a specific service (e.g. Bilanzgeld) are not aliquote without the service (lb-end-18). Two routes: PRAM_END (bemessung sonstig) covers premiums paid with the end-of-employment run — a special payment inside the annual sixth at the flat 6 % rate with the 620 EUR free amount and 2 615 EUR free threshold checked by the core, SV as special-payment contributions (KV/PV/AV without AK/WF) against the monthly HBG and the annual SZ cap, fully payroll-levy liable and BV-contributory at the uncapped 1.53 % rate (§ 6 Abs 1 iVm Abs 5 BMSVG). PRAM_END_TARIF (bemessung laufend plus the core l10n_at_s67_abs6_ueberhang flag) covers premiums due at a pre-agreed maturity because their amount only becomes determinable after the entitlement period ends (e.g. balance-sheet premiums): taxed like running pay with the payment-month tariff without touching the annual sixth (§ 67 Abs 10, not a § 67 Abs 8 lit c case per 98/14/0009 = ARD 5483/14/2004) — the SV contribution month rolls back into the termination year via a new payslip field consumed by an extended branch of the existing SV-basis-by-Beitragsmonat override (historical caps and rates, E-MVB 044-01-00-006), while the LSt stays in the payment month. The wizard section previews the § 16 pro-rata amount from the full premium, entitlement period and elapsed service, keeps the payable amount confirmable (KB agreement), requires the service/claim-basis confirmation, enforces the contribution month for the deferred case, and lands the memo on the payslip for the separate Lohnzettel workflow (LStR Rz 911a); the existing manual PRAM rule is untouched. The account matrix posts both rules to 6230. Verified against the original statute text in .ris/ (AngG § 16, BMSVG § 6 Abs 5) and the knowledge-base source lb-end-18; the full SZ roll-forward (storno plus recomputation against the termination year's SZ annual cap) and the mBGM storno/re-transmission remain open in the GP7 payroll-reporting track, and the BV attribution of the deferred premium remains in the payment month as a documented approximation. Version 19.0.16.0.0 (private)
This commit is contained in:
@@ -183,6 +183,62 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
help='Vergleichstext, strittige Ansprüche, erkennbare '
|
||||
'Abfertigungsanteile, BV-Zeiträume und allfälliger '
|
||||
'Verhältnisfaktor dokumentieren.')
|
||||
pram_aktiv = fields.Boolean(
|
||||
string='Prämie bei Beendigung (§ 16 AngG)',
|
||||
help='Aliquote periodische Prämie/Sonderzahlung (Jahres-, '
|
||||
'Umsatzprämie, Bonifikation, 15. Bezug), deren Anspruchs-'
|
||||
'zeitraum bei der Beendigung noch nicht abgelaufen ist '
|
||||
'(lb-end-18).')
|
||||
pram_zahlungsart = fields.Selection(
|
||||
[('mit_endabrechnung',
|
||||
'Mit der Endabrechnung ausgezahlt (sonstiger Bezug, '
|
||||
'Jahressechstel)'),
|
||||
('spaeter_faellig',
|
||||
'Später fällig (§ 67 Abs 10 — Tarif im Zahlungsmonat, '
|
||||
'ohne Sechstel; gesonderter Lohnzettel)')],
|
||||
string='Zahlungs-/Fälligkeitsart', default='mit_endabrechnung',
|
||||
help='Wird die Prämie erst zum im Vorhinein vereinbarten '
|
||||
'Fälligkeitszeitpunkt fällig, weil ihre Höhe erst nach '
|
||||
'Ablauf der Anspruchsperiode ermittelbar ist (z. B. '
|
||||
'Bilanzprämie), liegt keine Nachzahlung vor und läuft die '
|
||||
'Besteuerung über § 67 Abs 10 (lb-end-18).')
|
||||
pram_anspruchszeitraum_monate = fields.Integer(
|
||||
string='Anspruchszeitraum (Monate)', default=12,
|
||||
help='Dienstperiode, für die die Prämie gewährt wird — z. B. '
|
||||
'Kalenderjahr = 12 Monate (§ 16 AngG).')
|
||||
pram_dienstzeit_monate = fields.Integer(
|
||||
string='Zurückgelegte Dienstzeit im Anspruchszeitraum (Monate)',
|
||||
help='Grundlage der §-16-Aliquot-Vorschau; der tatsächliche '
|
||||
'Betrag folgt der KV-/Vertragsvereinbarung und bleibt '
|
||||
'bestätigbar.')
|
||||
pram_voller_betrag = fields.Monetary(
|
||||
string='Voller Prämien-Betrag (vor Aliquotierung)',
|
||||
currency_field='currency_id',
|
||||
help='Betrag für die gesamte Anspruchsperiode — Basis der '
|
||||
'§-16-Aliquot-Vorschau.')
|
||||
pram_betrag = fields.Monetary(
|
||||
string='Zu zahlender (aliquote) Brutto-Betrag',
|
||||
currency_field='currency_id')
|
||||
pram_beitragsmonat = fields.Date(
|
||||
string='SV-Beitragsmonat (Rollung ins Austrittsjahr)',
|
||||
help='Nur bei späterer Fälligkeit: Beitragsmonat, dem die '
|
||||
'Prämie sv-rechtlich zuzuordnen ist — der Zeitraum, in dem '
|
||||
'die Leistungen erbracht wurden (E-MVB 044-01-00-006). '
|
||||
'Die mBGM-Storno-/Neuübermittlung erfolgt im GP7-Track.')
|
||||
pram_leistung_bestaetigt = fields.Boolean(
|
||||
string='Leistungs-/Anspruchsgrundlage bestätigt',
|
||||
help='Bestätigung, dass die Prämie nicht an eine noch nicht '
|
||||
'erbrachte spezifische Leistung gebunden ist (z. B. '
|
||||
'Bilanzgeld — kein aliquoter Anspruch ohne Tätigkeit) und '
|
||||
'allfällige leistungsabhängige Verlustklauseln (nur '
|
||||
'Arbeiter, wirksam nur bei schuldhaftem Beendigungsgrund) '
|
||||
'geprüft sind. Für Angestellte gebührt die aliquote Prämie '
|
||||
'unabhängig von der Art der Beendigung (§ 16 AngG).')
|
||||
pram_nachweis = fields.Text(
|
||||
string='Nachweis/Begründung',
|
||||
help='KV-/Vertragsvereinbarung, Anspruchszeitraum, '
|
||||
'Aliquotierung, Fälligkeitszeitpunkt und '
|
||||
'Leistungsverknüpfung dokumentieren.')
|
||||
currency_id = fields.Many2one(
|
||||
'res.currency', default=lambda self: self.env.company.currency_id)
|
||||
|
||||
@@ -240,6 +296,9 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
vergleich_bv_lst_vorschau = fields.Monetary(
|
||||
string='LSt 6 % BV-Teil (Vorschau)', currency_field='currency_id',
|
||||
compute='_compute_vorschau')
|
||||
pram_aliquot_vorschau = fields.Monetary(
|
||||
string='§-16-Aliquote Prämie (Vorschau)',
|
||||
currency_field='currency_id', compute='_compute_vorschau')
|
||||
|
||||
@api.onchange('employee_id')
|
||||
def _onchange_employee(self):
|
||||
@@ -253,6 +312,31 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
wizard._at_abf_alt_vorschlag_setzen()
|
||||
wizard._at_abf_frei_vorschlag_setzen()
|
||||
|
||||
@api.onchange('pram_aktiv', 'pram_voller_betrag',
|
||||
'pram_dienstzeit_monate', 'pram_anspruchszeitraum_monate')
|
||||
def _onchange_pram(self):
|
||||
for wizard in self:
|
||||
if not wizard.pram_aktiv:
|
||||
continue
|
||||
aliquote = wizard._at_pram_aliquot()
|
||||
if aliquote and not wizard.pram_betrag:
|
||||
wizard.pram_betrag = aliquote
|
||||
|
||||
def _at_pram_aliquot(self):
|
||||
"""§ 16 AngG (Originalwortlaut): Betrag, der dem Verhältnis
|
||||
zwischen der Dienstperiode des Anspruchs und der zurückgelegten
|
||||
Dienstzeit entspricht."""
|
||||
self.ensure_one()
|
||||
if (not self.pram_anspruchszeitraum_monate
|
||||
or self.pram_anspruchszeitraum_monate < 0
|
||||
or self.pram_dienstzeit_monate < 0
|
||||
or not self.pram_voller_betrag):
|
||||
return 0.0
|
||||
return (self.pram_voller_betrag
|
||||
* min(self.pram_dienstzeit_monate,
|
||||
self.pram_anspruchszeitraum_monate)
|
||||
/ self.pram_anspruchszeitraum_monate)
|
||||
|
||||
@api.onchange('austrittsdatum', 'abf_alt_anspruchsart',
|
||||
'abf_alt_dienstzeit_monate', 'abf_alt_aktiv',
|
||||
'abf_alt_monatsentgelt', 'abf_alt_mehrfach',
|
||||
@@ -306,7 +390,10 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
'abf_frei_erhaltene_abfertigungen',
|
||||
'abf_frei_gesetzlicher_anspruch',
|
||||
'vergleich_aktiv', 'vergleich_rest_betrag',
|
||||
'vergleich_bv_betrag')
|
||||
'vergleich_bv_betrag',
|
||||
'pram_aktiv', 'pram_voller_betrag',
|
||||
'pram_dienstzeit_monate',
|
||||
'pram_anspruchszeitraum_monate')
|
||||
def _compute_vorschau(self):
|
||||
for wizard in self:
|
||||
wizard.uel_lfd_vorschau = 0.0
|
||||
@@ -327,6 +414,7 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
wizard.vergleich_fuenftel_frei_vorschau = 0.0
|
||||
wizard.vergleich_tarif_basis_vorschau = 0.0
|
||||
wizard.vergleich_bv_lst_vorschau = 0.0
|
||||
wizard.pram_aliquot_vorschau = 0.0
|
||||
if not wizard.employee_id or not wizard.austrittsdatum:
|
||||
continue
|
||||
slip = wizard._vorschau_payslip()
|
||||
@@ -369,6 +457,7 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
slip._at_fuenftel_tarif_basis()
|
||||
wizard.vergleich_bv_lst_vorschau = \
|
||||
slip._at_vergleich_bv_lst_6()
|
||||
wizard.pram_aliquot_vorschau = wizard._at_pram_aliquot()
|
||||
|
||||
def _vorschau_payslip(self):
|
||||
"""Flüchtiger Payslip-Kontext für die Vorschau-Berechnung (kein
|
||||
@@ -405,6 +494,7 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
self.abf_frei_gesetzlicher_anspruch,
|
||||
'l10n_at_abf_frei_nachweis': self.abf_frei_nachweis,
|
||||
'l10n_at_vergleich_nachweis': self.vergleich_nachweis,
|
||||
'l10n_at_pram_nachweis': self.pram_nachweis,
|
||||
})
|
||||
eingaben = [
|
||||
('ATP_UEL_TAGE', self.uel_tage),
|
||||
@@ -416,6 +506,12 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
if self.vergleich_aktiv else 0.0),
|
||||
('ATP_VERGLEICH_BV', self.vergleich_bv_betrag
|
||||
if self.vergleich_aktiv else 0.0),
|
||||
('ATP_PRAM_END', self.pram_betrag
|
||||
if self.pram_aktiv
|
||||
and self.pram_zahlungsart == 'mit_endabrechnung' else 0.0),
|
||||
('ATP_PRAM_END_TARIF', self.pram_betrag
|
||||
if self.pram_aktiv
|
||||
and self.pram_zahlungsart == 'spaeter_faellig' else 0.0),
|
||||
]
|
||||
slip.input_line_ids = [
|
||||
(0, 0, {
|
||||
@@ -444,6 +540,12 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
if self.vergleich_aktiv else 0.0),
|
||||
('ATP_VERGLEICH_BV', self.vergleich_bv_betrag
|
||||
if self.vergleich_aktiv else 0.0),
|
||||
('ATP_PRAM_END', self.pram_betrag
|
||||
if self.pram_aktiv
|
||||
and self.pram_zahlungsart == 'mit_endabrechnung' else 0.0),
|
||||
('ATP_PRAM_END_TARIF', self.pram_betrag
|
||||
if self.pram_aktiv
|
||||
and self.pram_zahlungsart == 'spaeter_faellig' else 0.0),
|
||||
]
|
||||
|
||||
def _abf_alt_validieren(self):
|
||||
@@ -535,6 +637,34 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
'Zeiträume voraus (§ 67 Abs 8 lit a letzter '
|
||||
'Satz).'))
|
||||
|
||||
def _pram_validieren(self):
|
||||
self.ensure_one()
|
||||
if not self.pram_aktiv:
|
||||
return
|
||||
if not self.pram_leistung_bestaetigt:
|
||||
raise UserError(_('Bitte die Leistungs-/Anspruchsgrundlage '
|
||||
'der Prämie bestätigen (lb-end-18).'))
|
||||
if self.pram_betrag <= 0:
|
||||
raise UserError(_('Der zu zahlende Prämien-Betrag muss '
|
||||
'größer als null sein.'))
|
||||
if (self.pram_anspruchszeitraum_monate < 0
|
||||
or self.pram_dienstzeit_monate < 0
|
||||
or self.pram_voller_betrag < 0):
|
||||
raise UserError(_('Anspruchszeitraum, Dienstzeit und '
|
||||
'voller Betrag dürfen nicht negativ '
|
||||
'sein.'))
|
||||
if (self.pram_anspruchszeitraum_monate
|
||||
and self.pram_dienstzeit_monate
|
||||
> self.pram_anspruchszeitraum_monate):
|
||||
raise UserError(_('Die zurückgelegte Dienstzeit kann den '
|
||||
'Anspruchszeitraum nicht übersteigen.'))
|
||||
if (self.pram_zahlungsart == 'spaeter_faellig'
|
||||
and not self.pram_beitragsmonat):
|
||||
raise UserError(_('Bei späterer Fälligkeit ist der SV-'
|
||||
'Beitragsmonat der Rollung ins '
|
||||
'Austrittsjahr erforderlich '
|
||||
'(E-MVB 044-01-00-006).'))
|
||||
|
||||
def action_payslip(self):
|
||||
"""Endabrechnungs-Lauf im Austrittsmonat anlegen und die
|
||||
gesammelten offenen Posten als Eingaben vorbefüllen."""
|
||||
@@ -542,6 +672,7 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
self._abf_alt_validieren()
|
||||
self._abf_frei_validieren()
|
||||
self._vergleich_validieren()
|
||||
self._pram_validieren()
|
||||
erster = self.austrittsdatum.replace(day=1)
|
||||
letzter = (erster + timedelta(days=32)).replace(day=1) \
|
||||
- timedelta(days=1)
|
||||
@@ -587,6 +718,11 @@ class L10nAtEndabrechnungWizard(models.TransientModel):
|
||||
self.abf_frei_nachweis if self.abf_frei_aktiv else False,
|
||||
'l10n_at_vergleich_nachweis':
|
||||
self.vergleich_nachweis if self.vergleich_aktiv else False,
|
||||
'l10n_at_pram_nachweis':
|
||||
self.pram_nachweis if self.pram_aktiv else False,
|
||||
'l10n_at_pram_beitragsmonat': self.pram_beitragsmonat
|
||||
if (self.pram_aktiv
|
||||
and self.pram_zahlungsart == 'spaeter_faellig') else False,
|
||||
})
|
||||
typen = {code: self.env['hr.payslip.input.type'].search(
|
||||
[('code', '=', code)], limit=1)
|
||||
|
||||
Reference in New Issue
Block a user