359 lines
12 KiB
C#
359 lines
12 KiB
C#
using BeWo.Data.Access;
|
|
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
|
|
{
|
|
public static 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:dd}.", 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(pRO);
|
|
|
|
for (int i = 1; i <= 31; i++)
|
|
{
|
|
if (!day2Detail.ContainsKey(i))
|
|
{
|
|
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:dd}.", newSr.StartDate);
|
|
|
|
if (abrAbwTagDict.ContainsKey(newSr.StartDate))
|
|
{
|
|
newSr.Minutes = BerechneMinutenProTag(BerechneStundenProWoche(pRO, newSr.StartDate));
|
|
newSr.Notice = "Erster Tag Abwesenheit";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newSr.StartDateString = String.Format("{0}.", i);
|
|
}
|
|
|
|
result.Add(newSr);
|
|
day2Detail.Add(i, newSr);
|
|
}
|
|
else
|
|
{
|
|
day2Detail[i].Minutes = Rundeauf15Minuten(day2Detail[i].Minutes);
|
|
}
|
|
}
|
|
|
|
double minutenGesamt = 0;
|
|
foreach (var record in result)
|
|
{
|
|
if (IstAbwesend(pRO, record.StartDate))
|
|
{
|
|
record.Notice5 = "x";
|
|
}
|
|
else
|
|
{
|
|
record.Notice5 = "";
|
|
}
|
|
minutenGesamt += record.Minutes;
|
|
}
|
|
pRO.TotalFLM = minutenGesamt;
|
|
return result.OrderBy(r => r.StartDateString).ToList();
|
|
}
|
|
|
|
public static 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 static 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 static 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 static bool IstAbwesend(ServicesOverviewRO pRO, DateTime startDate)
|
|
{
|
|
foreach (var at in pRO.Abwesenheiten)
|
|
{
|
|
if (startDate >= at.Start && (!at.End.HasValue || startDate <= at.End))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
public static Dictionary<DateTime, bool> GetAbrechenbareAbwesenheiten(ServicesOverviewRO ro)
|
|
{
|
|
//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.2022 bis 30.06.2022 und bis 10 mal im Schuljahr ab 2023/2024
|
|
|
|
DateTime startSchuljahr = DateTime.MinValue;
|
|
DateTime endeSchuljahr = DateTime.MinValue;
|
|
|
|
DateTime dt;
|
|
|
|
if (DateTime.TryParse(ro.ApprovedStartDate, out dt))
|
|
{
|
|
startSchuljahr = dt;
|
|
}
|
|
if (DateTime.TryParse(ro.ApprovedEndDate, out dt))
|
|
{
|
|
endeSchuljahr = dt;
|
|
}
|
|
|
|
|
|
int maxAnzahl = 10;
|
|
|
|
if (startSchuljahr < new DateTime(2022, 6, 30))
|
|
{
|
|
startSchuljahr = new DateTime(2022, 1, 1);
|
|
endeSchuljahr = new DateTime(2022, 6, 30);
|
|
|
|
maxAnzahl = 5;
|
|
}
|
|
|
|
int gesamtAnzahl = 0;
|
|
|
|
Dictionary<DateTime, bool> abrechenbareTage = new Dictionary<DateTime, bool>();
|
|
|
|
DateTime lastend = DateTime.MinValue;
|
|
foreach (var at in ro.Abwesenheiten) //sortieren?
|
|
{
|
|
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 static double BerechneMinutenProTag(double flsPerWeek)
|
|
{
|
|
var minutenProTag = flsPerWeek * 60 / 5;
|
|
|
|
//die Minuten müssen auf volle Viertelstunden auf oder abgerundet werden
|
|
return Rundeauf15Minuten(minutenProTag);
|
|
|
|
}
|
|
|
|
public static 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;
|
|
}
|
|
}
|
|
}
|