1347 lines
47 KiB
C#
1347 lines
47 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using BeWo.Service.Plugins;
|
|
using BS.Shared;
|
|
using BS.Shared.Core;
|
|
using BS.Shared.DataContracts;
|
|
using BS.Shared.DataContracts.Compact;
|
|
using BS.Shared.Extensions;
|
|
using BS.Shared.Services;
|
|
using BeWo.Data;
|
|
using BeWo.Data.Access;
|
|
using BeWo.Data.Entities;
|
|
using BeWo.Service.Core;
|
|
using BeWo.Service.DCEntityMapper;
|
|
|
|
namespace BeWo.Service.Invoicing
|
|
{
|
|
public class SettlementInvoiceCreation : AbstractIDSpecificDefaultClass<SettlementInvoiceCreation>
|
|
{
|
|
|
|
public virtual Settlement2DC GenerateSettlementInvoice(CostBearer2SupportConcept c2s, DateTime? periodStart, DateTime? periodEnd)
|
|
{
|
|
Settlement2DC settlementInvoice = new Settlement2DC();
|
|
|
|
settlementInvoice.CostBearer2SupportConceptOid = c2s.Oid;
|
|
settlementInvoice.CustomerReferenceNumber = c2s.CustomerReferenceNumber;
|
|
settlementInvoice.InvoiceDate = DateTime.Now.Date;
|
|
settlementInvoice.ServiceUnit = MapperFactory.CostRatePeriodDC_CostRatePeriod.MapToNewDCs(c2s.CostBearer.CostRatePeriods)
|
|
.GetCostRatePeriodForDate(CostRatePeriodType.MinutesPerServiceUnit, DateTime.Now);
|
|
if (settlementInvoice.ServiceUnit == null)
|
|
{
|
|
settlementInvoice.ServiceUnit = new CostRatePeriodDC();
|
|
settlementInvoice.ServiceUnit.CostRateType = CostRatePeriodType.MinutesPerServiceUnit;
|
|
settlementInvoice.ServiceUnit.UnitName = "FLS";
|
|
settlementInvoice.ServiceUnit.CostRateValue = 60;
|
|
|
|
}
|
|
|
|
if (String.IsNullOrEmpty(settlementInvoice.InvoiceNumber))
|
|
{
|
|
var inc = PluginLoader.FindClass<InvoiceNumberGenerator>();
|
|
settlementInvoice.InvoiceNumber = inc.GetNextInvoiceNumber(0, settlementInvoice);
|
|
}
|
|
|
|
if (periodStart.HasValue && periodEnd.HasValue)
|
|
{
|
|
settlementInvoice.AccountingPeriodStart = periodStart;
|
|
settlementInvoice.AccountingPeriodEnd = periodEnd;
|
|
}
|
|
else
|
|
{
|
|
settlementInvoice.AccountingPeriodStart = c2s.StartDate;
|
|
settlementInvoice.AccountingPeriodEnd = c2s.EndDate;
|
|
|
|
}
|
|
|
|
|
|
CreateSenderInformation(settlementInvoice);
|
|
CreateRecipientInformation(settlementInvoice, c2s);
|
|
|
|
|
|
if (CanCreateInvoiceTheOldWay(settlementInvoice, c2s))
|
|
CreateInvoiceDetailsTheOldWay(settlementInvoice, c2s);
|
|
else
|
|
CreateInvoiceDetails(settlementInvoice, c2s, periodStart, periodEnd);
|
|
|
|
if (settlementInvoice.InvoiceItems == null || settlementInvoice.InvoiceItems.Count == 0)
|
|
{
|
|
settlementInvoice.InvoiceItems = new List<InvoiceItemDC>();
|
|
settlementInvoice.InvoiceItems.Add(
|
|
new InvoiceItemDC
|
|
{
|
|
AmountTotal = settlementInvoice.Claim,
|
|
ItemPeriodStart = settlementInvoice.AccountingPeriodStart,
|
|
ItemPeriodEnd = settlementInvoice.AccountingPeriodEnd,
|
|
ItemDescription = "Spitzabrechnung"
|
|
});
|
|
}
|
|
return settlementInvoice;
|
|
}
|
|
|
|
public virtual IList<ServiceRecord> GetBillableServiceRecords(CostBearer2SupportConcept c2s)
|
|
{
|
|
return c2s.ServiceRecords;
|
|
}
|
|
|
|
|
|
|
|
public virtual bool CanCreateInvoiceTheOldWay(Settlement2DC si, CostBearer2SupportConcept c2s)
|
|
{
|
|
//Die alte Methode funktioniert nicht mehr wenn
|
|
//1. Es mehr als drei Stundensätze gibt
|
|
//2. Es mehr als einen Faktor gibt
|
|
//3. Mindestens einem Bewilligungszeitraum eine Kategorie zugeordnet ist
|
|
//4. Wenn sich Bewilligungszeiträume überscheiden
|
|
//5. ServiceRecords einer ServiceDescription/Category mit Stundensätzen zugeordnet sind
|
|
//In allen anderen Fällen wird die alte Methode noch verwendet, das sonst alle Kundenrechnungsformulare angepasst werden müssten.
|
|
|
|
//Prüfe 1:
|
|
var relDC = c2s.MapToNewDC();
|
|
|
|
|
|
DateTime start = si.AccountingPeriodStart.Value.Date;
|
|
DateTime end = si.AccountingPeriodEnd.Value.Date;
|
|
if (c2s.SupportConcept.Customer.TerminationDate.HasValue &&
|
|
c2s.SupportConcept.Customer.TerminationDate.Value < end)
|
|
{
|
|
end = c2s.SupportConcept.Customer.TerminationDate.Value;
|
|
}
|
|
if (end > DateTime.Now)
|
|
{
|
|
var srList = c2s.ServiceRecords;
|
|
|
|
var max = srList.Max(s => s.End);
|
|
|
|
if (max.HasValue && max < end)
|
|
{
|
|
end = max.Value;
|
|
}
|
|
}
|
|
var hourlyRatesInSpanList = relDC.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.HourlyRate, start, end).ToList();
|
|
if (hourlyRatesInSpanList.Count > 3)
|
|
return false;
|
|
|
|
var factorInSpanList = relDC.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.RateFactor, start, end).ToList();
|
|
if (factorInSpanList.Count > 1)
|
|
return false;
|
|
|
|
|
|
//Prüfe 3
|
|
//for (int i = 0; i < c2s.ApprovalPeriodList.Count - 1; i++)
|
|
//{
|
|
// var ap1 = c2s.ApprovalPeriodList[i];
|
|
|
|
// if (ap1.StartDate.HasValue && ap1.EndDate.HasValue)
|
|
// {
|
|
// for (int j = i + 1; j < c2s.ApprovalPeriodList.Count; j++)
|
|
// {
|
|
// var ap2 = c2s.ApprovalPeriodList[j];
|
|
// if (ap2.StartDate.HasValue && ap2.EndDate.HasValue)
|
|
// {
|
|
// if (ap1.EndDate >= ap2.StartDate && ap1.StartDate <= ap2.EndDate)
|
|
// return false;
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
//Prüfe 2
|
|
foreach (var ap in c2s.ApprovalPeriodList)
|
|
{
|
|
if (ap.ServiceCategory != null && ap.ServiceCategory.IsActive == ActivationTypeId.Active)
|
|
{
|
|
if (ap.ServiceCategory.CostRatePeriods != null && ap.ServiceCategory.CostRatePeriods.Count > 0)
|
|
{
|
|
foreach (var costRatePeriod in ap.ServiceCategory.CostRatePeriods)
|
|
{
|
|
if (costRatePeriod.CostRateValue.HasValue && costRatePeriod.CostRateValue.Value > 0)
|
|
return false;
|
|
}
|
|
}
|
|
var sdList = DAOFactory.SearchDAO.FindServiceDescriptionForCategory(ap.ServiceCategory.Oid.Value);
|
|
foreach (var sd in sdList)
|
|
{
|
|
if (sd.CostRatePeriods.Count > 0)
|
|
{
|
|
foreach (var costRatePeriod in sd.CostRatePeriods)
|
|
{
|
|
if (costRatePeriod.CostRateValue.HasValue && costRatePeriod.CostRateValue.Value > 0)
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Prüfe 4
|
|
foreach (var sr in GetBillableServiceRecords(c2s))
|
|
{
|
|
if (IsServiceRecordBillable(sr) && sr.DurationMinutes > 0)
|
|
{
|
|
if (sr.ServiceDescription.CostRatePeriods.Count > 0)
|
|
{
|
|
foreach (var costRatePeriod in sr.ServiceDescription.CostRatePeriods)
|
|
{
|
|
if (costRatePeriod.CostRateValue.HasValue && costRatePeriod.CostRateValue.Value > 0)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (sr.ServiceDescription.ServiceCategory.CostRatePeriods.Count > 0)
|
|
{
|
|
foreach (var costRatePeriod in sr.ServiceDescription.ServiceCategory.CostRatePeriods)
|
|
{
|
|
if (costRatePeriod.CostRateValue.HasValue && costRatePeriod.CostRateValue.Value > 0)
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
public virtual 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<Calculations>(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<DateTimeSpan, decimal> 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<long, bool> groupBookingDict = new Dictionary<long, bool>();
|
|
|
|
decimal flsCleared = 0;
|
|
records =
|
|
records.OrderBy<ServiceRecord, DateTime>(sr => sr.Start.HasValue ? sr.Start.Value : DateTime.MinValue)
|
|
.ToList<ServiceRecord>();
|
|
|
|
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))
|
|
{
|
|
decimal rd = iRecord.RoundedDuration;
|
|
if (iRecord.ServiceDescription.ServiceCategory.Percentage != 100)
|
|
{
|
|
rd = (rd*iRecord.ServiceDescription.ServiceCategory.Percentage)/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;
|
|
|
|
}
|
|
|
|
public virtual bool CheckMaxApprovedHours()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public virtual bool IsServiceRecordBillable(ServiceRecord iRecord)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public virtual decimal? CalculateMaxAmount(Settlement2DC si)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public virtual void CreateInvoiceDetails(Settlement2DC si, CostBearer2SupportConcept c2s, DateTime? periodStart,
|
|
DateTime? periodEnd)
|
|
{
|
|
var calc = PluginLoader.FindClass<Calculations>(_SpecificID) ?? Calculations.GetInstance(_SpecificID);
|
|
|
|
var records = GetBillableServiceRecords(c2s);
|
|
|
|
DateTimeSpan span = null;
|
|
if (periodStart.HasValue && periodEnd.HasValue)
|
|
{
|
|
span = new DateTimeSpan();
|
|
span.StartDateTime = periodStart.Value;
|
|
span.EndDateTime = periodEnd.Value;
|
|
|
|
records =
|
|
records.Where(
|
|
i => i.Start.HasValue && i.Start.Value.InBetween(periodStart.Value, periodEnd.Value, true))
|
|
.ToList();
|
|
|
|
}
|
|
|
|
foreach (var sr in records)
|
|
{
|
|
if (sr.GroupOid.HasValue)
|
|
{
|
|
si.HasGroupRecords = true;
|
|
}
|
|
}
|
|
|
|
var recordDCS = records.MapToNewDCsCompact();
|
|
var relDC = c2s.MapToNewDC();
|
|
|
|
CalculateSettlementInvoiceApprovedAmounts(si, relDC, calc);
|
|
|
|
var accountingPeriods = calc.GetAccountingPeriods(relDC, recordDCS, span);
|
|
|
|
foreach (var ap in accountingPeriods)
|
|
{
|
|
|
|
if (ap.SupportConceptApprovalPeriod != null && !ap.SupportConceptApprovalPeriod.ApprovedBETotal.HasValue)
|
|
{
|
|
ap.SupportConceptApprovalPeriod.ApprovedBETotal = si.ApprovedFLS;
|
|
}
|
|
}
|
|
si.InvoiceItems = CreateInvoiceItemsForAccountingPeriods(si, accountingPeriods, relDC.CostBearer.CostRatePeriods, calc);
|
|
|
|
if (si.ApprovedFLS.HasValue)
|
|
{
|
|
CalculateInvoiceItemAmounts(si);
|
|
}
|
|
//CalculateMaxApprovedAmounts(accountingPeriods, relDC.CostBearer.CostRatePeriods, calc);
|
|
|
|
CalculateAdvancedPayments(si, c2s);
|
|
|
|
CalculateEquityContribution(si, c2s.SupportConcept, periodStart, periodEnd);
|
|
|
|
CalculateSettlementInvoiceAmounts(si);
|
|
}
|
|
|
|
//public virtual void CalculateMaxApprovedAmounts(IList<AccountingPeriod> accountingPeriods, List<CostRatePeriodDC> costRatePeriods, Calculations calc)
|
|
//{
|
|
// Dictionary<long, SupportConceptApprovalPeriodDC> oid2Scap = new Dictionary<long, SupportConceptApprovalPeriodDC>();
|
|
// foreach (var ap in accountingPeriods)
|
|
// {
|
|
|
|
// var scap = ap.SupportConceptApprovalPeriod;
|
|
// SupportConceptApprovalPeriodDC scapHelper = null;
|
|
|
|
// if (scap != null)
|
|
// {
|
|
// if (oid2Scap.ContainsKey(scap.SupportConceptApprovalPeriodOid.Value))
|
|
// scapHelper = oid2Scap[scap.SupportConceptApprovalPeriodOid.Value];
|
|
// else
|
|
// {
|
|
// scapHelper = new SupportConceptApprovalPeriodDC();
|
|
// scapHelper.ApprovedBETotal = scap.ApprovedBETotal;
|
|
// if (!scapHelper.ApprovedBETotal.HasValue)
|
|
// scapHelper.ApprovedBETotal = calc.GetApprovedBETotal(scap, costRatePeriods);
|
|
// }
|
|
// }
|
|
|
|
// if (scapHelper.ApprovedBETotal.HasValue && scapHelper.ApprovedBETotal > ap.co
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
public virtual void CalculateSettlementInvoiceAmounts(Settlement2DC si)
|
|
{
|
|
decimal maxAmount = 0;
|
|
if (si.InvoiceItems != null)
|
|
{
|
|
si.AmountBillableTotal = si.InvoiceItems.Sum(ii => Math.Round(ii.GrossAmountTotal ?? 0, 2, MidpointRounding.AwayFromZero));
|
|
|
|
//maxAmount = si.InvoiceItems.Sum(ii =>
|
|
// {
|
|
// decimal amount = ii.GrossAmountTotal ?? 0;
|
|
// if (ii.MaxApprovedAmount.HasValue && ii.MaxApprovedAmount.Value > 0 && ii.MaxApprovedAmount < amount)
|
|
// amount = ii.MaxApprovedAmount.Value;
|
|
// return amount;
|
|
// });
|
|
if (maxAmount == 0)
|
|
maxAmount = si.AmountBillableTotal.Value;
|
|
}
|
|
|
|
si.Claim = maxAmount - (si.AmountAdvancedPayments ?? 0) - (si.EquityContribution ?? 0);
|
|
}
|
|
|
|
public virtual List<InvoiceItemDC> CreateInvoiceItemsForAccountingPeriods(Settlement2DC si, List<AccountingPeriod> accountingPeriods,
|
|
List<CostRatePeriodDC> costRatePeriods, Calculations calc)
|
|
{
|
|
Dictionary<long, SupportConceptApprovalPeriodDC> oid2Scap = new Dictionary<long, SupportConceptApprovalPeriodDC>();
|
|
List<InvoiceItemDC> invoiceItems = new List<InvoiceItemDC>();
|
|
|
|
foreach (var ap in accountingPeriods)
|
|
{
|
|
InvoiceItemDC ii = CreateInvoiceItemForAccountingPeriod(ap);
|
|
invoiceItems.Add(ii);
|
|
|
|
var scap = ap.SupportConceptApprovalPeriod;
|
|
SupportConceptApprovalPeriodDC scapHelper = null;
|
|
|
|
if (scap != null)
|
|
{
|
|
if (oid2Scap.ContainsKey(scap.SupportConceptApprovalPeriodOid.Value))
|
|
scapHelper = oid2Scap[scap.SupportConceptApprovalPeriodOid.Value];
|
|
else
|
|
{
|
|
scapHelper = new SupportConceptApprovalPeriodDC();
|
|
scapHelper.ApprovedBETotal = scap.ApprovedBETotal;
|
|
if (!scapHelper.ApprovedBETotal.HasValue)
|
|
scapHelper.ApprovedBETotal = calc.GetApprovedBETotal(scap, costRatePeriods);
|
|
|
|
oid2Scap[scap.SupportConceptApprovalPeriodOid.Value] = scapHelper;
|
|
}
|
|
}
|
|
|
|
if (!si.ApprovedFLS.HasValue)
|
|
{
|
|
if (scapHelper.ApprovedBETotal.HasValue && ii.UnitCount.HasValue)
|
|
{
|
|
if (scapHelper.ApprovedBETotal >= ii.UnitCount.Value)
|
|
{
|
|
scapHelper.ApprovedBETotal -= ii.UnitCount.Value;
|
|
ii.MaxApprovedUnitCount = null;
|
|
}
|
|
else
|
|
{
|
|
ii.MaxApprovedUnitCount = scapHelper.ApprovedBETotal;
|
|
}
|
|
}
|
|
|
|
CalculateInvoiceItemAmounts(ii);
|
|
}
|
|
|
|
if (ii.UnitCount.HasValue)
|
|
{
|
|
si.RecordedBillableFLSBrutto = (si.RecordedBillableFLSBrutto ?? 0) + ii.UnitCount;
|
|
}
|
|
|
|
var list = CreateAdditionalInvoiceItems(ap);
|
|
invoiceItems.AddRange(list);
|
|
}
|
|
return invoiceItems;
|
|
}
|
|
|
|
public virtual IList<InvoiceItemDC> CreateAdditionalInvoiceItems(AccountingPeriod ap)
|
|
{
|
|
//only for subclasses
|
|
return new List<InvoiceItemDC>();
|
|
}
|
|
|
|
public virtual InvoiceItemDC CreateInvoiceItemForAccountingPeriod(AccountingPeriod accountingPeriod)
|
|
{
|
|
InvoiceItemDC ii = new InvoiceItemDC();
|
|
ii.AccountingInterval = accountingPeriod.AccountingInterval;
|
|
ii.ItemPeriodStart = accountingPeriod.PeriodStart;
|
|
ii.ItemPeriodEnd = accountingPeriod.PeriodEnd;
|
|
ii.RateFactor = accountingPeriod.RateFactor;
|
|
ii.AmountPerUnit = accountingPeriod.Amount;
|
|
ii.UnitDescription = accountingPeriod.UnitName;
|
|
ii.MaxApprovedAmount = accountingPeriod.MaxApprovedAmount;
|
|
ii.MaxApprovedUnitCount = accountingPeriod.MaxApprovedUnitCount;
|
|
ii.ApprovedPerUnit = accountingPeriod.ApprovedPerUnit;
|
|
ii.ApprovalUnit = accountingPeriod.ApprovalUnit;
|
|
|
|
|
|
if (accountingPeriod.ServiceCategory != null)
|
|
ii.ItemDescription = accountingPeriod.ServiceCategory.Name;
|
|
|
|
if (accountingPeriod.AccountingInterval == AccountingIntervalType.FlatRate)
|
|
{
|
|
ii.UnitCount = accountingPeriod.ServiceRecordsInPeriod.Count;
|
|
|
|
}
|
|
else if (accountingPeriod.AccountingInterval == AccountingIntervalType.Hourly)
|
|
{
|
|
decimal minutesTotal = 0;
|
|
|
|
if (accountingPeriod.ServiceRecordsInPeriod != null)
|
|
{
|
|
foreach (var ar in accountingPeriod.ServiceRecordsInPeriod)
|
|
{
|
|
var rd = ar.RoundedDuration;
|
|
if (ar.ServiceDescription.Category.Percentage != 100)
|
|
{
|
|
rd = (rd*ar.ServiceDescription.Category.Percentage)/100;
|
|
}
|
|
minutesTotal += rd;
|
|
|
|
}
|
|
}
|
|
ii.UnitCount = minutesTotal/60;
|
|
|
|
if (String.IsNullOrEmpty(ii.UnitDescription))
|
|
ii.UnitDescription = ii.UnitCount.Value == 1 ? "Stunde" : "Stunden";
|
|
}
|
|
else if (accountingPeriod.PeriodStart > DateTime.MinValue && accountingPeriod.PeriodEnd < DateTime.MaxValue)
|
|
{
|
|
DateTime intervalStart = accountingPeriod.PeriodStart;
|
|
DateTime intervalEnd = intervalStart;
|
|
int count = 0;
|
|
while (intervalStart < accountingPeriod.PeriodEnd)
|
|
{
|
|
count++;
|
|
switch (accountingPeriod.AccountingInterval)
|
|
{
|
|
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;
|
|
}
|
|
intervalStart = intervalEnd;
|
|
}
|
|
ii.UnitCount = count;
|
|
|
|
switch (accountingPeriod.AccountingInterval)
|
|
{
|
|
case AccountingIntervalType.Daily:
|
|
ii.UnitDescription = count == 1 ? "Tag" : "Tage";
|
|
break;
|
|
case AccountingIntervalType.Weekly:
|
|
ii.UnitDescription = count == 1 ? "Woche" : "Wochen";
|
|
break;
|
|
case AccountingIntervalType.Fortnightly:
|
|
ii.UnitDescription = "2 Wochen";
|
|
break;
|
|
case AccountingIntervalType.Monthly:
|
|
ii.UnitDescription = count == 1 ? "Monat" : "Monate";
|
|
break;
|
|
case AccountingIntervalType.Quarterly:
|
|
ii.UnitDescription = count == 1 ? "Quartal" : "Quartale";
|
|
break;
|
|
case AccountingIntervalType.HalfYearly:
|
|
ii.UnitDescription = "Halbjährlich";
|
|
break;
|
|
case AccountingIntervalType.Yearly:
|
|
ii.UnitDescription = count == 1 ? "Jahr" : "Jahre";
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return ii;
|
|
}
|
|
|
|
public virtual void CalculateInvoiceItemAmounts(InvoiceItemDC ii)
|
|
{
|
|
if (ii.UnitCount.HasValue)
|
|
{
|
|
var uc = ii.UnitCount.Value;
|
|
if (ii.MaxApprovedUnitCount.HasValue && ii.MaxApprovedUnitCount.Value < uc)
|
|
uc = ii.MaxApprovedUnitCount.Value;
|
|
ii.UnitCount = Math.Round(uc, 2, MidpointRounding.AwayFromZero);
|
|
if (ii.AmountPerUnit.HasValue)
|
|
{
|
|
ii.AmountTotal = Math.Round(ii.UnitCount.Value*ii.AmountPerUnit.Value, 2,
|
|
MidpointRounding.AwayFromZero);
|
|
if (ii.RateFactor.HasValue && ii.RateFactor.Value != 0)
|
|
ii.GrossAmountTotal = Math.Round(ii.AmountTotal.Value*((100m + ii.RateFactor.Value)/100m), 2,
|
|
MidpointRounding.AwayFromZero);
|
|
else
|
|
ii.GrossAmountTotal = ii.AmountTotal;
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void CalculateInvoiceItemAmounts(Settlement2DC si)
|
|
{
|
|
decimal maxApprovedFls = si.ApprovedFLS ?? 0;
|
|
|
|
foreach (var ii in si.InvoiceItems)
|
|
{
|
|
if (ii.UnitCount.HasValue)
|
|
{
|
|
var uc = Math.Round(ii.UnitCount ?? 0, 2, MidpointRounding.AwayFromZero);
|
|
if (maxApprovedFls < uc)
|
|
uc = maxApprovedFls;
|
|
|
|
maxApprovedFls -= uc;
|
|
|
|
ii.UnitCount = uc;
|
|
|
|
if (ii.AmountPerUnit.HasValue)
|
|
{
|
|
ii.AmountTotal = ii.UnitCount.Value * ii.AmountPerUnit.Value;
|
|
if (ii.RateFactor.HasValue && ii.RateFactor.Value != 0)
|
|
ii.GrossAmountTotal = Math.Round(ii.AmountTotal.Value * ((100m + ii.RateFactor.Value) / 100m), 2,
|
|
MidpointRounding.AwayFromZero);
|
|
else
|
|
ii.GrossAmountTotal = ii.AmountTotal;
|
|
|
|
}
|
|
if (ii.MaxApprovedUnitCount < ii.UnitCount)
|
|
{
|
|
ii.MaxApprovedUnitCount = ii.UnitCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public virtual void CalculateSettlementInvoiceApprovedAmounts(Settlement2DC si, SupportConceptCostBearerRelDC relDC,
|
|
Calculations calc)
|
|
{
|
|
decimal flsWeek = calc.GetApprovedHoursPerWeekAverage(relDC, true) ?? 0m;
|
|
decimal flsTotal = calc.GetApprovedHoursTotal(relDC, true) ?? 0m;
|
|
flsTotal = Math.Round(flsTotal, 2, MidpointRounding.AwayFromZero);
|
|
si.ApprovedFLS = flsTotal;
|
|
si.ApprovedFLSWeekly = flsWeek;
|
|
}
|
|
|
|
|
|
|
|
public virtual void CreateRecipientInformation(Settlement2DC settlementInvoice, CostBearer2SupportConcept c2s)
|
|
{
|
|
if (c2s.CostBearer != null && c2s.CostBearer.Organisation != null)
|
|
{
|
|
settlementInvoice.RecipientOrganisation = c2s.CostBearer.Organisation.Name;
|
|
settlementInvoice.RecipientDivision = c2s.CostBearer.Organisation.Name2;
|
|
}
|
|
|
|
if (c2s.CostBearerContactPerson != null)
|
|
{
|
|
settlementInvoice.RecipientContactPerson = c2s.CostBearerContactPerson.ToString();
|
|
}
|
|
else if (c2s.CostBearer != null && c2s.CostBearer.Organisation != null)
|
|
{
|
|
var lContactPerson = c2s.CostBearer.Organisation.Contacts.SingleOrDefault(c => c.Type == ContactType.ContactPerson);
|
|
if (lContactPerson != null)
|
|
{
|
|
settlementInvoice.RecipientContactPerson = lContactPerson.Value;
|
|
}
|
|
}
|
|
|
|
// War die private Rechnungsadresse der Kontaktperson
|
|
//if (c2s.CostBearerContactPerson != null && c2s.CostBearerContactPerson.InvoiceAddress != null)
|
|
//{
|
|
// settlementInvoice.RecipientPostCode = c2s.CostBearerContactPerson.InvoiceAddress.PostalCode;
|
|
// settlementInvoice.RecipientStreet = c2s.CostBearerContactPerson.InvoiceAddress.Street;
|
|
// settlementInvoice.RecipientTown = c2s.CostBearerContactPerson.InvoiceAddress.Town;
|
|
//}
|
|
//else
|
|
if (c2s.CostBearer != null && c2s.CostBearer.Organisation != null)
|
|
{
|
|
if (c2s.CostBearer.Organisation.InvoiceAddress != null &&
|
|
!String.IsNullOrEmpty(c2s.CostBearer.Organisation.InvoiceAddress.Street))
|
|
{
|
|
settlementInvoice.RecipientPostCode = c2s.CostBearer.Organisation.InvoiceAddress.PostalCode;
|
|
settlementInvoice.RecipientStreet = c2s.CostBearer.Organisation.InvoiceAddress.Street;
|
|
settlementInvoice.RecipientTown = c2s.CostBearer.Organisation.InvoiceAddress.Town;
|
|
}
|
|
else if (c2s.CostBearer.Organisation.Address != null)
|
|
{
|
|
settlementInvoice.RecipientPostCode = c2s.CostBearer.Organisation.Address.PostalCode;
|
|
settlementInvoice.RecipientStreet = c2s.CostBearer.Organisation.Address.Street;
|
|
settlementInvoice.RecipientTown = c2s.CostBearer.Organisation.Address.Town;
|
|
}
|
|
|
|
settlementInvoice.RecipientPostBox = c2s.CostBearer.Organisation.Contacts.FirstOrDefault(f => f.Type.Equals(ContactType.business_POBox)) != null ? c2s.CostBearer.Organisation.Contacts.FirstOrDefault(f => f.Type.Equals(ContactType.business_POBox)).Value : String.Empty;
|
|
}
|
|
}
|
|
|
|
public virtual void CreateSenderInformation(Settlement2DC settlementInvoice)
|
|
{
|
|
if (LoggedInUserOperationContextExt.Current != null)
|
|
{
|
|
var lLoggedInEmployee = LoggedInUserOperationContextExt.Current.User.Employee;
|
|
|
|
|
|
if (lLoggedInEmployee != null)
|
|
{
|
|
settlementInvoice.SenderContactPersonFirstName = lLoggedInEmployee.Person.FirstName;
|
|
settlementInvoice.SenderContactPersonLastName = lLoggedInEmployee.Person.LastName;
|
|
|
|
foreach (var iContact in lLoggedInEmployee.Person.Contacts)
|
|
{
|
|
switch (iContact.Type)
|
|
{
|
|
case ContactType.business_Fax:
|
|
settlementInvoice.SenderContactPersonFax = iContact.Value;
|
|
break;
|
|
case ContactType.business_Mail:
|
|
settlementInvoice.SenderContactPersonMail = iContact.Value;
|
|
break;
|
|
case ContactType.business_Phone:
|
|
settlementInvoice.SenderContactPersonPhone = iContact.Value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
settlementInvoice.CreatorFirstName = lLoggedInEmployee.Person.FirstName;
|
|
settlementInvoice.CreatorLastName = lLoggedInEmployee.Person.LastName;
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void CalculateAdvancedPayments(Settlement2DC settlementInvoice, CostBearer2SupportConcept cb2sc)
|
|
{
|
|
if (settlementInvoice.InvoiceItems != null && settlementInvoice.InvoiceItems.Count > 0)
|
|
{
|
|
decimal amountTotal = 0;
|
|
var bookingList = cb2sc.AccountingTransactions;
|
|
|
|
foreach (var item in bookingList)
|
|
{
|
|
if (item.GueltigkeitsDatum.HasValue)
|
|
{
|
|
foreach (var ii in settlementInvoice.InvoiceItems)
|
|
{
|
|
if (ii.ItemPeriodStart.HasValue && ii.ItemPeriodEnd.HasValue)
|
|
{
|
|
if (item.GueltigkeitsDatum.Value.InBetween(ii.ItemPeriodStart.Value, ii.ItemPeriodEnd.Value, true))
|
|
{
|
|
ii.ReceivedAmount += item.Amount;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
amountTotal += item.Amount;
|
|
}
|
|
|
|
settlementInvoice.AmountAdvancedPayments = amountTotal;
|
|
}
|
|
}
|
|
|
|
public virtual void CalculateAdvancedPayments(Settlement2DC settlementInvoice, CostBearer2SupportConcept cb2sc,
|
|
DateTime? periodStart, DateTime? periodEnd, List<KeyValuePair<CostRatePeriodDC, DateTimeSpan>> hourlyRatesInSpanList)
|
|
{
|
|
decimal amountNew = 0;
|
|
decimal amountOld = 0;
|
|
decimal amount3 = 0;
|
|
decimal amountTotal = 0;
|
|
|
|
var bookingList = cb2sc.AccountingTransactions;
|
|
|
|
if (periodStart.HasValue && periodEnd.HasValue)
|
|
{
|
|
bookingList =
|
|
bookingList.Where(i => i.GueltigkeitsDatum.HasValue
|
|
&& i.GueltigkeitsDatum.Value.InBetween(periodStart.Value, periodEnd.Value, true)).ToList();
|
|
}
|
|
|
|
foreach (var item in bookingList)
|
|
{
|
|
if (hourlyRatesInSpanList.Count > 2 && item.GueltigkeitsDatum != null &&
|
|
item.GueltigkeitsDatum < hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 2].Value.StartDateTime)
|
|
{
|
|
amount3 += item.Amount;
|
|
}
|
|
else if (hourlyRatesInSpanList.Count > 1 && item.GueltigkeitsDatum != null &&
|
|
item.GueltigkeitsDatum < hourlyRatesInSpanList[hourlyRatesInSpanList.Count - 1].Value.StartDateTime)
|
|
{
|
|
amountOld += item.Amount;
|
|
}
|
|
else
|
|
{
|
|
amountNew += item.Amount;
|
|
}
|
|
|
|
amountTotal += item.Amount;
|
|
}
|
|
|
|
settlementInvoice.AmountTotalAdvancedPaidWithNewHourlyRate = amountNew;
|
|
settlementInvoice.AmountTotalAdvancedPaidWithOldHourlyRate = amountOld;
|
|
settlementInvoice.AmountTotalAdvancedPaidWithHourlyRate3 = amount3;
|
|
settlementInvoice.AmountAdvancedPayments = amountTotal;
|
|
}
|
|
|
|
public virtual void CalculateEquityContribution(Settlement2DC settlementInvoice, SupportConcept sc,
|
|
DateTime? periodStart, DateTime? periodEnd)
|
|
{
|
|
decimal equity = 0;
|
|
|
|
IList<InvoiceBase> invoiceList =
|
|
DAOFactory.SearchDAO.GetInvoiceBaseByTypeAndSupportConceptOid(InvoiceType.CustomerEquity, sc.Oid.Value);
|
|
|
|
if (periodStart.HasValue && periodEnd.HasValue)
|
|
{
|
|
invoiceList =
|
|
invoiceList.Where(i => i.InvoiceDate.HasValue
|
|
&& i.InvoiceDate.Value.InBetween(periodStart.Value, periodEnd.Value, true)).ToList();
|
|
}
|
|
|
|
foreach (InvoiceBase invoice in invoiceList)
|
|
{
|
|
foreach (InvoiceItem item in invoice.InvoiceItems)
|
|
{
|
|
if (item.AmountTotal != null)
|
|
{
|
|
equity += item.AmountTotal.Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
settlementInvoice.EquityContribution = equity;
|
|
}
|
|
|
|
public virtual IList<ApprovalPeriod> CreateApprovalPeriods(Settlement2DC si, CostBearer2SupportConcept c2s)
|
|
{
|
|
var relDc = c2s.MapToNewDC();
|
|
|
|
var hourlyRatesInSpanList = relDc.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.HourlyRate,
|
|
si.AccountingPeriodStart.Value.Date, si.AccountingPeriodEnd.Value.Date).ToList();
|
|
|
|
List<ApprovalPeriod> sonstigeAp = new List<ApprovalPeriod>();
|
|
|
|
Dictionary<DateTime, ApprovalPeriod> dtApDict = new Dictionary<DateTime, ApprovalPeriod>();
|
|
foreach (var keyValuePair in hourlyRatesInSpanList)
|
|
{
|
|
var ap = new ApprovalPeriod();
|
|
ap.PeriodStartDate = keyValuePair.Value.StartDate;
|
|
ap.PeriodEndDate = DateTime.MaxValue;
|
|
dtApDict.Add(ap.PeriodStartDate, ap);
|
|
}
|
|
|
|
var rateFactorInSpanList = relDc.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.RateFactor,
|
|
si.AccountingPeriodStart.Value.Date, si.AccountingPeriodEnd.Value.Date).ToList();
|
|
|
|
foreach (var keyValuePair in rateFactorInSpanList)
|
|
{
|
|
if (!dtApDict.ContainsKey(keyValuePair.Value.StartDate))
|
|
{
|
|
var ap = new ApprovalPeriod();
|
|
ap.PeriodStartDate = keyValuePair.Value.StartDate;
|
|
ap.PeriodEndDate = DateTime.MaxValue;
|
|
dtApDict.Add(ap.PeriodStartDate, ap);
|
|
}
|
|
}
|
|
|
|
foreach (var scap in c2s.ApprovalPeriodList)
|
|
{
|
|
if (scap.StartDate.HasValue && scap.EndDate.HasValue)
|
|
{
|
|
if (!dtApDict.ContainsKey(scap.StartDate.Value) && scap.ApprovedBEInterval.HasValue &&
|
|
scap.ApprovedBEPerInterval.HasValue)
|
|
{
|
|
var ap = new ApprovalPeriod();
|
|
ap.PeriodStartDate = scap.StartDate.Value;
|
|
ap.PeriodEndDate = DateTime.MaxValue;
|
|
dtApDict.Add(ap.PeriodStartDate, ap);
|
|
}
|
|
else if (scap.ApprovedBETotal.HasValue)
|
|
{
|
|
var ap = new ApprovalPeriod();
|
|
ap.PeriodStartDate = scap.StartDate.Value;
|
|
ap.PeriodEndDate = scap.EndDate.Value;
|
|
ap.ApprovedTotal = scap.ApprovedBETotal.Value;
|
|
ap.ApprovalUnit = AccountingIntervalType.FlatRate;
|
|
var hrspan = hourlyRatesInSpanList.FirstOrDefault(ispan => ispan.Value.StartDate <= ap.PeriodStartDate && ap.PeriodStartDate <= ispan.Value.EndDate);
|
|
var rfspan = rateFactorInSpanList.FirstOrDefault(ispan => ispan.Value.StartDate <= ap.PeriodStartDate && ap.PeriodStartDate <= ispan.Value.EndDate);
|
|
if (hrspan.Key != null && hrspan.Key.CostRateValue.HasValue)
|
|
{
|
|
ap.AmountPerUnit = hrspan.Key.CostRateValue.Value;
|
|
ap.BillingInterval = AccountingIntervalType.Hourly;
|
|
}
|
|
if (rfspan.Key != null && rfspan.Key.CostRateValue.HasValue)
|
|
{
|
|
ap.RateFactor = rfspan.Key.CostRateValue.Value;
|
|
}
|
|
sonstigeAp.Add(ap);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var dt in dtApDict.Keys)
|
|
{
|
|
ApprovalPeriod ap = dtApDict[dt];
|
|
var hrspan = hourlyRatesInSpanList.FirstOrDefault(ispan => ispan.Value.StartDate <= dt && dt <= ispan.Value.EndDate);
|
|
var rfspan = rateFactorInSpanList.FirstOrDefault(ispan => ispan.Value.StartDate <= dt && dt <= ispan.Value.EndDate);
|
|
|
|
var scap = c2s.ApprovalPeriodList.FirstOrDefault(iscap => iscap.StartDate <= dt && dt <= iscap.EndDate && !iscap.ApprovedBETotal.HasValue);
|
|
|
|
if (hrspan.Key != null && hrspan.Key.CostRateValue.HasValue)
|
|
{
|
|
ap.AmountPerUnit = hrspan.Key.CostRateValue.Value;
|
|
ap.BillingInterval = AccountingIntervalType.Hourly;
|
|
}
|
|
if (hrspan.Value != null && hrspan.Value.EndDate < ap.PeriodEndDate)
|
|
{
|
|
ap.PeriodEndDate = hrspan.Value.EndDate;
|
|
}
|
|
if (rfspan.Key != null && rfspan.Key.CostRateValue.HasValue)
|
|
{
|
|
ap.RateFactor = rfspan.Key.CostRateValue.Value;
|
|
}
|
|
if (rfspan.Value != null && rfspan.Value.EndDate < ap.PeriodEndDate)
|
|
{
|
|
ap.PeriodEndDate = rfspan.Value.EndDate;
|
|
}
|
|
if (scap != null)
|
|
{
|
|
if (scap.EndDate.HasValue && scap.EndDate < ap.PeriodEndDate)
|
|
ap.PeriodEndDate = scap.EndDate.Value;
|
|
|
|
CalculateApprovedAmountForApprovalPeriod(ap, scap);
|
|
}
|
|
}
|
|
|
|
|
|
var list = dtApDict.Values.OrderBy(ap => ap.PeriodStartDate).ToList();
|
|
foreach (var ap in sonstigeAp)
|
|
{
|
|
list.Add(ap);
|
|
}
|
|
foreach (var approvalPeriod in list)
|
|
{
|
|
InitApprovalPeriod(si, approvalPeriod);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public virtual void CalculateApprovedAmountForApprovalPeriod(ApprovalPeriod ap, SupportConceptApprovalPeriod scap)
|
|
{
|
|
if (scap.ApprovedBEPerInterval.HasValue && scap.ApprovedBEInterval.HasValue)
|
|
{
|
|
ap.ApprovedPerUnit = scap.ApprovedBEPerInterval.Value;
|
|
ap.ApprovalUnit = Calculations.ConvertApprovalToAccountingIntervalType(scap.ApprovedBEInterval.Value);
|
|
}
|
|
else if (scap.ApprovedBETotal.HasValue)
|
|
{
|
|
//Gesamtstunden auf ap Zeitraum umrechnen
|
|
if (ap.PeriodStartDate == scap.StartDate && ap.PeriodEndDate == scap.EndDate)
|
|
{
|
|
ap.ApprovedPerUnit = scap.ApprovedBETotal.Value;
|
|
}
|
|
else if (scap.EndDate.HasValue && scap.StartDate.HasValue)
|
|
{
|
|
decimal perioddays = (decimal)ap.PeriodEndDate.Subtract(ap.PeriodStartDate).TotalDays + 1;
|
|
decimal totaldays = (decimal)scap.EndDate.Value.Subtract(scap.StartDate.Value).TotalDays + 1;
|
|
|
|
var approvedPerDay = scap.ApprovedBETotal.Value / totaldays;
|
|
ap.ApprovedPerUnit = perioddays * approvedPerDay;
|
|
|
|
}
|
|
else
|
|
{
|
|
ap.ApprovedPerUnit = scap.ApprovedBETotal.Value;
|
|
}
|
|
ap.ApprovalUnit = AccountingIntervalType.FlatRate;
|
|
}
|
|
|
|
}
|
|
|
|
public virtual void InitApprovalPeriod(Settlement2DC si, ApprovalPeriod approvalPeriod)
|
|
{
|
|
approvalPeriod.Days = approvalPeriod.PeriodEndDate.Subtract(approvalPeriod.PeriodStartDate).Days + 1;
|
|
approvalPeriod.Weeks = approvalPeriod.Days / 7m;
|
|
|
|
if (approvalPeriod.ApprovalUnit == AccountingIntervalType.FlatRate)
|
|
{
|
|
if (approvalPeriod.ApprovedTotal == 0)
|
|
{
|
|
approvalPeriod.ApprovedTotal = approvalPeriod.ApprovedPerUnit;
|
|
}
|
|
}
|
|
else if (approvalPeriod.ApprovalUnit == AccountingIntervalType.Monthly)
|
|
{
|
|
var months = GetTotalMonths(approvalPeriod.PeriodStartDate, approvalPeriod.PeriodEndDate);
|
|
approvalPeriod.ApprovedTotal = months * approvalPeriod.ApprovedPerUnit;
|
|
}
|
|
else if (approvalPeriod.ApprovalUnit == AccountingIntervalType.Quarterly)
|
|
{
|
|
var months = GetTotalQuarters(approvalPeriod.PeriodStartDate, approvalPeriod.PeriodEndDate);
|
|
approvalPeriod.ApprovedTotal = months * approvalPeriod.ApprovedPerUnit;
|
|
}
|
|
else
|
|
{
|
|
|
|
approvalPeriod.ApprovedTotal = Math.Round(approvalPeriod.Weeks * approvalPeriod.ApprovedPerUnit, 2,
|
|
MidpointRounding.AwayFromZero);
|
|
}
|
|
approvalPeriod.ApprovedAmountTotal = Math.Round(approvalPeriod.ApprovedTotal * approvalPeriod.AmountPerUnit, 2,
|
|
MidpointRounding.AwayFromZero);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
}
|