using System; using System.Collections.Generic; using System.Linq; using System.Text; using BeWo.Data.Entities; using BeWo.Service.DCEntityMapper; using BS.Shared; using BS.Shared.Core; using BS.Shared.DataContracts; using BS.Shared.Extensions; using BS.Shared.Services; namespace BeWo.Service.Invoicing { [IDSpecificClass(Identifier = "LVRIBP")] class IBPLVRSettlementInvoiceCreation : SettlementInvoiceCreation { public override void CreateInvoiceDetailsTheOldWay(Settlement2DC si, CostBearer2SupportConcept c2s) { String id = c2s.CostBearer.ID; var calc = Calculations.GetInstance(id); var relDc = c2s.MapToNewDC(); 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; } var hourlyRatesInSpanList = relDc.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.HourlyRate, periodStart, periodEnd).ToList(); si.DifferentHourlyRateCount = hourlyRatesInSpanList.Count; 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 apList = CreateApprovalPeriods(si, c2s); si.ApprovedFLS = CalculateApprovedTotalFLS(apList); decimal approvedMinutesOhneFactor = ((si.ApprovedFLS ?? 0) * 60) / rf; 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); Dictionary groupBookingDict = new Dictionary(); decimal flmCleared = 0; records = records.OrderBy(sr => sr.Start.HasValue ? sr.Start.Value : DateTime.MinValue).ToList(); foreach (var iRecord in records) { if (iRecord.ServiceDescription.ServiceCategory.IsBillable) { if (iRecord.GroupOid == null || !groupBookingDict.ContainsKey(iRecord.GroupOid.Value)) { decimal rd = iRecord.RoundedDuration; if (iRecord.ServiceDescription.ServiceCategory.ProzentAbrechnung != 100) { rd = (rd * iRecord.ServiceDescription.ServiceCategory.ProzentAbrechnung) / 100; } var ap = apList.FirstOrDefault(iap => iap.PeriodStartDate <= iRecord.Start && (iap.PeriodEndDate == DateTime.MaxValue || iRecord.Start < iap.PeriodEndDate.AddDays(1))); if (ap != null) { decimal durationToAdd = rd; if (flmCleared + rd > approvedMinutesOhneFactor) { durationToAdd = approvedMinutesOhneFactor - flmCleared; if (durationToAdd < 0) durationToAdd = 0; } flmCleared += rd; ap.RecordedMinutes += durationToAdd; } if (iRecord.GroupOid != null && !groupBookingDict.ContainsKey(iRecord.GroupOid.Value)) { groupBookingDict.Add(iRecord.GroupOid.Value, true); } } } } si.InvoiceItems = CreateInvoiceItems(si, apList); decimal totalAmount = 0; foreach (var ii in si.InvoiceItems) { totalAmount += ii.GrossAmountTotal ?? 0; } si.RecordedBillableFLSNetto = (flmCleared / 60) * rf; //eigentlich falsch dass netto = brutto ist. si.RecordedBillableFLSBrutto = si.RecordedBillableFLSNetto; 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; } 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; } private List CreateInvoiceItems(Settlement2DC si, IList apList) { List iiList = new List(); decimal rf = GetRateFactor(si); var apsByHourlyRate = new Dictionary>(); foreach (var ap in apList) { IList list = null; if (apsByHourlyRate.ContainsKey(ap.AmountPerUnit)) { list = apsByHourlyRate[ap.AmountPerUnit]; } else { list = new List(); apsByHourlyRate[ap.AmountPerUnit] = list; } list.Add(ap); } foreach (var hr in apsByHourlyRate.Keys) { IList list = apsByHourlyRate[hr]; var ii = new InvoiceItemDC(); decimal minutesTotal = 0; DateTime start = DateTime.MaxValue; DateTime end = DateTime.MinValue; foreach (var approvalPeriod in list) { minutesTotal += approvalPeriod.RecordedMinutes; if (approvalPeriod.PeriodStartDate < start) start = approvalPeriod.PeriodStartDate; if (approvalPeriod.PeriodEndDate > end) end = approvalPeriod.PeriodEndDate; } ii.ItemPeriodStart = start; ii.ItemPeriodEnd = end; ii.RateFactor = si.RateFactor; ii.AmountPerUnit = hr; decimal hours = minutesTotal / 60m; hours *= rf; hours = Math.Round(hours, 2, MidpointRounding.AwayFromZero); ii.UnitCount = hours; ii.AmountTotal = Math.Round(hr * hours, 2, MidpointRounding.AwayFromZero); ii.GrossAmountTotal = ii.AmountTotal; iiList.Add(ii); } return iiList.OrderBy(ii => ii.ItemPeriodStart).ToList(); } public override IList CreateApprovalPeriods(Settlement2DC si, CostBearer2SupportConcept c2s) { decimal rf = GetRateFactor(si); var periods = base.CreateApprovalPeriods(si, c2s); foreach (var ap in periods) { ap.ApprovedTotal *= rf; } return periods; } private decimal? CalculateApprovedTotalFLS(IList apList) { decimal flsTotal = 0; foreach (var ap in apList) { flsTotal += ap.ApprovedTotal; } return flsTotal; } //public override void InitApprovalPeriod(Settlement2DC si, ApprovalPeriod approvalPeriod) //{ // base.InitApprovalPeriod(si, approvalPeriod); // approvalPeriod.Weeks = Math.Round(approvalPeriod.Days * 0.1427m, 2); // approvalPeriod.ApprovedTotal = Math.Round(approvalPeriod.Weeks * approvalPeriod.ApprovedPerUnit, 2); // approvalPeriod.ApprovedAmountTotal = Math.Round(approvalPeriod.ApprovedTotal * approvalPeriod.AmountPerUnit, 2); //} } }