Files
BeWoPlaner/Shared/Services/Calculations.cs
Christian 7e05645ece - Bugfixing Mok
- Umstellung auf 64 bit
- Weitere Platzhalterfelder
2025-09-09 00:44:55 +02:00

2082 lines
90 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;
namespace BS.Shared.Services
{
public class Calculations : AbstractIDSpecificDefaultClass<Calculations>
{
#region Public Methods
public virtual decimal GetIntervalCountForDays(decimal totalDays, SupportConceptApprovalInterval interval)
{
return ConvertPerIntervall2PerDay(totalDays, interval);
}
public virtual decimal ConvertPerIntervall2PerDay(decimal pPerInterval, SupportConceptApprovalInterval pInterval)
{
switch (pInterval)
{
case SupportConceptApprovalInterval.Daily:
return pPerInterval;
case SupportConceptApprovalInterval.Weekly:
return pPerInterval / 7m;
case SupportConceptApprovalInterval.Fortnightly:
return pPerInterval / 14m;
case SupportConceptApprovalInterval.Monthly:
return pPerInterval / (365m / 12m);
case SupportConceptApprovalInterval.Quarterly:
return pPerInterval / (365m / 4m);
case SupportConceptApprovalInterval.HalfYearly:
return pPerInterval / (365m / 2m);
case SupportConceptApprovalInterval.Yearly:
return pPerInterval / 365m;
case SupportConceptApprovalInterval.Hourly:
return pPerInterval * 24;
default:
return 0;
}
}
public virtual decimal? GetApprovedAmountForPeriod(SupportConceptCostBearerRelDC c2sDc, DateTime? start, DateTime? end, ServiceCategoryDC cat)
{
// Start- und Enddate sowie Leistungskategorie sind KannFelder
var dtStart = c2sDc.StartDate;
var dtEnd = c2sDc.EndDate;
if (start.HasValue && start > dtStart)
{
dtStart = start;
}
if (end.HasValue && end < dtEnd)
{
dtEnd = end;
}
decimal summe = 0;
var orgCrList = c2sDc.CostBearer.CostRatePeriods;
if (cat != null) // Im Fall, dass nur eine bestimmte Leistungskategorie berücksichtigt werden soll
{
foreach (var scap in c2sDc.ApprovalPeriodList)
{
if (scap.StartDate <= dtEnd && scap.EndDate >= dtStart && scap.ServiceCategory != null && scap.ServiceCategory.ServiceCategoryOid == cat.ServiceCategoryOid)
{
if (scap.ServiceCategory.CostRatePeriods != null && scap.ServiceCategory.CostRatePeriods.Count > 0)
{
summe += GetApprovedAmountDefaultHourlyRateForPeriod(scap, scap.ServiceCategory.CostRatePeriods, dtStart, dtEnd) ?? 0;
}
else
{
summe += GetApprovedAmountDefaultHourlyRateForPeriod(scap, orgCrList, dtStart, dtEnd) ?? 0;
}
}
}
}
else
{
foreach (var scap in c2sDc.ApprovalPeriodList)
{
if (scap.StartDate <= dtEnd && scap.EndDate >= dtStart)
{
if (scap.ServiceCategory != null && scap.ServiceCategory.CostRatePeriods != null && scap.ServiceCategory.CostRatePeriods.Count > 0)
{
summe += GetApprovedAmountDefaultHourlyRateForPeriod(scap, scap.ServiceCategory.CostRatePeriods, dtStart, dtEnd) ?? 0;
}
else
{
summe += GetApprovedAmountDefaultHourlyRateForPeriod(scap, orgCrList, dtStart, dtEnd) ?? 0;
}
}
}
}
return summe;
}
public virtual decimal? GetApprovedAmount(SupportConceptApprovalPeriodDC scap, List<CostRatePeriodDC> costRatePeriods)
{
decimal t1;
decimal t2;
if (scap.ApprovedFixedAmount.HasValue)
return this.GetApprovedFixedAmount(scap, out t1, out t2);
if (scap.ServiceCategory != null && scap.ServiceCategory.CostRatePeriods != null && scap.ServiceCategory.CostRatePeriods.Count > 0)
{
return this.GetApprovedAmountDefaultHourlyRate(scap, scap.ServiceCategory.CostRatePeriods);
}
return this.GetApprovedAmountDefaultHourlyRate(scap, costRatePeriods);
}
public virtual decimal? GetApprovedAmountDefaultHourlyRate(SupportConceptApprovalPeriodDC scap, List<CostRatePeriodDC> costRatePeriods)
{
return this.GetApprovedAmountDefaultHourlyRateForPeriod(scap, costRatePeriods, scap.StartDate, scap.EndDate);
}
public virtual decimal? GetApprovedAmountDefaultHourlyRateForPeriod(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods,
DateTime? start,
DateTime? end)
{
if (!start.HasValue || !end.HasValue)
{
return null;
}
if (scap.ApprovedBEInterval.HasValue && scap.ApprovedBEPerInterval.HasValue)
{
if (scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Monthly && !scap.IsApprovedBEShifting)
{
var totalMonths = GetTotalMonths(start.Value, end.Value);
var approvedHours = totalMonths * scap.ApprovedBEPerInterval.Value;
var hourlyRate = costRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, start.Value);
var rateFactor = costRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.RateFactor, start.Value);
decimal amount = 0;
if (hourlyRate != null && hourlyRate.CostRateValue.HasValue)
amount = approvedHours * hourlyRate.CostRateValue.Value;
if (rateFactor != null && rateFactor.CostRateValue.HasValue)
{
amount = amount + (amount * rateFactor.CostRateValue.Value / 100);
}
return amount;
}
}
var approvedHoursPerDay = this.GetApprovedHoursPerDay(scap, costRatePeriods);
if (!approvedHoursPerDay.HasValue)
{
return null;
}
decimal? result = 0m;
var day = start.Value.Date;
if (end.Value.Date == DateTime.MaxValue.Date)
{
end = end.Value.AddDays(-1);
}
do
{
var hourlyRate = costRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, day);
var rateFactor = costRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.RateFactor, day);
if (hourlyRate == null && rateFactor == null)
{
hourlyRate = costRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney, day);
}
decimal? amountThisDay = 0;
if (hourlyRate != null && hourlyRate.CostRateValue.HasValue && approvedHoursPerDay.HasValue)
amountThisDay = approvedHoursPerDay.Value * hourlyRate.CostRateValue.Value;
if (rateFactor != null && rateFactor.CostRateValue.HasValue)
{
amountThisDay = amountThisDay + (amountThisDay * rateFactor.CostRateValue / 100);
}
result += amountThisDay;
}
while ((day = day.AddDays(1)) <= end.Value.Date);
return result;
}
public virtual decimal? GetApprovedAmountPerMonthAverage(SupportConceptCostBearerRelDC relDC)
{
if (relDC.MonthlyPayment.HasValue)
{
return relDC.MonthlyPayment;
}
if (relDC.ApprovedStartDate.HasValue && relDC.ApprovedEndDate.HasValue)
{
return this.GetApprovedAmountTotal(relDC) / this.GetMonthCount(relDC.ApprovedStartDate.Value, relDC.ApprovedEndDate.Value);
}
return 0;
}
public virtual decimal? GetApprovedAmountPerMonth(SupportConceptCostBearerRelDC relDC, DateTime dt)
{
if (relDC.MonthlyPayment.HasValue)
{
return relDC.MonthlyPayment;
}
var scap = FindApprovalPeriodForDateAndCategory(relDC, dt, null);
if (scap == null && relDC.ApprovalPeriodList != null)
{
//letze Periode nehmen
if (relDC.ApprovalPeriodList.Count > 0)
scap = relDC.ApprovalPeriodList[0];
foreach (var ap in relDC.ApprovalPeriodList)
{
if (!ap.EndDate.HasValue)
scap = ap;
else if (scap.EndDate.HasValue && ap.EndDate > scap.EndDate)
scap = ap;
}
}
if (scap != null && scap.MonthlyPayment.HasValue && scap.MonthlyPayment.Value != 0)
return scap.MonthlyPayment;
else
{
if (relDC.ApprovedStartDate.HasValue && relDC.ApprovedEndDate.HasValue)
{
decimal ratefactor = 1;
if (relDC.CostBearer != null && relDC.CostBearer.CostRatePeriods != null)
{
decimal? factor =
relDC.CostBearer.CostRatePeriods.GetCurrentlyValidRateValue(CostRatePeriodType.RateFactor);
if (factor.HasValue)
ratefactor = (100 + factor.Value) / 100;
}
var monate = this.GetMonthCount(relDC.ApprovedStartDate.Value, relDC.ApprovedEndDate.Value);
if (monate != 0)
{
return (this.GetApprovedAmountTotal(relDC) / monate) / ratefactor;
}
}
}
return 0;
}
public virtual SupportConceptApprovalPeriodDC FindApprovalPeriodForDateAndCategory(SupportConceptCostBearerRelDC relDC, DateTime dt, ServiceCategoryDC category)
{
SupportConceptApprovalPeriodDC scap = null;
if (relDC.ApprovalPeriodList != null)
{
if (category != null)
{
scap = relDC.ApprovalPeriodList.FirstOrDefault(
i =>
dt.InBetween(i.Span, true) && i.ServiceCategory != null &&
i.ServiceCategory.ServiceCategoryOid == category.ServiceCategoryOid);
}
if (scap == null)
scap = relDC.ApprovalPeriodList.FirstOrDefault(i => dt.InBetween(i.Span, true));
}
return scap;
}
public virtual decimal? GetApprovedAmountTotal(SupportConceptCostBearerRelDC relDC)
{
if (relDC.ApprovalPeriodList == null || !relDC.GetApprovedDuration().HasValue)
{
return null;
}
return relDC.ApprovalPeriodList.Sum(i => this.GetApprovedAmount(i, relDC.CostBearer.CostRatePeriods));
}
public virtual decimal? GetApprovedBEPerWeek(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods)
{
return costRatePeriods.GetCurrentlyValidRate(CostRatePeriodType.MinutesPerServiceUnit)
.GetHoursInBE(this.GetApprovedHoursPerWeek(scap, costRatePeriods));
}
public virtual decimal? GetApprovedBEPerWeek(SupportConceptCostBearerRelDC relDC,
DateTime date)
{
if (!relDC.GetApprovedDuration().HasValue)
{
return null;
}
return relDC.CostBearer.CostRatePeriods.GetCurrentlyValidRate(CostRatePeriodType.MinutesPerServiceUnit)
.GetHoursInBE(this.GetApprovedHoursPerWeek(relDC, date));
}
public virtual decimal? GetApprovedBEPerWeekAverage(SupportConceptCostBearerRelDC relDC, bool useIsCalculationWithFactor)
{
if (!relDC.GetApprovedDuration().HasValue)
{
return null;
}
return relDC.CostBearer.CostRatePeriods.GetCurrentlyValidRate(CostRatePeriodType.MinutesPerServiceUnit)
.GetHoursInBE(this.GetApprovedHoursPerWeekAverage(relDC, useIsCalculationWithFactor));
}
private decimal? GetApprovedBETotal(SupportConceptCostBearerRelDC relDC, bool useIsCalculationWithFactor)
{
if (!relDC.GetApprovedDuration().HasValue)
{
return null;
}
return relDC.CostBearer.CostRatePeriods.GetCurrentlyValidRate(CostRatePeriodType.MinutesPerServiceUnit)
.GetHoursInBE(this.GetApprovedHoursTotal(relDC, useIsCalculationWithFactor));
}
public virtual decimal? GetApprovedBETotal(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods)
{
return costRatePeriods.GetCurrentlyValidRate(CostRatePeriodType.MinutesPerServiceUnit)
.GetHoursInBE(this.GetApprovedHoursTotal(scap, costRatePeriods));
}
public virtual decimal? GetApprovedFixedAmount(SupportConceptApprovalPeriodDC scap, out decimal amountPerUnit, out decimal unitCount)
{
return this.GetApprovedFixedAmountForPeriod(scap, scap.StartDate, scap.EndDate, out amountPerUnit, out unitCount);
}
public virtual decimal? GetApprovedFixedAmountForPeriod(SupportConceptApprovalPeriodDC scap, DateTime? pStart, DateTime? pEnd, out decimal amountPerUnit, out decimal unitCount)
{
amountPerUnit = 0;
unitCount = 0;
if (!pStart.HasValue || !pEnd.HasValue || !scap.ApprovedFixedAmount.HasValue || !scap.ApprovedFixedAmountInterval.HasValue)
{
return null;
}
decimal amount = 0;
TimeUnit tu = TimeUnit.Day;
switch (scap.ApprovedFixedAmountInterval.Value)
{
case SupportConceptApprovalInterval.Weekly:
tu = TimeUnit.Week;
break;
case SupportConceptApprovalInterval.Fortnightly:
tu = TimeUnit.Fortnightly;
break;
case SupportConceptApprovalInterval.Monthly:
tu = TimeUnit.Month;
break;
case SupportConceptApprovalInterval.Quarterly:
tu = TimeUnit.Quarter;
break;
case SupportConceptApprovalInterval.HalfYearly:
tu = TimeUnit.Halfyear;
break;
case SupportConceptApprovalInterval.Yearly:
tu = TimeUnit.Year;
break;
case SupportConceptApprovalInterval.Hourly:
tu = TimeUnit.Hour;
break;
}
DateTimeUnit du = pStart.Value.Date.GetDateTimeUnit(pEnd.Value.Date, tu);
amount = scap.ApprovedFixedAmount.Value * du.UnitCount;
amountPerUnit = scap.ApprovedFixedAmount.Value;
unitCount = du.UnitCount;
if (du.RestDays > 0)
{
decimal restamountperday = ConvertPerIntervall2PerDay(scap.ApprovedFixedAmount.Value, scap.ApprovedFixedAmountInterval.Value);
amount += (restamountperday * du.RestDays);
}
return amount;
}
public virtual decimal GetApprovedHoursForPeriod(SupportConceptCostBearerRelDC relDC,
DateTime pStart,
DateTime pEnd)
{
var costRatePeriods = relDC.CostBearer.CostRatePeriods;
decimal approvedHours = 0;
DateTime start = pStart;
DateTime end = pEnd;
while (start <= end)
{
var scap = relDC.ApprovalPeriodList.FirstOrDefault(i => start.InBetween(i.Span, true));
if (scap != null)
{
if (scap.EndDate.HasValue && scap.EndDate.Value < end)
end = scap.EndDate.Value;
var periodInDays = end.Subtract(start).Days + 1;
approvedHours += (this.GetApprovedHoursPerDay(scap, costRatePeriods) ?? 0) * periodInDays;
}
else
{
DateTime minStart = DateTime.MaxValue;
foreach (var period in relDC.ApprovalPeriodList)
{
if (period.StartDate.HasValue && period.EndDate.HasValue)
{
if (period.StartDate.Value > start && period.StartDate.Value <= pEnd && period.StartDate.Value < minStart)
{
minStart = period.StartDate.Value;
}
}
}
end = minStart.AddDays(-1);
}
start = end.AddDays(1);
end = pEnd;
}
return approvedHours;
}
public virtual decimal? GetApprovedHoursForPeriod(SupportConceptCostBearerRelDC relDC,
SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods,
DateTime? pStart,
DateTime? pEnd,
bool useIsCalculationWithFactor)
{
IList<AccountingPeriod> splittedPeriods = SplitPeriodsByRateFactors(scap, costRatePeriods, pStart, pEnd);
decimal? approvedTotal = null;
foreach (var ap in splittedPeriods)
{
decimal? approvedHours = GetApprovedHoursForPeriod(ap.SupportConceptApprovalPeriod, ap.CostRatesInPeriod, ap.PeriodStart, ap.PeriodEnd);
if (approvedHours.HasValue && useIsCalculationWithFactor)
{
DateTime dt = DateTime.Now;
if (ap.PeriodStart < dt)
{
dt = ap.PeriodStart;
}
approvedHours = ApplyIsCalculationWithFactor(relDC, approvedHours, dt);
}
if (approvedHours.HasValue)
{
if (!approvedTotal.HasValue)
{
approvedTotal = 0;
}
approvedTotal += approvedHours;
}
}
return approvedTotal;
}
public virtual IList<AccountingPeriod> SplitPeriodsByRateFactors(SupportConceptApprovalPeriodDC scap, List<CostRatePeriodDC> costRatePeriods, DateTime? start, DateTime? end)
{
List<AccountingPeriod> list = new List<AccountingPeriod>();
if (start.HasValue && end.HasValue)
{
var rateFactorList = costRatePeriods.GetSpans(CostRatePeriodType.RateFactor, start.Value, end.Value).ToList();
if (rateFactorList.Count > 1)
{
DateTime startTemp = start.Value;
DateTime endTemp = end.Value;
for (int i = 0; i < rateFactorList.Count; i++)
{
if (startTemp <= end.Value)
{
var crp = rateFactorList.ElementAt(i).Key;
if (crp.EndDate.HasValue && crp.EndDate.Value < endTemp)
endTemp = crp.EndDate.Value.Date;
var ap = CreateDefaultPeriod(scap, costRatePeriods, startTemp, endTemp);
if (crp.CostRateValue.HasValue)
ap.RateFactor = crp.CostRateValue.Value;
startTemp = endTemp.AddDays(1);
endTemp = end.Value;
list.Add(ap);
}
}
}
}
if (list.Count == 0)
{
list.Add(CreateDefaultPeriod(scap, costRatePeriods, start, end));
}
return list;
}
private AccountingPeriod CreateDefaultPeriod(SupportConceptApprovalPeriodDC scap, List<CostRatePeriodDC> costRatePeriods, DateTime? pStart, DateTime? pEnd)
{
var ap = new AccountingPeriod()
{
SupportConceptApprovalPeriod = scap,
CostRatesInPeriod = costRatePeriods
};
if (pStart.HasValue)
ap.PeriodStart = pStart.Value;
if (pEnd.HasValue)
ap.PeriodEnd = pEnd.Value;
return ap;
}
//Diese Methode überschreiben, wenn die bewilligten Stunden anders als Standard berechnet werden sollen (z.B. pro Monat 4.33 * Wochen)
public virtual decimal? GetApprovedHoursForPeriod(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods,
DateTime? pStart,
DateTime? pEnd)
{
if (!pStart.HasValue || !pEnd.HasValue)
{
return null;
}
if (scap.ApprovedBEInterval.HasValue && scap.ApprovedBEPerInterval.HasValue)
{
if (scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Monthly)
{
var months = GetTotalMonths(pStart.Value, pEnd.Value);
return months * scap.ApprovedBEPerInterval.Value;
}
else if (scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Quarterly)
{
var qs = GetTotalQuarters(pStart.Value, pEnd.Value);
return qs * scap.ApprovedBEPerInterval.Value;
}
}
var periodInDays = (pEnd.Value.Date - pStart.Value.Date).Days + 1;
return this.GetApprovedHoursPerDay(scap, costRatePeriods) * periodInDays;
}
public virtual decimal GetTotalMonths(DateTime start, DateTime end)
{
var am = DateTimeUtils.GetTotalMonths(start, end);
return am.AnzahlMonateGesamt;
}
public virtual decimal GetTotalQuarters(DateTime start, DateTime end)
{
int restTageStart = 0;
int restTageEnd = 0;
DateTime startDt = start;
DateTime endDt = end;
if (startDt.Day > 1)
{
var endMonat = new DateTime(startDt.Year, startDt.Month, 1).AddMonths(1).AddDays(-1);
if (endDt < endMonat)
{
endMonat = endDt;
}
restTageStart = endMonat.Subtract(startDt).Days + 1;
startDt = endMonat.AddDays(1);
}
DateTime startTemp = startDt;
int fullQuarters = 0;
while (startDt <= endDt)
{
startDt = startDt.AddMonths(3);
if (startDt <= endDt.AddDays(1))
{
startTemp = startDt;
fullQuarters++;
}
}
if (startTemp < endDt.AddDays(1))
{
restTageEnd = endDt.Subtract(startTemp).Days + 1;
}
decimal quartersTotal = fullQuarters;
if (restTageStart > 0)
{
quartersTotal += restTageStart / 90m;
}
if (restTageEnd > 0)
{
quartersTotal += restTageEnd / 90m;
}
return quartersTotal;
}
public virtual decimal? GetApprovedHoursPerDay(SupportConceptApprovalPeriodDC scap, List<CostRatePeriodDC> costRatePeriods)
{
if (!scap.EndDate.HasValue || !scap.StartDate.HasValue) // || scap.ApprovedFixedAmount.HasValue)
{
return null;
}
var serviceUnit = costRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.MinutesPerServiceUnit, scap.EndDate.Value);
if (scap.ApprovedBETotal.HasValue)
{
var scapDurationInDays = (scap.EndDate.Value - scap.StartDate.Value).Days + 1;
decimal approvedBEPerDay = 0;
if (scapDurationInDays != 0)
approvedBEPerDay = scap.ApprovedBETotal.Value / scapDurationInDays;
return serviceUnit.GetBEInMinutes(approvedBEPerDay) / 60m;
}
else if (scap.ApprovedBEPerInterval.HasValue)
{
decimal approvedBEPerDay = 0;
if (scap.ApprovedBEInterval.HasValue)
{
if (scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Yearly)
{
var totalDays = (scap.EndDate.Value - scap.StartDate.Value).Days + 1;
int totalYears = 0;
DateTime start = scap.StartDate.Value.AddYears(1);
//Anzahl Jahre ausrechnen. Nur wenn das Enddatum genau auf das Datum eines Jahres fällt
while (start <= scap.EndDate.Value.AddDays(1))
{
totalYears++;
start = start.AddYears(1);
if (start > scap.EndDate.Value.AddDays(1) && start != scap.EndDate.Value.AddDays(1).AddYears(1))
totalYears = 0;
}
if (totalYears > 0)
{
approvedBEPerDay = (scap.ApprovedBEPerInterval.Value * totalYears) / totalDays;
return serviceUnit.GetBEInMinutes(approvedBEPerDay) / 60m;
}
}
approvedBEPerDay = this.ConvertPerIntervall2PerDay(scap.ApprovedBEPerInterval.Value,
scap.ApprovedBEInterval.Value);
}
return serviceUnit.GetBEInMinutes(approvedBEPerDay) / 60m;
}
return null;
}
public virtual decimal? GetApprovedHoursPerDay(SupportConceptCostBearerRelDC relDC, DateTime date)
{
if (!relDC.GetApprovedDuration().HasValue)
{
return null;
}
var scap = relDC.ApprovalPeriodList.FirstOrDefault(i => date.InBetween(i.Span, true));
return scap != null
? this.GetApprovedHoursPerDay(scap, relDC.CostBearer.CostRatePeriods)
: null;
}
public virtual decimal? GetApprovedHoursPerWeek(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods)
{
if (scap.ApprovedBEPerInterval.HasValue && scap.ApprovedBEInterval.HasValue && scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Weekly)
{
DateTime dt = DateTime.Now;
if (scap.StartDate.HasValue && scap.StartDate.Value > dt)
{
dt = scap.StartDate.Value;
}
if (scap.EndDate.HasValue && scap.EndDate.Value < dt)
{
dt = scap.EndDate.Value;
}
var serviceUnit = costRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.MinutesPerServiceUnit, dt);
if (serviceUnit != null)
return serviceUnit.GetBEInHours(scap.ApprovedBEPerInterval);
}
return this.GetApprovedHoursPerDay(scap, costRatePeriods) * 7;
}
public virtual decimal? GetApprovedHoursPerWeek(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods, bool useIsCalculationWithFactor)
{
if (scap.ApprovedBEPerInterval.HasValue && scap.ApprovedBEInterval.HasValue && scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Weekly)
{
var serviceUnit = costRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.MinutesPerServiceUnit, DateTime.Now);
if (serviceUnit != null)
return serviceUnit.GetBEInHours(scap.ApprovedBEPerInterval);
}
return this.GetApprovedHoursPerDay(scap, costRatePeriods) * 7;
}
public virtual decimal? GetApprovedHoursPerWeek(SupportConceptCostBearerRelDC relDC, SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods, bool useIsCalculationWithFactor)
{
decimal? hoursPerWeek = GetApprovedHoursPerWeek(scap, costRatePeriods);
if (hoursPerWeek.HasValue && useIsCalculationWithFactor)
hoursPerWeek = ApplyIsCalculationWithFactor(relDC, scap, hoursPerWeek);
return hoursPerWeek;
}
public virtual decimal? GetApprovedHoursPerWeek(SupportConceptCostBearerRelDC relDC,
DateTime date)
{
return GetApprovedHoursPerWeek(relDC, date, true);
}
public virtual decimal? GetApprovedHoursPerWeek(SupportConceptCostBearerRelDC relDC,
DateTime date, bool useIsCalculationWithFactor)
{
if (!relDC.GetApprovedDuration().HasValue)
{
return null;
}
var scap = relDC.ApprovalPeriodList.FirstOrDefault(i => date.InBetween(i.Span, true));
decimal? hoursPerWeek = null;
if (scap != null)
{
hoursPerWeek = this.GetApprovedHoursPerWeek(scap, relDC.CostBearer.CostRatePeriods);
if (useIsCalculationWithFactor)
hoursPerWeek = ApplyIsCalculationWithFactor(relDC, hoursPerWeek);
}
return hoursPerWeek;
}
public virtual decimal? ApplyIsCalculationWithFactor(SupportConceptCostBearerRelDC relDC, SupportConceptApprovalPeriodDC scap, decimal? valueToApply)
{
DateTime dt = DateTime.Now;
if (scap.StartDate.HasValue && scap.StartDate.Value > dt)
{
dt = scap.StartDate.Value;
}
if (scap.EndDate.HasValue && scap.EndDate.Value < dt)
{
dt = scap.EndDate.Value;
}
return ApplyIsCalculationWithFactor(relDC, valueToApply, dt);
}
public virtual decimal? ApplyIsCalculationWithFactor(SupportConceptCostBearerRelDC relDC, decimal? valueToApply)
{
return ApplyIsCalculationWithFactor(relDC, valueToApply, DateTime.Now);
}
public virtual decimal? ApplyIsCalculationWithFactor(SupportConceptCostBearerRelDC relDC, decimal? valueToApply, DateTime date)
{
if (valueToApply.HasValue && relDC.CostBearer != null && relDC.CostBearer.IsCalculatingWithFactor)
{
if (relDC.CostBearer.CostRatePeriods != null)
{
decimal? rateFactor =
relDC.CostBearer.CostRatePeriods.GetValidRateValueForDate(CostRatePeriodType.RateFactor, date);
if (rateFactor.HasValue && rateFactor.Value > 0)
valueToApply = (valueToApply.Value * 100) / (rateFactor.Value + 100);
}
}
return valueToApply;
}
public virtual decimal? GetApprovedHoursPerWeekAverage(SupportConceptCostBearerRelDC relDC, bool useIsCalculationWithFactor)
{
var duration = relDC.GetApprovedDuration();
if (!duration.HasValue)
{
return null;
}
if (relDC.ApprovalPeriodList != null && relDC.ApprovalPeriodList.Count == 1)
{
decimal? hoursPerWeek = GetApprovedHoursPerWeek(relDC.ApprovalPeriodList[0], relDC.CostBearer.CostRatePeriods);
if (useIsCalculationWithFactor)
hoursPerWeek = ApplyIsCalculationWithFactor(relDC, hoursPerWeek);
return hoursPerWeek;
}
if (duration.Value.Days != 0)
{
var averagePerDay = this.GetApprovedHoursTotal(relDC, useIsCalculationWithFactor) / duration.Value.Days;
return averagePerDay * 7;
}
return null;
}
public virtual decimal? GetApprovedHoursTotal(SupportConceptCostBearerRelDC relDC, bool useIsCalculationWithFactor)
{
if (relDC.ApprovalPeriodList == null || !relDC.GetApprovedDuration().HasValue)
{
return null;
}
decimal? total = null;
foreach (var scap in relDC.ApprovalPeriodList)
{
IList<AccountingPeriod> splittedPeriods = SplitPeriodsByRateFactors(scap, relDC.CostBearer.CostRatePeriods, scap.StartDate, scap.EndDate);
foreach (var ap in splittedPeriods)
{
decimal? hours = this.GetApprovedHoursForPeriod(ap.SupportConceptApprovalPeriod, ap.CostRatesInPeriod, ap.PeriodStart, ap.PeriodEnd);
if (useIsCalculationWithFactor)
{
DateTime dt = DateTime.Now;
if (ap.PeriodStart < dt)
{
dt = ap.PeriodStart;
}
hours = ApplyIsCalculationWithFactor(relDC, hours, dt);
}
if (hours.HasValue)
{
if (!total.HasValue)
{
total = 0;
}
total += hours;
}
}
}
//decimal? hoursTotal = relDC.ApprovalPeriodList.Sum(i => this.GetApprovedHoursTotal(i, relDC.CostBearer.CostRatePeriods));
//if (useIsCalculationWithFactor)
// hoursTotal = ApplyIsCalculationWithFactor(relDC, hoursTotal);
if (total.HasValue)
total = Math.Round(total.Value, 10, MidpointRounding.AwayFromZero);
return total;
}
public virtual decimal? GetApprovedHoursTotal(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods)
{
IList<AccountingPeriod> splittedPeriods = SplitPeriodsByRateFactors(scap, costRatePeriods, scap.StartDate, scap.EndDate);
decimal? total = null;
foreach (var ap in splittedPeriods)
{
decimal? hours = this.GetApprovedHoursForPeriod(ap.SupportConceptApprovalPeriod, ap.CostRatesInPeriod, ap.PeriodStart, ap.PeriodEnd);
if (hours.HasValue)
{
if (!total.HasValue)
{
total = 0;
}
total += hours;
}
}
return total;
}
public virtual BillingData GetBillingData(ServiceRecordDC record)
{
BillingData data = new BillingData();
data.BillingPeriodStart = record.Start;
data.BillingPeriodEnd = record.End;
CostRatePeriodDC hourlyRate = null;
CostRatePeriodDC flatRate = null;
bool useRatefactor = true;
if (record.ServiceDescription.Category.IsBillable)
{
var crpList = record.ServiceDescription.CostRatePeriods;
var ai = record.ServiceDescription.AccountingInterval;
if (crpList.Count(c => c.CostRateValue.HasValue) == 0)
{
crpList = record.ServiceDescription.Category.CostRatePeriods;
ai = record.ServiceDescription.Category.AccountingInterval;
}
if (ai == null)
{
ai = AccountingIntervalType.Hourly;
}
if (crpList.Count(c => c.CostRateValue.HasValue) > 0)
{
CostRatePeriodDC crp = crpList.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney,
record.Start.Value);
if (ai.HasValue)
{
if (ai.Value == AccountingIntervalType.Hourly)
hourlyRate = crp;
else if (ai.Value == AccountingIntervalType.FlatRate)
flatRate = crp;
else if (ai.Value == AccountingIntervalType.Daily)
{
double days = 0;
if (data.BillingPeriodStart.HasValue && data.BillingPeriodEnd.HasValue)
{
days = data.BillingPeriodEnd.Value.Subtract(data.BillingPeriodStart.Value).Days + 1;
}
data.UnitCount = (decimal)days;
data.AmountPerUnit = crp.CostRateValue ?? 0;
data.AmountTotal = data.UnitCount * data.AmountPerUnit;
data.AccountingInterval = AccountingIntervalType.Daily;
data.GrossAmountTotal = data.AmountTotal;
return data;
}
else if (ai.Value == AccountingIntervalType.Monthly)
{
AnzahlMonate am = null;
data.UnitCount = 1;
if (data.BillingPeriodStart.HasValue && data.BillingPeriodEnd.HasValue)
{
am = DateTimeUtils.GetTotalMonths(data.BillingPeriodStart.Value, data.BillingPeriodEnd.Value);
decimal monate = Math.Ceiling(am.AnzahlMonateGesamt);
if (monate > data.UnitCount)
{
data.UnitCount = monate;
}
}
data.AmountPerUnit = crp.CostRateValue ?? 0;
data.AmountTotal = data.UnitCount * data.AmountPerUnit;
data.AccountingInterval = AccountingIntervalType.Monthly;
data.GrossAmountTotal = data.AmountTotal;
return data;
}
}
}
}
if (hourlyRate != null || flatRate != null)
useRatefactor = false;
if (flatRate != null)
{
if (record.DistanceInMeterDecimal.HasValue && record.DistanceInMeterDecimal.Value > 0)
{
data.UnitCount = record.DistanceInMeterDecimal.Value;
}
else
{
data.UnitCount = 1;
}
data.AmountPerUnit = flatRate.CostRateValue;
data.AmountTotal = data.UnitCount * data.AmountPerUnit;
data.AccountingInterval = AccountingIntervalType.FlatRate;
}
else
{
if (hourlyRate == null)
hourlyRate = this.GetHourlyRatePeriodForServiceRecord(record);
decimal rdMinutes = this.GetBillableDurationInMinutes(record, false);
data.UnitCount = rdMinutes / 60m;
if (hourlyRate != null)
{
var prozent = record.ServiceDescription.Category.Percentage;
if (record.ServiceDescription.ProzentAbrechnung.HasValue)
{
prozent = record.ServiceDescription.ProzentAbrechnung.Value;
}
data.AmountPerUnit = hourlyRate.CostRateValue * prozent / 100 ;
}
data.AmountTotal = data.AmountPerUnit * data.UnitCount;
data.AccountingInterval = AccountingIntervalType.Hourly;
}
if (useRatefactor)
{
var rateFactor =
record.CostBearer.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.RateFactor,
record.Start.Value);
if (rateFactor != null && rateFactor.CostRateValue.HasValue)
{
data.RateFactor = rateFactor.CostRateValue;
data.GrossAmountTotal = data.AmountTotal + (data.AmountTotal * rateFactor.CostRateValue / 100);
}
}
if (!data.GrossAmountTotal.HasValue)
data.GrossAmountTotal = data.AmountTotal;
return data;
}
public virtual decimal? GetBillableAmount(ServiceRecordDC record)
{
var rdMinutes = this.GetBillableDurationInMinutes(record, false);
var hourlyRate = this.GetHourlyRatePeriodForServiceRecord(record);
decimal amount = 0;
if (hourlyRate != null && hourlyRate.CostRateValue.HasValue)
amount = (rdMinutes / 60m) * hourlyRate.CostRateValue.Value;
var rateFactor = record.CostBearer.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.RateFactor, record.Start.Value);
if (rateFactor != null && rateFactor.CostRateValue.HasValue)
{
return amount + (amount * rateFactor.CostRateValue / 100);
}
return amount;
}
public virtual decimal GetBillableDurationInMinutes(ServiceRecordDC record)
{
return GetBillableDurationInMinutes(record, false);
}
public virtual decimal GetBillableDurationInMinutes(ServiceRecordDC record, bool useProzentAbrechenbar)
{
if (!record.ServiceDescription.Category.IsBillable)
{
return 0;
}
decimal rdMinutes = record.RoundedDuration;
//var prozent = record.ServiceDescription.Category.ProzentBudget ?? record.ServiceDescription.Category.Percentage;
//if (record.ServiceDescription.ProzentBudget.HasValue)
//{
// prozent = record.ServiceDescription.ProzentBudget.Value;
//}
decimal prozent = 100;
if (useProzentAbrechenbar)
{
if (record.ServiceDescription.ProzentAbrechnung.HasValue)
{
prozent = record.ServiceDescription.ProzentAbrechnung.Value;
}
else
{
prozent = record.ServiceDescription.Category.Percentage;
}
}
rdMinutes *= (prozent / 100);
if (record.GroupEmployeeCount.HasValue)
rdMinutes /= record.GroupEmployeeCount.Value;
return rdMinutes;
}
public virtual decimal GetDocumentedDurationInMinutes(ServiceRecordDC record, bool useProzentBudget)
{
if (!record.ServiceDescription.Category.IsBillable)
{
return 0;
}
decimal rdMinutes = record.RoundedDuration;
decimal prozent = 100;
if (useProzentBudget)
{
if (record.ServiceDescription.ProzentBudget.HasValue)
{
prozent = record.ServiceDescription.ProzentBudget.Value;
}
else
{
prozent = record.ServiceDescription.Category.Percentage;
}
}
rdMinutes *= (prozent / 100);
if (record.GroupEmployeeCount.HasValue)
rdMinutes /= record.GroupEmployeeCount.Value;
return rdMinutes;
}
//public virtual decimal GetBillableDurationInMinutes(ServiceRecordDC record)
//{
// if (!record.ServiceDescription.Category.IsBillable)
// {
// return 0;
// }
// decimal rdMinutes = record.RoundedDuration;
// var prozent = record.ServiceDescription.Category.ProzentBudget ?? record.ServiceDescription.Category.Percentage;
// if (record.ServiceDescription.ProzentBudget.HasValue)
// {
// prozent = record.ServiceDescription.ProzentBudget.Value;
// }
// rdMinutes *= (prozent / 100);
// if (record.GroupEmployeeCount.HasValue)
// rdMinutes /= record.GroupEmployeeCount.Value;
// return rdMinutes;
//}
//public virtual decimal GetBillableDurationInMinutes(ServiceRecordDC record)
//{
// if (!record.ServiceDescription.Category.IsBillable)
// {
// return 0;
// }
// decimal rdMinutes = record.RoundedDuration;
// decimal prozent = record.ServiceDescription.Category.ProzentBudget ?? record.ServiceDescription.Category.Percentage;
// if (record.ServiceDescription.ProzentBudget.HasValue)
// {
// prozent = record.ServiceDescription.ProzentBudget.Value;
// }
// rdMinutes *= (prozent / 100);
// if (record.GroupEmployeeCount.HasValue)
// rdMinutes /= record.GroupEmployeeCount.Value;
// return rdMinutes;
//}
public virtual decimal GetBillableDurationInMinutes(List<ServiceRecordDC> records)
{
return records.Sum(i => GetBillableDurationInMinutes(i, true));
}
public virtual decimal GetDocumentedDurationInMinutes(List<ServiceRecordDC> records) // Selbe wie GetBillableDurationInMinutes() aber mit ProzentBudget
{
return records.Sum(i => GetDocumentedDurationInMinutes(i, true));
}
public virtual decimal GetDurationInMinutesForBillableAmount(ServiceRecordDC record, decimal amount)
{
var hourlyRate = this.GetHourlyRatePeriodForServiceRecord(record);
var rateFactor = record.CostBearer.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.RateFactor, record.Start.Value);
if (rateFactor != null && rateFactor.CostRateValue.HasValue)
{
amount = (amount / (100 + rateFactor.CostRateValue.Value)) * 100;
}
if (hourlyRate != null && hourlyRate.CostRateValue.HasValue)
return (amount / hourlyRate.CostRateValue.Value) * 60m;
return 0;
}
public virtual CostRatePeriodDC GetHourlyRatePeriodForServiceRecord(ServiceRecordDC record)
{
var qualificationOIDs = record.Employee.ValueListEntries
.Where(i => i.Value == ValueListEntryType.StaffQualificationsType)
.Select(i => i.Key)
.ToList();
var qualificationHourlyRates = record.CostBearer.CostRatePeriods.Where(i =>
i.CostRateType == CostRatePeriodType.HourlyRate &&
i.ValueListEntry != null &&
i.ValueListEntry.Type == ValueListEntryType.StaffQualificationsType);
var matchingQualifications = qualificationHourlyRates
.Where(i => qualificationOIDs.Contains(i.ValueListEntry.ValueListEntryOid.Value))
.ToList();
var applyingQualificationRates = matchingQualifications
.GetCostRatePeriodForDateGroupedByValueListEntryOid(CostRatePeriodType.HourlyRate, record.Start.Value);
if (applyingQualificationRates.Count > 0)
{
var maxAmount = applyingQualificationRates.Max(i => i.Value.CostRateValue);
return applyingQualificationRates.First(i => i.Value.CostRateValue.Equals(maxAmount)).Value;
}
return record.CostBearer.CostRatePeriods
.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, record.Start.Value);
}
public virtual decimal GetHoursNotBillableDueToAbsenceTimes(SupportConceptCostBearerRelDC sc2cb,
List<ServiceRecordDC> records,
Dictionary<DateTimeSpan, decimal> absenceTimes,
bool doRemoveFromRecordsList,
bool doCrop)
{
return sc2cb.ApprovalPeriodList.Sum(i => this.GetHoursNotBillableDueToAbsenceTimes(i,
sc2cb.CostBearer.CostRatePeriods,
records,
absenceTimes,
doRemoveFromRecordsList,
doCrop));
}
public virtual decimal GetHoursNotBillableDueToAbsenceTimes(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRates,
List<ServiceRecordDC> records,
Dictionary<DateTimeSpan, decimal> absenceTimes,
bool doRemoveFromRecordsList,
bool doCrop)
{
if (scap.ApprovedFixedAmount.HasValue)
{
return 0m;
}
var hoursNotBillableAbsence = 0m;
foreach (var iRecord in records.ToList())
{
// falls mehrere Bewilligungen bestehen, dürfen Zeiterfassungeinträge nur einmal berücksichtigt werden!
if (!iRecord.Start.Value.InBetween(scap.Span, true))
{
continue;
}
var absenceSpan = absenceTimes.FirstOrDefault(i => iRecord.Start.Value.InBetween(i.Key, true)).Key;
if (absenceSpan != null)
{
var rd = this.GetBillableDurationInMinutes(iRecord, false);
if (absenceTimes[absenceSpan] == 0)
{
if (doRemoveFromRecordsList)
{
records.Remove(iRecord);
}
hoursNotBillableAbsence += rd / 60m;
continue;
}
if (absenceTimes[absenceSpan] - rd >= 0)
{
absenceTimes[absenceSpan] -= rd;
continue;
}
hoursNotBillableAbsence += (rd - absenceTimes[absenceSpan]) / 60;
if (!doCrop)
{
if (doRemoveFromRecordsList)
{
records.Remove(iRecord);
}
continue;
}
iRecord.End = iRecord.Start.Value.AddMinutes(Convert.ToDouble(absenceTimes[absenceSpan]));
var minuteInterval = costRates.GetCostRatePeriodForDate(CostRatePeriodType.MinutesIntervall, iRecord.Start.Value);
var duration = Convert.ToDecimal((iRecord.End - iRecord.Start).Value.TotalMinutes);
//###CB 5min
if (minuteInterval != null && minuteInterval.CostRateValue.HasValue && minuteInterval.CostRateValue.Value != 0)
{
iRecord.RoundedDuration = GetRoundedDuration((int)minuteInterval.CostRateValue.Value, duration);
}
else
{
iRecord.RoundedDuration = duration;
}
absenceTimes[absenceSpan] = 0;
}
}
return hoursNotBillableAbsence;
}
public virtual decimal GetHoursNotBillableDueToMoreThanApproved(SupportConceptCostBearerRelDC sc2cb,
List<ServiceRecordDC> records,
bool doRemoveFromRecordsList,
bool doCrop)
{
return sc2cb.ApprovalPeriodList.Sum(i => this.GetHoursNotBillableDueToMoreThanApproved(i,
sc2cb.CostBearer.CostRatePeriods,
records,
doRemoveFromRecordsList,
doCrop));
}
public virtual decimal GetHoursNotBillableDueToMoreThanApproved(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRates,
List<ServiceRecordDC> records,
bool doRemoveFromList,
bool doCrop)
{
if (scap.ApprovedFixedAmount.HasValue)
{
return 0m;
}
var approvedAmountCounter = this.GetApprovedAmountDefaultHourlyRate(scap, costRates) ?? 0m;
var hoursNotBillableNotApproved = 0m;
foreach (var iRecord in records.ToList())
{
if (!iRecord.Start.Value.InBetween(scap.Span, true))
{
if (doRemoveFromList)
{
records.Remove(iRecord);
}
continue;
}
var amount = this.GetBillableAmount(iRecord) ?? 0m;
if (approvedAmountCounter - amount >= 0)
{
approvedAmountCounter -= amount;
continue;
}
if (approvedAmountCounter == 0 || !doCrop)
{
if (doRemoveFromList)
{
records.Remove(iRecord);
}
hoursNotBillableNotApproved += this.GetBillableDurationInMinutes(iRecord, false) / 60m;
continue;
}
var oldDuration = this.GetBillableDurationInMinutes(iRecord, false);
iRecord.RoundedDuration = this.GetDurationInMinutesForBillableAmount(iRecord, approvedAmountCounter);
iRecord.End = iRecord.Start.Value.AddMinutes(Convert.ToInt32(iRecord.RoundedDuration));
hoursNotBillableNotApproved += (oldDuration - iRecord.RoundedDuration) / 60m;
approvedAmountCounter = 0;
}
return hoursNotBillableNotApproved;
}
public virtual decimal GetHoursNotBillableDueToOutOfSpan(SupportConceptCostBearerRelDC relDC, List<ServiceRecordDC> records)
{
decimal hoursOutOfSpan = 0m;
DateTimeSpan span = new DateTimeSpan();
span.StartDate = relDC.StartDate ?? DateTime.MinValue;
span.EndDate = relDC.EndDate ?? DateTime.MaxValue;
foreach (var iRecord in records)
{
if (!iRecord.Start.Value.InBetween(span, true))
{
hoursOutOfSpan += this.GetBillableDurationInMinutes(iRecord, true) / 60m;
}
}
return hoursOutOfSpan;
}
public virtual decimal GetMonthCount(DateTime startDate, DateTime endDate)
{
var am = DateTimeUtils.GetTotalMonths(startDate, endDate);
return am.AnzahlMonateGesamt;
}
public virtual decimal? GetApprovedHoursTillNow(SupportConceptCostBearerRelDC relDC, DateTime? appointedDate)
{
decimal? totalApproved = null;
if (relDC.ApprovalPeriodList != null)
{
if (relDC.ApprovalPeriodList.Count == 1)
{
decimal? flsTotal = GetApprovedHoursTotal(relDC, true);
decimal durationInWeeks = GetDurationInWeeks(relDC) ?? 0;
decimal durationInWeeksTillNow = GetDurationInWeeksTillNow(relDC, appointedDate) ?? 0;
if (flsTotal.HasValue && durationInWeeks != 0)
{
if (Math.Round(durationInWeeks, 10) == Math.Round(durationInWeeksTillNow, 10))
return flsTotal.Value;
totalApproved = flsTotal.Value * ((durationInWeeksTillNow + (1m / 7m)) / durationInWeeks);
}
else
{
var approvedPerWeek = GetApprovedHoursPerWeekAverage(relDC, true) ?? 0m;
totalApproved = approvedPerWeek * (durationInWeeksTillNow + (1m / 7m));
}
}
else if (relDC.ApprovalPeriodList.Count > 1)
{
DateTime calcDate = (appointedDate.HasValue && appointedDate.Value < DateTime.Now.Date)
? appointedDate.Value
: DateTime.Now.Date;
totalApproved = 0;
foreach (var period in relDC.ApprovalPeriodList)
{
if (period.StartDate.HasValue && period.EndDate.HasValue && calcDate >= period.StartDate)
{
var approvedHoursPerDay =
GetApprovedHoursPerDay(period, relDC.CostBearer.CostRatePeriods) ?? 0;
DateTime endDate = calcDate;
if (period.EndDate < endDate)
{
endDate = period.EndDate.Value;
}
decimal days = Convert.ToDecimal((endDate - period.StartDate.Value).Days + 1);
if (relDC.CostBearer.IsCalculatingWithFactor && relDC.CostBearer.CostRatePeriods != null)
{
var rateFactorsInSpan = relDC.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.RateFactor, period.StartDate.Value.Date, endDate).ToList();
if (rateFactorsInSpan.Count > 1)
{
days = 0; //Verhindere weitere Addition unten
foreach (var keyValuePair in rateFactorsInSpan)
{
var span = keyValuePair.Value;
var rf = keyValuePair.Key;
if (rf.CostRateValue.HasValue)
{
var spanDays = (span.EndDate - span.StartDate).Days + 1;
var approvedHoursPerDayRf = (approvedHoursPerDay * 100) / (rf.CostRateValue.Value + 100);
totalApproved += (spanDays * approvedHoursPerDayRf);
}
}
}
else if (rateFactorsInSpan.Count == 1)
{
decimal? rateFactor = rateFactorsInSpan[0].Key.CostRateValue;
if (rateFactor.HasValue && rateFactor.Value > 0)
approvedHoursPerDay = (approvedHoursPerDay * 100) / (rateFactor.Value + 100);
}
//decimal? rateFactor =
// relDC.CostBearer.CostRatePeriods.GetCurrentlyValidRateValue(CostRatePeriodType.RateFactor);
//if (rateFactor.HasValue && rateFactor.Value > 0)
// approvedHoursPerDay = (approvedHoursPerDay * 100) / (rateFactor.Value + 100);
}
totalApproved += (days * approvedHoursPerDay);
}
}
}
}
return totalApproved;
}
public virtual decimal? GetApprovedHoursTillNow(SupportConceptApprovalPeriodDC scap, List<CostRatePeriodDC> costRates, DateTime? appointedDate, bool excludeRateFactor)
{
decimal? totalApproved = null;
DateTime calcDate = (appointedDate.HasValue && appointedDate.Value < DateTime.Now.Date)
? appointedDate.Value
: DateTime.Now.Date;
if (scap.StartDate.HasValue && scap.EndDate.HasValue && calcDate >= scap.StartDate)
{
decimal days;
var approvedHoursPerDay =
GetApprovedHoursPerDay(scap, costRates) ?? 0;
if (excludeRateFactor)
{
decimal? rateFactor = costRates.GetCurrentlyValidRateValue(CostRatePeriodType.RateFactor);
if (rateFactor.HasValue && rateFactor.Value > 0)
approvedHoursPerDay = (approvedHoursPerDay * 100) / (rateFactor.Value + 100);
}
if (calcDate >= scap.EndDate.Value)
{
days = Convert.ToDecimal((scap.EndDate.Value - scap.StartDate.Value).Days + 1);
}
else
{
days = Convert.ToDecimal((calcDate - scap.StartDate.Value).Days + 1);
}
totalApproved = (days * approvedHoursPerDay);
}
return totalApproved;
}
#endregion
public virtual decimal? GetDurationInWeeks(SupportConceptCostBearerRelDC relDC)
{
if (relDC.StartDate != null && relDC.EndDate != null)
{
return Convert.ToDecimal((relDC.EndDate.Value - relDC.StartDate.Value).Days + 1) / 7;
}
return null;
}
public virtual decimal? GetDurationInWeeksTillNow(SupportConceptCostBearerRelDC relDC, DateTime? appointedDate)
{
if (relDC.StartDate != null && relDC.EndDate != null)
{
DateTime lCalcDate = (appointedDate.HasValue && appointedDate.Value < DateTime.Now.Date)
? appointedDate.Value
: DateTime.Now.Date;
lCalcDate = lCalcDate > relDC.EndDate
? relDC.EndDate.Value.Date.AddDays(1)
: lCalcDate;
return Convert.ToDecimal((lCalcDate - relDC.StartDate.Value).Days) / 7m;
}
return null;
}
public virtual IList<BillingData> GetFixedBillingData(SupportConceptApprovalPeriodDC supportConceptApprovalPeriod, DateTime? start, DateTime? end)
{
IList<BillingData> billingDatas = new List<BillingData>();
DateTime? dtStart = start ?? supportConceptApprovalPeriod.StartDate;
DateTime? dtEnd = end ?? supportConceptApprovalPeriod.EndDate;
if (dtStart.HasValue && dtEnd.HasValue)
{
decimal amountPerUnit;
decimal unitCount;
decimal? approvalPeriodFixedAmount = GetApprovedFixedAmountForPeriod(supportConceptApprovalPeriod, dtStart, dtEnd, out amountPerUnit, out unitCount);
if (approvalPeriodFixedAmount.HasValue)
{
billingDatas.Add(new BillingData()
{
AmountTotal = approvalPeriodFixedAmount,
GrossAmountTotal = approvalPeriodFixedAmount,
BillingPeriodStart = dtStart,
BillingPeriodEnd = dtEnd,
AccountingInterval = AccountingIntervalType.FlatRate,
AmountPerUnit = amountPerUnit,
UnitCount = unitCount
});
}
else if (supportConceptApprovalPeriod.ServiceCategory != null)
{
var crpList = supportConceptApprovalPeriod.ServiceCategory.CostRatePeriods;
var ai = supportConceptApprovalPeriod.ServiceCategory.AccountingInterval;
if (ai.HasValue)
{
DateTime intervalStart = dtStart.Value;
DateTime intervalEnd = dtStart.Value;
while (intervalStart <= dtEnd)
{
switch (ai.Value)
{
case AccountingIntervalType.Daily:
intervalEnd = intervalStart.AddDays(1);
break;
case AccountingIntervalType.Weekly:
intervalEnd = intervalStart.AddDays(7);
break;
case AccountingIntervalType.Fortnightly:
intervalEnd = intervalStart.AddDays(14);
break;
case AccountingIntervalType.Monthly:
intervalEnd = intervalStart.AddMonths(1);
break;
case AccountingIntervalType.Quarterly:
intervalEnd = intervalStart.AddMonths(3);
break;
case AccountingIntervalType.HalfYearly:
intervalEnd = intervalStart.AddMonths(6);
break;
case AccountingIntervalType.Yearly:
intervalEnd = intervalStart.AddYears(1);
break;
case AccountingIntervalType.FlatRate:
intervalEnd = dtEnd.Value.AddDays(1);
break;
default:
intervalEnd = dtEnd.Value.AddDays(1);
break;
}
CostRatePeriodDC crp = crpList.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney,
intervalStart);
if (crp != null && crp.CostRateValue.HasValue)
{
billingDatas.Add(new BillingData()
{
AmountTotal = crp.CostRateValue,
GrossAmountTotal = crp.CostRateValue,
BillingPeriodStart = intervalStart,
BillingPeriodEnd = intervalEnd.AddDays(-1),
AccountingInterval = ai
});
}
intervalStart = intervalEnd;
}
}
}
}
return billingDatas;
}
public virtual List<AccountingPeriod> GetAccountingPeriods(SupportConceptCostBearerRelDC relDC, List<ServiceRecordDC> recordDCS, DateTimeSpan span)
{
Dictionary<long, bool> groupBookingDict = new Dictionary<long, bool>();
List<AccountingPeriod> apList = new List<AccountingPeriod>();
Dictionary<AccountingPeriod, AccountingPeriod> ap2apDict = new Dictionary<AccountingPeriod, AccountingPeriod>();
foreach (var sr in recordDCS)
{
if (sr.ServiceDescription.Category.IsBillable && sr.Start.HasValue)
{
if (sr.GroupOid == null || !groupBookingDict.ContainsKey(sr.GroupOid.Value))
{
AccountingPeriod ap = GetAccountingPeriodForServiceRecord(relDC, sr, span);
if (ap != null)
{
if (ap2apDict.ContainsKey(ap))
{
ap2apDict[ap].ServiceRecordsInPeriod.Add(sr);
}
else
{
ap2apDict.Add(ap, ap);
apList.Add(ap);
}
}
if (sr.GroupOid != null && !groupBookingDict.ContainsKey(sr.GroupOid.Value))
{
groupBookingDict.Add(sr.GroupOid.Value, true);
}
}
}
}
return apList;
}
public virtual AccountingPeriod GetAccountingPeriodForServiceRecord(SupportConceptCostBearerRelDC relDC, ServiceRecordDC sr, DateTimeSpan span)
{
CostRatePeriodDC stundensatzCrp = null;
CostRatePeriodDC previousStundensatzCrp = null;
AccountingIntervalType intervalType = AccountingIntervalType.Hourly;
ServiceCategoryDC category = null;
var scap = FindApprovalPeriodForDateAndCategory(relDC, sr.Start.Value,
sr.ServiceDescription.Category);
if (scap != null)
{
category = scap.ServiceCategory;
stundensatzCrp =
sr.ServiceDescription.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney,
sr.Start.Value);
if (stundensatzCrp != null)
{
previousStundensatzCrp = GetPreviousCrp(stundensatzCrp, sr.ServiceDescription.CostRatePeriods);
intervalType = sr.ServiceDescription.AccountingInterval ?? AccountingIntervalType.Hourly;
category = sr.ServiceDescription.Category;
}
else
{
stundensatzCrp =
sr.ServiceDescription.Category.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney,
sr.Start.Value);
if (stundensatzCrp != null)
{
previousStundensatzCrp = GetPreviousCrp(stundensatzCrp, sr.ServiceDescription.Category.CostRatePeriods);
intervalType = sr.ServiceDescription.Category.AccountingInterval ??
AccountingIntervalType.Hourly;
category = sr.ServiceDescription.Category;
}
}
if (stundensatzCrp == null)
{
if (scap.ApprovedFixedAmount.HasValue && scap.ApprovedFixedAmountInterval.HasValue)
{
stundensatzCrp = new CostRatePeriodDC();
stundensatzCrp.CostRateValue = scap.ApprovedFixedAmount.Value;
stundensatzCrp.CostRateType = CostRatePeriodType.AmountOfMoney;
intervalType = ConvertApprovalToAccountingIntervalType(scap.ApprovedFixedAmountInterval.Value);
}
}
if (stundensatzCrp == null)
{
stundensatzCrp = relDC.CostBearer.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate,
sr.Start.Value);
previousStundensatzCrp = GetPreviousCrp(stundensatzCrp, relDC.CostBearer.CostRatePeriods);
}
if (stundensatzCrp != null)
{
CostRatePeriodDC rateFactor = relDC.CostBearer.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.RateFactor,
sr.Start.Value);
CostRatePeriodDC previousRateFactor = null;
if (rateFactor != null)
{
previousRateFactor = GetPreviousCrp(rateFactor, relDC.CostBearer.CostRatePeriods);
}
CostRatePeriodDC unit = relDC.CostBearer.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.MinutesPerServiceUnit,
sr.Start.Value);
AccountingPeriod ap = new AccountingPeriod();
ap.PeriodStart = scap.StartDate ?? DateTime.MinValue;
ap.PeriodEnd = scap.EndDate ?? DateTime.MaxValue;
if (span != null)
{
if (span.StartDate > ap.PeriodStart)
ap.PeriodStart = span.StartDate;
if (span.EndDate < ap.PeriodEnd)
ap.PeriodEnd = span.EndDate;
}
ap.Amount = stundensatzCrp.CostRateValue ?? 0;
ap.AccountingInterval = intervalType;
ap.ServiceCategory = category;
ap.ServiceRecordsInPeriod.Add(sr);
ap.CostRatesInPeriod = new List<CostRatePeriodDC>();
ap.CostRatesInPeriod.Add(stundensatzCrp);
if (stundensatzCrp.EndDate.HasValue && stundensatzCrp.EndDate.Value.Date < ap.PeriodEnd.Date)
ap.PeriodEnd = stundensatzCrp.EndDate.Value;
if (rateFactor != null && rateFactor.EndDate.HasValue && rateFactor.EndDate.Value.Date < ap.PeriodEnd.Date)
ap.PeriodEnd = rateFactor.EndDate.Value;
if (previousStundensatzCrp != null && previousStundensatzCrp.EndDate.HasValue && previousStundensatzCrp.EndDate.Value.Date >= ap.PeriodStart.Date)
{
ap.PeriodStart = previousStundensatzCrp.EndDate.Value.Date.AddDays(1);
}
if (previousRateFactor != null && previousRateFactor.EndDate.HasValue && previousRateFactor.EndDate.Value.Date >= ap.PeriodStart.Date)
{
ap.PeriodStart = previousRateFactor.EndDate.Value.Date.AddDays(1);
}
if (rateFactor != null)
{
ap.CostRatesInPeriod.Add(rateFactor);
ap.RateFactor = rateFactor.CostRateValue ?? 0;
}
if (unit != null)
{
ap.CostRatesInPeriod.Add(unit);
ap.UnitName = unit.UnitName;
}
CalculateApprovedAmounts(ap, scap);
if (sr.ServiceDescription.Category.Name.ToLower().Contains("fehlkontakt") || sr.ServiceDescription.Name.ToLower().Contains("fehlkontakt")
|| (sr.ServiceDescription.ProzentAbrechnung.HasValue && sr.ServiceDescription.ProzentAbrechnung.Value < 100 && sr.ServiceDescription.ProzentAbrechnung.Value > 0))
{
ap.Notice = "Fehlkontakte";
ap.RateFactor = 0;
}
return ap;
}
}
return null;
}
private CostRatePeriodDC GetPreviousCrp(CostRatePeriodDC crp, List<CostRatePeriodDC> allCrpList)
{
if (allCrpList == null || crp == null)
{
return null;
}
var oldList = allCrpList.GetOldRates(crp.CostRateType).OrderBy(i => i.EndDate);
if (!crp.EndDate.HasValue)
return oldList.LastOrDefault(c => c.EndDate.HasValue);
else
return oldList.LastOrDefault(c => c.EndDate < crp.EndDate);
}
public virtual void CalculateApprovedAmounts(AccountingPeriod ap, SupportConceptApprovalPeriodDC scap)
{
ap.SupportConceptApprovalPeriod = scap;
if (scap.ApprovedBETotal.HasValue)
{
if (scap.ApprovedBEPerInterval.HasValue && scap.ApprovedBEInterval.HasValue && scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Weekly)
{
ap.ApprovedPerUnit = scap.ApprovedBEPerInterval.Value;
ap.ApprovalUnit = AccountingIntervalType.Weekly;
}
else
{
ap.ApprovedPerUnit = scap.ApprovedBETotal.Value;
ap.ApprovalUnit = AccountingIntervalType.FlatRate;
}
}
else if (scap.ApprovedBEPerInterval.HasValue && scap.ApprovedBEInterval.HasValue)
{
ap.ApprovedPerUnit = scap.ApprovedBEPerInterval.Value;
switch (scap.ApprovedBEInterval.Value)
{
case SupportConceptApprovalInterval.Daily:
ap.ApprovalUnit = AccountingIntervalType.Daily;
break;
case SupportConceptApprovalInterval.Weekly:
ap.ApprovalUnit = AccountingIntervalType.Weekly;
break;
case SupportConceptApprovalInterval.Fortnightly:
ap.ApprovalUnit = AccountingIntervalType.Fortnightly;
break;
case SupportConceptApprovalInterval.Monthly:
ap.ApprovalUnit = AccountingIntervalType.Monthly;
break;
case SupportConceptApprovalInterval.Quarterly:
ap.ApprovalUnit = AccountingIntervalType.Quarterly;
break;
case SupportConceptApprovalInterval.HalfYearly:
ap.ApprovalUnit = AccountingIntervalType.HalfYearly;
break;
case SupportConceptApprovalInterval.Yearly:
ap.ApprovalUnit = AccountingIntervalType.Yearly;
break;
case SupportConceptApprovalInterval.Hourly:
ap.ApprovalUnit = AccountingIntervalType.Hourly;
break;
}
}
//ap.MaxApprovedAmount = GetApprovedAmount(ap, scap);
ap.MaxApprovedUnitCount = GetApprovedBETotalInPeriod(scap, ap.CostRatesInPeriod, ap.PeriodStart, ap.PeriodEnd);
//var test2 = GetApprovedAmountDefaultHourlyRate(scap, ap.CostRatesInPeriod);
//var test3 = GetApprovedAmountDefaultHourlyRateForPeriod(scap, ap.CostRatesInPeriod, ap.PeriodStart, ap.PeriodEnd);
//var test4 = GetApprovedFixedAmount(scap);
//var test5 = GetApprovedFixedAmountForPeriod(scap, ap.PeriodStart, ap.PeriodEnd);
if (scap.ApprovedFixedAmount.HasValue)
{
ap.MaxApprovedAmount = scap.ApprovedFixedAmount.Value;
}
}
public virtual decimal? GetApprovedAmount(AccountingPeriod ap, SupportConceptApprovalPeriodDC scap)
{
decimal t1, t2;
return scap.ApprovedFixedAmount.HasValue
? this.GetApprovedFixedAmountForPeriod(scap, ap.PeriodStart, ap.PeriodEnd, out t1, out t2)
: this.GetApprovedAmountDefaultHourlyRateForPeriod(scap, ap.CostRatesInPeriod, ap.PeriodStart, ap.PeriodEnd);
}
public virtual decimal? GetApprovedBETotalInPeriod(SupportConceptApprovalPeriodDC scap,
List<CostRatePeriodDC> costRatePeriods,
DateTime start, DateTime end)
{
IList<AccountingPeriod> splittedPeriods = SplitPeriodsByRateFactors(scap, costRatePeriods, start, end);
decimal? approvedTotal = null;
foreach (var ap in splittedPeriods)
{
decimal? approvedHours = GetApprovedHoursForPeriod(ap.SupportConceptApprovalPeriod, ap.CostRatesInPeriod, ap.PeriodStart, ap.PeriodEnd);
if (approvedHours.HasValue)
{
if (!approvedTotal.HasValue)
{
approvedTotal = 0;
}
approvedTotal += approvedHours;
}
}
return costRatePeriods.GetCurrentlyValidRate(CostRatePeriodType.MinutesPerServiceUnit).GetHoursInBE(approvedTotal);
}
public virtual int GetRoundedDuration(DataContracts.Compact.CompactOrganisationDC org, decimal durationInMinutes)
{
int minuteInterval = org.ActualMinuteIntervall;
return GetRoundedDuration(minuteInterval, durationInMinutes);
}
public virtual int GetRoundedDuration(DataContracts.Compact.CompactOrganisationDC org, DateTime date, decimal durationInMinutes)
{
int minuteInterval = org.ActualMinuteIntervall;
var crv = org.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.MinutesIntervall, date);
if (crv != null && crv.CostRateValue.HasValue)
{
minuteInterval = (int)crv.CostRateValue.Value;
}
return GetRoundedDuration(minuteInterval, durationInMinutes);
}
public virtual int GetRoundedDuration(int minuteInterval, decimal durationInMinutes)
{
decimal lRoundedDuration = durationInMinutes;
if (minuteInterval > 0)
{
lRoundedDuration = durationInMinutes % minuteInterval != 0
? durationInMinutes + (minuteInterval - (durationInMinutes % minuteInterval))
: durationInMinutes;
}
return (int)Math.Round(lRoundedDuration, 0, MidpointRounding.AwayFromZero);
}
public static AccountingIntervalType ConvertApprovalToAccountingIntervalType(SupportConceptApprovalInterval supportConceptApprovalInterval)
{
switch (supportConceptApprovalInterval)
{
case SupportConceptApprovalInterval.Daily:
return AccountingIntervalType.Daily;
case SupportConceptApprovalInterval.Weekly:
return AccountingIntervalType.Weekly;
case SupportConceptApprovalInterval.Fortnightly:
return AccountingIntervalType.Fortnightly;
case SupportConceptApprovalInterval.Monthly:
return AccountingIntervalType.Monthly;
case SupportConceptApprovalInterval.Quarterly:
return AccountingIntervalType.Quarterly;
case SupportConceptApprovalInterval.HalfYearly:
return AccountingIntervalType.HalfYearly;
case SupportConceptApprovalInterval.Hourly:
return AccountingIntervalType.Hourly;
default:
return AccountingIntervalType.Yearly;
}
}
public virtual Dictionary<DateTimeSpan, decimal> GetAbsencesTimesNotBillable(IList<AbsenceTimeDC> absenceTimeDcs)
{
var lResult = new Dictionary<DateTimeSpan, decimal>();
foreach (AbsenceTimeDC at in absenceTimeDcs)
{
DateTimeSpan span = new DateTimeSpan();
if (at.Start.HasValue && at.Start.Value <= DateTime.MaxValue.AddDays(-1))
{
span.StartDateTime = at.Start.Value.AddDays(1).Date;
}
if (at.End.HasValue && at.End.Value > DateTime.MinValue.AddDays(1))
{
span.EndDateTime = at.End.Value.AddDays(-1).Date;
}
else
{
span.EndDateTime = DateTime.MaxValue;
;
}
IEnumerable<DateTimeSpan> weeks = GetAbsenceWeeks(span);
foreach (DateTimeSpan weekSpan in weeks)
{
if (at.Reason.BillableMinutes.HasValue && at.Reason.BillableMinutes.Value > 0 && !lResult.ContainsKey(weekSpan))
{
lResult.Add(weekSpan, at.Reason.BillableMinutes.Value);
}
}
}
return lResult;
}
public virtual IEnumerable<DateTimeSpan> GetAbsenceWeeks(DateTimeSpan span)
{
var lResult = new List<DateTimeSpan>();
DateTime startDate = span.StartDate;
DateTime endDate = span.StartDate;
if (span.StartDate < DateTime.MaxValue.AddDays(-6))
{
endDate = span.StartDate.AddDays(6);
}
DateTime totalEnddate = span.EndDate;
if (totalEnddate == DateTime.MaxValue.Date && span.StartDate < DateTime.MaxValue.AddYears(-1))
totalEnddate = span.StartDate.AddYears(1);
while (startDate <= totalEnddate && startDate < DateTime.MaxValue)
{
var lCurrentWorkWeek = new DateTimeSpan
{
StartDateTime = startDate,
EndDateTime = endDate
};
if (lCurrentWorkWeek.EndDateTime > totalEnddate)
{
lCurrentWorkWeek.EndDateTime = totalEnddate;
}
lResult.Add(lCurrentWorkWeek);
if (endDate < DateTime.MaxValue.Date.AddDays(-7))
{
startDate = endDate.AddDays(1);
endDate = startDate.AddDays(6);
}
else
{
startDate = DateTime.MaxValue;
}
}
return lResult;
}
}
}