From e3c2a6a31598cbfa16fd1eab36bfb557a1da1ddd Mon Sep 17 00:00:00 2001 From: Kojo Date: Mon, 27 Apr 2026 09:24:15 +0200 Subject: [PATCH] =?UTF-8?q?Dakota:=20GKV-Abrechnung=20f=C3=BCr=20H=C3=A4us?= =?UTF-8?q?liche=20Krankenpflege=20unterst=C3=BCtzen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dakota/Dakota.csproj | 7 + Dakota/Models/Blocke/BlockEinsatz.cs | 47 ++++++ Dakota/Models/Blocke/BlockEinsatzPosition.cs | 64 ++++++++ Dakota/Models/Blocke/BlockKlientHKP.cs | 146 ++++++++++++++++++ Dakota/Models/Blocke/BlockKostenträger.cs | 16 +- Dakota/Models/Blocke/BlockKrankenkasse.cs | 105 ++++++++----- Dakota/Models/Blocke/Nutzdatendatei.cs | 17 +- .../Models/Infos/InfoAbrechnungsposition.cs | 20 ++- Dakota/Models/Nachrichten/NachrichtSLLA.cs | 124 ++++++++------- Dakota/Models/Segmente/SLLA/SegmentEHK.cs | 72 +++++++++ Dakota/Models/Segmente/SLLA/SegmentELP.cs | 33 ++++ Dakota/Models/Segmente/SLLA/SegmentESK.cs | 37 +++++ Dakota/Models/Segmente/SLLA/SegmentZHK.cs | 59 +++++++ 13 files changed, 634 insertions(+), 113 deletions(-) create mode 100644 Dakota/Models/Blocke/BlockEinsatz.cs create mode 100644 Dakota/Models/Blocke/BlockEinsatzPosition.cs create mode 100644 Dakota/Models/Blocke/BlockKlientHKP.cs create mode 100644 Dakota/Models/Segmente/SLLA/SegmentEHK.cs create mode 100644 Dakota/Models/Segmente/SLLA/SegmentELP.cs create mode 100644 Dakota/Models/Segmente/SLLA/SegmentESK.cs create mode 100644 Dakota/Models/Segmente/SLLA/SegmentZHK.cs diff --git a/Dakota/Dakota.csproj b/Dakota/Dakota.csproj index 4c8349cbd..f81b63dea 100644 --- a/Dakota/Dakota.csproj +++ b/Dakota/Dakota.csproj @@ -78,6 +78,9 @@ + + + @@ -143,6 +146,9 @@ + + + @@ -152,6 +158,7 @@ + diff --git a/Dakota/Models/Blocke/BlockEinsatz.cs b/Dakota/Models/Blocke/BlockEinsatz.cs new file mode 100644 index 000000000..bdf143627 --- /dev/null +++ b/Dakota/Models/Blocke/BlockEinsatz.cs @@ -0,0 +1,47 @@ +using Dakota.Models.Infos; +using Dakota.Models.Segmente; +using Dakota.Models.Segmente.SLLA; +using System.Collections.Generic; + +namespace Dakota.Models.Blocke +{ + /// + /// ESK + 1-n BlockEinsatzPosition – + /// entspricht einem einzelnen Einsatz/Hausbesuch + /// bei Häuslicher Krankenpflege (SLLA: C). + /// + internal class BlockEinsatz : Block + { + public SegmentSLLAESK SegmentSLLAESK { get; private set; } + public List Positionen { get; private set; } + + public BlockEinsatz() + { + SegmentSLLAESK = new SegmentSLLAESK(); + Positionen = new List(); + } + + public override List GetAllSegments() + { + var res = new List { SegmentSLLAESK }; + foreach (var pos in Positionen) + res.AddRange(pos.GetSegments()); + return res; + } + + public override int GetUNHCount() => 0; + + public void Apply(InfoAbrechnungsposition info) + { + // ESK: Datum + Uhrzeiten aus der Abrechnungsposition + SegmentSLLAESK.DatumLeistungserbringung.SetValue(info.DatumDerLeistungserbringung); + SegmentSLLAESK.UhrzeitBeginn.SetValue(info.Uhrzeit); + SegmentSLLAESK.UhrzeitEnde.SetValue(info.UhrzeitBis); + SegmentSLLAESK.Dauer.SetValue(info.Dauer > 0 ? info.Dauer.ToString() : null); + + var posBlock = new BlockEinsatzPosition(); + posBlock.Apply(info); + Positionen.Add(posBlock); + } + } +} diff --git a/Dakota/Models/Blocke/BlockEinsatzPosition.cs b/Dakota/Models/Blocke/BlockEinsatzPosition.cs new file mode 100644 index 000000000..4f929bb5a --- /dev/null +++ b/Dakota/Models/Blocke/BlockEinsatzPosition.cs @@ -0,0 +1,64 @@ +using Dakota.Models.Infos; +using Dakota.Models.Segmente; +using Dakota.Models.Segmente.SLLA; +using System.Collections.Generic; + +namespace Dakota.Models.Blocke +{ + /// + /// EHK + optionale ELP-Segmente + optionales TXT-Segment – + /// entspricht einer Abrechnungsposition innerhalb eines Einsatzes + /// bei Häuslicher Krankenpflege (SLLA: C). + /// + internal class BlockEinsatzPosition : Block + { + public SegmentSLLAEHK SegmentSLLAEHK { get; private set; } + + /// + /// Einzelleistungen innerhalb einer Leistungspauschale (0-n je EHK). + /// Nur füllen, wenn eine Pauschale abgerechnet wird. + /// + public List SegmenteELP { get; private set; } + + public SegmentSLLATXT SegmentSLLATXT { get; private set; } + + public decimal AnzahlEinheit => SegmentSLLAEHK.AnzahlMenge.DecimalValue; + public decimal EinzelbetragAbrechnungsposition => SegmentSLLAEHK.EinzelbetragAbrechnungsposition.DecimalValue; + + public BlockEinsatzPosition() + { + SegmentSLLAEHK = new SegmentSLLAEHK(); + SegmenteELP = new List(); + SegmentSLLATXT = new SegmentSLLATXT(); + } + + public override List GetAllSegments() + { + var res = new List { SegmentSLLAEHK }; + res.AddRange(SegmenteELP); + res.Add(SegmentSLLATXT); + return res; + } + + public override int GetUNHCount() => 0; + + public void Apply(InfoAbrechnungsposition info) + { + SegmentSLLAEHK.Abrechnungscode.SetValue(info.Abrechnungscode); + SegmentSLLAEHK.Tarifkennzeichen.SetValue(info.Tarifkennzeichen); + SegmentSLLAEHK.ArtLeistung.SetValue(info.GetAbrechnungsposition()); + SegmentSLLAEHK.AnzahlMenge.SetValue(info.AnzahlMenge); + SegmentSLLAEHK.EinzelbetragAbrechnungsposition.SetValue(info.EinzelbetragAbrechnungsposition); + SegmentSLLAEHK.GefahreneKilometer.SetValue(info.GefahreneKilometer); + + // Beschäftigtennummer: Pflichtfeld – Fallback auf Ersatzwert 999999999 + var bsnr1 = !string.IsNullOrWhiteSpace(info.Beschäftigtennummer) + ? info.Beschäftigtennummer + : "999999999"; + SegmentSLLAEHK.Beschäftigtennummer1.SetValue(bsnr1); + SegmentSLLAEHK.Beschäftigtennummer2.SetValue(info.Beschäftigtennummer2); + + SegmentSLLATXT.Text.SetValue(info.Text); + } + } +} diff --git a/Dakota/Models/Blocke/BlockKlientHKP.cs b/Dakota/Models/Blocke/BlockKlientHKP.cs new file mode 100644 index 000000000..5303929e4 --- /dev/null +++ b/Dakota/Models/Blocke/BlockKlientHKP.cs @@ -0,0 +1,146 @@ +using Dakota.Models.Infos; +using Dakota.Models.Segmente; +using Dakota.Models.Segmente.SLLA; +using System.Collections.Generic; +using System.Linq; + +namespace Dakota.Models.Blocke +{ + /// + /// Abrechnungsfall (INV … BES) für Häusliche Krankenpflege (SLLA: C). + /// Segmentfolge gem. TA § 302 Abs. 5.5.3.4: + /// INV, NAD, [IMG], ESK { EHK [ELP] [TXT] }+, ZHK [DIA] SKZ BES + /// + internal class BlockKlientHKP : Block + { + public SegmentSLLAINV SegmentSLLAINV { get; private set; } + public SegmentSLLANAD SegmentSLLANAD { get; private set; } + public SegmentSLLAIMG SegmentSLLAIMG { get; private set; } + + /// Ein BlockEinsatz pro Einsatz/Hausbesuch (ESK + EHK-Positionen). + public List BlockEinsätze { get; private set; } + + /// + /// ZHK – Zusatzinfo Verordnung HK. + /// Laut TA 1-n je INV (eine je Verordnung); hier zunächst eine Verordnung pro Fall. + /// + public SegmentSLLAZHK SegmentSLLAZHK { get; private set; } + + public List BlockDiagnose { get; private set; } + + /// + /// SKZ ist bei C Pflicht (1-n je ZHK, laut TA zwingend zu übermitteln). + /// Liegen mehrere Kostenzusagen vor, ist das Segment zu wiederholen – + /// hier wird zunächst eine Kostenzusage je Fall unterstützt. + /// + public SegmentSLLASKZ SegmentSLLASKZ { get; private set; } + + public SegmentSLLABES SegmentSLLABES { get; private set; } + + // Summen-Zugriff für NachrichtSLLA / SLGA + public decimal GesamtbetragBrutto => SegmentSLLABES.GesamtbetragBrutto.DecimalValue; + + public BlockKlientHKP() + { + SegmentSLLAINV = new SegmentSLLAINV(); + SegmentSLLANAD = new SegmentSLLANAD(); + SegmentSLLAIMG = new SegmentSLLAIMG(); + BlockEinsätze = new List(); + SegmentSLLAZHK = new SegmentSLLAZHK(); + BlockDiagnose = new List(); + SegmentSLLASKZ = new SegmentSLLASKZ(); + SegmentSLLABES = new SegmentSLLABES(); + } + + public override List GetAllSegments() + { + var res = new List(); + + res.Add(SegmentSLLAINV); + res.Add(SegmentSLLANAD); + // IMG nur wenn befüllt – wie in BlockKlient gehandhabt + + foreach (var einsatz in BlockEinsätze) + res.AddRange(einsatz.GetSegments()); + + res.Add(SegmentSLLAZHK); + + foreach (var dia in BlockDiagnose) + res.AddRange(dia.GetSegments()); + + res.Add(SegmentSLLASKZ); + res.Add(SegmentSLLABES); + + return res; + } + + public override int GetUNHCount() => 0; + + public void Apply(InfoAbrechnungsfall info) + { + // INV + SegmentSLLAINV.VersichertenNummer.SetValue(info.VersichtertenNummer); + SegmentSLLAINV.Versichertenstatus.SetValue(info.Versichertenstatus); + SegmentSLLAINV.Beleginformation.SetValue(info.Beleginformation); + SegmentSLLAINV.Belegnummer.SetValue(info.Belegnummer); + + // NAD + SegmentSLLANAD.Vorname.SetValue(info.VersichtertenVorname); + SegmentSLLANAD.Nachname.SetValue(info.VersichtertenNachname); + SegmentSLLANAD.Geburtsdatum.SetValue(info.VersichtertenGeburtstag); + SegmentSLLANAD.StraßeNr.SetValue(info.VersichtertenStraßeNr); + SegmentSLLANAD.PLZ.SetValue(info.VersichtertenPLZ); + SegmentSLLANAD.Wohnort.SetValue(info.VersichtertenWohnort); + SegmentSLLANAD.Länderkennzeichen.SetValue(info.VersichtertenLanderkennung); + + // ESK + EHK: je Abrechnungsposition ein eigener Einsatz + // (ein InvoiceItem = ein Einsatz; mehrere Positionen am selben Tag + // können durch den Aufrufer in einem BlockEinsatz zusammengefasst werden) + foreach (var posinfo in info.InfosAbrechnungsposition + .OrderBy(x => x.DatumDerLeistungserbringung)) + { + var einsatz = new BlockEinsatz(); + einsatz.Apply(posinfo); + BlockEinsätze.Add(einsatz); + } + + // ZHK + SegmentSLLAZHK.Betriebsstättennummer.SetValue( + string.IsNullOrWhiteSpace(info.Betriebsstättennummer) ? "999999999" : info.Betriebsstättennummer); + SegmentSLLAZHK.LebenslangeArztnummer.SetValue( + string.IsNullOrWhiteSpace(info.LebenslangeArztnummer) ? "999999999" : info.LebenslangeArztnummer); + SegmentSLLAZHK.Verordnungsdatum.SetValue(info.Verordnungsdatum); + SegmentSLLAZHK.Unfallkennzeichen.SetValue(info.Unfallkennzeichen); + SegmentSLLAZHK.KennzeichenBVGSonstiges.SetValue(info.KennzeichenBVGSonstiges); + SegmentSLLAZHK.KennzeichenVerordnungsbesonderheiten.SetValue(info.KennzeichenVerordnungsbesonderheiten); + + // DIA + if (info.DakotaInfoDiagnosen?.Any() == true) + { + foreach (var diagnose in info.DakotaInfoDiagnosen) + { + var block = new BlockDiagnose(); + block.Apply(diagnose); + BlockDiagnose.Add(block); + } + } + + // SKZ + SegmentSLLASKZ.Genehmigungskennzeichen.SetValue(info.Genehmigungskennzeichen); + SegmentSLLASKZ.DatumGenehmigung.SetValue(info.DatumDerGenehmigung); + SegmentSLLASKZ.ArtGenehmigung.SetValue(info.ArtDerGenehmigung); + + // BES + CalculateSums(); + } + + private void CalculateSums() + { + var gesamtbrutto = BlockEinsätze + .SelectMany(e => e.Positionen) + .Sum(p => p.AnzahlEinheit * p.EinzelbetragAbrechnungsposition); + + SegmentSLLABES.GesamtbetragBrutto.SetValue(gesamtbrutto); + } + } +} diff --git a/Dakota/Models/Blocke/BlockKostenträger.cs b/Dakota/Models/Blocke/BlockKostenträger.cs index 314aca213..9d1e3a2d0 100644 --- a/Dakota/Models/Blocke/BlockKostenträger.cs +++ b/Dakota/Models/Blocke/BlockKostenträger.cs @@ -1,4 +1,4 @@ -using Dakota.Models.Infos; +using Dakota.Models.Infos; using Dakota.Models.Nachrichten; using Dakota.Models.Schlüssels; using Dakota.Models.Segmente; @@ -55,6 +55,7 @@ namespace Dakota.Models.Blocke return list; } + public override int GetUNHCount() { var i = 0; @@ -74,7 +75,14 @@ namespace Dakota.Models.Blocke { BlockKrankenkasse.Add(block); } - public void Apply(InfoBlockKostentrager info) + + /// Infoobjekt für diesen Kostenträger-Block. + /// + /// true = Häusliche Krankenpflege (Sammelgruppenschlüssel C). + /// Wird an BlockKrankenkasse.Apply weitergereicht, damit dort + /// NachrichtSLLA die ESK/EHK-Struktur (BlockKlientHKP) verwendet. + /// + public void Apply(InfoBlockKostentrager info, bool isHKP = false) { if (IsSammelrechnung) { @@ -91,7 +99,7 @@ namespace Dakota.Models.Blocke { var blockkvkarte = new BlockKrankenkasse(); - blockkvkarte.Apply(infoblock, IsSammelrechnung); + blockkvkarte.Apply(infoblock, IsSammelrechnung, isHKP); Add(blockkvkarte); } @@ -106,7 +114,7 @@ namespace Dakota.Models.Blocke private void CalculateSLGA() { - Dictionary segments = new Dictionary(); + var segments = new Dictionary(); foreach (var block in BlockKrankenkasse) { diff --git a/Dakota/Models/Blocke/BlockKrankenkasse.cs b/Dakota/Models/Blocke/BlockKrankenkasse.cs index 784eb69a7..229162b20 100644 --- a/Dakota/Models/Blocke/BlockKrankenkasse.cs +++ b/Dakota/Models/Blocke/BlockKrankenkasse.cs @@ -1,4 +1,4 @@ -using Dakota.Models.Infos; +using Dakota.Models.Infos; using Dakota.Models.Nachrichten; using Dakota.Models.Schlüssels; using Dakota.Models.Segmente; @@ -13,24 +13,24 @@ using System.Threading.Tasks; namespace Dakota.Models.Blocke { /// - /// Wiederhole folgenden Block je IK der Krankenkarte bzw der Verordnung + /// Wiederhole folgenden Block je IK der Krankenkarte bzw. der Verordnung /// internal class BlockKrankenkasse : Block { - public SegmentUNH SegmentSLGAUNH { get; private set; } - public NachrichtSLGA NachrichtSLGA { get; private set; } - public SegmentUNT SegmentSLGAUNT { get; private set; } - public SegmentUNH SegmentSLLAUNH { get; private set; } - public NachrichtSLLA NachrichtSLLA { get; private set; } - public SegmentUNT SegmentSLLAUNT { get; private set; } + public SegmentUNH SegmentSLGAUNH { get; private set; } + public NachrichtSLGA NachrichtSLGA { get; private set; } + public SegmentUNT SegmentSLGAUNT { get; private set; } + public SegmentUNH SegmentSLLAUNH { get; private set; } + public NachrichtSLLA NachrichtSLLA { get; private set; } + public SegmentUNT SegmentSLLAUNT { get; private set; } public BlockKrankenkasse() { SegmentSLGAUNH = new SegmentUNH(); - NachrichtSLGA = new NachrichtSLGA(); + NachrichtSLGA = new NachrichtSLGA(); SegmentSLGAUNT = new SegmentUNT(SLGASegmentLength); SegmentSLLAUNH = new SegmentUNH(); - NachrichtSLLA = new NachrichtSLLA(); + NachrichtSLLA = new NachrichtSLLA(); SegmentSLLAUNT = new SegmentUNT(SLLASegmentLength); } @@ -45,7 +45,7 @@ namespace Dakota.Models.Blocke public override List GetAllSegments() { - var list = new List() { SegmentSLGAUNH }; + var list = new List { SegmentSLGAUNH }; list.AddRange(NachrichtSLGA.GetSegments()); list.Add(SegmentSLGAUNT); @@ -61,14 +61,21 @@ namespace Dakota.Models.Blocke return 2; } - public void Apply(InfoBlockKrankenkasse blockinfo, bool isSammelrechnung) + /// Infoobjekt für diesen KV-Karten-Block. + /// true = Sammelrechnung. + /// + /// true = Häusliche Krankenpflege (Sammelgruppenschlüssel C). + /// Schaltet in NachrichtSLLA auf ESK/EHK-Struktur (BlockKlientHKP) um. + /// + public void Apply(InfoBlockKrankenkasse blockinfo, bool isSammelrechnung, bool isHKP = false) { ApplySLGA(blockinfo.DakotaInfoSLGA); ApplyNachrichtSLGA(blockinfo.DakotaInfoNachrichtSLGA, isSammelrechnung); ApplySLLA(blockinfo.DakotaInfoSLLA); - ApplyNachrichtSLLA(blockinfo.DakotaInfoNachrichtSLLA); + ApplyNachrichtSLLA(blockinfo.DakotaInfoNachrichtSLLA, isHKP); CalculateSLGA(); } + private void ApplySLGA(InfoNachricht info) { SegmentSLGAUNH.Nachrichtenreferenznummer.SetValue(info.Nachrichtenreferenznummer); @@ -79,6 +86,7 @@ namespace Dakota.Models.Blocke SegmentSLGAUNT.Nachrichtenreferenznummer.SetValue(info.Nachrichtenreferenznummer); } + private void ApplyNachrichtSLGA(InfoNachrichtSLGA info, bool isSammelrechnung) { NachrichtSLGA.Apply(info, isSammelrechnung); @@ -94,40 +102,35 @@ namespace Dakota.Models.Blocke SegmentSLLAUNT.Nachrichtenreferenznummer.SetValue(info.Nachrichtenreferenznummer); } - private void ApplyNachrichtSLLA(InfoNachrichtSLLA info) + + private void ApplyNachrichtSLLA(InfoNachrichtSLLA info, bool isHKP) { - NachrichtSLLA.Apply(info); + NachrichtSLLA.Apply(info, isHKP); } + private void CalculateSLGA() { var sumseg = new decimal[3]; + var segments = new Dictionary(); - Dictionary segments = new Dictionary(); - + // G/N: ENF-basierte Fälle foreach (var fall in NachrichtSLLA.BlockKlienten) { - var versicherten_status = fall.SegmentSLLAINV.Versichertenstatus.GetValue(); - var schlüssel_summenstatus = SchlüsselSummenstatus.Parse(versicherten_status); - var status = schlüssel_summenstatus.Value; + AccumulateFall( + fall.SegmentSLLAINV.Versichertenstatus.GetValue(), + fall.GesamtbetragBrutto, + fall.GesamtbetragGesetzlicheZuzahlung + fall.GesamtbetragEigenanteil, + segments, sumseg); + } - if (!segments.ContainsKey(status)) - { - segments.Add(status, new decimal[3]); - } - - var segment = segments[status]; - - decimal bruttobetrag = fall.GesamtbetragBrutto; - decimal zuzahlung = fall.GesamtbetragGesetzlicheZuzahlung + fall.GesamtbetragEigenanteil; - decimal rechnungsbetrag = bruttobetrag - zuzahlung; - - segment[0] += rechnungsbetrag; - segment[1] += bruttobetrag; - segment[2] += zuzahlung; - - sumseg[0] += rechnungsbetrag; - sumseg[1] += bruttobetrag; - sumseg[2] += zuzahlung; + // C: ESK/EHK-basierte Fälle (Häusliche Krankenpflege) + foreach (var fall in NachrichtSLLA.BlockKlientenHKP) + { + AccumulateFall( + fall.SegmentSLLAINV.Versichertenstatus.GetValue(), + fall.GesamtbetragBrutto, + zuzahlung: 0, // HKP hat keine gesetzliche Zuzahlung im BES + segments, sumseg); } NachrichtSLGA.SegmentGES00.Status.SetValue(SchlüsselSummenstatus.Gesamtsumme); @@ -138,7 +141,7 @@ namespace Dakota.Models.Blocke foreach (var key in segments.Keys.OrderBy(x => x)) { var segment = new SegmentSLGAGES(); - var array = segments[key]; + var array = segments[key]; segment.Status.SetValue(key); segment.Gesamtrechnungsbetrag.SetValue(array[0]); @@ -148,5 +151,29 @@ namespace Dakota.Models.Blocke NachrichtSLGA.ListSegmentGES.Add(segment); } } + + private void AccumulateFall( + string versichertenStatus, + decimal bruttobetrag, + decimal zuzahlung, + Dictionary segments, + decimal[] sumseg) + { + var schlüssel = SchlüsselSummenstatus.Parse(versichertenStatus); + var status = schlüssel.Value; + + if (!segments.ContainsKey(status)) + segments.Add(status, new decimal[3]); + + var seg = segments[status]; + var rechnungsbetrag = bruttobetrag - zuzahlung; + + seg[0] += rechnungsbetrag; + seg[1] += bruttobetrag; + seg[2] += zuzahlung; + sumseg[0] += rechnungsbetrag; + sumseg[1] += bruttobetrag; + sumseg[2] += zuzahlung; + } } } diff --git a/Dakota/Models/Blocke/Nutzdatendatei.cs b/Dakota/Models/Blocke/Nutzdatendatei.cs index bbfbbd263..17532ccb7 100644 --- a/Dakota/Models/Blocke/Nutzdatendatei.cs +++ b/Dakota/Models/Blocke/Nutzdatendatei.cs @@ -1,5 +1,6 @@ -using Dakota.Models.Infos; +using Dakota.Models.Infos; using Dakota.Models.Nachrichten; +using Dakota.Models.Schlüssels; using Dakota.Models.Segmente; using System; using System.Collections.Generic; @@ -10,13 +11,13 @@ using System.Threading.Tasks; namespace Dakota.Models.Blocke { /// - /// Nutzdatendatei ohne Logik + /// Nutzdatendatei ohne Logik. /// internal class Nutzdatendatei : Block { public DakotaFile Parent { get; set; } - public SegmentUNB SegmentUNB { get; private set; } + public SegmentUNB SegmentUNB { get; private set; } public List BlockKostenträger { get; private set; } public SegmentUNZ SegmentUNZ { get; private set; } @@ -43,6 +44,7 @@ namespace Dakota.Models.Blocke return list; } + public override int GetUNHCount() { int i = 0; @@ -59,8 +61,13 @@ namespace Dakota.Models.Blocke { BlockKostenträger.Add(blockkosten); } + public void Apply(InfoDateiNutzdaten info, bool isSammelrechnung) { + // isHKP: true fuer Haeusliche Krankenpflege (Sammelgruppenschlüssel C) + var isHKP = info.Leistungsbereich?.Value == + SchlüsselLeistungserbringerSammelgruppenschlussel.LeistungserbringerVonHäuslicherKrankenpflege.Value; + SegmentUNB.SyntaxKennung.SetValue(info.SyntaxKennung); SegmentUNB.SyntaxVersionsnummer.SetValue(info.SyntaxVersion); SegmentUNB.Absenderdatei.SetValue(info.Absenderbezeichnung); @@ -75,9 +82,7 @@ namespace Dakota.Models.Blocke foreach (var blockinfo in info.BlockKostentragers) { var block = new BlockKostenträger(isSammelrechnung); - - block.Apply(blockinfo); - + block.Apply(blockinfo, isHKP); Add(block); } diff --git a/Dakota/Models/Infos/InfoAbrechnungsposition.cs b/Dakota/Models/Infos/InfoAbrechnungsposition.cs index 5d7d0f0ba..c1e35c815 100644 --- a/Dakota/Models/Infos/InfoAbrechnungsposition.cs +++ b/Dakota/Models/Infos/InfoAbrechnungsposition.cs @@ -1,9 +1,6 @@ -using Dakota.Models.Schlüssels; +using Dakota.Models.Schlüssels; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Dakota.Models.Infos { @@ -18,7 +15,7 @@ namespace Dakota.Models.Infos public SchlüsselPosArtDerEinrichtung AbrechnungspositionArtDerEinrichtung { get; set; } public SchlüsselPosBehandlungsart AbrechnungspositionBehandlungsart { get; set; } public SchlüsselPosVergütungsart AbrechnungspositionVergütungsart { get; set; } - + public decimal AnzahlMenge { get; set; } public decimal EinzelbetragAbrechnungsposition { get; set; } public DateTime? DatumDerLeistungserbringung { get; set; } @@ -31,6 +28,19 @@ namespace Dakota.Models.Infos public string Text { get; set; } + /// + /// Beschäftigtennummer nach § 293 Abs. 8 Satz 2 SGB V der Person, + /// die die Leistung erbracht hat (Pflichtfeld bei SLLA: C – Häusliche Krankenpflege). + /// Bei fehlendem Wert Ersatzwert gemäß Anlage 3, Schlüsseltabelle 8.1.19 verwenden. + /// + public string Beschäftigtennummer { get; set; } + + /// + /// Optionale Beschäftigtennummer einer zweiten Person (SLLA: C). + /// Wird zum Pflichtfeld, sobald zwei Personen die Leistung erbracht haben. + /// + public string Beschäftigtennummer2 { get; set; } + internal string GetAbrechnungsposition() { return AbrechnungspositionString ?? Abrechnungsposition.Value; diff --git a/Dakota/Models/Nachrichten/NachrichtSLLA.cs b/Dakota/Models/Nachrichten/NachrichtSLLA.cs index a326a127e..0f292a6ea 100644 --- a/Dakota/Models/Nachrichten/NachrichtSLLA.cs +++ b/Dakota/Models/Nachrichten/NachrichtSLLA.cs @@ -1,80 +1,86 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Dakota.Models.Blocke; using Dakota.Models.Infos; +using Dakota.Models.Schlüssels; using Dakota.Models.Segmente; using Dakota.Models.Segmente.SLLA; namespace Dakota.Models.Nachrichten { - /// - /// Leistungserbringer - /// - internal class NachrichtSLLA : Nachricht - { - /// - /// Das Segment enthält Informationen über den tatsächlichen - /// Leistungserbringer und das IK der Krankenkasse von der - /// Krankenversichertenkarte bzw.der ärztlichen Verordnung bezogen auf die folgenden Abrechnungsfälle.Es kommt je Nachricht nur einmal vor. - /// - public SegmentSLLAFKT SegmentSLLAFKT { get; private set; } - /// - /// Das Segment enthält die Rechnungsinformationen, wie Rechnungsnummer und Rechnungsdatum - /// - public SegmentSLLAREC SegmentSLLAREC { get; private set; } - /// - /// Abrechnungsfälle (INV - BES) - /// - public List BlockKlienten { get; set; } + /// + /// Leistungserbringer – Abrechnungsdaten (SLLA). + /// Unterstützt G/N (ENF-basiert via BlockKlient) und + /// C – Häusliche Krankenpflege (ESK/EHK-basiert via BlockKlientHKP). + /// + internal class NachrichtSLLA : Nachricht + { + public SegmentSLLAFKT SegmentSLLAFKT { get; private set; } + public SegmentSLLAREC SegmentSLLAREC { get; private set; } + /// Abrechnungsfälle für G/N (ENF-Struktur). + public List BlockKlienten { get; set; } + /// Abrechnungsfälle für C – Häusliche Krankenpflege (ESK/EHK-Struktur). + public List BlockKlientenHKP { get; set; } - public NachrichtSLLA() - { - SegmentSLLAFKT = new SegmentSLLAFKT(); - SegmentSLLAREC = new SegmentSLLAREC(); + public NachrichtSLLA() + { + SegmentSLLAFKT = new SegmentSLLAFKT(); + SegmentSLLAREC = new SegmentSLLAREC(); + BlockKlienten = new List(); + BlockKlientenHKP = new List(); + } - BlockKlienten = new List(); - } + public override List GetAllSegments() + { + var list = new List { SegmentSLLAFKT, SegmentSLLAREC }; - public override List GetAllSegments() - { - var list = new List() { SegmentSLLAFKT, SegmentSLLAREC }; + foreach (var block in BlockKlienten) + list.AddRange(block.GetSegments()); - foreach (var block in BlockKlienten) - { - list.AddRange(block.GetSegments()); - } + foreach (var block in BlockKlientenHKP) + list.AddRange(block.GetSegments()); - return list; - } + return list; + } - public void Add(BlockKlient fall) - { - BlockKlienten.Add(fall); - } - public void Apply(InfoNachrichtSLLA info) - { - SegmentSLLAFKT.Verarbeitungskennzeichen.SetValue(info.Verarbeitungskennzeichen); - SegmentSLLAFKT.IKLeistungserbringers.SetValue(info.IKLeistungserbringer); - SegmentSLLAFKT.IKKostenträgers.SetValue(info.IKKostentrager); - SegmentSLLAFKT.IKKrankenkasse.SetValue(info.IKKrankenkasse); - //SegmentSLLAFKT.IKRechnungsstellers.SetValue(info.IKAbsender); + public void Add(BlockKlient fall) => BlockKlienten.Add(fall); + public void Add(BlockKlientHKP fall) => BlockKlientenHKP.Add(fall); - foreach (var infofall in info.Abrechnungsfalle.OrderBy(x => x.InfosAbrechnungsposition.Min(y => y.DatumDerLeistungserbringung))) - { - var block = new BlockKlient(); + /// + /// Befüllt die Nachricht. Für Häusliche Krankenpflege (Sammelgruppenschlüssel C) + /// isHKP = true übergeben – dann wird BlockKlientHKP (ESK/EHK) statt BlockKlient (ENF) verwendet. + /// + public void Apply(InfoNachrichtSLLA info, bool isHKP = false) + { + SegmentSLLAFKT.Verarbeitungskennzeichen.SetValue(info.Verarbeitungskennzeichen); + SegmentSLLAFKT.IKLeistungserbringers.SetValue(info.IKLeistungserbringer); + SegmentSLLAFKT.IKKostenträgers.SetValue(info.IKKostentrager); + SegmentSLLAFKT.IKKrankenkasse.SetValue(info.IKKrankenkasse); - block.Apply(infofall); + foreach (var infofall in info.Abrechnungsfalle + .OrderBy(x => x.InfosAbrechnungsposition.Min(y => y.DatumDerLeistungserbringung))) + { + if (isHKP) + { + var block = new BlockKlientHKP(); + block.Apply(infofall); + Add(block); + } + else + { + var block = new BlockKlient(); + block.Apply(infofall); + Add(block); + } + } - Add(block); - } - - SegmentSLLAREC.SammelRechnungsnummer.SetValue(info.Rechnungsnummer); - SegmentSLLAREC.EinzelRechnungsnummer.SetValue("0"); - SegmentSLLAREC.Rechnungsdatum.SetValue(info.Rechnungsdatum); - SegmentSLLAREC.Rechnungsart.SetValue(info.Rechnungsart); - } - } + SegmentSLLAREC.SammelRechnungsnummer.SetValue(info.Rechnungsnummer); + SegmentSLLAREC.EinzelRechnungsnummer.SetValue("0"); + SegmentSLLAREC.Rechnungsdatum.SetValue(info.Rechnungsdatum); + SegmentSLLAREC.Rechnungsart.SetValue(info.Rechnungsart); + } + } } diff --git a/Dakota/Models/Segmente/SLLA/SegmentEHK.cs b/Dakota/Models/Segmente/SLLA/SegmentEHK.cs new file mode 100644 index 000000000..3be2ffe65 --- /dev/null +++ b/Dakota/Models/Segmente/SLLA/SegmentEHK.cs @@ -0,0 +1,72 @@ +using Dakota.Models.Daten; +using System.Collections.Generic; + +namespace Dakota.Models.Segmente.SLLA +{ + /// + /// EHK – Einzelfallnachweis Häusliche Krankenpflege (SLLA: C). + /// Das Segment ist je Einsatz/Hausbesuch 1-n mal zu übermitteln. + /// Das letzte EHK kennzeichnet das Einsatzende. + /// + internal class SegmentSLLAEHK : Segment + { + /// Datenelementgruppe Abrechnungscode:Tarifkennzeichen. + public Datenelementgruppe Leistungserbringergruppe { get; private set; } + public Datenelement Abrechnungscode { get; private set; } + public Datenelement Tarifkennzeichen { get; private set; } + + /// Zu vergütende Abrechnungspositionsnummer (Anlage 3, Abschnitt 8.2.4). + public Datenelement ArtLeistung { get; private set; } + + /// Anzahl der Abrechnungspositionen. Max. ..4,2. + public DatenelementDecimal AnzahlMenge { get; private set; } + + /// + /// Einzelpreis inkl. MwSt. Als Einzelpreis ist immer der vereinbarte + /// Preis einschließlich Mehrwertsteuer einer Abrechnungsposition zu verstehen. + /// + public DatenelementDecimal EinzelbetragAbrechnungsposition { get; private set; } + + /// Anzahl der gefahrenen Kilometer (Kann-Feld). + public DatenelementDecimal GefahreneKilometer { get; private set; } + + /// + /// Beschäftigtennummer nach § 293 Abs. 8 Satz 2 SGB V der Person, + /// die die Leistung erbracht hat. Pflichtfeld – bei fehlendem Wert + /// ist ein Ersatzwert gemäß Anlage 3, Schlüsseltabelle 8.1.19 anzugeben. + /// + public Datenelement Beschäftigtennummer1 { get; private set; } + + /// + /// Beschäftigtennummer der zweiten Person (Kann-Feld; wird zum + /// Muss-Feld, sobald eine zweite Person die Leistung erbracht hat). + /// + public Datenelement Beschäftigtennummer2 { get; private set; } + + public SegmentSLLAEHK() : base(Feldart.Muss) + { + Leistungserbringergruppe = new Datenelementgruppe("Leistungserbringergruppe", 2); + Abrechnungscode = Leistungserbringergruppe.Datenelemente[0] = new Datenelement("Abrechnungscode", 2, Feldart.Muss); + Tarifkennzeichen = Leistungserbringergruppe.Datenelemente[1] = new Datenelement("Tarifkennzeichen", 5, Feldart.Muss); + ArtLeistung = new Datenelement("ArtLeistung", 0, 10, Feldart.Muss); + AnzahlMenge = new DatenelementDecimal("AnzahlMenge", 3, 7, Feldart.Muss); + EinzelbetragAbrechnungsposition = new DatenelementDecimal("EinzelbetragAbrechnungsposition", 3, 13, Feldart.Muss); + GefahreneKilometer = new DatenelementDecimal("GefahreneKilometer", 0, 6, Feldart.Kann); + Beschäftigtennummer1 = new Datenelement("Beschäftigtennummer1", 9, Feldart.Muss); + Beschäftigtennummer2 = new Datenelement("Beschäftigtennummer2", 9, Feldart.Kann); + } + + public override string GetHead() => "EHK"; + public override List GetBody() + => new List + { + Leistungserbringergruppe, + ArtLeistung, + AnzahlMenge, + EinzelbetragAbrechnungsposition, + GefahreneKilometer, + Beschäftigtennummer1, + Beschäftigtennummer2 + }; + } +} diff --git a/Dakota/Models/Segmente/SLLA/SegmentELP.cs b/Dakota/Models/Segmente/SLLA/SegmentELP.cs new file mode 100644 index 000000000..9dbd4bf93 --- /dev/null +++ b/Dakota/Models/Segmente/SLLA/SegmentELP.cs @@ -0,0 +1,33 @@ +using Dakota.Models.Daten; +using System.Collections.Generic; + +namespace Dakota.Models.Segmente.SLLA +{ + /// + /// ELP – Erbrachte unterschiedliche Leistungen je Leistungspauschale (SLLA: C). + /// Das Segment ist je EHK 0-n mal zu übermitteln. + /// Wird eine Leistungspauschale abgerechnet, sind hier die im Rahmen + /// der Leistungspauschale erbrachten Einzelleistungen zwingend anzugeben. + /// + internal class SegmentSLLAELP : Segment + { + /// + /// Abrechnungspositionsnummer der erbrachten Einzelleistung + /// (Anlage 3, Abschnitt 8.2.4). + /// + public Datenelement Abrechnungspositionsnummer { get; private set; } + + /// Anzahl der Abrechnungspositionen. Max. ..4,2. + public DatenelementDecimal AnzahlMenge { get; private set; } + + public SegmentSLLAELP() : base(Feldart.Kann) + { + Abrechnungspositionsnummer = new Datenelement("Abrechnungspositionsnummer", 0, 10, Feldart.Muss); + AnzahlMenge = new DatenelementDecimal("AnzahlMenge", 3, 7, Feldart.Muss); + } + + public override string GetHead() => "ELP"; + public override List GetBody() + => new List { Abrechnungspositionsnummer, AnzahlMenge }; + } +} diff --git a/Dakota/Models/Segmente/SLLA/SegmentESK.cs b/Dakota/Models/Segmente/SLLA/SegmentESK.cs new file mode 100644 index 000000000..9f3384916 --- /dev/null +++ b/Dakota/Models/Segmente/SLLA/SegmentESK.cs @@ -0,0 +1,37 @@ +using Dakota.Models.Daten; +using System.Collections.Generic; + +namespace Dakota.Models.Segmente.SLLA +{ + /// + /// ESK – Informationen zum Einsatz/Hausbesuch (SLLA: C Häusliche Krankenpflege). + /// Das Segment ist je Abrechnungsfall 1-n mal zu übermitteln. + /// Gilt als Beginn-Segment für einen Einsatz/Hausbesuch. + /// + internal class SegmentSLLAESK : Segment + { + /// Tag der Leistungserbringung (JJJJMMTT). + public DatenelementDateTime DatumLeistungserbringung { get; private set; } + + /// Beginn des Einsatzes (HHMM). Wertebereich HH 00–23, MM 00–59. + public DatenelementDateTime UhrzeitBeginn { get; private set; } + + /// Ende des Einsatzes (HHMM). Kann-Feld. + public DatenelementDateTime UhrzeitEnde { get; private set; } + + /// Zeitangabe in Minuten. Kann-Feld. + public Datenelement Dauer { get; private set; } + + public SegmentSLLAESK() : base(Feldart.Muss) + { + DatumLeistungserbringung = new DatenelementDateTime("DatumLeistungserbringung", 8, "yyyyMMdd", Feldart.Muss); + UhrzeitBeginn = new DatenelementDateTime("UhrzeitBeginn", 4, "HHmm", Feldart.Muss); + UhrzeitEnde = new DatenelementDateTime("UhrzeitEnde", 4, "HHmm", Feldart.Kann); + Dauer = new Datenelement("Dauer", 0, 4, Feldart.Kann); + } + + public override string GetHead() => "ESK"; + public override List GetBody() + => new List { DatumLeistungserbringung, UhrzeitBeginn, UhrzeitEnde, Dauer }; + } +} diff --git a/Dakota/Models/Segmente/SLLA/SegmentZHK.cs b/Dakota/Models/Segmente/SLLA/SegmentZHK.cs new file mode 100644 index 000000000..8e35478b8 --- /dev/null +++ b/Dakota/Models/Segmente/SLLA/SegmentZHK.cs @@ -0,0 +1,59 @@ +using Dakota.Models.Daten; +using System.Collections.Generic; + +namespace Dakota.Models.Segmente.SLLA +{ + /// + /// ZHK – Zusatzinfo Verordnung für Häusliche Krankenpflege (SLLA: C). + /// Das Segment ist für jede Verordnung zu übermitteln. + /// + internal class SegmentSLLAZHK : Segment + { + /// + /// Betriebsstättennummer aus der Verordnung (zwingend). + /// Falls nicht vorhanden: 999999999 angeben. + /// + public Datenelement Betriebsstättennummer { get; private set; } + + /// + /// Lebenslange Arztnummer aus der Verordnung (zwingend). + /// Falls nicht vorhanden: 999999999 angeben. + /// Auffüllen auf 9 Stellen ist unzulässig. + /// + public Datenelement LebenslangeArztnummer { get; private set; } + + /// Verordnungsdatum (JJJJMMTT). + public DatenelementDateTime Verordnungsdatum { get; private set; } + + /// Siehe Schlüssel Unfall/Sonstiges Anlage 3 Abschnitt 8.1.2. + public Datenelement Unfallkennzeichen { get; private set; } + + /// Siehe Schlüssel BVG/SER Anlage 3 Abschnitt 8.1.2.1. + public Datenelement KennzeichenBVGSonstiges { get; private set; } + + /// Siehe Schlüssel Kennzeichen Verordnungsbesonderheiten Anlage 3 Abschnitt 8.1.11. + public Datenelement KennzeichenVerordnungsbesonderheiten { get; private set; } + + public SegmentSLLAZHK() : base(Feldart.Muss) + { + Betriebsstättennummer = new Datenelement("Betriebsstättennummer", 0, 9, Feldart.Muss); + LebenslangeArztnummer = new Datenelement("LebenslangeArztnummer", 0, 9, Feldart.Muss); + Verordnungsdatum = new DatenelementDateTime("Verordnungsdatum", 8, "yyyyMMdd", Feldart.Muss); + Unfallkennzeichen = new Datenelement("Unfallkennzeichen", 1, Feldart.Kann); + KennzeichenBVGSonstiges = new Datenelement("KennzeichenBVGSonstiges", 1, Feldart.Kann); + KennzeichenVerordnungsbesonderheiten = new Datenelement("KennzeichenVerordnungsbesonderheiten", 1, Feldart.Kann); + } + + public override string GetHead() => "ZHK"; + public override List GetBody() + => new List + { + Betriebsstättennummer, + LebenslangeArztnummer, + Verordnungsdatum, + Unfallkennzeichen, + KennzeichenBVGSonstiges, + KennzeichenVerordnungsbesonderheiten + }; + } +}