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: Sachbezüge (AP12)
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||||
"""AP12b: wertgebundene Sachbezüge auf dem Dienstverhältnis.
|
||||
|
||||
Ein Fahrzeug bzw. eine Wohnung je Version ist bewusst MVP-Grenze. Wechsel,
|
||||
Pool-/Mehrfachfahrzeuge, Mini-Sachbezug und Kleinwohnungs-Retroaktivität
|
||||
bleiben dokumentierte Folgefälle (lb-sac-03/04/09/18/15/08).
|
||||
"""
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
BUNDESLAENDER = [
|
||||
('burgenland', 'Burgenland'), ('kaernten', 'Kärnten'),
|
||||
('niederoesterreich', 'Niederösterreich'),
|
||||
('oberoesterreich', 'Oberösterreich'), ('salzburg', 'Salzburg'),
|
||||
('steiermark', 'Steiermark'), ('tirol', 'Tirol'),
|
||||
('vorarlberg', 'Vorarlberg'), ('wien', 'Wien'),
|
||||
]
|
||||
|
||||
|
||||
class HrVersion(models.Model):
|
||||
_inherit = 'hr.version'
|
||||
|
||||
l10n_at_sb_wagen_aktiv = fields.Boolean(
|
||||
string='AT Dienstwagen privat nutzbar', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wagen_ak = fields.Monetary(
|
||||
string='AT Dienstwagen Anschaffungskosten', currency_field='currency_id',
|
||||
tracking=True, groups='hr_payroll.group_hr_payroll_user',
|
||||
help='Maßgebliche AK inkl. USt/NoVA nach § 4 SBWVO; bei '
|
||||
'Gebrauchtwagen historischer Neupreis (lb-sac-03).')
|
||||
l10n_at_sb_wagen_erstzulassung = fields.Date(
|
||||
string='AT Dienstwagen Erstzulassung', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user',
|
||||
help='Bestimmt den CO₂-Grenzwert; bei Gebrauchtwagen ist das '
|
||||
'Erstzulassungsjahr maßgeblich (lb-sac-03).')
|
||||
l10n_at_sb_wagen_co2 = fields.Float(
|
||||
string='AT Dienstwagen CO₂ (g/km)', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wagen_halb = fields.Boolean(
|
||||
string='AT Dienstwagen halber Sachbezug', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user',
|
||||
help='Nachweislich höchstens 500 Privat-km/Monat bzw. 6.000/Jahr; '
|
||||
'Nachweis/Fahrtenbuch durch Arbeitgeber prüfen (lb-sac-03).')
|
||||
l10n_at_sb_wagen_kostenbeitrag = fields.Monetary(
|
||||
string='AT Dienstwagen Kostenbeitrag monatlich', currency_field='currency_id',
|
||||
tracking=True, groups='hr_payroll.group_hr_payroll_user',
|
||||
help='Laufender DN-Kostenbeitrag; mindert nach § 4 Abs 7 SBWVO '
|
||||
'den Sachbezugswert (nicht einzelne Betriebskosten).')
|
||||
|
||||
l10n_at_sb_wohnung_aktiv = fields.Boolean(
|
||||
string='AT Dienstwohnung überlassen', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_flaeche = fields.Float(
|
||||
string='AT Dienstwohnung Fläche (m²)', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_bundesland = fields.Selection(
|
||||
BUNDESLAENDER, string='AT Dienstwohnung Bundesland', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_norm = fields.Boolean(
|
||||
string='AT Dienstwohnung Normwohnung', default=True, tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_besorger = fields.Boolean(
|
||||
string='AT Dienstwohnung Hausbesorger/Betreuer', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_arbeitsplatznah = fields.Boolean(
|
||||
string='AT Dienstwohnung arbeitsplatznah (≤ 15 Min.)', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_kein_mittelpunkt = fields.Boolean(
|
||||
string='AT Dienstwohnung nicht Mittelpunkt Lebensinteressen', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_ueberlassung_ab = fields.Date(
|
||||
string='AT Dienstwohnung überlassen ab', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_kostenbeitrag = fields.Monetary(
|
||||
string='AT Dienstwohnung Kostenbeitrag monatlich', currency_field='currency_id',
|
||||
tracking=True, groups='hr_payroll.group_hr_payroll_user')
|
||||
|
||||
l10n_at_sb_parkplatz_aktiv = fields.Boolean(
|
||||
string='AT Parkplatz in Kurzparkzone berechtigt', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_parkplatz_ausnahme = fields.Boolean(
|
||||
string='AT Parkplatz sachbezugsbefreit', tracking=True,
|
||||
groups='hr_payroll.group_hr_payroll_user',
|
||||
help='Nachtdienst ohne Gebührenpflicht, Behinderung mit Pauschbetrag '
|
||||
'oder kontrollierter Verzicht/Nichtparken (lb-sac-18).')
|
||||
l10n_at_sb_parkplatz_kostenbeitrag = fields.Monetary(
|
||||
string='AT Parkplatz Kostenbeitrag monatlich', currency_field='currency_id',
|
||||
tracking=True, groups='hr_payroll.group_hr_payroll_user')
|
||||
|
||||
l10n_at_sb_handy_profil = fields.Selection(
|
||||
[('beruflich', 'Beruflich/fallweise privat (kein Sachbezug)'),
|
||||
('ueberwiegend_privat', 'Überwiegend privat (tatsächliche Kosten)'),
|
||||
('private_ueberlassung', 'Private Überlassung (Rabatt-Regime)')],
|
||||
string='AT Handy-/Arbeitsmittel-Nutzungsprofil', default='beruflich',
|
||||
tracking=True, groups='hr_payroll.group_hr_payroll_user')
|
||||
|
||||
def _l10n_at_sb_wagen_wert(self, datum):
|
||||
self.ensure_one()
|
||||
if not (self.l10n_at_sb_wagen_aktiv and self.l10n_at_sb_wagen_ak):
|
||||
return 0.0
|
||||
co2 = self.l10n_at_sb_wagen_co2
|
||||
if co2 == 0.0:
|
||||
return 0.0
|
||||
werte = self.env['hr.rule.parameter']._get_parameter_from_code(
|
||||
'at_sb_wagen', datum, raise_if_not_found=False) or {}
|
||||
grenzen = self.env['hr.rule.parameter']._get_parameter_from_code(
|
||||
'at_sb_wagen_co2', datum, raise_if_not_found=False) or {}
|
||||
ez_jahr = (self.l10n_at_sb_wagen_erstzulassung or datum).year
|
||||
grenze = float(grenzen.get('ab_2025' if ez_jahr >= 2025
|
||||
else str(ez_jahr),
|
||||
grenzen.get('vor_2016', 0.0)))
|
||||
niedrig = bool(grenze and co2 <= grenze)
|
||||
art = 'niedrig' if niedrig else 'hoch'
|
||||
prefix = 'halb' if self.l10n_at_sb_wagen_halb else 'voll'
|
||||
wert = self.l10n_at_sb_wagen_ak * float(
|
||||
werte.get('%s_%s_satz' % (prefix, art), 0.0)) / 100.0
|
||||
wert = min(wert, float(werte.get('%s_%s_cap' % (prefix, art), 0.0)))
|
||||
return max(wert - self.l10n_at_sb_wagen_kostenbeitrag, 0.0)
|
||||
|
||||
def _l10n_at_sb_wohnung_wert(self, datum):
|
||||
self.ensure_one()
|
||||
if not (self.l10n_at_sb_wohnung_aktiv
|
||||
and self.l10n_at_sb_wohnung_flaeche
|
||||
and self.l10n_at_sb_wohnung_bundesland):
|
||||
return 0.0
|
||||
werte = self.env['hr.rule.parameter']._get_parameter_from_code(
|
||||
'at_sb_wohnung', datum, raise_if_not_found=False) or {}
|
||||
flaeche = self.l10n_at_sb_wohnung_flaeche
|
||||
klein = (self.l10n_at_sb_wohnung_arbeitsplatznah
|
||||
and self.l10n_at_sb_wohnung_kein_mittelpunkt)
|
||||
if klein and flaeche <= float(werte.get('klein_frei_m2', 0.0)):
|
||||
return 0.0
|
||||
wert = flaeche * float(werte.get(
|
||||
self.l10n_at_sb_wohnung_bundesland, 0.0))
|
||||
if (not self.l10n_at_sb_wohnung_norm
|
||||
and self.l10n_at_sb_wohnung_besorger):
|
||||
wert *= 1.0 - float(werte.get('kombiniert_abschlag', 0.0))
|
||||
elif not self.l10n_at_sb_wohnung_norm:
|
||||
wert *= 1.0 - float(werte.get('nicht_norm_abschlag', 0.0))
|
||||
elif self.l10n_at_sb_wohnung_besorger:
|
||||
wert *= 1.0 - float(werte.get('besorger_abschlag', 0.0))
|
||||
if (klein and flaeche <= float(werte.get('klein_abschlag_bis_m2', 0.0))
|
||||
and self.l10n_at_sb_wohnung_ueberlassung_ab
|
||||
and datum < self.l10n_at_sb_wohnung_ueberlassung_ab
|
||||
+ relativedelta(months=12)):
|
||||
wert *= 1.0 - float(werte.get('klein_abschlag', 0.0))
|
||||
return max(wert - self.l10n_at_sb_wohnung_kostenbeitrag, 0.0)
|
||||
|
||||
def _l10n_at_sb_parkplatz_wert(self, datum):
|
||||
self.ensure_one()
|
||||
if not (self.l10n_at_sb_parkplatz_aktiv
|
||||
and not self.l10n_at_sb_parkplatz_ausnahme):
|
||||
return 0.0
|
||||
wert = float(self.env['hr.rule.parameter']._get_parameter_from_code(
|
||||
'at_sb_parkplatz', datum, raise_if_not_found=False) or 0.0)
|
||||
return max(wert - self.l10n_at_sb_parkplatz_kostenbeitrag, 0.0)
|
||||
|
||||
|
||||
class HrEmployee(models.Model):
|
||||
_inherit = 'hr.employee'
|
||||
|
||||
l10n_at_sb_wagen_aktiv = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_wagen_aktiv', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wagen_ak = fields.Monetary(
|
||||
related='version_id.l10n_at_sb_wagen_ak', inherited=True,
|
||||
readonly=False, currency_field='currency_id',
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wagen_erstzulassung = fields.Date(
|
||||
related='version_id.l10n_at_sb_wagen_erstzulassung', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wagen_co2 = fields.Float(
|
||||
related='version_id.l10n_at_sb_wagen_co2', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wagen_halb = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_wagen_halb', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wagen_kostenbeitrag = fields.Monetary(
|
||||
related='version_id.l10n_at_sb_wagen_kostenbeitrag', inherited=True,
|
||||
readonly=False, currency_field='currency_id',
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_aktiv = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_wohnung_aktiv', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_flaeche = fields.Float(
|
||||
related='version_id.l10n_at_sb_wohnung_flaeche', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_bundesland = fields.Selection(
|
||||
related='version_id.l10n_at_sb_wohnung_bundesland', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_norm = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_wohnung_norm', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_besorger = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_wohnung_besorger', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_arbeitsplatznah = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_wohnung_arbeitsplatznah', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_kein_mittelpunkt = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_wohnung_kein_mittelpunkt', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_ueberlassung_ab = fields.Date(
|
||||
related='version_id.l10n_at_sb_wohnung_ueberlassung_ab', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_wohnung_kostenbeitrag = fields.Monetary(
|
||||
related='version_id.l10n_at_sb_wohnung_kostenbeitrag', inherited=True,
|
||||
readonly=False, currency_field='currency_id',
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_parkplatz_aktiv = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_parkplatz_aktiv', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_parkplatz_ausnahme = fields.Boolean(
|
||||
related='version_id.l10n_at_sb_parkplatz_ausnahme', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_parkplatz_kostenbeitrag = fields.Monetary(
|
||||
related='version_id.l10n_at_sb_parkplatz_kostenbeitrag', inherited=True,
|
||||
readonly=False, currency_field='currency_id',
|
||||
groups='hr_payroll.group_hr_payroll_user')
|
||||
l10n_at_sb_handy_profil = fields.Selection(
|
||||
related='version_id.l10n_at_sb_handy_profil', inherited=True,
|
||||
readonly=False, groups='hr_payroll.group_hr_payroll_user')
|
||||
Reference in New Issue
Block a user