diff --git a/ReportImp/VSDHammReports/CustomSettlementInvoiceCreation.cs b/ReportImp/VSDHammReports/CustomSettlementInvoiceCreation.cs index c798a4d29..18a55a1bf 100644 --- a/ReportImp/VSDHammReports/CustomSettlementInvoiceCreation.cs +++ b/ReportImp/VSDHammReports/CustomSettlementInvoiceCreation.cs @@ -1,14 +1,18 @@ using BeWo.Data.Access; using BeWo.Data.Entities; +using BeWo.Service.DCEntityMapper; using BeWo.Service.Invoicing; using BeWo.Service.Plugins; +using BS.Shared; using BS.Shared.Core; using BS.Shared.DataContracts; +using BS.Shared.Services; using System; using System.Collections.Generic; using System.Linq; using System.Text; using static BeWo.Report.ReportObjects.SettlementRO; +using BS.Shared.Extensions; namespace VSDHammReports { @@ -22,11 +26,7 @@ namespace VSDHammReports public override bool SchneideBeiErreichenDesBudgetsAb { get { return true; } } - public override void CreateInvoiceDetailsTheOldWay(Settlement2DC si, CostBearer2SupportConcept c2s) - { - base.CreateInvoiceDetailsTheOldWay(si, c2s); - } - + public override List CreateInvoiceItems(Settlement2DC si, IList apList, bool schneideBeiMaxAb) { //var items = base.CreateInvoiceItems(si, apList, true); @@ -127,7 +127,237 @@ namespace VSDHammReports } + public override void CreateInvoiceDetailsTheOldWay(Settlement2DC si, CostBearer2SupportConcept c2s) + { + String id = c2s.CostBearer.ID; + + var calc = PluginLoader.FindClass(id); + if (calc == null) + { + calc = Calculations.GetInstance(id); + } + + var relDc = c2s.MapToNewDC(); + + var apListFehlkontakt = new List(); + var apListFLS = CreateApprovalPeriods(si, c2s); + foreach (var ap in apListFLS) + { + var fkAp = new ApprovalPeriod(); + fkAp.PeriodStartDate = ap.PeriodStartDate; + fkAp.PeriodEndDate = ap.PeriodEndDate; + fkAp.AmountPerUnit = ap.AmountPerUnit; + fkAp.BillingInterval = ap.BillingInterval; + fkAp.RateFactor = 0; + fkAp.Notice = "Fehlkontakte"; + apListFehlkontakt.Add(fkAp); + } + si.ApprovedFLS = CalculateApprovedTotalFLS(apListFLS); + + DateTime periodStart = si.AccountingPeriodStart.Value.Date; + DateTime periodEnd = si.AccountingPeriodEnd.Value.Date; + + //Prüfe ob vorher abgemeldet + if (c2s.SupportConcept.Customer.TerminationDate.HasValue && + c2s.SupportConcept.Customer.TerminationDate.Value < periodEnd) + { + periodEnd = c2s.SupportConcept.Customer.TerminationDate.Value; + si.ErrorNotice = + String.Format( + "Achtung: Die Betreuung endete am {0:dd.MM.yyyy}. Alle nachträglich eingegebenen Stunden werden nicht abgerechnet!", + periodEnd); + } + + var hourlyRatesInSpanList = relDc.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.HourlyRate, periodStart, periodEnd).ToList(); + + si.DifferentHourlyRateCount = hourlyRatesInSpanList.Count; + if (si.DifferentHourlyRateCount == 0) + { + si.DifferentHourlyRateCount = 1; + } + var rateFactorsInSpanList = relDc.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.RateFactor, periodStart, periodEnd).ToList(); + if (rateFactorsInSpanList.Count > 0) + { + var cdc = rateFactorsInSpanList.Last().Key; + if (cdc.CostRateValue.HasValue) + si.RateFactor = cdc.CostRateValue.Value; + } + decimal rf = GetRateFactor(si); + + var records = c2s.ServiceRecords; + + records = records.Where(i => i.Start.HasValue && i.Start.Value.InBetween(periodStart, periodEnd, true)).ToList(); + + var recordDCS = records.MapToNewDCs(); + + var absenceTimes = MapperFactory.AbsenceTimeDC_AbsenceTime.MapToNewDCs(c2s.SupportConcept.Customer.AbsenceTimes); + Dictionary span2Hours = calc.GetAbsencesTimesNotBillable(absenceTimes); + + + si.RecordedBillableFLSNotBillableCustomerAbsent + = calc.GetHoursNotBillableDueToAbsenceTimes(relDc, recordDCS, + span2Hours, false, false); + + si.RecordedBillableFLSNotBillableOutOfApprovedSpan = calc.GetHoursNotBillableDueToOutOfSpan(relDc, recordDCS); + //calc.GetHoursNotBillableDueToMoreThanApproved(relDC, recordDCS, false, false); + + Dictionary groupBookingDict = new Dictionary(); + //decimal flmCleared = 0; + + records = records.OrderBy(sr => sr.Start.HasValue ? sr.Start.Value : DateTime.MinValue).ToList(); + decimal maxApprovedMinutes = (si.ApprovedFLS ?? 0) * 60; + decimal totalMinutesGeleistet = 0; + foreach (var iRecord in records) + { + if (iRecord.ServiceDescription.ServiceCategory.IsBillable) + { + if (iRecord.GroupOid == null || !groupBookingDict.ContainsKey(iRecord.GroupOid.Value)) + { + + decimal dauerAbrechenbar = iRecord.RoundedDuration; + decimal dauerBudget = iRecord.RoundedDuration; + + if (ReduziereBetragBeiAbwesenheiten()) + { + //Die Liste recordDCS enthält nach Aufruf von GetHoursNotBillableDueToAbsenceTimes nur noch die Einträge, die auch während Abwesenheiten abgerechnet werden dürfen + var dcRecord = recordDCS.Where(r => r.ServiceRecordOid == iRecord.Oid).FirstOrDefault(); + if (dcRecord == null) + { + dauerAbrechenbar = 0; + dauerBudget = 0; + } + else + { + dauerAbrechenbar = dcRecord.RoundedDuration; + dauerBudget = dcRecord.RoundedDuration; + } + } + + //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) + { + prozent = iRecord.ServiceDescription.ProzentBudget.Value; + } + dauerBudget *= prozent / 100; + + var apList = apListFLS; + if (iRecord.ServiceDescription.Name.ToLower().Contains("fehlkontakt") || (iRecord.ServiceDescription.ProzentAbrechnung.HasValue && iRecord.ServiceDescription.ProzentAbrechnung.Value < 100)) + { + apList = apListFehlkontakt; + } + + var ap = apList.FirstOrDefault( + iap => + { + return iap.PeriodStartDate <= iRecord.Start && + (iap.PeriodEndDate >= DateTime.MaxValue.AddDays(-1) || iRecord.Start < iap.PeriodEndDate.AddDays(1)); + }); + + if (ap != null) + { + //Christian wars:-) + var dauerBudgetMitRf = dauerBudget * ((ap.RateFactor ?? 0) + 100) / 100; + if (SchneideBeiErreichenDesBudgetsAb) + { + if (totalMinutesGeleistet + dauerBudgetMitRf > maxApprovedMinutes) + { + dauerBudget = maxApprovedMinutes - totalMinutesGeleistet; + dauerBudget /= ((ap.RateFactor ?? 0) + 100) / 100; + + if (dauerBudget < 0) + { + dauerBudget = 0; + } + if (dauerAbrechenbar > dauerBudget) + { + dauerAbrechenbar = dauerBudget; + } + } + + + } + + totalMinutesGeleistet += dauerBudgetMitRf; + + ap.RecordedMinutes += dauerAbrechenbar; + ap.BudgetMinutes += dauerBudget; + } + + if (iRecord.GroupOid != null && !groupBookingDict.ContainsKey(iRecord.GroupOid.Value)) + { + si.HasGroupRecords = true; + groupBookingDict.Add(iRecord.GroupOid.Value, true); + } + } + } + } + + si.RecordedMinutesTotal = totalMinutesGeleistet; + + //decimal? maxAmount = CalculateMaxAmount(si, apList); + var gesamtListe = new List(); + gesamtListe.AddRange(apListFLS.Where(a => a.RecordedMinutes > 0)); + gesamtListe.AddRange(apListFehlkontakt.Where(a => a.RecordedMinutes > 0)); + si.InvoiceItems = CreateInvoiceItems(si, gesamtListe); + + decimal totalAmount = 0; + decimal rateFactorAmount = 0; + + foreach (var ii in si.InvoiceItems) + { + decimal grossAmount = ii.GrossAmountTotal ?? 0; + totalAmount += grossAmount; + + if (ii.RateFactor.HasValue && ii.RateFactor.Value > 0) + { + rateFactorAmount += (grossAmount - (grossAmount / ((100 + ii.RateFactor.Value) / 100))); + } + } + + if (!si.RecordedBillableFLSBrutto.HasValue) + { + si.RecordedBillableFLSNetto = si.InvoiceItems.Sum(ii => (ii.UnitCount ?? 0)); // * rf; //eigentlich falsch dass netto = brutto ist. + si.RecordedBillableFLSBrutto = si.RecordedBillableFLSNetto; + } + si.AmountBillableTotal = totalAmount; + si.AmountWithRateFactor = rateFactorAmount; + + + //AdvancedPayments + CalculateAdvancedPayments(si, c2s, null, null, hourlyRatesInSpanList); + //EquityContribution (Eigenanteil) + CalculateEquityContribution(si, c2s.SupportConcept, null, null); + + si.Claim = si.AmountBillableTotal - (si.AmountAdvancedPayments ?? 0) - si.EquityContribution; + } + private decimal? CalculateApprovedTotalFLS(IList apList) + { + decimal flsTotal = 0; + foreach (var ap in apList) + { + flsTotal += ap.ApprovedTotal; + } + return flsTotal; + } + private decimal GetRateFactor(Settlement2DC si) + { + decimal rf = 1; + if (si.RateFactor.HasValue && si.RateFactor.Value != 0) + { + rf = si.RateFactor.Value; + rf = (100 + rf) / 100; + } + return rf; + } // Abwesenheitsstunden werden hier auch in Berechnung ausgeklammert, Calc auch anpassen + public override bool ReduziereBetragBeiAbwesenheiten() { return true;