4b86bcb790
Split the voluntary severance into its privileged part and a tariff remainder on the exit run: the privileged part combines the quarter rule (1/4 of the last twelve months' running pay, capped at nine times the monthly HBG) with the twelfth rule (2/12 to 12/12 by proven service, capped at n × 3 × HBG), reduced per Z 3 by severance already received and the statutory claim due at this termination, all taxed at the flat 6 % rate. The excess runs as its own rule flagged l10n_at_s67_abs6_ueberhang: taxed with the running tariff of the payment month but excluded from the annual sixth, since Z 5 exempts only the Z 1/Z 2 amounts and the excess is a special payment, not running pay. The twelve-month basis aggregates validated prior runs plus own lines, excluding the flagged excess and § 26 Z 4 travel overhang via a dedicated rule flag. Free of SV (§ 49 Abs 3 Z 7 ASVG), payroll levies regardless of the 6 %/tarif split (§ 41 Abs 4 lit b FLAG, § 122 Abs 8 WKG, § 5 Abs 2 lit b KommStG) and BV contributions; the former BV-Anwartschaft exclusion Z 7 is repealed (BGBl I 118/2015). The wizard proposes the rolling basis and the statutory claim, previews Z 1/Z 2/reduction/privileged/excess/tax and requires explicit confirmation against claim-conversion risk. The § 291d EO termination pot nets both severance wage-tax rules; key 260 now includes LST_ABF_FREI. Verified against the original statute text in .ris/ (EStG § 67 Abs 6) and the knowledge-base sources lb-end-12/13/15; KZ positioning of Abs-6 amounts and the excess's § 291d pot allocation remain documented verification points against LStR Rz 1087 ff. Version 19.0.14.0.0 (private), 19.0.10.0.0 (core)
421 lines
20 KiB
Python
421 lines
20 KiB
Python
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||
"""GP3 Lohnsteuer-Kern: § 33 Tarif, Absetzbeträge, § 66 kumulative
|
||
Monatslohnsteuer (Rollung), § 68-Freibeträge, § 67 Sechstel/Fixsätze
|
||
mit Günstig-Aufrollung, DN-SV-Basis. Rechenfälle s.
|
||
personalverrechnung/RECHTSQUELLEN-Privat.md Abschnitt 5 (P0-GP3)."""
|
||
from datetime import date, timedelta
|
||
|
||
from odoo.tests import TransactionCase, tagged
|
||
|
||
|
||
@tagged('post_install', '-at_install')
|
||
class LohnsteuerTest(TransactionCase):
|
||
|
||
def setUp(self):
|
||
super().setUp()
|
||
self.category = self.env['hr.salary.rule.category'].create({
|
||
'name': 'Test AT Kern',
|
||
'code': 'TEST_AT_KERN',
|
||
})
|
||
self.structure_type = self.env['hr.payroll.structure.type'].create({
|
||
'name': 'Test AT Kern Type',
|
||
})
|
||
self.structure = self.env['hr.payroll.structure'].create({
|
||
'name': 'Test AT Lohnsteuer',
|
||
'code': 'TEST_AT_LST',
|
||
'type_id': self.structure_type.id,
|
||
})
|
||
|
||
def _regel(self, code, betrag, bemessung='laufend', flag68='keine',
|
||
anteil=0.0, quantity='1.0', python=None, st_frei='keine',
|
||
sv_art='folgt'):
|
||
vals = {
|
||
'name': code,
|
||
'code': code,
|
||
'struct_id': self.structure.id,
|
||
'category_id': self.category.id,
|
||
'condition_select': 'none',
|
||
'l10n_at_bemessung': bemessung,
|
||
'l10n_at_steuerbefreiung_68': flag68,
|
||
'l10n_at_zuschlagsanteil': anteil,
|
||
'l10n_at_st_frei': st_frei,
|
||
'l10n_at_sv_art': sv_art,
|
||
}
|
||
if python:
|
||
vals.update({'amount_select': 'code',
|
||
'amount_python_compute': python})
|
||
else:
|
||
vals.update({'amount_select': 'fix', 'amount_fix': betrag,
|
||
'quantity': quantity})
|
||
return self.env['hr.salary.rule'].create(vals)
|
||
|
||
def _employee(self, version_vals=None):
|
||
employee = self.env['hr.employee'].create({'name': 'Test LSt'})
|
||
version = self.env['hr.version'].search(
|
||
[('employee_id', '=', employee.id)], limit=1)
|
||
if not version:
|
||
version = self.env['hr.version'].create({
|
||
'employee_id': employee.id,
|
||
'date_start': date(2020, 1, 1)})
|
||
version.write({'contract_date_start': date(2020, 1, 1)})
|
||
if version_vals:
|
||
version.write(version_vals)
|
||
return employee
|
||
|
||
def _slip(self, employee, monat, jahr=2026, confirm=False):
|
||
erster = date(jahr, monat, 1)
|
||
naechster = (erster + timedelta(days=32)).replace(day=1)
|
||
slip = self.env['hr.payslip'].create({
|
||
'name': 'Test-LSt %d/%d' % (monat, jahr),
|
||
'employee_id': employee.id,
|
||
'struct_id': self.structure.id,
|
||
'date_from': erster,
|
||
'date_to': naechster - timedelta(days=1),
|
||
})
|
||
slip.compute_sheet()
|
||
if confirm:
|
||
slip.action_payslip_done()
|
||
return slip
|
||
|
||
def _total(self, slip, code):
|
||
return sum(slip.line_ids.filtered(
|
||
lambda l: l.code == code).mapped('total'))
|
||
|
||
# ------------------------------------------------------------------
|
||
# § 33 Tarif / Absetzbeträge
|
||
# ------------------------------------------------------------------
|
||
def test_01_tarif_zonen(self):
|
||
employee = self._employee()
|
||
slip = self._slip(employee, 1)
|
||
self.assertAlmostEqual(slip._l10n_at_tarif(13539.0), 0.0, places=2)
|
||
# 15.000: 20 % auf 1.461 = 292,20
|
||
self.assertAlmostEqual(slip._l10n_at_tarif(15000.0), 292.20, places=2)
|
||
# 30.000: 1.690,60 + (30.000−21.992) × 0,30 = 4.093,00
|
||
self.assertAlmostEqual(slip._l10n_at_tarif(30000.0), 4093.00, places=2)
|
||
# 80.000: 1.690,60 + 4.339,80 + 13.562,80 + 4.624,80 = 24.218,00
|
||
self.assertAlmostEqual(slip._l10n_at_tarif(80000.0), 24218.00, places=2)
|
||
|
||
def test_02_absetzbetraege(self):
|
||
employee = self._employee()
|
||
slip = self._slip(employee, 1)
|
||
self.assertAlmostEqual(slip._l10n_at_absetzbetraege(20000.0), 496.0, places=2)
|
||
version = slip.version_id
|
||
version.write({'l10n_at_familienabsetzbetrag': 'avb', 'children': 1})
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_absetzbetraege(20000.0), 496.0 + 612.0, places=2)
|
||
version.write({'children': 3})
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_absetzbetraege(20000.0),
|
||
496.0 + 828.0 + 273.0, places=2)
|
||
|
||
|
||
# ------------------------------------------------------------------
|
||
# Lohnsteuertage (user decision: 30 je vollem Monat)
|
||
# ------------------------------------------------------------------
|
||
def test_03_lohnsteuertage(self):
|
||
employee = self._employee()
|
||
slip = self._slip(employee, 1)
|
||
self.assertEqual(slip._l10n_at_lohnsteuertage(), 30)
|
||
slip.version_id.write({
|
||
'contract_date_start': date(2026, 1, 16)})
|
||
# 16.–31. 1. = 16 Kalendertage (inkl. arbeitsfreier, § 66 Abs 3)
|
||
self.assertEqual(slip._l10n_at_lohnsteuertage(), 16)
|
||
slip.version_id.write({
|
||
'contract_date_start': date(2026, 1, 1),
|
||
'contract_date_end': date(2026, 1, 10)})
|
||
self.assertEqual(slip._l10n_at_lohnsteuertage(), 10)
|
||
|
||
# ------------------------------------------------------------------
|
||
# § 67 Abs 6 Z 6 — Überhang (tarifisch, ohne Sechstel-Effekt)
|
||
# ------------------------------------------------------------------
|
||
def test_20_abs6_ueberhang_ohne_sechstel(self):
|
||
"""Der gekennzeichnete Überhang läuft tarifisch in der laufenden
|
||
Bemessung, erhöht aber das Jahressechstel nicht."""
|
||
employee = self._employee()
|
||
slip_ohne = self._slip(employee, 1)
|
||
regel = self._regel('T_ABS6_UEB', 1000.0, sv_art='keine')
|
||
regel.l10n_at_s67_abs6_ueberhang = True
|
||
slip_mit = self._slip(employee, 2)
|
||
|
||
self.assertAlmostEqual(
|
||
slip_mit._l10n_at_abs6_ueberhang_total(), 1000.0, places=2)
|
||
self.assertAlmostEqual(
|
||
slip_mit._l10n_at_bemessung_laufen()
|
||
- slip_ohne._l10n_at_bemessung_laufen(), 1000.0, places=2)
|
||
self.assertAlmostEqual(
|
||
slip_mit._l10n_at_sechstel() - slip_ohne._l10n_at_sechstel(),
|
||
0.0, places=2)
|
||
|
||
# ------------------------------------------------------------------
|
||
# § 68 Freibeträge (Buckets über Regel-Flags)
|
||
# ------------------------------------------------------------------
|
||
def test_68_freibetraege(self):
|
||
employee = self._employee()
|
||
self._regel('L68A', 300.0, flag68='szfn', anteil=50.0)
|
||
self._regel('L68B', 300.0, flag68='szfn', anteil=50.0) # 300 gesamt > 400? 2x150=300
|
||
self._regel('L68C', 41.19, flag68='ue_std', anteil=33.33, quantity='2.0')
|
||
slip = self._slip(employee, 1)
|
||
freibe = slip._l10n_at_freibetraege_68()
|
||
# szfn: 150 + 150 = 300 ≤ 400
|
||
self.assertAlmostEqual(freibe['szfn'], 300.0, places=2)
|
||
# ue_std: 41,19 × 2 h? total = 41,19 × 2 = 82,38; Anteil 33,33 %
|
||
# → 27,46; 2 h ≤ 15; ≤ 170
|
||
self.assertAlmostEqual(freibe['ue_std'], 27.46, places=2)
|
||
slip.version_id.write({'l10n_at_ueberw_nachtarbeit': True})
|
||
freibe = slip._l10n_at_freibetraege_68()
|
||
self.assertAlmostEqual(freibe['szfn'], 300.0, places=2)
|
||
|
||
def test_68_ue_std_cap(self):
|
||
"""§ 68 Abs 2 iVm § 124b Z 440: 15 ÜStd/170 € (2026)."""
|
||
employee = self._employee()
|
||
# 20 ÜStd à 41,19 (Anteil 33,33 %) → Zuschlag 274,60; > 15 h
|
||
# → anteilig 15/20; cap 170 greift
|
||
self._regel('LUE', 41.19, flag68='ue_std', anteil=33.33, quantity='20.0')
|
||
slip = self._slip(employee, 1)
|
||
freibe = slip._l10n_at_freibetraege_68()
|
||
self.assertAlmostEqual(
|
||
freibe['ue_std'], min(41.19 * 20 * 0.3333 * 15 / 20, 170.0), places=2)
|
||
self.assertAlmostEqual(freibe['ue_std'], 170.0, places=1)
|
||
|
||
# ------------------------------------------------------------------
|
||
# DN-SV / Bemessung (user-Formel)
|
||
# ------------------------------------------------------------------
|
||
def test_05_svdn_und_bemessung(self):
|
||
"""SV-DN auf 2.059,41 €: § 2a AMPFG mindert den DN-AV auf 0 %
|
||
(BG ≤ 2.225 €) → DN-Gesamt 15,12 % statt 18,07 % (GP4-Staffel;
|
||
DG-AV bleibt 2,95 %); Bemessung = Arbeitslohn − SV-DN."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2059.41)
|
||
slip = self._slip(employee, 1)
|
||
svdn = slip._l10n_at_svdn_gesamt()
|
||
self.assertAlmostEqual(svdn, 2059.41 * 0.1512, places=2)
|
||
bem = slip._l10n_at_bemessung_laufen()
|
||
self.assertAlmostEqual(bem, 2059.41 - svdn, places=2)
|
||
|
||
def test_06_svdn_wien_wf(self):
|
||
employee = self._employee()
|
||
self._regel('LFD', 2059.41)
|
||
slip = self._slip(employee, 1)
|
||
slip.company_id.write({'l10n_at_wf_wien': True})
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_svdn('wf'), 2059.41 * 0.0075, places=2)
|
||
|
||
# ------------------------------------------------------------------
|
||
# § 66 kumulative Monatslohnsteuer + Rollung
|
||
# ------------------------------------------------------------------
|
||
def test_07_lst_laufend_monat(self):
|
||
"""Vollmonat: JBG = Bemessung × 12 − 192; Tarif − Verkehrs-AB."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2059.41)
|
||
slip = self._slip(employee, 1)
|
||
svdn = slip._l10n_at_svdn_gesamt()
|
||
bem = 2059.41 - svdn
|
||
jbg = bem * 12 - 132 - 60
|
||
erwartet = max(0.0, (0.20 * (jbg - 13539)) - 496.0) / 12
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_lst_laufend(), erwartet, places=2)
|
||
|
||
def test_08_lst_rollung_zweiter_monat(self):
|
||
"""Kumulativ mit LST-Linie: Februar zahlt die Differenz zum
|
||
Jänner-Soll (Rollung über result_rules-Mechanik)."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2059.41)
|
||
self._regel(
|
||
'LST_LFD', 0.0, bemessung='neutral',
|
||
python='result = payslip._l10n_at_lst_laufend(result_rules)')
|
||
slip_jan = self._slip(employee, 1, confirm=True)
|
||
jan = self._total(slip_jan, 'LST_LFD')
|
||
slip_feb = self._slip(employee, 2)
|
||
feb = self._total(slip_feb, 'LST_LFD')
|
||
# Identisches Gehalt: Feb-Soll ≈ Jan-Soll (kumulative Neuberechnung
|
||
# minus bereits einbehaltene LSt)
|
||
self.assertAlmostEqual(feb, jan, places=2)
|
||
# Rollung: dritter Monat zieht die Differenz nach
|
||
slip_mar = self._slip(employee, 3)
|
||
self.assertAlmostEqual(self._total(slip_mar, 'LST_LFD'), jan, places=2)
|
||
|
||
# ------------------------------------------------------------------
|
||
# § 67 sonstige Bezüge
|
||
# ------------------------------------------------------------------
|
||
def test_09_lst_sonstige_b13(self):
|
||
"""B13 über Freigrenze: Fixsatz 6 % nach 620-Freibetrag;
|
||
Abs 12: SV-DN vom SZ vorher. SZ-Regel erst NACH dem Oktober-
|
||
lauf anlegen (sonst zahlt Oktober fälschlich SZ)."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2059.41)
|
||
slip_okt = self._slip(employee, 10, confirm=True)
|
||
self._regel('SZ', 2059.41, bemessung='sonstig')
|
||
slip_nov = self._slip(employee, 11)
|
||
sz_bem = slip_nov._l10n_at_sz_bemessung()
|
||
sv_sz = 2059.41 * 0.1412 # KV+PV auf SZ-Basis; AV-DN 0 (§ 2a)
|
||
self.assertAlmostEqual(sz_bem, 2059.41 - sv_sz, places=2)
|
||
# Sechstel = 2 × 2059,41 × 60 ÷ 60 = 4.118,82 > Freigrenze
|
||
self.assertAlmostEqual(
|
||
slip_nov._l10n_at_sechstel(), 2 * 2059.41, places=2)
|
||
erwartet = (sz_bem - 620.0) * 0.06
|
||
self.assertAlmostEqual(
|
||
slip_nov._l10n_at_lst_sonstige(), erwartet, places=2)
|
||
self.assertAlmostEqual(slip_nov._l10n_at_sz_tarifisch_aktuell(), 0.0, places=2)
|
||
|
||
def test_10_sechstel_freigrenze_tarifisch(self):
|
||
"""Sechstel ≤ 2.615 €: Pauschalierung unterbleibt — SZ läuft
|
||
tarifisch über die §-66-Kette."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 500.0)
|
||
self._regel('SZ', 300.0, bemessung='sonstig')
|
||
slip = self._slip(employee, 1)
|
||
# Sechstel = 500 × 60/30 = 1.000 ≤ 2.615
|
||
self.assertAlmostEqual(slip._l10n_at_sechstel(), 1000.0, places=2)
|
||
self.assertAlmostEqual(slip._l10n_at_lst_sonstige(), 0.0, places=2)
|
||
sz_bem = slip._l10n_at_sz_bemessung()
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_sz_tarifisch_aktuell(), sz_bem, places=2)
|
||
|
||
def test_11_guenstig_aufrollung_zweite_sz(self):
|
||
"""Günstig-Aufrollung: zweite SZ-Zahlung rechnet die Jahres-
|
||
SZ-Steuer mit dem dann aktuellen Sechstel neu."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2059.41)
|
||
slip_okt = self._slip(employee, 10, confirm=True)
|
||
self._regel('SZ', 2059.41, bemessung='sonstig')
|
||
self._regel(
|
||
'LST_SZ', 0.0, bemessung='neutral',
|
||
python='result = payslip._l10n_at_lst_sonstige(result_rules)')
|
||
slip_nov = self._slip(employee, 11, confirm=True)
|
||
sz_nov = self._total(slip_nov, 'LST_SZ')
|
||
# SV-SZ = 2.059,41 × 14,12 % (KV+PV; AV-DN 0 nach § 2a AMPFG)
|
||
self.assertAlmostEqual(
|
||
sz_nov, (2059.41 * (1 - 0.1412) - 620.0) * 0.06, places=1)
|
||
slip_dez = self._slip(employee, 12)
|
||
sz_dez = self._total(slip_dez, 'LST_SZ')
|
||
# Jahres-SZ-Bemessung = 2 × (2.059,41 − SV-SZ)
|
||
jahres_bem = 2 * 2059.41 * (1 - 0.1412)
|
||
soll_jahr = (jahres_bem - 620.0) * 0.06
|
||
self.assertAlmostEqual(sz_dez, soll_jahr - sz_nov, places=1)
|
||
|
||
def test_12_sz_ueberschuss_tarifisch(self):
|
||
"""§ 67 Abs 10: SZ über dem Sechstel läuft tarifisch (LSt-lfd);
|
||
Sechstel muss über der Freigrenze 2.615 € liegen."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2000.0)
|
||
self._regel('SZ', 6000.0, bemessung='sonstig')
|
||
slip = self._slip(employee, 1)
|
||
# Sechstel = 2.000 × 60/30 = 4.000 > 2.615 → Pauschalierung
|
||
self.assertAlmostEqual(slip._l10n_at_sechstel(), 4000.0, places=2)
|
||
sz_bem = slip._l10n_at_sz_bemessung() # 6.000 − SV-SZ (14,12 %)
|
||
self.assertAlmostEqual(sz_bem, 6000.0 - 6000.0 * 0.1412, places=2)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_sz_tarifisch_aktuell(), sz_bem - 4000.0, places=2)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_lst_sonstige(), (4000.0 - 620.0) * 0.06, places=1)
|
||
|
||
# ------------------------------------------------------------------
|
||
# § 3/§ 26 — steuerfreie Sachbezüge (Freibeträge, Jahres-Kumulative)
|
||
# ------------------------------------------------------------------
|
||
def test_13_st_frei_mahlzeit(self):
|
||
"""Mahlzeiten-Gutschein 11 €/AT × 10 AT = 110 €: 80 € steuerfrei
|
||
(8 €/AT, § 3 Abs 1 Z 17), 30 € steuerpflichtig; LSt-Bemessung
|
||
um 80 € reduziert (lb-sac-17)."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2000.0)
|
||
self._regel('MAH', 11.0, quantity='10.0', st_frei='mahlzeit')
|
||
slip = self._slip(employee, 1)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_st_frei_freie_laufen(), 80.0, places=2)
|
||
svdn = slip._l10n_at_svdn_gesamt()
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_bemessung_laufen(),
|
||
2000.0 + 110.0 - svdn - 80.0, places=2)
|
||
|
||
def test_14_st_frei_jahrespools(self):
|
||
"""Jahres-Kumulative: Betriebsveranstaltung 365 €/J (Freibetrag)
|
||
und Sachzuwendung/Jubiläum 186 €/J als separate Pools
|
||
(§ 3 Abs 1 Z 14; lb-sac-07, lb-ges-02)."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2000.0)
|
||
self._regel('BV', 200.0, st_frei='betriebsveranstaltung')
|
||
slip_a = self._slip(employee, 1, confirm=True)
|
||
self.assertAlmostEqual(
|
||
slip_a._l10n_at_st_frei_freie_laufen(), 200.0, places=2)
|
||
# Februar: 165 € Rest (365 − 200) → 165 frei, 35 steuerpflichtig
|
||
slip_b = self._slip(employee, 2, confirm=True)
|
||
self.assertAlmostEqual(
|
||
slip_b._l10n_at_st_frei_freie_laufen(), 165.0, places=2)
|
||
# März: Pool verbraucht → 0 frei, 200 steuerpflichtig
|
||
slip_c = self._slip(employee, 3)
|
||
self.assertAlmostEqual(
|
||
slip_c._l10n_at_st_frei_freie_laufen(), 0.0, places=2)
|
||
# Sachzuwendung separater Pool: 300 € → 186 frei, 114 pflichtig
|
||
self._regel('GSC', 300.0, st_frei='jubilaeum')
|
||
slip_d = self._slip(employee, 4)
|
||
self.assertAlmostEqual(
|
||
slip_d._l10n_at_st_frei_freie_laufen(), 186.0, places=2)
|
||
|
||
def test_15_st_frei_homeoffice(self):
|
||
"""Homeoffice 3 €/Tag, max 100 Tage/Jahr (§ 26 Z 9): 70 Tage im
|
||
Jänner (210 frei), Februar nur 30 Tage frei (90), 40 Tage × 3 =
|
||
120 steuerpflichtig."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2000.0)
|
||
self._regel('HO', 3.0, quantity='70.0', st_frei='homeoffice')
|
||
slip_a = self._slip(employee, 1, confirm=True)
|
||
self.assertAlmostEqual(
|
||
slip_a._l10n_at_st_frei_freie_laufen(), 210.0, places=2)
|
||
# Februar: 30 Tage Rest (100 − 70) → 90 frei, 120 steuerpflichtig
|
||
slip_b = self._slip(employee, 2)
|
||
self.assertAlmostEqual(
|
||
slip_b._l10n_at_st_frei_freie_laufen(), 90.0, places=2)
|
||
|
||
def test_16_st_frei_neutral(self):
|
||
"""Ohne st_frei-Flag keine Wirkung auf die LSt-Bemessung
|
||
(Regression)."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 2000.0)
|
||
slip = self._slip(employee, 1)
|
||
self.assertAlmostEqual(slip._l10n_at_st_frei_freie_laufen(), 0.0)
|
||
svdn = slip._l10n_at_svdn_gesamt()
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_bemessung_laufen(), 2000.0 - svdn, places=2)
|
||
|
||
def test_17_sv_art_entkoppelt_lst_art(self):
|
||
"""SV-Art folgt standardmäßig der LSt-Art; Drittlohn kann nur
|
||
SV-laufend sein, Hardware-Verkauf LSt-sonstig/SV-laufend."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 100.0)
|
||
self._regel('DRITT', 300.0, bemessung='neutral', sv_art='laufend')
|
||
self._regel('HW', 200.0, bemessung='sonstig', sv_art='laufend')
|
||
slip = self._slip(employee, 1)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_sv_brutto('laufend'), 600.0, places=2)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_sv_brutto('sonstig'), 0.0, places=2)
|
||
self.assertAlmostEqual(slip._l10n_at_svdn_basis_sz(), 0.0, places=2)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_brutto('laufend'), 100.0, places=2)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_brutto('sonstig'), 200.0, places=2)
|
||
|
||
def test_18_sv_art_folgt_ist_neutral(self):
|
||
"""Der Default 'folgt' erhält bestehende laufende und sonstige
|
||
SV-Zuordnungen unverändert."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 100.0)
|
||
self._regel('SZ', 200.0, bemessung='sonstig')
|
||
slip = self._slip(employee, 1)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_sv_brutto('laufend'), 100.0, places=2)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_sv_brutto('sonstig'), 200.0, places=2)
|
||
|
||
def test_19_sv_art_keine_nur_lst(self):
|
||
"""SV-Art 'keine' schließt eine Regel ausschließlich aus der
|
||
SV aus; die deklarierte LSt-Bemessung bleibt unverändert."""
|
||
employee = self._employee()
|
||
self._regel('LFD', 100.0)
|
||
self._regel('NUR_LST', 300.0, sv_art='keine')
|
||
slip = self._slip(employee, 1)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_sv_brutto('laufend'), 100.0, places=2)
|
||
self.assertAlmostEqual(
|
||
slip._l10n_at_brutto('laufend'), 400.0, places=2)
|