Files
BeWoPlaner/ReportImp/VkmAachenSbd/Invoicing/CustomInvoiceCreation.cs
2019-07-12 10:33:31 +02:00

584 lines
22 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.DCEntityMapper;
using BeWo.Service.Invoicing;
using BeWo.Service.Plugins;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;
using BS.Shared.Services;
using DevExpress.Data.Helpers;
namespace VkmAachenSbd.Invoicing
{
public class CustomInvoiceCreation : InvoiceCreation
{
public override void SetInvoiceId(ServiceInvoice invoice)
{
invoice.InvoiceBase.InvoiceId = "SBD";
invoice.InvoiceBase.InvoiceTypeText = "Abrechnung Schulbegleitender Dienst";
}
public override void SetServiceInvoicePeriods(ServiceInvoice invoice, CostBearer2SupportConcept costBearer2SupportConcept,
DateTimeSpan invoicePeriod, List<ServiceRecordDC> serviceRecords)
{
base.SetServiceInvoicePeriods(invoice, costBearer2SupportConcept, invoicePeriod, serviceRecords);
IList<ServiceInvoicePeriod> newSipList = new List<ServiceInvoicePeriod>();
Dictionary<String, ServiceInvoicePeriod> key2Sip = new Dictionary<string, ServiceInvoicePeriod>();
Dictionary<String, InvoiceItem> key2sammelItem = new Dictionary<string, InvoiceItem>();
Dictionary<String, InvoiceItem> key2rateFactorItem = new Dictionary<string, InvoiceItem>();
foreach (var sip in invoice.ServiceInvoicePeriodList)
{
foreach (var ii in sip.InvoiceItemList)
{
var key = String.Format("{0}{1}", ii.AmountPerUnit ?? 0, ii.RateFactor ?? 0);
if (!key2Sip.ContainsKey(key))
{
ServiceInvoicePeriod newsip = new ServiceInvoicePeriod();
newsip.InvoiceItemList = new List<InvoiceItem>();
newsip.Start = sip.Start;
newsip.End = sip.End;
key2Sip.Add(key, newsip);
newSipList.Add(newsip);
InvoiceItem newItem = new InvoiceItem();
newItem.ItemPeriodStart = invoicePeriod.StartDateTime;
newItem.ItemPeriodEnd = invoicePeriod.EndDateTime;
newItem.ItemDescription = "Betreuungseinsätze";
newItem.AmountPerUnit = ii.AmountPerUnit;
newItem.UnitCount = 0;
newsip.InvoiceItemList.Add(newItem);
key2sammelItem.Add(key, newItem);
if (ii.RateFactor.HasValue && ii.RateFactor.Value > 0)
{
var rfItem = new InvoiceItem();
rfItem.ItemPeriodStart = newItem.ItemPeriodStart;
rfItem.ItemPeriodEnd = newItem.ItemPeriodEnd;
rfItem.RateFactor = ii.RateFactor;
rfItem.AmountPerUnit = Math.Round(ii.AmountPerUnit.Value * (ii.RateFactor.Value / 100), 2, MidpointRounding.AwayFromZero);
rfItem.UnitCount = 0;
newsip.InvoiceItemList.Add(rfItem);
key2rateFactorItem.Add(key, rfItem);
}
}
key2Sip[key].InvoiceItemList.Add(ii);
}
}
invoice.ServiceInvoicePeriodList = newSipList;
foreach (var key in key2Sip.Keys)
{
decimal hours = 0;
var sip = key2Sip[key];
foreach (var ii in sip.InvoiceItemList)
{
hours += ii.UnitCount ?? 0;
}
var newItem = key2sammelItem[key];
newItem.UnitCount = hours;
newItem.AmountTotal = Math.Round((newItem.AmountPerUnit ?? 0) * hours, 2, MidpointRounding.AwayFromZero);
newItem.GrossAmountTotal = newItem.AmountTotal;
if (key2rateFactorItem.ContainsKey(key))
{
var rfItem = key2rateFactorItem[key];
rfItem.UnitCount = hours;
rfItem.AmountTotal = Math.Round((rfItem.AmountPerUnit ?? 0) * hours, 2, MidpointRounding.AwayFromZero);
rfItem.GrossAmountTotal = rfItem.AmountTotal;
rfItem.ItemDescription = String.Format("{0:0.##}% Zuschlag auf Betreuungszeit", rfItem.RateFactor);
}
}
}
public override void SetInvoiceItems(ServiceInvoice invoice,
ServiceInvoicePeriod serviceInvoicePeriod,
SupportConceptApprovalPeriodDC supportConceptApprovalPeriod,
CostBearer2SupportConcept cb2sc,
DateTimeSpan invoicePeriod,
List<ServiceRecordDC> serviceRecords)
{
Calculations calc = PluginLoader.FindClass<Calculations>(_SpecificID) ?? Calculations.GetInstance(_SpecificID);
List<ServiceRecordDC> serviceRecordsInPeriod = serviceRecords.Where(
i =>
{
bool valid = i.Start.Value.InBetween(serviceInvoicePeriod.Start.Value,
serviceInvoicePeriod.End.Value, true);
//if (valid && serviceInvoicePeriod.SupportConceptApprovalPeriod != null && serviceInvoicePeriod.SupportConceptApprovalPeriod.ServiceCategory != null)
// valid = serviceInvoicePeriod.SupportConceptApprovalPeriod.ServiceCategory.Oid ==
// i.ServiceDescription.Category.ServiceCategoryOid;
return valid;
}).ToList();
var itemList = CreateAllInvoiceItems(cb2sc, serviceRecordsInPeriod, invoicePeriod, serviceInvoicePeriod.SupportConceptApprovalPeriod, calc);
serviceInvoicePeriod.InvoiceItemList.AddRange(itemList);
}
public IList<InvoiceItem> CreateAllInvoiceItems(CostBearer2SupportConcept c2s, List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
{
var items = CreateSbdInvoiceItems(c2s.SupportConcept.Customer, serviceRecordsInPeriod, invoicePeriod, scap, calc);
decimal hours = 0;
decimal hourlyRateBewilligung = GetHourlyRateForBewilligung(c2s, scap, invoicePeriod.StartDate) ?? 0;
var crList = MapperFactory.CostRatePeriodDC_CostRatePeriod.MapToNewDCs(c2s.CostBearer.CostRatePeriods);
foreach (var item in items)
{
if (!item.AmountPerUnit.HasValue)
{
item.AmountPerUnit = GetCostRateValue(crList, CostRatePeriodType.HourlyRate, item.ItemPeriodStart.Value);
}
if (!item.RateFactor.HasValue)
{
item.RateFactor = GetCostRateValue(crList, CostRatePeriodType.RateFactor, item.ItemPeriodStart.Value);
}
hours += item.UnitCount ?? 0;
if (item.AmountPerUnit.Value > hourlyRateBewilligung)
{
item.AmountPerUnit = hourlyRateBewilligung;
}
item.AmountTotal = 0;
item.GrossAmountTotal = 0;
}
return items;
}
private decimal? GetHourlyRateForBewilligung(CostBearer2SupportConcept c2s, SupportConceptApprovalPeriod scap, DateTime date)
{
if (scap.ServiceCategory != null)
{
return GetQualifikationsabhaengigenStundensatz(c2s.CostBearer, scap.ServiceCategory, date);
}
return null;
}
private decimal? GetQualifikationsabhaengigenStundensatz(CostBearer cb, ServiceCategory category, DateTime date)
{
if (cb.CostRatePeriods != null)
{
//var qualificationHourlyRates = cb.CostRatePeriods.Where(i =>
// i.CostRateType == CostRatePeriodType.HourlyRate &&
// i.ValueListEntry != null &&
// i.ValueListEntry.Type == ValueListEntryType.StaffQualificationsType);
//Valuelistentryoid:
//9 Fachkraft
//10 Nicht - Fachkraft
//11 Diplom Fachkraft
//12 medizinische Fachkraft
//13 Sonder - Fachkraft
//52 pädagogische Fachkraft
var ratesDc = MapperFactory.CostRatePeriodDC_CostRatePeriod.MapToNewDCs(cb.CostRatePeriods);
CostRatePeriodDC cr = null;
//Betreuung (Nichtfachkraft)
//Betreuung (Diplomfachkraft)
//Betreuung(Fachkraft)
if (category.Name.Contains("(Diplomfachkraft)"))
{
cr = ratesDc.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, date, 11);
}
else if (category.Name.Contains("(Nichtfachkraft)"))
{
cr = ratesDc.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, date, 10);
}
else if (category.Name.Contains("(Fachkraft)"))
{
cr = ratesDc.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, date, 9);
if (cr == null)
{
cr = ratesDc.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, date, 52);
}
if (cr == null)
{
cr = ratesDc.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, date, 12);
}
if (cr == null)
{
cr = ratesDc.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, date, 13);
}
}
if (cr != null)
{
return cr.CostRateValue;
}
}
return null;
}
public IList<InvoiceItem> CreateSbdInvoiceItems(Customer customer, List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
{
IList<InvoiceItem> result = new List<InvoiceItem>();
//var stundenplanItems = ErstelleStundenplanItems(customer, invoicePeriod.StartDate, invoicePeriod.EndDate);
IList<InvoiceItem> srList = new List<InvoiceItem>();
foreach (ServiceRecordDC iServiceRecord in serviceRecordsInPeriod)
{
if (iServiceRecord.ServiceDescription.Category.IsBillable)
{
if (!iServiceRecord.AlreadyAccounted)
{
var invoiceItem = CreateInvoiceItem(iServiceRecord, scap, calc);
invoiceItem.ItemDescription = String.Format("{0} {1}", iServiceRecord.Employee.FirstName, iServiceRecord.Employee.LastName);
if (iServiceRecord.ServiceDescription.Category.Name.Contains("Sonstige"))
{
invoiceItem.ItemDescription += "\n" + iServiceRecord.ServiceDescription.Name;
}
srList.Add(invoiceItem);
iServiceRecord.AlreadyAccounted = true;
}
}
}
Dictionary<String, bool> dayDict = new Dictionary<String, bool>();
foreach (var item in srList)
{
String key = String.Format("{0:dd.MM.yyyy}", item.ItemPeriodStart);
if (!dayDict.ContainsKey(key))
{
dayDict.Add(key, true);
}
result.Add(item);
}
//foreach (var ii in stundenplanItems)
//{
// String key = String.Format("{0:dd.MM.yyyy}", ii.ItemPeriodStart);
// if (!dayDict.ContainsKey(key))
// {
// ii.ItemDescription = GetHauptbetreuer(customer);
// result.Add(ii);
// }
// }
var newList = result.Where(i => i.UnitCount.HasValue && i.UnitCount.Value > 0).OrderBy(i => i.ItemPeriodStart).ToList();
return CreateSummaryInvoiceItems(newList, invoicePeriod, scap, calc);
}
private string GetHauptbetreuer(Customer customer)
{
foreach (var e2c in customer.Employee2CustomerList)
{
foreach (var v2e in e2c.ValueList)
{
if (v2e.Entry.Type == ValueListEntryType.StaffRoleType && v2e.Entry.Value == "Hauptbetreuung")
{
return e2c.Employee.Person.FirstNameLastName;
}
}
}
return "";
}
private List<InvoiceItem> ErstelleStundenplanItems(Customer customer, DateTime start, DateTime ende)
{
var stundenplan = GetStundenplan(customer, start, ende);
var vs = PluginLoader.FindClass<VacationService>();
List<InvoiceItem> items = new List<InvoiceItem>();
while (start <= ende)
{
bool istSamstag = false;
bool istSonntag = false;
bool istFerien = false;
bool istFeiertag = false;
if (start.DayOfWeek == DayOfWeek.Saturday)
{
istSamstag = true;
}
if (start.DayOfWeek == DayOfWeek.Sunday)
{
istSonntag = true;
}
var ferien = vs.GetFerien(start, "nrw");
if (ferien != null)
{
istFerien = true;
}
var ft = vs.GetFeiertag(start);
if (ft != null)
{
istFeiertag = true;
}
if (!istSamstag && !istSonntag && !istFerien && !istFeiertag)
{
var subItems = ErstelleStundenplanEintraege(stundenplan, start);
items.AddRange(subItems);
}
start = start.AddDays(1);
}
return items;
}
private static Organisation SucheSchule(Customer customer)
{
foreach (var c2o in customer.Customer2OrganisationList)
{
foreach (var v2o in c2o.ValueList)
{
if (v2o.Entry.Value != null && v2o.Entry.Value.Contains("Schule"))
{
return c2o.Organisation;
}
}
}
return null;
}
private static Arbeitszeit GetStundenplan(Customer customer, DateTime start, DateTime ende)
{
var stundenplan = SucheStundenplan(customer.Arbeitszeiten, start, ende);
if (stundenplan == null)
{
//Kein Stundenplan hinterlegt, suche Stundenplan bei der Organisation (Schule)
var org = SucheSchule(customer);
if (org != null)
{
return SucheStundenplan(org.Arbeitszeiten, start, ende);
}
}
return stundenplan;
}
private static Arbeitszeit SucheStundenplan(IList<Arbeitszeit> arbeitszeiten, DateTime start, DateTime ende)
{
if (arbeitszeiten != null && arbeitszeiten.Count > 0)
{
foreach (var az in arbeitszeiten)
{
if ((!az.GueltigVon.HasValue || az.GueltigVon <= ende) && (!az.GueltigBis.HasValue || az.GueltigBis >= start))
{
return az;
}
}
}
return null;
}
private static List<InvoiceItem> ErstelleStundenplanEintraege(Arbeitszeit arbeitszeit, DateTime date)
{
List<InvoiceItem> result = new List<InvoiceItem>();
if (arbeitszeit != null && arbeitszeit.ArbeitszeitEintraege != null && arbeitszeit.ArbeitszeitEintraege.Count > 0)
{
if (arbeitszeit.GueltigVon <= date && date.Date <= arbeitszeit.GueltigBis)
{
var day = date.DayOfWeek;
foreach (var ae in arbeitszeit.ArbeitszeitEintraege)
{
if (SindAmGleichenWochentag(day, ae.Tag))
{
String dateStr1 = String.Format("{0:dd.MM.yyyy} {1}", date, ae.UhrzeitVon);
String dateStr2 = String.Format("{0:dd.MM.yyyy} {1}", date, ae.UhrzeitBis);
DateTime date1;
DateTime date2;
if (DateTime.TryParse(dateStr1, out date1) && DateTime.TryParse(dateStr2, out date2))
{
var item = new InvoiceItem();
item.ItemPeriodStart = date1;
item.ItemPeriodEnd = date2;
item.UnitCount = (decimal) date2.Subtract(date1).TotalHours;
if (ae.Employee != null)
{
item.ItemDescription = ae.Employee.Person.FirstNameLastName;
}
else
{
item.ItemDescription = "Hauptbetreuer";
}
result.Add(item);
}
}
}
}
}
return result;
}
private static decimal BerechneStunden(ArbeitszeitEintrag ae)
{
return 0;
}
private static bool SindAmGleichenWochentag(DayOfWeek day, AppointmentDayOfWeek aeTag)
{
if (day == DayOfWeek.Monday && aeTag == AppointmentDayOfWeek.Montag)
{
return true;
}
if (day == DayOfWeek.Tuesday && aeTag == AppointmentDayOfWeek.Dienstag)
{
return true;
}
if (day == DayOfWeek.Wednesday && aeTag == AppointmentDayOfWeek.Mittwoch)
{
return true;
}
if (day == DayOfWeek.Thursday && aeTag == AppointmentDayOfWeek.Donnerstag)
{
return true;
}
if (day == DayOfWeek.Friday && aeTag == AppointmentDayOfWeek.Freitag)
{
return true;
}
if (day == DayOfWeek.Saturday && aeTag == AppointmentDayOfWeek.Samstag)
{
return true;
}
return false;
}
public virtual InvoiceItem CreateInvoiceItem(ServiceRecordDC iServiceRecord, SupportConceptApprovalPeriod scap, Calculations calc)
{
var invoiceItem = new InvoiceItem();
BillingData bd = calc.GetBillingData(iServiceRecord);
invoiceItem.AmountPerUnit = bd.AmountPerUnit;
invoiceItem.UnitCount = bd.UnitCount;
invoiceItem.AmountTotal = bd.AmountTotal;
invoiceItem.ItemPeriodStart = bd.BillingPeriodStart;
invoiceItem.ItemPeriodEnd = bd.BillingPeriodEnd;
invoiceItem.RateFactor = bd.RateFactor;
invoiceItem.GrossAmountTotal = bd.GrossAmountTotal;
invoiceItem.AccountingInterval = bd.AccountingInterval;
invoiceItem.ItemDescription = iServiceRecord.ServiceDescription.Name; //iServiceRecord.Employee + " - " + iServiceRecord.ServiceDescription.Name;
invoiceItem.ServiceRecord = DAOFactory.GenericDAO.LoadByID<ServiceRecord>(iServiceRecord.ServiceRecordOid.Value);
if (scap != null)
invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid;
//var crs = iServiceRecord.CostBearer.CostRatePeriods;
//List<long> costRatePeriodOids = new List<long>();
//if (cdc != null)
// costRatePeriodOids.Add(cdc.CostRatePeriodOid.Value);
//cdc = crs.GetCostRatePeriodForDate(CostRatePeriodType.MinutesIntervall, iServiceRecord.Start.Value);
//if (cdc != null)
// costRatePeriodOids.Add(cdc.CostRatePeriodOid.Value);
//cdc = crs.GetCostRatePeriodForDate(CostRatePeriodType.MinutesPerServiceUnit, iServiceRecord.Start.Value);
//if (cdc != null)
// costRatePeriodOids.Add(cdc.CostRatePeriodOid.Value);
//cdc = crs.GetCostRatePeriodForDate(CostRatePeriodType.RateFactor, iServiceRecord.Start.Value);
//if (cdc != null)
// costRatePeriodOids.Add(cdc.CostRatePeriodOid.Value);
//cdc = crs.GetCostRatePeriodForDate(CostRatePeriodType.ServiceTolerance, iServiceRecord.Start.Value);
//if (cdc != null)
// costRatePeriodOids.Add(cdc.CostRatePeriodOid.Value);
//invoiceItem.CostRatePeriodList = DAOFactory.GenericDAO.LoadByIDs<CostRatePeriod>(costRatePeriodOids);
//var rateFactor = invoiceItem.CostRatePeriodList.SingleOrDefault(i => i.CostRateType == CostRatePeriodType.RateFactor);
//if (rateFactor != null && !iServiceRecord.CostBearer.IsCalculatingWithFactor)
//{
// invoiceItem.RateFactor = rateFactor.CostRateValue;
// invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal
// + (invoiceItem.AmountTotal * rateFactor.CostRateValue / 100);
//}
//else
//{
// invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal;
//}
return invoiceItem;
}
private decimal GetCostRateValue(List<CostRatePeriodDC> crList, CostRatePeriodType t, DateTime date)
{
var cp = crList.GetCostRatePeriodForDate(t, date);
if (cp != null && cp.CostRateValue.HasValue)
return cp.CostRateValue.Value;
return 0;
}
public override void CheckMaxApprovedAmount(ServiceInvoice invoice, ServiceInvoicePeriod sip, SupportConceptApprovalPeriodDC scap, CostBearer2SupportConcept costBearer2SupportConcept, DateTimeSpan invoicePeriod, List<ServiceRecordDC> serviceRecords)
{
//do nothing
}
public override IList<InvoiceItem> CreateSummaryInvoiceItems(IList<InvoiceItem> itemList, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap,
Calculations calc)
{
return itemList;
}
}
}