MH x Claude: VSDHammReports Spitzabrechnung kappen bei wöchentlicher / monatlicher Übererbringung

SupportOID=165914
This commit is contained in:
2026-06-23 14:56:21 +02:00
parent 9ec68c3161
commit 36bf26bb44

View File

@@ -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<Calculations>(id);
@@ -204,9 +205,15 @@ namespace VSDHammReports
Dictionary<long, bool> groupBookingDict = new Dictionary<long, bool>();
//decimal flmCleared = 0;
#endregion
// Anpassungen gekennzeichnet mit // Claude:
records = records.OrderBy<ServiceRecord, DateTime>(sr => sr.Start.HasValue ? sr.Start.Value : DateTime.MinValue).ToList<ServiceRecord>();
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<DateTime, decimal> intervalMinutesGeleistet = new Dictionary<DateTime, decimal>();
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<ApprovalPeriod> apList)
{