Files
BeWoPlaner/Service/Invoicing/LWLSettlementInvoiceCreation.cs
2017-02-01 13:53:59 +01:00

339 lines
10 KiB
C#

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;
using DevExpress.Utils;
namespace BeWo.Service.Invoicing
{
[IDSpecificClass(Identifier = "LWLNEU")]
public class LWLSettlementInvoiceCreation : SettlementInvoiceCreation
{
public override bool CanCreateInvoiceTheOldWay(Settlement2DC si, CostBearer2SupportConcept c2s)
{
return true;
}
public override void CreateInvoiceDetailsTheOldWay(Settlement2DC si, CostBearer2SupportConcept c2s)
{
String id = c2s.CostBearer.ID;
var calc = Calculations.GetInstance(id);
var relDc = c2s.MapToNewDC();
var apList = CreateApprovalPeriods(si, c2s);
si.ApprovedFLS = CalculateApprovedTotalFLS(apList);
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();
si.RecordedBillableFLSNotBillableCustomerAbsent
= calc.GetHoursNotBillableDueToAbsenceTimes(relDc, recordDCS,
c2s.SupportConcept.Customer.GetAbsencesTimesNotBillableWholeWeeks(), false, false);
si.RecordedBillableFLSNotBillableOutOfApprovedSpan = calc.GetHoursNotBillableDueToOutOfSpan(relDc, recordDCS);
//calc.GetHoursNotBillableDueToMoreThanApproved(relDC, recordDCS, false, false);
Dictionary<long, bool> groupBookingDict = new Dictionary<long, bool>();
//decimal flmCleared = 0;
//decimal approvedMinutes = ((si.ApprovedFLS ?? 0) * 60) / rf;
records = records.OrderBy<ServiceRecord, DateTime>(sr => sr.Start.HasValue ? sr.Start.Value : DateTime.MinValue).ToList<ServiceRecord>();
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.Percentage != 100)
{
rd = (rd * iRecord.ServiceDescription.ServiceCategory.Percentage) / 100;
}
var ap = apList.FirstOrDefault(
iap =>
{
return iap.PeriodStartDate <= iRecord.Start &&
(iap.PeriodEndDate >= DateTime.MaxValue.AddDays(-1) || iRecord.Start < iap.PeriodEndDate.AddDays(1));
});
//decimal duration = rd / 60;
if (ap != null)
{
//si.RecordedBillableFLSNetto += duration;
decimal durationToAdd = rd;
//if (flmCleared + rd > approvedMinutes)
//{
// durationToAdd = approvedMinutes - 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);
}
}
}
}
//decimal? maxAmount = CalculateMaxAmount(si, apList);
si.InvoiceItems = CreateInvoiceItems(si, apList);
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)));
}
}
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 GetRateFactor(Settlement2DC si)
{
decimal rf = 1;
if (si.RateFactor.HasValue && si.RateFactor.Value != 0)
{
rf = si.RateFactor.Value;
rf = (100 + rf) / 100;
}
return rf;
}
public virtual List<InvoiceItemDC> CreateInvoiceItems(Settlement2DC si, IList<ApprovalPeriod> apList)
{
return CreateInvoiceItems(si, apList, true);
}
public virtual List<InvoiceItemDC> CreateInvoiceItems(Settlement2DC si, IList<ApprovalPeriod> apList, bool schneideBeiMaxAb)
{
List<InvoiceItemDC> iiList = new List<InvoiceItemDC>();
var apsByHourlyRate = new Dictionary<String, IList<ApprovalPeriod>>();
foreach (var ap in apList)
{
IList<ApprovalPeriod> list = null;
String key = String.Format("{0}_{1}", ap.AmountPerUnit, ap.RateFactor);
if (apsByHourlyRate.ContainsKey(key))
{
list = apsByHourlyRate[key];
}
else
{
list = new List<ApprovalPeriod>();
apsByHourlyRate[key] = list;
}
list.Add(ap);
}
decimal maxApprovedFls = si.ApprovedFLS ?? 0;
decimal totalHours = 0;
foreach (var key in apsByHourlyRate.Keys)
{
IList<ApprovalPeriod> list = apsByHourlyRate[key];
var ii = new InvoiceItemDC();
decimal minutesTotal = 0;
DateTime start = DateTime.MaxValue;
DateTime end = DateTime.MinValue;
decimal rf = si.RateFactor ?? 0;
decimal hr = 0;
foreach (var approvalPeriod in list)
{
minutesTotal += approvalPeriod.RecordedMinutes;
if (approvalPeriod.PeriodStartDate < start)
start = approvalPeriod.PeriodStartDate;
if (approvalPeriod.PeriodEndDate > end)
end = approvalPeriod.PeriodEndDate;
hr = approvalPeriod.AmountPerUnit;
if (approvalPeriod.RateFactor.HasValue)
{
rf = approvalPeriod.RateFactor.Value;
}
}
ii.ItemPeriodStart = start;
ii.ItemPeriodEnd = end;
ii.RateFactor = rf;
ii.AmountPerUnit = hr;
decimal hours = Math.Round(minutesTotal / 60m, 2, MidpointRounding.AwayFromZero);
hours *= (100 + rf) / 100;
hours = Math.Round(hours, 2, MidpointRounding.AwayFromZero);
if (schneideBeiMaxAb)
{
if (totalHours + hours > maxApprovedFls)
{
hours = maxApprovedFls - totalHours;
if (hours < 0)
hours = 0;
}
}
totalHours += hours;
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();
}
private decimal? CalculateApprovedTotalFLS(IList<ApprovalPeriod> apList)
{
decimal flsTotal = 0;
foreach (var ap in apList)
{
flsTotal += ap.ApprovedTotal;
}
return flsTotal;
}
//private decimal? CalculateMaxAmount(Settlement2DC si, IList<ApprovalPeriod> apList)
//{
// var apsByHourlyRate = new Dictionary<decimal, IList<ApprovalPeriod>>();
// foreach (var ap in apList)
// {
// IList<ApprovalPeriod> list = null;
// if (apsByHourlyRate.ContainsKey(ap.AmountPerUnit))
// {
// list = apsByHourlyRate[ap.AmountPerUnit];
// }
// else
// {
// list = new List<ApprovalPeriod>();
// apsByHourlyRate[ap.AmountPerUnit] = list;
// }
// list.Add(ap);
// }
// decimal amount = 0;
// foreach (var hr in apsByHourlyRate.Keys)
// {
// IList<ApprovalPeriod> list = apsByHourlyRate[hr];
// decimal flsTotal = 0;
// foreach (var approvalPeriod in list)
// {
// var fls = Math.Round(approvalPeriod.Weeks * approvalPeriod.ApprovedPerUnit, 2);
// flsTotal += fls;
// }
// decimal a = Math.Round(flsTotal, 2) * hr;
// amount += Math.Round(a, 2);
// }
// return amount;
//}
public override void InitApprovalPeriod(Settlement2DC si, ApprovalPeriod approvalPeriod)
{
base.InitApprovalPeriod(si, approvalPeriod);
approvalPeriod.Weeks = Math.Round(approvalPeriod.Days*0.1427m, 2);
if (approvalPeriod.ApprovalUnit == AccountingIntervalType.Weekly)
{
approvalPeriod.ApprovedTotal = Math.Round(approvalPeriod.Weeks*approvalPeriod.ApprovedPerUnit, 2);
}
approvalPeriod.ApprovedAmountTotal = Math.Round(approvalPeriod.ApprovedTotal * approvalPeriod.AmountPerUnit, 2);
}
}
}