using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Web.Mvc; using BeWoPlanerMobil.Models; using BeWoPlanerMobil.Service; using BeWoPlanerMobil.Util; using BS.Shared; using BS.Shared.DataContracts; using BS.Shared.DataContracts.Compact; using BS.Shared.Extensions; using DevExpress.XtraScheduler; using DevExpress.XtraScheduler.Compatibility; using Newtonsoft.Json; using static BeWoPlanerMobil.Util.MobileUtils; using RecurrenceInformation = BS.Shared.Core.RecurrenceInformation; namespace BeWoPlanerMobil.Controllers { public class SchedulerController : AbstractBaseController { private SchedulerModel _Model; public SchedulerModel Model { get { if (!MobileSessionFacade.IsUserLoggedIn()) { Logout(); return null; } if (_Model == null) { _Model = new SchedulerModel(); InitModel(_Model); InitViewModel(); } //if (((SchedulerModel) Session[ModelSessionConstants.SchedulerModelKey])?.LoggedInEmployee is null) //{ // _Model = new SchedulerModel(); // InitModel(_Model); // Session[ModelSessionConstants.SchedulerModelKey] = _Model; //} //else //{ // _Model = (SchedulerModel) Session[ModelSessionConstants.SchedulerModelKey]; //} return _Model; } } private void InitViewModel() { if (Model.HasRightToInsertRessourceAppointments || Model.HasRightToViewAllResourceAppointments) { var allResources = KalenderService.GetAllResources().OrderBy(r => r.Name).ToList(); var categories2Resources = new Dictionary>(); foreach (var category in allResources.Select(resource => resource.ResourceCategory)) { categories2Resources.AddOrUpdateValueInDictionary(category, allResources.Where(resource => resource.ResourceCategory.Equals(category)).OrderBy(r => r.Name).ToList()); } Model.ResourceCategories2Resources = categories2Resources.OrderBy(kvp => kvp.Key.DisplayName).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); } if (Model?.LoggedInEmployee?.EmployeeOid.HasValue ?? false) { var compactEmployee = EmployeeService.GetActiveCompactEmployeeWithOid(Model.LoggedInEmployee.EmployeeOid.Value); Model.MyTeamEmployees = EmployeeService.GetAllTeamMember(compactEmployee).OrderBy(employee => employee.LastName).ToList(); } else if (!(Model is null)) { Model.MyTeamEmployees = new List(); } if (Model.HasRightToViewTeams && (Model?.LoggedInEmployee?.EmployeeOid.HasValue ?? false)) { Model.MyTeams = EmployeeService.GetAllActiveCompactTeamsForEmployee(Model.LoggedInEmployee.EmployeeOid.Value).OrderBy(team => team.Name).ToList(); } if (!(Model is null)) { Model.TeamMemberCustomerOids = EmployeeService.LoadTeamsRelatedCustomerOids(LoggedInUser.Employee.EmployeeOid); } if (Model.HasRightToViewCustomerSelectionInScheduler) { Model.AllCustomers = CustomerService.GetAllActiveCompactCustomers().OrderBy(customer => customer.LastName).ToList(); } if (Model.HasRightToViewEmployeeAppointments) { Model.AllEmployees = EmployeeService.GetAllActiveEmployeesCompact().OrderBy(employee => employee.LastName).ToList(); } //LoadAppointmentsForDate(); if (Model.SelectedAppointmentOid.HasValue) { if (Model.Appointments == null) { LoadAppointmentsForDate(); } Model.SelectedAppointment = Model.Appointments.FirstOrDefault(app => app.SchedulerAppointmentOid.HasValue && app.SchedulerAppointmentOid.Value == Model.SelectedAppointmentOid.Value); } SetHasResourcesEmployeesOrCustomers(); UpdateSelectedObjects(); } private void UpdateSelectedObjects() { //mache aus dem Ressourcenkategorien Dictionary eine flache Liste: var list = new List(); Model.ResourceCategories2Resources.Values.DoForEach(l => l.DoForEach(s => list.AddIfNotIn(s))); Model.SelectedEmployees = Model.AllEmployees.Where(employee => Model.SelectedEmployeeOids.Contains(employee.EmployeeOid)).ToList(); Model.SelectedCustomers = Model.AllCustomers.Where(customer => Model.SelectedCustomerOids.Contains(customer.CustomerOid)).ToList(); Model.SelectedResources = list.Where(resource => resource.ResourceOid.HasValue && Model.SelectedResourceOids.Contains(resource.ResourceOid.Value)).ToList(); Model.SelectedEmployeesForFiltering = Model.AllEmployees.Where(employee => Model.SelectedEmployeeOidsForFiltering.Contains(employee.EmployeeOid)).ToList(); Model.SelectedCustomersForFiltering = Model.AllCustomers.Where(customer => Model.SelectedCustomerOidsForFiltering.Contains(customer.CustomerOid)).ToList(); Model.SelectedResourcesForFiltering = list.Where(resource => resource.ResourceOid.HasValue && Model.SelectedResourceOidsForFiltering.Contains(resource.ResourceOid.Value)).ToList(); Model.SelectedEmployeesForIntervalFinder = Model.AllEmployees.Where(employee => Model.SelectedEmployeeOidsForIntervalFinder.Contains(employee.EmployeeOid)).ToList(); Model.SelectedCustomersForIntervalFinder = Model.AllCustomers.Where(customer => Model.SelectedCustomerOidsForIntervalFinder.Contains(customer.CustomerOid)).ToList(); Model.SelectedResourcesForIntervalFinder = list.Where(resource => resource.ResourceOid.HasValue && Model.SelectedResourceOidsForIntervalFinder.Contains(resource.ResourceOid.Value)).ToList(); } // ToDo: Überarbeiten? Es kam das Ansehen hinzu private void SetHasResourcesEmployeesOrCustomers() { var isOwnAppointment = !Model.IsInEditMode || Model.SelectedAppointment?.Originator.EmployeeOid == LoggedInEmployee.EmployeeOid; var v1 = Model.HasRightToInsertEmployeeAppointments || Model.IsInEditMode && Model.HasRightToEditEmployeeAppointments; var v2 = Model.HasRightToInsertRessourceAppointments || Model.IsInEditMode && Model.HasRightToEditResourceAppointments; if (Model.IsInEditMode && !isOwnAppointment) { v2 = Model.HasRightToEditOthersResourceAppointments; } var v3 = Model.HasRightToInsertCustomerAppointments || Model.IsInEditMode && Model.HasRightToEditCustomerAppointments; Model.HasResourcesEmployeesOrCustomers = v1 || v2 || v3; } [Authorize] public ActionResult Scheduler() { if(!MobileSessionFacade.IsUserLoggedIn() || Request.Browser.Browser.Equals("InternetExplorer") || !Model.IsAllowedToSeeScheduler) { return Logout(); } return View(Model); } private void LoadAppointmentsForDate() { if(Model?.LoggedInEmployee.EmployeeOid is null) { return; } var date = Model.SelectedDate; var monday = date.GetInSameCalendarWeek(DayOfWeek.Monday); var sunday = monday.Date.AddDays(6); var start = date; var end = date.AddDays(1); if(Model.SelectedSchedulerView == "5") { start = monday; end = monday.AddDays(4); } else if(Model.SelectedSchedulerView == "7") { start = monday; end = sunday; } var selectedCustomers = Model.SelectedCustomerOidsForFiltering; var selectedEmployees = Model.SelectedEmployeeOidsForFiltering.Clone(); //Wird soinst im KalenderService geändert var selectedResources = Model.SelectedResourceOidsForFiltering; var appointments = KalenderService.LoadFilteredAppointmentsMitAufgaben(Model.HasRightToViewEmployeeAppointments, Model.LoggedInEmployee.EmployeeOid.Value, start.Date, end, selectedEmployees, selectedCustomers, selectedResources, false, false, false, false, true, true).ToList(); // Private Termine foreach(var appointment in appointments.Where(a => a.IsPrivate)) { if(appointment.Originator.Equals(LoggedInUser.Employee) || appointment.EmployeeList.Any(e2a => e2a.Employee.Equals(LoggedInUser.Employee))) { continue; } appointment.CanBeEdited = false; appointment.Description = "Privater Termin"; appointment.Subject = $"Privat ({appointment.Originator})"; } // Unerledigte Aufgaben var tasks = appointments.Where(w => w.IsTask && w.CompletedDate is null).ToList(); // Nur eigene Kliententermine ansehen if(!Model.HasRightToViewCustomerAppointments) { appointments = appointments.Where(a => a.CustomerList.All(c => LoggedInEmployee.RelatedCustomers.Any(rc => rc.Customer.Equals(c)))).ToList(); } if(!Model.HasRightToViewAllResourceAppointments) { appointments = appointments.Where(a => a.ResourceList.Count == 0).ToList(); } if(!Model.IsAllowedToSeeCustomers) { appointments = appointments.Where(a => a.CustomerList.Count == 0).ToList(); } // Wenn es ein ganztägiger Termin ist, eine Sekunde abziehen und beim Speichern wieder draufaddieren? foreach(var app in appointments.Where(a => a.AllDay)) { if(app.EndDate is null) { continue; } app.EndDate = app.EndDate.Value.AddMinutes(-1); } var holySweetFlyingFuck = appointments.Where(w => w.IsTask == false && // Aufgaben ausschließen w.StartDate.HasValue && w.EndDate.HasValue && // Datumsangaben haben einen Wert (date.InBetween(w.StartDate.Value, w.EndDate.Value, false) || date.CompareShortDates(w.StartDate.Value)) // Einzeltermine oder Ausnahmen und gelöschte Ausnahmen && (w.RecurrenceInfo is null || w.RecurrenceInfo != null && (w.Type == 3 || w.Type == 4)) ).ToList(); var deletedOccurrences = holySweetFlyingFuck.Where(w => w.Type == 4).Select(s => BS.Shared.Core.Utils.GetOccurrenceId(s.RecurrenceInfo)).ToList(); var changedOccurrences = holySweetFlyingFuck.Where(w => w.Type == 3).Select(s => BS.Shared.Core.Utils.GetOccurrenceId(s.RecurrenceInfo)).ToList(); holySweetFlyingFuck = holySweetFlyingFuck.Where(w => w.Type != 4).ToList(); holySweetFlyingFuck.AddRangeIfElementsNotIn(CalculateRecurrences(appointments, start, end, changedOccurrences, deletedOccurrences)); holySweetFlyingFuck.AddRange(tasks); Model.Appointments = Model.ShouldLoadTasks ? holySweetFlyingFuck.OrderByDescending(appointment => appointment.IsTask).ThenBy(appointment => appointment.StartDate).ToList() : holySweetFlyingFuck.Where(w => w.IsTask is false).OrderBy(appointment => appointment.StartDate).ToList(); UpdateAppointmentListItems(); Model.WeekViewObject = new WeekViewObject(Model.Appointments, Model.SelectedDate.GetInSameCalendarWeek(DayOfWeek.Monday), Model.LoggedInEmployee); } private void UpdateAppointmentListItems() { var md5 = new MD5CryptoServiceProvider(); var list = new List(); foreach (var appointment in Model.Appointments) { String key = String.Format("{0}_{1}", appointment.SchedulerAppointmentOid, appointment.RecurrenceInfo); String id = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(key))).Replace("-", "").ToLower(); var listItem = new AppointmentListItem(id, appointment); list.Add(listItem); } Model.AppointmentListItems = list; } private static IEnumerable CalculateRecurrences(IEnumerable appointments, DateTime start, DateTime end, IReadOnlyCollection changedOccurrences, IReadOnlyCollection deletedOccurrences) { var result = new List(); var interval = new TimeInterval(start, end); foreach (var appointment in appointments.Where(app => app.RecurrenceInfo != null && app.Type == 1)) { var recurrenceInfo = new RecurrenceInfo(); recurrenceInfo.FromXml(appointment.RecurrenceInfo); var occurrenceCalculator = OccurrenceCalculator.CreateInstance(recurrenceInfo); var pattern = StaticAppointmentFactory.CreateAppointment(AppointmentType.Pattern); pattern.RecurrenceInfo.FromXml(appointment.RecurrenceInfo); pattern.Start = pattern.RecurrenceInfo.Start; pattern.End = pattern.RecurrenceInfo.End; var patternId = pattern.RecurrenceInfo.Id.ToString(); var occurrences = occurrenceCalculator.CalcOccurrences(interval, pattern); if(occurrences.Count > 0) { foreach(var app in occurrences.GetAppointments(interval)) { var index = app.RecurrenceIndex; var duration = (appointment.EndDate.Value - appointment.StartDate.Value).TotalMinutes; var isOutOfInterval = app.Start.GetShortDateTime().AreInBetweenDates(app.Start.AddMinutes(duration), start, end) == false; var isChangedOccurrence = changedOccurrences.Any(a => a.PatternId.Equals(patternId) && a.Index == index); var isDeletedOccurrence = deletedOccurrences.Any(a => a.PatternId.Equals(patternId) && a.Index == index); if(isOutOfInterval || isChangedOccurrence || isDeletedOccurrence) { continue; } var recurringAppointment = new SchedulerAppointmentDC { AllDay = appointment.AllDay, CustomerList = appointment.CustomerList, Description = appointment.Description?.RemoveUppercaseEsszett(), EmployeeList = appointment.EmployeeList, EndDate = app.Start.AddMinutes(duration), FormerBookingSequenceOid = appointment.FormerBookingSequenceOid, IsPrivate = appointment.IsPrivate, LabelKey = appointment.LabelKey, Location = appointment.Location?.RemoveUppercaseEsszett(), Originator = appointment.Originator, RecurrenceInfo = app.RecurrenceInfo.ToXml(), RecurrenceIndex = index, ReminderInfo = appointment.ReminderInfo, ResourceList = appointment.ResourceList, StartDate = app.Start, Subject = appointment.Subject?.RemoveUppercaseEsszett() ?? "", Type = (int) app.Type, ServiceRecordList = appointment.ServiceRecordList, SupportConceptList = appointment.SupportConceptList }; result.AddIfNotIn(recurringAppointment); } } } // Es wird bei ganztägigen Serienterminen eine Minute abgezogen, damit die nicht als zweitägig angezeigt werden. Bearbeiten kann man Serientermin im MoK noch nicht. foreach(var app in result.Where(w => w.AllDay && w.EndDate.HasValue)) { app.EndDate = app.EndDate.Value.AddMinutes(-1); } return result; } [Authorize] [HttpPost] public ActionResult InsertOrUpdateAppointment(FormCollection formCollection) { try { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } var rawStartDate = formCollection[FormCollectionConstants.AppointmentStartDateKey]; var rawEndDate = formCollection[FormCollectionConstants.AppointmentEndDateKey]; var subject = formCollection[FormCollectionConstants.AppointmentSubjectKey] ?? string.Empty; var location = formCollection[FormCollectionConstants.AppointmentLocationKey] ?? string.Empty; var notice = formCollection[FormCollectionConstants.AppointmentNoticeKey] ?? string.Empty; subject = subject.RemoveUppercaseEsszett(); location = location.RemoveUppercaseEsszett(); notice = notice.RemoveUppercaseEsszett(); var isPrivate = formCollection[FormCollectionConstants.AppointmentIsPrivateKey] == "on"; var allDay = formCollection[FormCollectionConstants.AppointmentIsAllDayKey] == "on"; var startAndEnd = ConvertStringDatesToDateTimes(rawStartDate, rawEndDate); var startDate = startAndEnd.StartDate; var endDate = startAndEnd.EndDate; var appointmentToInsert = Model.SelectedAppointment ?? new SchedulerAppointmentDC(); var isNew = !appointmentToInsert.SchedulerAppointmentOid.HasValue; var appointmentEmployeeList = new List(); if(Model.SelectedEmployees?.Any() ?? false) { foreach(var employee in Model.SelectedEmployees) { var employee2Appointment = new Employee2SchedulerAppointmentDC { Employee = employee, }; appointmentEmployeeList.Add(employee2Appointment); } } if(allDay) { startDate = startDate.Date; endDate = endDate.AddDays(1); } appointmentToInsert.EmployeeList = appointmentEmployeeList; appointmentToInsert.CustomerList = Model.SelectedCustomers; appointmentToInsert.ResourceList = Model.SelectedResources ?? new List(); appointmentToInsert.SupportConceptList = isNew ? new List() : appointmentToInsert.SupportConceptList; appointmentToInsert.ServiceRecordList = isNew ? new List() : appointmentToInsert.ServiceRecordList; appointmentToInsert.EndDate = endDate; appointmentToInsert.StartDate = startDate; appointmentToInsert.Subject = subject; appointmentToInsert.Description = notice; appointmentToInsert.Originator = LoggedInUser.Employee; appointmentToInsert.Location = location; appointmentToInsert.ActivationType = ActivationTypeId.Active; appointmentToInsert.IsPrivate = isPrivate; appointmentToInsert.AllDay = allDay; // Eine Minute addieren, wenn die Uhrzeit eines ganztägigen Termins nicht exakt 00:00 ist. // ToDo: Wird beim SelectAppointmentToEdit gemacht, damit die Formularanzeige korrekt ist! if(allDay && endDate.Hour == 23 && endDate.Minute == 59) { appointmentToInsert.EndDate = endDate.AddMinutes(1); } // ToDo: Rechte beachten! if(appointmentToInsert.CanBeEdited) { if(!isNew) { KalenderService.UpdateSchedulerAppointments(new List {appointmentToInsert}); } else { KalenderService.InsertSchedulerAppointments(new List {appointmentToInsert}); } } } catch(Exception exception) { Log.Error(exception.Message, exception); } finally { if(Model != null) { Model.IsAllDay = false; Model.SelectedAppointmentOid = null; Model.SelectedResourceOids?.Clear(); Model.SelectedCustomerOids?.Clear(); Model.SelectedEmployeeOids?.Clear(); } } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult NavigateToPreviousDate() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } Model.SelectedDate = Model.SelectedDate.AddDays(-1); if(Model != null) { Model.SelectedAppointmentOid = null; //Model.SelectedResources.Clear(); } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult NavigateToNextDate() { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } Model.SelectedDate = Model.SelectedDate.AddDays(1); if(!(Model is null)) { Model.SelectedAppointmentOid = null; //Model.SelectedResources.Clear(); } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult SelectSchedulerDate(FormCollection formCollection) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } var rawSchedulerDate = formCollection[FormCollectionConstants.AppointmentSchedulerDateKey]; var schedulerDate = DateTime.ParseExact(rawSchedulerDate, "dd.MM.yyyy", null); Model.SelectedDate = schedulerDate; Model.SelectedAppointmentOid = null; Model.SelectedResourceOids.Clear(); return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult SelectAppointmentToEdit(FormCollection formCollection) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; #if DEBUG TempData[TempDataConstants.ErrorMessageKey] = "Model war null"; #endif return Logout(); } var rawOid = formCollection[FormCollectionConstants.AppointmentSchedulerOidHolderKey]; var isSuccessful = long.TryParse(rawOid, out var appointmentOid); if(!isSuccessful) { return RedirectToActionPermanent("Scheduler"); } LoadAppointmentsForDate(); Model.SelectedAppointmentOid = appointmentOid; Model.SelectedAppointment = Model.Appointments.FirstOrDefault(app => app.SchedulerAppointmentOid.HasValue && app.SchedulerAppointmentOid.Value == appointmentOid); if (Model.SelectedAppointment != null) { if(Model.SelectedAppointment.AllDay && Model.SelectedAppointment.EndDate.HasValue) { Model.SelectedAppointment.EndDate = Model.SelectedAppointment.EndDate.Value.AddMinutes(1).AddDays(-1); } Model.IsAllDay = Model.SelectedAppointment.AllDay; Model.IsPrivate = Model.SelectedAppointment.IsPrivate; Model.SelectedResourceOids = Model.SelectedAppointment?.ResourceList.Select(r => r.ResourceOid.Value).ToList() ?? new List(); Model.SelectedEmployeeOids = Model.SelectedAppointment?.EmployeeList.Select(e2a => e2a.Employee.EmployeeOid).ToList() ?? new List(); Model.SelectedCustomerOids = Model.SelectedAppointment?.CustomerList.Select(c => c.CustomerOid).ToList() ?? new List(); } return RedirectToActionPermanent("Scheduler"); } [Authorize] public JsonResult ResetSelectedAppointment() { if(Model != null) { Model.SelectedAppointmentOid = null; Model.SelectedResourceOids.Clear(); Model.SelectedEmployeeOids.Clear(); Model.SelectedCustomerOids.Clear(); Model.IsAllDay = false; Model.IsPrivate = false; } UpdateSelectedObjects(); return Json(null, JsonRequestBehavior.AllowGet); } [Authorize] public JsonResult CheckForOverlappingAppointments(string startDateRaw, string endDateRaw, string startTimeRaw, string endTimeRaw) { if (Model is null) { Logout(); return null; } var isOverlapping = false; var oid = Model.SelectedAppointmentOid; var isSuccessfulStartDate = DateTime.TryParseExact(startDateRaw, "dd.MM.yyyy", null, DateTimeStyles.None, out var startDate); var isSuccessfulStartTime = DateTime.TryParseExact(startTimeRaw, "HH:mm", null, DateTimeStyles.None, out var startTime); var isSuccessfulEndDate = DateTime.TryParseExact(endDateRaw, "dd.MM.yyyy", null, DateTimeStyles.None, out var endDate); var isSuccessfulEndTime = DateTime.TryParseExact(endTimeRaw, "HH:mm", null, DateTimeStyles.None, out var endTime); if (isSuccessfulStartDate && isSuccessfulStartTime && isSuccessfulEndDate && isSuccessfulEndTime) { startDate = startDate.MergeDatesByDate(startTime); endDate = endDate.MergeDatesByDate(endTime); var customerOidList = Model.SelectedAppointment?.CustomerList?.Select(customer => customer.CustomerOid).ToList() ?? new List(); var employeeOidList = Model.SelectedAppointment?.EmployeeList?.Select(employee2Appointment => employee2Appointment.Employee.EmployeeOid).ToList() ?? new List(); var resourceOidList = Model.SelectedResources.Where(resource => resource.ResourceOid.HasValue).Select(resource => resource.ResourceOid.Value).ToList() ?? new List(); var originator = Model.SelectedAppointment?.Originator ?? LoggedInUser.Employee; var recurrenceId = Model.SelectedAppointment?.RecurrenceId ?? string.Empty; var recurrenceIndex = Model.SelectedAppointment?.RecurrenceIndex ?? 0; isOverlapping = KalenderService.OverlappingAppointmentsExist(startDate, endDate, employeeOidList, customerOidList, resourceOidList, originator.EmployeeOid, oid, recurrenceId, recurrenceIndex); // TODO: Serientermine überprüfen if(Model.Appointments != null) { foreach(var appointment in Model.Appointments.Where(app => app.SchedulerAppointmentOid is null && app.IsTask == false)) { } } } return Json(isOverlapping, JsonRequestBehavior.AllowGet); } [Authorize] public string CheckResourcesAvailability(string start, string end, string resourceOids, bool allDay) { if(string.IsNullOrWhiteSpace(start) || string.IsNullOrWhiteSpace(end) || string.IsNullOrWhiteSpace(resourceOids) || Model is null) { return LeerzeichenFuerGetMethoden; } if(!Model.HasRightToInsertRessourceAppointments) { return "Fehler! Sie haben nicht das Recht, Termine mit Ressourcen anzulegen!"; } var oidList = ConvertOidStringToList(resourceOids); foreach(var oid in oidList) { if(!Model.ResourceCategories2Resources.Any(a => a.Value.All(b => b.ResourceOid != oid))) { return LeerzeichenFuerGetMethoden; } } var dateTimes = ConvertStringDatesToDateTimes(start, end); if(allDay) { dateTimes.EndDate = dateTimes.EndDate.AddDays(1); } var info = KalenderService.CheckResourceAvailabilityWithEmployeeInformation(dateTimes.StartDate, dateTimes.EndDate, oidList, Model.SelectedAppointmentOid, null); var result = string.Empty; foreach(var kvp in info) { result += $"Die Ressource \"{kvp.Key}\" ist im ausgewählten Zeitraum {start} bis {end} bereits gebucht"; if(!kvp.Value.All(string.IsNullOrWhiteSpace)) { result += ":

"; } foreach(var interval in kvp.Value) { result += $"{interval}
"; } } return result; } [Authorize] public string HasSelectedAppointment() { return JsonConvert.SerializeObject(Model?.SelectedAppointmentOid.HasValue); } [Authorize] [HttpPost] public ActionResult ChangeSchedulerView(FormCollection formCollection) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } var selectedSchedulerView = formCollection["SelectedSchedulerView"]; Model.SelectedSchedulerView = selectedSchedulerView; return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult FindFreeIntervals(FormCollection formCollection) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } var durationString = formCollection["Duration"]; var intervalStartDateString = formCollection["IntervalStart"].Substring(0, 10); var intervalStartTimeString = formCollection["IntervalStartTime"]; var intervalEndDateString = formCollection["IntervalEnd"].Substring(0, 10); var intervalEndTimeString = formCollection["IntervalEndTime"]; if(int.TryParse(durationString, out var intervalDuration) && DateTime.TryParse($"{intervalStartDateString} {intervalStartTimeString}", out var intervalStart) && DateTime.TryParse($"{intervalEndDateString} {intervalEndTimeString}", out var intervalEnd) && Model.LoggedInEmployee.EmployeeOid.HasValue) { var customerOids = Model.SelectedCustomerOidsForIntervalFinder.Clone(); var employeeOids = Model.SelectedEmployeeOidsForIntervalFinder.Clone(); var resourceOids = Model.SelectedResourceOidsForIntervalFinder.Clone(); Model.FreeIntervals = KalenderService.FindAppointmentsInRangeForIntervalFinder(intervalDuration, intervalStart, intervalEnd, resourceOids, customerOids, employeeOids, Model.LoggedInEmployee.EmployeeOid.Value); Model.IntervalStartDate = intervalStart; Model.IntervalEndDate = intervalEnd; Model.IntervalDuration = intervalDuration; } return RedirectToActionPermanent("Scheduler"); } [Authorize] public string SelectEmployeesForIntervalFinder(string oidString) { if (Model is null) { Logout(); return LeerzeichenFuerGetMethoden; } Model.SelectedEmployeeOidsForIntervalFinder = ConvertOidStringToList(oidString); UpdateSelectedObjects(); return JsonConvert.SerializeObject(Model.SelectedEmployeesForIntervalFinder.OrderBy(o => o.DetailDescription)); } [Authorize] public string SelectCustomersForIntervalFinder(string oidString) { if (Model is null) { Logout(); return LeerzeichenFuerGetMethoden; } Model.SelectedCustomerOidsForIntervalFinder = ConvertOidStringToList(oidString); UpdateSelectedObjects(); return JsonConvert.SerializeObject(Model.SelectedCustomersForIntervalFinder.OrderBy(o => o.LastNameFirstName)); } [Authorize] public string SelectResourcesForIntervalFinder(string resourceOids) { if(Model is null) { Logout(); return LeerzeichenFuerGetMethoden; } Model.SelectedResourceOidsForIntervalFinder = ConvertOidStringToList(resourceOids); UpdateSelectedObjects(); return JsonConvert.SerializeObject(Model.SelectedResourcesForIntervalFinder); } [Authorize] [HttpPost] public ActionResult SetIsInIntervalFinderMode(FormCollection formCollection) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } var newValue = !Model.IsInIntervalFinderMode; Model.IsInIntervalFinderMode = newValue; if(!newValue) { Model.SelectedEmployeeOidsForIntervalFinder.Clear(); Model.SelectedCustomerOidsForIntervalFinder.Clear(); Model.SelectedResourceOidsForIntervalFinder.Clear(); } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult SelectIntervalForForm(FormCollection formCollection) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } var startStr = formCollection["startDate"]; var endStr = formCollection["endDate"]; if(DateTime.TryParse(startStr, out var startDate) && DateTime.TryParse(endStr, out var endDate)) { Model.IsInIntervalFinderMode = false; var employees2Appointment = new List(); Model.SelectedEmployeesForIntervalFinder.DoForEach(employee => { employees2Appointment.Add(new Employee2SchedulerAppointmentDC { Employee = employee }); }); Model.SelectedAppointment = new SchedulerAppointmentDC() { ActivationType = ActivationTypeId.Active, IsTask = false, IsPrivate = false, Originator = LoggedInUser.Employee, StartDate = startDate, EndDate = endDate }; Model.SelectedCustomerOids = Model.SelectedCustomerOidsForIntervalFinder.Clone(); Model.SelectedEmployeeOids = Model.SelectedEmployeeOidsForIntervalFinder.Clone(); Model.SelectedResourceOids = Model.SelectedResourceOidsForIntervalFinder.Clone(); Model.SelectedCustomerOidsForIntervalFinder.Clear(); Model.SelectedEmployeeOidsForIntervalFinder.Clear(); Model.SelectedResourceOidsForIntervalFinder.Clear(); Model.IntervalStartDate = null; Model.IntervalEndDate = null; } return RedirectToActionPermanent("Scheduler"); } [Authorize] public string ResetIntervalFinder() { if(Model is null) { return LeerzeichenFuerGetMethoden; } Model.SelectedCustomerOidsForIntervalFinder.Clear(); Model.SelectedEmployeeOidsForIntervalFinder.Clear(); Model.SelectedResourceOidsForIntervalFinder.Clear(); Model.SelectedCustomersForIntervalFinder.Clear(); Model.SelectedEmployeesForIntervalFinder.Clear(); Model.SelectedResourcesForIntervalFinder.Clear(); return LeerzeichenFuerGetMethoden; } [Authorize] public ActionResult FetchAppointments() { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("OneDaySchedulerPartial"); } LoadAppointmentsForDate(); return PartialView("OneDaySchedulerPartial", Model); } [Authorize] public string SelectResourcesForAppointmentFiltering(string resourceOids) { if(Model is null) { Logout(); return LeerzeichenFuerGetMethoden; } var oidList = ConvertOidStringToList(resourceOids); var list = new List(); Model.ResourceCategories2Resources.Values.DoForEach(l => l.DoForEach(s => list.AddIfNotIn(s))); Model.SelectedResourcesForFiltering = list.Where(resource => resource.ResourceOid.HasValue && oidList.Contains(resource.ResourceOid.Value)).ToList(); Model.SelectedResourceOidsForFiltering = oidList; return JsonConvert.SerializeObject(Model.SelectedResourcesForFiltering); } [Authorize] public string SelectEmployeesForAppointmentFiltering(string oidString) { if(Model is null) { Logout(); return LeerzeichenFuerGetMethoden; } Model.SelectedEmployeeOidsForFiltering = ConvertOidStringToList(oidString); return Model.SelectedEmployeeOidsForFiltering.Count.ToString(); } [Authorize] public string SelectCustomersForAppointmentFiltering(string oidString) { if(Model is null) { Logout(); return LeerzeichenFuerGetMethoden; } Model.SelectedCustomerOidsForFiltering = ConvertOidStringToList(oidString); return Model.SelectedCustomerOidsForFiltering.Count.ToString(); } [Authorize] public ActionResult FetchSelectedEmployeesForPopup() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; } return PartialView("EmployeeForFilteringPartial", Model); } [Authorize] public ActionResult FetchEmployeeFilteringModalBody() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; } return PartialView("EmployeeFilteringModalContentPartial", Model); } [Authorize] public string SelectTeamForFiltering(string teamOidString) { if(Model?.LoggedInEmployee?.EmployeeOid is null) { Logout(); return LeerzeichenFuerGetMethoden; } if(long.TryParse(teamOidString, out var teamOid)) { var team = EmployeeService.FindTeamByOid(teamOid, Model.LoggedInEmployee.EmployeeOid.Value); if(!(team is null)) { Model.SelectedEmployeeOidsForFiltering.AddRangeIfElementsNotIn(team.Member.Select(m => m.EmployeeOid)); } } UpdateSelectedObjects(); return LeerzeichenFuerGetMethoden; } #region Mitarbeiterauswahl [Authorize] public string SelectTeamForAppointment(string teamOidString) { if(Model?.LoggedInEmployee?.EmployeeOid is null) { TempData[TempDataConstants.DoLogoutKey] = true; return LeerzeichenFuerGetMethoden; } var teamMemberOids = new List(); if(!long.TryParse(teamOidString, out var teamOid)) { return LeerzeichenFuerGetMethoden; } var team = EmployeeService.FindTeamByOid(teamOid, Model.LoggedInEmployee.EmployeeOid.Value); if(team is null) { return LeerzeichenFuerGetMethoden; } Model.SelectedEmployeeOids.AddRangeIfElementsNotIn(team.Member.Select(m => m.EmployeeOid)); UpdateSelectedObjects(); return LeerzeichenFuerGetMethoden; } [Authorize] public ActionResult UpdateEmployeeSelection(string oidString) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; Logout(); return PartialView("SchedulerEmployeeSelectionPartial"); } Model.SelectedEmployeeOids = ConvertOidStringToList(oidString); UpdateSelectedObjects(); return PartialView("SchedulerEmployeeSelectionPartial", Model); } [Authorize] public ActionResult SelectAllEmployees(bool isChecked) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("EmployeeSelectionPopupListPartial"); } Model.SelectedEmployeeOids = isChecked ? Model.AllEmployees.Select(r => r.EmployeeOid).ToList() : new List(); UpdateSelectedObjects(); return PartialView("EmployeeSelectionPopupListPartial", Model); } [Authorize] public ActionResult LoadUpdatedEmployees() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("SchedulerEmployeeSelectionPartial"); } return PartialView("SchedulerEmployeeSelectionPartial", Model); } [Authorize] public ActionResult LoadUpdatedEmployeePopupList() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("EmployeeSelectionPopupListPartial"); } return PartialView("EmployeeSelectionPopupListPartial", Model); } #endregion #region Klientenauswahl [Authorize] public ActionResult SelectAllCustomers(bool isChecked) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; Logout(); return PartialView("CustomerSelectionPopupListPartial"); } Model.SelectedCustomerOids = isChecked ? Model.AllCustomers.Select(r => r.CustomerOid).ToList() : new List(); UpdateSelectedObjects(); return PartialView("CustomerSelectionPopupListPartial", Model); } [Authorize] public ActionResult LoadUpdatedCustomers() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("SchedulerCustomerSelectionPartial"); } return PartialView("SchedulerCustomerSelectionPartial", Model); } [Authorize] public ActionResult LoadUpdatedCustomerPopupList() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("CustomerSelectionPopupListPartial"); } return PartialView("CustomerSelectionPopupListPartial", Model); } [Authorize] public ActionResult UpdateCustomerSelection(string oidString) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; Logout(); return PartialView("SchedulerCustomerSelectionPartial"); } Model.SelectedCustomerOids = ConvertOidStringToList(oidString); UpdateSelectedObjects(); return PartialView("SchedulerCustomerSelectionPartial", Model); } #endregion #region Ressourcenauswahl [Authorize] public ActionResult UpdateResourceSelection(string oidString) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("SchedulerResourceSelectionPartial"); } //var list = new List(); //Model.ResourceCategories2Resources.Values.DoForEach(l => l.DoForEach(s => list.AddIfNotIn(s))); //Model.SelectedResources = list.Where(resource => resource.ResourceOid.HasValue && oidList.Contains(resource.ResourceOid.Value)).ToList(); Model.SelectedResourceOids = ConvertOidStringToList(oidString); UpdateSelectedObjects(); return PartialView("SchedulerResourceSelectionPartial", Model); } [Authorize] public ActionResult SelectAllResources(bool isChecked) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("ResourceSelectionPopupListPartial"); } Model.SelectedResourceOids = isChecked ? Model.AllResources.Select(r => r.ResourceOid.Value).ToList() : new List(); UpdateSelectedObjects(); return PartialView("ResourceSelectionPopupListPartial", Model); } [Authorize] public ActionResult LoadUpdatedResourcePopupList() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("ResourceSelectionPopupListPartial"); } return PartialView("ResourceSelectionPopupListPartial", Model); } [Authorize] public ActionResult LoadUpdatedResources() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return PartialView("SchedulerResourceSelectionPartial"); } return PartialView("SchedulerResourceSelectionPartial", Model); } #endregion [Authorize] public ActionResult FetchCustomersForFiltering() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; } return PartialView("CustomerFilterSelectionPartial", Model); } [Authorize] public ActionResult FetchCustomerFilteringModalBody() { if (Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; } return PartialView("CustomerFilteringModalContentPartial", Model); } [Authorize] public string SetShouldLoadTasks(bool isChecked) { try { if(Model is null) { Logout(); return LeerzeichenFuerGetMethoden; } Model.ShouldLoadTasks = isChecked; return LeerzeichenFuerGetMethoden; } catch(Exception exception) { Log.Error(exception.Message, exception); } return LeerzeichenFuerGetMethoden; } [Authorize] public string DeleteAppointment(string appointmentIdentifier, bool deleteSeries) { if(Model?.LoggedInEmployee?.EmployeeOid is null) { Logout(); return LeerzeichenFuerGetMethoden; } LoadAppointmentsForDate(); var schedulerAppointment = Model.AppointmentListItems.FirstOrDefault(app => app.Identifier.Equals(appointmentIdentifier))?.SchedulerAppointment; if(schedulerAppointment is null) { return LeerzeichenFuerGetMethoden; } if(schedulerAppointment.SchedulerAppointmentOid is null && !(schedulerAppointment.RecurrenceInfo is null)) { var recurrenceInfo = new RecurrenceInfo(); recurrenceInfo.FromXml(schedulerAppointment.RecurrenceInfo); var pattern = StaticAppointmentFactory.CreateAppointment(AppointmentType.Pattern); pattern.RecurrenceInfo.FromXml(schedulerAppointment.RecurrenceInfo); pattern.Start = pattern.RecurrenceInfo.Start; pattern.End = pattern.RecurrenceInfo.End; var exception = pattern.CreateException(AppointmentType.DeletedOccurrence, schedulerAppointment.RecurrenceIndex); var recurrenceId = exception.RecurrenceInfo.Id.ToString(); schedulerAppointment = deleteSeries ? KalenderService.FindRootAppointmentByRecurrenceId(recurrenceId) : CloneAppointment(schedulerAppointment, $"", (int)exception.Type); } if(schedulerAppointment is null) { return LeerzeichenFuerGetMethoden; } var teamMemberCustomerOids = EmployeeService.LoadTeamsRelatedCustomerOids(Model.LoggedInEmployee.EmployeeOid.Value); var customerList = schedulerAppointment.CustomerList; var employeeList = schedulerAppointment.EmployeeList; var resourceList = schedulerAppointment.ResourceList; var originator = schedulerAppointment.Originator; var isNew = schedulerAppointment.SchedulerAppointmentOid is null; var loggedOnUser = LoggedInUser; var isAllowedToDelete = BS.Shared.Core.Utils.CheckSchedulerRights(customerList, resourceList, employeeList, originator, isNew, SchedulerRightsCheckType.Edit, loggedOnUser, teamMemberCustomerOids); if(isAllowedToDelete) { if(schedulerAppointment.SchedulerAppointmentOid.HasValue && schedulerAppointment.NewSchedulerAppointmentVersion.HasValue) { var oid2Version = new Dictionary { { schedulerAppointment.SchedulerAppointmentOid.Value, schedulerAppointment.NewSchedulerAppointmentVersion.Value } }; KalenderService.DeactivateSchedulerAppointments(oid2Version); } // DeletedOccurrence if(schedulerAppointment.Type == 4 && !deleteSeries) { KalenderService.InsertSchedulerAppointments(new List { schedulerAppointment }); } } return LeerzeichenFuerGetMethoden; } [Authorize] public static SchedulerAppointmentDC CloneAppointment(SchedulerAppointmentDC schedulerAppointment, string recurrenceInfo, int type) { return new SchedulerAppointmentDC { StartDate = schedulerAppointment.StartDate, EndDate = schedulerAppointment.EndDate, ServiceRecordList = schedulerAppointment.ServiceRecordList ?? new List(), EmployeeList = schedulerAppointment.EmployeeList ?? new List(), ActivationType = ActivationTypeId.Active, AllDay = schedulerAppointment.AllDay, CanBeEdited = schedulerAppointment.CanBeEdited, CompletedDate = schedulerAppointment.CompletedDate, CompletedNotice = schedulerAppointment.CompletedNotice, CompletedUser = schedulerAppointment.CompletedUser, CustomerList = schedulerAppointment.CustomerList ?? new List(), Description = schedulerAppointment.Description?.RemoveUppercaseEsszett(), DueDate = schedulerAppointment.DueDate, FormerBookingSequenceOid = schedulerAppointment.FormerBookingSequenceOid, FormerTaskOid = schedulerAppointment.FormerTaskOid, HasServiceRecordEntry = schedulerAppointment.HasServiceRecordEntry, IsPrivate = schedulerAppointment.IsPrivate, IsTask = schedulerAppointment.IsTask, IsTeilnahmeBestaetigung = schedulerAppointment.IsTeilnahmeBestaetigung, LabelKey = schedulerAppointment.LabelKey, Location = schedulerAppointment.Location?.RemoveUppercaseEsszett(), Originator = schedulerAppointment.Originator, RecurrenceInfo = recurrenceInfo, ReminderInfo = schedulerAppointment.ReminderInfo, ResourceList = schedulerAppointment.ResourceList ?? new List(), Status = schedulerAppointment.Status, Subject = schedulerAppointment.Subject?.RemoveUppercaseEsszett() ?? string.Empty, SupportConceptList = schedulerAppointment.SupportConceptList ?? new List(), TaskDescription = schedulerAppointment.TaskDescription, Type = type }; } [Authorize] public string SelectTeamForIntervalFinder(string teamOidString) { if(Model?.LoggedInEmployee?.EmployeeOid is null) { Logout(); return LeerzeichenFuerGetMethoden; } if(long.TryParse(teamOidString, out var teamOid)) { var team = EmployeeService.FindTeamByOid(teamOid, Model.LoggedInEmployee.EmployeeOid.Value); if(!(team is null)) { var memberOids = team.Member.Select(member => member.EmployeeOid).ToList(); Model.SelectedEmployeeOidsForIntervalFinder.AddRangeIfElementsNotIn(memberOids); return JsonConvert.SerializeObject(memberOids); } } return LeerzeichenFuerGetMethoden; } [Authorize] [HttpPost] public ActionResult TransformAppointmentToServiceRecord(FormCollection formCollection) { if(Model is null) { TempData[TempDataConstants.DoLogoutKey] = true; return Logout(); } var identifier = formCollection[FormCollectionConstants.AppointmentIdInputKey]; if (Model.AppointmentListItems == null) { LoadAppointmentsForDate(); } var appointmentListItem = Model.AppointmentListItems.FirstOrDefault(f => f.Identifier.Equals(identifier)); if(appointmentListItem is null) { return RedirectToActionPermanent("PrepareServiceRecordInsert", "Main"); } var appointment = appointmentListItem.SchedulerAppointment; //var employeeOids = appointment.EmployeeList.Select(employee2Appointment => employee2Appointment.Employee.EmployeeOid).ToList(); //if(employeeOids.Count == 0) //{ // employeeOids.Add(appointment.Originator.EmployeeOid); //} TempData[TempDataConstants.AppointmentOidKey] = appointmentListItem.SchedulerAppointment?.SchedulerAppointmentOid; return RedirectToActionPermanent("PrepareServiceRecordInsert", "Main"); } [Authorize] public override string SaveCollapsibleStatus(bool isOpen, string identifier) { Model.Collapsibles2IsShown[identifier] = isOpen; return LeerzeichenFuerGetMethoden; } } }