850e99df20
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)
742 lines
38 KiB
Python
742 lines
38 KiB
Python
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||
"""AP14-A: Endabrechnungs-Wizard — sammelt die offenen Posten der
|
||
Beendigungs-Abrechnung (Urlaubsersatzleistung, Abgangsentschädigung,
|
||
Zeitguthaben/-schulden, offene Vorschüsse) und legt den
|
||
Endabrechnungs-Lauf mit vorbefüllten Eingaben an. Reiner
|
||
Sammel-/Anlageprozess; die BV-Anwartschaft läuft über den eigenen
|
||
BV-Wizard (GP5), die Pfändung über die AP11-Maschine.
|
||
AP15-C: Vergleichssumme (§ 67 Abs 8 lit a) — Rest (Fünftelregelung)
|
||
und BV-Anwartschafts-Teil (bis 7.500 € mit 6 %)."""
|
||
from datetime import timedelta
|
||
|
||
from dateutil.relativedelta import relativedelta
|
||
|
||
from odoo import _, api, fields, models
|
||
from odoo.exceptions import UserError
|
||
|
||
|
||
class L10nAtEndabrechnungWizard(models.TransientModel):
|
||
_name = 'l10n.at.payroll.endabrechnung.wizard'
|
||
_description = 'Endabrechnung (Beendigung des Dienstverhältnisses)'
|
||
|
||
employee_id = fields.Many2one(
|
||
'hr.employee', string='Dienstnehmer:in', required=True)
|
||
austrittsdatum = fields.Date(
|
||
string='Austritt (Ende des Arbeitsverhältnisses)', required=True)
|
||
departure_reason_id = fields.Many2one(
|
||
'hr.departure.reason', string='Abgangsgrund', required=True,
|
||
domain="['|', ('country_id', '=', False), ('country_id.code', '=', 'AT')]",
|
||
help='Odoo-Abgangsgrund des Beschäftigtendatensatzes; die '
|
||
'Abfertigungsberechtigung wird zusätzlich ausdrücklich bestätigt.')
|
||
uel_tage = fields.Float(
|
||
string='Offene Urlaubstage (Arbeitstage)',
|
||
help='Resturlaub früherer Urlaubsjahre zur Gänze plus aliquoter '
|
||
'Anspruch des laufenden Urlaubsjahres abzüglich verbrauchter '
|
||
'Tage, ohne Rundung (§ 10 UrlG, lb-url-16). Für '
|
||
'unberechtigten vorzeitigen Austritt sind die Tage der 5. '
|
||
'und 6. Urlaubswoche des laufenden Jahres herauszurechnen.')
|
||
abgang_betrag = fields.Monetary(
|
||
string='Abgangsentschädigung (Brutto, § 67 Abs 8 lit b EStG)',
|
||
currency_field='currency_id',
|
||
help='Entschädigung für den Verzicht auf die Arbeitsleistung '
|
||
'während der (fiktiven) Kündigungsfrist — LSt: Fünftelregelung; '
|
||
'SV: Umlegung auf den Kündigungsfrist-Zeitraum (§ 11 Abs 2 '
|
||
'ASVG); voll lohnnebenkostenpflichtig.')
|
||
abgang_ffrist_tage = fields.Float(
|
||
string='Kündigungsfrist (Kalendertage)',
|
||
help='Kalendertage der (fiktiven) Kündigungsfrist, auf die die '
|
||
'pauschalierte Abgangsentschädigung sv-rechtlich umzulegen '
|
||
'ist (§ 11 Abs 2 ASVG).')
|
||
zeit_guthaben_stunden = fields.Float(
|
||
string='Zeitguthaben an Normalarbeitszeit (Stunden)',
|
||
help='Offenes Guthaben an Normalarbeitszeit aus durchrechenbarem '
|
||
'Arbeitszeitmodell — Abgeltung mit 50 % Zuschlag (§ 19e '
|
||
'Abs 2 AZG); bei unberechtigtem vorzeitigem Austritt kein '
|
||
'Zuschlag.')
|
||
zeit_schulden_stunden = fields.Float(
|
||
string='Zeitschulden (Stunden)',
|
||
help='Offene Zeitschulden (negative Zeitguthaben), abgerechnet '
|
||
'mit der aktuellen Normalstunde (lb-end-08).')
|
||
vorschuss_saldo = fields.Monetary(
|
||
string='Offener Vorschuss-/Darlehenssaldo',
|
||
currency_field='currency_id',
|
||
help='Bei Beendigung zur Gänze fälliger, noch offener '
|
||
'Vorschusssaldo (lb-end-06) — Rückverrechnung vom Netto '
|
||
'nach SV und Lohnsteuer, ohne Abgabenberührung '
|
||
'(§ 293 Abs 3 EO).')
|
||
abf_alt_aktiv = fields.Boolean(string='Gesetzliche Abfertigung Alt')
|
||
abf_alt_anspruch_bestaetigt = fields.Boolean(
|
||
string='Anspruch und Nachweise geprüft',
|
||
help='Bestätigung, dass Alt-Anwartschaft, Beendigungsgrund, '
|
||
'Dienstzeiten und Bemessungsgrundlage geprüft wurden.')
|
||
abf_alt_anspruchsart = fields.Selection(
|
||
[('normal', 'Normalanspruch (§ 23 AngG)'),
|
||
('eltern', 'Elternaustritt (§ 23a Abs 3/4 AngG)'),
|
||
('tod', 'Tod (§ 23 Abs 6 AngG)'),
|
||
('pension', 'Pension/Invalidität (§ 23a Abs 1 AngG)'),
|
||
('eingefroren', 'Eingefrorener Altanspruch (§ 47 BMSVG)'),
|
||
('manuell', 'Sonstiger nachgewiesener Anspruch')],
|
||
string='Anspruchsart', default='normal')
|
||
abf_alt_dienstzeit_monate = fields.Integer(
|
||
string='Nachgewiesene Abfertigungsdienstzeit (Monate)')
|
||
abf_alt_monatsentgelt = fields.Monetary(
|
||
string='Maßgebliches Monatsentgelt', currency_field='currency_id',
|
||
help='Bestätigte arbeitsrechtliche Bemessungsgrundlage: letzter '
|
||
'Monat einschließlich regelmäßiger Bezugsteile, Sachbezüge '
|
||
'und aliquoter Sonderzahlungen.')
|
||
abf_alt_laufender_arbeitslohn = fields.Monetary(
|
||
string='Laufender Monatsarbeitslohn (§ 67 Abs 3)',
|
||
currency_field='currency_id',
|
||
help='Laufender Arbeitslohn für den steuerlichen Vervielfacher; '
|
||
'aliquote Sonderzahlungen gehören hier nicht dazu.')
|
||
abf_alt_monatslohnsteuer = fields.Monetary(
|
||
string='Tarif-LSt des laufenden Monats', currency_field='currency_id',
|
||
help='Die auf den maßgeblichen laufenden Monatsarbeitslohn '
|
||
'entfallende tarifmäßige Lohnsteuer nach den persönlichen '
|
||
'Verhältnissen. Bei steuerfreiem Monatslohn ausdrücklich 0 '
|
||
'bestätigen.')
|
||
abf_alt_mehrfach = fields.Float(
|
||
string='Bestätigter Anspruchsfaktor',
|
||
help='§-23-Staffel, gegebenenfalls halbiert/gedeckelt oder als '
|
||
'eingefrorener beziehungsweise nachgewiesener Faktor.')
|
||
abf_alt_nachweis = fields.Text(
|
||
string='Nachweis/Begründung',
|
||
help='Quelle der Dienstzeiten, Anspruchsprüfung, Alt-/Neu-Status '
|
||
'und allfällige manuelle Abweichung dokumentieren.')
|
||
abf_frei_aktiv = fields.Boolean(
|
||
string='Freiwillige Abfertigung (§ 67 Abs 6)')
|
||
abf_frei_anspruch_bestaetigt = fields.Boolean(
|
||
string='Prüfung und Nachweise bestätigt',
|
||
help='Bestätigung, dass es sich um eine Beendigungsleistung ohne '
|
||
'schädliche Anspruchsumwandlung handelt (KE/UE/SZ/Zeitguthaben '
|
||
'müssen getrennt abrechnet werden — GPLB-Risiko, lb-end-15), '
|
||
'dass die (Vor-)Dienstzeiten lückenlos zum Lohnkonto '
|
||
'(§ 76 EStG) nachgewiesen sind und erhaltene Abfertigungen '
|
||
'angegeben wurden.')
|
||
abf_frei_betrag = fields.Monetary(
|
||
string='Bruttobetrag', currency_field='currency_id')
|
||
abf_frei_basis_12 = fields.Monetary(
|
||
string='Laufende Bezüge letzte 12 Monate',
|
||
currency_field='currency_id',
|
||
help='Basis der Viertel-/Zwölftelregelung: alle steuerbaren '
|
||
'Bezugsteile (auch steuerfreie Zuschläge, Sachbezüge), '
|
||
'ohne Sonderzahlungen und ohne §-26-Z-4-Reisevergütungen; '
|
||
'wird aus den letzten zwölf validierten Läufen vorgeschlagen '
|
||
'und ist bestätigbar (lb-end-13).')
|
||
abf_frei_dienstzeit_monate = fields.Integer(
|
||
string='Nachgewiesene Dienstzeit (Monate)')
|
||
abf_frei_erhaltene_abfertigungen = fields.Monetary(
|
||
string='Bereits erhaltene Abfertigungen', currency_field='currency_id',
|
||
help='In den nachgewiesenen Dienstzeiten erhaltene Abfertigungen '
|
||
'(§ 67 Abs 3 oder Abs 6 EStG) — Kürzung nach Z 3.')
|
||
abf_frei_gesetzlicher_anspruch = fields.Monetary(
|
||
string='Bestehender gesetzlicher Anspruch',
|
||
currency_field='currency_id',
|
||
help='Anspruch auf eine gesetzliche Abfertigung am aktuellen '
|
||
'Dienstverhältnis-Ende (Z 3); bei aktiver Alt-Abfertigung '
|
||
'automatisch aus dem Alt-Anspruch vorgeschlagen.')
|
||
abf_frei_nachweis = fields.Text(
|
||
string='Nachweis/Begründung',
|
||
help='Vordienstzeiten-Nachweis (Lohnkonto § 76 EStG), erhaltene '
|
||
'Abfertigungen, Basis-Abweichungen und Anspruchsgrundlage '
|
||
'dokumentieren.')
|
||
vergleich_aktiv = fields.Boolean(
|
||
string='Vergleich (§ 67 Abs 8 lit a)',
|
||
help='Auf gerichtlichen oder außergerichtlichen Vergleichen '
|
||
'beruhende Vergleichssummen sowie Bereinigungen/Nachzahlungen '
|
||
'aus Urteilen/Bescheiden und Zahlungen bei '
|
||
'Kündigungsanfechtung (lb-end-21). Erkennbare '
|
||
'Abfertigungsanteile werden getrennt über die Abschnitte '
|
||
'Abfertigung Alt (§ 67 Abs 3) bzw. freiwillige Abfertigung '
|
||
'(§ 67 Abs 6) erfasst; Pensionsabfindungen (lit e) und '
|
||
'Sozialplan-Zahlungen (lit f) gehören nicht hierher.')
|
||
vergleich_rest_betrag = fields.Monetary(
|
||
string='Vergleichssumme — Rest (Fünftelregelung)',
|
||
currency_field='currency_id',
|
||
help='Nach Abzug der §-62-Beiträge ist ein Fünftel steuerfrei '
|
||
'(Deckel 1/5 × 9 × monatliche HBG), 4/5 laufen tarifisch im '
|
||
'Zuflussmonat — ohne Jahressechstel-Effekt (§ 67 Abs 8 lit '
|
||
'a iVm Abs 10).')
|
||
vergleich_bv_betrag = fields.Monetary(
|
||
string='Vergleichssumme — BV-Anwartschafts-Teil',
|
||
currency_field='currency_id',
|
||
help='Anteil für Zeiträume mit BV-Kassen-Anwartschaft: bis zum '
|
||
'Deckel (2026: 7 500 €) mit 6 %, der übersteigende Teil '
|
||
'fällt in die Fünftelregelung zurück. Der Alt-/Neu-Übertritt '
|
||
'steuert die Anwendung (lb-end-21: eingefrorene Zeiträume '
|
||
'kein 6 %-Teil).')
|
||
vergleich_bv_anwartschaft_bestaetigt = fields.Boolean(
|
||
string='BV-Anwartschaft für die betroffenen Zeiträume',
|
||
help='Voraussetzung des 6-%-Teils: die Vergleichssumme wird für '
|
||
'Zeiträume ausbezahlt, für die eine Anwartschaft gegenüber '
|
||
'einer BV-Kasse besteht (§ 67 Abs 8 lit a letzter Satz).')
|
||
vergleich_aufteilung_bestaetigt = fields.Boolean(
|
||
string='Aufgliederung und Strittigkeit bestätigt',
|
||
help='Bestätigung der Aufgliederung in der Vergleichsvereinbarung '
|
||
'(Praxistipp lb-end-21): Widmungen sind abgabenrechtlich nur '
|
||
'anerkannt, wenn die Ansprüche strittig waren (lb-end-22, '
|
||
'VwGH); beim Pauschalvergleich ist der Verhältnisfaktor '
|
||
'Forderungsbetrag : Vergleichssumme zu dokumentieren '
|
||
'(E-MVB 011-02-00-001).')
|
||
vergleich_nachweis = fields.Text(
|
||
string='Nachweis/Begründung',
|
||
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)
|
||
|
||
uel_lfd_vorschau = fields.Monetary(
|
||
string='UEL laufender Anteil (Vorschau)',
|
||
currency_field='currency_id', compute='_compute_vorschau')
|
||
uel_sz_vorschau = fields.Monetary(
|
||
string='UEL Sonderzahlungsanteil (Vorschau)',
|
||
currency_field='currency_id', compute='_compute_vorschau')
|
||
sv_tage_vorschau = fields.Integer(
|
||
string='SV-Verlängerungstage (§ 11 Abs 2)',
|
||
compute='_compute_vorschau')
|
||
abf_alt_betrag_vorschau = fields.Monetary(
|
||
string='Abfertigung Alt brutto', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_alt_steuer_vervielfachung_vorschau = fields.Monetary(
|
||
string='LSt Vervielfachungsmethode', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_alt_steuer_6_vorschau = fields.Monetary(
|
||
string='LSt 6 %', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_alt_lohnsteuer_vorschau = fields.Monetary(
|
||
string='Angewendete günstigere LSt', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_alt_netto_vorschau = fields.Monetary(
|
||
string='Abfertigung Alt netto', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_frei_z1_vorschau = fields.Monetary(
|
||
string='Z 1 Viertelregelung (Vorschau)', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_frei_z2_vorschau = fields.Monetary(
|
||
string='Z 2 Zwölftelregelung (Vorschau)', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_frei_kuerzung_vorschau = fields.Monetary(
|
||
string='Z 3 Kürzung (Vorschau)', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_frei_beguenstigt_vorschau = fields.Monetary(
|
||
string='Begünstigter Teil 6 % (Vorschau)', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_frei_ueberhang_vorschau = fields.Monetary(
|
||
string='Überhang zum Tarif (Vorschau)', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_frei_lst_vorschau = fields.Monetary(
|
||
string='LSt 6 % (Vorschau)', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
abf_frei_netto_vorschau = fields.Monetary(
|
||
string='Begünstigter Teil netto (Vorschau)',
|
||
currency_field='currency_id', compute='_compute_vorschau')
|
||
vergleich_fuenftel_frei_vorschau = fields.Monetary(
|
||
string='Steuerfreies Fünftel (Vorschau)', currency_field='currency_id',
|
||
compute='_compute_vorschau')
|
||
vergleich_tarif_basis_vorschau = fields.Monetary(
|
||
string='Fünftel-Bezüge tarifischer Teil (Vorschau)',
|
||
currency_field='currency_id', compute='_compute_vorschau')
|
||
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):
|
||
for wizard in self:
|
||
if not wizard.employee_id:
|
||
continue
|
||
version = wizard.employee_id.version_id
|
||
wizard.austrittsdatum = (
|
||
version.contract_date_end or fields.Date.today())
|
||
wizard.departure_reason_id = version.departure_reason_id
|
||
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',
|
||
'abf_frei_aktiv', 'abf_frei_dienstzeit_monate')
|
||
def _onchange_abf_alt(self):
|
||
for wizard in self:
|
||
wizard._at_abf_alt_vorschlag_setzen()
|
||
wizard._at_abf_frei_vorschlag_setzen()
|
||
|
||
def _at_abf_alt_vorschlag_setzen(self):
|
||
self.ensure_one()
|
||
if not self.employee_id or not self.austrittsdatum:
|
||
return
|
||
version = self.employee_id.version_id
|
||
start = version.contract_date_start
|
||
if start and not self.abf_alt_dienstzeit_monate:
|
||
dauer = relativedelta(
|
||
self.austrittsdatum + timedelta(days=1), start)
|
||
self.abf_alt_dienstzeit_monate = dauer.years * 12 + dauer.months
|
||
slip = self._vorschau_payslip()
|
||
if not self.abf_alt_laufender_arbeitslohn:
|
||
self.abf_alt_laufender_arbeitslohn = slip._at_kv_gehalt_basis()
|
||
if not self.abf_alt_monatsentgelt:
|
||
self.abf_alt_monatsentgelt = (
|
||
self.abf_alt_laufender_arbeitslohn
|
||
+ 2.0 * slip._at_sz_basis(self.austrittsdatum) / 12.0)
|
||
vorgeschlagen = slip._at_abf_alt_mehrfach_vorschlag(
|
||
self.abf_alt_dienstzeit_monate, self.abf_alt_anspruchsart)
|
||
if vorgeschlagen or not self.abf_alt_mehrfach:
|
||
self.abf_alt_mehrfach = vorgeschlagen
|
||
|
||
def _at_abf_frei_vorschlag_setzen(self):
|
||
self.ensure_one()
|
||
if not self.employee_id or not self.austrittsdatum:
|
||
return
|
||
slip = self._vorschau_payslip()
|
||
if self.abf_frei_aktiv and not self.abf_frei_basis_12:
|
||
self.abf_frei_basis_12 = slip._at_bezuege_12_monate()
|
||
if (self.abf_frei_aktiv and self.abf_alt_aktiv
|
||
and not self.abf_frei_gesetzlicher_anspruch):
|
||
self.abf_frei_gesetzlicher_anspruch = (
|
||
self.abf_alt_monatsentgelt * self.abf_alt_mehrfach)
|
||
|
||
@api.depends('employee_id', 'austrittsdatum', 'uel_tage',
|
||
'abf_alt_aktiv', 'abf_alt_monatsentgelt',
|
||
'abf_alt_laufender_arbeitslohn', 'abf_alt_monatslohnsteuer',
|
||
'abf_alt_mehrfach',
|
||
'abf_alt_dienstzeit_monate', 'abf_alt_anspruchsart',
|
||
'abf_frei_aktiv', 'abf_frei_betrag', 'abf_frei_basis_12',
|
||
'abf_frei_dienstzeit_monate',
|
||
'abf_frei_erhaltene_abfertigungen',
|
||
'abf_frei_gesetzlicher_anspruch',
|
||
'vergleich_aktiv', 'vergleich_rest_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
|
||
wizard.uel_sz_vorschau = 0.0
|
||
wizard.sv_tage_vorschau = 0
|
||
wizard.abf_alt_betrag_vorschau = 0.0
|
||
wizard.abf_alt_steuer_vervielfachung_vorschau = 0.0
|
||
wizard.abf_alt_steuer_6_vorschau = 0.0
|
||
wizard.abf_alt_lohnsteuer_vorschau = 0.0
|
||
wizard.abf_alt_netto_vorschau = 0.0
|
||
wizard.abf_frei_z1_vorschau = 0.0
|
||
wizard.abf_frei_z2_vorschau = 0.0
|
||
wizard.abf_frei_kuerzung_vorschau = 0.0
|
||
wizard.abf_frei_beguenstigt_vorschau = 0.0
|
||
wizard.abf_frei_ueberhang_vorschau = 0.0
|
||
wizard.abf_frei_lst_vorschau = 0.0
|
||
wizard.abf_frei_netto_vorschau = 0.0
|
||
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()
|
||
wizard.uel_lfd_vorschau = slip._at_uel_lfd()
|
||
wizard.uel_sz_vorschau = slip._at_uel_sz()
|
||
wizard.sv_tage_vorschau = slip._at_end_sv_tage(
|
||
wizard.uel_tage)
|
||
if wizard.abf_alt_aktiv:
|
||
betrag = slip._at_abf_alt_betrag()
|
||
steuer_vervielfachung = \
|
||
slip._at_abf_alt_steuer_vervielfachung()
|
||
steuer_6 = slip._at_abf_alt_steuer_6()
|
||
steuer = min(steuer_vervielfachung, steuer_6)
|
||
wizard.abf_alt_betrag_vorschau = betrag
|
||
wizard.abf_alt_steuer_vervielfachung_vorschau = \
|
||
steuer_vervielfachung
|
||
wizard.abf_alt_steuer_6_vorschau = steuer_6
|
||
wizard.abf_alt_lohnsteuer_vorschau = steuer
|
||
wizard.abf_alt_netto_vorschau = betrag - steuer
|
||
if wizard.abf_frei_aktiv:
|
||
split = slip._at_abf_frei_split()
|
||
satz = float(slip._l10n_at_param(
|
||
'at_endabrechnung')['abfertigung_steuersatz'])
|
||
wizard.abf_frei_z1_vorschau = split['z1']
|
||
wizard.abf_frei_z2_vorschau = split['z2']
|
||
wizard.abf_frei_kuerzung_vorschau = split['kuerzung']
|
||
wizard.abf_frei_beguenstigt_vorschau = split['beguenstigt']
|
||
wizard.abf_frei_ueberhang_vorschau = split['ueberhang']
|
||
wizard.abf_frei_lst_vorschau = \
|
||
split['beguenstigt'] * satz / 100.0
|
||
wizard.abf_frei_netto_vorschau = \
|
||
split['beguenstigt'] - wizard.abf_frei_lst_vorschau
|
||
if wizard.vergleich_aktiv:
|
||
# Der tarifische Fünftel-Teil läuft über die laufende
|
||
# Bemessung (LST_LFD); die Vorschau zeigt die Pfade
|
||
# getrennt (Fünftel-Pool inkl. ABGANG, falls erfasst).
|
||
wizard.vergleich_fuenftel_frei_vorschau = \
|
||
slip._at_fuenftel_frei_betr()
|
||
wizard.vergleich_tarif_basis_vorschau = \
|
||
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
|
||
Speichern): trägt Austrittsmonat, Struktur und die Eingaben."""
|
||
self.ensure_one()
|
||
erster = self.austrittsdatum.replace(day=1)
|
||
letzter = (erster + timedelta(days=32)).replace(day=1) \
|
||
- timedelta(days=1)
|
||
struct = self.employee_id.version_id.structure_id
|
||
if not struct:
|
||
struct = self.env.ref(
|
||
'l10n_at_hr_payroll_private.structure_at_privat')
|
||
slip = self.env['hr.payslip'].new({
|
||
'employee_id': self.employee_id.id,
|
||
'struct_id': struct.id,
|
||
'date_from': erster,
|
||
'date_to': letzter,
|
||
'l10n_at_abf_alt_anspruchsart': self.abf_alt_anspruchsart,
|
||
'l10n_at_abf_alt_dienstzeit_monate':
|
||
self.abf_alt_dienstzeit_monate,
|
||
'l10n_at_abf_alt_monatsentgelt': self.abf_alt_monatsentgelt,
|
||
'l10n_at_abf_alt_laufender_arbeitslohn':
|
||
self.abf_alt_laufender_arbeitslohn,
|
||
'l10n_at_abf_alt_monatslohnsteuer':
|
||
self.abf_alt_monatslohnsteuer,
|
||
'l10n_at_abf_alt_mehrfach': self.abf_alt_mehrfach,
|
||
'l10n_at_abf_alt_nachweis': self.abf_alt_nachweis,
|
||
'l10n_at_abf_frei_basis_12': self.abf_frei_basis_12,
|
||
'l10n_at_abf_frei_dienstzeit_monate':
|
||
self.abf_frei_dienstzeit_monate,
|
||
'l10n_at_abf_frei_erhaltene_abfertigungen':
|
||
self.abf_frei_erhaltene_abfertigungen,
|
||
'l10n_at_abf_frei_gesetzlicher_anspruch':
|
||
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),
|
||
('ATP_ABF_ALT', self.abf_alt_monatsentgelt
|
||
* self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0),
|
||
('ATP_ABF_FREI', self.abf_frei_betrag
|
||
if self.abf_frei_aktiv else 0.0),
|
||
('ATP_VERGLEICH', self.vergleich_rest_betrag
|
||
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, {
|
||
'input_type_id': self.env['hr.payslip.input.type']
|
||
.search([('code', '=', code)], limit=1).id,
|
||
'amount': betrag,
|
||
})
|
||
for code, betrag in eingaben if betrag
|
||
]
|
||
return slip
|
||
|
||
def _eingaben(self):
|
||
self.ensure_one()
|
||
return [
|
||
('ATP_UEL_TAGE', self.uel_tage),
|
||
('ATP_ABGANG', self.abgang_betrag),
|
||
('ATP_ABGANG_FFRIST_TAGE', self.abgang_ffrist_tage),
|
||
('ATP_ZEIT_GUTHABEN', self.zeit_guthaben_stunden),
|
||
('ATP_ZEIT_SCHULDEN', self.zeit_schulden_stunden),
|
||
('ATP_ABRECHNUNG_VORSCHUSS', self.vorschuss_saldo),
|
||
('ATP_ABF_ALT', self.abf_alt_monatsentgelt
|
||
* self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0),
|
||
('ATP_ABF_FREI', self.abf_frei_betrag
|
||
if self.abf_frei_aktiv else 0.0),
|
||
('ATP_VERGLEICH', self.vergleich_rest_betrag
|
||
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):
|
||
self.ensure_one()
|
||
if not self.abf_alt_aktiv:
|
||
return
|
||
if not self.abf_alt_anspruch_bestaetigt:
|
||
raise UserError(_('Bitte Anspruch und Nachweise der '
|
||
'Abfertigung Alt bestätigen.'))
|
||
if self.employee_id.version_id.l10n_at_abfertigung_neu \
|
||
and self.abf_alt_anspruchsart != 'eingefroren':
|
||
raise UserError(_(
|
||
'Das Dienstverhältnis ist als Abfertigung Neu markiert. '
|
||
'Eine Alt-Abfertigung ist nur als nachgewiesener '
|
||
'eingefrorener Anspruch zulässig.'))
|
||
if self.abf_alt_anspruchsart == 'eltern' \
|
||
and self.abf_alt_dienstzeit_monate < 60:
|
||
raise UserError(_(
|
||
'Ein Elternaustritt nach § 23a Abs. 3/4 AngG setzt ein '
|
||
'ununterbrochenes Dienstverhältnis von fünf Jahren voraus.'))
|
||
if (self.abf_alt_dienstzeit_monate <= 0
|
||
or self.abf_alt_monatsentgelt <= 0
|
||
or self.abf_alt_laufender_arbeitslohn <= 0
|
||
or self.abf_alt_monatslohnsteuer < 0
|
||
or self.abf_alt_mehrfach <= 0):
|
||
raise UserError(_('Dienstzeit, Monatsentgelt, laufender '
|
||
'Arbeitslohn und Anspruchsfaktor müssen '
|
||
'größer als null sein; die Tarif-LSt darf '
|
||
'nicht negativ sein.'))
|
||
agrd = self.departure_reason_id.l10n_at_agrd
|
||
if agrd == '02' and self.abf_alt_anspruchsart not in (
|
||
'eltern', 'pension', 'manuell'):
|
||
raise UserError(_(
|
||
'Eine gewöhnliche Arbeitnehmerkündigung begründet keinen '
|
||
'Anspruch nach § 23 AngG. Bitte einen §-23a-Sonderfall '
|
||
'wählen oder den Anspruch manuell nachweisen.'))
|
||
if agrd == '06' and self.abf_alt_anspruchsart != 'manuell':
|
||
raise UserError(_(
|
||
'Der Abgangsgrund „Fristlose Entlassung“ unterscheidet '
|
||
'nicht zwischen verschuldeter und unverschuldeter '
|
||
'Entlassung. Bitte den Anspruch manuell bestätigen und '
|
||
'begründen.'))
|
||
|
||
def _abf_frei_validieren(self):
|
||
self.ensure_one()
|
||
if not self.abf_frei_aktiv:
|
||
return
|
||
if not self.abf_frei_anspruch_bestaetigt:
|
||
raise UserError(_('Bitte Prüfung und Nachweise der freiwilligen '
|
||
'Abfertigung bestätigen.'))
|
||
if self.abf_frei_betrag <= 0:
|
||
raise UserError(_('Der Bruttobetrag der freiwilligen '
|
||
'Abfertigung muss größer als null sein.'))
|
||
if (self.abf_frei_basis_12 < 0
|
||
or self.abf_frei_erhaltene_abfertigungen < 0
|
||
or self.abf_frei_gesetzlicher_anspruch < 0
|
||
or self.abf_frei_dienstzeit_monate < 0):
|
||
raise UserError(_('12-Monats-Basis, erhaltene Abfertigungen, '
|
||
'gesetzlicher Anspruch und Dienstzeit dürfen '
|
||
'nicht negativ sein.'))
|
||
|
||
def _vergleich_validieren(self):
|
||
self.ensure_one()
|
||
if not self.vergleich_aktiv:
|
||
return
|
||
if not self.vergleich_aufteilung_bestaetigt:
|
||
raise UserError(_('Bitte die Aufgliederung der Vergleichs-'
|
||
'summe und die Strittigkeit der Ansprüche '
|
||
'bestätigen (lb-end-21/22).'))
|
||
if self.vergleich_rest_betrag < 0 or self.vergleich_bv_betrag < 0:
|
||
raise UserError(_('Vergleichsbeträge dürfen nicht negativ '
|
||
'sein.'))
|
||
if not self.vergleich_rest_betrag and not self.vergleich_bv_betrag:
|
||
raise UserError(_('Bitte den Rest der Vergleichssumme oder '
|
||
'den BV-Anwartschafts-Teil erfassen; '
|
||
'erkennbare Abfertigungsanteile gehören in '
|
||
'die Abfertigungs-Abschnitte.'))
|
||
slip = self._vorschau_payslip()
|
||
deckel = float(slip._l10n_at_param('at_lst_67_abs8_vergleich_bv'))
|
||
if self.vergleich_bv_betrag > deckel:
|
||
raise UserError(_(
|
||
'Der BV-Anwartschafts-Teil ist mit %.2f € gedeckelt '
|
||
'(§ 67 Abs 8 lit a letzter Satz); den übersteigenden '
|
||
'Betrag als Rest (Fünftelregelung) erfassen.') % deckel)
|
||
if self.vergleich_bv_betrag > 0 \
|
||
and not self.vergleich_bv_anwartschaft_bestaetigt:
|
||
raise UserError(_('Der 6-%-Teil setzt eine bestätigte '
|
||
'BV-Anwartschaft für die betroffenen '
|
||
'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."""
|
||
self.ensure_one()
|
||
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)
|
||
version = self.employee_id.version_id
|
||
version.write({
|
||
'contract_date_end': self.austrittsdatum,
|
||
'departure_reason_id': self.departure_reason_id.id,
|
||
})
|
||
struct = version.structure_id \
|
||
or self.env.ref('l10n_at_hr_payroll_private.structure_at_privat')
|
||
slip = self.env['hr.payslip'].create({
|
||
'name': _('Endabrechnung %s') % self.employee_id.name,
|
||
'employee_id': self.employee_id.id,
|
||
'struct_id': struct.id,
|
||
'date_from': erster,
|
||
'date_to': letzter,
|
||
'l10n_at_abf_alt_anspruchsart': self.abf_alt_anspruchsart
|
||
if self.abf_alt_aktiv else False,
|
||
'l10n_at_abf_alt_dienstzeit_monate':
|
||
self.abf_alt_dienstzeit_monate if self.abf_alt_aktiv else 0,
|
||
'l10n_at_abf_alt_monatsentgelt':
|
||
self.abf_alt_monatsentgelt if self.abf_alt_aktiv else 0.0,
|
||
'l10n_at_abf_alt_laufender_arbeitslohn':
|
||
self.abf_alt_laufender_arbeitslohn
|
||
if self.abf_alt_aktiv else 0.0,
|
||
'l10n_at_abf_alt_monatslohnsteuer':
|
||
self.abf_alt_monatslohnsteuer if self.abf_alt_aktiv else 0.0,
|
||
'l10n_at_abf_alt_mehrfach':
|
||
self.abf_alt_mehrfach if self.abf_alt_aktiv else 0.0,
|
||
'l10n_at_abf_alt_nachweis':
|
||
self.abf_alt_nachweis if self.abf_alt_aktiv else False,
|
||
'l10n_at_abf_frei_basis_12':
|
||
self.abf_frei_basis_12 if self.abf_frei_aktiv else 0.0,
|
||
'l10n_at_abf_frei_dienstzeit_monate':
|
||
self.abf_frei_dienstzeit_monate if self.abf_frei_aktiv else 0,
|
||
'l10n_at_abf_frei_erhaltene_abfertigungen':
|
||
self.abf_frei_erhaltene_abfertigungen
|
||
if self.abf_frei_aktiv else 0.0,
|
||
'l10n_at_abf_frei_gesetzlicher_anspruch':
|
||
self.abf_frei_gesetzlicher_anspruch
|
||
if self.abf_frei_aktiv else 0.0,
|
||
'l10n_at_abf_frei_nachweis':
|
||
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)
|
||
for code, _betrag in self._eingaben()}
|
||
self.env['hr.payslip.input'].create([{
|
||
'payslip_id': slip.id,
|
||
'input_type_id': typen[code].id,
|
||
'amount': betrag,
|
||
} for code, betrag in self._eingaben() if betrag])
|
||
slip.compute_sheet()
|
||
return {
|
||
'type': 'ir.actions.act_window',
|
||
'name': _('Endabrechnung'),
|
||
'res_model': 'hr.payslip',
|
||
'view_mode': 'form',
|
||
'res_id': slip.id,
|
||
} |