Files
BeWoPlaner/Report/ReportObjects/MitarbeiterstundenkontoBerechnung.cs
2017-02-01 13:53:59 +01:00

1504 lines
46 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using BeWo.Report;
using BeWo.Data.Entities;
using BeWo.Data.Access;
using BeWo.Service.Configuration;
using BeWo.Service.ServiceImplementations;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.Extensions;
using DevExpress.XtraCharts.Native;
namespace BeWo.Report.ReportObjects
{
public class MitarbeiterstundenkontoBerechnung
{
private decimal maxWochenstunden = 40;
private AppSettings appSettings;
private const int ANZ_WOCHENTAGE = 5;
public MitarbeiterstundenkontoBerechnung()
{
appSettings = AppSettings.CreateSettings();
}
public MitarbeiterstundenkontoBerechnung(decimal maxWochenstunden) : this()
{
this.maxWochenstunden = maxWochenstunden;
}
public virtual void CreateReport(MitarbeiterstundenkontoRO ro)
{
CreateEmployeeDetails(ro);
CreateTeamDetails(ro);
CreateTotals(ro);
}
public virtual void CreateTotals(MitarbeiterstundenkontoRO ro)
{
foreach (var empDetail in ro.EmployeeDetailList)
{
ro.SollGesamt += empDetail.StundenSollOhneUrlaubKrankheit;
ro.FlsSollGesamt += empDetail.FlsSoll;
ro.FlsIstGesamt += empDetail.FlsIst;
ro.MittelbarIst += empDetail.MittelbarIst;
ro.FlsDiffGesamt += empDetail.FlsDiff;
ro.StundenGesamt += empDetail.StundenGesamtIst;
}
if (ro.FlsSollGesamt != 0)
ro.RelationIstSollGesamt = (ro.FlsIstGesamt / ro.FlsSollGesamt) * 100m;
if (ro.FlsIstGesamt + ro.MittelbarIst != 0)
ro.RelationFlsZuMittelbar = (ro.FlsIstGesamt / (ro.FlsIstGesamt + ro.MittelbarIst)) * 100;
}
public virtual void CreateTeamDetails(MitarbeiterstundenkontoRO ro)
{
foreach (var teamDetail in ro.TeamDetailList)
{
teamDetail.EmployeeDetailList = FilterEmployeeList(teamDetail.EmployeeDetailList);
foreach (var empDetail in teamDetail.EmployeeDetailList)
{
teamDetail.SollGesamt += empDetail.StundenSollOhneUrlaubKrankheit;
teamDetail.FlsSollGesamt += empDetail.FlsSoll;
teamDetail.FlsIstGesamt += empDetail.FlsIst;
teamDetail.MittelbarIst += empDetail.MittelbarIst;
teamDetail.FlsDiffGesamt += empDetail.FlsDiff;
teamDetail.StundenGesamt += empDetail.StundenGesamtIst;
}
if (teamDetail.FlsSollGesamt != 0)
teamDetail.RelationIstSollGesamt = (teamDetail.FlsIstGesamt / teamDetail.FlsSollGesamt) * 100m;
if (teamDetail.FlsIstGesamt + teamDetail.MittelbarIst != 0)
teamDetail.RelationFlsZuMittelbar = (teamDetail.FlsIstGesamt / (teamDetail.FlsIstGesamt + teamDetail.MittelbarIst)) * 100;
}
}
public virtual void CreateEmployeeDetails(MitarbeiterstundenkontoRO ro)
{
foreach (var empDetail in ro.EmployeeDetailList)
{
DateTime monatsAnfang = ro.ReportStartDate;
DateTime monatsEnde = monatsAnfang.AddMonths(1);
DateTime berichtsAnfang = monatsAnfang;
DateTime berichtsEnde = monatsEnde;
Employee emp = empDetail.Employee;
decimal bu = 0;
int anzWochentage = ANZ_WOCHENTAGE;
Contract c = emp.GetValidContractForDate(ro.ReportStartDate);
if (c == null) // Kein Vertrag vom 1. gefunden, gucken, ob es einen gibt, der mitten im Monat beginnt.
{
var c2 = GetNextValidContractForDate(ro.ReportStartDate, emp);
if (c2 != null && c2.EntryDate.HasValue && c2.EntryDate.Value < ro.ReportEndDate)
c = c2;
}
if (c != null)
{
if (c.EntryDate.HasValue && c.EntryDate > monatsAnfang)
{
berichtsAnfang = c.EntryDate.Value;
}
if (c.ContractEndDate.HasValue && c.ContractEndDate < monatsEnde)
{
berichtsEnde = c.ContractEndDate.Value.Date.AddDays(1);
}
empDetail.HasContract = true;
}
decimal flsIst = 0;
decimal mittelbarIst = 0;
decimal pause1 = 0;
decimal pause2 = 0;
decimal weeklyTotalHours = 0;
decimal flsSollGesamt = 0;
decimal? fehlZeitenGesamt = null;
decimal? tageUrlaubGesamt = null;
decimal? tageKrankheitGesamt = null;
decimal? abwesenheitTageGesamt = null;
decimal workdaysTotal = 0;
decimal stundenSollGesamt = 0;
decimal tatsaechlicheSollStdGesamt = 0;
IList<ServiceRecord> recordsAll = DAOFactory.SearchDAO.FindServiceRecords(emp.Oid, null);
recordsAll = AnalysisServiceImp.FilterActiveServiceRecords(recordsAll);
IList<ServiceRecord> recordsThisMonth = new List<ServiceRecord>();
IList<ServiceRecord> groupFilteredRecords = new List<ServiceRecord>();
Dictionary<long, bool> groupBookingDict = new Dictionary<long, bool>();
foreach (var item in recordsAll)
{
if (!item.GroupOid.HasValue || !groupBookingDict.ContainsKey(item.GroupOid.Value))
{
groupFilteredRecords.Add(item);
if (item.GroupOid.HasValue)
{
groupBookingDict.Add(item.GroupOid.Value, true);
}
}
}
while (berichtsAnfang < berichtsEnde)
{
var arbeitstage = GetArbeitstageImBereich(berichtsAnfang, berichtsEnde, emp);
//if (anzWochentage != 5)
//{
// arbeitstage *= anzWochentage/5m;
//}
workdaysTotal += arbeitstage;
weeklyTotalHours = 0;
if (c != null)
{
if (c.WeeklyTotalHours.HasValue)
{
weeklyTotalHours = c.WeeklyTotalHours.Value;
bu = c.WeeklyTotalHours.Value/this.maxWochenstunden;
}
//if (c.WeeklyDays.HasValue && c.WeeklyDays.Value > 0)
//{
// anzWochentage = c.WeeklyDays.Value;
//}
//if (c.EntryDate > ro.ReportStartDate)
// bu = 0;
}
var stundenSollProMonat = BerechneSollProMonat(emp, berichtsAnfang, berichtsEnde);
var stundenSoll = stundenSollProMonat;
if (!stundenSoll.HasValue)
{
stundenSoll = arbeitstage*(weeklyTotalHours/anzWochentage);
}
stundenSollGesamt += stundenSoll ?? 0;
tatsaechlicheSollStdGesamt += stundenSoll ?? 0;
HandleServiceRecords(empDetail, groupFilteredRecords, c);
foreach (var item in groupFilteredRecords)
{
if (!IsServiceRecordFehlzeit(item))
{
if (item.Start.Value >= berichtsAnfang && item.Start.Value < berichtsEnde)
{
String test = String.Format("{0:dd.MM.yyyy HH:mm}, {1:0} Minuten, {2}, {3}", item.Start, item.RoundedDuration, item.ServiceDescription.Name, item.Notice);
HandleServiceRecord(empDetail, item);
if (AddServiceRecordToDuration(item))
{
decimal duration = 0;
if (item.GroupRoundedDuration.HasValue)
{
duration = item.GroupRoundedDuration.Value;
}
else
{
if (appSettings.ShowRoundedDurationInEmployeeAnalysis)
{
duration = item.RoundedDuration;
}
else
{
duration = (decimal) item.End.Value.Subtract(item.Start.Value).TotalMinutes;
}
}
if (item.ServiceDescription != null &&
item.ServiceDescription.ServiceCategory != null &&
item.ServiceDescription.ServiceCategory.IsBillable)
flsIst += duration;
else
mittelbarIst += duration;
}
recordsThisMonth.Add(item);
}
}
}
if (SollPauseBerechnen())
{
pause1 += BerechnePauseMinuten(recordsThisMonth);
pause2 += BerechneAutoPausen(recordsThisMonth);
}
var flsSollProMonat = BerechneFlsSollProMonat(emp, berichtsAnfang, berichtsEnde);
decimal? fehlZeiten = GetFehlzeiten(groupFilteredRecords, berichtsAnfang, berichtsEnde);
if (fehlZeiten.HasValue)
{
if (!fehlZeitenGesamt.HasValue)
fehlZeitenGesamt = 0;
fehlZeitenGesamt += fehlZeiten;
tatsaechlicheSollStdGesamt -= fehlZeiten.Value;
}
var ath = GetAbsenceTimeDays(emp.AbsenceTimes, berichtsAnfang, berichtsEnde);
if (ath.TageUrlaub.HasValue)
{
if (!tageUrlaubGesamt.HasValue)
tageUrlaubGesamt = 0;
tageUrlaubGesamt += ath.TageUrlaub;
}
if (ath.TageKrankheit.HasValue)
{
if (!tageKrankheitGesamt.HasValue)
tageKrankheitGesamt = 0;
tageKrankheitGesamt += ath.TageKrankheit;
}
empDetail.ArbeitstageProWoche = anzWochentage;
if (ath.TageGesamt.HasValue)
{
if (!abwesenheitTageGesamt.HasValue)
abwesenheitTageGesamt = 0;
abwesenheitTageGesamt += ath.TageGesamt;
if (c != null && c.WeeklyDays.HasValue && c.WeeklyDays.Value > 0)
{
empDetail.ArbeitstageProWoche = c.WeeklyDays.Value;
}
if (stundenSollProMonat.HasValue)
{
decimal stundenProTag = stundenSollProMonat.Value/arbeitstage;
tatsaechlicheSollStdGesamt -= (ath.TageGesamt.Value * stundenProTag);
}
else
{
tatsaechlicheSollStdGesamt -= (ath.TageGesamt.Value * (weeklyTotalHours / empDetail.ArbeitstageProWoche));
}
}
flsSollGesamt = tatsaechlicheSollStdGesamt;
if (flsSollProMonat.HasValue)
{
if (stundenSollProMonat.HasValue)
{
flsSollGesamt *= flsSollProMonat.Value / stundenSollProMonat.Value;
}
}
else
{
if (c != null && c.WeeklyFLS.HasValue && c.WeeklyTotalHours.HasValue && c.WeeklyTotalHours.Value != 0)
flsSollGesamt *= c.WeeklyFLS.Value / c.WeeklyTotalHours.Value;
}
berichtsAnfang = berichtsEnde;
berichtsEnde = monatsEnde;
c = GetNextValidContractForDate(berichtsAnfang, emp);
if (c != null)
{
if (c.EntryDate.HasValue && c.EntryDate >= berichtsAnfang)
berichtsAnfang = c.EntryDate.Value;
if (c.ContractEndDate.HasValue && c.ContractEndDate < monatsEnde)
{
berichtsEnde = c.ContractEndDate.Value.Date.AddDays(1);
}
}
}
if (AddRateFactorToIst() != 1)
{
flsIst *= AddRateFactorToIst();
}
flsIst /= 60m;
mittelbarIst /= 60m;
empDetail.WorkDaysThisMonth = workdaysTotal;
//decimal stundenSollMax = arbeitstage * (maxWochenstunden / xxx) * bu;
empDetail.SollProTag = (weeklyTotalHours/ anzWochentage);
empDetail.StundenSollMax = stundenSollGesamt;
empDetail.Fehlzeiten = fehlZeitenGesamt;
empDetail.TageUrlaub = tageUrlaubGesamt;
empDetail.TageKrankheit = tageKrankheitGesamt;
empDetail.UrlaubUndKrankheit = abwesenheitTageGesamt;
empDetail.StundenSollOhneUrlaubKrankheit = tatsaechlicheSollStdGesamt;
empDetail.FlsSoll = flsSollGesamt;
empDetail.MittelbarIst = mittelbarIst;
empDetail.Bu = bu;
empDetail.FlsIst = flsIst;
empDetail.FlsDiff = flsIst - empDetail.FlsSoll;
empDetail.StundenMittelbarIst = mittelbarIst;
empDetail.StundenGesamtIst = flsIst + mittelbarIst;
empDetail.StundenGesamtIst -= pause1/60;
empDetail.StundenGesamtIst -= pause2/60;
if (empDetail.FlsSoll != 0)
empDetail.RelationIstSoll = (empDetail.FlsIst/empDetail.FlsSoll)*100m;
if (flsIst + mittelbarIst != 0)
empDetail.RelationFlsZuMittelbar = (flsIst/(flsIst + mittelbarIst))*100;
decimal? ueberstunden = empDetail.StundenGesamtIst - empDetail.StundenSollOhneUrlaubKrankheit;
decimal? ueberstundenVormonat;
decimal alteExtraUeberstunden = 0;
BerechneUeberstundenBis(emp, groupFilteredRecords, ro.ReportStartDate, out ueberstundenVormonat,
out alteExtraUeberstunden);
decimal extraStunden = 0;
BerechneExtraUeberstunden(emp, monatsAnfang, monatsEnde, out extraStunden);
if (ShouldCreateDayDetails())
{
empDetail.Days = CreateDayDetails(monatsAnfang, monatsEnde, empDetail, recordsThisMonth);
var ah = GetAdditionalHours(empDetail.Days, monatsAnfang, monatsEnde, empDetail, recordsThisMonth);
ueberstunden += ah;
empDetail.StundenGesamtIst += ah;
}
empDetail.Ueberstunden = ueberstunden;
empDetail.UeberstundenVormonat = ueberstundenVormonat;
if (!empDetail.UeberstundenGesamt.HasValue)
empDetail.UeberstundenGesamt = ((ueberstundenVormonat ?? 0) + (ueberstunden ?? 0)) + extraStunden;
else
empDetail.UeberstundenGesamt += ((ueberstundenVormonat ?? 0) + (ueberstunden ?? 0)) + extraStunden;
empDetail.UeberstundenAusbezahlt = extraStunden;
//Urlaubskonto (todo)
empDetail.UrlaubGesamtImAktuellenJahr =
GetAbsenceTimeDays(emp.AbsenceTimes, new DateTime(monatsAnfang.Year, 1, 1), monatsEnde).TageUrlaub;
}
ro.EmployeeDetailList = FilterEmployeeList(ro.EmployeeDetailList);
}
public virtual decimal BerechneAutoPausen(IList<ServiceRecord> recordsThisMonth)
{
return 0;
}
public virtual decimal BerechnePauseMinuten(IList<ServiceRecord> srList)
{
decimal pausenZeit = 0;
List<ServiceRecord> pausen = new List<ServiceRecord>();
List<ServiceRecord> nichtpausen = new List<ServiceRecord>();
foreach (var sr in srList)
{
if (sr.ServiceDescription.Name == "Pause")
{
pausen.Add(sr);
}
else
{
nichtpausen.Add(sr);
}
}
foreach (var pause in pausen)
{
foreach (var arbeitszeit in nichtpausen)
{
var pauseSpan = new DateTimeSpan
{
StartDateTime = pause.Start.Value,
EndDateTime = pause.Start.Value.AddMinutes((double) pause.RoundedDuration)
};
var arbeitszeitSpan = new DateTimeSpan
{
StartDateTime = arbeitszeit.Start.Value,
EndDateTime = arbeitszeit.Start.Value.AddMinutes((double) arbeitszeit.RoundedDuration)
};
if (arbeitszeit.GroupOid.HasValue)
{
arbeitszeitSpan.EndDateTime =
arbeitszeit.Start.Value.AddMinutes((double) (arbeitszeit.GroupRoundedDuration ?? 0));
}
if (pauseSpan.Overlaps(arbeitszeitSpan))
{
DateTime startUeberlappung = pauseSpan.StartDateTime;
if (arbeitszeitSpan.StartDateTime > startUeberlappung)
startUeberlappung = arbeitszeitSpan.StartDateTime;
DateTime endUeberlappung = pauseSpan.EndDateTime;
if (arbeitszeitSpan.EndDateTime < endUeberlappung)
endUeberlappung = arbeitszeitSpan.EndDateTime;
var overlapping = (decimal) endUeberlappung.Subtract(startUeberlappung).TotalMinutes;
pausenZeit += overlapping;
}
}
}
return pausenZeit;
}
public virtual bool SollPauseBerechnen()
{
return false;
}
public virtual List<MitarbeiterstundenkontoRO.EmployeeDetail> FilterEmployeeList(List<MitarbeiterstundenkontoRO.EmployeeDetail> employeeDetailList)
{
List<MitarbeiterstundenkontoRO.EmployeeDetail> newEmpList = new List<MitarbeiterstundenkontoRO.EmployeeDetail>();
foreach (var ed in employeeDetailList)
{
if (ed.Employee.IsActive == ActivationTypeId.Active)
{
newEmpList.Add(ed);
}
else if (ed.Employee.IsActive == ActivationTypeId.Archived)
{
if (ed.StundenGesamtIst != 0)
{
newEmpList.Add(ed);
}
}
}
return newEmpList;
}
public virtual void HandleServiceRecords(MitarbeiterstundenkontoRO.EmployeeDetail empDetail, IList<ServiceRecord> groupFilteredRecords, Contract contract)
{
//do nothing
}
public virtual void CorrectOverlappingTimes(IList<ServiceRecord> serviceRecords)
{
List<ServiceRecord> oldRecords = new List<ServiceRecord>();
foreach (var newRecord in serviceRecords)
{
if (!CorrectOverlappingTime(newRecord))
{
continue;
}
if (newRecord.Start.HasValue && newRecord.Start.Value.Second > 0)
{
continue;
}
bool isGroup = false;
var minuten = newRecord.RoundedDuration;
if (newRecord.GroupRoundedDuration.HasValue)
{
minuten = newRecord.GroupRoundedDuration.Value;
isGroup = true;
}
var newSpan = new DateTimeSpan
{
StartDateTime = newRecord.Start.Value,
EndDateTime = newRecord.Start.Value.AddMinutes((double)minuten)
};
foreach (var oldRecord in oldRecords)
{
var oldSpan = new DateTimeSpan
{
StartDateTime = oldRecord.Start.Value,
EndDateTime = oldRecord.Start.Value.AddMinutes((double)oldRecord.RoundedDuration)
};
if (oldRecord.GroupRoundedDuration.HasValue)
{
oldSpan.EndDateTime = oldRecord.Start.Value.AddMinutes((double)oldRecord.GroupRoundedDuration);
}
if (oldSpan.Overlaps(newSpan))
{
DateTime start = newSpan.StartDateTime;
if (oldSpan.StartDateTime > start)
start = oldSpan.StartDateTime;
DateTime end = newSpan.EndDateTime;
if (oldSpan.EndDateTime < end)
end = oldSpan.EndDateTime;
if (newSpan.StartDateTime >= oldSpan.StartDateTime)
{
newSpan.StartDateTime = oldSpan.EndDateTime;
if (newSpan.StartDateTime > newSpan.EndDateTime)
{
newSpan.StartDateTime = newSpan.EndDateTime;
}
newRecord.Start = newSpan.StartDateTime;
newRecord.End = newSpan.EndDateTime;
if (!isGroup)
{
newRecord.RoundedDuration =
(decimal)newRecord.End.Value.Subtract(newRecord.Start.Value).TotalMinutes;
}
else
{
newRecord.GroupRoundedDuration = (decimal)newRecord.End.Value.Subtract(newRecord.Start.Value).TotalMinutes;
}
}
else
{
oldSpan.StartDateTime = newSpan.EndDateTime;
if (oldSpan.StartDateTime > oldSpan.EndDateTime)
{
oldSpan.StartDateTime = oldSpan.EndDateTime;
}
oldRecord.Start = oldSpan.StartDateTime;
oldRecord.End = oldSpan.EndDateTime;
if (!isGroup)
{
oldRecord.RoundedDuration = (decimal)oldRecord.End.Value.Subtract(oldRecord.Start.Value).TotalMinutes;
}
else
{
oldRecord.GroupRoundedDuration = (decimal)oldRecord.End.Value.Subtract(oldRecord.Start.Value).TotalMinutes;
}
}
}
}
oldRecords.Add(newRecord);
}
}
public virtual bool CorrectOverlappingTime(ServiceRecord newRecord)
{
return true;
}
public virtual decimal? BerechneSollProMonat(Employee emp, DateTime start, DateTime ende)
{
return null;
}
public virtual decimal? BerechneFlsSollProMonat(Employee emp, DateTime start, DateTime ende)
{
return null;
}
public virtual void HandleServiceRecord(MitarbeiterstundenkontoRO.EmployeeDetail emp, ServiceRecord item)
{
//do nothing
}
public virtual bool ShouldCreateDayDetails()
{
return false;
}
public virtual IList<MitarbeiterstundenkontoRO.DayDetail> CreateDayDetails(DateTime berichtStart, DateTime berichtEnde, MitarbeiterstundenkontoRO.EmployeeDetail ed, IList<ServiceRecord> recordsAll)
{
Dictionary<int, MitarbeiterstundenkontoRO.DayDetail> dayToDetail = new Dictionary<int, MitarbeiterstundenkontoRO.DayDetail>();
for (int i = berichtStart.Day; i <= berichtEnde.AddDays(-1).Day; i++)
{
MitarbeiterstundenkontoRO.DayDetail dd = CreateDayDetail(new DateTime(berichtStart.Year, berichtStart.Month, i), ed);
dayToDetail.Add(i, dd);
}
foreach (var sr in recordsAll)
{
if (sr.Start.HasValue && sr.Start >= berichtStart && sr.Start < berichtEnde && sr.End.HasValue)
{
var dd = dayToDetail[sr.Start.Value.Day];
if (!IsServiceRecordFehlzeit(sr) && AddServiceRecordToDuration(sr))
{
decimal duration = 0;
if (sr.GroupRoundedDuration.HasValue)
{
duration = sr.GroupRoundedDuration.Value;
}
else
{
if (appSettings.ShowRoundedDurationInEmployeeAnalysis)
{
duration = sr.RoundedDuration;
}
else
{
duration = (decimal)sr.End.Value.Subtract(sr.Start.Value).TotalMinutes;
}
}
dd.MinutesTotal += duration;
if (dd.ServiceRecords == null)
dd.ServiceRecords = new List<ServiceRecord>();
dd.ServiceRecords.Add(sr);
CalculateSpecialHours(dd, sr, duration);
}
}
}
//Berechne von bis Zeiten
foreach (var ddKeyValue in dayToDetail)
{
var dd = ddKeyValue.Value;
if (dd.ServiceRecords != null)
{
var orderedList = dd.ServiceRecords.OrderBy(i => i.Start);
DateTime lastEnd = DateTime.MinValue;
var gapCount = -1;
foreach (var sr in orderedList)
{
decimal duration = 0;
if (sr.GroupRoundedDuration.HasValue)
{
duration = sr.GroupRoundedDuration.Value;
}
else
{
if (appSettings.ShowRoundedDurationInEmployeeAnalysis)
{
duration = sr.RoundedDuration;
}
else
{
duration = (decimal)sr.End.Value.Subtract(sr.Start.Value).TotalMinutes;
}
}
DateTime dtEnd = sr.Start.Value.AddMinutes((double)duration);
if (sr.Start > lastEnd)
{
gapCount++;
}
if (dtEnd > lastEnd)
{
lastEnd = dtEnd;
}
if (gapCount == 0)
{
if (!dd.StartDateTime1.HasValue || sr.Start < dd.StartDateTime1)
{
dd.StartDateTime1 = sr.Start;
}
if (!dd.EndDateTime1.HasValue || dtEnd > dd.EndDateTime1)
{
dd.EndDateTime1 = dtEnd;
}
}
else if (gapCount == 1)
{
if (!dd.StartDateTime2.HasValue || sr.Start < dd.StartDateTime2)
{
dd.StartDateTime2 = sr.Start;
}
if (!dd.EndDateTime2.HasValue || dtEnd > dd.EndDateTime2)
{
dd.EndDateTime2 = dtEnd;
}
}
else if (gapCount == 2)
{
if (!dd.StartDateTime3.HasValue || sr.Start < dd.StartDateTime3)
{
dd.StartDateTime3 = sr.Start;
}
if (!dd.EndDateTime3.HasValue || dtEnd > dd.EndDateTime3)
{
dd.EndDateTime3 = dtEnd;
}
}
else
{
if (!dd.StartDateTime4.HasValue || sr.Start < dd.StartDateTime4)
{
dd.StartDateTime4 = sr.Start;
}
if (!dd.EndDateTime4.HasValue || dtEnd > dd.EndDateTime4)
{
dd.EndDateTime4 = dtEnd;
}
}
}
}
}
return dayToDetail.Values.OrderBy(dd => dd.Date).ToList();
}
public virtual void CalculateSpecialHours(MitarbeiterstundenkontoRO.DayDetail dd, ServiceRecord sr, decimal duration)
{
if (sr.Start.Value.DayOfWeek == DayOfWeek.Sunday)
{
dd.HoursSunday += duration / 60;
}
else if (IstFeiertag(sr.Start.Value))
{
dd.HoursHoliday += duration / 60;
}
else if (dd.NightEnd.HasValue && dd.NightStart.HasValue)
{
DateTime dtEnd = sr.Start.Value.AddMinutes((double)duration);
if (dtEnd.Hour >= dd.NightStart.Value)
{
DateTime dtStart = dtEnd.Date.AddHours(dd.NightStart.Value);
if (sr.Start.Value > dtStart)
dtStart = sr.Start.Value;
TimeSpan ts = dtEnd.Subtract(dtStart);
dd.SpecialHours += (decimal)ts.TotalMinutes / 60;
}
if (sr.Start.Value.Hour < dd.NightEnd)
{
DateTime dtEnd2 = sr.Start.Value.Date.AddHours(dd.NightEnd.Value);
if (dtEnd < dtEnd2)
dtEnd2 = dtEnd;
TimeSpan ts = dtEnd2.Subtract(sr.Start.Value);
dd.SpecialHours += (decimal)(Math.Round(ts.TotalMinutes, 0) / 60);
}
}
}
public virtual MitarbeiterstundenkontoRO.DayDetail CreateDayDetail(DateTime date, MitarbeiterstundenkontoRO.EmployeeDetail ed)
{
MitarbeiterstundenkontoRO.DayDetail dd = new MitarbeiterstundenkontoRO.DayDetail();
dd.Date = date.Date;
dd.NightStart = 20;
dd.NightEnd = 6;
dd.MaxHoursUntilBreak = 6;
dd.BreakMinutes = 30;
CalculateAbsenceTimesForDay(dd, ed);
return dd;
}
public virtual void CalculateAbsenceTimesForDay(MitarbeiterstundenkontoRO.DayDetail dd, MitarbeiterstundenkontoRO.EmployeeDetail ed)
{
var absenceTimes = ed.Employee.AbsenceTimes;
if (absenceTimes != null)
{
foreach (var absenceTime in absenceTimes)
{
if (IsUrlaubAbsenceTime(absenceTime) || IsKrankheitAbsenceTime(absenceTime))
{
DateTimeSpan span = new DateTimeSpan();
span.StartDate = dd.Date;
if (absenceTime.Start.HasValue && absenceTime.Start.Value > span.StartDate)
{
span.StartDate = absenceTime.Start.Value;
}
span.EndDate = dd.Date.AddDays(1);
if (absenceTime.End.HasValue && absenceTime.End.Value.Date.AddDays(1) < span.EndDate)
{
span.EndDate = absenceTime.End.Value.Date.AddDays(1);
}
if (span.EndDate > dd.Date && span.StartDate < dd.Date.AddDays(1))
{
DateTime day = span.StartDate;
var faktor = GetFeiertagsFaktor(day);
if (faktor < 1 && day.DayOfWeek != DayOfWeek.Saturday && day.DayOfWeek != DayOfWeek.Sunday)
{
var soll = ed.SollProTag;
if (faktor != 0)
{
soll *= faktor; //halbe Feiertage etc. berücksichtigen
}
if (IsKrankheitAbsenceTime(absenceTime))
{
dd.HoursSick = soll;
}
else if (IsUrlaubAbsenceTime(absenceTime))
{
dd.HoursInVacation = soll;
}
dd.MinutesTotal += soll * 60;
}
}
}
//}
}
}
}
public virtual bool IsKrankheitAbsenceTime(AbsenceTime absenceTime)
{
return !String.IsNullOrEmpty(absenceTime.AbsenceReason.Description) &&
(absenceTime.AbsenceReason.Description.ToLower().IndexOf("arbeitsunfähig") >= 0
|| absenceTime.AbsenceReason.Description.ToLower().IndexOf("krank") >= 0);
}
public virtual bool IsUrlaubAbsenceTime(AbsenceTime absenceTime)
{
return !String.IsNullOrEmpty(absenceTime.AbsenceReason.Description) &&
absenceTime.AbsenceReason.Description.ToLower().IndexOf("urlaub") >= 0;
}
public virtual bool AddServiceRecordToDuration(ServiceRecord item)
{
return true;
}
public virtual decimal AddRateFactorToIst()
{
return 1;
}
private void BerechneUeberstundenBis(Employee emp, IList<ServiceRecord> records, DateTime monat, out decimal? ueberstunden, out decimal alteExtraUeberstunden)
{
ueberstunden = null;
alteExtraUeberstunden = 0;
Contract c = emp.FirstContract;
if (c != null)
{
Dictionary<String, IList<ServiceRecord>> srDict = CreateServiceRecordDictByDate(records);
DateTime start = c.EntryDate.HasValue ? c.EntryDate.Value : new DateTime(2011, 1, 1);
while (c != null && start < monat)
{
DateTime contractEnd = c.ContractEndDate.HasValue ? c.ContractEndDate.Value : DateTime.MaxValue;
decimal bu = 0;
decimal weeklyTotalHours = this.maxWochenstunden;
int anzWochentage = ANZ_WOCHENTAGE;
//if (c.WeeklyDays.HasValue && c.WeeklyDays.Value > 0)
//{
// anzWochentage = c.WeeklyDays.Value;
//}
if (c.WeeklyTotalHours.HasValue)
{
weeklyTotalHours = c.WeeklyTotalHours.Value;
bu = c.WeeklyTotalHours.Value / maxWochenstunden;
}
while (start < monat && start < contractEnd)
{
decimal flsIst = 0;
decimal mittelbarIst = 0;
decimal minutenMonat = 0;
DateTime ende = new DateTime(start.Year, start.Month, 1).AddMonths(1);
if (contractEnd < DateTime.MaxValue && contractEnd.AddDays(1) < ende)
ende = contractEnd.AddDays(1);
IList<ServiceRecord> recordsThisMonth = new List<ServiceRecord>();
String key = String.Format("{0:yyyyMM}", start);
if (srDict.ContainsKey(key))
{
foreach (var item in srDict[key])
{
if (item.Start.HasValue && item.Start >= start && item.Start < ende)
{
if (AddServiceRecordToDuration(item))
{
decimal duration = 0;
if (item.GroupRoundedDuration.HasValue)
{
duration = item.GroupRoundedDuration.Value;
}
else
{
if (appSettings.ShowRoundedDurationInEmployeeAnalysis)
{
duration = item.RoundedDuration;
}
else
{
duration = (decimal)item.End.Value.Subtract(item.Start.Value).TotalMinutes;
}
}
minutenMonat += duration;
if (AddRateFactorToIst() != 1)
{
if (item.ServiceDescription != null &&
item.ServiceDescription.ServiceCategory != null &&
item.ServiceDescription.ServiceCategory.IsBillable)
flsIst += duration;
else
mittelbarIst += duration;
}
}
recordsThisMonth.Add(item);
}
}
}
decimal arbeitstage = GetArbeitstageImBereich(start, ende, emp);
//if (anzWochentage != 5)
//{
// arbeitstage *= anzWochentage / 5m;
//}
var stundenSollProMonat = BerechneSollProMonat(emp, start, ende);
var soll = stundenSollProMonat;
if (!soll.HasValue)
{
decimal maxSollMonat = arbeitstage * (maxWochenstunden / anzWochentage);
soll = maxSollMonat*bu;
}
decimal sollMitarbeiter = soll ?? 0;
var ath = GetAbsenceTimeDays(emp.AbsenceTimes, start, ende);
decimal? fehlzeit = GetFehlzeiten(records, start, ende);
if (fehlzeit.HasValue)
{
sollMitarbeiter -= fehlzeit.Value;
}
var arbeitstageProWoche = anzWochentage;
if (ath.TageGesamt.HasValue)
{
if (c != null && c.WeeklyDays.HasValue && c.WeeklyDays.Value > 0)
{
arbeitstageProWoche = c.WeeklyDays.Value;
}
if (stundenSollProMonat.HasValue)
{
decimal stundenProTag = stundenSollProMonat.Value / arbeitstage;
sollMitarbeiter -= (ath.TageGesamt.Value * stundenProTag);
}
else
{
sollMitarbeiter -= (ath.TageGesamt.Value * (maxWochenstunden / arbeitstageProWoche) * bu);
}
}
decimal stundenMonat = minutenMonat/60m;
if (AddRateFactorToIst() != 1)
{
stundenMonat = ((flsIst*AddRateFactorToIst()) + mittelbarIst)/60m;
}
if (!ueberstunden.HasValue)
ueberstunden = 0;
ueberstunden += stundenMonat - sollMitarbeiter;
if (SollPauseBerechnen())
{
var pause1 = BerechnePauseMinuten(recordsThisMonth);
var pause2 = BerechneAutoPausen(recordsThisMonth);
ueberstunden -= pause1/60;
ueberstunden -= pause2/60;
}
decimal extraUeberstunden = 0;
BerechneExtraUeberstunden(emp, start, ende, out extraUeberstunden);
ueberstunden += extraUeberstunden;
alteExtraUeberstunden += extraUeberstunden;
if (ShouldCreateDayDetails())
{
MitarbeiterstundenkontoRO.EmployeeDetail ed = new MitarbeiterstundenkontoRO.EmployeeDetail();
ed.SollProTag = weeklyTotalHours/ anzWochentage;
ed.ArbeitstageProWoche = arbeitstageProWoche;
ed.Employee = emp;
var days = CreateDayDetails(start, ende, ed, records);
var ah = GetAdditionalHours(days, start, ende, ed, records);
ueberstunden += ah;
}
start = ende;
}
if (start >= contractEnd)
{
var ctemp = GetNextValidContractForDate(start, emp);
if (ctemp != null && ctemp.Oid != c.Oid)
{
c = ctemp;
}
else
{
c = null;
}
if (c != null && c.EntryDate.HasValue && c.EntryDate >= start)
start = c.EntryDate.Value;
else
{
start = start.AddMonths(1);
c = GetNextValidContractForDate(start, emp);
if (c != null && c.EntryDate.HasValue && c.EntryDate >= start)
start = c.EntryDate.Value;
}
}
}
}
}
public virtual Dictionary<string, IList<ServiceRecord>> CreateServiceRecordDictByDate(IList<ServiceRecord> records)
{
var dict = new Dictionary<string, IList<ServiceRecord>>();
foreach (var item in records)
{
if (!IsServiceRecordFehlzeit(item))
{
if (item.Start.HasValue)
{
String key = String.Format("{0:yyyyMM}", item.Start.Value);
IList<ServiceRecord> list;
if (!dict.ContainsKey(key))
{
list = new List<ServiceRecord>();
dict.Add(key, list);
}
else
{
list = dict[key];
}
list.Add(item);
}
}
}
return dict;
}
public virtual decimal GetAdditionalHours(IList<MitarbeiterstundenkontoRO.DayDetail> days, DateTime berichtStart, DateTime berichtEnde, MitarbeiterstundenkontoRO.EmployeeDetail ed, IList<ServiceRecord> recordsAll)
{
decimal addHours = 0;
foreach (var dayDetail in days)
{
if (dayDetail.BreakMinutes.HasValue && dayDetail.MaxHoursUntilBreak.HasValue)
{
if (dayDetail.EndDateTime1.HasValue && dayDetail.StartDateTime1.HasValue)
{
if (dayDetail.EndDateTime1.Value.Subtract(dayDetail.StartDateTime1.Value).TotalHours >
dayDetail.MaxHoursUntilBreak.Value)
{
addHours -= (dayDetail.BreakMinutes.Value/60m);
dayDetail.MinutesTotal -= dayDetail.BreakMinutes.Value;
}
}
if (dayDetail.EndDateTime2.HasValue && dayDetail.StartDateTime2.HasValue)
{
if (dayDetail.EndDateTime2.Value.Subtract(dayDetail.StartDateTime2.Value).TotalHours >
dayDetail.MaxHoursUntilBreak.Value)
{
addHours -= (dayDetail.BreakMinutes.Value/60m);
dayDetail.MinutesTotal -= dayDetail.BreakMinutes.Value;
}
}
if (dayDetail.EndDateTime3.HasValue && dayDetail.StartDateTime3.HasValue)
{
if (dayDetail.EndDateTime3.Value.Subtract(dayDetail.StartDateTime3.Value).TotalHours >
dayDetail.MaxHoursUntilBreak.Value)
{
addHours -= (dayDetail.BreakMinutes.Value/60m);
dayDetail.MinutesTotal -= dayDetail.BreakMinutes.Value;
}
}
if (dayDetail.EndDateTime4.HasValue && dayDetail.StartDateTime4.HasValue)
{
if (dayDetail.EndDateTime4.Value.Subtract(dayDetail.StartDateTime4.Value).TotalHours >
dayDetail.MaxHoursUntilBreak.Value)
{
addHours -= (dayDetail.BreakMinutes.Value / 60m);
dayDetail.MinutesTotal -= dayDetail.BreakMinutes.Value;
}
}
}
}
return addHours;
}
public virtual void BerechneExtraUeberstunden(Employee emp, DateTime start, DateTime ende, out decimal stunden)
{
stunden = 0;
if (emp.Overtimes != null)
{
foreach (var ot in emp.Overtimes)
{
if (ot.Date >= start && ot.Date < ende)
{
stunden += ot.Betrag;
}
}
}
}
public Contract GetNextValidContractForDate(DateTime dt, Employee emp)
{
Contract contractNextToStartDate = emp.GetValidContractForDate(dt);
if (contractNextToStartDate == null)
{
foreach (var item in emp.Contracts)
{
if (item.EntryDate.HasValue && item.EntryDate.Value >= dt)
{
if (contractNextToStartDate == null || item.EntryDate.Value < contractNextToStartDate.EntryDate.Value)
{
contractNextToStartDate = item;
}
}
}
}
return contractNextToStartDate;
}
public virtual AbsenceTimeDays GetAbsenceTimeDays(IList<AbsenceTime> absenceTimes, DateTime start, DateTime end)
{
var atd = new AbsenceTimeDays();
decimal? tage = null;
if (absenceTimes != null)
{
foreach (var item in absenceTimes)
{
DateTimeSpan span = new DateTimeSpan();
span.StartDate = start;
if (item.Start.HasValue && item.Start.Value > span.StartDate)
{
span.StartDate = item.Start.Value;
}
span.EndDate = end;
if (item.End.HasValue && item.End.Value.Date.AddDays(1) < span.EndDate)
{
span.EndDate = item.End.Value.Date.AddDays(1);
}
if (span.EndDate >= start && span.StartDate < end)
{
DateTime day = span.StartDate;
while (day < end && day < span.EndDate)
{
var faktor = GetFeiertagsFaktor(day);
if (faktor < 1 && day.DayOfWeek != DayOfWeek.Saturday && day.DayOfWeek != DayOfWeek.Sunday)
{
if (!tage.HasValue)
tage = 0;
var tag = 1m;
var std = 24m;
if (faktor != 0)
{
tag *= faktor;
std *= faktor;
}
tage += std;
if (IsKrankheitAbsenceTime(item))
{
if (!atd.TageKrankheit.HasValue)
atd.TageKrankheit = 0;
atd.TageKrankheit += tag;
}
if (IsUrlaubAbsenceTime(item))
{
if (!atd.TageUrlaub.HasValue)
atd.TageUrlaub = 0;
atd.TageUrlaub += tag;
}
}
day = day.AddDays(1);
}
}
//}
}
}
if (tage.HasValue)
tage /= 24;
atd.TageGesamt = tage;
return atd;
}
public virtual decimal? GetFehlzeiten(IList<ServiceRecord> records, DateTime monat)
{
return GetFehlzeiten(records, monat, monat.AddMonths(1));
}
public virtual decimal? GetFehlzeiten(IList<ServiceRecord> records, DateTime start, DateTime ende)
{
decimal? stunden = null;
decimal minuten = 0;
if (records != null)
{
foreach (var item in records)
{
if (IsServiceRecordFehlzeit(item))
{
if (item.Start.Value >= start && item.Start.Value < ende)
{
if (item.GroupRoundedDuration.HasValue)
{
minuten += item.GroupRoundedDuration.Value;
}
else
{
if (appSettings.ShowRoundedDurationInEmployeeAnalysis)
{
minuten += item.RoundedDuration;
}
else
{
minuten += (decimal)item.End.Value.Subtract(item.Start.Value).TotalMinutes;
}
}
}
}
}
}
if (minuten != 0)
stunden = minuten / 60;
return stunden;
}
public virtual decimal GetArbeitstageImMonat(DateTime datum, Employee emp)
{
Contract c = GetNextValidContractForDate(datum, emp);
if (c == null)
return 0;
DateTime start = new DateTime(datum.Year, datum.Month, 1);
DateTime end = start.AddMonths(1);
if (c.EntryDate.HasValue)
{
if (c.EntryDate >= end)
return 0;
if (c.EntryDate > start)
start = c.EntryDate.Value;
}
if (c.ContractEndDate.HasValue && c.ContractEndDate.Value.AddDays(1) < end)
end = c.ContractEndDate.Value.AddDays(1);
return GetArbeitstageImBereich(start, end, emp);
}
public virtual decimal GetArbeitstageImBereich(DateTime von, DateTime bis, Employee emp)
{
DateTime dt = DateTime.Now;
DateTime start = von;
DateTime end = bis;
TimeSpan ts = end.Subtract(start);
var maxDays = (decimal)ts.TotalDays;
while (start < end)
{
if (start.DayOfWeek == DayOfWeek.Saturday || start.DayOfWeek == DayOfWeek.Sunday)
{
maxDays -= 1;
}
else
{
maxDays -= GetFeiertagsFaktor(start);
//if (IstFeiertag(start))
// maxDays--;
}
start = start.AddDays(1);
}
return maxDays;
}
//gibt 1 zurück wenn ganzer Feiertag und z.B. 0.5 bei halben etc.
public virtual decimal GetFeiertagsFaktor(DateTime start)
{
if (IstFeiertag(start))
{
return 1;
}
return 0;
}
public virtual bool IstFeiertag(DateTime start)
{
List<DateTime> feiertage = GetFeiertage(start.Year);
foreach (var ft in feiertage)
{
if (start.Date == ft)
return true;
}
return false;
}
public virtual List<DateTime> GetFeiertage(int year)
{
List<DateTime> list = new List<DateTime>();
list.Add(new DateTime(year, 1, 1)); // "Neujahr"));
//list.Add(new DateTime(year, 1, 6)); // , "Heilige Drei Könige"));
list.Add(new DateTime(year, 5, 1)); // , "Tag der Arbeit"));
//list.Add(new DateTime(year, 8, 15)); // , "Mariä Himmelfahrt"));
list.Add(new DateTime(year, 10, 3)); // , "Tag der dt. Einheit"));
//list.Add(new DateTime(year, 10, 31)); // , "Reformationstag"));
list.Add(new DateTime(year, 11, 1)); // , "Allerheiligen "));
list.Add(new DateTime(year, 12, 24)); // , "Heilig Abend"));
list.Add(new DateTime(year, 12, 25)); // , "1. Weihnachtstag"));
list.Add(new DateTime(year, 12, 26)); // , "2. Weihnachtstag"));
if (year == 2017)
{
list.Add(new DateTime(year, 10, 31)); // , "Reformationstag"));
}
DateTime osterSonntag = GetOsterSonntag(year);
//list.Add(osterSonntag); // , "Ostersonntag"));
//list.Add(osterSonntag.AddDays(-3)); // , "Gründonnerstag")); q
//list.Add(osterSonntag.AddDays(-48)); // , "Rosenmontag"));
list.Add(osterSonntag.AddDays(-2)); // , "Karfreitag"));
list.Add(osterSonntag.AddDays(1)); // , "Ostermontag"));
list.Add(osterSonntag.AddDays(39)); // , "Christi Himmelfahrt"));
//list.Add(osterSonntag.AddDays(49)); // , "Pfingstsonntag"));
list.Add(osterSonntag.AddDays(50)); // , "Pfingstmontag"));
list.Add(osterSonntag.AddDays(60)); // , "Fronleichnam"));
//01.01. Neujahr
//01.05. Tag der Arbeit
//03.10. Tag der Deutschen Einheit
//01.11. Allerheiligen
//25.12. 1. Weihnachtstag
//26.12. 2. Weihnachtstag
//Karfreitag
//Ostermontag
//Christi Himmelfahrt (39 Tage nach Ostersonntag)
//Pfingstmontag (50 Tage nach Ostersonntag)
//Fronleichnam (60 Tage nach Ostersonntag)
//24.12. Heilig Abend
return list;
}
protected DateTime GetOsterSonntag(int year)
{
int g, h, c, j, l, i;
g = year % 19;
c = year / 100;
h = ((c - (c / 4)) - (((8 * c) + 13) / 25) + (19 * g) + 15) % 30;
i = h - (h / 28) * (1 - (29 / (h + 1)) * ((21 - g) / 11));
j = (year + (year / 4) + i + 2 - c + (c / 4)) % 7;
l = i - j;
int month = (int)(3 + ((l + 40) / 44));
int day = (int)(l + 28 - 31 * (month / 4));
return new DateTime(year, month, day);
}
public virtual bool IsServiceRecordFehlzeit(ServiceRecord sr)
{
if (sr.ServiceDescription != null && sr.ServiceDescription.ServiceCategory != null && !String.IsNullOrEmpty(sr.ServiceDescription.ServiceCategory.Name) && sr.ServiceDescription.ServiceCategory.Name.ToLower().IndexOf("fehlzeit") >= 0)
return true;
return false;
}
}
public class AbsenceTimeDays
{
public decimal? TageUrlaub;
public decimal? TageKrankheit;
public decimal? TageGesamt;
}
}