508 lines
19 KiB
C#
508 lines
19 KiB
C#
using BeWo.Data.Access;
|
|
using BeWo.Data.Entities;
|
|
using BeWo.Report.ReportObjects;
|
|
using BS.Shared.Core;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AkggMid
|
|
{
|
|
public class LeistungsnachweisHelper
|
|
{
|
|
private ServicesOverviewRO servicesOverviewRO;
|
|
private LeistungsnachweisHelper tandemBetreuungHelper = null;
|
|
|
|
public LeistungsnachweisHelper(ServicesOverviewRO ro, bool checkMehrfachBetreuung)
|
|
{
|
|
servicesOverviewRO = ro;
|
|
//Pruefe ob eine 1 zu 2 Betreuung vorliegt
|
|
if (checkMehrfachBetreuung)
|
|
{
|
|
var customers = Get1Zu2BetreuungCustomerOids();
|
|
|
|
if (customers.Count > 1)
|
|
{
|
|
foreach (var oid in customers)
|
|
{
|
|
if (oid != ro.CustomerOid)
|
|
{
|
|
//public static ServicesOverviewRO Create(long pCustomerOid, int pMonth, int pYear, bool disableEmptySupportConcepts, long orgaOid, long empOid, int start, int end, bool searchServiceRecordsByEndDate, long? serviceCategoryOid = null, bool checkQbStatus = false)
|
|
|
|
var tandemBetreuungRO = ServicesOverviewRO.Create(oid, ro.StartDate.Month, ro.StartDate.Year, false, 0, 0, ro.StartDate.Day, ro.EndDate.Day, null);
|
|
tandemBetreuungHelper = new LeistungsnachweisHelper(tandemBetreuungRO, false);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public List<ServicesOverviewRO.ServiceDetail> ErstelleDummyRecords(ServicesOverviewRO pRO)
|
|
{
|
|
Dictionary<int, ServicesOverviewRO.ServiceDetail> day2Detail = new Dictionary<int, ServicesOverviewRO.ServiceDetail>();
|
|
|
|
var result = new List<ServicesOverviewRO.ServiceDetail>();
|
|
foreach (var sr in pRO.Services)
|
|
{
|
|
//result.Add(sr);
|
|
|
|
if (!day2Detail.ContainsKey(sr.StartDate.Day))
|
|
{
|
|
sr.StartDateString = String.Format("{0:dddd dd.MM.}", sr.StartDate);
|
|
day2Detail.Add(sr.StartDate.Day, sr);
|
|
result.Add(sr);
|
|
}
|
|
else
|
|
{
|
|
var dsr = day2Detail[sr.StartDate.Day];
|
|
dsr.Minutes += sr.Minutes;
|
|
|
|
if (!String.IsNullOrWhiteSpace(sr.Notice))
|
|
{
|
|
if (!String.IsNullOrWhiteSpace(dsr.Notice))
|
|
{
|
|
dsr.Notice += ", " + sr.Notice;
|
|
}
|
|
else
|
|
{
|
|
dsr.Notice = sr.Notice;
|
|
}
|
|
|
|
}
|
|
|
|
if (!String.IsNullOrWhiteSpace(sr.Notice3))
|
|
{
|
|
if (!String.IsNullOrWhiteSpace(dsr.Notice3))
|
|
{
|
|
dsr.Notice3 += ", " + sr.Notice3;
|
|
}
|
|
else
|
|
{
|
|
dsr.Notice3 = sr.Notice3;
|
|
}
|
|
|
|
}
|
|
if (!String.IsNullOrWhiteSpace(sr.Notice4))
|
|
{
|
|
if (!String.IsNullOrWhiteSpace(dsr.Notice4))
|
|
{
|
|
dsr.Notice4 += ", " + sr.Notice4;
|
|
}
|
|
else
|
|
{
|
|
dsr.Notice4 = sr.Notice4;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
var abrAbwTagDict = GetAbrechenbareAbwesenheiten();
|
|
|
|
double wochensumme = 0;
|
|
for (int i = 1; i <= pRO.EndDate.Day; i++)
|
|
{
|
|
if (!day2Detail.ContainsKey(i))
|
|
{
|
|
//Erstelle Dummy Records für fehlende Tage
|
|
var newSr = new ServicesOverviewRO.ServiceDetail();
|
|
if (i <= pRO.EndDate.Day)
|
|
{
|
|
newSr.StartDate = new DateTime(pRO.StartDate.Year, pRO.StartDate.Month, i);
|
|
newSr.StartDateString = String.Format("{0:dddd dd.MM.}", newSr.StartDate);
|
|
|
|
if (abrAbwTagDict.ContainsKey(newSr.StartDate))
|
|
{
|
|
newSr.Minutes = BerechneMinutenProTag(BerechneStundenProWoche(pRO, newSr.StartDate));
|
|
newSr.Notice = "Abwesenheit (erstattet)";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newSr.StartDateString = String.Format("", i);
|
|
}
|
|
|
|
result.Add(newSr);
|
|
day2Detail.Add(i, newSr);
|
|
}
|
|
else
|
|
{
|
|
//day2Detail[i].Minutes = Rundeauf15Minuten(day2Detail[i].Minutes);
|
|
|
|
}
|
|
|
|
//Erstelle Dummy Record für Wochensumme
|
|
var record = day2Detail[i];
|
|
day2Detail[i].TimeRangeString = String.Format("{0:00}", i); // Benutzer TimeRangeString für die Sortierung
|
|
wochensumme += record.Minutes;
|
|
if (record.StartDate.DayOfWeek == DayOfWeek.Friday || i == pRO.EndDate.Day)
|
|
{
|
|
var newSr = new ServicesOverviewRO.ServiceDetail();
|
|
newSr.StartDateString = "";
|
|
newSr.Notice = "Wochensumme";
|
|
newSr.IstFerien = true;
|
|
newSr.TimeRangeString = String.Format("{0:00}z", i);
|
|
newSr.Minutes = Rundeauf15Minuten(wochensumme);
|
|
wochensumme = 0;
|
|
result.Add(newSr);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
double minutenGesamt = 0;
|
|
foreach (var record in result)
|
|
{
|
|
if (record.StartDate.DayOfWeek != DayOfWeek.Saturday && record.StartDate.DayOfWeek != DayOfWeek.Sunday && IstAbwesend(record.StartDate))
|
|
{
|
|
record.Notice5 = "x";
|
|
}
|
|
else
|
|
{
|
|
record.Notice5 = "";
|
|
}
|
|
if (record.IstFerien) // Wochensumme
|
|
{
|
|
minutenGesamt += record.Minutes;
|
|
}
|
|
|
|
|
|
if (record.StartDate.DayOfWeek == DayOfWeek.Saturday)
|
|
{
|
|
record.IstSamstag = true;
|
|
}
|
|
else if (record.StartDate.DayOfWeek == DayOfWeek.Sunday)
|
|
{
|
|
record.IstSonntag = true;
|
|
}
|
|
}
|
|
pRO.TotalFLM = minutenGesamt;
|
|
return result.OrderBy(r => r.TimeRangeString).ToList();
|
|
}
|
|
|
|
public void PruefeWochenBudget(ServicesOverviewRO ro)
|
|
{
|
|
Calendar cal = CultureInfo.CurrentCulture.Calendar;
|
|
|
|
var ersterTag = new DateTime(ro.StartDate.Year, ro.StartDate.Month, 1);
|
|
//Laut Herr Kloss darf die Wochenbewilligung nicht überschritten werden und die letzten Einträge einer Kalenderwoche sollen entsprechend gekürzt werden.
|
|
|
|
var tempListe = new List<ServicesOverviewRO.ServiceDetail>();
|
|
tempListe.AddRange(HoleFehlendeWochentageVormonat(ro));
|
|
|
|
|
|
tempListe.AddRange(ro.Services);
|
|
|
|
|
|
|
|
|
|
int kwAktuelleWoche = cal.GetWeekOfYear(ersterTag, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
|
|
double wochenSumme = 0;
|
|
|
|
foreach (var item in tempListe)
|
|
{
|
|
// Übertrags Dummy rausfiltern
|
|
if (item.ServiceDescription == "Übertrag:")
|
|
continue;
|
|
|
|
var kwAktuellerTag = cal.GetWeekOfYear(item.StartDate, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
|
|
if (kwAktuelleWoche != kwAktuellerTag)
|
|
{
|
|
kwAktuelleWoche = kwAktuellerTag;
|
|
wochenSumme = 0;
|
|
}
|
|
|
|
|
|
wochenSumme += item.Minutes / 60;
|
|
double wochenBudget = BerechneStundenProWoche(ro, item.StartDate);
|
|
if (wochenSumme > wochenBudget)
|
|
{
|
|
item.Minutes -= (double)(wochenSumme - wochenBudget) * 60;
|
|
if (item.Minutes < 0)
|
|
{
|
|
item.Minutes = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
double minutenGesamt = 0;
|
|
foreach (var record in ro.Services)
|
|
{
|
|
minutenGesamt += record.Minutes;
|
|
}
|
|
ro.TotalFLM = minutenGesamt;
|
|
}
|
|
|
|
private double BerechneStundenProWoche(ServicesOverviewRO ro, DateTime datum)
|
|
{
|
|
if (ro.SupportConceptCostBearer != null)
|
|
{
|
|
decimal wochenGesamtBudget = 0;
|
|
foreach (var ap in ro.SupportConceptCostBearer.ApprovalPeriodList)
|
|
{
|
|
if (ap.StartDate <= datum.Date && ap.EndDate >= datum.Date && ap.ApprovedBEInterval.Value == BS.Shared.SupportConceptApprovalInterval.Weekly)
|
|
{
|
|
|
|
var wochenBudget = ap.ApprovedBEPerInterval ?? 0;
|
|
|
|
decimal prozentualeBetreuung = 0;
|
|
foreach (var item in ap.SupportConceptApprovalPeriodEmployeeRelations)
|
|
{
|
|
if (!item.IsAbsolut)
|
|
{
|
|
prozentualeBetreuung += item.Betreuungsschluessel;
|
|
}
|
|
}
|
|
|
|
if (prozentualeBetreuung > 0)
|
|
{
|
|
wochenBudget *= prozentualeBetreuung / 100;
|
|
}
|
|
|
|
wochenGesamtBudget += wochenBudget;
|
|
}
|
|
}
|
|
if (wochenGesamtBudget > 0)
|
|
{
|
|
return (double)Math.Round(wochenGesamtBudget, 2, MidpointRounding.AwayFromZero);
|
|
}
|
|
}
|
|
|
|
return (double)ro.ApprovedFLSPerWeek;
|
|
}
|
|
|
|
private List<long> Get1Zu2BetreuungCustomerOids()
|
|
{
|
|
List<long> result = new List<long>();
|
|
|
|
if (this.servicesOverviewRO.SupportConceptCostBearer != null)
|
|
{
|
|
foreach (var ap in servicesOverviewRO.SupportConceptCostBearer.ApprovalPeriodList)
|
|
{
|
|
if (ap.StartDate <= servicesOverviewRO.EndDate.Date && ap.EndDate >= servicesOverviewRO.StartDate.Date)
|
|
{
|
|
foreach (var item in ap.SupportConceptApprovalPeriodEmployeeRelations)
|
|
{
|
|
if (!item.IsAbsolut && item.Betreuungsschluessel == 50)
|
|
{
|
|
//Ja ist eine 1:2 Betreuung
|
|
var sql = String.Format(@"select c.oid
|
|
from supportconceptapprovalperiod2employee scap2e
|
|
join supportconceptapprovalperiod scap on scap2e.SupportConceptApprovalPeriodOid = scap.oid
|
|
join costbearer2supportconcept c2s on scap.CostBearer2SupportConceptOid = c2s.oid
|
|
join supportconcept sc on c2s.SupportConceptOid = sc.oid
|
|
join customer c on sc.customeroid = c.oid
|
|
where scap2e.EmployeeOid = {0} and scap.Start <= '{1:yyyy-MM-dd}' and scap.EndDate >= '{2:yyyy-MM-dd}' and scap2e.Betreuungsschluessel = 50", item.Employee.EmployeeOid, servicesOverviewRO.EndDate.Date, servicesOverviewRO.StartDate.Date);
|
|
var sqlresult = DAOFactory.SearchDAO.GetSqlResult(sql);
|
|
|
|
foreach (long oid in sqlresult)
|
|
{
|
|
result.Add(oid);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private IEnumerable<ServicesOverviewRO.ServiceDetail> HoleFehlendeWochentageVormonat(ServicesOverviewRO ro)
|
|
{
|
|
var fehlendeRecords = new List<ServicesOverviewRO.ServiceDetail>();
|
|
|
|
var ersterDesMonats = new DateTime(ro.StartDate.Year, ro.StartDate.Month, 1);
|
|
|
|
if (ersterDesMonats.DayOfWeek != DayOfWeek.Monday)
|
|
{
|
|
if (ro.SupportConceptCostBearer != null && ro.SupportConceptCostBearer.CostBearer2SupportConceptOid != null)
|
|
{
|
|
|
|
var startDate = ersterDesMonats;
|
|
|
|
while (startDate.DayOfWeek != DayOfWeek.Monday)
|
|
{
|
|
startDate = startDate.AddDays(-1);
|
|
}
|
|
|
|
var span = new DateTimeSpan(startDate, ersterDesMonats);
|
|
|
|
var liste = DAOFactory.SearchDAO.FindServiceRecordsInSpan(ro.SupportConceptCostBearer.CostBearer2SupportConceptOid.Value, span);
|
|
|
|
foreach (var item in liste)
|
|
{
|
|
var newRecord = new ServicesOverviewRO.ServiceDetail();
|
|
newRecord.StartDate = item.Start.Value;
|
|
newRecord.Minutes = (double)item.RoundedDuration;
|
|
|
|
fehlendeRecords.Add(newRecord);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return fehlendeRecords.OrderBy(r => r.StartDate);
|
|
|
|
}
|
|
|
|
public bool IstAbwesend(DateTime startDate)
|
|
{
|
|
foreach (var at in servicesOverviewRO.Abwesenheiten)
|
|
{
|
|
if (startDate >= at.Start && (!at.End.HasValue || startDate <= at.End))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
public Dictionary<DateTime, bool> GetAbrechenbareAbwesenheiten()
|
|
{
|
|
//Herr Kloss meint, der erste Tag einer Abwesenheit darf ein fünftel der Wochenstundenzahl abgerechnet werden, aber nur bis 5 mal im Zeitraum 01.01.2023 bis 21.07.2023 und bis 10 mal im Schuljahr ab 2023/2024
|
|
|
|
DateTime startSchuljahr = DateTime.MinValue;
|
|
DateTime endeSchuljahr = DateTime.MinValue;
|
|
|
|
DateTime dt;
|
|
|
|
if (DateTime.TryParse(servicesOverviewRO.ApprovedStartDate, out dt))
|
|
{
|
|
startSchuljahr = dt;
|
|
}
|
|
if (DateTime.TryParse(servicesOverviewRO.ApprovedEndDate, out dt))
|
|
{
|
|
endeSchuljahr = dt;
|
|
}
|
|
|
|
|
|
int maxAnzahl = 10;
|
|
|
|
if (startSchuljahr < new DateTime(2023, 7, 21))
|
|
{
|
|
startSchuljahr = new DateTime(2023, 1, 1);
|
|
endeSchuljahr = new DateTime(2023, 7, 21);
|
|
|
|
maxAnzahl = 5;
|
|
}
|
|
|
|
int gesamtAnzahl = 0;
|
|
|
|
Dictionary<DateTime, bool> abrechenbareTage = new Dictionary<DateTime, bool>();
|
|
|
|
var c = DAOFactory.GenericDAO.LoadByID<Customer>(servicesOverviewRO.CustomerOid);
|
|
foreach (AbsenceTime at in c.AbsenceTimes.OrderBy(a => a.Start))
|
|
{
|
|
if (at.Start >= startSchuljahr && at.Start <= endeSchuljahr && (at.End == null || at.End >= startSchuljahr))
|
|
{
|
|
|
|
DateTime dtIterator = at.Start.Value;
|
|
DateTime end = endeSchuljahr;
|
|
if (at.End.HasValue)
|
|
{
|
|
end = at.End.Value;
|
|
}
|
|
|
|
|
|
while (dtIterator <= end && gesamtAnzahl < maxAnzahl)
|
|
{
|
|
if (dtIterator.DayOfWeek != DayOfWeek.Saturday && dtIterator.DayOfWeek != DayOfWeek.Sunday)
|
|
{
|
|
bool istAbrechenbar = true;
|
|
if (tandemBetreuungHelper != null)
|
|
{
|
|
istAbrechenbar = false;
|
|
|
|
if (tandemBetreuungHelper.IstAbwesend(dtIterator))
|
|
{
|
|
istAbrechenbar = true;
|
|
}
|
|
}
|
|
if (istAbrechenbar)
|
|
{
|
|
abrechenbareTage.Add(dtIterator, true);
|
|
gesamtAnzahl++;
|
|
}
|
|
}
|
|
dtIterator = dtIterator.AddDays(1);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//int gesamtAnzahl = 0;
|
|
|
|
//Dictionary<DateTime, bool> abrechenbareTage = new Dictionary<DateTime, bool>();
|
|
|
|
//DateTime lastend = DateTime.MinValue;
|
|
//foreach (var at in ro.Abwesenheiten)
|
|
//{
|
|
// if (at.Start >= startSchuljahr && at.Start <= endeSchuljahr && (at.End == null || at.End >= startSchuljahr))
|
|
// {
|
|
// //Prüfe ob mindestens ein Tag zwischen zwei Abwesenheiten liegt.
|
|
// var days = at.Start.Value.Subtract(lastend).TotalDays;
|
|
// if (days > 1)
|
|
// {
|
|
|
|
// if (gesamtAnzahl <= maxAnzahl)
|
|
// {
|
|
// abrechenbareTage.Add(at.Start.Value, true);
|
|
|
|
// gesamtAnzahl++;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// if (at.End.HasValue)
|
|
// {
|
|
// lastend = at.End.Value;
|
|
// }
|
|
// else
|
|
// {
|
|
// lastend = DateTime.MaxValue;
|
|
// }
|
|
//}
|
|
|
|
return abrechenbareTage;
|
|
}
|
|
|
|
public double BerechneMinutenProTag(double flsPerWeek)
|
|
{
|
|
var minutenProTag = flsPerWeek * 60 / 5;
|
|
return minutenProTag;
|
|
|
|
//die Minuten müssen auf volle Viertelstunden auf oder abgerundet werden
|
|
//return Rundeauf15Minuten(minutenProTag);
|
|
|
|
}
|
|
|
|
public double Rundeauf15Minuten(double minuten)
|
|
{
|
|
var minutenGerundet = minuten;
|
|
|
|
//die Minuten müssen auf volle Viertelstunden auf oder abgerundet werden
|
|
var modulo = minutenGerundet % 15;
|
|
if (modulo <= 7)
|
|
{
|
|
minutenGerundet -= modulo;
|
|
}
|
|
else
|
|
{
|
|
minutenGerundet += 15 - modulo;
|
|
}
|
|
return minutenGerundet;
|
|
}
|
|
}
|
|
}
|