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: GP6 FI-Buchung UGB (KFS/BW-6-Matrix, EKR-Debit-Split, NET-Konvention)
Buchungsmatrix nach dem Oesterreichischen Einheitskontenrahmen (KFS/BW 6; Nutzer-Referenz-Exemplar .additional_docs/KFSBW6_13072017_RF.pdf): Hook _configure_payroll_account_at (models/account_chart_private.py) ordnet Regelkonten, Journal SLR (Default = Gehaelterkonto 6200, BE-Muster) und das NET-Konto 3850 "Verbindlichkeiten aus Lohn und Gehalt" (Nutzer-Entscheidung 5.1; Anlage + reconcile, l10n_at-Standardchart hat es nicht) je Company zu — getriggert beim Chart-Load (_post_load_data) UND ueber die <function>-Datendatei data/hr_payroll_account_private.xml fuer Bestands-Companies (erster <value> einer function ist die Record-ID-Liste, convert.py-Semantik), idempotent. Konto-Suche exakt zuerst, Praefix-Fallback nur bis eine Stelle laenger — verhindert Matches auf Odoo-Scaffold-Konten chartloser Firmen (6000 darf nicht 600000 "Expenses" matchen). EKR-Debit-Split Arbeiter/Angestellte (Nutzer-Klaerung: 600-619 Loehne, 620-639 Gehaelter — "6000 Gehaelter/6200 Loehne" war gegen die eigene KFS/BW-6-Referenz vertauscht): l10n_at_personalgruppe am Vertrag (models/hr_version_private.py) + Override-Feld l10n_at_account_debit_arbeiter je Regel; Option A minimal (Nutzer-Entscheidung 5.2: Grundentgelt 6000, Sozialaufwand 6500, Abgaben 6600/6601/6602; Zuschlaege/UeStd/Praemien/SZ und BV (EKR 644 ohne Split) buchen fuer Arbeiter bis zur Referenzbuchhaltungs-Fixierung auf die Angestellten-Konten — fehlende Konten warnen, keine Erfindung). models/account_posting_private.py: Gesamtueberschreibung von _prepare_slip_lines nach Upstream-Muster (Odoo-Pin 19.0+e.20260910) mit einzeiliger Kontosubstitution — Odoo bietet dafuer keinen Override-Punkt; Verhalten testgepinnt. Matrix: KVGEO/URL_UE 6200/6000, Zuschlaege 6225, UeStd 6310, Praemien 6230, B13/B14 6240, DN-SV/LSt auf 3600/3540, NET 3850, SVDG-Block 6560/6500 auf 3600, BVG 6440 (Fallback 6400) auf Credit 3600 (Abfuhr via KV-Traeger, Nutzer 5.3), FLAFDB 6661/6601 auf 3541, KOMMST 6660/6600 auf 3550, DZ 6662/6602 auf 3542. NET-Umbenennung NETTO -> NET (Odoo-Konvention: action_register_payment, net_wage und Negativ-Netto-Erkennung filtern code == NET) inkl. 4 Bestands-Suiten. Odoo-19-Fund: das Anlegen einer Structure kopiert die Regeln des hr_payroll.default_structure (BASIC/GROSS/NET/...) via Feld-Default in rule_ids — die kopierte Default-NET-Regel kollidierte im result_rules-Dict (Netto fiel auf 0); Fix: <function> in salary_rules_private.xml archiviert die Kopie (active=False; KEIN Unlink — struct_id ist NOT NULL und historische Lohnkontolinien behalten ihre Regel-Referenz; One2many blendet Archivierte aus). Journal-Default-Konten duerfen nicht Receivable/Payable sein (Odoo-Constraint); Rundungscents bucht Odoo als Adjustment Entry aufs Journal-Default. depends: + l10n_at, hr_payroll_account_iso20022 (SEPA-Auszahlung, Plan 4.5; kein VRV/MVAG — gem360-Bruecke). Tests: test_account_private (4: RF-BUCH-1..4 — Kontenplan-Mock ohne Chart-Install, Move-Balance, Kontenzeilen je Matrix, Arbeiter-Split, Geringfuegiger, Fallback/Warnung) — gesamt 88/88 gruen auf Wegwerf-DB (frischer -i-Lauf). Rechenfaelle docs/rechenfaelle/buchhaltung.md. 19.0.6.0.0.
This commit is contained in:
@@ -4,4 +4,6 @@ from . import hr_version_private
|
||||
from . import payslip_private
|
||||
from . import bv_kasse
|
||||
from . import abfertigung_private
|
||||
from . import bv_report
|
||||
from . import bv_report
|
||||
from . import account_chart_private
|
||||
from . import account_posting_private
|
||||
@@ -0,0 +1,238 @@
|
||||
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||||
"""GP6 FI-Buchung UGB: Buchungsmatrix nach dem Österreichischen
|
||||
Einheitskontenrahmen (KFS/BW 6, Fachsenat Betriebswirtschaft der
|
||||
Kammer der Wirtschaftstreuhänder 2017 — Nutzer-Referenz 2026-09-12)
|
||||
für die privatwirtschaftliche Structure.
|
||||
|
||||
Matrix (Nutzer-Entscheidungen 2026-09-12): Angestellte buchen auf
|
||||
Gehälter (620–639), Sozialaufwand Angestellte (656–659) und
|
||||
gehaltsabhängige Abgaben (666–669); Arbeiter über das Debit-Override-
|
||||
Feld ``l10n_at_account_debit_arbeiter`` auf Löhne (600–619),
|
||||
Sozialaufwand Arbeiter (650–655) und lohnabhängige Abgaben (660–665)
|
||||
— Option A minimal: nur Grundentgelt 6000, Sozialaufwand 6500 und
|
||||
Abgaben 6600/6601/6602; Zuschläge/ÜStd/SZ/Prämien buchen bis zur
|
||||
Referenzbuchhaltungs-Fixierung auf die Angestellten-Konten. Credits
|
||||
sind gruppenneutral (Verrechnungskonten 3540/3541/3542/3550/3600).
|
||||
NET-Konto **3850 „Verbindlichkeiten aus Lohn und Gehalt"** (EKR-Bereich
|
||||
370–389 übrige sonstige Verbindlichkeiten) wird angelegt, wenn es
|
||||
fehlt, und auf reconcile gesetzt — die Zahlungsregistrierung prüft
|
||||
``NET.account_credit.reconcile``. BV-Verbindlichkeit 3600 (Abfuhr
|
||||
über den KV-Träger); BV-Aufwand: Kandidatensuche 6440 (EKR 644)
|
||||
vor 6400 (Odoo-l10n_at-Standard).
|
||||
|
||||
Trigger: (1) automatisch beim Laden des AT-Kontenrahmens
|
||||
(``account.chart.template._post_load_data`` →
|
||||
``_load_payroll_accounts``, Kontext ``chart_template_load``) und
|
||||
(2) über die ``<function>``-Datendatei für Bestands-Companies bei
|
||||
Modul-Install/-Update. Beide Pfade sind idempotent.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
# Buchungsmatrix: Regel-XML-ID → Konten-Kandidaten (Präfixsuche je
|
||||
# Company-Chart; erster Treffer gewinnt; fehlende Konten werden nur
|
||||
# gewarnt — der Referenzbuchhaltungs-Kontenplan ist verbindlich,
|
||||
# GP0-Rest). 'debit' = Standard (Angestellte), 'debit_arbeiter' =
|
||||
# Override für Personalgruppe Arbeiter, 'credit' = Verrechnungskonto.
|
||||
L10N_AT_BUCHUNGSMATRIX = {
|
||||
# Entgelt (KFS/BW 6: 600–619 Löhne · 620–639 Gehälter)
|
||||
'rule_kvgeo': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
|
||||
'rule_url_ue': {'debit': ('6200',), 'debit_arbeiter': ('6000',)},
|
||||
'rule_nacht_sv': {'debit': ('6225',)},
|
||||
'rule_mehr_vz': {'debit': ('6225',)},
|
||||
'rule_mehr_vz_nacht': {'debit': ('6225',)},
|
||||
'rule_mehr_tz': {'debit': ('6225',)},
|
||||
'rule_mehr_tz_nacht': {'debit': ('6225',)},
|
||||
'rule_ue_std': {'debit': ('6310',)},
|
||||
'rule_ue_nacht': {'debit': ('6310',)},
|
||||
'rule_ue_nacht_frueh': {'debit': ('6310',)},
|
||||
'rule_ue_sofei': {'debit': ('6310',)},
|
||||
'rule_ue_sofei_nacht': {'debit': ('6310',)},
|
||||
'rule_pram': {'debit': ('6230',)},
|
||||
'rule_b13': {'debit': ('6240',)},
|
||||
'rule_b14': {'debit': ('6240',)},
|
||||
'rule_b14_rueck': {'debit': ('6240',)},
|
||||
# Abzüge DN (§ 62-Kette) und Lohnsteuer — Credit-Verrechnungen
|
||||
'rule_svdn_kv': {'credit': ('3600',)},
|
||||
'rule_svdn_pv': {'credit': ('3600',)},
|
||||
'rule_svdn_av': {'credit': ('3600',)},
|
||||
'rule_svdn_ak': {'credit': ('3600',)},
|
||||
'rule_svdn_wf': {'credit': ('3600',)},
|
||||
'rule_svdn_sz': {'credit': ('3600',)},
|
||||
'rule_lst_lfd': {'credit': ('3540',)},
|
||||
'rule_lst_sz': {'credit': ('3540',)},
|
||||
# Nettoauszahlung (reconcilable, s. o.)
|
||||
'rule_netto': {'credit': ('3850',)},
|
||||
# DG-Beiträge (650–655 SV Arbeiter · 656–659 SV Angestellte)
|
||||
'rule_svdg_kv': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_pv': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_av': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_uv': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_wf': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_iesg': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_sz_kv': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_sz_pv': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_sz_av': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_sz_uv': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_sz_iesg': {'debit': ('6560',),
|
||||
'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
'rule_svdg_uv_gfg': {'debit': ('6560',), 'debit_arbeiter': ('6500',),
|
||||
'credit': ('3600',)},
|
||||
# Abfertigung Neu: Aufwand 644 (EKR) mit Fallback Odoo-Standard
|
||||
# 6400; Abfuhr über den KV-Träger → Verrechnung 3600 (5.3).
|
||||
'rule_bvg': {'debit': ('6440', '6400'), 'credit': ('3600',)},
|
||||
# Lohnabhängige Abgaben: 666er gehaltsabhängig (Angestellte),
|
||||
# 660er lohnabhängig (Arbeiter); Verrechnungen 3541/3550/3542.
|
||||
'rule_flafdb': {'debit': ('6661',), 'debit_arbeiter': ('6601',),
|
||||
'credit': ('3541',)},
|
||||
'rule_kommst': {'debit': ('6660',), 'debit_arbeiter': ('6600',),
|
||||
'credit': ('3550',)},
|
||||
'rule_dz': {'debit': ('6662',), 'debit_arbeiter': ('6602',),
|
||||
'credit': ('3542',)},
|
||||
}
|
||||
|
||||
|
||||
class HrSalaryRule(models.Model):
|
||||
_inherit = 'hr.salary.rule'
|
||||
|
||||
l10n_at_account_debit_arbeiter = fields.Many2one(
|
||||
'account.account', string='AT Debitkonto Arbeiter (EKR)',
|
||||
company_dependent=True, ondelete='restrict',
|
||||
help='Debit-Override der Lohnverrechnungsbuchung für Arbeiter '
|
||||
'(KFS/BW 6: Löhne 600–619, Sozialaufwand Arbeiter '
|
||||
'650–655, lohnabhängige Abgaben 660–665). Leer = '
|
||||
'Buchung auf das Standard-Debitkonto (Angestellte). '
|
||||
'Nur Aufwandskonten splitten; Verrechnungskonten sind '
|
||||
'gruppenneutral.')
|
||||
|
||||
|
||||
class AccountChartTemplate(models.AbstractModel):
|
||||
_inherit = 'account.chart.template'
|
||||
|
||||
def _l10n_at_buchungskonto(self, company, codes):
|
||||
"""Konto je Kandidaten-Code: exakter Code zuerst, sonst
|
||||
Praefix-Fallback nur fuer leicht verlaengerte Konten (max. eine
|
||||
Stelle, z. B. 6200 → 62000) — blockiert Odoo-Scaffold-Konten
|
||||
chartloser Firmen (6000 darf nicht auf 600000 „Expenses"
|
||||
matchen). Leer, wenn nichts Passendes existiert."""
|
||||
account_model = self.env['account.account'].with_company(company)
|
||||
basis = account_model._check_company_domain(company)
|
||||
for code in codes:
|
||||
account = account_model.search(
|
||||
basis + [('code', '=', code)], limit=1)
|
||||
if account:
|
||||
return account
|
||||
kandidaten = account_model.search(
|
||||
basis + [('code', '=like', '%s%%' % code)])
|
||||
account = kandidaten.filtered(
|
||||
lambda a: len(a.code) <= len(code) + 1)[:1]
|
||||
if account:
|
||||
return account
|
||||
return self.env['account.account']
|
||||
|
||||
def _l10n_at_netto_konto(self, company):
|
||||
"""NET-Konto 3850 'Verbindlichkeiten aus Lohn und Gehalt'
|
||||
(EKR 370–389): anlegen, wenn es fehlt; reconcile erzwingen —
|
||||
die Zahlungsregistrierung prüft NET.account_credit.reconcile
|
||||
konten (hr_payroll_account) und l10n_at führt alle Verrechnungs-
|
||||
konten reconcile."""
|
||||
konto = self._l10n_at_buchungskonto(company, ('3850',))
|
||||
if not konto:
|
||||
konto = self.env['account.account'].with_company(
|
||||
company).create({
|
||||
'name': 'Verbindlichkeiten aus Lohn und Gehalt',
|
||||
'code': '3850',
|
||||
'account_type': 'liability_payable',
|
||||
'reconcile': True,
|
||||
})
|
||||
elif not konto.reconcile:
|
||||
konto.reconcile = True
|
||||
return konto
|
||||
|
||||
def _l10n_at_lohnjournal(self, company, aufwand_konto):
|
||||
"""Lohnjournal SLR (Code des hr_payroll_account-Templates)
|
||||
suchen oder anlegen. Default-Konto = Gehälter-Aufwandskonto
|
||||
(6200, BE-Muster: Journal-Default des Lohnjournals ist das
|
||||
Bezugs-Aufwandskonto; die Unbalance-Ausgleichsbuchung
|
||||
_prepare_adjust_line läuft darüber) — NICHT das NET-Konto:
|
||||
Journal-Defaultkonten dürfen nach Odoo-Constraint nicht
|
||||
Receivable/Payable sein (Constraint
|
||||
_check_account_is_bank_journal_bank_account)."""
|
||||
journal_model = self.env['account.journal'].with_company(company)
|
||||
journal = journal_model.search([
|
||||
*journal_model._check_company_domain(company),
|
||||
('code', '=', 'SLR'),
|
||||
], limit=1)
|
||||
if not journal:
|
||||
journal = journal_model.create({
|
||||
'name': 'Lohnverrechnung',
|
||||
'code': 'SLR',
|
||||
'type': 'general',
|
||||
})
|
||||
if not journal.default_account_id and aufwand_konto:
|
||||
journal.default_account_id = aufwand_konto.id
|
||||
return journal
|
||||
|
||||
def _configure_payroll_account_at(self, companies):
|
||||
"""Buchungsmatrix je Company anwenden (idempotent): Konten je
|
||||
Kandidaten-Code suchen (fehlende nur warnen — der Kontenplan
|
||||
der Referenzbuchhaltung ist verbindlich, GP0-Rest), NET-Konto
|
||||
3850 sicherstellen, Journal SLR zuordnen."""
|
||||
netto_konto = False
|
||||
journal = False
|
||||
fehlend = []
|
||||
for company in companies:
|
||||
netto_konto = self._l10n_at_netto_konto(company)
|
||||
gehaelter_konto = self._l10n_at_buchungskonto(company, ('6200',))
|
||||
if not gehaelter_konto:
|
||||
fehlend.append('rule_kvgeo → (\'6200\',) [Journal-Standard]')
|
||||
journal = self._l10n_at_lohnjournal(company, gehaelter_konto)
|
||||
for xmlid, mapping in L10N_AT_BUCHUNGSMATRIX.items():
|
||||
rule = self.env.ref(
|
||||
'l10n_at_hr_payroll_private.%s' % xmlid, raise_if_not_found=False)
|
||||
if not rule:
|
||||
continue
|
||||
vals = {}
|
||||
for feld, schluessel in (
|
||||
('account_debit', 'debit'),
|
||||
('l10n_at_account_debit_arbeiter', 'debit_arbeiter'),
|
||||
('account_credit', 'credit')):
|
||||
codes = mapping.get(schluessel)
|
||||
if not codes:
|
||||
continue
|
||||
if codes == ('3850',):
|
||||
konto = netto_konto
|
||||
else:
|
||||
konto = self._l10n_at_buchungskonto(company, codes)
|
||||
if not konto:
|
||||
fehlend.append('%s → %s' % (xmlid, codes))
|
||||
continue
|
||||
vals[feld] = konto.id
|
||||
if vals:
|
||||
rule.with_company(company).write(vals)
|
||||
struktur = self.env.ref(
|
||||
'l10n_at_hr_payroll_private.structure_at_privat',
|
||||
raise_if_not_found=False)
|
||||
if struktur:
|
||||
struktur.with_company(company).journal_id = journal
|
||||
if fehlend:
|
||||
_logger.warning(
|
||||
'AT-Payroll-Buchungsmatrix: fehlende Konten nicht '
|
||||
'zugeordnet (Referenzbuchhaltung pflegen): %s',
|
||||
', '.join(fehlend))
|
||||
return {'netto_konto': netto_konto, 'journal': journal,
|
||||
'fehlend': fehlend}
|
||||
@@ -0,0 +1,89 @@
|
||||
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||||
"""GP6: EKR-Debit-Split Arbeiter/Angestellte im Buchungslauf.
|
||||
|
||||
``hr_payroll_account`` liest die Buchungskonten statisch je Regel
|
||||
(``hr.salary.rule.account_debit`` — Company-Property). Der Arbeiter/
|
||||
Angestellte-Split des Einheitskontenrahmen braucht dieselbe Regel je
|
||||
Personalgruppe auf zwei Konten — Odoo bietet dafür keinen Override-
|
||||
Punkt (Accounts werden direkt in der Posting-Schleife gelesen).
|
||||
Deshalb Gesamtüberschreibung von ``_prepare_slip_lines`` nach dem
|
||||
Upstream-Muster (``hr_payroll_account/models/hr_payslip.py``, Odoo-
|
||||
Pin 19.0+e.20260910) mit genau einer Substitution: Debit-Konto =
|
||||
``l10n_at_account_debit_arbeiter``, wenn die Personalgruppe des
|
||||
Vertrags 'arbeiter' ist und ein Override gesetzt ist. Credits sind
|
||||
gruppenneutral (Verrechnungskonten). Das Verhalten ist durch
|
||||
``test_account_private.py`` gepinnt; bei Odoo-Upgrades gegen den Pin
|
||||
neu abgleichen (Muster: hr_payroll_account Upstream).
|
||||
"""
|
||||
from odoo import models
|
||||
from odoo.tools import float_is_zero
|
||||
|
||||
|
||||
class HrPayslip(models.Model):
|
||||
_inherit = 'hr.payslip'
|
||||
|
||||
def _prepare_slip_lines(self, date, line_ids):
|
||||
self.ensure_one()
|
||||
precision = self.env['decimal.precision'].precision_get('Payroll')
|
||||
new_lines = []
|
||||
for line in self.line_ids.filtered(lambda line: line.category_id):
|
||||
amount = line.total
|
||||
if line.code == 'NET': # Check if the line is the 'Net Salary'.
|
||||
for tmp_line in self.line_ids.filtered(lambda line: line.category_id):
|
||||
if tmp_line.salary_rule_id.not_computed_in_net: # Check if the rule must be computed in the 'Net Salary' or not.
|
||||
if amount > 0:
|
||||
amount -= abs(tmp_line.total)
|
||||
elif amount < 0:
|
||||
amount += abs(tmp_line.total)
|
||||
if float_is_zero(amount, precision_digits=precision):
|
||||
continue
|
||||
debit_account = line.salary_rule_id.account_debit
|
||||
credit_account = line.salary_rule_id.account_credit
|
||||
# GP6 EKR-Split (KFS/BW 6): Personalgruppe 'arbeiter' am
|
||||
# Vertrag bucht auf das Arbeiter-Debitkonto, wenn ein
|
||||
# Override gesetzt ist (Option A minimal); sonst Standard-
|
||||
# debit (Angestellte). Referenzbuchhaltung pflegt die
|
||||
# Company-Properties je Kontenplan.
|
||||
if (self.version_id.l10n_at_personalgruppe == 'arbeiter'
|
||||
and line.salary_rule_id.l10n_at_account_debit_arbeiter):
|
||||
debit_account = \
|
||||
line.salary_rule_id.l10n_at_account_debit_arbeiter
|
||||
merge_amounts = self.company_id.batch_payroll_move_lines \
|
||||
or not line.salary_rule_id.employee_move_line
|
||||
|
||||
if debit_account.id: # If the rule has a debit account.
|
||||
if self.company_id.account_storno and self.credit_note:
|
||||
debit = amount if amount < 0.0 else 0.0
|
||||
credit = -amount if amount > 0.0 else 0.0
|
||||
else:
|
||||
debit = amount if amount > 0.0 else 0.0
|
||||
credit = -amount if amount < 0.0 else 0.0
|
||||
|
||||
debit_line = merge_amounts and next(self._get_existing_lines(
|
||||
line_ids + new_lines, line, debit_account.id, debit, credit), False)
|
||||
|
||||
if not debit_line:
|
||||
debit_lines = self._prepare_line_values(line, debit_account, date, debit, credit)
|
||||
new_lines.extend(debit_lines)
|
||||
else:
|
||||
debit_line['debit'] += debit
|
||||
debit_line['credit'] += credit
|
||||
|
||||
if credit_account.id: # If the rule has a credit account.
|
||||
if self.company_id.account_storno and self.credit_note:
|
||||
debit = -amount if amount > 0.0 else 0.0
|
||||
credit = amount if amount < 0.0 else 0.0
|
||||
else:
|
||||
debit = -amount if amount < 0.0 else 0.0
|
||||
credit = amount if amount > 0.0 else 0.0
|
||||
|
||||
credit_line = merge_amounts and next(self._get_existing_lines(
|
||||
line_ids + new_lines, line, credit_account.id, debit, credit), False)
|
||||
|
||||
if not credit_line:
|
||||
credit_lines = self._prepare_line_values(line, credit_account, date, debit, credit)
|
||||
new_lines.extend(credit_lines)
|
||||
else:
|
||||
credit_line['debit'] += debit
|
||||
credit_line['credit'] += credit
|
||||
return new_lines
|
||||
@@ -33,6 +33,17 @@ class HrVersion(models.Model):
|
||||
"z. B. § 18 Anrechnung der Rahmen-KVs).")
|
||||
currency_id = fields.Many2one(
|
||||
'res.currency', related='company_id.currency_id')
|
||||
l10n_at_personalgruppe = fields.Selection(
|
||||
[('angestellte', 'Angestellte (Gehälter)'),
|
||||
('arbeiter', 'Arbeiter (Löhne)')],
|
||||
string='AT Personalgruppe (EKR)',
|
||||
default='angestellte',
|
||||
groups="hr_payroll.group_hr_payroll_user", tracking=True,
|
||||
help='Personalgruppe nach dem Einheitskontenrahmen (KFS/BW 6): '
|
||||
'steuert die Debit-Konten der Lohnverrechnungsbuchung '
|
||||
'(600–619 Löhne · 620–639 Gehälter · 650/656 Sozialaufwand '
|
||||
'· 660/666 Abgaben). Rechenlogik (KV-Regime) ist identisch; '
|
||||
'nur die FI-Buchung splittet (GP6).')
|
||||
|
||||
def _get_kv_gehalt(self, datum=None):
|
||||
"""Katalog-Position (Monatsgehalt) der Version zum Stichtag."""
|
||||
@@ -55,4 +66,7 @@ class HrEmployee(models.Model):
|
||||
ueberzahlung = fields.Monetary(
|
||||
related="version_id.ueberzahlung", inherited=True,
|
||||
readonly=False, groups="hr_payroll.group_hr_payroll_user",
|
||||
currency_field='currency_id')
|
||||
currency_field='currency_id')
|
||||
l10n_at_personalgruppe = fields.Selection(
|
||||
related="version_id.l10n_at_personalgruppe", inherited=True,
|
||||
readonly=False, groups="hr_payroll.group_hr_payroll_user")
|
||||
@@ -14,6 +14,32 @@ class HrWorkEntryType(models.Model):
|
||||
'(zuschlagsunabhängig, kumulativ).')
|
||||
|
||||
|
||||
class HrPayrollStructure(models.Model):
|
||||
_inherit = 'hr.payroll.structure'
|
||||
|
||||
def _l10n_at_entferne_default_net_kopie(self):
|
||||
"""Odoo kopiert beim Anlegen einer Structure die Regeln des
|
||||
``hr_payroll.default_structure`` (BASIC/GROSS/NET/ASSIG_
|
||||
SALARY/…) in ``rule_ids`` (Feld-Default ``_get_default_
|
||||
rule_ids``). Die kopierte NET-Regel kollidiert ab GP6 mit
|
||||
unserer Netto-Regel (Code ``NET`` nach Odoo-Konvention —
|
||||
Zahlungsregistrierung, net_wage und Negativ-Netto-Erkennung
|
||||
filtern ``code == 'NET'``): zwei Regeln mit Code NET in einer
|
||||
Structure überschreiben sich im ``result_rules``-Dict und die
|
||||
Netto-Zeile fällt auf 0. Die Kopie wird daher archiviert —
|
||||
One2many-Liesungen (rule_ids, Compute-Schleife, NET-Filter)
|
||||
blenden Archivierte aus, historische Lohnkontolinien behalten
|
||||
aber ihre Regel-Referenz (struct_id ist NOT NULL, ein Abhängen
|
||||
ist nicht möglich). Idempotent (Aufruf via <function> in
|
||||
salary_rules_private.xml bei Install und Update)."""
|
||||
self.ensure_one()
|
||||
unsere = self.env.ref(
|
||||
'l10n_at_hr_payroll_private.rule_netto', False)
|
||||
kopien = self.rule_ids.filtered(
|
||||
lambda r: r.code == 'NET' and (not unsere or r != unsere))
|
||||
kopien.write({'active': False})
|
||||
|
||||
|
||||
class HrVersionPrivate(models.Model):
|
||||
_inherit = 'hr.version'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user