From 36bf26bb44de64770e38a8897f3edf81a4df088c Mon Sep 17 00:00:00 2001 From: HirschleM Date: Tue, 23 Jun 2026 14:56:21 +0200 Subject: [PATCH] =?UTF-8?q?MH=20x=20Claude:=20VSDHammReports=20Spitzabrech?= =?UTF-8?q?nung=20kappen=20bei=20w=C3=B6chentlicher=20/=20monatlicher=20?= =?UTF-8?q?=C3=9Cbererbringung=20SupportOID=3D165914?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomSettlementInvoiceCreation.cs | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/ReportImp/VSDHammReports/CustomSettlementInvoiceCreation.cs b/ReportImp/VSDHammReports/CustomSettlementInvoiceCreation.cs index 18a55a1bf..53c618103 100644 --- a/ReportImp/VSDHammReports/CustomSettlementInvoiceCreation.cs +++ b/ReportImp/VSDHammReports/CustomSettlementInvoiceCreation.cs @@ -129,6 +129,7 @@ namespace VSDHammReports public override void CreateInvoiceDetailsTheOldWay(Settlement2DC si, CostBearer2SupportConcept c2s) { + #region Standard String id = c2s.CostBearer.ID; var calc = PluginLoader.FindClass(id); @@ -204,9 +205,15 @@ namespace VSDHammReports Dictionary groupBookingDict = new Dictionary(); //decimal flmCleared = 0; + #endregion + + // Anpassungen gekennzeichnet mit // Claude: records = records.OrderBy(sr => sr.Start.HasValue ? sr.Start.Value : DateTime.MinValue).ToList(); decimal maxApprovedMinutes = (si.ApprovedFLS ?? 0) * 60; decimal totalMinutesGeleistet = 0; + // Claude: Bei wöchentlicher/monatlicher Bewilligung wird die Kappung pro Intervall geprüft. + // Hier werden die je Intervall (Woche bzw. Monat) verbrauchten Minuten (inkl. RF) gesammelt. + Dictionary intervalMinutesGeleistet = new Dictionary(); foreach (var iRecord in records) { if (iRecord.ServiceDescription.ServiceCategory.IsBillable) @@ -233,13 +240,6 @@ namespace VSDHammReports } } - //var prozent = iRecord.ServiceDescription.ServiceCategory.ProzentAbrechnung; - //if (iRecord.ServiceDescription.ProzentAbrechnung.HasValue) - //{ - // prozent = iRecord.ServiceDescription.ProzentAbrechnung.Value; - //} - //dauerAbrechenbar *= prozent / 100; - var prozent = iRecord.ServiceDescription.ServiceCategory.ProzentBudget ?? 100; if (iRecord.ServiceDescription.ProzentBudget.HasValue) { @@ -266,8 +266,38 @@ namespace VSDHammReports var dauerBudgetMitRf = dauerBudget * ((ap.RateFactor ?? 0) + 100) / 100; if (SchneideBeiErreichenDesBudgetsAb) { - if (totalMinutesGeleistet + dauerBudgetMitRf > maxApprovedMinutes) + // Claude: Bei Wochen-/Monatsbewilligung auf Intervall-Ebene kappen statt auf Gesamtebene. + if (ap.ApprovalUnit == AccountingIntervalType.Weekly || ap.ApprovalUnit == AccountingIntervalType.Monthly) { + // Claude: Bewilligte Minuten pro Intervall (ApprovedPerUnit ist die Menge je Woche bzw. Monat). + DateTime intervalKey = ap.ApprovalUnit == AccountingIntervalType.Weekly + ? iRecord.Start.Value.GetLast(DayOfWeek.Monday).Date + : iRecord.Start.Value.GetFirstOfMonth(); + decimal maxIntervalMinutes = ap.ApprovedPerUnit * 60; + decimal intervalMinutes = intervalMinutesGeleistet.ContainsKey(intervalKey) + ? intervalMinutesGeleistet[intervalKey] + : 0; + + if (intervalMinutes + dauerBudgetMitRf > maxIntervalMinutes) + { + dauerBudget = maxIntervalMinutes - intervalMinutes; + dauerBudget /= ((ap.RateFactor ?? 0) + 100) / 100; + + if (dauerBudget < 0) + { + dauerBudget = 0; + } + if (dauerAbrechenbar > dauerBudget) + { + dauerAbrechenbar = dauerBudget; + } + } + + intervalMinutesGeleistet[intervalKey] = intervalMinutes + dauerBudgetMitRf; + } + else if (totalMinutesGeleistet + dauerBudgetMitRf > maxApprovedMinutes) + { + #region Standard dauerBudget = maxApprovedMinutes - totalMinutesGeleistet; dauerBudget /= ((ap.RateFactor ?? 0) + 100) / 100; @@ -336,6 +366,7 @@ namespace VSDHammReports CalculateEquityContribution(si, c2s.SupportConcept, null, null); si.Claim = si.AmountBillableTotal - (si.AmountAdvancedPayments ?? 0) - si.EquityContribution; + #endregion } private decimal? CalculateApprovedTotalFLS(IList apList) {