2646 lines
91 KiB
C#
2646 lines
91 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();
|
|
CheckIst = true;
|
|
}
|
|
|
|
public MitarbeiterstundenkontoBerechnung(decimal maxWochenstunden) : this()
|
|
{
|
|
this.maxWochenstunden = maxWochenstunden;
|
|
}
|
|
|
|
public bool CheckIst { get; set; }
|
|
|
|
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;
|
|
|
|
var c = GetContractForDate(emp, ro.ReportStartDate, ro.ReportEndDate);
|
|
|
|
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;
|
|
}
|
|
|
|
ServiceRecordSummary summaryTotal = new ServiceRecordSummary();
|
|
summaryTotal.RecordsImBerichtszeitraum = new List<ServiceRecord>();
|
|
|
|
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 tatSollStdGesamt = 0;
|
|
|
|
IList<ServiceRecord> recordsAll = DAOFactory.SearchDAO.FindServiceRecords(emp.Oid, null);
|
|
recordsAll = AnalysisServiceImp.FilterActiveServiceRecords(recordsAll);
|
|
|
|
//
|
|
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)
|
|
{
|
|
empDetail.ArbeitstageImBerichtszeitraum = GetArbeitstageImBereich(berichtsAnfang, berichtsEnde, emp);
|
|
empDetail.ArbeitstageProWoche = ANZ_WOCHENTAGE;
|
|
|
|
|
|
workdaysTotal += empDetail.ArbeitstageImBerichtszeitraum;
|
|
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)
|
|
{
|
|
empDetail.ArbeitstageProWoche = c.WeeklyDays.Value;
|
|
}
|
|
|
|
empDetail.WeeklyFLS = c.WeeklyFLS;
|
|
empDetail.HourlyRate = c.HourlyRate;
|
|
empDetail.EmploymentType = c.EmploymentType;
|
|
|
|
}
|
|
empDetail.SollProTag = (weeklyTotalHours / empDetail.ArbeitstageProWoche);
|
|
|
|
empDetail.SollProWoche = BerechneSollProWoche(c, empDetail);
|
|
|
|
HandleServiceRecords(empDetail, groupFilteredRecords, c);
|
|
|
|
if (CheckIst)
|
|
{
|
|
|
|
var summary = BerechneStunden(empDetail, groupFilteredRecords, berichtsAnfang, berichtsEnde);
|
|
summaryTotal.IstAbrechenbar += summary.IstAbrechenbar;
|
|
summaryTotal.IstNichtAbrechenbar += summary.IstNichtAbrechenbar;
|
|
summaryTotal.RecordsImBerichtszeitraum.AddRange(summary.RecordsImBerichtszeitraum);
|
|
|
|
if (SollPauseBerechnen())
|
|
{
|
|
pause1 += BerechnePauseMinuten(summary.RecordsImBerichtszeitraum);
|
|
pause2 += BerechneAutoPausen(summary.RecordsImBerichtszeitraum);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
decimal? stundenSollProMonat = null;
|
|
|
|
var stundenSollImVertragsUndBerichtzeitraum = GetSollNachArbeitszeiten(empDetail.Employee, berichtsAnfang, berichtsEnde);
|
|
|
|
if (!stundenSollImVertragsUndBerichtzeitraum.HasValue)
|
|
{
|
|
stundenSollProMonat = BerechneSollProMonat(emp, berichtsAnfang, berichtsEnde);
|
|
stundenSollImVertragsUndBerichtzeitraum = stundenSollProMonat;
|
|
}
|
|
|
|
if (!stundenSollImVertragsUndBerichtzeitraum.HasValue)
|
|
{
|
|
if (!stundenSollImVertragsUndBerichtzeitraum.HasValue)
|
|
{
|
|
if (empDetail.ArbeitstageProWoche <= 5)
|
|
{
|
|
stundenSollImVertragsUndBerichtzeitraum =
|
|
empDetail.ArbeitstageImBerichtszeitraum * (weeklyTotalHours / 5);
|
|
}
|
|
else
|
|
{
|
|
stundenSollImVertragsUndBerichtzeitraum =
|
|
empDetail.ArbeitstageImBerichtszeitraum * (weeklyTotalHours / empDetail.ArbeitstageProWoche);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
stundenSollGesamt += stundenSollImVertragsUndBerichtzeitraum ?? 0;
|
|
|
|
|
|
empDetail.StundenSollMax = stundenSollGesamt;
|
|
|
|
|
|
var tatSollStdImVertragsUndBerichtzeitraum = stundenSollImVertragsUndBerichtzeitraum ?? 0;
|
|
|
|
|
|
decimal? fehlZeiten = GetFehlzeiten(groupFilteredRecords, berichtsAnfang, berichtsEnde);
|
|
if (fehlZeiten.HasValue)
|
|
{
|
|
if (!fehlZeitenGesamt.HasValue)
|
|
fehlZeitenGesamt = 0;
|
|
fehlZeitenGesamt += fehlZeiten;
|
|
|
|
tatSollStdImVertragsUndBerichtzeitraum -= fehlZeiten.Value;
|
|
}
|
|
|
|
var ath = GetAbsenceTimeDaysWithWorkWeeks(emp, berichtsAnfang, berichtsEnde, empDetail.ArbeitstageProWoche);
|
|
empDetail.AbsenceTimeDays = ath;
|
|
|
|
if (ath.TageUrlaub.HasValue)
|
|
{
|
|
if (!tageUrlaubGesamt.HasValue)
|
|
tageUrlaubGesamt = 0;
|
|
tageUrlaubGesamt += ath.TageUrlaub;
|
|
}
|
|
if (ath.TageKrankheit.HasValue)
|
|
{
|
|
if (!tageKrankheitGesamt.HasValue)
|
|
tageKrankheitGesamt = 0;
|
|
tageKrankheitGesamt += ath.TageKrankheit;
|
|
}
|
|
|
|
|
|
if (ath.TageGesamt.HasValue)
|
|
{
|
|
if (!abwesenheitTageGesamt.HasValue)
|
|
abwesenheitTageGesamt = 0;
|
|
abwesenheitTageGesamt += ath.TageGesamt;
|
|
|
|
var minusStunden = BerechneStundenDurchAbwesenheiten(ath, berichtsAnfang, berichtsEnde, c, empDetail);
|
|
tatSollStdImVertragsUndBerichtzeitraum -= minusStunden;
|
|
if (tatSollStdImVertragsUndBerichtzeitraum < 0 && !StundenDurchAbwesenheitenDuerfenNegativSein())
|
|
{
|
|
|
|
tatSollStdImVertragsUndBerichtzeitraum = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var ath2 = GetAbwesenheitenDurchServiceRecords(empDetail, c, groupFilteredRecords, berichtsAnfang, berichtsEnde);
|
|
|
|
if (ath2 != null)
|
|
{
|
|
|
|
var stunden = ath2.StundenKrankheit + ath2.StundenUrlaub;
|
|
|
|
tatSollStdImVertragsUndBerichtzeitraum -= stunden;
|
|
|
|
if (tatSollStdImVertragsUndBerichtzeitraum < 0 && !StundenDurchAbwesenheitenDuerfenNegativSein())
|
|
{
|
|
tatSollStdImVertragsUndBerichtzeitraum = 0;
|
|
}
|
|
|
|
if (empDetail.SollProTag > 0)
|
|
{
|
|
if (!abwesenheitTageGesamt.HasValue)
|
|
abwesenheitTageGesamt = 0;
|
|
abwesenheitTageGesamt += stunden / empDetail.SollProTag;
|
|
|
|
if (ath2.StundenKrankheit > 0)
|
|
{
|
|
if (!tageKrankheitGesamt.HasValue)
|
|
{
|
|
tageKrankheitGesamt = 0;
|
|
}
|
|
tageKrankheitGesamt += ath2.StundenKrankheit / empDetail.SollProTag;
|
|
}
|
|
|
|
if (ath2.StundenUrlaub > 0)
|
|
{
|
|
if (!tageUrlaubGesamt.HasValue)
|
|
{
|
|
tageUrlaubGesamt = 0;
|
|
}
|
|
tageUrlaubGesamt += ath2.StundenUrlaub / empDetail.SollProTag;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
tatSollStdGesamt += tatSollStdImVertragsUndBerichtzeitraum;
|
|
|
|
|
|
flsSollGesamt += BerechneFlsSoll(emp, c, berichtsAnfang, berichtsEnde, tatSollStdImVertragsUndBerichtzeitraum, stundenSollProMonat);
|
|
|
|
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)
|
|
{
|
|
summaryTotal.IstAbrechenbar *= AddRateFactorToIst();
|
|
}
|
|
summaryTotal.IstAbrechenbar /= 60m;
|
|
summaryTotal.IstNichtAbrechenbar /= 60m;
|
|
|
|
empDetail.WorkDaysThisMonth = workdaysTotal;
|
|
//decimal stundenSollMax = arbeitstage * (maxWochenstunden / xxx) * bu;
|
|
|
|
|
|
|
|
empDetail.Fehlzeiten = fehlZeitenGesamt;
|
|
empDetail.TageUrlaub = tageUrlaubGesamt;
|
|
empDetail.TageKrankheit = tageKrankheitGesamt;
|
|
empDetail.UrlaubUndKrankheit = abwesenheitTageGesamt;
|
|
|
|
empDetail.StundenSollOhneUrlaubKrankheit = tatSollStdGesamt;
|
|
|
|
empDetail.FlsSoll = flsSollGesamt;
|
|
|
|
|
|
|
|
empDetail.MittelbarIst = summaryTotal.IstNichtAbrechenbar;
|
|
empDetail.Bu = bu;
|
|
empDetail.FlsIst = summaryTotal.IstAbrechenbar;
|
|
empDetail.FlsDiff = summaryTotal.IstAbrechenbar - empDetail.FlsSoll;
|
|
empDetail.StundenMittelbarIst = summaryTotal.IstNichtAbrechenbar;
|
|
empDetail.StundenGesamtIst = summaryTotal.IstAbrechenbar + summaryTotal.IstNichtAbrechenbar;
|
|
|
|
empDetail.StundenGesamtIst -= pause1/60;
|
|
empDetail.StundenGesamtIst -= pause2/60;
|
|
|
|
if (empDetail.FlsSoll != 0)
|
|
empDetail.RelationIstSoll = (empDetail.FlsIst/empDetail.FlsSoll)*100m;
|
|
|
|
|
|
if (summaryTotal.IstAbrechenbar + summaryTotal.IstNichtAbrechenbar != 0)
|
|
empDetail.RelationFlsZuMittelbar = (summaryTotal.IstAbrechenbar / (summaryTotal.IstAbrechenbar + summaryTotal.IstNichtAbrechenbar))*100;
|
|
|
|
|
|
decimal? ueberstunden = empDetail.StundenGesamtIst - empDetail.StundenSollOhneUrlaubKrankheit;
|
|
decimal? ueberstundenVormonat;
|
|
|
|
|
|
decimal alteExtraUeberstunden = 0;
|
|
BerechneUeberstundenBis(empDetail, groupFilteredRecords, ro.ReportStartDate, out ueberstundenVormonat,
|
|
out alteExtraUeberstunden);
|
|
|
|
|
|
decimal extraStunden = 0;
|
|
|
|
BerechneExtraUeberstunden(emp, monatsAnfang, monatsEnde, out extraStunden);
|
|
|
|
if (ShouldCreateDayDetails())
|
|
{
|
|
|
|
empDetail.Days = CreateDayDetails(monatsAnfang, monatsEnde, empDetail, summaryTotal.RecordsImBerichtszeitraum);
|
|
var ah = GetAdditionalHours(empDetail.Days, monatsAnfang, monatsEnde, empDetail, summaryTotal.RecordsImBerichtszeitraum);
|
|
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 =
|
|
GetAbsenceTimeDaysWithWorkWeeks(emp, new DateTime(monatsAnfang.Year, 1, 1), monatsEnde, empDetail.ArbeitstageProWoche).TageUrlaub;
|
|
|
|
CalculateEmployeeSalary(empDetail, berichtsAnfang, berichtsEnde);
|
|
}
|
|
|
|
ro.EmployeeDetailList = FilterEmployeeList(ro.EmployeeDetailList);
|
|
}
|
|
|
|
|
|
protected virtual AbsenceTimeHours GetAbwesenheitenDurchServiceRecords(MitarbeiterstundenkontoRO.EmployeeDetail empDetail, Contract c, IList<ServiceRecord> groupFilteredRecords, DateTime berichtsAnfang, DateTime berichtsEnde)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected virtual decimal BerechneFlsSoll(Employee emp, Contract contract, DateTime berichtsAnfang, DateTime berichtsEnde, decimal tatSollStdImVertragsUndBerichtzeitraum, decimal? stundenSollProMonat)
|
|
{
|
|
var festeflsSollProMonat = BerechneFlsSollProMonat(emp, berichtsAnfang, berichtsEnde);
|
|
decimal flsSollImVertragsUndBerichtzeitraum = 0;
|
|
|
|
if (festeflsSollProMonat.HasValue)
|
|
{
|
|
flsSollImVertragsUndBerichtzeitraum = tatSollStdImVertragsUndBerichtzeitraum;
|
|
|
|
if (stundenSollProMonat.HasValue)
|
|
{
|
|
flsSollImVertragsUndBerichtzeitraum *= (festeflsSollProMonat.Value / stundenSollProMonat.Value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (contract != null && contract.WeeklyFLS.HasValue)
|
|
{
|
|
flsSollImVertragsUndBerichtzeitraum = tatSollStdImVertragsUndBerichtzeitraum;
|
|
|
|
if (HatArbeitszeitImZeitraum(emp.Arbeitszeiten, berichtsAnfang, berichtsEnde))
|
|
{
|
|
var wochenArbeitszeit = GetWochenArbeitszeit(emp.Arbeitszeiten, berichtsAnfang, berichtsEnde);
|
|
|
|
if (wochenArbeitszeit > 0)
|
|
{
|
|
flsSollImVertragsUndBerichtzeitraum *= contract.WeeklyFLS.Value / wochenArbeitszeit;
|
|
}
|
|
|
|
}
|
|
else if (contract.WeeklyTotalHours.HasValue && contract.WeeklyTotalHours.Value != 0)
|
|
{
|
|
flsSollImVertragsUndBerichtzeitraum *= contract.WeeklyFLS.Value / contract.WeeklyTotalHours.Value;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return flsSollImVertragsUndBerichtzeitraum;
|
|
}
|
|
|
|
private decimal GetWochenArbeitszeit(IList<Arbeitszeit> arbeitszeiten, DateTime start, DateTime ende)
|
|
{
|
|
if (arbeitszeiten != null)
|
|
{
|
|
foreach (var az in arbeitszeiten)
|
|
{
|
|
if ((!az.GueltigVon.HasValue || az.GueltigVon.Value < ende) &&
|
|
(!az.GueltigBis.HasValue || az.GueltigBis.Value >= start))
|
|
{
|
|
|
|
DateTime wochenStart = start;
|
|
while (wochenStart.DayOfWeek != DayOfWeek.Monday)
|
|
{
|
|
wochenStart = wochenStart.AddDays(1);
|
|
}
|
|
|
|
decimal stunden = 0;
|
|
for (int i = 0; i < 7; i++)
|
|
{
|
|
stunden += GetArbeitszeitStundenFuerTag(az, wochenStart);
|
|
|
|
wochenStart = wochenStart.AddDays(1);
|
|
}
|
|
|
|
return stunden;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
protected virtual bool StundenDurchAbwesenheitenDuerfenNegativSein()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
protected virtual decimal? GetSollNachArbeitszeiten(Employee emp, DateTime start, DateTime ende)
|
|
{
|
|
if (emp.Arbeitszeiten != null && emp.Arbeitszeiten.Count > 0)
|
|
{
|
|
if (HatArbeitszeitImZeitraum(emp.Arbeitszeiten, start, ende))
|
|
{
|
|
decimal soll = 0;
|
|
|
|
DateTime startTemp = start;
|
|
|
|
while (startTemp < ende)
|
|
{
|
|
soll += GetSollNachArbeitszeitenFuerTag(emp, startTemp);
|
|
startTemp = startTemp.AddDays(1);
|
|
}
|
|
|
|
return soll;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private bool HatArbeitszeitImZeitraum(IList<Arbeitszeit> arbeitszeiten, DateTime start, DateTime ende)
|
|
{
|
|
if (arbeitszeiten != null)
|
|
{
|
|
foreach (var az in arbeitszeiten)
|
|
{
|
|
if ((!az.GueltigVon.HasValue || az.GueltigVon.Value < ende) && (!az.GueltigBis.HasValue || az.GueltigBis.Value >= start) && az.ArbeitszeitEintraege != null && az.ArbeitszeitEintraege.Count > 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected virtual decimal GetSollNachArbeitszeitenFuerTag(Employee emp, DateTime tag)
|
|
{
|
|
decimal soll = 0;
|
|
if (!IstFeiertag(tag))
|
|
{
|
|
if (emp.Arbeitszeiten != null)
|
|
{
|
|
foreach (var az in emp.Arbeitszeiten)
|
|
{
|
|
if ((!az.GueltigVon.HasValue || az.GueltigVon.Value <= tag) &&
|
|
(!az.GueltigBis.HasValue || az.GueltigBis.Value >= tag))
|
|
{
|
|
soll += GetArbeitszeitStundenFuerTag(az, tag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return soll;
|
|
}
|
|
|
|
private decimal GetArbeitszeitStundenFuerTag(Arbeitszeit az, DateTime tag)
|
|
{
|
|
var day = tag.DayOfWeek;
|
|
decimal stunden = 0;
|
|
foreach (var ae in az.ArbeitszeitEintraege)
|
|
{
|
|
if (SindAmGleichenWochentag(day, ae.Tag))
|
|
{
|
|
String dateStr1 = String.Format("{0:dd.MM.yyyy} {1}", tag, ae.UhrzeitVon);
|
|
String dateStr2 = String.Format("{0:dd.MM.yyyy} {1}", tag, ae.UhrzeitBis);
|
|
|
|
DateTime date1;
|
|
DateTime date2;
|
|
|
|
if (DateTime.TryParse(dateStr1, out date1) && DateTime.TryParse(dateStr2, out date2))
|
|
{
|
|
|
|
stunden += (decimal)date2.Subtract(date1).TotalHours;
|
|
}
|
|
}
|
|
}
|
|
|
|
return stunden;
|
|
}
|
|
|
|
private 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;
|
|
}
|
|
|
|
protected virtual void CalculateEmployeeSalary(MitarbeiterstundenkontoRO.EmployeeDetail empDetail, DateTime start, DateTime ende)
|
|
{
|
|
decimal maxpayment = 0;
|
|
|
|
Contract cstart = empDetail.Employee.GetValidContractForDate(start);
|
|
Contract cend = empDetail.Employee.GetValidContractForDate(ende);
|
|
if (cstart != null && cstart.HourlyRate.HasValue && cstart.WeeklyTotalHours.HasValue && cend != null)
|
|
{
|
|
if (cstart.Oid.Value == cend.Oid.Value || !cend.EntryDate.HasValue)
|
|
{
|
|
maxpayment = cstart.HourlyRate.Value * cstart.WeeklyTotalHours.Value * 4;
|
|
}
|
|
else
|
|
{
|
|
decimal totalHoursPerDay = cstart.WeeklyTotalHours.Value / 7m;
|
|
DateTime end = cend.EntryDate.Value;
|
|
TimeSpan ts = end.Subtract(start);
|
|
int days = (int)ts.TotalDays;
|
|
|
|
maxpayment = totalHoursPerDay * cstart.HourlyRate.Value * days;
|
|
|
|
Contract c2 = empDetail.Employee.GetValidContractForDate(end.AddDays(1));
|
|
if (c2 != null && c2.HourlyRate.HasValue && c2.WeeklyTotalHours.HasValue)
|
|
{
|
|
decimal totalHoursPerDay2 = c2.WeeklyTotalHours.Value / 7m;
|
|
TimeSpan ts2 = ende.Subtract(end);
|
|
int days2 = (int)ts2.TotalDays + 1;
|
|
|
|
maxpayment += totalHoursPerDay2 * c2.HourlyRate.Value * days2;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
empDetail.EmployeeSalaryByContract = maxpayment;
|
|
|
|
decimal salary = 0;
|
|
|
|
if (empDetail.ServiceRecordsInSelectedTimeSpan != null)
|
|
{
|
|
foreach (var sr in empDetail.ServiceRecordsInSelectedTimeSpan)
|
|
{
|
|
if (sr.ServiceDescription.Name != "Freizeit" || sr.ServiceDescription.ServiceCategory.Name != "Selbstzahler Freizeit")
|
|
{
|
|
Contract con = empDetail.Employee.GetValidContractForDate(sr.Start);
|
|
if (con != null && con.HourlyRate.HasValue)
|
|
{
|
|
salary += con.HourlyRate.Value * (sr.RoundedDuration / 60);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
empDetail.EmployeeSalaryByHours = salary;
|
|
}
|
|
|
|
protected virtual ServiceRecordSummary BerechneStunden(MitarbeiterstundenkontoRO.EmployeeDetail empDetail, IList<ServiceRecord> groupFilteredRecords, DateTime berichtsAnfang, DateTime berichtsEnde)
|
|
{
|
|
var sum = new ServiceRecordSummary();
|
|
sum.RecordsImBerichtszeitraum = new List<ServiceRecord>();
|
|
|
|
empDetail.ServiceRecordsInSelectedTimeSpan = new List<ServiceRecord>();
|
|
|
|
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))
|
|
{
|
|
empDetail.ServiceRecordsInSelectedTimeSpan.Add(item);
|
|
|
|
String test = String.Format("{0:dd.MM. HH:mm} - {1:HH:mm}, {2}", item.Start, item.End, item.RoundedDuration);
|
|
|
|
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 (UseServiceDescriptionPercentage())
|
|
{
|
|
if (item.ServiceDescription != null &&
|
|
item.ServiceDescription.ServiceCategory != null &&
|
|
item.ServiceDescription.ServiceCategory.Percentage != 100)
|
|
{
|
|
duration = (duration * item.ServiceDescription.ServiceCategory.Percentage) / 100;
|
|
}
|
|
}
|
|
|
|
if (item.ServiceDescription != null &&
|
|
item.ServiceDescription.ServiceCategory != null &&
|
|
item.ServiceDescription.ServiceCategory.IsBillable)
|
|
sum.IstAbrechenbar += duration;
|
|
else
|
|
sum.IstNichtAbrechenbar += duration;
|
|
|
|
if (duration > 0)
|
|
{
|
|
int test2 = 0;
|
|
}
|
|
}
|
|
sum.RecordsImBerichtszeitraum.Add(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
public virtual bool UseServiceDescriptionPercentage()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
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 (!oldRecord.GroupRoundedDuration.HasValue)
|
|
//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)
|
|
{
|
|
Contract c = GetContractForDate(emp, start, ende);
|
|
|
|
|
|
if (c != null && c.MonthlyTotalHours.HasValue && c.MonthlyTotalHours.Value > 0)
|
|
{
|
|
return c.MonthlyTotalHours.Value;
|
|
|
|
DateTime monatsAnfang = start;
|
|
DateTime monatsEnde = ende;
|
|
|
|
if (c.EntryDate.HasValue && c.EntryDate > monatsAnfang)
|
|
{
|
|
monatsAnfang = c.EntryDate.Value;
|
|
}
|
|
if (c.ContractEndDate.HasValue && c.ContractEndDate < monatsEnde)
|
|
{
|
|
monatsEnde = c.ContractEndDate.Value.Date.AddDays(1);
|
|
}
|
|
|
|
if (monatsAnfang < monatsEnde)
|
|
{
|
|
//if (monatsAnfang.Day == 1 && monatsEnde.Day == 1)
|
|
//{
|
|
return c.MonthlyTotalHours.Value;
|
|
//}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public virtual decimal? BerechneFlsSollProMonat(Employee emp, DateTime start, DateTime ende)
|
|
{
|
|
Contract c = GetContractForDate(emp, start, ende);
|
|
|
|
|
|
if (c != null && c.MonthlyFLS.HasValue && c.MonthlyFLS.Value > 0)
|
|
{
|
|
return c.MonthlyFLS.Value;
|
|
|
|
DateTime monatsAnfang = start;
|
|
DateTime monatsEnde = ende;
|
|
|
|
if (c.EntryDate.HasValue && c.EntryDate > monatsAnfang)
|
|
{
|
|
monatsAnfang = c.EntryDate.Value;
|
|
}
|
|
if (c.ContractEndDate.HasValue && c.ContractEndDate < monatsEnde)
|
|
{
|
|
monatsEnde = c.ContractEndDate.Value.Date.AddDays(1);
|
|
}
|
|
|
|
if (monatsAnfang < monatsEnde)
|
|
{
|
|
//if (monatsAnfang.Day == 1 && monatsEnde.Day == 1)
|
|
//{
|
|
return c.MonthlyFLS.Value;
|
|
//}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public virtual void HandleServiceRecord(MitarbeiterstundenkontoRO.EmployeeDetail emp, ServiceRecord item)
|
|
{
|
|
//do nothing
|
|
}
|
|
|
|
public virtual bool ShouldCreateDayDetails()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public virtual bool ShouldCreateDayDetailsForEachServiceRecord()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public virtual IList<MitarbeiterstundenkontoRO.DayDetail> CreateDayDetails(DateTime berichtStart, DateTime berichtEnde, MitarbeiterstundenkontoRO.EmployeeDetail ed, IList<ServiceRecord> recordsAll)
|
|
{
|
|
if (ShouldCreateDayDetailsForEachServiceRecord())
|
|
{
|
|
return CreateDayDetailsForEachServiceRecord(berichtStart, berichtEnde, ed, 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 = GetDuration(sr);
|
|
|
|
|
|
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.ZusammenhaengendeZeitraeume == null)
|
|
{
|
|
dd.ZusammenhaengendeZeitraeume = new List<DateTimeSpan>();
|
|
}
|
|
|
|
if (dd.ServiceRecords != null)
|
|
{
|
|
var orderedList = dd.ServiceRecords.OrderBy(i => i.Start);
|
|
|
|
DateTime lastEnd = DateTime.MinValue;
|
|
var gapCount = -1;
|
|
|
|
foreach (var sr in orderedList)
|
|
{
|
|
if (sr.Start.HasValue && sr.Start.Value.Hour == 0 && sr.Start.Value.Second > 0)
|
|
{
|
|
continue;
|
|
}
|
|
decimal duration = GetDuration(sr);
|
|
|
|
|
|
DateTime dtEnd = sr.Start.Value.AddMinutes((double)duration);
|
|
if (sr.Start > lastEnd)
|
|
{
|
|
gapCount++;
|
|
|
|
}
|
|
if (dtEnd > lastEnd)
|
|
{
|
|
lastEnd = dtEnd;
|
|
}
|
|
|
|
DateTimeSpan currentSpan = null;
|
|
if (gapCount + 1 > dd.ZusammenhaengendeZeitraeume.Count)
|
|
{
|
|
currentSpan = new DateTimeSpan();
|
|
currentSpan.StartDateTime = DateTime.MaxValue;
|
|
currentSpan.EndDateTime = DateTime.MinValue;
|
|
dd.ZusammenhaengendeZeitraeume.Add(currentSpan);
|
|
}
|
|
else
|
|
{
|
|
currentSpan = dd.ZusammenhaengendeZeitraeume[gapCount];
|
|
}
|
|
|
|
if (sr.Start < currentSpan.StartDateTime)
|
|
{
|
|
currentSpan.StartDateTime = sr.Start.Value;
|
|
}
|
|
if (dtEnd > currentSpan.EndDateTime)
|
|
{
|
|
currentSpan.EndDateTime = 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 IList<MitarbeiterstundenkontoRO.DayDetail> CreateDayDetailsForEachServiceRecord(DateTime berichtStart, DateTime berichtEnde, MitarbeiterstundenkontoRO.EmployeeDetail ed, IList<ServiceRecord> recordsAll)
|
|
{
|
|
var details = new List<MitarbeiterstundenkontoRO.DayDetail>();
|
|
|
|
foreach (var sr in recordsAll)
|
|
{
|
|
if (sr.Start.HasValue && sr.Start >= berichtStart && sr.Start < berichtEnde && sr.End.HasValue)
|
|
{
|
|
if (sr.Start.Value.Day == 8)
|
|
{
|
|
int test = 0;
|
|
}
|
|
if (!IsServiceRecordFehlzeit(sr) && AddServiceRecordToDuration(sr))
|
|
{
|
|
var dd = CreateDayDetail(sr.Start.Value, ed);
|
|
details.Add(dd);
|
|
|
|
decimal duration = GetDuration(sr);
|
|
|
|
|
|
dd.MinutesTotal += duration;
|
|
if (dd.ServiceRecords == null)
|
|
dd.ServiceRecords = new List<ServiceRecord>();
|
|
dd.ServiceRecords.Add(sr);
|
|
|
|
dd.Date = sr.Start.Value;
|
|
|
|
if (sr.Start.Value.Second == 0)
|
|
{
|
|
DateTime dtEnd = sr.Start.Value.AddMinutes((double)duration);
|
|
dd.StartDateTime1 = sr.Start;
|
|
|
|
dd.EndDateTime1 = dtEnd;
|
|
|
|
}
|
|
|
|
CalculateSpecialHours(dd, sr, duration);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return details.OrderBy(dd => dd.Date).ToList();
|
|
}
|
|
|
|
private decimal GetDuration(ServiceRecord 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;
|
|
}
|
|
}
|
|
|
|
return duration;
|
|
}
|
|
|
|
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;
|
|
}
|
|
if (sr.Start.Value.Second == 0 && dd.NightEnd.HasValue && dd.NightStart.HasValue)
|
|
{
|
|
var minuten = CheckNachtzeiten(sr.Start.Value, dd.NightStart.Value, dd.NightEnd.Value, (double)duration);
|
|
|
|
if (minuten > 0)
|
|
{
|
|
dd.SpecialHours += (decimal)(Math.Round(minuten, 0) / 60);
|
|
}
|
|
|
|
//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);
|
|
//}
|
|
}
|
|
}
|
|
|
|
private double CheckNachtzeiten(DateTime start, int nightStart, int nightEnd, double minuten)
|
|
{
|
|
DateTime nightStartDt = start.Date.AddHours(nightStart);
|
|
DateTime nightEndDt = start.Date.AddDays(1).AddHours(nightEnd);
|
|
|
|
|
|
DateTime dtEnd = start.AddMinutes(minuten);
|
|
|
|
double minutes = GetOverlappingMinutes(start, dtEnd, nightStartDt, nightEndDt);
|
|
minutes += GetOverlappingMinutes(start, dtEnd, nightStartDt.AddDays(-1), nightEndDt.AddDays(-1));
|
|
minutes += GetOverlappingMinutes(start, dtEnd, nightStartDt.AddDays(1), nightEndDt.AddDays(1));
|
|
|
|
return minutes;
|
|
|
|
}
|
|
|
|
private double GetOverlappingMinutes(DateTime start, DateTime end, DateTime nightStart, DateTime nightEnd)
|
|
{
|
|
if (end > nightStart && start < nightEnd)
|
|
{
|
|
DateTime dtStart = start;
|
|
|
|
if (dtStart < nightStart)
|
|
dtStart = nightStart;
|
|
|
|
DateTime dtEnd = end;
|
|
|
|
if (dtEnd > nightEnd)
|
|
dtEnd = nightEnd;
|
|
TimeSpan ts = dtEnd.Subtract(dtStart);
|
|
|
|
return ts.TotalMinutes;
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public virtual MitarbeiterstundenkontoRO.DayDetail CreateDayDetail(DateTime date, MitarbeiterstundenkontoRO.EmployeeDetail ed)
|
|
{
|
|
MitarbeiterstundenkontoRO.DayDetail dd = new MitarbeiterstundenkontoRO.DayDetail();
|
|
dd.ZusammenhaengendeZeitraeume = new List<DateTimeSpan>();
|
|
|
|
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 (ed.AbsenceTimeDays != null && ed.AbsenceTimeDays.TageProWocheDict != null)
|
|
{
|
|
if (ed.AbsenceTimeDays.RestStundenProWocheDict == null)
|
|
{
|
|
ed.AbsenceTimeDays.RestStundenProWocheDict = new Dictionary<DateTimeSpan, decimal>();
|
|
}
|
|
foreach (var week in ed.AbsenceTimeDays.TageProWocheDict.Keys)
|
|
{
|
|
if (!ed.AbsenceTimeDays.RestStundenProWocheDict.ContainsKey(week))
|
|
{
|
|
ed.AbsenceTimeDays.RestStundenProWocheDict.Add(week, ed.SollProWoche);
|
|
}
|
|
|
|
if (day.Date >= week.StartDate && day.Date <= week.EndDate)
|
|
{
|
|
var rest = ed.AbsenceTimeDays.RestStundenProWocheDict[week];
|
|
if (rest < soll)
|
|
{
|
|
soll = rest;
|
|
}
|
|
rest -= soll;
|
|
if (rest < 0)
|
|
{
|
|
rest = 0;
|
|
}
|
|
|
|
ed.AbsenceTimeDays.RestStundenProWocheDict[week] = rest;
|
|
}
|
|
}
|
|
}
|
|
decimal maxSoll = soll;
|
|
if (faktor != 0)
|
|
{
|
|
soll *= faktor; //halbe Feiertage etc. berücksichtigen
|
|
}
|
|
if (IsKrankheitAbsenceTime(absenceTime))
|
|
{
|
|
dd.HoursSick = soll;
|
|
}
|
|
else if (IsUrlaubAbsenceTime(absenceTime))
|
|
{
|
|
dd.HoursInVacation = soll;
|
|
}
|
|
if (dd.AbsenceTimes == null)
|
|
{
|
|
dd.AbsenceTimes = new List<AbsenceTime>();
|
|
}
|
|
dd.AbsenceTimes.Add(absenceTime);
|
|
dd.MinutesTotal += soll * 60;
|
|
}
|
|
}
|
|
}
|
|
|
|
//}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public virtual bool IstAnrechenbareAbsenceTime(AbsenceTime item)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
public virtual MitarbeiterstundenkontoRO.EmployeeDetail BerechneUeberstundenBis(MitarbeiterstundenkontoRO.EmployeeDetail edOrig, IList<ServiceRecord> records, DateTime monat, out decimal? ueberstunden, out decimal alteExtraUeberstunden)
|
|
{
|
|
MitarbeiterstundenkontoRO.EmployeeDetail edTotal = new MitarbeiterstundenkontoRO.EmployeeDetail();
|
|
|
|
ueberstunden = null;
|
|
alteExtraUeberstunden = 0;
|
|
|
|
var emp = edOrig.Employee;
|
|
|
|
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;
|
|
}
|
|
}
|
|
if (UseServiceDescriptionPercentage())
|
|
{
|
|
if (item.ServiceDescription != null &&
|
|
item.ServiceDescription.ServiceCategory != null &&
|
|
item.ServiceDescription.ServiceCategory.Percentage != 100)
|
|
{
|
|
duration = (duration * item.ServiceDescription.ServiceCategory.Percentage) / 100;
|
|
}
|
|
}
|
|
|
|
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);
|
|
var arbeitstageProWoche = anzWochentage;
|
|
if (c != null && c.WeeklyDays.HasValue && c.WeeklyDays.Value > 0)
|
|
{
|
|
arbeitstageProWoche = c.WeeklyDays.Value;
|
|
}
|
|
|
|
//if (anzWochentage != 5)
|
|
//{
|
|
// arbeitstage *= anzWochentage / 5m;
|
|
//}
|
|
var soll = GetSollNachArbeitszeiten(emp, start, ende);
|
|
|
|
if (!soll.HasValue)
|
|
{
|
|
var stundenSollProMonat = BerechneSollProMonat(emp, start, ende);
|
|
soll = stundenSollProMonat;
|
|
}
|
|
|
|
if (!soll.HasValue)
|
|
{
|
|
|
|
if (!soll.HasValue)
|
|
{
|
|
decimal maxSollMonat = arbeitstage * (maxWochenstunden / arbeitstageProWoche);
|
|
if (arbeitstageProWoche <= 5)
|
|
{
|
|
maxSollMonat = arbeitstage * (maxWochenstunden / 5);
|
|
}
|
|
|
|
soll = maxSollMonat * bu;
|
|
}
|
|
}
|
|
|
|
decimal sollMitarbeiter = soll ?? 0;
|
|
|
|
var ath = GetAbsenceTimeDaysWithWorkWeeks(emp, start, ende, arbeitstageProWoche);
|
|
decimal? fehlzeit = GetFehlzeiten(records, start, ende);
|
|
|
|
if (fehlzeit.HasValue)
|
|
{
|
|
sollMitarbeiter -= fehlzeit.Value;
|
|
|
|
}
|
|
|
|
|
|
MitarbeiterstundenkontoRO.EmployeeDetail ed = new MitarbeiterstundenkontoRO.EmployeeDetail();
|
|
ed.SollProTag = weeklyTotalHours / arbeitstageProWoche;
|
|
ed.ArbeitstageProWoche = arbeitstageProWoche;
|
|
ed.ArbeitstageImBerichtszeitraum = arbeitstage;
|
|
ed.SollProWoche = BerechneSollProWoche(c, ed);
|
|
ed.AbsenceTimeDays = ath;
|
|
ed.Employee = emp;
|
|
ed.StundenSollMax = sollMitarbeiter;
|
|
|
|
|
|
if (ath.TageGesamt.HasValue)
|
|
{
|
|
var minusStunden = BerechneStundenDurchAbwesenheiten(ath, start, ende, c, ed);
|
|
sollMitarbeiter -= minusStunden;
|
|
if (sollMitarbeiter < 0 && !StundenDurchAbwesenheitenDuerfenNegativSein())
|
|
{
|
|
sollMitarbeiter = 0;
|
|
}
|
|
//if (stundenSollProMonat.HasValue)
|
|
//{
|
|
// decimal stundenProTag = stundenSollProMonat.Value;
|
|
// if (arbeitstage != 0)
|
|
// {
|
|
// stundenProTag = stundenSollProMonat.Value/arbeitstage;
|
|
// }
|
|
// sollMitarbeiter -= (ath.TageGesamt.Value * stundenProTag);
|
|
//}
|
|
//else
|
|
//{
|
|
// decimal sollProWoche = maxWochenstunden*bu;
|
|
|
|
|
|
// var minusStunden = BerechneStundenDurchAbwesenheiten(ath, start, ende, c, sollProWoche);
|
|
|
|
|
|
//}
|
|
}
|
|
|
|
var ath2 = GetAbwesenheitenDurchServiceRecords(ed, c, records, start, ende);
|
|
|
|
if (ath2 != null)
|
|
{
|
|
|
|
var stunden = (ath2.StundenKrankheit + ath2.StundenUrlaub);
|
|
|
|
sollMitarbeiter -= stunden;
|
|
|
|
if (sollMitarbeiter < 0 && !StundenDurchAbwesenheitenDuerfenNegativSein())
|
|
{
|
|
sollMitarbeiter = 0;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
ueberstunden = BerechneUeberstunden(ed, ueberstunden, c, start, ende);
|
|
if (ShouldCreateDayDetails())
|
|
{
|
|
|
|
|
|
var days = CreateDayDetails(start, ende, ed, records);
|
|
var ah = GetAdditionalHours(days, start, ende, ed, records);
|
|
ueberstunden += ah;
|
|
}
|
|
|
|
edTotal.StundenSollOhneUrlaubKrankheit += sollMitarbeiter;
|
|
edTotal.StundenSollMax += soll ?? 0;
|
|
edTotal.FlsIst += flsIst / 60;
|
|
edTotal.MittelbarIst += mittelbarIst / 60;
|
|
edTotal.StundenGesamtIst += stundenMonat;
|
|
edTotal.Ueberstunden += ueberstunden;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return edTotal;
|
|
}
|
|
|
|
protected virtual decimal? BerechneUeberstunden(MitarbeiterstundenkontoRO.EmployeeDetail ed, decimal? ueberstundenStd, Contract contract, DateTime start, DateTime ende)
|
|
{
|
|
return ueberstundenStd;
|
|
}
|
|
|
|
public virtual decimal BerechneSollProWoche(Contract c, MitarbeiterstundenkontoRO.EmployeeDetail ed)
|
|
{
|
|
if (c != null)
|
|
{
|
|
if (c.MonthlyTotalHours.HasValue && c.MonthlyTotalHours.Value > 0)
|
|
{
|
|
if (ed.ArbeitstageImBerichtszeitraum > 0)
|
|
{
|
|
|
|
decimal stundenProTag = GetSollArbeitszeitProArbeitstag(c, ed);
|
|
|
|
|
|
return (stundenProTag * 5);
|
|
//sollStundenProWoche = stundenProTag * ed.ArbeitstageProWoche;
|
|
|
|
//return (ath.TageGesamt.Value * stundenProTag);
|
|
}
|
|
}
|
|
else if (c.WeeklyTotalHours.HasValue)
|
|
{
|
|
return c.WeeklyTotalHours.Value;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
public virtual decimal BerechneStundenDurchAbwesenheiten(AbsenceTimeDays ath, DateTime start, DateTime ende, Contract c, MitarbeiterstundenkontoRO.EmployeeDetail ed)
|
|
{
|
|
if (BerechneAlteAbwesenheitsStunden(start))
|
|
{
|
|
return BerechneStundenDurchAbwesenheitenAlt(ath, start, ende, c, ed);
|
|
|
|
}
|
|
decimal stunden = 0;
|
|
|
|
if (c != null)
|
|
{
|
|
if (ath.TageGesamt.HasValue)
|
|
{
|
|
if (HatArbeitszeitImZeitraum(ed.Employee.Arbeitszeiten, start, ende))
|
|
{
|
|
return BerechneAbwesenheitsStundenDurchArbeitszeiten(ed.Employee, start, ende);
|
|
|
|
}
|
|
decimal sollStundenProWoche = BerechneSollProWoche(c, ed);
|
|
|
|
if (sollStundenProWoche > 0)
|
|
{
|
|
if (ed.ArbeitstageProWoche == 5)
|
|
{
|
|
stunden = ath.TageGesamt.Value * (sollStundenProWoche / 5);
|
|
}
|
|
else if (ath.TageProWocheDict != null && ed.ArbeitstageProWoche > 0)
|
|
{
|
|
foreach (var week in ath.TageProWocheDict.Keys)
|
|
{
|
|
var tage = ath.TageProWocheDict[week];
|
|
|
|
if (tage > 0)
|
|
{
|
|
if (tage > ed.ArbeitstageProWoche)
|
|
{
|
|
tage = ed.ArbeitstageProWoche;
|
|
|
|
}
|
|
|
|
stunden += tage * (sollStundenProWoche / ed.ArbeitstageProWoche);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return stunden;
|
|
}
|
|
|
|
public virtual decimal BerechneAbwesenheitsStundenDurchArbeitszeiten(Employee emp, DateTime start, DateTime ende)
|
|
{
|
|
decimal stunden = 0;
|
|
|
|
DateTime startTemp = start;
|
|
|
|
while (startTemp < ende)
|
|
{
|
|
stunden += BerechneAlleAbwesenheitsStundenFuerArbeitszeiten(emp, startTemp);
|
|
|
|
startTemp = startTemp.AddDays(1);
|
|
}
|
|
|
|
return stunden;
|
|
}
|
|
|
|
public virtual decimal BerechneAlleAbwesenheitsStundenFuerArbeitszeiten(Employee emp, DateTime tag)
|
|
{
|
|
decimal stunden = 0;
|
|
|
|
foreach (var az in emp.Arbeitszeiten)
|
|
{
|
|
if ((!az.GueltigVon.HasValue || az.GueltigVon.Value <= tag) &&
|
|
(!az.GueltigBis.HasValue || az.GueltigBis.Value >= tag))
|
|
{
|
|
|
|
var day = tag.DayOfWeek;
|
|
foreach (var ae in az.ArbeitszeitEintraege)
|
|
{
|
|
if (SindAmGleichenWochentag(day, ae.Tag))
|
|
{
|
|
|
|
String dateStr1 = String.Format("{0:dd.MM.yyyy} {1}", tag, ae.UhrzeitVon);
|
|
String dateStr2 = String.Format("{0:dd.MM.yyyy} {1}", tag, ae.UhrzeitBis);
|
|
|
|
DateTime date1;
|
|
DateTime date2;
|
|
|
|
if (DateTime.TryParse(dateStr1, out date1) && DateTime.TryParse(dateStr2, out date2))
|
|
{
|
|
stunden += BerechneAbwesenheitsStundenFuerArbeitstag(emp, date1, date2);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return stunden;
|
|
}
|
|
|
|
public virtual decimal BerechneAbwesenheitsStundenFuerArbeitstag(Employee emp, DateTime arbeitstagStart, DateTime arbeitstagEnde)
|
|
{
|
|
foreach (var at in emp.AbsenceTimes)
|
|
{
|
|
|
|
if ((!at.Start.HasValue || at.Start.Value <= arbeitstagEnde.Date) &&
|
|
(!at.End.HasValue || at.End.Value >= arbeitstagStart.Date))
|
|
{
|
|
var faktor = GetFeiertagsFaktor(arbeitstagStart);
|
|
|
|
if (faktor < 1)
|
|
{
|
|
var hours = (decimal)arbeitstagEnde.Subtract(arbeitstagStart).TotalHours;
|
|
if (faktor != 0)
|
|
{
|
|
hours *= faktor;
|
|
}
|
|
|
|
return hours;
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//CB 12.4.18: Die Abwesenheitsstunden wurden bei Arbeitstagen < 5 früher falsch berechnet. Damit bereits erstellte Stundenkonto nicht zu veränderten Werten führen, habe
|
|
//ich einen Schalter eingebaut, mit dem bestimmt werden kann, ob die alte Berechnung angewendet werden soll oder nicht (Standard ist ja)
|
|
public virtual bool BerechneAlteAbwesenheitsStunden(DateTime monatAnfang)
|
|
{
|
|
if (monatAnfang < new DateTime(2018, 4, 1))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private decimal BerechneStundenDurchAbwesenheitenAlt(AbsenceTimeDays ath, DateTime start, DateTime ende, Contract c, MitarbeiterstundenkontoRO.EmployeeDetail ed)
|
|
{
|
|
|
|
decimal? sollProMonat = BerechneSollProMonat(ed.Employee, start, ende);
|
|
|
|
if (sollProMonat.HasValue)
|
|
{
|
|
decimal stundenProTag = sollProMonat.Value / ed.ArbeitstageImBerichtszeitraum;
|
|
return (ath.TageGesamt.Value * stundenProTag);
|
|
}
|
|
else
|
|
{
|
|
decimal sollProWoche = BerechneSollProWoche(c, ed);
|
|
decimal stunden = 0;
|
|
|
|
if (ath.TageGesamt.HasValue)
|
|
{
|
|
if (ed.ArbeitstageProWoche == 5)
|
|
{
|
|
stunden = ath.TageGesamt.Value * (sollProWoche / ed.ArbeitstageProWoche);
|
|
}
|
|
else if (ath.TageProWocheDict != null && ed.ArbeitstageProWoche > 0)
|
|
{
|
|
foreach (var week in ath.TageProWocheDict.Keys)
|
|
{
|
|
var tage = ath.TageProWocheDict[week];
|
|
|
|
if (tage > 0)
|
|
{
|
|
if (tage > ed.ArbeitstageProWoche)
|
|
{
|
|
tage = ed.ArbeitstageProWoche;
|
|
|
|
}
|
|
stunden += tage * (sollProWoche / ed.ArbeitstageProWoche);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return stunden;
|
|
}
|
|
}
|
|
|
|
public virtual decimal GetSollArbeitszeitProArbeitstag(Contract contract, MitarbeiterstundenkontoRO.EmployeeDetail ed)
|
|
{
|
|
if (contract.MonthlyTotalHours.HasValue && contract.MonthlyTotalHours.Value > 0 && ed.ArbeitstageImBerichtszeitraum > 0)
|
|
{
|
|
return contract.MonthlyTotalHours.Value / ed.ArbeitstageImBerichtszeitraum;
|
|
}
|
|
else if (contract.WeeklyTotalHours.HasValue && ed.ArbeitstageProWoche > 0)
|
|
{
|
|
return contract.WeeklyTotalHours.Value / ed.ArbeitstageProWoche;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//Wird nicht mehr benutzt
|
|
public virtual decimal BerechneStundenDurchAbwesenheiten(AbsenceTimeDays ath, DateTime start, DateTime ende, int arbeitstageProWoche, decimal sollProWoche)
|
|
{
|
|
decimal stunden = 0;
|
|
|
|
if (ath.TageGesamt.HasValue)
|
|
{
|
|
if (arbeitstageProWoche == 5)
|
|
{
|
|
stunden = ath.TageGesamt.Value*(sollProWoche/arbeitstageProWoche);
|
|
}
|
|
else if (ath.TageProWocheDict != null && arbeitstageProWoche > 0)
|
|
{
|
|
foreach (var week in ath.TageProWocheDict.Keys)
|
|
{
|
|
var tage = ath.TageProWocheDict[week];
|
|
|
|
if (tage > 0)
|
|
{
|
|
if (tage > arbeitstageProWoche)
|
|
{
|
|
tage = arbeitstageProWoche;
|
|
|
|
}
|
|
stunden += tage * (sollProWoche / arbeitstageProWoche);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return stunden;
|
|
}
|
|
|
|
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.BreakMinutes2.HasValue && dayDetail.MaxHoursUntilBreak2.HasValue)
|
|
{
|
|
addHours += CalculateBreakMinutes(dayDetail, dayDetail.MaxHoursUntilBreak2.Value, dayDetail.BreakMinutes2.Value);
|
|
}
|
|
if (dayDetail.BreakMinutes.HasValue && dayDetail.MaxHoursUntilBreak.HasValue)
|
|
{
|
|
addHours += CalculateBreakMinutes(dayDetail, dayDetail.MaxHoursUntilBreak.Value, dayDetail.BreakMinutes.Value);
|
|
}
|
|
|
|
}
|
|
|
|
return addHours;
|
|
}
|
|
|
|
public virtual decimal CalculateBreakMinutes(MitarbeiterstundenkontoRO.DayDetail dayDetail, int maxHoursUntilBreak, int breakMinutes)
|
|
{
|
|
decimal addHours = 0;
|
|
|
|
if (dayDetail.ZusammenhaengendeZeitraeume != null && dayDetail.ZusammenhaengendeZeitraeume.Count > 0)
|
|
{
|
|
foreach (var span in dayDetail.ZusammenhaengendeZeitraeume)
|
|
{
|
|
if (span.EndDateTime.Subtract(span.StartDateTime).TotalHours > maxHoursUntilBreak)
|
|
{
|
|
addHours -= (breakMinutes / 60m);
|
|
dayDetail.MinutesTotal -= breakMinutes;
|
|
dayDetail.PauseInMinuten += breakMinutes;
|
|
}
|
|
}
|
|
|
|
return addHours;
|
|
}
|
|
|
|
if (dayDetail.EndDateTime1.HasValue && dayDetail.StartDateTime1.HasValue)
|
|
{
|
|
if (dayDetail.EndDateTime1.Value.Subtract(dayDetail.StartDateTime1.Value).TotalHours > maxHoursUntilBreak)
|
|
{
|
|
addHours -= (breakMinutes / 60m);
|
|
dayDetail.MinutesTotal -= breakMinutes;
|
|
dayDetail.PauseInMinuten += breakMinutes;
|
|
}
|
|
}
|
|
if (dayDetail.EndDateTime2.HasValue && dayDetail.StartDateTime2.HasValue)
|
|
{
|
|
if (dayDetail.EndDateTime2.Value.Subtract(dayDetail.StartDateTime2.Value).TotalHours > maxHoursUntilBreak)
|
|
{
|
|
addHours -= (breakMinutes / 60m);
|
|
dayDetail.MinutesTotal -= breakMinutes;
|
|
dayDetail.PauseInMinuten += breakMinutes;
|
|
}
|
|
}
|
|
if (dayDetail.EndDateTime3.HasValue && dayDetail.StartDateTime3.HasValue)
|
|
{
|
|
if (dayDetail.EndDateTime3.Value.Subtract(dayDetail.StartDateTime3.Value).TotalHours > maxHoursUntilBreak)
|
|
{
|
|
addHours -= (breakMinutes / 60m);
|
|
dayDetail.MinutesTotal -= breakMinutes;
|
|
dayDetail.PauseInMinuten += breakMinutes;
|
|
}
|
|
}
|
|
if (dayDetail.EndDateTime4.HasValue && dayDetail.StartDateTime4.HasValue)
|
|
{
|
|
if (dayDetail.EndDateTime4.Value.Subtract(dayDetail.StartDateTime4.Value).TotalHours > maxHoursUntilBreak)
|
|
{
|
|
addHours -= (breakMinutes / 60m);
|
|
dayDetail.MinutesTotal -= breakMinutes;
|
|
dayDetail.PauseInMinuten += breakMinutes;
|
|
}
|
|
}
|
|
|
|
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 GetAbsenceTimeDaysWithWorkWeeks(Employee emp, DateTime start, DateTime end, int arbeitstageProWoche)
|
|
{
|
|
if (HatArbeitszeitImZeitraum(emp.Arbeitszeiten, start, end))
|
|
{
|
|
return GetAbsenceTimeDaysNachArbeitszeiten(emp, start, end, arbeitstageProWoche);
|
|
}
|
|
return GetAbsenceTimeDaysWithWorkWeeks(emp.AbsenceTimes, start, end, arbeitstageProWoche);
|
|
|
|
}
|
|
|
|
public virtual AbsenceTimeDays GetAbsenceTimeDaysNachArbeitszeiten(Employee emp, DateTime start, DateTime end, int arbeitstageProWoche)
|
|
{
|
|
var atd = new AbsenceTimeDays();
|
|
|
|
decimal? tage = null;
|
|
|
|
DateTime startTemp = start;
|
|
|
|
while (startTemp < end)
|
|
{
|
|
AddAbsenceDaysNachArbeitszeitenFuerTag(atd, emp, startTemp);
|
|
|
|
startTemp = startTemp.AddDays(1);
|
|
}
|
|
|
|
|
|
return atd;
|
|
}
|
|
|
|
public virtual void AddAbsenceDaysNachArbeitszeitenFuerTag(AbsenceTimeDays atd, Employee emp, DateTime tag)
|
|
{
|
|
foreach (var az in emp.Arbeitszeiten)
|
|
{
|
|
if ((!az.GueltigVon.HasValue || az.GueltigVon.Value <= tag) &&
|
|
(!az.GueltigBis.HasValue || az.GueltigBis.Value >= tag))
|
|
{
|
|
|
|
var day = tag.DayOfWeek;
|
|
foreach (var ae in az.ArbeitszeitEintraege)
|
|
{
|
|
if (SindAmGleichenWochentag(day, ae.Tag))
|
|
{
|
|
|
|
String dateStr1 = String.Format("{0:dd.MM.yyyy} {1}", tag, ae.UhrzeitVon);
|
|
String dateStr2 = String.Format("{0:dd.MM.yyyy} {1}", tag, ae.UhrzeitBis);
|
|
|
|
DateTime date1;
|
|
DateTime date2;
|
|
|
|
if (DateTime.TryParse(dateStr1, out date1) && DateTime.TryParse(dateStr2, out date2))
|
|
{
|
|
AddAbsenceDaysFuerTag(atd, emp, date1, date2);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AddAbsenceDaysFuerTag(AbsenceTimeDays atd, Employee emp, DateTime arbeitstagStart, DateTime arbeitstagEnde)
|
|
{
|
|
var hours = (decimal)arbeitstagEnde.Subtract(arbeitstagStart).TotalHours;
|
|
|
|
foreach (var at in emp.AbsenceTimes)
|
|
{
|
|
|
|
if ((!at.Start.HasValue || at.Start.Value <= arbeitstagEnde.Date) &&
|
|
(!at.End.HasValue || at.End.Value >= arbeitstagStart.Date))
|
|
{
|
|
|
|
var faktor = GetFeiertagsFaktor(arbeitstagStart);
|
|
|
|
if (faktor < 1)
|
|
{
|
|
var tag = 1m;
|
|
if (faktor != 0)
|
|
{
|
|
tag *= faktor;
|
|
hours *= faktor;
|
|
}
|
|
|
|
|
|
if (IsKrankheitAbsenceTime(at))
|
|
{
|
|
if (!atd.TageKrankheit.HasValue)
|
|
atd.TageKrankheit = 0;
|
|
|
|
atd.TageKrankheit += tag;
|
|
}
|
|
|
|
if (IsUrlaubAbsenceTime(at))
|
|
{
|
|
if (!atd.TageUrlaub.HasValue)
|
|
atd.TageUrlaub = 0;
|
|
|
|
atd.TageUrlaub += tag;
|
|
}
|
|
if (!atd.TageGesamt.HasValue)
|
|
atd.TageGesamt = 0;
|
|
|
|
|
|
atd.TageGesamt += tag;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public virtual AbsenceTimeDays GetAbsenceTimeDaysWithWorkWeeks(IList<AbsenceTime> absenceTimes, DateTime start, DateTime end, int arbeitstageProWoche)
|
|
{
|
|
var atd = new AbsenceTimeDays();
|
|
var totalSpan = new DateTimeSpan();
|
|
totalSpan.StartDate = start;
|
|
totalSpan.EndDate = end.AddDays(-1);
|
|
|
|
var weeks = totalSpan.GetWeeks(true, false);
|
|
if (BerechneAlteAbwesenheitsStunden(start))
|
|
{
|
|
totalSpan.EndDate = end;
|
|
|
|
weeks = totalSpan.GetWholeWeeks();
|
|
}
|
|
|
|
atd.TageProWocheDict = new Dictionary<DateTimeSpan, decimal>();
|
|
foreach (var week in weeks)
|
|
{
|
|
atd.TageProWocheDict.Add(week, 0);
|
|
}
|
|
decimal? tage = null;
|
|
if (absenceTimes != null)
|
|
{
|
|
foreach (var item in absenceTimes)
|
|
{
|
|
if (IstAnrechenbareAbsenceTime(item))
|
|
{
|
|
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);
|
|
bool istWochenende =
|
|
day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday;
|
|
if (arbeitstageProWoche == 6)
|
|
{
|
|
istWochenende = day.DayOfWeek == DayOfWeek.Sunday;
|
|
}
|
|
else if (arbeitstageProWoche > 6)
|
|
{
|
|
istWochenende = false;
|
|
}
|
|
|
|
if (faktor < 1 && !istWochenende)
|
|
{
|
|
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;
|
|
}
|
|
|
|
foreach (var week in weeks)
|
|
{
|
|
if (day >= week.StartDate && day <= week.EndDate)
|
|
{
|
|
if (atd.TageProWocheDict.ContainsKey(week))
|
|
{
|
|
atd.TageProWocheDict[week] += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
day = day.AddDays(1);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (tage.HasValue)
|
|
tage /= 24;
|
|
atd.TageGesamt = tage;
|
|
return atd;
|
|
}
|
|
|
|
|
|
public virtual AbsenceTimeDays GetAbsenceTimeDays(IList<AbsenceTime> absenceTimes, DateTime start, DateTime end)
|
|
{
|
|
return GetAbsenceTimeDaysWithWorkWeeks(absenceTimes, start, end, ANZ_WOCHENTAGE);
|
|
}
|
|
|
|
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 start = von;
|
|
DateTime end = bis;
|
|
|
|
TimeSpan ts = end.Subtract(start);
|
|
|
|
var maxDays = (decimal)ts.TotalDays;
|
|
|
|
while (start < end)
|
|
{
|
|
int arbeitstageProWoche = ANZ_WOCHENTAGE;
|
|
|
|
var c = GetContractForDate(emp, start, start);
|
|
|
|
if (c != null && c.WeeklyDays.HasValue && c.WeeklyDays > 0)
|
|
{
|
|
arbeitstageProWoche = c.WeeklyDays.Value;
|
|
}
|
|
|
|
|
|
if (arbeitstageProWoche <= 5 && (start.DayOfWeek == DayOfWeek.Saturday || start.DayOfWeek == DayOfWeek.Sunday))
|
|
{
|
|
maxDays -= 1;
|
|
}
|
|
else if (arbeitstageProWoche == 6 && start.DayOfWeek == DayOfWeek.Sunday)
|
|
{
|
|
maxDays -= 1;
|
|
}
|
|
else
|
|
{
|
|
maxDays -= GetFeiertagsFaktor(start);
|
|
//if (IstFeiertag(start))
|
|
// maxDays--;
|
|
}
|
|
start = start.AddDays(1);
|
|
}
|
|
return maxDays;
|
|
|
|
}
|
|
|
|
public virtual Contract GetContractForDate(Employee emp, DateTime start, DateTime ende)
|
|
{
|
|
Contract c = emp.GetValidContractForDate(start);
|
|
if (c == null) // Kein Vertrag vom 1. gefunden, gucken, ob es einen gibt, der mitten im Monat beginnt.
|
|
{
|
|
var c2 = GetNextValidContractForDate(start, emp);
|
|
if (c2 != null && c2.EntryDate.HasValue && c2.EntryDate.Value < ende)
|
|
c = c2;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
//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;
|
|
|
|
public Dictionary<DateTimeSpan, decimal> TageProWocheDict;
|
|
public Dictionary<DateTimeSpan, decimal> RestStundenProWocheDict;
|
|
}
|
|
|
|
public class AbsenceTimeHours
|
|
{
|
|
public decimal StundenUrlaub;
|
|
public decimal StundenKrankheit;
|
|
}
|
|
|
|
public class ServiceRecordSummary
|
|
{
|
|
public decimal IstAbrechenbar { get; set; }
|
|
|
|
public decimal IstNichtAbrechenbar { get; set; }
|
|
|
|
public IList<ServiceRecord> RecordsImBerichtszeitraum { get; set; }
|
|
}
|
|
}
|