diff --git a/ReportImp/TeamPfeil/CustomReportCreator.cs b/ReportImp/TeamPfeil/CustomReportCreator.cs index 6896694b5..ca42df4da 100644 --- a/ReportImp/TeamPfeil/CustomReportCreator.cs +++ b/ReportImp/TeamPfeil/CustomReportCreator.cs @@ -179,7 +179,7 @@ namespace TeamPfeil if (ap.ServiceCategory.Name.Contains("Qualifizierte Assistenz")) { budgetFuerQualAss = KorridorberechnungHelper.BerechneBudgetFuerQualAss(bewilligtGesamt); - double genutzt = KorridorberechnungHelper.BerechneGenutzteKorridorstunden(scOid, ap.ServiceCategory, budgetFuerQualAss, ro.EndDate, true); + double genutzt = KorridorberechnungHelper.BerechneGenutzteKorridorstunden(scOid, ap.ServiceCategory, budgetFuerQualAss, ro.EndDate.AddDays(1).AddTicks(-1), true); ro.TotalFLMQualified = genutzt; ro.TotalFLSQualified = budgetFuerQualAss - genutzt; @@ -194,7 +194,7 @@ namespace TeamPfeil else if (ap.ServiceCategory.Name.Contains("Unterstützende Assistenz")) { budgetFuerUnterstAss = KorridorberechnungHelper.BerechneBudgetFuerUnterstAss(bewilligtGesamt); - double genutzt = KorridorberechnungHelper.BerechneGenutzteKorridorstunden(scOid, ap.ServiceCategory, budgetFuerUnterstAss, ro.EndDate, false); + double genutzt = KorridorberechnungHelper.BerechneGenutzteKorridorstunden(scOid, ap.ServiceCategory, budgetFuerUnterstAss, ro.EndDate.AddDays(1).AddTicks(-1), false); ro.TotalFLMUnqualified = genutzt; ro.TotalFLSUnqualified = budgetFuerUnterstAss - genutzt; diff --git a/ReportImp/TeamPfeil/Invoicing/CustomInvoiceCreation.cs b/ReportImp/TeamPfeil/Invoicing/CustomInvoiceCreation.cs index 9e3ab6d04..26e802f3d 100644 --- a/ReportImp/TeamPfeil/Invoicing/CustomInvoiceCreation.cs +++ b/ReportImp/TeamPfeil/Invoicing/CustomInvoiceCreation.cs @@ -69,7 +69,57 @@ namespace TeamPfeil.Invoicing } } + public override IList CreateInvoiceItems(List serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc) + { + var list = new List(); + foreach (ServiceRecordDC iServiceRecord in serviceRecordsInPeriod) + { + if (iServiceRecord.ServiceDescription.Category.IsBillable) + { + if (!iServiceRecord.AlreadyAccounted) + { + InvoiceItem invoiceItem = CreateInvoiceItem(iServiceRecord, scap, calc); + if (invoiceItem != null) + { + // Wenn das Item ganz normal abgerechnet wird, einfach normal zur Liste + if (invoiceItem.CustomString5 != "Mischitem") + list.Add(invoiceItem); + else + { + // Ist es ein Mischitem, müssen zwei Items erstellt werden. Eins mit dem Mitarbeiterstundensatz und eins mit dem Leistungsstundensatz + // invoiceItem.CustomNumber1: Stunden für den MA-Stundensatz + // invoiceItem.CustomNumber2: MA-Stundensatz + // invoiceItem.CustomString2: Leistungsname für MA-Stundensatz + // invoiceItem.CustomNumber3: Stunden für den Leistungs-Stundensatz + // invoiceItem.CustomNumber4: Leistungs-Stundensatz + // invoiceItem.CustomString4: Leistungsname für Leistungsstundensatz + var item1 = invoiceItem; + var item2 = CopyInvoiceItem(invoiceItem); + item1.UnitCount = invoiceItem.CustomNumber1; + item1.AmountPerUnit = invoiceItem.CustomNumber2; + item1.AmountTotal = item1.UnitCount * invoiceItem.AmountPerUnit; + item1.GrossAmountTotal = item1.AmountTotal; + item1.ItemDescription = item1.CustomString2; + list.Add(item1); + + item2.UnitCount = invoiceItem.CustomNumber3; + item2.AmountPerUnit = invoiceItem.CustomNumber4; + item2.AmountTotal = item2.UnitCount * invoiceItem.AmountPerUnit; + item2.GrossAmountTotal = item2.AmountTotal; + item2.ItemDescription = item1.CustomString4; + list.Add(item2); + } + } + iServiceRecord.AlreadyAccounted = true; + } + } + } + + return CreateSummaryInvoiceItems(list, invoicePeriod, scap, calc); + } + + public override InvoiceItem CreateInvoiceItem(ServiceRecordDC iServiceRecord, SupportConceptApprovalPeriod scap, Calculations calc) { @@ -111,6 +161,7 @@ namespace TeamPfeil.Invoicing } } + // Ab 2026 wird das abgerechnet, was dokumentiert wird. // Sonderfall: Korridor // Korridor wird Thema, wenn die bewilligte Leistungsform sich von der Qualifikation der dokumentierenden Person unterscheidet. @@ -121,81 +172,100 @@ namespace TeamPfeil.Invoicing // den der Korridormitarbeiter eigentlich hat (also qualfi.abhäng. Stundensatz im Kostenträger, der der Qualifikation des Mitarbeiters entspricht) else { - bool korridorAufgebraucht = false; - bool mischitem = false; // Mischitem = ServiceRecord kann nur teilweise mit Leistungsstundensatz abgerechnet werden, teils aber mit MA-Qual--Std.satz + + bool korridorAufgebraucht = false; // Wenn true, wird statt dem Leistungsstundensatz der MA-Stundensatz genommen + // Mischitem = ServiceRecord kann nur teilweise mit Leistungsstundensatz abgerechnet werden, der Rest muss aber mit MA-Qual--Std.satz abgerechnet werden + // In dem Fall werden im Item beide Teilstunden und beide jeweiligem Stundensätze gesetzt und im Nachgang wird ein weiteres Item erzeugt (in CreateInvoiceItems) + bool mischitem = false; + // KORRIDOR ERMITTELN var scapDC = MapperFactory.SupportConceptApprovalPeriodDC_SupportConceptApprovalPeriod.MapToNewDC(scap); var gesamtBewilligt = KorridorberechnungHelper.BerechneStundenBewilligtGesamt(scapDC); double korridorbudget = 0; double genutztesKorridorbudget = 0; double rest = 0; - if (scap.ServiceCategory.Name.Contains("Qualifizierte Assistenz")) { korridorbudget = KorridorberechnungHelper.BerechneBudgetFuerQualAss(gesamtBewilligt); genutztesKorridorbudget = KorridorberechnungHelper.BerechneGenutzteKorridorstunden(iServiceRecord.SupportConcept.SupportConceptOid, scapDC.ServiceCategory, - korridorbudget, iServiceRecord.Start.Value, true); + korridorbudget, iServiceRecord.Start.Value.AddTicks(-1), true); rest = korridorbudget - genutztesKorridorbudget; } else if (scap.ServiceCategory.Name.Contains("Unterstützende Assistenz")) { korridorbudget = KorridorberechnungHelper.BerechneBudgetFuerUnterstAss(gesamtBewilligt); genutztesKorridorbudget = KorridorberechnungHelper.BerechneGenutzteKorridorstunden(iServiceRecord.SupportConcept.SupportConceptOid, scapDC.ServiceCategory, - korridorbudget, iServiceRecord.Start.Value, false); + korridorbudget, iServiceRecord.Start.Value.AddTicks(-1), false); rest = korridorbudget - genutztesKorridorbudget; } - // todo: Wenn das Item noch etwas Restbudget hat, aber es nicht ganz ausreicht, um alles abzudecken, muss eig ein Mischitem erzeugt werden. + // Wenn das Item noch etwas Restbudget hat, aber es nicht ganz ausreicht, um alles abzudecken, muss ein Mischitem erzeugt werden. // Es muss also der Teil, der noch verfügbar ist, mit dem Leistungsstundensatz verrechnet werden und der Rest mit der Qualifikation + // Dazu werden der jeweilige UnitCount und der jeweilige Stundensatz in CustomNumbers gespeichert, um in CreateInvoiceItems ein zweites Item zu machen if (rest > 0 && rest - Convert.ToDouble(iServiceRecord.RoundedDuration) / 60 < 0) { decimal zeitNormalAbrechenbar = Convert.ToDecimal(rest); decimal zeitMitMitarbeiterStundensatz = iServiceRecord.RoundedDuration / 60 - Convert.ToDecimal(rest); - + // Wenn Mischitem, dann UnitCounts zwischenspeichern, um später aufzuteilen + invoiceItem.CustomNumber1 = zeitMitMitarbeiterStundensatz; + invoiceItem.CustomNumber3 = zeitNormalAbrechenbar; mischitem = true; + invoiceItem.CustomString5 = "Mischitem"; } - else if (rest <= 0) + // Wenn der Rest eh schon unter 0 ist, wird einfach mit dem MA-Stundensatz abgerechnet + else if (rest < 0) korridorAufgebraucht = true; - if (korridorAufgebraucht) // Stundensatz der Mitarbeitendenqualifikation + if (korridorAufgebraucht || mischitem) // Stundensatz der Mitarbeitendenqualifikation { var qualifikation = iServiceRecord.Employee.ValueListEntries.FirstOrDefault(v => v.Value == ValueListEntryType.StaffQualificationsType); if (qualifikation.Key != null) { qualiOid = qualifikation.Key; - if (qualiOid == 2118) + if (qualiOid == 2118) // QA 1 { stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, qualiOid, iServiceRecord.Start); - invoiceItem.ItemDescription = "Qualifikationsniveau 1: "; + invoiceItem.ItemDescription = "QA 1: "; } - else if (qualiOid == 2119) + else if (qualiOid == 2119) // QA 2 { stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, qualiOid, iServiceRecord.Start); - invoiceItem.ItemDescription = "Qualifikationsniveau 2: "; + invoiceItem.ItemDescription = "QA 2: "; } - else if (qualiOid == 2120) + else if (qualiOid == 2120) // UA 3 { stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, qualiOid, iServiceRecord.Start); - invoiceItem.ItemDescription = "Qualifikationsniveau 3: "; + invoiceItem.ItemDescription = "UA 3: "; } - else if (qualiOid == 2121) + else if (qualiOid == 2121) // UA 4 { stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, qualiOid, iServiceRecord.Start); - invoiceItem.ItemDescription = "Qualifikationsniveau 4: "; + invoiceItem.ItemDescription = "UA 4: "; + } + + if (mischitem) // Wenn Mischitem, dann Stundensatz der Person + dessen Qualifikation zwischenspeichern, um später aufzuteilen + { + invoiceItem.CustomNumber2 = stundensatz; + invoiceItem.CustomString2 = invoiceItem.ItemDescription; } } } - else // Stundensatz, der der dokumentierten Leistung entspricht + if (!korridorAufgebraucht || mischitem) // Stundensatz, der der dokumentierten Leistung entspricht { var leistung = iServiceRecord.ServiceDescription.Name; switch (leistung) { - case "QA 1": stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, 2118, iServiceRecord.Start); invoiceItem.ItemDescription = "Qualifikationsniveau 1: "; break; - case "QA 2": stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, 2119, iServiceRecord.Start); invoiceItem.ItemDescription = "Qualifikationsniveau 2: "; break; - case "UA 3": stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, 2120, iServiceRecord.Start); invoiceItem.ItemDescription = "Qualifikationsniveau 3: "; break; - case "UA 4": stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, 2121, iServiceRecord.Start); invoiceItem.ItemDescription = "Qualifikationsniveau 4: "; break; + case "QA 1": stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, 2118, iServiceRecord.Start); invoiceItem.ItemDescription = "QA 1: "; break; + case "QA 2": stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, 2119, iServiceRecord.Start); invoiceItem.ItemDescription = "QA 2: "; break; + case "UA 3": stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, 2120, iServiceRecord.Start); invoiceItem.ItemDescription = "UA 3: "; break; + case "UA 4": stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, 2121, iServiceRecord.Start); invoiceItem.ItemDescription = "UA 4: "; break; + } + if (mischitem) // Wenn Mischitem, dann Stundensatz der Leistung + Leistungsbezeichnung zwischenspeichern, um später aufzuteilen + { + invoiceItem.CustomNumber4 = stundensatz; + invoiceItem.CustomString4 = invoiceItem.ItemDescription; } } } @@ -221,7 +291,6 @@ namespace TeamPfeil.Invoicing invoiceItem.ItemPeriodEnd = bd.BillingPeriodEnd; invoiceItem.RateFactor = bd.RateFactor; invoiceItem.AccountingInterval = bd.AccountingInterval; - //iServiceRecord.Employee + " - " + iServiceRecord.ServiceDescription.Name; invoiceItem.ServiceRecord = DAOFactory.GenericDAO.LoadByID(iServiceRecord.ServiceRecordOid.Value); return invoiceItem; @@ -249,7 +318,29 @@ namespace TeamPfeil.Invoicing return 0; } - + private InvoiceItem CopyInvoiceItem(InvoiceItem invoiceItem) + { + return new InvoiceItem() + { + AccountingInterval = invoiceItem.AccountingInterval, + AmountPerUnit = invoiceItem.AmountPerUnit, + AmountTotal = invoiceItem.AmountTotal, + ApprovalUnit = invoiceItem.ApprovalUnit, + ApprovedPerUnit = invoiceItem.ApprovedPerUnit, + GrossAmountTotal = invoiceItem.GrossAmountTotal, + ItemDescription = invoiceItem.ItemDescription, + IsActive = invoiceItem.IsActive, + ItemPeriodEnd = invoiceItem.ItemPeriodEnd, + ItemPeriodStart = invoiceItem.ItemPeriodStart, + MaxApprovedAmount = invoiceItem.MaxApprovedAmount, + MaxApprovedUnitCount = invoiceItem.MaxApprovedAmount, + RateFactor = invoiceItem.RateFactor, + ServiceRecord = invoiceItem.ServiceRecord, + SupportConceptApprovalPeriodOid = invoiceItem.SupportConceptApprovalPeriodOid, + UnitCount = invoiceItem.UnitCount, + UnitDescription = invoiceItem.UnitDescription, + }; + } public override string GetSummaryItemKey(SupportConceptApprovalPeriod scap, InvoiceItem iitem, bool summaryPerMonth) { String key = String.Format("{0}_{1}", iitem.AmountPerUnit, iitem.ItemDescription); diff --git a/ReportImp/TeamPfeil/Korridorberechnung/KorridorberechnungHelper.cs b/ReportImp/TeamPfeil/Korridorberechnung/KorridorberechnungHelper.cs index a3d9ad1dd..bab9dac45 100644 --- a/ReportImp/TeamPfeil/Korridorberechnung/KorridorberechnungHelper.cs +++ b/ReportImp/TeamPfeil/Korridorberechnung/KorridorberechnungHelper.cs @@ -45,7 +45,7 @@ namespace TeamPfeil.Korridorberechnung double genutzteStunden = 0; var serviceRecords = DAOFactory.SearchDAO.FindServiceRecordsForSupportConcept(supportConceptOid.Value) - .Where(sr => sr.ServiceDescription.ServiceCategory.Oid == serviceCategory.ServiceCategoryOid && sr.Start.Value.Date <= reportEndDate) + .Where(sr => sr.ServiceDescription.ServiceCategory.Oid == serviceCategory.ServiceCategoryOid && sr.Start.Value <= reportEndDate) .ToList(); if (serviceRecords != null && serviceRecords.Count > 0) diff --git a/ReportImp/TeamPfeil/Statistics/CustomServiceRecordStatisticFactory.cs b/ReportImp/TeamPfeil/Statistics/CustomServiceRecordStatisticFactory.cs new file mode 100644 index 000000000..768fcdb37 --- /dev/null +++ b/ReportImp/TeamPfeil/Statistics/CustomServiceRecordStatisticFactory.cs @@ -0,0 +1,22 @@ +using BeWo.Service.Plugins; +using BS.Shared.DataContracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TeamPfeil.Statistics +{ + public class CustomServiceRecordStatisticFactory : ServiceRecordStatisticFactory + { + public override SupportConceptStatisticsDC CreateSupportConceptStatisticsImpl(long costBearer2SupportConceptOid, DateTime statisticsDate, long? ignoreServiceRecordOid) + { + var stats = base.CreateSupportConceptStatisticsImpl(costBearer2SupportConceptOid, statisticsDate, ignoreServiceRecordOid); + + stats.PeriodStatistics = stats.PeriodStatistics.OrderByDescending(s => s.SupportConceptApprovalPeriod.StartDate).ToList(); + + return stats; + } + } +} diff --git a/ReportImp/TeamPfeil/TeamPfeil.csproj b/ReportImp/TeamPfeil/TeamPfeil.csproj index 06b872b75..b5fd4625c 100644 --- a/ReportImp/TeamPfeil/TeamPfeil.csproj +++ b/ReportImp/TeamPfeil/TeamPfeil.csproj @@ -114,6 +114,7 @@ SettlementReport.cs +