using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Globalization; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using BeWo.Annotations; using BeWo.Scheduler.ViewModel; using BeWo.ServiceProxy; using BS.Shared; using BS.Shared.DataContracts; using BS.Shared.DataContracts.Compact; using BS.Shared.Extensions; using DevExpress.Xpf.Editors; using DevExpress.XtraScheduler; namespace BeWo.Scheduler.View { public partial class RequestAnswerView : INotifyPropertyChanged { public static readonly RoutedEvent ParticipationChangedEvent = EventManager.RegisterRoutedEvent(nameof(ParticipationChanged), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(RequestAnswerView)); public event RoutedEventHandler ParticipationChanged { add => AddHandler(ParticipationChangedEvent, value); remove => RemoveHandler(ParticipationChangedEvent, value); } private void RaiseParticipationChangedEventEvent() { var newEventArgs = new RoutedEventArgs(ParticipationChangedEvent); RaiseEvent(newEventArgs); } public event PropertyChangedEventHandler PropertyChanged; [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public ObservableCollection OffeneTermine { get; set; } private IMainSessionointment _selektierterTermin; public IMainSessionointment SelektierterTermin { get => _selektierterTermin; set { _selektierterTermin = value; OnPropertyChanged(nameof(SelektierterTermin)); } } public RequestAnswerView(IEnumerable appointments, IEnumerable statusUpdates) { var statusUpdatesAsAppointments = new List(); foreach(var MainSessionointment in statusUpdates) { var item = (SchedulerAppointmentVM) MainSessionointment; foreach(var relation in item.EmployeeList.Where(emp => emp.IsPChanged && emp.ParticipationAnswer != ParticipationAnswer.Offen && emp.ParticipationAnswer != ParticipationAnswer.Verstrichen && !emp.Employee.EmployeeOid.Equals(MainSession.LoggedOnEmployee.EmployeeOid))) { if(statusUpdatesAsAppointments.All(a => a.LabelId != relation.Employee2SchedulerAppointmentOid)) { if(relation.Employee2SchedulerAppointmentOid != null) { statusUpdatesAsAppointments.Add(BuildNewVMFromOldVM(item, relation.Employee2SchedulerAppointmentOid.Value)); } } } } OffeneTermine = appointments.ToObservableCollection(); OffeneTermine.AddRange(new List(statusUpdatesAsAppointments)); DataContext = this; InitializeComponent(); } private static SchedulerAppointmentVM BuildNewVMFromOldVM(SchedulerAppointmentVM item, long emp2AppOid) { var customFieldStorage = (CustomFieldStorage) item.CustomFields[nameof(CustomFieldStorage)]; return new SchedulerAppointmentVM(new SchedulerAppointmentDC { SchedulerAppointmentOid = item.CommitToDataContract().SchedulerAppointmentOid, NewSchedulerAppointmentVersion = item.CommitToDataContract().NewSchedulerAppointmentVersion, IsPrivate = item.IsPrivate, RecurrenceInfo = item.RecurrenceInfo, Type = item.EventType, CustomerList = customFieldStorage.CustomerList, ResourceList = customFieldStorage.ResourceList, AllDay = item.AllDay, EmployeeList = item.EmployeeList.ToList(), Description = item.Description, EndDate = item.End, StartDate = item.Start, Location = item.Location, Subject = item.Subject, Status = 1, Originator = customFieldStorage.Originator, IsTeilnahmeBestaetigung = true, SupportConceptList = customFieldStorage.SupportConceptList }) { CustomFields = item.CustomFields, LabelId = Convert.ToInt32(emp2AppOid)}; } private void CloseButton_Click(object sender, RoutedEventArgs e) { Close(); } private void Selector_OnSelected(object sender, RoutedEventArgs e) { var lv = (ListView) sender; SelektierterTermin = (IMainSessionointment) lv.SelectedItem; } private void Zusagen_OnClick(object sender, RoutedEventArgs e) { var meinTermin = SelektierterTermin as SchedulerAppointmentVM; UpdateTeilnahme(ParticipationAnswer.Zusage, meinTermin); } private void Absagen_OnClick(object sender, RoutedEventArgs e) { var meinTermin = SelektierterTermin as SchedulerAppointmentVM; UpdateTeilnahme(ParticipationAnswer.Absage, meinTermin); } private void MitVorbehalt_OnClick(object sender, RoutedEventArgs e) { var meinTermin = SelektierterTermin as SchedulerAppointmentVM; UpdateTeilnahme(ParticipationAnswer.Vorbehalt, meinTermin); } private void UpdateTeilnahme(ParticipationAnswer antwort, SchedulerAppointmentVM termin) { termin.EmployeeList.DoForEach(e => { if (e.Employee.EmployeeOid.Equals(MainSession.LoggedOnEmployee.EmployeeOid)) { e.ParticipationAnswer = antwort; } }); ToggleControls(); ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List { termin.CommitToDataContract() }), UpdateView); } private void UpdateView(List aktualisierteTermine) { foreach (var dc in aktualisierteTermine) { foreach (var ivm in OffeneTermine) { var vm = ivm as SchedulerAppointmentVM; if (vm == null || !vm.DataContract.Equals(dc)) { continue; } var found = vm; found.DataContract = dc; UpdateViewModel(dc, (SchedulerAppointmentVM) ivm); vm.UpdateCustomFields(); if (vm.LabelId == 0) { this.Dispatch(() => { OffeneTermine = OffeneTermine.Where(w => !w.Equals(vm)).ToObservableCollection(); OnPropertyChanged(nameof(OffeneTermine)); RaiseParticipationChangedEventEvent(); }); } else { var test = (SchedulerAppointmentVM) OffeneTermine.FirstOrDefault(f => dc.EmployeeList.Any(a => a.Employee2SchedulerAppointmentOid.HasValue && a.Employee2SchedulerAppointmentOid.Value == f.LabelId)); this.Dispatch(() => { OffeneTermine = OffeneTermine.Where(w => !w.Equals(test)).ToObservableCollection(); OnPropertyChanged(nameof(OffeneTermine)); RaiseParticipationChangedEventEvent(); }); } } } this.Dispatch(() => { RaiseParticipationChangedEventEvent(); ToggleControls(); if (OffeneTermine.Count == 0 && OTListView.Items.Count == 0) { Close(); } else { OTListView.SelectedIndex = 0; } }); } private void OK_OnClick(object sender, RoutedEventArgs e) { SelektierterTermin = OTListView.SelectedItem as IMainSessionointment; if(_selektierterTermin != null && _selektierterTermin.Start < DateTime.Now && _selektierterTermin.End < DateTime.Now) { if(SelektierterTermin != null && MainSession.LoggedOnEmployee.EmployeeOid.HasValue) { var customFieldStorage = (CustomFieldStorage) SelektierterTermin.CustomFields[nameof(CustomFieldStorage)]; var emp2App = customFieldStorage.EmployeeList.ToList().Find(f => f.Employee2SchedulerAppointmentOid == SelektierterTermin.LabelId) ?? customFieldStorage.EmployeeList.ToList().Find(f => f.Employee.EmployeeOid == MainSession.LoggedOnEmployee.EmployeeOid.Value); if(emp2App.Employee.EmployeeOid == MainSession.LoggedOnEmployee.EmployeeOid.Value) { emp2App.ParticipationAnswer = ParticipationAnswer.Verstrichen; } emp2App.IsPC_CheckedTs = DateTime.Now; emp2App.IsPChanged = false; } ToggleControls(); ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List { ((SchedulerAppointmentVM)SelektierterTermin).DataContract }), UpdateView); return; } if(SelektierterTermin == null || SelektierterTermin.LabelId <= 0) { return; } var customFieldStorage2 = (CustomFieldStorage)SelektierterTermin.CustomFields[nameof(CustomFieldStorage)]; customFieldStorage2.EmployeeList.ToList().Find(f => f.Employee2SchedulerAppointmentOid == SelektierterTermin.LabelId).IsPC_CheckedTs = DateTime.Now; customFieldStorage2.EmployeeList.ToList().Find(f => f.Employee2SchedulerAppointmentOid == SelektierterTermin.LabelId).IsPChanged = false; ToggleControls(); ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List {((SchedulerAppointmentVM) SelektierterTermin).DataContract}), UpdateView); } private static void UpdateViewModel(SchedulerAppointmentDC dc, SchedulerAppointmentVM vm) { vm.EmployeeList = new ObservableCollection(dc.EmployeeList); } private void ToggleControls() { ZusagenStack.IsEnabled = !ZusagenStack.IsEnabled; OkButton.IsEnabled = !OkButton.IsEnabled; CloseBtn.IsEnabled = !CloseBtn.IsEnabled; } private void PopupBaseEdit_OnPopupOpening(object sender, OpenPopupEventArgs e) { // Es wird verhindert, dass das Popup angezeigt wird auch wenn das DateEdit readonly ist, damit man es nicht auf disabled setzen muss, da sonst die Schriftfarbe schwer lesbar ist. e.Cancel = true; } private void RequestAnswerView_OnClosing(object sender, CancelEventArgs e) { MainSession.MainPage.AufOffeneTerminePruefen(); } } public class LVItemConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var app = (IMainSessionointment) value; if(app == null) { return string.Empty; } if(app.LabelId <= 0) { return $"{app.Start.ToShortDateString()}: {app.Subject}"; } var s = string.Empty; var customFieldStorage = (CustomFieldStorage) app.CustomFields[nameof(CustomFieldStorage)]; var l = customFieldStorage.EmployeeList.ToList().Find(f => f.Employee2SchedulerAppointmentOid == app.LabelId); switch(l.ParticipationAnswer) { case ParticipationAnswer.Zusage: s = "zugesagt"; break; case ParticipationAnswer.Vorbehalt: s = "mit Vorbehalt zugesagt"; break; case ParticipationAnswer.Absage: s = "abgesagt"; break; } return $"{app.Start.ToShortDateString()}: {l.Employee.FirstName} {l.Employee.LastName} hat {s}"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class OriginatorExtraxtor : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if(value == null) { return null; } var app = (IMainSessionointment)value; var customFieldStorage = (CustomFieldStorage) app.CustomFields[nameof(CustomFieldStorage)]; var originator = customFieldStorage.Originator; return originator.FirstName + " " + originator.LastName; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class Int2VisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if(value == null) { return Visibility.Collapsed; } var appointment = (SchedulerAppointmentVM) value; var eternalEh = false; var liegtInDerVergangenheit = appointment.Start < DateTime.Now && appointment.End < DateTime.Now; if(appointment.RecurrenceInfo != null) { IRecurrenceInfo info = new RecurrenceInfo(); info.FromXml(appointment.RecurrenceInfo); eternalEh = info.Range == RecurrenceRange.NoEndDate; liegtInDerVergangenheit = info.Start < DateTime.Now && info.End < DateTime.Now; } if(parameter != null && parameter.Equals("ZusagenStack")) { if(appointment.IsTeilnahmeBestaetigung) { return Visibility.Collapsed; } var shouldBeVisible = !liegtInDerVergangenheit; if(appointment.RecurrenceInfo != null) { shouldBeVisible = !liegtInDerVergangenheit || eternalEh; } return shouldBeVisible ? Visibility.Visible : Visibility.Collapsed; } if(parameter != null && parameter.Equals("OKBtn")) { return appointment.IsTeilnahmeBestaetigung || liegtInDerVergangenheit && !eternalEh ? Visibility.Visible : Visibility.Collapsed; } if(parameter != null && parameter.Equals("TerminVerstrichen")) { return liegtInDerVergangenheit && !eternalEh ? Visibility.Visible : Visibility.Collapsed; } if(parameter != null && parameter.Equals("SerienterminLabel")) { return appointment.RecurrenceInfo != null ? Visibility.Visible : Visibility.Collapsed; } return appointment.IsTeilnahmeBestaetigung || liegtInDerVergangenheit ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class SerienterminDauerAnzeigeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if(value == null) { return null; } var appointment = (SchedulerAppointmentVM) value; if(appointment.RecurrenceInfo == null) { return ""; } IRecurrenceInfo info = new RecurrenceInfo(); info.FromXml(appointment.RecurrenceInfo); var rangeString = ""; var suffix = ""; var periodicity = info.Periodicity; var intervalPlural = ""; var wochentage = ""; string wocheDesMonats; switch(info.Range) { case RecurrenceRange.EndByDate: rangeString += "bis zum " + info.End.ToShortDateString() + " "; break; case RecurrenceRange.OccurrenceCount: rangeString += info.OccurrenceCount + " mal "; break; } switch(info.Type) { case RecurrenceType.Daily: if(periodicity == 1) { suffix = info.WeekDays.Equals(WeekDays.WorkDays) ? "jeden Arbeitstag " : "täglich "; } intervalPlural = " Tage "; break; case RecurrenceType.Weekly: if(periodicity == 1) { suffix = "wöchentlich "; } intervalPlural = " Wochen "; wochentage = TranslateWorkDays(info.WeekDays.ToString(), true); break; case RecurrenceType.Yearly: wochentage = TranslateWorkDays(info.WeekDays.ToString(), false); wocheDesMonats = TranslateWeekOfMonth(info.WeekOfMonth); var tag = info.DayNumber; suffix = "jährlich "; if(info.WeekOfMonth != WeekOfMonth.None) { suffix += "jeden " + wocheDesMonats + wochentage + "im " + GetMonthByInt(info.Month); } else { suffix += "am " + tag + ". " + GetMonthByInt(info.Month); } wochentage = ""; break; case RecurrenceType.Monthly: string monatlichesInterval; if(info.WeekOfMonth != WeekOfMonth.None) { wocheDesMonats = TranslateWeekOfMonth(info.WeekOfMonth); wochentage = TranslateWorkDays(info.WeekDays.ToString(), false); suffix = "jeden " + wocheDesMonats + wochentage; if(periodicity == 1) { monatlichesInterval = "jedes Monats "; } else { monatlichesInterval = "jedes " + periodicity + ". Monats "; } suffix += monatlichesInterval; wochentage = ""; } else { if(periodicity == 1) { monatlichesInterval = "jedes Monats "; } else { monatlichesInterval = "jedes " + periodicity + ". Monats "; } suffix = "am " + info.DayNumber + ". " + monatlichesInterval; wochentage = ""; } break; } if(periodicity > 1 && info.Type != RecurrenceType.Monthly) { suffix = "alle " + periodicity + intervalPlural; } return "Dieser Termin wird " + rangeString + suffix + wochentage + "wiederholt"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } private static string TranslateWorkDays(string weekDays, bool mitGenitivS) { weekDays = weekDays.Replace("Monday", mitGenitivS ? "Montags" : "Montag"); weekDays = weekDays.Replace("Tuesday", mitGenitivS ? "Dienstags" : "Dienstag"); weekDays = weekDays.Replace("Wednesday", mitGenitivS ? "Mittwochs" : "Mittwoch"); weekDays = weekDays.Replace("Thursday", mitGenitivS ? "Donnerstags" : "Donnerstag"); weekDays = weekDays.Replace("Friday", mitGenitivS ? "Freitags" : "Freitag"); weekDays = weekDays.Replace("Saturday", mitGenitivS ? "Samstags" : "Samstag"); weekDays = weekDays.Replace("Sunday", mitGenitivS ? "Sonntags" : "Sonntag"); weekDays = weekDays.Replace("EveryDay", "jeden Tag"); var lastComma = weekDays.LastIndexOf(','); if(lastComma != -1) { weekDays = weekDays.Remove(lastComma, 1).Insert(lastComma, " und"); } return weekDays + " "; } private static string TranslateWeekOfMonth(WeekOfMonth weekOfMonth) { var result = " "; switch(weekOfMonth) { case WeekOfMonth.First: result = "ersten "; break; case WeekOfMonth.Second: result = "zweiten "; break; case WeekOfMonth.Third: result = "dritten "; break; case WeekOfMonth.Fourth: result = "vierten "; break; case WeekOfMonth.Last: result = "letzten "; break; case WeekOfMonth.None: return result; default: return result; } return result; } private static string GetMonthByInt(int month) { switch(month) { case 1: return "Januar "; case 2: return "Februar "; case 3: return "März "; case 4: return "April "; case 5: return "Mai "; case 6: return "Juni "; case 7: return "Juli "; case 8: return "August "; case 9: return "September "; case 10: return "Oktober "; case 11: return "November "; case 12: return "Dezember "; default: return " "; } } } }