using System; using System.Collections.Generic; using System.Globalization; using System.Linq; 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 (((SchedulerModel) Session[ModelSessionConstants.SchedulerModelKey])?.Employee == null) { _Model = new SchedulerModel { Employee = MobileSessionFacade.LoggedInEmployee }; Session[ModelSessionConstants.SchedulerModelKey] = _Model; } else { _Model = (SchedulerModel) Session[ModelSessionConstants.SchedulerModelKey]; } return _Model; } } [Authorize] public ActionResult Scheduler() { if (!MobileSessionFacade.IsUserLoggedIn() || Request.Browser.Browser.Equals("InternetExplorer") || !AbstractModel.IsAllowedToSeeScheduler) { return Logout(); } if(AbstractModel.HasRightToInsertRessourceAppointments) { var allResources = KalenderService.GetAllResources().ToList(); var categories2Resources = new Dictionary>(); foreach(var category in allResources.Select(resource => resource.ResourceCategory)) { categories2Resources.AddOrUpdateValueInDictionary(category, allResources.Where(resource => resource.ResourceCategory.Equals(category)).ToList()); } Model.ResourceCategories2Resources = categories2Resources; } LoadAppointmentsForDate(); return View(Model); } private void LoadAppointmentsForDate() { if(Model?.Employee.EmployeeOid == 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 appointments = KalenderService.LoadFilteredAppointmentsMitAufgaben(AbstractModel.HasRightToSeeAllEmployeeAppointments, Model.Employee.EmployeeOid.Value, start.Date, end, new List(), new List(), new List(), false, false, false, false, true, true).ToList(); var tasks = appointments.Where(w => w.IsTask).ToList(); var zuErledigen = tasks.Where(t => t.DueDate.HasValue && t.DueDate.Value.Date >= DateTime.Today && !t.CompletedDate.HasValue); // Nur eigene Kliententermine ansehen if(!AbstractModel.HasRightToSeeAllCustomerAppointments) { appointments = appointments.Where(a => a.CustomerList.All(c => MobileSessionFacade.LoggedInEmployee.RelatedCustomers.Any(rc => rc.Customer.Equals(c)))).ToList(); } if(!AbstractModel.HasRightToSeeAllResourceAppointments) { appointments = appointments.Where(a => a.ResourceList.Count == 0).ToList(); } if(!AbstractModel.IsAllowedToSeeCustomers) { appointments = appointments.Where(a => a.CustomerList.Count == 0).ToList(); } 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)) && (w.RecurrenceInfo == 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(zuErledigen); Model.Appointments = holySweetFlyingFuck.OrderBy(appointment => appointment.StartDate).ToList(); Model.WeekViewObject = new WeekViewObject(Model.Appointments, Model.SelectedDate.GetInSameCalendarWeek(DayOfWeek.Monday)); if(AbstractModel.HasRightToInsertEmployeeAppointments) { Model.AllCustomers = EmployeeService.GetActiveCompactCustomersForEmployee(Model.Employee.EmployeeOid).OrderBy(o => o.DetailDescription).ToList(); } if(AbstractModel.HasRightToInsertCustomerAppointments) { Model.AllEmployees = EmployeeService.GetActiveCompactEmployeesForEmployee(Model.Employee.EmployeeOid.Value).OrderBy(o => o.DetailDescription).ToList(); } } 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, EmployeeList = appointment.EmployeeList, EndDate = app.Start.AddMinutes(duration), FormerBookingSequenceOid = appointment.FormerBookingSequenceOid, IsPrivate = appointment.IsPrivate, LabelId = appointment.LabelId, Location = appointment.Location, Originator = appointment.Originator, RecurrenceInfo = app.RecurrenceInfo.ToXml(), ReminderInfo = appointment.ReminderInfo, ResourceList = appointment.ResourceList, StartDate = app.Start, Subject = appointment.Subject ?? "", Type = appointment.Type }; result.AddIfNotIn(recurringAppointment); } } } return result; } [Authorize] [HttpPost] public ActionResult InsertOrUpdateAppointment(FormCollection formCollection) { try { if (Model == null) { Logout(); } var rawStartDate = formCollection[FormCollectionConstants.AppointmentStartDateKey]; var rawEndDate = formCollection[FormCollectionConstants.AppointmentEndDateKey]; var rawStartTime = formCollection[FormCollectionConstants.AppointmentStartTimeKey]; var rawEndTime = formCollection[FormCollectionConstants.AppointmentEndTimeKey]; var subject = formCollection[FormCollectionConstants.AppointmentSubjectKey]; var location = formCollection[FormCollectionConstants.AppointmentLocationKey]; var notice = formCollection[FormCollectionConstants.AppointmentNoticeKey]; var isPrivate = formCollection[FormCollectionConstants.AppointmentIsPrivate] == "true,false"; var allDay = formCollection[FormCollectionConstants.AppointmentIsAllDay] == "true,false"; var isSuccessfulStartTime = DateTime.TryParseExact(rawStartTime, "HH:mm", null, DateTimeStyles.None, out var startTime); var isSuccessfulEndTime = DateTime.TryParseExact(rawEndTime, "HH:mm", null, DateTimeStyles.None, out var endTime); if(rawStartTime == null) { rawStartTime = "00:00"; } if (rawEndTime == null) { rawEndTime = "00:00"; } var startAndEnd = ConvertStringDatesToDateTimes($"{rawStartDate} {rawStartTime}", $"{rawEndDate} {rawEndTime}"); var startDate = startAndEnd.StartDate; var endDate = startAndEnd.EndDate; if (!allDay && isSuccessfulStartTime && isSuccessfulEndTime || allDay) { startDate = startDate.MergeDatesByDate(startTime); endDate = endDate.MergeDatesByDate(endTime); 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); } } appointmentToInsert.EmployeeList = appointmentEmployeeList; appointmentToInsert.CustomerList = Model.SelectedCustomers; appointmentToInsert.ResourceList = Model.SelectedResources ?? new List(); appointmentToInsert.SupportConceptList = isNew ? new List() : appointmentToInsert.SupportConceptList; appointmentToInsert.EndDate = endDate; appointmentToInsert.StartDate = startDate; appointmentToInsert.Subject = subject; appointmentToInsert.Description = notice; appointmentToInsert.Originator = MobileSessionFacade.LoggedInCompactEmployee; appointmentToInsert.Location = location; appointmentToInsert.ActivationType = ActivationTypeId.Active; appointmentToInsert.IsPrivate = isPrivate; appointmentToInsert.AllDay = allDay; 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.SelectedAppointment = null; Model.SelectedResources?.Clear(); } } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult NavigateToPreviousDate() { if (Model == null) { Logout(); } Model.SelectedDate = Model.SelectedDate.AddDays(-1); if(Model != null) { Model.SelectedAppointment = null; Model.SelectedResources.Clear(); } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult NavigateToNextDate() { if(Model == null) { Logout(); } Model.SelectedDate = Model.SelectedDate.AddDays(1); if(Model != null) { Model.SelectedAppointment = null; Model.SelectedResources.Clear(); } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult SelectSchedulerDate(FormCollection formCollection) { if (Model == null) { Logout(); } var rawSchedulerDate = formCollection[FormCollectionConstants.AppointmentSchedulerDateKey]; var schedulerDate = DateTime.ParseExact(rawSchedulerDate, "dd.MM.yyyy", null); Model.SelectedDate = schedulerDate; if(Model != null) { Model.SelectedAppointment = null; Model.SelectedResources.Clear(); } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult SelectAppointmentToEdit(FormCollection formCollection) { var rawOid = formCollection[FormCollectionConstants.AppointmentSchedulerOidHolderKey]; var isSuccessful = long.TryParse(rawOid, out var appointmentOid); if (isSuccessful) { Model.SelectedAppointment = Model.Appointments.FirstOrDefault(app => app.SchedulerAppointmentOid.HasValue && app.SchedulerAppointmentOid.Value == appointmentOid); if(Model.SelectedAppointment != null) { Model.IsAllDay = Model.SelectedAppointment.AllDay; Model.IsPrivate = Model.SelectedAppointment.IsPrivate; Model.SelectedResources = Model.SelectedAppointment?.ResourceList ?? new List(); Model.SelectedEmployees = Model.SelectedAppointment?.EmployeeList.Select(e2a => e2a.Employee).ToList() ?? new List(); Model.SelectedCustomers = Model.SelectedAppointment?.CustomerList ?? new List(); } } return RedirectToActionPermanent("Scheduler"); } [Authorize] public JsonResult ResetSelectedAppointment() { if (Model != null) { Model.SelectedAppointment = null; Model.SelectedResources.Clear(); Model.IsAllDay = false; Model.IsPrivate = false; } return Json(null, JsonRequestBehavior.AllowGet); } [Authorize] public JsonResult CheckForOverlappingAppointments(string startDateRaw, string endDateRaw, string startTimeRaw, string endTimeRaw) { if (Model == null) { Logout(); return null; } var isOverlapping = false; var oid = Model.SelectedAppointment?.SchedulerAppointmentOid; 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 ?? MobileSessionFacade.LoggedInCompactEmployee; 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 == null && app.IsTask == false)) { } } } return Json(isOverlapping, JsonRequestBehavior.AllowGet); } [Authorize] public string SelectResourcesForAppointment(string resourceOids) { if(Model == null) { Logout(); return _LeerzeichenFuerGetMethoden; } var oidList = ConvertOidStringToList(resourceOids); 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(); return JsonConvert.SerializeObject(Model.SelectedResources); } [Authorize] public string SelectEmployeesForAppointment(string oidString) { if (Model == null) { Logout(); return _LeerzeichenFuerGetMethoden; } var oidList = ConvertOidStringToList(oidString); Model.SelectedEmployees = Model.AllEmployees.Where(employee => oidList.Contains(employee.EmployeeOid)).ToList(); return JsonConvert.SerializeObject(Model.SelectedEmployees.OrderBy(o => o.DetailDescription)); } [Authorize] public string SelectCustomersForAppointment(string oidString) { if (Model == null) { Logout(); return _LeerzeichenFuerGetMethoden; } var oidList = ConvertOidStringToList(oidString); Model.SelectedCustomers = Model.AllCustomers.Where(customer => oidList.Contains(customer.CustomerOid)).ToList(); return JsonConvert.SerializeObject(Model.SelectedCustomers.OrderBy(o => o.LastNameFirstName)); } [Authorize] public string CheckResourcesAvailability(string start, string end, string resourceOids) { if(!AbstractModel.HasRightToInsertRessourceAppointments) { return _LeerzeichenFuerGetMethoden; } if(!string.IsNullOrWhiteSpace(start) && !string.IsNullOrWhiteSpace(end) && !string.IsNullOrWhiteSpace(resourceOids) && Model != null) { var oidList = ConvertOidStringToList(resourceOids); foreach(var oid in oidList) { if(!Model.ResourceCategories2Resources.Any(a => a.Value.All(b => b.ResourceOid != oid))) { return JsonConvert.SerializeObject(new List()); } } var dateTimes = ConvertStringDatesToDateTimes(start, end); var unavailableResources = KalenderService.CheckResourceAvailability(dateTimes.StartDate, dateTimes.EndDate, oidList, Model.SelectedAppointment?.SchedulerAppointmentOid); return JsonConvert.SerializeObject(unavailableResources); } return _LeerzeichenFuerGetMethoden; } [Authorize] public string HasSelectedAppointment() { return JsonConvert.SerializeObject(Model?.SelectedAppointment != null); } [Authorize] [HttpPost] public ActionResult ChangeSchedulerView(FormCollection formCollection) { if(Model == null) { return Logout(); } var selectedSchedulerView = formCollection["SelectedSchedulerView"]; Model.SelectedSchedulerView = selectedSchedulerView; return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult FindFreeIntervals(FormCollection formCollection) { if(Model == null) { return Logout(); } var d = formCollection["Duration"]; var s = formCollection["IntervalStart"]; var st = formCollection["IntervalStartTime"]; var e = formCollection["IntervalEnd"]; var et = formCollection["IntervalEndTime"]; if (int.TryParse(d, out var duration) && DateTime.TryParse($"{s} {st}", out var start) && DateTime.TryParse($"{e} {et}", out var end) && Model.Employee.EmployeeOid.HasValue) { var customerOids = Model.SelectedCustomersForIntervalFinder.Select(c => c.CustomerOid).ToList(); var employeeOids = Model.SelectedEmployeesForIntervalFinder.Select(m => m.EmployeeOid).ToList(); var resourceOids = Model.SelectedResourcesForIntervalFinder.Where(w => w.ResourceOid.HasValue).Select(r => r.ResourceOid.Value).ToList(); Model.FreeIntervals = KalenderService.FindAppointmentsInRange(duration, start, end, resourceOids, customerOids, employeeOids, Model.Employee.EmployeeOid.Value); Model.IntervalStartDate = start; Model.IntervalEndDate = end; Model.IntervalDuration = duration; } return RedirectToActionPermanent("Scheduler"); } [Authorize] public string SelectEmployeesForIntervalFinder(string oidString) { if (Model == null) { Logout(); return _LeerzeichenFuerGetMethoden; } var employeeOids = ConvertOidStringToList(oidString); Model.SelectedEmployeesForIntervalFinder = Model.AllEmployees.Where(employee => employeeOids.Contains(employee.EmployeeOid)).ToList(); return JsonConvert.SerializeObject(Model.SelectedEmployeesForIntervalFinder.OrderBy(o => o.DetailDescription)); } [Authorize] public string SelectCustomersForIntervalFinder(string oidString) { if (Model == null) { Logout(); return _LeerzeichenFuerGetMethoden; } var customerOids = ConvertOidStringToList(oidString); Model.SelectedCustomersForIntervalFinder = Model.AllCustomers.Where(customer => customerOids.Contains(customer.CustomerOid)).ToList(); return JsonConvert.SerializeObject(Model.SelectedCustomersForIntervalFinder.OrderBy(o => o.LastNameFirstName)); } [Authorize] public string SelectResourcesForIntervalFinder(string resourceOids) { if (Model == null) { Logout(); return _LeerzeichenFuerGetMethoden; } var resourceOidList = ConvertOidStringToList(resourceOids); var list = new List(); Model.ResourceCategories2Resources.Values.DoForEach(l => l.DoForEach(s => list.AddIfNotIn(s))); Model.SelectedResourcesForIntervalFinder = list.Where(resource => resource.ResourceOid.HasValue && resourceOidList.Contains(resource.ResourceOid.Value)).ToList(); return JsonConvert.SerializeObject(Model.SelectedResourcesForIntervalFinder); } [Authorize] [HttpPost] public ActionResult SetIsInIntervalFinderMode(FormCollection formCollection) { if(Model == null) { return Logout(); } var newValue = !Model.IsInIntervalFinderMode; Model.IsInIntervalFinderMode = newValue; if(!newValue) { Model.SelectedEmployeesForIntervalFinder.Clear(); Model.SelectedCustomersForIntervalFinder.Clear(); Model.SelectedResourcesForIntervalFinder.Clear(); } return RedirectToActionPermanent("Scheduler"); } [Authorize] [HttpPost] public ActionResult SelectIntervalForForm(FormCollection formCollection) { if(Model == null) { 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 = MobileSessionFacade.LoggedInCompactEmployee, StartDate = startDate, EndDate = endDate }; Model.SelectedCustomers = Model.SelectedCustomersForIntervalFinder.Clone(); Model.SelectedEmployees = Model.SelectedEmployeesForIntervalFinder.Clone(); Model.SelectedResources = Model.SelectedResourcesForIntervalFinder.Clone(); Model.SelectedCustomersForIntervalFinder.Clear(); Model.SelectedEmployeesForIntervalFinder.Clear(); Model.SelectedResourcesForIntervalFinder.Clear(); Model.IntervalStartDate = null; Model.IntervalEndDate = null; } return RedirectToActionPermanent("Scheduler"); } [Authorize] public string ResetIntervalFinder() { if(Model == null) { return _LeerzeichenFuerGetMethoden; } Model.SelectedCustomersForIntervalFinder.Clear(); Model.SelectedEmployeesForIntervalFinder.Clear(); Model.SelectedResourcesForIntervalFinder.Clear(); return _LeerzeichenFuerGetMethoden; } } }