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 + }; + } +} diff --git a/Queries/Anteil Zeiterfassung Über- Unterqualifiziert erbracht (Korridore Bayern).txt b/Queries/Anteil Zeiterfassung Über- Unterqualifiziert erbracht (Korridore Bayern).txt new file mode 100644 index 000000000..97276c13e --- /dev/null +++ b/Queries/Anteil Zeiterfassung Über- Unterqualifiziert erbracht (Korridore Bayern).txt @@ -0,0 +1,51 @@ +-- Wie viel Prozent der Stunden wurden bei Leistungskategorie Qualifiziert durch Assistenzkraft erbracht und andersrum +-- 3432911735 (APP4) Caritasverband GünzburgNeuUlm + + -- *** Mapping (kundenspezifisch anpassen) *** + -- Leistungskategorie 'Qualifiziert' -> passende Qualifikation: Q1, Q2 + -- Leistungskategorie 'Unterstützend' -> passende Qualifikation: Q3, Q4 + +SELECT + p.LastName AS 'Nachname', + p.Firstname AS 'Vorname', + c2s.ApprovedStartDate AS 'Bewilligt von', + c2s.ApprovedEndDate AS 'Bewilligt bis', + ROUND(SUM(CASE WHEN scat.Name = 'Qualifiziert' AND q12.EmployeeOid IS NOT NULL THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END) / 60, 2) AS 'Qualifiziert durch Q1/Q2', + ROUND(SUM(CASE WHEN scat.Name = 'Qualifiziert' AND q34.EmployeeOid IS NOT NULL THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END) / 60, 2) AS 'Qualifiziert durch Q3/Q4', + ROUND(SUM(CASE WHEN scat.Name = 'Unterstützend' AND q12.EmployeeOid IS NOT NULL THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END) / 60, 2) AS 'Unterstützend durch Q1/Q2', + ROUND(SUM(CASE WHEN scat.Name = 'Unterstützend' AND q34.EmployeeOid IS NOT NULL THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END) / 60, 2) AS 'Unterstützend durch Q3/Q4', + ROUND(SUM(CASE WHEN q12.EmployeeOid IS NULL AND q34.EmployeeOid IS NULL THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END) / 60, 2) AS 'Ohne Qualifikation', + ROUND(SUM(sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount)) / 60, 2) AS 'Gesamt (Std)', + -- Unterqualifiziert: Qualifiziert durch Q3/Q4 in % + ROUND(SUM(CASE WHEN scat.Name = 'Qualifiziert' AND q34.EmployeeOid IS NOT NULL THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END) + / NULLIF(SUM(CASE WHEN scat.Name = 'Qualifiziert' THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END), 0) * 100, 1) AS '% Unterqualifiziert', + -- Überqualifiziert: Unterstützend durch Q1/Q2 in % + ROUND(SUM(CASE WHEN scat.Name = 'Unterstützend' AND q12.EmployeeOid IS NOT NULL THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END) + / NULLIF(SUM(CASE WHEN scat.Name = 'Unterstützend' THEN sr.Roundedduration / IF(sr.GroupEmployeeCount IS NULL, 1, sr.GroupEmployeeCount) ELSE 0 END), 0) * 100, 1) AS '% Überqualifiziert' +FROM servicerecord sr +JOIN costbearer2supportconcept c2s ON sr.CostBearer2SupportConceptOid = c2s.Oid +JOIN supportconcept sc ON c2s.SupportConceptOid = sc.Oid +JOIN customer c ON sc.CustomerOid = c.Oid +JOIN person p ON c.PersonOid = p.Oid +JOIN servicedescription sd ON sd.Oid = sr.ServiceDescriptionOid +JOIN servicecategory scat ON scat.Oid = sd.ServiceCategoryOid + +-- *** Mapping (kundenspezifisch anpassen) *** +LEFT JOIN ( + SELECT DISTINCT v2o.ObjectOid AS EmployeeOid + FROM valuelistentry2object v2o + JOIN valuelistentry vle ON vle.Oid = v2o.ValuelistEntryOid + WHERE v2o.ObjectTid = 2 AND v2o.IsActive = 1 AND vle.Type = 5 AND vle.IsActive = 1 AND vle.Value IN ('Q1', 'Q2') -- Qualifikationen für 'Qualifiziert' +) q12 ON q12.EmployeeOid = sr.EmployeeOid + +LEFT JOIN ( + SELECT DISTINCT v2o.ObjectOid AS EmployeeOid + FROM valuelistentry2object v2o + JOIN valuelistentry vle ON vle.Oid = v2o.ValuelistEntryOid + WHERE v2o.ObjectTid = 2 AND v2o.IsActive = 1 AND vle.Type = 5 AND vle.IsActive = 1 AND vle.Value IN ('Q3', 'Q4') -- Qualifikationen für 'Unterstützend' +) q34 ON q34.EmployeeOid = sr.EmployeeOid +-- *** Ende Mapping *** +WHERE scat.Billable = 1 AND c2s.ApprovedStartDate <= CURDATE() AND (c2s.ApprovedEndDate >= CURDATE() OR c2s.ApprovedEndDate IS NULL) +-- AND sr.StartDate >= ':Von' AND sr.StartDate < ':Bis' +GROUP BY p.LastName, p.Firstname, c2s.ApprovedStartDate, c2s.ApprovedEndDate +ORDER BY p.LastName; \ No newline at end of file diff --git a/Queries/Hilfepläne mit aktuellen Bewilligungen - mit Stunden, Leistungskategorien UND Betreuern.txt b/Queries/Hilfepläne mit aktuellen Bewilligungen - mit Stunden, Leistungskategorien UND Betreuern.txt new file mode 100644 index 000000000..f5e43b466 --- /dev/null +++ b/Queries/Hilfepläne mit aktuellen Bewilligungen - mit Stunden, Leistungskategorien UND Betreuern.txt @@ -0,0 +1,78 @@ +-- Query- für Herrn Ferchland - 2385915144 (APP6) +-- Hilfepläne mit aktuellen Bewilligungen (max 3 Bew mit Leistungskategorie u Stunden / Woche + Betreuern) + +SELECT + base.Nachname, base.Vorname, base.Kostentraeger, base.`Bewilligt von`, base.`Bewilligt bis`, base.`Bewilligung 1`, base.`Stunden 1`, + -- Betreuer für SCAP 1 + (SELECT GROUP_CONCAT(CONCAT(p2.`FirstName`, ' ', p2.`LastName`) ORDER BY scap2e.EmployeeOid SEPARATOR ', ') + FROM supportconceptapprovalperiod2employee scap2e + INNER JOIN `employee` e ON scap2e.`EmployeeOid` = e.`Oid` + INNER JOIN `person` p2 ON e.`PersonOid` = p2.`Oid` + WHERE scap2e.SupportConceptApprovalPeriodOid = base.scap1_oid + ) AS 'Betreuer 1', + base.`Bewilligung 2`, base.`Stunden 2`, + -- Betreuer für SCAP 2 + (SELECT GROUP_CONCAT( + CONCAT(p2.`FirstName`, ' ', p2.`LastName`) + ORDER BY scap2e.EmployeeOid SEPARATOR ', ') + FROM supportconceptapprovalperiod2employee scap2e + INNER JOIN `employee` e ON scap2e.`EmployeeOid` = e.`Oid` + INNER JOIN `person` p2 ON e.`PersonOid` = p2.`Oid` + WHERE scap2e.SupportConceptApprovalPeriodOid = base.scap2_oid + ) AS 'Betreuer 2', + base.`Bewilligung 3`, base.`Stunden 3`, + -- Betreuer für SCAP 3 + (SELECT GROUP_CONCAT( + CONCAT(p2.`FirstName`, ' ', p2.`LastName`) + ORDER BY scap2e.EmployeeOid SEPARATOR ', ') + FROM supportconceptapprovalperiod2employee scap2e + INNER JOIN `employee` e ON scap2e.`EmployeeOid` = e.`Oid` + INNER JOIN `person` p2 ON e.`PersonOid` = p2.`Oid` + WHERE scap2e.SupportConceptApprovalPeriodOid = base.scap3_oid + ) AS 'Betreuer 3' + +FROM ( + -- Kernabfrage Bewilligungen ohne Betreuuer + SELECT + p.LastName AS Nachname, + p.FirstName AS Vorname, + o.`Name` AS Kostentraeger, + cb2sc.ApprovedStartDate AS 'Bewilligt von', + cb2sc.ApprovedEndDate AS 'Bewilligt bis', + MAX(CASE WHEN scap.rn = 1 THEN ROUND(scap.ApprovedBEPerInterval, 2) END) AS 'Stunden 1', + MAX(CASE WHEN scap.rn = 1 THEN CONCAT(DATE_FORMAT(scap.Start, '%d.%m.%Y'), ' - ', DATE_FORMAT(scap.EndDate, '%d.%m.%Y'), ' ', cat1.Name) END) AS 'Bewilligung 1', + MAX(CASE WHEN scap.rn = 2 THEN ROUND(scap.ApprovedBEPerInterval, 2) END) AS 'Stunden 2', + MAX(CASE WHEN scap.rn = 2 THEN CONCAT(DATE_FORMAT(scap.Start, '%d.%m.%Y'), ' - ', DATE_FORMAT(scap.EndDate, '%d.%m.%Y'), ' ', cat2.Name) END) AS 'Bewilligung 2', + MAX(CASE WHEN scap.rn = 3 THEN ROUND(scap.ApprovedBEPerInterval, 2) END) AS 'Stunden 3', + MAX(CASE WHEN scap.rn = 3 THEN CONCAT(DATE_FORMAT(scap.Start, '%d.%m.%Y'), ' - ', DATE_FORMAT(scap.EndDate, '%d.%m.%Y'), ' ', cat3.Name) END) AS 'Bewilligung 3', + -- Hilfsspalten: OIDs der 4 SCRAPs für die Betreuer-Subqueries + MAX(CASE WHEN scap.rn = 1 THEN scap.Oid END) AS scap1_oid, + MAX(CASE WHEN scap.rn = 2 THEN scap.Oid END) AS scap2_oid, + MAX(CASE WHEN scap.rn = 3 THEN scap.Oid END) AS scap3_oid + FROM `person` p + INNER JOIN `customer` c ON p.Oid = c.PersonOid + LEFT JOIN team2customer t2c ON c.Oid = t2c.CustomerOid + LEFT JOIN team t ON t2c.TeamOid = t.Oid + INNER JOIN `supportconcept` sc ON c.Oid = sc.CustomerOid + INNER JOIN `costbearer2supportconcept` cb2sc ON sc.Oid = cb2sc.SupportConceptOid + INNER JOIN `costbearer` cb ON cb2sc.`CostBearerOid` = cb.`Oid` + INNER JOIN `organisation` o ON cb.`Oid` = o.`CostBearerOid` + INNER JOIN ( + SELECT s1.Oid, s1.CostBearer2SupportConceptOid, s1.ApprovedBEPerInterval, + s1.Start, s1.EndDate, s1.ServiceCategoryOid, s1.Notice, + COUNT(s2.Oid) + 1 AS rn + FROM `supportconceptapprovalperiod` s1 + LEFT JOIN `supportconceptapprovalperiod` s2 + ON s1.CostBearer2SupportConceptOid = s2.CostBearer2SupportConceptOid + -- AND s1.Start <= CURDATE() AND (s1.EndDate IS NULL OR s1.EndDate >= CURDATE()) + AND (s2.Start < s1.Start OR (s2.Start = s1.Start AND s2.Oid < s1.Oid)) + -- WHERE s1.Start <= CURDATE() AND (s1.EndDate IS NULL OR s1.EndDate >= CURDATE()) + GROUP BY s1.Oid, s1.CostBearer2SupportConceptOid, s1.ApprovedBEPerInterval, s1.Start, s1.EndDate, s1.ServiceCategoryOid, s1.Notice + ) scap ON cb2sc.Oid = scap.CostBearer2SupportConceptOid + LEFT JOIN servicecategory cat1 ON scap.ServiceCategoryOid = cat1.Oid AND scap.rn = 1 + LEFT JOIN servicecategory cat2 ON scap.ServiceCategoryOid = cat2.Oid AND scap.rn = 2 + LEFT JOIN servicecategory cat3 ON scap.ServiceCategoryOid = cat3.Oid AND scap.rn = 3 + WHERE c.IsActive = 1 AND sc.IsActive = 1 + GROUP BY p.Oid, p.LastName, p.FirstName, p.DateOfBirth, o.`Name`, cb2sc.ApprovedStartDate, cb2sc.ApprovedEndDate + ORDER BY t.Name, p.LastName +) base; \ No newline at end of file diff --git a/Report/DefaultReports/SettlementReport.cs b/Report/DefaultReports/SettlementReport.cs index faa9e1fd0..409462030 100644 --- a/Report/DefaultReports/SettlementReport.cs +++ b/Report/DefaultReports/SettlementReport.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using BeWo.Data.Access; using BeWo.Data.Entities; using BeWo.Report; @@ -24,7 +25,6 @@ namespace BeWo.Report.DefaultReports.Alt { lblNotice.Visible = false; } - if (pRO.InvoiceItems != null && pRO.InvoiceItems.Count == 1) { var ii = pRO.InvoiceItems[0]; @@ -35,7 +35,7 @@ namespace BeWo.Report.DefaultReports.Alt } if (!isDefaultSpitzabrechnung) { - if (pRO.DifferentHourlyRateCount > 0 && pRO.HourlyRateNew.HasValue) + if (pRO.DifferentHourlyRateCount > 0 && pRO.HourlyRateNew.HasValue && !pRO.InvoiceItems.Any(d => d.ItemDescription != null && d.ItemDescription.Contains("Storno"))) { isDefaultSpitzabrechnung = true; } @@ -70,11 +70,19 @@ namespace BeWo.Report.DefaultReports.Alt { foreach (var ii in pRO.InvoiceItems) { - ii.ItemDescription = String.Format("{0:dd.MM.yyyy} bis {1:dd.MM.yyyy}: {2:0.00##} FLS {3}x {4:c}", + if (ii.ItemDescription != null && ii.ItemDescription.Contains("Storno")) + { + ii.ItemDescription = String.Format("Ausbuchung zur vorherigen Rechnung - {0:dd.MM.yyyy} bis {1:dd.MM.yyyy}", + ii.ItemPeriodStart, ii.ItemPeriodEnd); + } + else + { + ii.ItemDescription = String.Format("{0:dd.MM.yyyy} bis {1:dd.MM.yyyy}: {2:0.00##} FLS {3}x {4:c}", ii.ItemPeriodStart, ii.ItemPeriodEnd, ii.UnitCount, ii.RateFactor == 0 ? "" : "x " + pRO.RateFactorText2 + " ", ii.AmountPerUnit); - } + } + } } } } diff --git a/Report/ReportObjects/FinanceRO.cs b/Report/ReportObjects/FinanceRO.cs index 13e1d5e7d..7fe00c880 100644 --- a/Report/ReportObjects/FinanceRO.cs +++ b/Report/ReportObjects/FinanceRO.cs @@ -223,15 +223,20 @@ namespace BeWo.Report.ReportObjects { records = new List(); } - + + // AB, 22.04.2026: Bugfix wenn Betreuung beendet und ein Zeitraum über Ende hinweg gewählt wird + var terminationDate = ro.Costbearer2Supportconcept.SupportConcept.Customer.TerminationDate; + DateTime? effectiveEnd = end; + if (terminationDate.HasValue && (!effectiveEnd.HasValue || terminationDate.Value < effectiveEnd.Value)) + { + effectiveEnd = terminationDate.Value; + } //1. if (ro.SupportConceptApprovalPeriod != null && ro.SupportConceptApprovalPeriod.ServiceCategory != null) { ro.Leistungskategorie = ro.SupportConceptApprovalPeriod.ServiceCategory.Name; - ro.ServiceRecords = records.Where(sr => - sr.ServiceDescription.Category.ServiceCategoryOid == ro.SupportConceptApprovalPeriod.ServiceCategory.ServiceCategoryOid) - .ToList(); + ro.ServiceRecords = records.Where(sr => sr.ServiceDescription.Category.ServiceCategoryOid == ro.SupportConceptApprovalPeriod.ServiceCategory.ServiceCategoryOid).ToList(); } else { @@ -272,7 +277,7 @@ namespace BeWo.Report.ReportObjects } else { - ro.ApprovedHours = calc.GetApprovedHoursTillNow(ro.Costbearer2Supportconcept, end.Value) ?? 0; + ro.ApprovedHours = calc.GetApprovedHoursTillNow(ro.Costbearer2Supportconcept, effectiveEnd.Value) ?? 0; } ro.StundenNichtFehlkontakte = calc.GetBillableDurationInMinutes(flsRecords.Where(sr => sr.Start.Value.Date < end.Value.AddDays(1)).ToList()) / 60; ro.StundenFehlkontakte = calc.GetBillableDurationInMinutes(fkRecords.Where(sr => sr.Start.Value.Date < end.Value.AddDays(1)).ToList()) / 60; @@ -317,20 +322,20 @@ namespace BeWo.Report.ReportObjects } if (ro.SupportConceptApprovalPeriod != null) { - ro.ApprovedHoursInReportTimeSpan = calc.GetApprovedHoursForPeriod(ro.SupportConceptApprovalPeriod, costRateDcs, start, end) ?? 0; + ro.ApprovedHoursInReportTimeSpan = calc.GetApprovedHoursForPeriod(ro.SupportConceptApprovalPeriod, costRateDcs, start, effectiveEnd) ?? 0; } else { - ro.ApprovedHoursInReportTimeSpan = calc.GetApprovedHoursForPeriod(ro.Costbearer2Supportconcept, start.Value, end.Value); + ro.ApprovedHoursInReportTimeSpan = calc.GetApprovedHoursForPeriod(ro.Costbearer2Supportconcept, start.Value, effectiveEnd.Value); } if (splitByServiceCategory && ro.SupportConceptApprovalPeriod != null) { - ro.ApprovedAmountInReportTimeSpan = (decimal)calc.GetApprovedAmountForPeriod(ro.Costbearer2Supportconcept, start.Value, end.Value, ro.SupportConceptApprovalPeriod.ServiceCategory); + ro.ApprovedAmountInReportTimeSpan = (decimal)calc.GetApprovedAmountForPeriod(ro.Costbearer2Supportconcept, start.Value, effectiveEnd.Value, ro.SupportConceptApprovalPeriod.ServiceCategory); } else { - ro.ApprovedAmountInReportTimeSpan = (decimal)calc.GetApprovedAmountForPeriod(ro.Costbearer2Supportconcept, start.Value, end.Value, null); + ro.ApprovedAmountInReportTimeSpan = (decimal)calc.GetApprovedAmountForPeriod(ro.Costbearer2Supportconcept, start.Value, effectiveEnd.Value, null); } ro.AmountInReportTimeSpan = 0; ro.AmountNichtFehlkontakteInReportTimeSpan = 0; diff --git a/ReportImp/AsSozialeDienstleistungenEV/Taetigkeitsnachweis.cs b/ReportImp/AsSozialeDienstleistungenEV/Taetigkeitsnachweis.cs index 96d0e4742..6222f3b22 100644 --- a/ReportImp/AsSozialeDienstleistungenEV/Taetigkeitsnachweis.cs +++ b/ReportImp/AsSozialeDienstleistungenEV/Taetigkeitsnachweis.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Linq; using System.Text.RegularExpressions; using BeWo.Data.Access; using BeWo.Data.Entities; @@ -33,11 +34,11 @@ namespace AsSozialeDienstleistungenEV decimal minutes = 0; decimal betrag = 0; decimal stundensatz = 0; - if (pRO.Services != null && pRO.Services.Count > 0) { List servicesBillable = new List(); - stundensatz = GetStundensatz(pRO.Services[0], pRO.StartDate); + var mainRecord = pRO.Services.GroupBy(e => e.ServiceCategory).OrderByDescending(g => g.Count()).First().First(); + stundensatz = GetStundensatz(mainRecord, pRO.StartDate); foreach (var sd in pRO.Services) { @@ -103,5 +104,6 @@ namespace AsSozialeDienstleistungenEV // return 0; //} + } } diff --git a/ReportImp/AutismusLeben/Service/CustomAccountingService.cs b/ReportImp/AutismusLeben/Service/CustomAccountingService.cs index bb323eb44..d1bd352cc 100644 --- a/ReportImp/AutismusLeben/Service/CustomAccountingService.cs +++ b/ReportImp/AutismusLeben/Service/CustomAccountingService.cs @@ -38,9 +38,29 @@ namespace AutismusLeben.Service } DAOFactory.GenericDAO.Insert(i); - inc.IncreaseInvoiceNumber(1, null); + return i; + } + + public override SettlementInvoice ErstelleStornoSpitzabrechnung(InvoiceBaseDC ibdc) + { + var i = base.ErstelleStornoSpitzabrechnung(ibdc); + int invoiceCounter = 0; + var inc = PluginLoader.FindClass(); + i.InvoiceBase.InvoiceNumber = inc.GetNextInvoiceNumber(invoiceCounter, i.InvoiceBase) + " Storno"; + + if (String.IsNullOrEmpty(i.InvoiceBase.InvoiceTypeText)) + { + i.InvoiceBase.InvoiceTypeText = "Storno"; + } + else + { + i.InvoiceBase.InvoiceTypeText += " Storno"; + } + + DAOFactory.GenericDAO.Insert(i); + inc.IncreaseInvoiceNumber(1, null); return i; } diff --git a/ReportImp/FeidPartnerReports/Invoicing/CollectiveInvoiceBeWo67Creation.cs b/ReportImp/FeidPartnerReports/Invoicing/CollectiveInvoiceBeWo67Creation.cs index 94ca2de56..cd698aea9 100644 --- a/ReportImp/FeidPartnerReports/Invoicing/CollectiveInvoiceBeWo67Creation.cs +++ b/ReportImp/FeidPartnerReports/Invoicing/CollectiveInvoiceBeWo67Creation.cs @@ -24,6 +24,8 @@ namespace FeidPartnerReports.Invoicing private decimal BG1Tag = 50m; private decimal BG2Tag = 30m; private bool monthly = true; + private HashSet _periodenMitNahtlosemNachfolger = new HashSet(); + private HashSet _periodenMitNahtlosemVorgaenger = new HashSet(); public override void SetInvoiceId(ServiceInvoice invoice) { @@ -67,11 +69,11 @@ namespace FeidPartnerReports.Invoicing { var invoice = new ServiceInvoice(); var newDict = new Dictionary>(); - // Zweites Dict nur für unbewilligte Hilfepläne. Vorher sind unbewilligte und bewilligte im selben Dict gelandet und beide abgerechnet + // Zweites Dict nur für unbewilligte Hilfepl�ne. Vorher sind unbewilligte und bewilligte im selben Dict gelandet und beide abgerechnet var unbewilligteDict = new Dictionary>(); bool unbewilligte = true; - if (supportConcepts2ServiceRecords.Any(sc2sr => sc2sr.Key.IsApproved)) // Für normalen Rechnungslauf + if (supportConcepts2ServiceRecords.Any(sc2sr => sc2sr.Key.IsApproved)) // Für normalen Rechnungslauf { unbewilligte = false; } @@ -83,7 +85,7 @@ namespace FeidPartnerReports.Invoicing } else { - unbewilligteDict.Add(sc2sr.Key, sc2sr.Value); // Rechnungsvorschau für Unbewilligte Hilfepläne in Berichten + unbewilligteDict.Add(sc2sr.Key, sc2sr.Value); // Rechnungsvorschau für Unbewilligte Hilfepläne in Berichten } } @@ -113,6 +115,59 @@ namespace FeidPartnerReports.Invoicing return invoice; } + public override void SetCollectiveBillingServiceInvoicePeriods(ServiceInvoice invoice, DateTimeSpan invoicePeriod, + Dictionary> supportConcepts2ServiceRecords) + { + BuildNahtlosNachfolgerSet(supportConcepts2ServiceRecords); + base.SetCollectiveBillingServiceInvoicePeriods(invoice, invoicePeriod, supportConcepts2ServiceRecords); + } + + private void BuildNahtlosNachfolgerSet(Dictionary> dict) + { + _periodenMitNahtlosemNachfolger.Clear(); + _periodenMitNahtlosemVorgaenger.Clear(); + + // (customerOid, serviceCategoryOid) → alle Bewilligungsperioden dieser Kombination + var lookup = new Dictionary<(long customerOid, long serviceCategoryOid), List<(long scapOid, DateTime start, DateTime end)>>(); + + foreach (var sc2sr in dict) + { + if (sc2sr.Key.CostBearerRelOids == null || sc2sr.Key.CostBearerRelOids.Count == 0) continue; + + var c2s = DAOFactory.GenericDAO.LoadByID(sc2sr.Key.CostBearerRelOids[0]); + if (c2s?.ApprovalPeriodList == null || c2s.SupportConcept?.Customer == null) continue; + + long customerOid = c2s.SupportConcept.Customer.Oid.Value; + + foreach (SupportConceptApprovalPeriod iPeriod in c2s.ApprovalPeriodList) + { + var scapDC = MapperFactory.SupportConceptApprovalPeriodDC_SupportConceptApprovalPeriod.MapToNewDC(iPeriod); + if (!scapDC.SupportConceptApprovalPeriodOid.HasValue) continue; + if (scapDC.ServiceCategory?.ServiceCategoryOid == null) continue; + if (!scapDC.StartDate.HasValue || !scapDC.EndDate.HasValue) continue; + + var key = (customerOid, scapDC.ServiceCategory.ServiceCategoryOid.Value); + if (!lookup.ContainsKey(key)) + lookup[key] = new List<(long, DateTime, DateTime)>(); + + lookup[key].Add((scapDC.SupportConceptApprovalPeriodOid.Value, scapDC.StartDate.Value, scapDC.EndDate.Value)); + } + } + + foreach (var group in lookup.Values) + { + var sorted = group.OrderBy(p => p.start).ToList(); + for (int i = 0; i < sorted.Count - 1; i++) + { + if (sorted[i].end.AddDays(1).Date == sorted[i + 1].start.Date) + { + _periodenMitNahtlosemNachfolger.Add(sorted[i].scapOid); + _periodenMitNahtlosemVorgaenger.Add(sorted[i + 1].scapOid); + } + } + } + } + public override void CreateFixedAmounts(ServiceInvoicePeriod serviceInvoicePeriod, SupportConceptApprovalPeriodDC supportConceptApprovalPeriod, CostBearer2SupportConcept cb2sc) { var calc = PluginLoader.FindClass(_SpecificID) ?? BS.Shared.Services.Calculations.GetInstance(_SpecificID); @@ -130,7 +185,7 @@ namespace FeidPartnerReports.Invoicing { CreateInvoiceItemsLwv(serviceInvoicePeriod, supportConceptApprovalPeriod, start, end, preis, null); } - // ...aber es können auch Zeiträume für einzelne Klienten nachträglich abgerechnet werden, + // ...aber es können auch Zeiträume für einzelne Klienten nachträglich abgerechnet werden, // dann monatliche Rechnungsposition else { @@ -139,7 +194,7 @@ namespace FeidPartnerReports.Invoicing .GroupBy(e => new DateTime(e.BillingPeriodStart.Value.Year, e.BillingPeriodStart.Value.Month, 1)) .ToDictionary( g => g.Key, - g => g.OrderBy(e => e.BillingPeriodStart).ToList() // Liste der Einträge in diesem Monat + g => g.OrderBy(e => e.BillingPeriodStart).ToList() // Liste der Einträge in diesem Monat ); foreach (var kvp in monthlyDict.OrderBy(k => k.Key)) @@ -157,6 +212,30 @@ namespace FeidPartnerReports.Invoicing private void CreateInvoiceItemsLwv(ServiceInvoicePeriod serviceInvoicePeriod, SupportConceptApprovalPeriodDC supportConceptApprovalPeriod, DateTime start, DateTime end, decimal preis, decimal? count) { + // Nahtloser Vorgänger deckt den Monatsanfang ab: HP1 rechnet den vollen Monat ab, + // dieser Hilfeplan (HP2) erzeugt keinen eigenen Posten für diesen Monat. + var scapOid = supportConceptApprovalPeriod.SupportConceptApprovalPeriodOid; + if (scapOid.HasValue && _periodenMitNahtlosemVorgaenger.Contains(scapOid.Value) + && supportConceptApprovalPeriod.StartDate.HasValue + && supportConceptApprovalPeriod.StartDate.Value > start) + { + //Falls kein InvoiceItem mit neuen HP erwünscht ist einfach auskommentieren und stattdessen -> return; + serviceInvoicePeriod.InvoiceItemList.Add(new InvoiceItem + { + ItemPeriodStart = serviceInvoicePeriod.Start, + ItemPeriodEnd = serviceInvoicePeriod.End, + SupportConceptApprovalPeriodOid = supportConceptApprovalPeriod.SupportConceptApprovalPeriodOid, + AccountingInterval = AccountingIntervalType.Monthly, + ItemDescription = supportConceptApprovalPeriod.ServiceCategory.Name, + UnitCount = 0, + AmountPerUnit = 0, + AmountTotal = 0, + GrossAmountTotal = 0, + Notice = "Folgebewilligung" + }); + return; + } + if (count == null) { count = 1; @@ -172,16 +251,20 @@ namespace FeidPartnerReports.Invoicing UnitDescription = String.Format("{0:MM.yyyy}", start), Notice = "keine Minuten" }; - bool teilmonat = false; // es gibt eigentlich feste Monatsbeträge, nur wenn Bew im Monat endet werden Tage genommen + bool teilmonat = false; // es gibt eigentlich feste Monatsbeträge, nur wenn Bew im Monat endet werden Tage genommen if (supportConceptApprovalPeriod.StartDate != null && supportConceptApprovalPeriod.StartDate > start) { start = supportConceptApprovalPeriod.StartDate.Value; teilmonat = true; } + // Kein Teilmonat wenn ein nahtloser Nachfolge-Hilfeplan den Rest des Monats abdeckt if (supportConceptApprovalPeriod.EndDate != null && supportConceptApprovalPeriod.EndDate < end) { - end = supportConceptApprovalPeriod.EndDate.Value; - teilmonat = true; + if (!scapOid.HasValue || !_periodenMitNahtlosemNachfolger.Contains(scapOid.Value)) + { + end = supportConceptApprovalPeriod.EndDate.Value; + teilmonat = true; + } } ii.AccountingInterval = AccountingIntervalType.Monthly; @@ -217,13 +300,17 @@ namespace FeidPartnerReports.Invoicing { iPeriod.Claim = 0; if (iPeriod.SupportConceptApprovalPeriod.ServiceCategory.Name != "qA" && iPeriod.ApprovedFixedAmount.HasValue && iPeriod.ApprovedFixedAmount.Value != 0) + { iPeriod.Claim = iPeriod.ApprovedFixedAmount; + } else { foreach (InvoiceItem item in iPeriod.InvoiceItemList) { if (item.GrossAmountTotal.HasValue) + { iPeriod.Claim += item.GrossAmountTotal; + } } } iPeriod.Claim = Math.Round(iPeriod.Claim.Value, 2, MidpointRounding.AwayFromZero); diff --git a/ReportImp/InputFamilienhilfe/Invoicing/UnterbringungInvoiceCreation.cs b/ReportImp/InputFamilienhilfe/Invoicing/UnterbringungInvoiceCreation.cs index abf34dd97..59b6aacb7 100644 --- a/ReportImp/InputFamilienhilfe/Invoicing/UnterbringungInvoiceCreation.cs +++ b/ReportImp/InputFamilienhilfe/Invoicing/UnterbringungInvoiceCreation.cs @@ -72,64 +72,66 @@ namespace InputFamilienhilfe.Invoicing { list.Add(i); } - - var listIzl = CreateIZLItems(scap, calc, serviceRecordsInPeriod, invoicePeriod); - list.AddRange(listIzl); - - //Bekleidungsergänzung wird erst ab dem ersten VOLLEN Monat des Hilfeplans berechnet - DateTime startMonat2 = new DateTime(scap.StartDate.Value.Year, scap.StartDate.Value.Month, 1).AddMonths(1); - - if (scap.StartDate.Value.Day == 1 || invoicePeriod.StartDate >= startMonat2) + // AB, 24.04.2026: neue Betreuungsform wo (vorerst) nur die Tagessätze und nichts anderes abgerechnet wir -> Alias BJW EGH + if (!scap.CostBearer2SupportConcept.SupportConcept.Customer.CustomerAlias.ToLower().Contains("egh")) { - i = CreateInvoiceItem(scap, invoicePeriod, 1, 48, "Bekleidungsergänzung"); + var listIzl = CreateIZLItems(scap, calc, serviceRecordsInPeriod, invoicePeriod); + list.AddRange(listIzl); + + //Bekleidungsergänzung wird erst ab dem ersten VOLLEN Monat des Hilfeplans berechnet + DateTime startMonat2 = new DateTime(scap.StartDate.Value.Year, scap.StartDate.Value.Month, 1).AddMonths(1); + + if (scap.StartDate.Value.Day == 1 || invoicePeriod.StartDate >= startMonat2) + { + i = CreateInvoiceItem(scap, invoicePeriod, 1, 48, "Bekleidungsergänzung"); + if (i != null) + { + list.Add(i); + } + } + i = CreateInvoiceItem(scap, invoicePeriod, 1, 55, "Budget Sonderaufwendungen"); + if (i != null) + { + list.Add(i); + } + + decimal barbetragPreis = GetBarbetragPreis(scap, invoicePeriod.EndDate); + + if (barbetragPreis > 0) + { + i = CreateInvoiceItem(scap, invoicePeriod, 1, barbetragPreis, "Barbetrag"); + if (i != null) + { + list.Add(i); + } + } + + // AB 24.04.2026, noch ältere Abrechnungslogik, hab die Funktionen mal gelöscht, aber hier lass ich mal für den Fall der Fälle stehe + //i = CreateWohnenPauschale(scap, calc, invoicePeriod); + //if (i != null) + //{ + // list.Add(i); + //} + + //i = CreateHluPauschale(scap, calc, invoicePeriod); + //if (i != null) + //{ + // list.Add(i); + //} + //i = CreateBudget623Pauschale(scap, calc, invoicePeriod); + //if (i != null) + //{ + // list.Add(i); + //} + var iilist = CreateSonstigeKosten(scap, calc, serviceRecordsInPeriod, invoicePeriod); + list.AddRange(iilist); + + i = CreateLohnAnteil(scap, calc, invoicePeriod); if (i != null) { list.Add(i); } } - i = CreateInvoiceItem(scap, invoicePeriod, 1, 55, "Budget Sonderaufwendungen"); - if (i != null) - { - list.Add(i); - } - - decimal barbetragPreis = GetBarbetragPreis(scap, invoicePeriod.EndDate); - - if (barbetragPreis > 0) - { - i = CreateInvoiceItem(scap, invoicePeriod, 1, barbetragPreis, "Barbetrag"); - if (i != null) - { - list.Add(i); - } - } - //i = CreateWohnenPauschale(scap, calc, invoicePeriod); - //if (i != null) - //{ - // list.Add(i); - //} - - //i = CreateHluPauschale(scap, calc, invoicePeriod); - //if (i != null) - //{ - // list.Add(i); - //} - - - //i = CreateBudget623Pauschale(scap, calc, invoicePeriod); - //if (i != null) - //{ - // list.Add(i); - //} - var iilist = CreateSonstigeKosten(scap, calc, serviceRecordsInPeriod, invoicePeriod); - list.AddRange(iilist); - - i = CreateLohnAnteil(scap, calc, invoicePeriod); - if (i != null) - { - list.Add(i); - } - return CreateSummaryInvoiceItems(list, invoicePeriod, scap, calc); } @@ -227,15 +229,9 @@ namespace InputFamilienhilfe.Invoicing } unitCount = days; } - } - - - - + } } - - invoiceItem.UnitCount = unitCount; invoiceItem.AmountPerUnit = amount; invoiceItem.AmountTotal = invoiceItem.AmountPerUnit * invoiceItem.UnitCount; @@ -249,107 +245,6 @@ namespace InputFamilienhilfe.Invoicing return invoiceItem; } - private InvoiceItem CreateWohnenPauschale(SupportConceptApprovalPeriod scap, Calculations calc, DateTimeSpan invoicePeriod) - { - if (scap.ApprovedFixedAmount.HasValue) - { - - var invoiceItem = new InvoiceItem(); - - if (scap.ApprovedFixedAmountInterval.HasValue && - scap.ApprovedFixedAmountInterval.Value == SupportConceptApprovalInterval.Monthly) - { - invoiceItem.UnitCount = 1; - } - else - { - DateTime start = invoicePeriod.StartDate; - DateTime end = invoicePeriod.EndDate; - - if (scap.StartDate.HasValue && scap.StartDate.Value > start) - { - start = scap.StartDate.Value; - } - if (scap.EndDate.HasValue && scap.EndDate.Value < end) - { - end = scap.EndDate.Value; - } - - decimal days = 0; - - if (end >= start) - { - days = (decimal)end.Subtract(start).TotalDays + 1; - } - - invoiceItem.UnitCount = days; - } - - invoiceItem.AmountPerUnit = scap.ApprovedFixedAmount.Value; - invoiceItem.AmountTotal = invoiceItem.AmountPerUnit * invoiceItem.UnitCount; - invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal; - invoiceItem.ItemPeriodStart = invoicePeriod.StartDate; - invoiceItem.ItemPeriodEnd = invoicePeriod.EndDate; - invoiceItem.AccountingInterval = AccountingIntervalType.FlatRate; - invoiceItem.ItemDescription = "Wohnen / Tag"; - invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid; - - return invoiceItem; - } - - return null; - } - - private InvoiceItem CreateHluPauschale(SupportConceptApprovalPeriod scap, Calculations calc, DateTimeSpan invoicePeriod) - { - var invoiceItem = new InvoiceItem(); - - - decimal preis = 432; - - var cat = DAOFactory.SearchDAO.FindServiceCategoryByName("HLU"); - { - if (cat != null) - { - var crpList = MapperFactory.CostRatePeriodDC_CostRatePeriod.MapToNewDCs(cat.CostRatePeriods); - var crp = crpList.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney, invoicePeriod.StartDate); - if (crp != null && crp.CostRateValue.HasValue) - { - preis = crp.CostRateValue.Value; - } - - } - } - invoiceItem.UnitCount = 1; - invoiceItem.AmountPerUnit = preis; - invoiceItem.AmountTotal = invoiceItem.AmountPerUnit * invoiceItem.UnitCount; - invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal; - invoiceItem.ItemPeriodStart = invoicePeriod.StartDate; - invoiceItem.ItemPeriodEnd = invoicePeriod.EndDate; - invoiceItem.AccountingInterval = AccountingIntervalType.FlatRate; - invoiceItem.ItemDescription = "HLU / Monat"; - invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid; - - return invoiceItem; - } - - private InvoiceItem CreateBudget623Pauschale(SupportConceptApprovalPeriod scap, Calculations calc, DateTimeSpan invoicePeriod) - { - var invoiceItem = new InvoiceItem(); - - invoiceItem.UnitCount = 1; - invoiceItem.AmountPerUnit = 22; - invoiceItem.AmountTotal = invoiceItem.AmountPerUnit * invoiceItem.UnitCount; - invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal; - invoiceItem.ItemPeriodStart = invoicePeriod.StartDate; - invoiceItem.ItemPeriodEnd = invoicePeriod.EndDate; - invoiceItem.AccountingInterval = AccountingIntervalType.FlatRate; - invoiceItem.ItemDescription = "Budget nach § 6.2.3"; - invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid; - - return invoiceItem; - } - private InvoiceItem CreateInvoiceItem(SupportConceptApprovalPeriod scap, DateTimeSpan invoicePeriod, decimal unitCount, decimal amountPerUnit, String bezeichnung) { var invoiceItem = new InvoiceItem(); diff --git a/ReportImp/KcmGmbHSozio/SoziotherapieRechnung.Designer.cs b/ReportImp/KcmGmbHSozio/SoziotherapieRechnung.Designer.cs index 465b9ece1..412270fb6 100644 --- a/ReportImp/KcmGmbHSozio/SoziotherapieRechnung.Designer.cs +++ b/ReportImp/KcmGmbHSozio/SoziotherapieRechnung.Designer.cs @@ -35,9 +35,14 @@ namespace KcmGmbHSozio this.ReportHeader = new DevExpress.XtraReports.UI.ReportHeaderBand(); this.ruleRateFactorNull = new DevExpress.XtraReports.UI.FormattingRule(); this.topMarginBand1 = new DevExpress.XtraReports.UI.TopMarginBand(); + this.xrPictureBox1 = new DevExpress.XtraReports.UI.XRPictureBox(); + this.xrLabel1 = new DevExpress.XtraReports.UI.XRLabel(); this.bottomMarginBand1 = new DevExpress.XtraReports.UI.BottomMarginBand(); + this.xrLabel12 = new DevExpress.XtraReports.UI.XRLabel(); + this.xrLabel13 = new DevExpress.XtraReports.UI.XRLabel(); + this.xrLabel11 = new DevExpress.XtraReports.UI.XRLabel(); this.Page1 = new DevExpress.XtraReports.UI.GroupHeaderBand(); - this.xrRichText1 = new DevExpress.XtraReports.UI.XRRichText(); + this.xrLabel2 = new DevExpress.XtraReports.UI.XRLabel(); this.xrTable2 = new DevExpress.XtraReports.UI.XRTable(); this.xrTableRow4 = new DevExpress.XtraReports.UI.XRTableRow(); this.xrTableCell16 = new DevExpress.XtraReports.UI.XRTableCell(); @@ -88,7 +93,6 @@ namespace KcmGmbHSozio this.xrTableCell1 = new DevExpress.XtraReports.UI.XRTableCell(); this.xrTableCell5 = new DevExpress.XtraReports.UI.XRTableCell(); this.bindingSource1 = new System.Windows.Forms.BindingSource(this.components); - ((System.ComponentModel.ISupportInitialize)(this.xrRichText1)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.xrTable2)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.xrTable4)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.xrTable6)).BeginInit(); @@ -119,21 +123,94 @@ namespace KcmGmbHSozio // // topMarginBand1 // + this.topMarginBand1.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] { + this.xrPictureBox1, + this.xrLabel1}); this.topMarginBand1.HeightF = 200.625F; this.topMarginBand1.Name = "topMarginBand1"; // + // xrPictureBox1 + // + this.xrPictureBox1.ImageSource = new DevExpress.XtraPrinting.Drawing.ImageSource("img", resources.GetString("xrPictureBox1.ImageSource")); + this.xrPictureBox1.LocationFloat = new DevExpress.Utils.PointFloat(0.1342773F, 132.125F); + this.xrPictureBox1.Name = "xrPictureBox1"; + this.xrPictureBox1.SizeF = new System.Drawing.SizeF(249.8656F, 48.27777F); + this.xrPictureBox1.Sizing = DevExpress.XtraPrinting.ImageSizeMode.ZoomImage; + // + // xrLabel1 + // + this.xrLabel1.Font = new DevExpress.Drawing.DXFont("Calibri", 10F); + this.xrLabel1.LocationFloat = new DevExpress.Utils.PointFloat(332.9997F, 132.125F); + this.xrLabel1.Multiline = true; + this.xrLabel1.Name = "xrLabel1"; + this.xrLabel1.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); + this.xrLabel1.SizeF = new System.Drawing.SizeF(317F, 68.49998F); + this.xrLabel1.StylePriority.UseFont = false; + this.xrLabel1.StylePriority.UseTextAlignment = false; + this.xrLabel1.Text = "KCM BeWo GmbH\r\nDilborner Strasse 65\r\n41379 Brüggen\r\n\r\n"; + this.xrLabel1.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopRight; + // // bottomMarginBand1 // + this.bottomMarginBand1.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] { + this.xrLabel12, + this.xrLabel13, + this.xrLabel11}); this.bottomMarginBand1.Font = new DevExpress.Drawing.DXFont("Arial", 7F); - this.bottomMarginBand1.HeightF = 97.29169F; + this.bottomMarginBand1.HeightF = 112.5234F; this.bottomMarginBand1.Name = "bottomMarginBand1"; this.bottomMarginBand1.StylePriority.UseFont = false; // + // xrLabel12 + // + this.xrLabel12.Borders = DevExpress.XtraPrinting.BorderSide.Top; + this.xrLabel12.Font = new DevExpress.Drawing.DXFont("Calibri", 10F); + this.xrLabel12.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F); + this.xrLabel12.Multiline = true; + this.xrLabel12.Name = "xrLabel12"; + this.xrLabel12.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); + this.xrLabel12.SizeF = new System.Drawing.SizeF(287.8331F, 79.99996F); + this.xrLabel12.StylePriority.UseBorders = false; + this.xrLabel12.StylePriority.UseFont = false; + this.xrLabel12.StylePriority.UseTextAlignment = false; + this.xrLabel12.Text = "KCM BeWo GmbH\r\nGLS Bank\r\nIBAN: DE76 4306 0967 1221 8357 00\r\nBIC: GENODEM1GLS"; + this.xrLabel12.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleCenter; + // + // xrLabel13 + // + this.xrLabel13.Borders = DevExpress.XtraPrinting.BorderSide.Top; + this.xrLabel13.Font = new DevExpress.Drawing.DXFont("Calibri", 10F); + this.xrLabel13.LocationFloat = new DevExpress.Utils.PointFloat(287.8329F, 0F); + this.xrLabel13.Multiline = true; + this.xrLabel13.Name = "xrLabel13"; + this.xrLabel13.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); + this.xrLabel13.SizeF = new System.Drawing.SizeF(144.2209F, 79.99995F); + this.xrLabel13.StylePriority.UseBorders = false; + this.xrLabel13.StylePriority.UseFont = false; + this.xrLabel13.StylePriority.UseTextAlignment = false; + this.xrLabel13.Text = "www.kcm-bewo.de\r\nkontakt@kcm.de\r\n+49 2163 9498915"; + this.xrLabel13.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleCenter; + // + // xrLabel11 + // + this.xrLabel11.Borders = DevExpress.XtraPrinting.BorderSide.Top; + this.xrLabel11.Font = new DevExpress.Drawing.DXFont("Calibri", 10F); + this.xrLabel11.LocationFloat = new DevExpress.Utils.PointFloat(432.054F, 0F); + this.xrLabel11.Multiline = true; + this.xrLabel11.Name = "xrLabel11"; + this.xrLabel11.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); + this.xrLabel11.SizeF = new System.Drawing.SizeF(218.6613F, 79.99995F); + this.xrLabel11.StylePriority.UseBorders = false; + this.xrLabel11.StylePriority.UseFont = false; + this.xrLabel11.StylePriority.UseTextAlignment = false; + this.xrLabel11.Text = "Geschäftsführerin Lena Richter\r\nAmtsgericht Krefeld\r\nHRB15069"; + this.xrLabel11.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleCenter; + // // Page1 // this.Page1.BorderWidth = 2F; this.Page1.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] { - this.xrRichText1, + this.xrLabel2, this.xrTable2, this.xrLabel6, this.xrLabel7, @@ -145,14 +222,18 @@ namespace KcmGmbHSozio this.Page1.StylePriority.UseBorderWidth = false; this.Page1.StylePriority.UseFont = false; // - // xrRichText1 + // xrLabel2 // - this.xrRichText1.Font = new DevExpress.Drawing.DXFont("Calibri", 8.5F); - this.xrRichText1.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F); - this.xrRichText1.Name = "xrRichText1"; - this.xrRichText1.SerializableRtfString = resources.GetString("xrRichText1.SerializableRtfString"); - this.xrRichText1.SizeF = new System.Drawing.SizeF(317.0001F, 18F); - this.xrRichText1.StylePriority.UseFont = false; + this.xrLabel2.Font = new DevExpress.Drawing.DXFont("Calibri", 8.5F); + this.xrLabel2.LocationFloat = new DevExpress.Utils.PointFloat(0.134023F, 0F); + this.xrLabel2.Multiline = true; + this.xrLabel2.Name = "xrLabel2"; + this.xrLabel2.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); + this.xrLabel2.SizeF = new System.Drawing.SizeF(316.8658F, 24.99998F); + this.xrLabel2.StylePriority.UseFont = false; + this.xrLabel2.StylePriority.UseTextAlignment = false; + this.xrLabel2.Text = "KCM BeWo GmbH • Dilborner Strasse 65 • 41379 Brüggen\r\n\r\n"; + this.xrLabel2.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft; // // xrTable2 // @@ -300,6 +381,7 @@ namespace KcmGmbHSozio this.xrTableCell7.StylePriority.UseFont = false; this.xrTableCell7.StylePriority.UsePadding = false; this.xrTableCell7.StylePriority.UseTextAlignment = false; + this.xrTableCell7.Text = "460586883"; this.xrTableCell7.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleRight; this.xrTableCell7.Weight = 0.53122488360866615D; // @@ -841,14 +923,13 @@ namespace KcmGmbHSozio this.Font = new DevExpress.Drawing.DXFont("Verdana", 10F); this.FormattingRuleSheet.AddRange(new DevExpress.XtraReports.UI.FormattingRule[] { this.ruleRateFactorNull}); - this.Margins = new DevExpress.Drawing.DXMargins(100F, 50F, 200.625F, 97.29169F); + this.Margins = new DevExpress.Drawing.DXMargins(100F, 50F, 200.625F, 112.5234F); this.PageHeight = 1169; - this.PageWidth = 827; + this.PageWidth = 826; this.PaperKind = DevExpress.Drawing.Printing.DXPaperKind.A4; this.Version = "23.2"; xrWatermark1.Id = "Watermark1"; this.Watermarks.Add(xrWatermark1); - ((System.ComponentModel.ISupportInitialize)(this.xrRichText1)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.xrTable2)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.xrTable4)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.xrTable6)).EndInit(); @@ -916,6 +997,11 @@ namespace KcmGmbHSozio private DevExpress.XtraReports.UI.XRTableCell xrTableCell20; private DevExpress.XtraReports.UI.XRTableCell xrTableCell45; private DevExpress.XtraReports.UI.XRTableCell xrTableCell47; - private DevExpress.XtraReports.UI.XRRichText xrRichText1; + private DevExpress.XtraReports.UI.XRLabel xrLabel12; + private DevExpress.XtraReports.UI.XRLabel xrLabel13; + private DevExpress.XtraReports.UI.XRLabel xrLabel11; + private DevExpress.XtraReports.UI.XRPictureBox xrPictureBox1; + private DevExpress.XtraReports.UI.XRLabel xrLabel1; + private DevExpress.XtraReports.UI.XRLabel xrLabel2; } } diff --git a/ReportImp/KcmGmbHSozio/SoziotherapieRechnung.resx b/ReportImp/KcmGmbHSozio/SoziotherapieRechnung.resx index 22ced7263..2699ab83e 100644 --- a/ReportImp/KcmGmbHSozio/SoziotherapieRechnung.resx +++ b/ReportImp/KcmGmbHSozio/SoziotherapieRechnung.resx @@ -117,7 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ewBcAHIAdABmADEAXABkAGUAZgBmADAAewBcAGYAbwBuAHQAdABiAGwAewBcAGYAMAAgAEMAYQBsAGkAYgByAGkAOwB9AHsAXABmADEAIABUAGkAbQBlAHMAIABOAGUAdwAgAFIAbwBtAGEAbgA7AH0AfQB7AFwAYwBvAGwAbwByAHQAYgBsACAAOwBcAHIAZQBkADAAXABnAHIAZQBlAG4AMABcAGIAbAB1AGUAMAAgADsAXAByAGUAZAAwAFwAZwByAGUAZQBuADAAXABiAGwAdQBlADIANQA1ACAAOwB9AHsAXAAqAFwAZABlAGYAYwBoAHAAIABcAGYAMQBcAGYAcwAyADQAfQB7AFwAKgBcAGQAZQBmAHAAYQBwACAAXAB3AGkAZABjAHQAbABwAGEAcgB9AHsAXABzAHQAeQBsAGUAcwBoAGUAZQB0ACAAewBcAHEAbABcAGYAMQBcAGYAcwAyADQAIABOAG8AcgBtAGEAbAA7AH0AewBcACoAXABjAHMAMQBcAGYAMQBcAGYAcwAyADQAXABjAGYAMQAgAEQAZQBmAGEAdQBsAHQAIABQAGEAcgBhAGcAcgBhAHAAaAAgAEYAbwBuAHQAOwB9AHsAXAAqAFwAYwBzADIAXABzAGIAYQBzAGUAZABvAG4AMQBcAGYAMQBcAGYAcwAyADQAXABjAGYAMQAgAEwAaQBuAGUAIABOAHUAbQBiAGUAcgA7AH0AewBcACoAXABjAHMAMwBcAGYAMQBcAGYAcwAyADQAXAB1AGwAXABjAGYAMgAgAEgAeQBwAGUAcgBsAGkAbgBrADsAfQB7AFwAKgBcAHQAcwA0AFwAdABzAHIAbwB3AGQAXABmADEAXABmAHMAMgA0AFwAcQBsAFwAdABzAGMAZQBsAGwAcABhAGQAZABmAGwAMwBcAHQAcwBjAGUAbABsAHAAYQBkAGQAbAAxADAAOABcAHQAcwBjAGUAbABsAHAAYQBkAGQAZgBiADMAXAB0AHMAYwBlAGwAbABwAGEAZABkAGYAcgAzAFwAdABzAGMAZQBsAGwAcABhAGQAZAByADEAMAA4AFwAdABzAGMAZQBsAGwAcABhAGQAZABmAHQAMwBcAHQAcwB2AGUAcgB0AGEAbAB0AFwAYwBsAHQAeABsAHIAdABiACAATgBvAHIAbQBhAGwAIABUAGEAYgBsAGUAOwB9AHsAXAAqAFwAdABzADUAXAB0AHMAcgBvAHcAZABcAHMAYgBhAHMAZQBkAG8AbgA0AFwAZgAxAFwAZgBzADIANABcAHEAbABcAHQAcgBiAHIAZAByAHQAXABiAHIAZAByAHMAXABiAHIAZAByAHcAMQAwAFwAdAByAGIAcgBkAHIAbABcAGIAcgBkAHIAcwBcAGIAcgBkAHIAdwAxADAAXAB0AHIAYgByAGQAcgBiAFwAYgByAGQAcgBzAFwAYgByAGQAcgB3ADEAMABcAHQAcgBiAHIAZAByAHIAXABiAHIAZAByAHMAXABiAHIAZAByAHcAMQAwAFwAdAByAGIAcgBkAHIAaABcAGIAcgBkAHIAcwBcAGIAcgBkAHIAdwAxADAAXAB0AHIAYgByAGQAcgB2AFwAYgByAGQAcgBzAFwAYgByAGQAcgB3ADEAMABcAHQAcwBjAGUAbABsAHAAYQBkAGQAZgBsADMAXAB0AHMAYwBlAGwAbABwAGEAZABkAGwAMQAwADgAXAB0AHMAYwBlAGwAbABwAGEAZABkAGYAcgAzAFwAdABzAGMAZQBsAGwAcABhAGQAZAByADEAMAA4AFwAdABzAHYAZQByAHQAYQBsAHQAXABjAGwAdAB4AGwAcgB0AGIAIABUAGEAYgBsAGUAIABTAGkAbQBwAGwAZQAgADEAOwB9AH0AewBcACoAXABsAGkAcwB0AG8AdgBlAHIAcgBpAGQAZQB0AGEAYgBsAGUAfQBcAG4AbwB1AGkAYwBvAG0AcABhAHQAXABoAHQAbQBhAHUAdABzAHAAXABzAHAAbAB5AHQAdwBuAGkAbgBlAFwAYQBsAG4AdABiAGwAaQBuAGQAXABlAHgAcABzAGgAcgB0AG4AXABzAHAAbAB0AHAAZwBwAGEAcgBcAG4AbwBnAHIAbwB3AGEAdQB0AG8AZgBpAHQAXAB1AHQAaQBuAGwAXABuAG8AYgByAGsAdwByAHAAdABiAGwAXABmAHQAbgBsAHkAdAB3AG4AaQBuAGUAXABuAG8AdABjAHYAYQBzAHAAXABkAG4AdABiAGwAbgBzAGIAZABiAFwAbgBlAHcAdABiAGwAcwB0AHkAcgB1AGwAcwBcAHAAYQByAGQAXABwAGwAYQBpAG4AXABxAGwAXABmADEAXABmAHMAMgA0AFwA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 \ No newline at end of file diff --git a/Service/Plugins/AccountingService.cs b/Service/Plugins/AccountingService.cs index 05fc017a9..6592cc191 100644 --- a/Service/Plugins/AccountingService.cs +++ b/Service/Plugins/AccountingService.cs @@ -18,121 +18,121 @@ using BS.Shared.Models; namespace BeWo.Service.Plugins { - public class AccountingService : AbstractIDSpecificDefaultClass - { - public virtual List GenerateInitialServiceInvoices(long costBearerOid, long? supportConceptOid, DateTimeSpan invoicePeriod) - { - var cs = PluginLoader.FindClass(); - IEnumerable supportConcepts; - // GetAllActiveSupportConceptCostbearer returns a "Flat" SupportConcept List, one for each CostBearer2SupportConcept! - if (!supportConceptOid.HasValue) - { - supportConcepts = cs.GetAllActiveSupportConceptCostbearer(false, true, 0) - .Where(i => i.CostBearerOids2CostBearerRelOids.ContainsKey(costBearerOid)); - } - else - { - supportConcepts = cs.GetCompactSupportConcepts(supportConceptOid.Value, null) - .Where(i => i.CostBearerOids2CostBearerRelOids.ContainsKey(costBearerOid)); - } - - DateTimeSpan newSpan = null; - if (invoicePeriod != null) - { - //invoicePeriod.StartDateTime = invoicePeriod.StartDateTime.Date; - //invoicePeriod.EndDateTime = invoicePeriod.EndDateTime.Date; - newSpan = new DateTimeSpan(); - newSpan.StartDateTime = invoicePeriod.StartDateTime.Date; - newSpan.EndDateTime = invoicePeriod.EndDateTime.Date.AddDays(1).AddTicks(-1); - if (!supportConceptOid.HasValue) - { - supportConcepts = - supportConcepts.Where(sc => sc.StartDate < newSpan.EndDateTime && sc.EndDate >= newSpan.StartDate); - } - } - var supportConcepts2ServiceRecords = supportConcepts.ToDictionary( - i => i, - i => MapperFactory.ServiceRecordDC_ServiceRecord.MapToNewDCs( - DAOFactory.SearchDAO.FindServiceRecordsInSpan(i.CostBearerRelOids[0], newSpan))); - var cb = DAOFactory.GenericDAO.LoadByID(costBearerOid); - String tenant = PluginLoader.Tenant; - var factory = PluginLoader.FindClass(cb.ID); - if (factory == null) - { - factory = InvoiceFactory.GetInstance(cb.ID, tenant); - } - - var creator = factory.CreateInvoiceCreator(cb.ID, tenant, supportConcepts2ServiceRecords); - var newInvoices = creator.GenerateServiceInvoices(costBearerOid, invoicePeriod, supportConcepts2ServiceRecords); - - - //Prüfe ob Rechnungen neu sind oder Diff vorhanden - var differenzRechnungChecks = GetNewInvoices(newInvoices, invoicePeriod?.StartDate, invoicePeriod?.EndDate); - var resultList = ErstelleNeueRechnungen(differenzRechnungChecks); - - - return resultList; - } - - protected virtual List ErstelleNeueRechnungen(List differenzRechnungChecks) + public class AccountingService : AbstractIDSpecificDefaultClass + { + public virtual List GenerateInitialServiceInvoices(long costBearerOid, long? supportConceptOid, DateTimeSpan invoicePeriod) { - var rechnungen = new List(); - foreach (var item in differenzRechnungChecks) - { - if (item.VorhandeneRechungen.Count == 0 || !item.VorhandeneRechungen.Any(r => item.NeueRechnung.InvoiceBase.CustomerOid == r.InvoiceBase.CustomerOid)) - { - item.NeueRechnung.InvoiceBase.NeuErstellen = true; - rechnungen.Add(item.NeueRechnung); - } - else - { - var diffRechnung = ErstelleDifferenzRechnung(item); - if (diffRechnung != null) - { - diffRechnung.InvoiceBase.NeuErstellen = false; - rechnungen.Add(diffRechnung); - } - } - } + var cs = PluginLoader.FindClass(); + IEnumerable supportConcepts; + // GetAllActiveSupportConceptCostbearer returns a "Flat" SupportConcept List, one for each CostBearer2SupportConcept! + if (!supportConceptOid.HasValue) + { + supportConcepts = cs.GetAllActiveSupportConceptCostbearer(false, true, 0) + .Where(i => i.CostBearerOids2CostBearerRelOids.ContainsKey(costBearerOid)); + } + else + { + supportConcepts = cs.GetCompactSupportConcepts(supportConceptOid.Value, null) + .Where(i => i.CostBearerOids2CostBearerRelOids.ContainsKey(costBearerOid)); + } - return rechnungen; - } + DateTimeSpan newSpan = null; + if (invoicePeriod != null) + { + //invoicePeriod.StartDateTime = invoicePeriod.StartDateTime.Date; + //invoicePeriod.EndDateTime = invoicePeriod.EndDateTime.Date; + newSpan = new DateTimeSpan(); + newSpan.StartDateTime = invoicePeriod.StartDateTime.Date; + newSpan.EndDateTime = invoicePeriod.EndDateTime.Date.AddDays(1).AddTicks(-1); + if (!supportConceptOid.HasValue) + { + supportConcepts = + supportConcepts.Where(sc => sc.StartDate < newSpan.EndDateTime && sc.EndDate >= newSpan.StartDate); + } + } + var supportConcepts2ServiceRecords = supportConcepts.ToDictionary( + i => i, + i => MapperFactory.ServiceRecordDC_ServiceRecord.MapToNewDCs( + DAOFactory.SearchDAO.FindServiceRecordsInSpan(i.CostBearerRelOids[0], newSpan))); + var cb = DAOFactory.GenericDAO.LoadByID(costBearerOid); + String tenant = PluginLoader.Tenant; + var factory = PluginLoader.FindClass(cb.ID); + if (factory == null) + { + factory = InvoiceFactory.GetInstance(cb.ID, tenant); + } - protected virtual ServiceInvoiceDC ErstelleDifferenzRechnung(DifferenzRechnungCheck item) + var creator = factory.CreateInvoiceCreator(cb.ID, tenant, supportConcepts2ServiceRecords); + var newInvoices = creator.GenerateServiceInvoices(costBearerOid, invoicePeriod, supportConcepts2ServiceRecords); + + + //Prüfe ob Rechnungen neu sind oder Diff vorhanden + var differenzRechnungChecks = GetNewInvoices(newInvoices, invoicePeriod?.StartDate, invoicePeriod?.EndDate); + var resultList = ErstelleNeueRechnungen(differenzRechnungChecks); + + + return resultList; + } + + protected virtual List ErstelleNeueRechnungen(List differenzRechnungChecks) { - ServiceInvoiceDC diffRechnung = null; - //var alterBetrag = item.VorhandeneRechungen.Sum(i => i.ClaimSum ?? 0); - var letzteRg = item.VorhandeneRechungen.OrderByDescending(r => r.ServiceInvoiceOid).FirstOrDefault(); + var rechnungen = new List(); + foreach (var item in differenzRechnungChecks) + { + if (item.VorhandeneRechungen.Count == 0 || !item.VorhandeneRechungen.Any(r => item.NeueRechnung.InvoiceBase.CustomerOid == r.InvoiceBase.CustomerOid)) + { + item.NeueRechnung.InvoiceBase.NeuErstellen = true; + rechnungen.Add(item.NeueRechnung); + } + else + { + var diffRechnung = ErstelleDifferenzRechnung(item); + if (diffRechnung != null) + { + diffRechnung.InvoiceBase.NeuErstellen = false; + rechnungen.Add(diffRechnung); + } + } + } - letzteRg = item.VorhandeneRechungen.FirstOrDefault(r => item.NeueRechnung.InvoiceBase.CustomerOid == r.InvoiceBase.CustomerOid); - if (letzteRg != null) - { - if (item.NeueRechnung.ClaimSum == letzteRg.ClaimSum) - { - diffRechnung = item.NeueRechnung; - diffRechnung.InvoiceBase.NeuErstellen = false; - diffRechnung.InvoiceBase.Hinweise = String.Format("Rechnung wurde bereits erstellt"); - } - else - { - diffRechnung = new ServiceInvoiceDC(); - diffRechnung.OriginalZurDifferenz = item.NeueRechnung; - diffRechnung.InvoiceBase = new InvoiceBaseDC(); - CopyInvoiceBaseDC(item.NeueRechnung.InvoiceBase, diffRechnung); + return rechnungen; + } - ServiceInvoice counterInvoice = new ServiceInvoice(); - var serviceInvoice = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(letzteRg.InvoiceBase.InvoiceBaseOid.Value); + protected virtual ServiceInvoiceDC ErstelleDifferenzRechnung(DifferenzRechnungCheck item) + { + ServiceInvoiceDC diffRechnung = null; + //var alterBetrag = item.VorhandeneRechungen.Sum(i => i.ClaimSum ?? 0); + var letzteRg = item.VorhandeneRechungen.OrderByDescending(r => r.ServiceInvoiceOid).FirstOrDefault(); - CopyServiceInvoice(serviceInvoice, counterInvoice); - SetzeStornoInfos(counterInvoice); - SetzeRechnungspositionenServiceInvoice(diffRechnung, counterInvoice, item); + letzteRg = item.VorhandeneRechungen.FirstOrDefault(r => item.NeueRechnung.InvoiceBase.CustomerOid == r.InvoiceBase.CustomerOid); + if (letzteRg != null) + { + if (item.NeueRechnung.ClaimSum == letzteRg.ClaimSum) + { + diffRechnung = item.NeueRechnung; + diffRechnung.InvoiceBase.NeuErstellen = false; + diffRechnung.InvoiceBase.Hinweise = String.Format("Rechnung wurde bereits erstellt"); + } + else + { + diffRechnung = new ServiceInvoiceDC(); + diffRechnung.OriginalZurDifferenz = item.NeueRechnung; + diffRechnung.InvoiceBase = new InvoiceBaseDC(); + CopyInvoiceBaseDC(item.NeueRechnung.InvoiceBase, diffRechnung); + + ServiceInvoice counterInvoice = new ServiceInvoice(); + var serviceInvoice = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(letzteRg.InvoiceBase.InvoiceBaseOid.Value); + + CopyServiceInvoice(serviceInvoice, counterInvoice); + SetzeStornoInfos(counterInvoice); + SetzeRechnungspositionenServiceInvoice(diffRechnung, counterInvoice, item); diffRechnung.InvoiceBase.NeuErstellen = true; - diffRechnung.InvoiceBase.Hinweise = String.Format("Rechnungsdifferenz zu Rechnung {0} in Höhe von {1:c}", letzteRg.InvoiceBase.InvoiceNumber, letzteRg.InvoiceBase.TotalAmount.Value); - } - } + diffRechnung.InvoiceBase.Hinweise = String.Format("Rechnungsdifferenz zu Rechnung {0} in Höhe von {1:c}", letzteRg.InvoiceBase.InvoiceNumber, letzteRg.InvoiceBase.TotalAmount.Value); + } + } - return diffRechnung; + return diffRechnung; } protected virtual List GetNewInvoices(List invoices, DateTime? start, DateTime? end) @@ -142,63 +142,63 @@ namespace BeWo.Service.Plugins foreach (var si in invoices) { - var checkResult = new DifferenzRechnungCheck(); - result.Add(checkResult); - checkResult.NeueRechnung = si; - checkResult.VorhandeneRechungen = new List(); + var checkResult = new DifferenzRechnungCheck(); + result.Add(checkResult); + checkResult.NeueRechnung = si; + checkResult.VorhandeneRechungen = new List(); foreach (var i2 in existingInvoices.Where(i => i.Type == InvoiceType.Service)) { - if (si.InvoiceBase.SupportConceptCostBearerRelDc != null && si.InvoiceBase.SupportConceptCostBearerRelDc.CostBearer2SupportConceptOid == i2.CostBearer2SupportConceptOid) - { - var siAlt = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(i2.Oid.Value); - var siDCAlt = MapperFactory.ServiceInvoiceDC_ServiceInvoice.MapToNewDC(siAlt); - - checkResult.VorhandeneRechungen.Add(siDCAlt); - } - else // Sammelrechnung + if (si.InvoiceBase.SupportConceptCostBearerRelDc != null && si.InvoiceBase.SupportConceptCostBearerRelDc.CostBearer2SupportConceptOid == i2.CostBearer2SupportConceptOid) { - if (i2.SupportConceptOid == invoices[0].InvoiceBase.SupportConceptOid) - { - var siAlt = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(i2.Oid.Value); - var siDCAlt = MapperFactory.ServiceInvoiceDC_ServiceInvoice.MapToNewDC(siAlt); - if (siAlt.ServiceInvoicePeriodList != null && siAlt.ServiceInvoicePeriodList.Count > 0) - { - foreach (var i in invoices) - { - if (i.ServiceInvoicePeriods != null && i.ServiceInvoicePeriods.Count > 0) - { - foreach (var sip in siDCAlt.ServiceInvoicePeriods) - { - if (sip.Customer != null && i.ServiceInvoicePeriods.Any(s => s.Customer.CustomerOid == sip.Customer.CustomerOid)) - { - checkResult.VorhandeneRechungen.Add(siDCAlt); - break; - } - } - } - } - } - } - } - } + var siAlt = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(i2.Oid.Value); + var siDCAlt = MapperFactory.ServiceInvoiceDC_ServiceInvoice.MapToNewDC(siAlt); + + checkResult.VorhandeneRechungen.Add(siDCAlt); + } + else // Sammelrechnung + { + if (i2.SupportConceptOid == invoices[0].InvoiceBase.SupportConceptOid) + { + var siAlt = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(i2.Oid.Value); + var siDCAlt = MapperFactory.ServiceInvoiceDC_ServiceInvoice.MapToNewDC(siAlt); + if (siAlt.ServiceInvoicePeriodList != null && siAlt.ServiceInvoicePeriodList.Count > 0) + { + foreach (var i in invoices) + { + if (i.ServiceInvoicePeriods != null && i.ServiceInvoicePeriods.Count > 0) + { + foreach (var sip in siDCAlt.ServiceInvoicePeriods) + { + if (sip.Customer != null && i.ServiceInvoicePeriods.Any(s => s.Customer.CustomerOid == sip.Customer.CustomerOid)) + { + checkResult.VorhandeneRechungen.Add(siDCAlt); + break; + } + } + } + } + } + } + } + } } return result; } public virtual List UpdateServiceInvoices(List invoices) - { - //if (!Data.Security.UserRightHelper.LoggedInUserHasRight(UserRightType.AccountingTransactionView_Create)) - //{ - // throw new FaultException(new BeWoFault("Du kommst hier nicht rein!", BeWoFaultType.CustomWithoutDetails)); - //} - var originals = DAOFactory.GenericDAO.LoadByIDs(invoices.Select(i => i.ServiceInvoiceOid.Value)); - MapperFactory.ServiceInvoiceDC_ServiceInvoice.MergeWithEntitys(invoices, originals); - DAOFactory.GenericDAO.Update(originals); - return originals.Select(e => e.Version.Value).ToList(); - } + { + //if (!Data.Security.UserRightHelper.LoggedInUserHasRight(UserRightType.AccountingTransactionView_Create)) + //{ + // throw new FaultException(new BeWoFault("Du kommst hier nicht rein!", BeWoFaultType.CustomWithoutDetails)); + //} + var originals = DAOFactory.GenericDAO.LoadByIDs(invoices.Select(i => i.ServiceInvoiceOid.Value)); + MapperFactory.ServiceInvoiceDC_ServiceInvoice.MergeWithEntitys(invoices, originals); + DAOFactory.GenericDAO.Update(originals); + return originals.Select(e => e.Version.Value).ToList(); + } - public virtual List GetInvoiceBases(DateTime? startDate, DateTime? endDate) + public virtual List GetInvoiceBases(DateTime? startDate, DateTime? endDate) { DateTime? end = endDate; if (end.HasValue) @@ -210,398 +210,476 @@ namespace BeWo.Service.Plugins return MapperFactory.InvoiceBaseDC_InvoiceBase.MapToNewDCs(list); } - public virtual List GetInvoiceBases(DateTime? startDate, DateTime? endDate, bool filterByInvoiceDate) - { - DateTime? end = endDate; - if (end.HasValue) - { - end = end.Value.Date.AddDays(1).AddTicks(-1); - } - var list = DAOFactory.SearchDAO.GetInvoiceBases(startDate, end, filterByInvoiceDate); + public virtual List GetInvoiceBases(DateTime? startDate, DateTime? endDate, bool filterByInvoiceDate) + { + DateTime? end = endDate; + if (end.HasValue) + { + end = end.Value.Date.AddDays(1).AddTicks(-1); + } + var list = DAOFactory.SearchDAO.GetInvoiceBases(startDate, end, filterByInvoiceDate); - return MapperFactory.InvoiceBaseDC_InvoiceBase.MapToNewDCs(list); - } - - public virtual List GetInvoiceBases(DateTime? startDate, DateTime? endDate, long costBearerOid, String invoiceId) - { - DateTime? end = endDate; - if (end.HasValue) - { - end = end.Value.Date.AddDays(1).AddTicks(-1); - } - var list = DAOFactory.SearchDAO.GetInvoiceBases(startDate, end, costBearerOid, invoiceId); - - return MapperFactory.InvoiceBaseDC_InvoiceBase.MapToNewDCs(list); - } - - public virtual void DeactivateInvoiceBases(List invoices) - { - ServiceLogic.SetActivationType(invoices.ToDictionary(i => i.InvoiceBaseOid.Value, i => i.InvoiceBaseVersion.Value), ActivationTypeId.Deleted); + return MapperFactory.InvoiceBaseDC_InvoiceBase.MapToNewDCs(list); } - - public virtual void DeactivateServiceInvoices(List invoices) - { - ServiceLogic.SetActivationType(invoices.ToDictionary(i => i.ServiceInvoiceOid.Value, i => i.ServiceInvoiceVersion.Value), ActivationTypeId.Deleted); - ServiceLogic.SetActivationType(invoices.ToDictionary(i => i.InvoiceBase.InvoiceBaseOid.Value, i => i.InvoiceBase.InvoiceBaseVersion.Value), ActivationTypeId.Deleted); - } - public virtual void StorniereInvoiceBases(List invoices) - { + public virtual List GetInvoiceBases(DateTime? startDate, DateTime? endDate, long costBearerOid, String invoiceId) + { + DateTime? end = endDate; + if (end.HasValue) + { + end = end.Value.Date.AddDays(1).AddTicks(-1); + } + var list = DAOFactory.SearchDAO.GetInvoiceBases(startDate, end, costBearerOid, invoiceId); + + return MapperFactory.InvoiceBaseDC_InvoiceBase.MapToNewDCs(list); + } + + public virtual void DeactivateInvoiceBases(List invoices) + { + ServiceLogic.SetActivationType(invoices.ToDictionary(i => i.InvoiceBaseOid.Value, i => i.InvoiceBaseVersion.Value), ActivationTypeId.Deleted); + } + + public virtual void DeactivateServiceInvoices(List invoices) + { + ServiceLogic.SetActivationType(invoices.ToDictionary(i => i.ServiceInvoiceOid.Value, i => i.ServiceInvoiceVersion.Value), ActivationTypeId.Deleted); + ServiceLogic.SetActivationType(invoices.ToDictionary(i => i.InvoiceBase.InvoiceBaseOid.Value, i => i.InvoiceBase.InvoiceBaseVersion.Value), ActivationTypeId.Deleted); + } + + public virtual void StorniereInvoiceBases(List invoices) + { foreach (var item in invoices) { - if (item.Type == InvoiceType.Service) - { - ErstelleStornoRechnung(item); - } + if (item.Type == InvoiceType.Service) + { + ErstelleStornoRechnung(item); + } else if (item.Type == InvoiceType.Settlement) { - //ErstelleStornoSpitzabrechnung(item); + ErstelleStornoSpitzabrechnung(item); } - else - { - ErstelleStornoAllgemeineRechnung(item); - } - } - } + else + { + ErstelleStornoAllgemeineRechnung(item); + } + } + } - public virtual InvoiceBase ErstelleStornoAllgemeineRechnung(InvoiceBaseDC ibdc) - { - InvoiceBase newInvoice = new InvoiceBase(); + public virtual InvoiceBase ErstelleStornoAllgemeineRechnung(InvoiceBaseDC ibdc) + { + InvoiceBase newInvoice = new InvoiceBase(); - var oldInvoice = DAOFactory.GenericDAO.LoadByID(ibdc.InvoiceBaseOid.Value); + var oldInvoice = DAOFactory.GenericDAO.LoadByID(ibdc.InvoiceBaseOid.Value); - CopyInvoiceBase(oldInvoice, newInvoice); - SetzeStornoInfos(newInvoice); + CopyInvoiceBase(oldInvoice, newInvoice); + SetzeStornoInfos(newInvoice); - return newInvoice; - } - - public virtual ServiceInvoice ErstelleStornoRechnung(InvoiceBaseDC ibdc) - { - ServiceInvoice newInvoice = new ServiceInvoice(); - var serviceInvoice = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(ibdc.InvoiceBaseOid.Value); - - CopyServiceInvoice(serviceInvoice, newInvoice); - SetzeStornoInfos(newInvoice); - return newInvoice; - } - - //public virtual InvoiceBase ErstelleStornoSpitzabrechnung(InvoiceBaseDC ibdc) - //{ - // InvoiceBase newInvoice = new InvoiceBase(); - - // var oldInvoice = DAOFactory.GenericDAO.LoadByID(ibdc.InvoiceBaseOid.Value); - - // CopyInvoiceBase(oldInvoice, newInvoice); - // SetzeStornoInfos(newInvoice); - - // return newInvoice; - //} - - public virtual ServiceInvoice ErstelleStornoRechnung(ServiceInvoiceDC sidc) - { - ServiceInvoice newInvoice = new ServiceInvoice(); - - var serviceInvoice = DAOFactory.GenericDAO.LoadByID(sidc.ServiceInvoiceOid.Value); - - CopyServiceInvoice(serviceInvoice, newInvoice); - SetzeStornoInfos(newInvoice); - - return newInvoice; } - public virtual void SaveStornoRechnung(InvoiceBase originalInvoice, ServiceInvoice stornoInvoice) - { - DAOFactory.GenericDAO.Insert(stornoInvoice); - originalInvoice.StornoInvoiceBaseOid = stornoInvoice.Oid; - DAOFactory.GenericDAO.Update(originalInvoice); + public virtual ServiceInvoice ErstelleStornoRechnung(InvoiceBaseDC ibdc) + { + ServiceInvoice newInvoice = new ServiceInvoice(); + var serviceInvoice = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(ibdc.InvoiceBaseOid.Value); - } + CopyServiceInvoice(serviceInvoice, newInvoice); + SetzeStornoInfos(newInvoice); - public virtual void SetzeStornoInfos(InvoiceBase newInvoice) - { - foreach (var ii in newInvoice.InvoiceItems) - { - if (ii.AmountTotal.HasValue) - { - ii.AmountTotal *= -1; - } + return newInvoice; + } - if (ii.GrossAmountTotal.HasValue) - { - ii.GrossAmountTotal *= -1; - } - } - } + public virtual SettlementInvoice ErstelleStornoSpitzabrechnung(InvoiceBaseDC ibdc) + { + SettlementInvoice newInvoice = new SettlementInvoice(); + newInvoice.InvoiceBase = new InvoiceBase(); - public virtual void SetzeStornoInfos(ServiceInvoice newInvoice) - { - foreach (var sip in newInvoice.ServiceInvoicePeriodList) - { - sip.HoursNotBillableAbsence = 0; - sip.HoursNotBillableNotApproved = 0; - if (sip.Claim.HasValue) - { - sip.Claim *= -1; - } + var settlementInvoice = DAOFactory.SearchDAO.GetSettlementInvoiceByInvoiceBaseOid(ibdc.InvoiceBaseOid.Value); - foreach (var ii in sip.InvoiceItemList) - { - if (ii.AmountTotal.HasValue) - { - ii.AmountTotal *= -1; - } + CopySettlementInvoice(settlementInvoice, newInvoice); + SetzeStornoInfos(newInvoice); - if (ii.GrossAmountTotal.HasValue) - { - ii.GrossAmountTotal *= -1; + if (newInvoice.InvoiceBase.InvoiceItems.Count == 0 && newInvoice.Claim.HasValue) + { + newInvoice.InvoiceBase.InvoiceItems.Add(new InvoiceItem + { + AmountTotal = newInvoice.Claim, + ItemPeriodStart = newInvoice.InvoiceBase.AccountingPeriodStart, + ItemPeriodEnd = newInvoice.InvoiceBase.AccountingPeriodEnd, + ItemDescription = "Spitzabrechnung" + + }); + } + + return newInvoice; + } + + public virtual ServiceInvoice ErstelleStornoRechnung(ServiceInvoiceDC sidc) + { + ServiceInvoice newInvoice = new ServiceInvoice(); + + var serviceInvoice = DAOFactory.GenericDAO.LoadByID(sidc.ServiceInvoiceOid.Value); + + CopyServiceInvoice(serviceInvoice, newInvoice); + SetzeStornoInfos(newInvoice); + + return newInvoice; + } + + public virtual void SaveStornoRechnung(InvoiceBase originalInvoice, ServiceInvoice stornoInvoice) + { + DAOFactory.GenericDAO.Insert(stornoInvoice); + originalInvoice.StornoInvoiceBaseOid = stornoInvoice.Oid; + DAOFactory.GenericDAO.Update(originalInvoice); + + } + + public virtual void SetzeStornoInfos(InvoiceBase newInvoice) + { + foreach (var ii in newInvoice.InvoiceItems) + { + if (ii.AmountTotal.HasValue) + { + ii.AmountTotal *= -1; + } + + if (ii.GrossAmountTotal.HasValue) + { + ii.GrossAmountTotal *= -1; + } + } + } + + public virtual void SetzeStornoInfos(SettlementInvoice newInvoice) + { + if (newInvoice.Claim.HasValue) + newInvoice.Claim *= -1; + if (newInvoice.AmountBillableTotal.HasValue) + newInvoice.AmountBillableTotal *= -1; + if (newInvoice.AmountTotalAdvancedPaidWithNewHourlyRate.HasValue) + newInvoice.AmountTotalAdvancedPaidWithNewHourlyRate *= -1; + if (newInvoice.AmountTotalAdvancedPaidWithOldHourlyRate.HasValue) + newInvoice.AmountTotalAdvancedPaidWithOldHourlyRate *= -1; + if (newInvoice.AmountWithRateFactor.HasValue) + newInvoice.AmountWithRateFactor *= -1; + if (newInvoice.AmountRateFactor.HasValue) + newInvoice.AmountRateFactor *= -1; + + // FLS-Felder negieren, damit isDefaultSpitzabrechnung-Pfad negative Positionen berechnet + if (newInvoice.ApprovedFLSWithActualHourlyRate.HasValue) + newInvoice.ApprovedFLSWithActualHourlyRate *= -1; + if (newInvoice.ApprovedFLSWithOldHourlyRate.HasValue) + newInvoice.ApprovedFLSWithOldHourlyRate *= -1; + + // XMLData aktualisieren: Claim (wird vom Mapper als TotalAmount verwendet) und + // ApprovedFLSWithHourlyRate3 (nur bei DifferentHourlyRateCount == 3 vorhanden) negieren + if (newInvoice.InvoiceBase != null && !string.IsNullOrEmpty(newInvoice.InvoiceBase.XMLData)) + { + var xmlDC = BS.Shared.Core.Utils.XMLDeserializeFromString(newInvoice.InvoiceBase.XMLData); + if (xmlDC != null) + { + bool xmlChanged = false; + if (xmlDC.Claim != 0) + { + xmlDC.Claim *= -1; + xmlChanged = true; } - } - } - } + if (xmlDC.ApprovedFLSWithHourlyRate3 != 0) + { + xmlDC.ApprovedFLSWithHourlyRate3 *= -1; + xmlChanged = true; + } + if (xmlChanged) + newInvoice.InvoiceBase.XMLData = BS.Shared.Core.Utils.XMLSerializeToString(xmlDC); + } + } - public void CopyServiceInvoice(ServiceInvoice existingInvoice, ServiceInvoice copyInvoice) - { - copyInvoice.AmountAdvancePayments = existingInvoice.AmountAdvancePayments; - copyInvoice.AmountEquityContribution = existingInvoice.AmountEquityContribution; - copyInvoice.ServiceUnitOid = existingInvoice.ServiceUnitOid; - - CopyInvoiceBase(existingInvoice.InvoiceBase, copyInvoice.InvoiceBase); - - foreach (var sip in existingInvoice.ServiceInvoicePeriodList) - { - var copySip = new ServiceInvoicePeriod(); - copyInvoice.ServiceInvoicePeriodList.Add(copySip); - - CopyServiceInvoicePeriod(sip, copySip); - } + SetzeStornoInfos(newInvoice.InvoiceBase); } - //private void CopySettlementInvoice(SettlementInvoice existingInvoice, SettlementInvoice copyInvoice) - // { - - // CopyInvoiceBase(existingInvoice.InvoiceBase, copyInvoice.InvoiceBase); + public virtual void SetzeStornoInfos(ServiceInvoice newInvoice) + { + foreach (var sip in newInvoice.ServiceInvoicePeriodList) + { + sip.HoursNotBillableAbsence = 0; + sip.HoursNotBillableNotApproved = 0; + if (sip.Claim.HasValue) + { + sip.Claim *= -1; + } - - // } + foreach (var ii in sip.InvoiceItemList) + { + if (ii.AmountTotal.HasValue) + { + ii.AmountTotal *= -1; + } - public void CopyInvoiceBase(InvoiceBase existing, InvoiceBase copy) - { - copy.AccountingPeriodEnd = existing.AccountingPeriodEnd; - copy.AccountingPeriodStart = existing.AccountingPeriodStart; - copy.CostBearer2SupportConcept = existing.CostBearer2SupportConcept; - copy.CreatorFirstName = existing.CreatorFirstName; - copy.CreatorLastName = existing.CreatorLastName; - copy.CustomerReferenceNumber = existing.CustomerReferenceNumber; - copy.DueDate = existing.DueDate; - copy.DunningLetterCount = existing.DunningLetterCount; - copy.InvoiceDate = existing.InvoiceDate; - copy.InvoiceId = existing.InvoiceId; - copy.InvoiceNumber = existing.InvoiceNumber; - copy.InvoiceTitle = existing.InvoiceTitle; - copy.InvoiceTypeText = existing.InvoiceTypeText; - copy.IsPaid = existing.IsPaid; - copy.IsPrinted = existing.IsPrinted; - copy.RecipientCostBearerOid = existing.RecipientCostBearerOid; - copy.RecipientCustomerOid = existing.RecipientCustomerOid; - copy.RecipientDivision = existing.RecipientDivision; - copy.RecipientOrganisation = existing.RecipientOrganisation; - copy.RecipientOrganisationOid = existing.RecipientOrganisationOid; - copy.RecipientPersonFirstName = existing.RecipientPersonFirstName; - copy.RecipientPersonLastName = existing.RecipientPersonLastName; - copy.RecipientPersonOid = existing.RecipientPersonOid; - copy.SenderDivision = existing.SenderDivision; - copy.SenderFirstName = existing.SenderFirstName; - copy.SenderLastName = existing.SenderLastName; - copy.SenderOrganisation = existing.SenderOrganisation; - copy.SupportConceptOid = existing.SupportConceptOid; - copy.Type = existing.Type; - copy.XMLData = existing.XMLData; + if (ii.GrossAmountTotal.HasValue) + { + ii.GrossAmountTotal *= -1; + } + } + } + } - foreach (var ii in existing.InvoiceItems) - { - var copyItem = new InvoiceItem(); - copy.InvoiceItems.Add(copyItem); + public void CopyServiceInvoice(ServiceInvoice existingInvoice, ServiceInvoice copyInvoice) + { + copyInvoice.AmountAdvancePayments = existingInvoice.AmountAdvancePayments; + copyInvoice.AmountEquityContribution = existingInvoice.AmountEquityContribution; + copyInvoice.ServiceUnitOid = existingInvoice.ServiceUnitOid; - CopyInvoiceItem(ii, copyItem); - - } + CopyInvoiceBase(existingInvoice.InvoiceBase, copyInvoice.InvoiceBase); - if (existing.RecipientAddress != null) - { - copy.RecipientAddress = CreateCopyAddress(existing.RecipientAddress); - } + foreach (var sip in existingInvoice.ServiceInvoicePeriodList) + { + var copySip = new ServiceInvoicePeriod(); + copyInvoice.ServiceInvoicePeriodList.Add(copySip); - if (existing.RecipientContacts != null) - { + CopyServiceInvoicePeriod(sip, copySip); + } + } + + public void CopySettlementInvoice(SettlementInvoice existing, SettlementInvoice copy) + { + copy.AmountAdvancedPayments = existing.AmountAdvancedPayments; + copy.AmountBillableTotal = existing.AmountBillableTotal; + copy.AmountRateFactor = existing.AmountRateFactor; + copy.AmountTotalAdvancedPaidWithNewHourlyRate = existing.AmountTotalAdvancedPaidWithNewHourlyRate; + copy.AmountTotalAdvancedPaidWithOldHourlyRate = existing.AmountTotalAdvancedPaidWithOldHourlyRate; + copy.AmountWithRateFactor = existing.AmountWithRateFactor; + copy.ApprovalNoticeDate = existing.ApprovalNoticeDate; + copy.ApprovedFLS = existing.ApprovedFLS; + copy.ApprovedFLSWithActualHourlyRate = existing.ApprovedFLSWithActualHourlyRate; + copy.ApprovedFLSWithOldHourlyRate = existing.ApprovedFLSWithOldHourlyRate; + copy.Claim = existing.Claim; + copy.ErrorNotice = existing.ErrorNotice; + copy.HourlyRateNew = existing.HourlyRateNew; + copy.HourlyRateNewStartDate = existing.HourlyRateNewStartDate; + copy.HourlyRateOld = existing.HourlyRateOld; + copy.HourlyRateOldEndDate = existing.HourlyRateOldEndDate; + copy.RecordedBillableFLSBrutto = existing.RecordedBillableFLSBrutto; + copy.RecordedBillableFLSNetto = existing.RecordedBillableFLSNetto; + copy.RecordedBillableFLSNotBillableCustomerAbsent = existing.RecordedBillableFLSNotBillableCustomerAbsent; + copy.RecordedBillableFLSNotBillableOutOfApprovedSpan = existing.RecordedBillableFLSNotBillableOutOfApprovedSpan; + + CopyInvoiceBase(existing.InvoiceBase, copy.InvoiceBase); + } + + public void CopyInvoiceBase(InvoiceBase existing, InvoiceBase copy) + { + copy.AccountingPeriodEnd = existing.AccountingPeriodEnd; + copy.AccountingPeriodStart = existing.AccountingPeriodStart; + copy.CostBearer2SupportConcept = existing.CostBearer2SupportConcept; + copy.CreatorFirstName = existing.CreatorFirstName; + copy.CreatorLastName = existing.CreatorLastName; + copy.CustomerReferenceNumber = existing.CustomerReferenceNumber; + copy.DueDate = existing.DueDate; + copy.DunningLetterCount = existing.DunningLetterCount; + copy.InvoiceDate = existing.InvoiceDate; + copy.InvoiceId = existing.InvoiceId; + copy.InvoiceNumber = existing.InvoiceNumber; + copy.InvoiceTitle = existing.InvoiceTitle; + copy.InvoiceTypeText = existing.InvoiceTypeText; + copy.IsPaid = existing.IsPaid; + copy.IsPrinted = existing.IsPrinted; + copy.RecipientCostBearerOid = existing.RecipientCostBearerOid; + copy.RecipientCustomerOid = existing.RecipientCustomerOid; + copy.RecipientDivision = existing.RecipientDivision; + copy.RecipientOrganisation = existing.RecipientOrganisation; + copy.RecipientOrganisationOid = existing.RecipientOrganisationOid; + copy.RecipientPersonFirstName = existing.RecipientPersonFirstName; + copy.RecipientPersonLastName = existing.RecipientPersonLastName; + copy.RecipientPersonOid = existing.RecipientPersonOid; + copy.SenderDivision = existing.SenderDivision; + copy.SenderFirstName = existing.SenderFirstName; + copy.SenderLastName = existing.SenderLastName; + copy.SenderOrganisation = existing.SenderOrganisation; + copy.SupportConceptOid = existing.SupportConceptOid; + copy.Type = existing.Type; + copy.XMLData = existing.XMLData; + + foreach (var ii in existing.InvoiceItems) + { + var copyItem = new InvoiceItem(); + copy.InvoiceItems.Add(copyItem); + + CopyInvoiceItem(ii, copyItem); + + } + + if (existing.RecipientAddress != null) + { + copy.RecipientAddress = CreateCopyAddress(existing.RecipientAddress); + } + + if (existing.RecipientContacts != null) + { copy.RecipientContacts = new List(); - foreach (var existingContact in existing.RecipientContacts) - { - copy.RecipientContacts.Add(CreateCopyContact(existingContact)); - } - } + foreach (var existingContact in existing.RecipientContacts) + { + copy.RecipientContacts.Add(CreateCopyContact(existingContact)); + } + } - if (existing.SenderAddress != null) - { - copy.SenderAddress = existing.SenderAddress; - } + if (existing.SenderAddress != null) + { + copy.SenderAddress = existing.SenderAddress; + } + + if (existing.SenderContacts != null) + { + copy.SenderContacts = new List(); + foreach (var existingContact in existing.SenderContacts) + { + copy.SenderContacts.Add(CreateCopyContact(existingContact)); + } + } - if (existing.SenderContacts != null) - { - copy.SenderContacts = new List(); - foreach (var existingContact in existing.SenderContacts) - { - copy.SenderContacts.Add(CreateCopyContact(existingContact)); - } - } - } - public void CopyInvoiceBaseDC(InvoiceBaseDC orgRechnung, ServiceInvoiceDC diffRechnung) - { - diffRechnung.InvoiceBase.DiffErstellen = true; - diffRechnung.InvoiceBase.AccountingPeriodStart = orgRechnung.AccountingPeriodStart; - diffRechnung.InvoiceBase.AccountingPeriodEnd = orgRechnung.AccountingPeriodEnd; - diffRechnung.InvoiceBase.CustomerLastName = orgRechnung.CustomerLastName; - diffRechnung.InvoiceBase.CustomerFirstName = orgRechnung.CustomerFirstName; - diffRechnung.InvoiceBase.CustomerReferenceNumber = orgRechnung.CustomerReferenceNumber; - diffRechnung.InvoiceBase.InvoiceBaseOid = orgRechnung.InvoiceBaseOid; - diffRechnung.InvoiceBase.InvoiceDate = orgRechnung.InvoiceDate; - diffRechnung.InvoiceBase.InvoiceId = orgRechnung.InvoiceId; - diffRechnung.InvoiceBase.InvoiceNumber = orgRechnung.InvoiceNumber; - diffRechnung.InvoiceBase.InvoiceTitle = orgRechnung.InvoiceTitle; - diffRechnung.InvoiceBase.InvoiceTypeText = orgRechnung.InvoiceTypeText; - diffRechnung.InvoiceBase.RecipientAddressLine1 = orgRechnung.RecipientAddressLine1; - diffRechnung.InvoiceBase.RecipientAddressOid = orgRechnung.RecipientAddressOid; - diffRechnung.InvoiceBase.RecipientAddressVersion = orgRechnung.RecipientAddressVersion; - diffRechnung.InvoiceBase.RecipientContactInformations = orgRechnung.RecipientContactInformations; - diffRechnung.InvoiceBase.RecipientCostBearerOid = orgRechnung.RecipientCostBearerOid; - diffRechnung.InvoiceBase.RecipientCustomerOid = orgRechnung.RecipientCustomerOid; - diffRechnung.InvoiceBase.RecipientDivision = orgRechnung.RecipientDivision; - diffRechnung.InvoiceBase.RecipientOrganisation = orgRechnung.RecipientOrganisation; - diffRechnung.InvoiceBase.RecipientOrganisationOid = orgRechnung.RecipientOrganisationOid; - diffRechnung.InvoiceBase.RecipientPersonFirstName = orgRechnung.RecipientPersonFirstName; - diffRechnung.InvoiceBase.RecipientPersonLastName = orgRechnung.RecipientPersonLastName; - diffRechnung.InvoiceBase.RecipientPersonOid = orgRechnung.RecipientPersonOid; - diffRechnung.InvoiceBase.RecipientPostCode = orgRechnung.RecipientPostCode; - diffRechnung.InvoiceBase.RecipientSalutationAddressField = orgRechnung.RecipientSalutationAddressField; - diffRechnung.InvoiceBase.RecipientStreet = orgRechnung.RecipientStreet; - diffRechnung.InvoiceBase.RecipientTown = orgRechnung.RecipientTown; - diffRechnung.InvoiceBase.SenderAddressOid = orgRechnung.SenderAddressOid; - diffRechnung.InvoiceBase.SenderAddressVersion = orgRechnung.SenderAddressVersion; - diffRechnung.InvoiceBase.SenderContactInformations = orgRechnung.SenderContactInformations; - diffRechnung.InvoiceBase.SenderDivision = orgRechnung.SenderDivision; - diffRechnung.InvoiceBase.SenderFirstName = orgRechnung.SenderFirstName; - diffRechnung.InvoiceBase.SenderLastName = orgRechnung.SenderLastName; - diffRechnung.InvoiceBase.SenderOrganisation = orgRechnung.SenderOrganisation; - diffRechnung.InvoiceBase.SenderPostCode = orgRechnung.SenderPostCode; - diffRechnung.InvoiceBase.SenderStreet = orgRechnung.SenderStreet; - diffRechnung.InvoiceBase.SenderTown = orgRechnung.SenderTown; - diffRechnung.InvoiceBase.SupportConceptCostBearerRelDc = orgRechnung.SupportConceptCostBearerRelDc; - diffRechnung.InvoiceBase.SupportConceptOid = orgRechnung.SupportConceptOid; - diffRechnung.InvoiceBase.TotalAmount = orgRechnung.TotalAmount; - diffRechnung.InvoiceBase.Type = orgRechnung.Type; - } + public void CopyInvoiceBaseDC(InvoiceBaseDC orgRechnung, ServiceInvoiceDC diffRechnung) + { + diffRechnung.InvoiceBase.DiffErstellen = true; + diffRechnung.InvoiceBase.AccountingPeriodStart = orgRechnung.AccountingPeriodStart; + diffRechnung.InvoiceBase.AccountingPeriodEnd = orgRechnung.AccountingPeriodEnd; + diffRechnung.InvoiceBase.CustomerLastName = orgRechnung.CustomerLastName; + diffRechnung.InvoiceBase.CustomerFirstName = orgRechnung.CustomerFirstName; + diffRechnung.InvoiceBase.CustomerReferenceNumber = orgRechnung.CustomerReferenceNumber; + diffRechnung.InvoiceBase.InvoiceBaseOid = orgRechnung.InvoiceBaseOid; + diffRechnung.InvoiceBase.InvoiceDate = orgRechnung.InvoiceDate; + diffRechnung.InvoiceBase.InvoiceId = orgRechnung.InvoiceId; + diffRechnung.InvoiceBase.InvoiceNumber = orgRechnung.InvoiceNumber; + diffRechnung.InvoiceBase.InvoiceTitle = orgRechnung.InvoiceTitle; + diffRechnung.InvoiceBase.InvoiceTypeText = orgRechnung.InvoiceTypeText; + diffRechnung.InvoiceBase.RecipientAddressLine1 = orgRechnung.RecipientAddressLine1; + diffRechnung.InvoiceBase.RecipientAddressOid = orgRechnung.RecipientAddressOid; + diffRechnung.InvoiceBase.RecipientAddressVersion = orgRechnung.RecipientAddressVersion; + diffRechnung.InvoiceBase.RecipientContactInformations = orgRechnung.RecipientContactInformations; + diffRechnung.InvoiceBase.RecipientCostBearerOid = orgRechnung.RecipientCostBearerOid; + diffRechnung.InvoiceBase.RecipientCustomerOid = orgRechnung.RecipientCustomerOid; + diffRechnung.InvoiceBase.RecipientDivision = orgRechnung.RecipientDivision; + diffRechnung.InvoiceBase.RecipientOrganisation = orgRechnung.RecipientOrganisation; + diffRechnung.InvoiceBase.RecipientOrganisationOid = orgRechnung.RecipientOrganisationOid; + diffRechnung.InvoiceBase.RecipientPersonFirstName = orgRechnung.RecipientPersonFirstName; + diffRechnung.InvoiceBase.RecipientPersonLastName = orgRechnung.RecipientPersonLastName; + diffRechnung.InvoiceBase.RecipientPersonOid = orgRechnung.RecipientPersonOid; + diffRechnung.InvoiceBase.RecipientPostCode = orgRechnung.RecipientPostCode; + diffRechnung.InvoiceBase.RecipientSalutationAddressField = orgRechnung.RecipientSalutationAddressField; + diffRechnung.InvoiceBase.RecipientStreet = orgRechnung.RecipientStreet; + diffRechnung.InvoiceBase.RecipientTown = orgRechnung.RecipientTown; + diffRechnung.InvoiceBase.SenderAddressOid = orgRechnung.SenderAddressOid; + diffRechnung.InvoiceBase.SenderAddressVersion = orgRechnung.SenderAddressVersion; + diffRechnung.InvoiceBase.SenderContactInformations = orgRechnung.SenderContactInformations; + diffRechnung.InvoiceBase.SenderDivision = orgRechnung.SenderDivision; + diffRechnung.InvoiceBase.SenderFirstName = orgRechnung.SenderFirstName; + diffRechnung.InvoiceBase.SenderLastName = orgRechnung.SenderLastName; + diffRechnung.InvoiceBase.SenderOrganisation = orgRechnung.SenderOrganisation; + diffRechnung.InvoiceBase.SenderPostCode = orgRechnung.SenderPostCode; + diffRechnung.InvoiceBase.SenderStreet = orgRechnung.SenderStreet; + diffRechnung.InvoiceBase.SenderTown = orgRechnung.SenderTown; + diffRechnung.InvoiceBase.SupportConceptCostBearerRelDc = orgRechnung.SupportConceptCostBearerRelDc; + diffRechnung.InvoiceBase.SupportConceptOid = orgRechnung.SupportConceptOid; + diffRechnung.InvoiceBase.TotalAmount = orgRechnung.TotalAmount; + diffRechnung.InvoiceBase.Type = orgRechnung.Type; + } - public Contact CreateCopyContact(Contact existingContact) - { - Contact newContact = new Contact(); - newContact.Value = existingContact.Value; - newContact.Type = existingContact.Type; + public Contact CreateCopyContact(Contact existingContact) + { + Contact newContact = new Contact(); + newContact.Value = existingContact.Value; + newContact.Type = existingContact.Type; - return newContact; - } + return newContact; + } - public Address CreateCopyAddress(Address address) - { - Address newAddress = new Address(); - newAddress.AddressLine1 = address.AddressLine1; - newAddress.AddressLine2 = address.AddressLine2; - newAddress.Country = address.Country; - newAddress.PostalCode = address.PostalCode; - newAddress.State = address.State; - newAddress.Street = address.Street; - newAddress.Town = address.Town; - - return newAddress; - } + public Address CreateCopyAddress(Address address) + { + Address newAddress = new Address(); + newAddress.AddressLine1 = address.AddressLine1; + newAddress.AddressLine2 = address.AddressLine2; + newAddress.Country = address.Country; + newAddress.PostalCode = address.PostalCode; + newAddress.State = address.State; + newAddress.Street = address.Street; + newAddress.Town = address.Town; - public void CopyServiceInvoicePeriod(ServiceInvoicePeriod existingSip, ServiceInvoicePeriod copySip) - { - copySip.AccountingInterval = existingSip.AccountingInterval; - copySip.ApprovedAmountDefaultHourlyRate = existingSip.ApprovedAmountDefaultHourlyRate; - copySip.ApprovedBE = existingSip.ApprovedBE; - copySip.ApprovedFixedAmount = existingSip.ApprovedFixedAmount; - copySip.ApprovedHours = existingSip.ApprovedHours; - copySip.Claim = existingSip.Claim; - copySip.End = existingSip.End; - copySip.HoursNotBillableAbsence = existingSip.HoursNotBillableAbsence; - copySip.HoursNotBillableNotApproved = existingSip.HoursNotBillableNotApproved; - copySip.ServiceUnitName = existingSip.ServiceUnitName; - copySip.Start = existingSip.Start; - copySip.Notice = existingSip.Notice; + return newAddress; + } + + public void CopyServiceInvoicePeriod(ServiceInvoicePeriod existingSip, ServiceInvoicePeriod copySip) + { + copySip.AccountingInterval = existingSip.AccountingInterval; + copySip.ApprovedAmountDefaultHourlyRate = existingSip.ApprovedAmountDefaultHourlyRate; + copySip.ApprovedBE = existingSip.ApprovedBE; + copySip.ApprovedFixedAmount = existingSip.ApprovedFixedAmount; + copySip.ApprovedHours = existingSip.ApprovedHours; + copySip.Claim = existingSip.Claim; + copySip.End = existingSip.End; + copySip.HoursNotBillableAbsence = existingSip.HoursNotBillableAbsence; + copySip.HoursNotBillableNotApproved = existingSip.HoursNotBillableNotApproved; + copySip.ServiceUnitName = existingSip.ServiceUnitName; + copySip.Start = existingSip.Start; + copySip.Notice = existingSip.Notice; copySip.Customer = existingSip.Customer; copySip.SupportConceptApprovalPeriod = existingSip.SupportConceptApprovalPeriod; - foreach (var ii in existingSip.InvoiceItemList) - { - var copyItem = new InvoiceItem(); - copySip.InvoiceItemList.Add(copyItem); + foreach (var ii in existingSip.InvoiceItemList) + { + var copyItem = new InvoiceItem(); + copySip.InvoiceItemList.Add(copyItem); + + CopyInvoiceItem(ii, copyItem); + } - CopyInvoiceItem(ii, copyItem); - } - } - public void CopyInvoiceItem(InvoiceItem existingItem, InvoiceItem copyItem) - { - copyItem.AccountingInterval = existingItem.AccountingInterval; - copyItem.AmountPerUnit = existingItem.AmountPerUnit; - copyItem.AmountTotal = existingItem.AmountTotal; - copyItem.ApprovalUnit = existingItem.AccountingInterval; - copyItem.ApprovedPerUnit = existingItem.ApprovedPerUnit; - copyItem.GrossAmountTotal = existingItem.GrossAmountTotal; - copyItem.ItemDescription = existingItem.ItemDescription; - copyItem.ItemPeriodEnd = existingItem.ItemPeriodEnd; - copyItem.ItemPeriodStart = existingItem.ItemPeriodStart; - copyItem.MaxApprovedAmount = existingItem.MaxApprovedAmount; - copyItem.MaxApprovedUnitCount = existingItem.MaxApprovedUnitCount; - copyItem.RateFactor = existingItem.RateFactor; - copyItem.ReceivedAmount = existingItem.ReceivedAmount; - copyItem.SupportConceptApprovalPeriodOid = existingItem.SupportConceptApprovalPeriodOid; - copyItem.UnitCount = existingItem.UnitCount; - copyItem.UnitDescription = existingItem.UnitDescription; - copyItem.Notice = existingItem.Notice; + public void CopyInvoiceItem(InvoiceItem existingItem, InvoiceItem copyItem) + { + copyItem.AccountingInterval = existingItem.AccountingInterval; + copyItem.AmountPerUnit = existingItem.AmountPerUnit; + copyItem.AmountTotal = existingItem.AmountTotal; + copyItem.ApprovalUnit = existingItem.AccountingInterval; + copyItem.ApprovedPerUnit = existingItem.ApprovedPerUnit; + copyItem.GrossAmountTotal = existingItem.GrossAmountTotal; + copyItem.ItemDescription = existingItem.ItemDescription; + copyItem.ItemPeriodEnd = existingItem.ItemPeriodEnd; + copyItem.ItemPeriodStart = existingItem.ItemPeriodStart; + copyItem.MaxApprovedAmount = existingItem.MaxApprovedAmount; + copyItem.MaxApprovedUnitCount = existingItem.MaxApprovedUnitCount; + copyItem.RateFactor = existingItem.RateFactor; + copyItem.ReceivedAmount = existingItem.ReceivedAmount; + copyItem.SupportConceptApprovalPeriodOid = existingItem.SupportConceptApprovalPeriodOid; + copyItem.UnitCount = existingItem.UnitCount; + copyItem.UnitDescription = existingItem.UnitDescription; + copyItem.Notice = existingItem.Notice; copyItem.ServiceRecord = existingItem.ServiceRecord; } - public virtual void SetzeRechnungspositionenServiceInvoice(ServiceInvoiceDC diffRechnung, ServiceInvoice counterInvoice, DifferenzRechnungCheck item) - { - var siDCAlt = MapperFactory.ServiceInvoiceDC_ServiceInvoice.MapToNewDC(counterInvoice); - if (siDCAlt.ServiceInvoicePeriods != null && siDCAlt.ServiceInvoicePeriods.Count > 0) - { - diffRechnung.ServiceInvoicePeriods = siDCAlt.ServiceInvoicePeriods; - } + public virtual void SetzeRechnungspositionenServiceInvoice(ServiceInvoiceDC diffRechnung, ServiceInvoice counterInvoice, DifferenzRechnungCheck item) + { + var siDCAlt = MapperFactory.ServiceInvoiceDC_ServiceInvoice.MapToNewDC(counterInvoice); + if (siDCAlt.ServiceInvoicePeriods != null && siDCAlt.ServiceInvoicePeriods.Count > 0) + { + diffRechnung.ServiceInvoicePeriods = siDCAlt.ServiceInvoicePeriods; + } - if (item.NeueRechnung.ServiceInvoicePeriods != null && item.NeueRechnung.ServiceInvoicePeriods.Count > 0) - { - if (diffRechnung.ServiceInvoicePeriods == null) - { - diffRechnung.ServiceInvoicePeriods = item.NeueRechnung.ServiceInvoicePeriods; - } - else - { - foreach (var NewSip in item.NeueRechnung.ServiceInvoicePeriods) - { - if (NewSip.InvoiceItems != null && NewSip.InvoiceItems.Count > 0) - { - if (NewSip.Customer != null && diffRechnung.ServiceInvoicePeriods.Any(s => s.Customer.CustomerOid == NewSip.Customer.CustomerOid) && - NewSip.SupportConceptApprovalPeriod != null && NewSip.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.HasValue - && diffRechnung.ServiceInvoicePeriods.Any(s => s.SupportConceptApprovalPeriod != null && s.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.HasValue - && s.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value == NewSip.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value)) - { - var ip = diffRechnung.ServiceInvoicePeriods.Where(s => s.SupportConceptApprovalPeriod != null && s.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value == NewSip.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value).First(); + if (item.NeueRechnung.ServiceInvoicePeriods != null && item.NeueRechnung.ServiceInvoicePeriods.Count > 0) + { + if (diffRechnung.ServiceInvoicePeriods == null) + { + diffRechnung.ServiceInvoicePeriods = item.NeueRechnung.ServiceInvoicePeriods; + } + else + { + foreach (var NewSip in item.NeueRechnung.ServiceInvoicePeriods) + { + if (NewSip.InvoiceItems != null && NewSip.InvoiceItems.Count > 0) + { + if (NewSip.Customer != null && diffRechnung.ServiceInvoicePeriods.Any(s => s.Customer.CustomerOid == NewSip.Customer.CustomerOid) && + NewSip.SupportConceptApprovalPeriod != null && NewSip.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.HasValue + && diffRechnung.ServiceInvoicePeriods.Any(s => s.SupportConceptApprovalPeriod != null && s.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.HasValue + && s.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value == NewSip.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value)) + { + var ip = diffRechnung.ServiceInvoicePeriods.Where(s => s.SupportConceptApprovalPeriod != null && s.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value == NewSip.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value).First(); if (ip.InvoiceItems != null && ip.InvoiceItems.Count > 0) { ip.Claim += NewSip.Claim; @@ -623,48 +701,159 @@ namespace BeWo.Service.Plugins } } else - { - diffRechnung.ServiceInvoicePeriods.Add(NewSip); - } - } - } - } - } - } - - public virtual Settlement2DC ErstelleDifferenzSpitzabrechnung(Settlement2DC neueRechnung, Settlement2DC letzteRechnung) - { - var diff = neueRechnung.Claim - letzteRechnung.Claim; - var ii = new InvoiceItemDC(); - - neueRechnung.Claim = diff; - neueRechnung.InvoiceItems = new List(); - neueRechnung.InvoiceItems.Add(ii); - - return neueRechnung; + { + diffRechnung.ServiceInvoicePeriods.Add(NewSip); + } + } + } + } + } } - public virtual AddressInformation GetAddressInformation(long? customer_oid = null) - { - var user = UserRightHelper.GetLoggedInUser().Employee; - var mandator = AppSettings.GetMandatorEntity(); + public virtual Settlement2DC ErstelleDifferenzSpitzabrechnung(Settlement2DC neueRechnung, Settlement2DC letzteRechnung) + { + neueRechnung.Claim = neueRechnung.Claim - letzteRechnung.Claim; - return new AddressInformation() - { - IKLeistungserbringer = mandator.IKLeistungserbringer, - Fax = user.Person.Contacts.FirstOrDefault(x => x.Type == ContactType.business_Fax)?.Value.ToNullIfEmpty(), - Mail = user.Person.Contacts.FirstOrDefault(x => x.Type == ContactType.business_Mail)?.Value.ToNullIfEmpty(), - Phone = user.Person.Contacts.FirstOrDefault(x => x.Type == ContactType.business_Phone)?.Value.ToNullIfEmpty(), - OrganisationName = mandator.Name, - PostCode = mandator.PostalCode, - Street = mandator.Street, - Town = mandator.Town, - Website = mandator.Website - }; - } - } + var differenzItems = new List(); - public class DifferenzRechnungCheck + // Exaktieselbe Erkennung wie SettlementReport.cs für isDefaultSpitzabrechnung: + // genau 1 Item mit Bezeichnung "Spitzabrechnung"/"Spitzabrechung", GrossAmountTotal==null, RateFactor==null + bool letzteIstOldWay = letzteRechnung.InvoiceItems == null + || (letzteRechnung.InvoiceItems.Count == 1 && (letzteRechnung.InvoiceItems[0].ItemDescription == "Spitzabrechnung" || letzteRechnung.InvoiceItems[0].ItemDescription == "Spitzabrechung") + && letzteRechnung.InvoiceItems[0].GrossAmountTotal == null && letzteRechnung.InvoiceItems[0].RateFactor == null); + + if (letzteIstOldWay) + { + // Storno der alten Gesamtsumme als einzelne explizite Position + differenzItems.Add(new InvoiceItemDC + { + AmountTotal = -(letzteRechnung.Claim ?? 0), + GrossAmountTotal = -(letzteRechnung.Claim ?? 0), + ItemPeriodStart = letzteRechnung.AccountingPeriodStart, + ItemPeriodEnd = letzteRechnung.AccountingPeriodEnd, + ItemDescription = "Storno" + }); + + // Neue Rechnung als Old-Way mit expliziten Items (isDefaultSpitzabrechnung = false im Report) + bool neueHatExpliziteItems = neueRechnung.InvoiceItems != null && neueRechnung.InvoiceItems.Any(ii => ii.GrossAmountTotal != null); + if (neueHatExpliziteItems) + differenzItems.AddRange(neueRechnung.InvoiceItems); + else + differenzItems.AddRange(ErstelleExpliziteSpitzabrechnungsItems(neueRechnung)); + + // Claim aus den tatsächlichen Items berechnen (Storno + neue Items), + // da bei old-way Rechnungen neueRechnung.Claim null sein kann + neueRechnung.Claim = differenzItems.Sum(i => i.AmountTotal ?? 0m); + } + else + { + // Normalfall: Items der alten Rechnung negieren (SettlementReport2 → SettlementReport2) + if (letzteRechnung.InvoiceItems != null) + { + foreach (var item in letzteRechnung.InvoiceItems) + { + differenzItems.Add(new InvoiceItemDC + { + AmountTotal = -(item.AmountTotal ?? 0), + GrossAmountTotal = item.GrossAmountTotal.HasValue ? -item.GrossAmountTotal : null, + AmountPerUnit = item.AmountPerUnit, + ApprovedPerUnit = item.ApprovedPerUnit, + ItemPeriodStart = item.ItemPeriodStart, + ItemPeriodEnd = item.ItemPeriodEnd, + UnitDescription = item.UnitDescription, + UnitCount = item.UnitCount, + RateFactor = item.RateFactor, + ItemDescription = item.ItemDescription + " (Storno)" + }); + } + } + + if (neueRechnung.InvoiceItems != null) + differenzItems.AddRange(neueRechnung.InvoiceItems); + } + + neueRechnung.InvoiceItems = differenzItems; + neueRechnung.Notice = string.Format("Differenzrechnung zu Rechnung {0} vom {1:dd.MM.yyyy}", letzteRechnung.InvoiceNumber, letzteRechnung.InvoiceDate); + + return neueRechnung; + } + + private IList ErstelleExpliziteSpitzabrechnungsItems(Settlement2DC dc) + { + decimal fact = 1; + if (dc.RateFactor != null && dc.RateFactor.Value > 0) + { + fact = (100 + dc.RateFactor.Value) / 100; + } + decimal? rateFactor = fact != 1 ? fact : (decimal?)null; + var items = new List(); + + // Periode mit drittem Stundensatz (nur bei DifferentHourlyRateCount >= 3) + if (dc.DifferentHourlyRateCount >= 3) + { + items.Add(new InvoiceItemDC + { + ItemPeriodStart = dc.AccountingPeriodStart, + ItemPeriodEnd = dc.HourlyRateEndDate3, + UnitCount = dc.ApprovedFLSWithHourlyRate3, + AmountPerUnit = dc.HourlyRate3, + RateFactor = rateFactor, + GrossAmountTotal = dc.ApprovedFLSWithHourlyRate3 * fact * dc.HourlyRate3, + AmountTotal = dc.ApprovedFLSWithHourlyRate3 * fact * dc.HourlyRate3 + }); + } + + // Periode mit altem Stundensatz (bei DifferentHourlyRateCount >= 2) + if (dc.DifferentHourlyRateCount >= 2) + { + items.Add(new InvoiceItemDC + { + ItemPeriodStart = dc.DifferentHourlyRateCount >= 3 ? dc.HourlyRateOldStartDate : dc.AccountingPeriodStart, + ItemPeriodEnd = dc.HourlyRateOldEndDate, + UnitCount = dc.ApprovedFLSWithOldHourlyRate, + AmountPerUnit = dc.HourlyRateOld, + RateFactor = rateFactor, + GrossAmountTotal = dc.ApprovedFLSWithOldHourlyRate * fact * (dc.HourlyRateOld ?? 0), + AmountTotal = dc.ApprovedFLSWithOldHourlyRate * fact * (dc.HourlyRateOld ?? 0) + }); + } + + // Periode mit aktuellem Stundensatz (immer vorhanden) + items.Add(new InvoiceItemDC + { + ItemPeriodStart = dc.DifferentHourlyRateCount >= 2 ? dc.HourlyRateNewStartDate : dc.AccountingPeriodStart, + ItemPeriodEnd = dc.AccountingPeriodEnd, + UnitCount = dc.ApprovedFLSWithActualHourlyRate, + AmountPerUnit = dc.HourlyRateNew, + RateFactor = rateFactor, + GrossAmountTotal = dc.ApprovedFLSWithActualHourlyRate * fact * (dc.HourlyRateNew ?? 0), + AmountTotal = dc.ApprovedFLSWithActualHourlyRate * fact * (dc.HourlyRateNew ?? 0) + }); + + return items; + } + + public virtual AddressInformation GetAddressInformation(long? customer_oid = null) + { + var user = UserRightHelper.GetLoggedInUser().Employee; + var mandator = AppSettings.GetMandatorEntity(); + + return new AddressInformation() + { + IKLeistungserbringer = mandator.IKLeistungserbringer, + Fax = user.Person.Contacts.FirstOrDefault(x => x.Type == ContactType.business_Fax)?.Value.ToNullIfEmpty(), + Mail = user.Person.Contacts.FirstOrDefault(x => x.Type == ContactType.business_Mail)?.Value.ToNullIfEmpty(), + Phone = user.Person.Contacts.FirstOrDefault(x => x.Type == ContactType.business_Phone)?.Value.ToNullIfEmpty(), + OrganisationName = mandator.Name, + PostCode = mandator.PostalCode, + Street = mandator.Street, + Town = mandator.Town, + Website = mandator.Website + }; + } + } + + public class DifferenzRechnungCheck { public ServiceInvoiceDC NeueRechnung { get; set; } public IList VorhandeneRechungen { get; set; }