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 MitarbeiterstundenkontoRO.EmployeeDetail AktuellBearbeitetesEmployeeDetail { get; set; } 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(); 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 groupFilteredRecords = empDetail.AllServiceRecords; if (groupFilteredRecords == null) { IList recordsAll = DAOFactory.SearchDAO.FindServiceRecords(emp.Oid, null); recordsAll = AnalysisServiceImp.FilterActiveServiceRecords(recordsAll); // groupFilteredRecords = new List(); Dictionary groupBookingDict = new Dictionary(); 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); } } } empDetail.AllServiceRecords = groupFilteredRecords; } while (berichtsAnfang < berichtsEnde) { StarteBerechnung(berichtsAnfang, berichtsEnde, empDetail); 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; decimal? stundenSollImVertragsUndBerichtzeitraum = null; if (empDetail.HasContract) { 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; } AktuellBearbeitetesEmployeeDetail = empDetail; 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 + ath2.StundenSonstiges; 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); // ABCDEF statt alle SR alle Diensteinträge abarbeiten var alleDiensteintraege = DAOFactory.GenericDAO.GetAllActive().Where(d => d.EmployeeOid == empDetail.Employee.Oid).ToList(); var alleDienstvertretungen = DAOFactory.GenericDAO.GetAllActive().Where(d => d.EmployeeOid == empDetail.Employee.Oid).ToList(); decimal? ueberstundenVormonatFuerDienstplanung; decimal? alteExtraUeberstundenDienstplanung; empDetail.DienstplanIst += BerechneDienstplanIst(empDetail, alleDiensteintraege, alleDienstvertretungen, ro.ReportStartDate, out ueberstundenVormonatFuerDienstplanung, out alteExtraUeberstundenDienstplanung); // ABCDEF var dienstplanIstAlsStunden = empDetail.DienstplanIst / 60; decimal extraStunden = 0; BerechneExtraUeberstunden(emp, monatsAnfang, monatsEnde, out extraStunden); // OverTimes 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); } #region Ist-Berechnung für Dienstplanung public decimal BerechneDienstplanIst(MitarbeiterstundenkontoRO.EmployeeDetail empDetail, List eintraege, List vertretungen, DateTime monat, out decimal? ueberstunden, out decimal? alteExtraUeberstunden) // ABCDEF { ueberstunden = null; alteExtraUeberstunden = 0; decimal dpIst = 0; MitarbeiterstundenkontoRO.EmployeeDetail edTotal = new MitarbeiterstundenkontoRO.EmployeeDetail(); Employee emp = empDetail.Employee; Contract c = emp.FirstContract; // Der Einfachheit halber: Vertretungen in Einträge umwandeln eintraege.AddRange(VertretungenUmwandeln(vertretungen.ToList())); if (c != null) { Dictionary> eintragDict = CreateDiensteintragDictByDate(eintraege); // Anzahl der Einträge korrekt 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.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); List entriesThisMonth = new List(); string key = string.Format("{0:yyyyMM}", start); if (eintragDict.ContainsKey(key)) { foreach (var item in eintragDict[key]) { minutenMonat += Convert.ToDecimal(item.DauerInStunden * 60); entriesThisMonth.Add(item); } } dpIst += minutenMonat; decimal arbeitstage = GetArbeitstageImBereich(start, ende, emp); var arbeitstageProWoche = anzWochentage; if (c != null && c.WeeklyDays.HasValue && c.WeeklyDays.Value > 0) arbeitstageProWoche = c.WeeklyDays.Value; 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); 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; } } decimal stundenMonat = minutenMonat / 60m; stundenMonat = ((flsIst * AddRateFactorToIst()) + mittelbarIst) / 60m; if (!ueberstunden.HasValue) ueberstunden = 0; ueberstunden += stundenMonat - sollMitarbeiter; decimal extraUeberstunden = 0; BerechneExtraUeberstunden(emp, start, ende, out extraUeberstunden); ueberstunden += extraUeberstunden; alteExtraUeberstunden = extraUeberstunden; ed.StundenSollOhneUrlaubKrankheit = sollMitarbeiter; ed.StundenGesamtIst = stundenMonat; ed.Ueberstunden = ueberstunden; ed.UeberstundenVormonat = edTotal.Ueberstunden; 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 dpIst; } private Dictionary> CreateDiensteintragDictByDate(List eintraege) { var dict = new Dictionary>(); foreach (var item in eintraege) { //if (!IsServiceRecordFehlzeit(item)) //{ string key = string.Format("{0:yyyyMM}", item.Datum); List list; if (!dict.ContainsKey(key)) { list = new List(); dict.Add(key, list); } else { list = dict[key]; } list.Add(item); //} } return dict; } private List VertretungenUmwandeln(List vertretungen) { List eintraege = new List(); foreach (var v in vertretungen) { eintraege.Add(new DienstEintrag() { Datum = v.Datum, DauerInStunden = v.DauerInStunden, DienstOid = v.DienstOid, EmployeeOid = v.EmployeeOid, Endzeit = v.Endzeit, Notice = v.Notice, Startzeit = v.Startzeit, WohnheimOid = v.WohnheimOid, Zeile = v.Zeile }); } return eintraege; } #endregion protected virtual void StarteBerechnung(DateTime berichtsAnfang, DateTime berichtsEnde, MitarbeiterstundenkontoRO.EmployeeDetail empDetail) { //do nothing } protected virtual AbsenceTimeHours GetAbwesenheitenDurchServiceRecords(MitarbeiterstundenkontoRO.EmployeeDetail empDetail, Contract c, IList 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 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 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; var fak = GetFeiertagsFaktor(tag); if (fak < 1) { 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)) { var std = GetArbeitszeitStundenFuerTag(az, tag); soll += (std * (1 - fak)); } } } } 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 groupFilteredRecords, DateTime berichtsAnfang, DateTime berichtsEnde) { var sum = new ServiceRecordSummary(); sum.RecordsImBerichtszeitraum = new List(); empDetail.ServiceRecordsInSelectedTimeSpan = new List(); 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 recordsThisMonth) { return 0; } public virtual decimal BerechnePauseMinuten(IList srList) { decimal pausenZeit = 0; List pausen = new List(); List nichtpausen = new List(); 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 FilterEmployeeList(List employeeDetailList) { List newEmpList = new List(); 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 groupFilteredRecords, Contract contract) { //do nothing } public virtual void CorrectOverlappingTimes(IList serviceRecords) { List oldRecords = new List(); 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 CreateDayDetails(DateTime berichtStart, DateTime berichtEnde, MitarbeiterstundenkontoRO.EmployeeDetail ed, IList recordsAll) { if (ShouldCreateDayDetailsForEachServiceRecord()) { return CreateDayDetailsForEachServiceRecord(berichtStart, berichtEnde, ed, recordsAll); } Dictionary dayToDetail = new Dictionary(); 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(); 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(); } 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 CreateDayDetailsForEachServiceRecord(DateTime berichtStart, DateTime berichtEnde, MitarbeiterstundenkontoRO.EmployeeDetail ed, IList recordsAll) { var details = new List(); 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(); 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(); 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; } if (absenceTime.End.HasValue && absenceTime.End.Value.Date == span.StartDate.Date && absenceTime.End.Value.Hour > 0) { span.EndDate = absenceTime.End.Value; } else { 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 sollDiesenTag = ed.SollProTag; var c = ed.Employee.GetValidContractForDate(dd.Date); if (c != null) { decimal wth = 0; int apw = ANZ_WOCHENTAGE; if (c.WeeklyTotalHours.HasValue) { wth = c.WeeklyTotalHours.Value; } if (c.WeeklyDays.HasValue && c.WeeklyDays.Value > 0) { apw = c.WeeklyDays.Value; } sollDiesenTag = wth / apw; } if (span.StartDate.Hour > 0 && span.EndDate.Hour > 0) { var ts = span.EndDate.Subtract(span.StartDate); sollDiesenTag -= ts.Hours; faktor = 1; // Keine halben Feiertag berücksichtigen, wenn die Abwesenheit in Stunden angegeben wurde } if (ed.AbsenceTimeDays != null && ed.AbsenceTimeDays.TageProWocheDict != null) { if (ed.AbsenceTimeDays.RestStundenProWocheDict == null) { ed.AbsenceTimeDays.RestStundenProWocheDict = new Dictionary(); } 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 < sollDiesenTag) { sollDiesenTag = rest; } rest -= sollDiesenTag; if (rest < 0) { rest = 0; } ed.AbsenceTimeDays.RestStundenProWocheDict[week] = rest; } } } decimal maxSoll = sollDiesenTag; if (faktor != 0) { sollDiesenTag *= faktor; //halbe Feiertage etc. berücksichtigen } if (IsKrankheitAbsenceTime(absenceTime)) { // Vermutlich diese Methode in CustomMitarbeiterStundenKontoBerechnung überschreiben und hier Prüfung machen, ob absenceReason ohne Fortzahlung ist //und wenn ja, HoursSick oder Soll oder so für den Tag auf 0 setzen dd.HoursSick = sollDiesenTag; } else if (IsUrlaubAbsenceTime(absenceTime)) { dd.HoursInVacation = sollDiesenTag; } if (dd.AbsenceTimes == null) { dd.AbsenceTimes = new List(); } dd.AbsenceTimes.Add(absenceTime); dd.MinutesTotal += sollDiesenTag * 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 || absenceTime.AbsenceReason.Description.ToLower() == "au"); } 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 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> 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 recordsThisMonth = new List(); 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 (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 + ath2.StundenSonstiges; sollMitarbeiter -= stunden; if (sollMitarbeiter < 0 && !StundenDurchAbwesenheitenDuerfenNegativSein()) { sollMitarbeiter = 0; } } decimal stundenMonat = minutenMonat/60m; 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()) { var days = CreateDayDetails(start, ende, ed, records); var ah = GetAdditionalHours(days, start, ende, ed, records); ueberstunden += ah; } ed.StundenSollOhneUrlaubKrankheit = sollMitarbeiter; ed.FlsIst = flsIst / 60; ed.MittelbarIst = mittelbarIst / 60; ed.StundenGesamtIst = stundenMonat; ed.Ueberstunden = ueberstunden; ed.UeberstundenVormonat = edTotal.Ueberstunden; ueberstunden = BerechneUeberstunden(ed, ueberstunden, c, start, ende); 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> CreateServiceRecordDictByDate(IList records) { var dict = new Dictionary>(); foreach (var item in records) { if (!IsServiceRecordFehlzeit(item)) { if (item.Start.HasValue) { String key = String.Format("{0:yyyyMM}", item.Start.Value); IList list; if (!dict.ContainsKey(key)) { list = new List(); dict.Add(key, list); } else { list = dict[key]; } list.Add(item); } } } return dict; } public virtual decimal GetAdditionalHours(IList days, DateTime berichtStart, DateTime berichtEnde, MitarbeiterstundenkontoRO.EmployeeDetail ed, IList 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) { Dictionary daysDict = new Dictionary(); 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)) { String dayKey = String.Format("{0:dd.MM.yyyy}", date1); if (!daysDict.ContainsKey(dayKey)) { AddAbsenceDaysFuerTag(atd, emp, date1, date2); daysDict.Add(dayKey, true); } } } } } } } 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 (at.Start.HasValue && at.End.HasValue && at.Start.Value.Day == at.End.Value.Day && // at.Start.Value.Month == at.End.Value.Month) //{ // var std = at.End.Value.Subtract(at.Start.Value) //} 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 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(); 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 (item.Start.HasValue && item.End.HasValue && item.Start.Value.Date == item.End.Value.Date && item.Start.Value.Hour > 0) { if (AktuellBearbeitetesEmployeeDetail != null) { faktor = 1; decimal hours = item.End.Value.Subtract(item.Start.Value).Hours; var sollAmTag = AktuellBearbeitetesEmployeeDetail.SollProTag; if (hours > sollAmTag) { hours = sollAmTag; } if (sollAmTag > 0) { tag = hours / sollAmTag; std = tag * 24; } } } 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 absenceTimes, DateTime start, DateTime end) { return GetAbsenceTimeDaysWithWorkWeeks(absenceTimes, start, end, ANZ_WOCHENTAGE); } public virtual decimal? GetFehlzeiten(IList records, DateTime monat) { return GetFehlzeiten(records, monat, monat.AddMonths(1)); } public virtual decimal? GetFehlzeiten(IList 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 feiertage = GetFeiertage(start.Year); foreach (var ft in feiertage) { if (start.Date == ft) return true; } return false; } public virtual List GetFeiertage(int year) { List list = new List(); 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 TageProWocheDict; public Dictionary RestStundenProWocheDict; } public class AbsenceTimeHours { public decimal StundenUrlaub; public decimal StundenKrankheit; public decimal StundenSonstiges; } public class ServiceRecordSummary { public decimal IstAbrechenbar { get; set; } public decimal IstNichtAbrechenbar { get; set; } public IList RecordsImBerichtszeitraum { get; set; } } }