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: GP7 ELDA-Fixsatz-Framework, L16 + Arbeitsstättenmeldung, Kind-Modell, Belege (AP5/AP6)
ELDA-Fixsatz-Framework (models/elda.py) nach DM-ORG 42.7.0 Kapitel C.1/C.2+E.1-E.3: Fixlängen-Sätze ohne Feldtrennzeichen (a/a-n linksbündig, Grundstellung blank; n rechtsbündig, Grundstellung 0, führende Nullen, KEINE Interpunktion — Beträge EURO-Cent kaufmännisch gerundet, Prozentsätze x1000 mit 3 Nachkommastellen), Encoding ISO-8859-15 (Standard-Encoding für Fixlängen), optionaler Dateiheader (DHKZ 2x blank + DHVN 01 + ENCD), Vorlaufsatz SART 00 (BEST/VSTR/VERS) + Schlusssatz SART 99 mit SANZ; SANR lückenlos ab 1 je Datenbestand; CRLF als Satztrenner (Praxis-Annahme, DM-ORG normiert keines — Parallellauf verifizieren). Lohnzettel Finanz L16 (models/lohnzettel_l16.py): Informationssatz I1 (SART I1, Länge 1.100, Strukturversion 03) + Mitteilungssatz L1 (SART L1, Länge 3.500, Lohnzettelversion 28 — zwingend ab 01.03.2026) mit vollständiger, PDF-verifizierter Feldtabelle (~210 Felder inkl. Kinderblock 15x123 ab Pos. 1501; DM-ORG 42.7.0 E.13/E.14). KZ-245-Formel: KZ 210 = Bruttobezüge gem. § 25 GESAMT (DM-ORG-Feldbeschreibung) — die Formel 210-215-220-230-243 ergibt die laufende Steuerbemessung, per Konstruktion konsistent mit der GP3-§-66-Kette (Ableitung aus l10n_at_bemessung/steuerbefreiung_68/s67_abs und Regelcodes; bewusst KEIN paralleles KZ-Klassifikationsfeld). Arbeitsstättenmeldung § 34 Abs 6 ASVG: SART 45 (Länge 300, Version 02, BEST AD/VSTR ST Statistik Austria) je AN am 31.12. aus dem Dienstort-Partner (GKZ manuell, Warnung wenn fehlt) — im selben Jahreslauf (Nutzer-Entscheidung 5.1). Kind-Datenmodell (models/kind.py — l10n.at.payroll.kind): Stammdaten-Wartung des Familienbonus Plus (Nutzer-Entscheidung 5.3: FB+ rechnet NICHT im Lohnsteuerkern — bei Unterschreiten der Steuer auf 0 erfolgt die Geltendmachung über die Arbeitnehmerveranlagung); Felder für den L16-Kinderblock (Familienname/Vorname/Geburtsdatum/VSNR/Staatsangehörigkeit/FB+-Monate voll/halb, Alterstaffel 166,68/58,34). Stammdaten (models/meldewesen.py): Beitragskontonummer BKNR + Lohnsteuernummer (res.company), Gemeindekennziffer GKZ (res.partner), VSNR-Formatprüfung LLLPTTMMJJ auf hr.version.ssnid (Prüfzifferalgorithmus = dokumentierter Rest, SVS-Quelle beschaffen), eSV-Abmeldegrund AGRD-Mapping auf hr.departure.reason (Standard 00); fallweise-Beschäftigungs-Flag auf hr.version (§ 33 Abs 1a Z 1 ASVG). Belege (AP6): Lohnzettel AT (ir.actions.report auf hr.payslip, AT-Layout mit Bezügen/DN-Abzügen/DG-Anteilen/Netto), Monatsdienstliste (mBGM-Kontrollschicht je AN) + Monatsjournal (je Lohnart Summen je Lauf) auf hr.payslip.run als QWeb (models/monatsreports.py + report/belege_reports.xml; account.report wird in keinem HR-Modul genutzt). Tests: test_elda_l16 (4 — Feldformatierung/Cent-Beträge/skala, Bestands-Assembly SANR/SANZ/CRLF/ISO-8859-15/Dateiheader, L16-Lauf mit positionsexakten Assertions aus der November-Fixture, Arbeitsstätten-Satz). 19.0.4.0.0.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# Part of the odoo-at-payroll project. License: LGPL-3.
|
||||
"""Monatsdienstliste und Monatsjournal (GP7/AP6): QWeb-Datenlieferanten
|
||||
auf dem Lohnlauf (hr.payslip.run) — voraberechnete Aggregation über
|
||||
`hr.payslip.line` (read_group-Muster des Contribution Register), damit
|
||||
die Templates reine Darstellung bleiben.
|
||||
|
||||
- **Monatsdienstliste**: je AN eine Zeile mit den mBGM-Kontrollgrößen
|
||||
(Versicherungstage/Beitragsgrundlagen je Beitragsmonat, DN- und
|
||||
DG-Beiträge, DG-Anteile) — Abstimmung Abrechnung ↔ SV-Meldung.
|
||||
- **Monatsjournal**: je Lohnart die Summe über den Lauf (Brutto,
|
||||
Abzüge, DG-Anteile, Netto) mit Kontrollsummen gegen die
|
||||
GP6-Buchung."""
|
||||
from odoo import models
|
||||
|
||||
|
||||
class L10nAtPayrollMonatsReports(models.AbstractModel):
|
||||
_name = 'report.l10n_at_hr_payroll.report_monatsdienstliste'
|
||||
_description = 'Monatsdienstliste (GP7/AP6)'
|
||||
|
||||
def _get_report_values(self, docids, data=None):
|
||||
runs = self.env['hr.payslip.run'].browse(docids)
|
||||
zeilen = []
|
||||
for run in runs:
|
||||
for slip in run.slip_ids.filtered(
|
||||
lambda p: p.state not in ('draft', 'cancel')):
|
||||
version = slip.version_id
|
||||
basen = slip._l10n_at_sv_basis_laufen_monate()
|
||||
sv_dn = sum(
|
||||
slip._l10n_at_svdn(k) for k in
|
||||
('kv', 'pv', 'av', 'ak', 'wf'))
|
||||
sv_dg = slip._l10n_at_svdg_gesamt()
|
||||
sz_dn = slip._l10n_at_svdn_sz()
|
||||
sz_basis = slip._l10n_at_svdn_basis_sz()
|
||||
zeilen.append({
|
||||
'slip': slip,
|
||||
'versicherungsnummer': version.ssnid if version else '',
|
||||
'personalgruppe': getattr(
|
||||
version, 'l10n_at_personalgruppe', '')
|
||||
if version else '',
|
||||
'geringfuegig': slip.l10n_at_geringfuegig,
|
||||
'basis_laufen': sum(
|
||||
b for _m, b in basen),
|
||||
'sz_basis': sz_basis,
|
||||
'sv_dn': sv_dn,
|
||||
'sv_dg': sv_dg,
|
||||
'sv_dn_sz': sz_dn,
|
||||
'lohnsteuer': sum(
|
||||
slip.line_ids.filtered(
|
||||
lambda l: l.code in ('LST_LFD', 'LST_SZ')
|
||||
).mapped('total')),
|
||||
'netto': sum(
|
||||
slip.line_ids.filtered(
|
||||
lambda l: l.code == 'NET').mapped('total')),
|
||||
'brutto': sum(
|
||||
slip.line_ids.filtered(
|
||||
lambda l: l.salary_rule_id.l10n_at_bemessung
|
||||
!= 'neutral').mapped('total')),
|
||||
})
|
||||
return {'docs': runs, 'zeilen': zeilen}
|
||||
|
||||
|
||||
class L10nAtPayrollMonatsjournal(models.AbstractModel):
|
||||
_name = 'report.l10n_at_hr_payroll.report_monatsjournal'
|
||||
_description = 'Monatsjournal (GP7/AP6)'
|
||||
|
||||
def _get_report_values(self, docids, data=None):
|
||||
runs = self.env['hr.payslip.run'].browse(docids)
|
||||
zeilen = []
|
||||
for run in runs:
|
||||
gruppen = {}
|
||||
for slip in run.slip_ids.filtered(
|
||||
lambda p: p.state not in ('draft', 'cancel')):
|
||||
for line in slip.line_ids:
|
||||
regel = line.salary_rule_id
|
||||
if not line.total or regel.l10n_at_bemessung \
|
||||
== 'neutral':
|
||||
continue
|
||||
schluessel = (regel.code, regel.name,
|
||||
regel.l10n_at_bemessung)
|
||||
eintrag = gruppen.setdefault(schluessel, 0.0)
|
||||
gruppen[schluessel] = eintrag + line.total
|
||||
zeilen.append({
|
||||
'run': run,
|
||||
'arten': [
|
||||
{'code': code, 'name': name, 'bemessung': bemessung,
|
||||
'summe': summe}
|
||||
for (code, name, bemessung), summe
|
||||
in sorted(gruppen.items())],
|
||||
})
|
||||
return {'docs': runs, 'journal': zeilen}
|
||||
Reference in New Issue
Block a user