diff --git a/ReportImp/InputFamilienhilfe/InputFamilienhilfe.csproj b/ReportImp/InputFamilienhilfe/InputFamilienhilfe.csproj
index f8e5d0258..3a3db7da5 100644
--- a/ReportImp/InputFamilienhilfe/InputFamilienhilfe.csproj
+++ b/ReportImp/InputFamilienhilfe/InputFamilienhilfe.csproj
@@ -63,6 +63,7 @@
InvoiceCustomerReport.cs
+
diff --git a/ReportImp/InputFamilienhilfe/Invoicing/CustomSettlementInvoiceCreation.cs b/ReportImp/InputFamilienhilfe/Invoicing/CustomSettlementInvoiceCreation.cs
new file mode 100644
index 000000000..984e817b3
--- /dev/null
+++ b/ReportImp/InputFamilienhilfe/Invoicing/CustomSettlementInvoiceCreation.cs
@@ -0,0 +1,368 @@
+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.Extensions;
+using BS.Shared.Services;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InputFamilienhilfe.Invoicing
+{
+ class CustomSettlementInvoiceCreation : SettlementInvoiceCreation
+ {
+ public override void CreateInvoiceDetailsTheOldWay(Settlement2DC si, CostBearer2SupportConcept c2s)
+ {
+ bool isLWL = false;
+ String id = c2s.CostBearer.ID;
+ if (String.IsNullOrEmpty(id))
+ {
+ if (!String.IsNullOrEmpty(si.RecipientOrganisation) && si.RecipientOrganisation.Trim().ToLower().IndexOf("lwl") == 0)
+ {
+ isLWL = true;
+ id = "LWL";
+ }
+
+ }
+ var calc = PluginLoader.FindClass(id) ?? Calculations.GetInstance(id);
+ var relDC = c2s.MapToNewDC();
+
+ decimal lDurationInWeeks =
+ calc.GetIntervalCountForDays(
+ Convert.ToDecimal((c2s.EndDate.Value - c2s.StartDate.Value).Days + 1),
+ SupportConceptApprovalInterval.Weekly);
+
+ decimal lApprovedFLSWeeklyForMaxAmountCalculation = 0;
+
+ CalculateSettlementInvoiceApprovedAmounts(si, relDC, calc);
+
+ 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);
+
+ }
+ //Prüfe ob Enddatum in Zukunft liegt:
+ if (periodEnd > DateTime.Now)
+ {
+ var srList = c2s.ServiceRecords;
+
+ var max = srList.Max(s => s.End);
+
+ if (max.HasValue && max < periodEnd)
+ {
+ periodEnd = max.Value;
+ }
+ }
+
+
+ var tolerancesInSpanList = relDC.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.ServiceTolerance, periodStart, periodEnd).ToList();
+
+ var hourlyRatesInSpanList = relDC.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.HourlyRate, periodStart, periodEnd).ToList();
+
+ si.DifferentHourlyRateCount = hourlyRatesInSpanList.Count;
+
+ if (hourlyRatesInSpanList.Count > 1)
+ {
+ if (hourlyRatesInSpanList.Count == 2)
+ {
+ si.WeeksWithOldHourlyRate =
+ calc.GetIntervalCountForDays(Convert.ToDecimal(hourlyRatesInSpanList.First().Value.GetTimeSpan().Days + 1),
+ SupportConceptApprovalInterval.Weekly);
+ si.WeeksWithNewHourlyRate =
+ calc.GetIntervalCountForDays(
+ Convert.ToDecimal((c2s.EndDate.Value - hourlyRatesInSpanList.Last().Value.StartDate).Days + 1),
+ SupportConceptApprovalInterval.Weekly);
+ si.WeeksWithHourlyRate3 = 0;
+ }
+ else if (hourlyRatesInSpanList.Count == 3)
+ {
+ si.WeeksWithHourlyRate3 =
+ calc.GetIntervalCountForDays(Convert.ToDecimal(hourlyRatesInSpanList.First().Value.GetTimeSpan().Days + 1),
+ SupportConceptApprovalInterval.Weekly);
+ si.WeeksWithOldHourlyRate =
+ calc.GetIntervalCountForDays(Convert.ToDecimal(hourlyRatesInSpanList.ElementAt(1).Value.GetTimeSpan().Days + 1),
+ SupportConceptApprovalInterval.Weekly);
+ si.WeeksWithNewHourlyRate =
+ calc.GetIntervalCountForDays(
+ Convert.ToDecimal((c2s.EndDate.Value - hourlyRatesInSpanList.Last().Value.StartDate).Days + 1),
+ SupportConceptApprovalInterval.Weekly);
+ }
+ }
+ else
+ {
+ si.WeeksWithNewHourlyRate = lDurationInWeeks;
+ }
+
+ decimal currentRateFactor = 0;
+ decimal currentHourlyRate = 0;
+
+ decimal lastHourlyRate = 0;
+ decimal thirdHourlyRate = 0;
+
+ var rateFactorsInSpanList = relDC.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.RateFactor, periodStart, periodEnd).ToList();
+
+ if (hourlyRatesInSpanList.Count > 0)
+ {
+ var cdc = hourlyRatesInSpanList.Last().Key;
+ if (cdc.CostRateValue.HasValue)
+ currentHourlyRate = cdc.CostRateValue.Value;
+ }
+
+ if (rateFactorsInSpanList.Count > 0)
+ {
+ var cdc = rateFactorsInSpanList.Last().Key;
+ if (cdc.CostRateValue.HasValue)
+ currentRateFactor = cdc.CostRateValue.Value;
+ }
+
+
+ if (hourlyRatesInSpanList.Count > 1)
+ {
+ var cdc = hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 2].Key;
+ if (cdc.CostRateValue.HasValue)
+ lastHourlyRate = cdc.CostRateValue.Value;
+ si.HourlyRateOldEndDate = hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 2].Value.EndDate;
+ si.HourlyRateNewStartDate = hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 1].Value.StartDate;
+ }
+
+ if (hourlyRatesInSpanList.Count > 2)
+ {
+ var cdc = hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 3].Key;
+ if (cdc.CostRateValue.HasValue)
+ thirdHourlyRate = cdc.CostRateValue.Value;
+ si.HourlyRateEndDate3 = hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 3].Value.EndDate;
+ si.HourlyRateOldStartDate = hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 2].Value.StartDate;
+ }
+
+ if (si.ApprovedFLSWeekly == null)
+ {
+ si.ApprovedFLSWeekly = 0;
+ }
+
+
+ //decimal maxAmount = 0;
+
+ //decimal maxFLS = lApprovedFLSWeeklyForMaxAmountCalculation * si.WeeksWithNewHourlyRate;
+ //maxFLS += lApprovedFLSWeeklyForMaxAmountCalculation * si.WeeksWithOldHourlyRate;
+ //maxFLS += lApprovedFLSWeeklyForMaxAmountCalculation * si.WeeksWithHourlyRate3;
+
+ si.RateFactor = currentRateFactor;
+ si.HourlyRateNew = currentHourlyRate;
+
+ si.HourlyRateOld = lastHourlyRate;
+ si.HourlyRate3 = thirdHourlyRate;
+
+ //decimal totalAmount = 0;
+
+
+ var records = GetBillableServiceRecords(c2s);
+
+ 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 flsCleared = 0;
+ records =
+ records.OrderBy(sr => sr.Start.HasValue ? sr.Start.Value : DateTime.MinValue)
+ .ToList();
+
+ decimal tolerance = 100;
+ if (tolerancesInSpanList.Count > 0)
+ {
+ if (tolerancesInSpanList[0].Key.CostRateValue.HasValue && tolerancesInSpanList[0].Key.CostRateValue.Value > 0)
+ {
+ tolerance = tolerancesInSpanList[0].Key.CostRateValue ?? 100;
+ }
+ }
+
+ decimal approved = si.ApprovedFLS ?? 0;
+ if (tolerance != 100)
+ {
+ approved = (approved * tolerance) / 100m;
+ }
+
+ if (!CheckMaxApprovedHours())
+ {
+ approved = Decimal.MaxValue;
+ }
+ foreach (var iRecord in records)
+ {
+ if (iRecord.ServiceDescription.ServiceCategory.IsBillable && IsServiceRecordBillable(iRecord))
+ {
+ if (iRecord.GroupOid == null || !groupBookingDict.ContainsKey(iRecord.GroupOid.Value))
+ {
+ //
+ if (iRecord.GroupPersonCount != null || iRecord.GroupPersonCount > 0)
+ iRecord.RoundedDuration = iRecord.GroupRoundedDuration.Value / iRecord.GroupPersonCount.Value;
+ decimal rd = iRecord.RoundedDuration;
+ var prozent = iRecord.ServiceDescription.ServiceCategory.ProzentAbrechnung;
+ if (iRecord.ServiceDescription.ProzentAbrechnung.HasValue)
+ {
+ prozent = iRecord.ServiceDescription.ProzentAbrechnung.Value;
+ }
+ rd = (rd * prozent) / 100;
+
+ decimal duration = rd / 60;
+ if (si.RecordedBillableFLSBrutto == null)
+ {
+ si.RecordedBillableFLSBrutto = 0;
+ }
+
+ si.RecordedBillableFLSBrutto += duration;
+ si.RecordedBillableFLSNetto += duration;
+
+
+ //if (maxAmount == 0)
+ //{
+ if (flsCleared + duration > approved)
+ {
+ duration = approved - flsCleared;
+ flsCleared = approved;
+ }
+ else
+ {
+ flsCleared += duration;
+ }
+ //}
+
+ //decimal? hourlyRate = null;
+ //decimal? rateFactor = null;
+
+ var rates = c2s.CostBearer.CostRatePeriods.MapToNewDCs();
+ //if (iRecord.Start != null)
+ //{
+
+ // hourlyRate = rates.GetValidRateValueForDate(CostRatePeriodType.HourlyRate, iRecord.Start.Value);
+ // rateFactor = rates.GetValidRateValueForDate(CostRatePeriodType.RateFactor, iRecord.Start.Value);
+
+ //}
+ //else
+ //{
+ // hourlyRate = rates.GetCurrentlyValidRateValue(CostRatePeriodType.HourlyRate);
+ // rateFactor = rates.GetCurrentlyValidRateValue(CostRatePeriodType.RateFactor);
+ //}
+ //if (!hourlyRate.HasValue)
+ // hourlyRate = 0;
+ //if (!rateFactor.HasValue)
+ // rateFactor = 0;
+
+ if (hourlyRatesInSpanList.Count > 2 && iRecord.Start != null &&
+ iRecord.Start < hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 2].Value.StartDateTime)
+ {
+ si.ApprovedFLSWithHourlyRate3 += duration;
+ }
+ else if (hourlyRatesInSpanList.Count > 1 && iRecord.Start != null &&
+ iRecord.Start < hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 1].Value.StartDateTime)
+ {
+ si.ApprovedFLSWithOldHourlyRate += duration;
+ }
+ else
+ {
+ si.ApprovedFLSWithActualHourlyRate += duration;
+ }
+
+ if (iRecord.GroupOid != null && !groupBookingDict.ContainsKey(iRecord.GroupOid.Value))
+ {
+ si.HasGroupRecords = true;
+ groupBookingDict.Add(iRecord.GroupOid.Value, true);
+ }
+
+ }
+ }
+ }
+
+ si.ApprovedFLSWithActualHourlyRate = Math.Round(si.ApprovedFLSWithActualHourlyRate, 2, MidpointRounding.AwayFromZero);
+ si.ApprovedFLSWithHourlyRate3 = Math.Round(si.ApprovedFLSWithHourlyRate3, 2, MidpointRounding.AwayFromZero);
+ si.ApprovedFLSWithOldHourlyRate = Math.Round(si.ApprovedFLSWithOldHourlyRate, 2, MidpointRounding.AwayFromZero);
+
+ decimal rf = 1;
+ if (si.RateFactor.HasValue && si.RateFactor.Value != 0)
+ {
+ rf = si.RateFactor.Value;
+ rf = (100 + rf) / 100;
+ }
+
+ decimal roundedNewAmount = 0;
+ decimal amountRateFactor = 0;
+
+ if (si.HourlyRateNew.HasValue)
+ {
+
+ roundedNewAmount = Math.Round(si.ApprovedFLSWithActualHourlyRate * si.HourlyRateNew.Value * rf, 2,
+ MidpointRounding.AwayFromZero);
+ amountRateFactor =
+ Math.Round(
+ roundedNewAmount -
+ Math.Round(si.ApprovedFLSWithActualHourlyRate * si.HourlyRateNew.Value, 2, MidpointRounding.AwayFromZero), 2,
+ MidpointRounding.AwayFromZero);
+ }
+ if (si.HourlyRateOld.HasValue)
+ {
+ decimal a2 = Math.Round(si.ApprovedFLSWithOldHourlyRate * si.HourlyRateOld.Value * rf, 2, MidpointRounding.AwayFromZero);
+ roundedNewAmount += a2;
+ amountRateFactor +=
+ Math.Round(
+ a2 - Math.Round(si.ApprovedFLSWithOldHourlyRate * si.HourlyRateOld.Value, 2, MidpointRounding.AwayFromZero), 2,
+ MidpointRounding.AwayFromZero);
+ }
+ if (si.HourlyRate3 > 0)
+ {
+ decimal a3 = Math.Round(si.ApprovedFLSWithHourlyRate3 * si.HourlyRate3 * rf, 2, MidpointRounding.AwayFromZero);
+ roundedNewAmount += a3;
+ amountRateFactor +=
+ Math.Round(a3 - Math.Round(si.ApprovedFLSWithHourlyRate3 * si.HourlyRate3, 2, MidpointRounding.AwayFromZero), 2,
+ MidpointRounding.AwayFromZero);
+ }
+
+ si.AmountWithRateFactor += amountRateFactor;
+
+ var totalAmount = Math.Round(roundedNewAmount, 2, MidpointRounding.AwayFromZero);
+
+ decimal? maxAmount = CalculateMaxAmount(si);
+
+ if (maxAmount.HasValue && totalAmount > maxAmount.Value)
+ {
+ totalAmount = maxAmount.Value;
+ }
+ si.AmountBillableTotal = totalAmount;
+
+ //AdvancedPayments
+ CalculateAdvancedPayments(si, c2s, null, null, hourlyRatesInSpanList);
+ //EquityContribution (Eigenanteil)
+ CalculateEquityContribution(si, c2s.SupportConcept, null, null);
+
+ si.Claim = si.AmountBillableTotal - (si.AmountAdvancedPayments ?? 0) - si.EquityContribution;
+
+ }
+ }
+}