using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using Comal.Classes; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.DynamicGrid; using InABox.WPF; namespace PRSDesktop { public class HTMLConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var str = value as string; return CoreUtils.StripHTML(str); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class HideIfMineConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var guid = (Guid)value; return guid.Equals(ClientFactory.UserGuid) ? Visibility.Collapsed : Visibility.Visible; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class DueDateToColorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var duedate = (DateTime)value; return duedate < DateTime.Today ? "Salmon" : duedate < DateTime.Today.AddDays(7) ? "LightYellow" : "LightGreen"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class DateIsInListConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Length < 2 || !(values[0] is DateTime) || !(values[1] is IEnumerable)) return false; var date = (DateTime)values[0]; var dateList = (IEnumerable)values[1]; return dateList.Any(hd => hd.Date.Equals(date)); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class HighlightedDateDescriptionConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Length < 2 || !(values[0] is DateTime) || !(values[1] is IEnumerable)) return false; var date = (DateTime)values[0]; var dateList = (IEnumerable)values[1]; var highlightedDate = dateList.FirstOrDefault(hd => hd.Date.Equals(date)); return highlightedDate != null ? highlightedDate.Description : string.Empty; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class HighlightDatePicker : DatePicker { public static readonly DependencyProperty HighlightedDatesProperty = DependencyProperty.Register("HighlightedDates", typeof(IList), typeof(HighlightDatePicker)); public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.Register("HighlightBrush", typeof(Brush), typeof(HighlightDatePicker), new PropertyMetadata(Brushes.Orange)); static HighlightDatePicker() { DefaultStyleKeyProperty.OverrideMetadata(typeof(HighlightDatePicker), new FrameworkPropertyMetadata(typeof(HighlightDatePicker))); } public IList HighlightedDates { get => (IList)GetValue(HighlightedDatesProperty); set => SetValue(HighlightedDatesProperty, value); } public Brush HighlightBrush { get => (Brush)GetValue(HighlightBrushProperty); set => SetValue(HighlightBrushProperty, value); } } public class HighlightedDate { public HighlightedDate(DateTime date, string description) { Date = date; Description = description; } public DateTime Date { get; set; } public string Description { get; set; } } public class RequiredReport { public RequiredReport(Guid id, DateTime date, TimeSpan start, TimeSpan finish, string notes) { ID = id; Date = date; Start = start; Finish = finish; Notes = notes; } public Guid ID { get; set; } public DateTime Date { get; set; } public TimeSpan Start { get; set; } public TimeSpan Finish { get; set; } public string Notes { get; set; } } public class TimeSheetConfirmedArgs : EventArgs { public DateTime Date { get; set; } } public delegate void TimeSheetConfirmedEvent(TimeSheetConfirmedArgs e); /// /// Interaction logic for DailyReport.xaml /// public partial class DailyReport : UserControl, IPanel, IDynamicEditorHost { private DailyActivityScreenSettings _settings; private string _taskcategory = "Open"; private bool bProgramaticallyChanging = false; private bool bSelectingAssignment; private AssignmentModel copiedAssignment; private KanbanGrid kg = new(); private MenuItem MoveToComplete; private MenuItem MoveToCurrent; private MenuItem MoveToOpen; private MenuItem MoveToWaiting; private int RequiredReportIndex; private readonly List RequiredReports = new(); private Assignment SelectedAssignment; private Point startPoint; private CalendarSettings Calendar_OnLoadSettings(object sender) { var settings = new CalendarSettings(); settings.SettingsVisible = CalendarSettingsVisibility.Disabled; settings.AssignmentType = CalendarAssignmentType.Automatic; settings.CalendarView = CalendarViewType.Day; settings.BackgroundType = CalendarBackgroundType.Automatic; settings.TimeInterval = CalendarTimeInterval.FifteenMinutes; settings.EmployeeSelection = new EmployeeSelectorData(new Guid[] { Guid.Empty }, new Guid[] { Employee.ID }); settings.Zoom = _settings.Zoom; return settings; } private void Calendar_OnSaveSettings(object sender, CalendarSettings properties) { _settings.Zoom = properties.Zoom; new UserConfiguration().Save(_settings); } public DailyReport() { InitializeComponent(); ImportEmails.Visibility = Security.CanImport() ? Visibility.Visible : Visibility.Collapsed; ImportEmailsImage.Source = PRSDesktop.Resources.target.AsBitmapImage(); ProcessWindowTrackers.Visibility = Security.IsAllowed() ? Visibility.Visible : Visibility.Collapsed; ImportHistoryImage.Source = PRSDesktop.Resources.email.AsBitmapImage(); ConfirmTimeSheetImage.Source = PRSDesktop.Resources.tick.AsBitmapImage(); } #region IDynamicEditorHost public IEnumerable Columns { get; } = InitialiseColumns(); private static DynamicGridColumns InitialiseColumns() { var columns = new DynamicGridColumns(); columns.ExtractColumns(typeof(Assignment)); return columns; } public void LoadColumns(string column, Dictionary columns) { columns.Clear(); var comps = column.Split('.').ToList(); comps.RemoveAt(comps.Count - 1); var prefix = string.Format("{0}.", string.Join(".", comps)); var cols = Columns.Where(x => !x.ColumnName.Equals(column) && x.ColumnName.StartsWith(prefix)); foreach (var col in cols) columns[col.ColumnName.Replace(prefix, "")] = col.ColumnName; } public IFilter? DefineFilter(Type type) => LookupFactory.DefineFilter(new Assignment[] { SelectedAssignment }, type); public void LoadLookups(ILookupEditorControl editor) { if (editor == Activity) Activity_OnDefineLookups(editor); else if (editor == Kanban) Task_OnDefineLookups(editor); else if (editor == ITP) ITP_OnDefineLookups(editor); } public Document? FindDocument(string filename) { return new Client().Load(new Filter(x => x.FileName).IsEqualTo(filename)).FirstOrDefault(); } public Document? GetDocument(Guid id) { Document? doc = null; if (id != Guid.Empty) doc = new Client().Load(new Filter(x => x.ID).IsEqualTo(id)).FirstOrDefault(); return doc; } public void SaveDocument(Document document) { new Client().Save(document, ""); } object?[] IDynamicEditorHost.GetItems() => new object?[] { SelectedAssignment }; public BaseEditor? GetEditor(DynamicGridColumn column) => column.Editor.CloneEditor(); #endregion public void Setup() { Calendar.DisableUpdate(); try { Parallel.ForEach( new Action[] { () => _settings = new UserConfiguration().Load(), () => Employee = new Client().Load(new Filter(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid)).FirstOrDefault(), }, (a => a()) ); Calendar.Setup(); LoadRequiredReports(); if (!RequiredReports.Any()) { var start = TimeSpan.FromHours(6); var finish = TimeSpan.FromHours(18); var blocks = Calendar.GetRoster(Employee.ID, DateTime.Today)?.GetBlocks(DateTime.Today, TimeSpan.FromSeconds(0), TimeSpan.FromDays(1)); if (blocks?.Any() == true) { start = blocks.Aggregate(TimeSpan.FromDays(1), (time, block) => time.Ticks < block.Start.Ticks ? time : block.Start); finish = blocks.Aggregate(TimeSpan.Zero, (time, block) => time.Ticks > block.Finish.Ticks ? time : block.Start); } RequiredReports.Add(new RequiredReport(Guid.Empty, DateTime.Today, start, finish, "")); ConfirmDock.Visibility = Visibility.Collapsed; } ConfigureEditor(Title, new TextBoxEditor()); ConfigureEditor(ActivityNotes, new MemoEditor()); ConfigureEditor(Start, new TimeOfDayEditor()); ConfigureEditor(Duration, new TimeOfDayEditor()); ConfigureEditor(Finish, new TimeOfDayEditor()); ConfigureEditor(Notes, new MemoEditor()); Activity.EditorDefinition = DatabaseSchema.Property(typeof(Assignment), CoreUtils.GetFullPropertyName(c=>c.ActivityLink.ID,".")).Editor as ILookupEditor; Activity.OtherColumns["Color"] = CoreUtils.GetFullPropertyName(c=>c.ActivityLink.Color,"."); Activity.OtherColumns["Description"] = CoreUtils.GetFullPropertyName(c=>c.ActivityLink.Description,"."); ConfigureEditor(Activity); ITP.EditorDefinition = DatabaseSchema.Property(typeof(Assignment), "ITP.ID").Editor as ILookupEditor; ITP.OtherColumns["Code"] = "ITP.Code"; //ConfigureEditor(ITP); Kanban.EditorDefinition = DatabaseSchema.Property(typeof(Assignment), "Task.ID").Editor as ILookupEditor; Kanban.OtherColumns["JobLink.ID"] = "JobLink.ID"; Kanban.OtherColumns["JobLink.JobNumber"] = "JobLink.JobNumber"; Kanban.OtherColumns["JobLink.Name"] = "JobLink.Name"; ConfigureEditor(Kanban); Job.EditorDefinition = DatabaseSchema.Property(typeof(Assignment), "JobLink.ID").Editor as CodePopupEditor; Job.OtherColumns["JobNumber"] = "JobLink.JobNumber"; Job.OtherColumns["Name"] = "JobLink.Name"; ConfigureEditor(Job); GotoCurrentRequiredReport(); LoadKanbans("Open"); } finally { Calendar.EnableUpdate(); } } public void Shutdown() { } private void LoadRequiredReports() { var unconfirmed = new Client().Query( new Filter(x => x.EmployeeLink.ID).IsEqualTo(Employee.ID).And(x => x.Confirmed).IsEqualTo(DateTime.MinValue) .And(x => x.LeaveRequestLink).NotLinkValid(), new Columns(x => x.ID, x => x.Date, x => x.Start, x => x.Finish, x => x.Notes), new SortOrder(x => x.Date) ); var id = Guid.Empty; var date = DateTime.MinValue; var start = TimeSpan.MaxValue; var end = TimeSpan.MinValue; var notes = new List(); foreach (var row in unconfirmed.Rows) { var curid = row.Get(x => x.ID); var curdate = row.Get(c => c.Date).Date; var curstart = row.Get(c => c.Start); var curend = row.Get(c => c.Finish); var curnotes = row.Get(c => c.Notes); if (date != curdate) { if (id != Guid.Empty) RequiredReports.Add(new RequiredReport(id, date, start, end, string.Join("\n===================================\n", notes))); id = curid; date = curdate; start = TimeSpan.MaxValue; end = TimeSpan.MinValue; notes.Clear(); } start = start > curstart ? curstart : start; end = end < curend ? curend : end; if (!string.IsNullOrEmpty(curnotes)) notes.Add(curnotes); } if (id != Guid.Empty) RequiredReports.Add(new RequiredReport(id, date, start, end, string.Join("\n===================================\n", notes))); } public Employee Employee { get; set; } public event DataModelUpdateEvent? OnUpdateDataModel; public bool IsReady { get; set; } public void CreateToolbarButtons(IPanelHost host) { } public string SectionName => "Daily Report"; public DataModel DataModel(Selection selected) => Calendar.DataModel(selected); public void Heartbeat(TimeSpan time) { } public void Refresh() { RefreshAssignments(); LoadKanbans(); } public Dictionary Selected() { return new Dictionary(); } public event TimeSheetConfirmedEvent OnTimeSheetConfirmed; private void PopulateFavourites(ItemsControl menu, RoutedEventHandler action, DateTime time, bool filltime) { menu.Items.RemoveAt(0); var create = new MenuItem { Header = "Create New Assignment" }; create.Tag = new Tuple(time, null); create.Click += action; menu.Items.Insert(0,create); if (_settings.Favourites?.Any() == true) { menu.Items.Insert(1,new Separator()); int i = 2; foreach (var favourite in _settings.Favourites) { var fav = new MenuItem { Header = favourite.Title }; fav.Tag = new Tuple(time, favourite); fav.Click += action; menu.Items.Insert(i,fav); i++; } } } private void Assignments_OnCustomiseContextMenu(object sender, ICalendarDataEventArgs args) { if (sender is not ContextMenu menu) return; if (args is CalendarDataEventArgs slot) { PopulateFavourites(menu, CreateAssignment_Click, slot.Item.Time, false); } else if (args is CalendarDataEventArgs model) { menu.Items.Insert(1,new Separator()); var SetAsFavouriteMenu = new MenuItem { Header = GetFavourite(model.Item) == null ? "Set As Favourite" : "Update Favourite"}; SetAsFavouriteMenu.Click += (o, args) => SetAsFavourite(model.Item); menu.Items.Insert(2,SetAsFavouriteMenu); if (_settings.Favourites.Any()) { var ManageFavouritesMenu = new MenuItem { Header = "Manage Favourites" }; ManageFavouritesMenu.Click += ManageFavourites_Click; menu.Items.Insert(3,ManageFavouritesMenu); } } } private AssignmentFavourite? GetFavourite(AssignmentModel? model) { return model == null ? null : _settings.Favourites.FirstOrDefault(x => string.Equals(x.Title, model.Subject)); } private void SetAsFavourite(AssignmentModel? model) { if (model == null) { MessageBox.Show("Please select an Assignment first!"); return; } var bCreated = false; var favourite = GetFavourite(model); if (favourite == null) { bCreated = true; favourite = new AssignmentFavourite { Title = model.Subject }; _settings.Favourites.Add(favourite); } favourite.JobID = model.JobID; favourite.JobNumber = model.JobNumber; favourite.ITPID = model.ItpID; favourite.ITPCode = model.ItpCode; favourite.ActivityID = model.ActivityID; favourite.ActivityColor = model.Color; favourite.ActivityName = model.ActivityCode; new UserConfiguration().Save(_settings); MessageBox.Show(bCreated ? "Favourite Created!" : "Favourite Updated!"); } private void ManageFavourites_Click(object sender, RoutedEventArgs e) { new DailyReportFavouriteWindow(_settings.Favourites).ShowDialog(); new UserConfiguration().Save(_settings); } private void ViewEmailInterfaceForm_Click(object sender, RoutedEventArgs e) { var form = new EmailInterfaceForm { FromDate = Calendar.SelectedDate, ToDate = Calendar.SelectedDate }; form.ShowDialog(); //UpdateDayButtons(); } private void ProcessWindowTrackerMenu_Click(object sender, RoutedEventArgs e) { var history = new WindowTrackerSummary(Employee.ID, Calendar.SelectedDate); history.ShowDialog(); //UpdateDayButtons(); } private void CreateAssignment_Click(object sender, RoutedEventArgs e) { var fav = (sender as MenuItem)?.Tag as Tuple; var start = fav != null ? fav.Item1.TimeOfDay : Calendar.SelectedDate.TimeOfDay; CreateNewAssignment(start, fav?.Item2); } private void CreateNewAssignment(TimeSpan start, AssignmentFavourite? favourite) { CalendarDataEvent populate = (sender, args) => PopulateFavourite(args.Item as Assignment, favourite); Calendar.ItemCreated += populate; var ass = Calendar.CreateAssignment(new CalendarTimeSlot(Employee.ID, Calendar.SelectedDate.Add(start))); Calendar.ItemCreated -= populate; SelectAssignment(ass); } private void PopulateFavourite(Assignment? assignment, AssignmentFavourite? favourite) { if (assignment == null) return; assignment.Title = favourite != null ? favourite.Title : ""; assignment.JobLink.ID = favourite != null ? favourite.JobID : Guid.Empty; assignment.ITP.ID = favourite != null ? favourite.ITPID : Guid.Empty; assignment.ActivityLink.ID = favourite != null ? favourite.ActivityID : Guid.Empty; assignment.ActivityLink.Color = favourite != null ? favourite.ActivityColor : ""; new Client().Save(assignment, "Created by Daily Report"); } private void RefreshAssignments() { Calendar.Refresh(); } private void Assignments_OnSelectionChanged(object sender, ICalendarDataEventArgs args) { if (args is CalendarDataEventArgs ass) { CheckandSaveAssignment(); SelectAssignment(ass.Item); } else SelectAssignment(null); } private void CheckandSaveAssignment() { if (SelectedAssignment != null && SelectedAssignment.IsChanged()) { new Client().Save(SelectedAssignment, "", (o, e) => { }); //SelectedAssignment.CommitChanges(); } } private void SelectAssignment(Assignment? assignment) { Logger.Send(LogType.Information, ClientFactory.UserID, "Into Assignment_SelectionChanged()"); bSelectingAssignment = true; try { SelectedAssignment = assignment; var bOK = assignment != null; //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (1/9): Setting Title"); SetEditorValue(Title, bOK ? assignment.Title : "", bOK); //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (2/9): Setting Description"); SetEditorValue(ActivityNotes, bOK ? assignment.Description : "", bOK); //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (3/9): Setting Start/Duration/Finish"); SetEditorValue(Start, bOK ? assignment.Actual.Start : TimeSpan.MinValue, bOK); SetEditorValue(Duration, bOK ? assignment.Actual.Finish - assignment.Actual.Start : TimeSpan.MinValue, bOK); SetEditorValue(Finish, bOK ? assignment.Actual.Finish : TimeSpan.MinValue, bOK); var jobid = Job.Value; //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (4/9): Setting JobLink"); SetEditorValue(Job, bOK ? assignment.JobLink.ID : Guid.Empty, bOK); if (bOK && !Equals(jobid, Job.Value)) //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (5/9): Configuring ITP"); ConfigureEditor(ITP); //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (6/9): Setting ITP"); SetEditorValue(ITP, bOK ? assignment.ITP.ID : Guid.Empty, bOK); //if (bOK) //{ // //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (7/9): Configuring Activity"); // ConfigureEditor(Activity); //} //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (8/9): Setting Activity"); //SetEditorValue(Activity, bOK ? assignment.ActivityLink.ID : Guid.Empty, bOK); Activity.Value = bOK ? assignment.ActivityLink.ID : Guid.Empty; Activity.IsEnabled = bOK; //if (bOK) //{ // //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (9/9): Configuring Task"); // ConfigureEditor(Kanban); //} //Logger.Send(LogType.Information, ClientFactory.UserID, "ASC (8/9): Setting Task"); //SetEditorValue(Kanban, bOK ? assignment.Task.ID : Guid.Empty, bOK); Kanban.Value = bOK ? assignment.Task.ID : Guid.Empty; Kanban.IsEnabled = bOK; Job.IsEnabled = bOK ? !assignment.Task.IsValid() : false; if (assignment != null) { if (string.IsNullOrWhiteSpace(Title.Value)) Title.SetFocus(); else Notes.SetFocus(); } } finally { bSelectingAssignment = false; } Logger.Send(LogType.Information, ClientFactory.UserID, "Out Of Assignment_SelectionChanged()"); } private void ConfigureEditor(BaseDynamicEditorControl editor, BaseEditor? definition = null) { editor.Host = this; if (definition != null) editor.EditorDefinition = definition; editor.Configure(); editor.Loaded = true; } private void SetEditorValue(BaseDynamicEditorControl editor, object value, bool enabled) { editor.Loaded = false; editor.SetValue(editor.ColumnName, value); editor.IsEnabled = enabled; editor.Loaded = true; } private void Assignments_OnItemChanged(object sender, ICalendarDataEventArgs args) { if (args is CalendarDataEventArgs ass) { if (ass.Item.ID == Guid.Empty) using (new WaitCursor()) { ass.Item.Actual.Duration = new TimeSpan(0, 30, 0); new Client().Save(ass.Item, "Created from Daily Report Drag & Drop"); } } } private void EditorValueChanged(IDynamicEditorControl sender, Dictionary values) { if (SelectedAssignment == null || bSelectingAssignment) return; DumpAssignmentValues(SelectedAssignment); var before = SelectedAssignment.GetValues(true); foreach (var key in values.Keys) { CoreUtils.SetPropertyValue(SelectedAssignment, key, values[key]); if (key.Equals("Task.ID")) Job.IsEnabled = values[key] == null || ((Guid)values[key]).Equals(Guid.Empty); if (key.Equals("JobLink.ID")) { ConfigureEditor(ITP); SelectedAssignment.ITP.ID = Guid.Empty; } } var after = SelectedAssignment.GetValues(true); var changes = before.Keys.Where(x => !values.Keys.Contains(x) && ((before[x] == null && after[x] != null) || (before[x] != null && !before[x].Equals(after[x])))); foreach (var change in changes) if (change.Equals("Actual.Start")) SetEditorValue(Start, SelectedAssignment.Actual.Start, Start.IsEnabled); else if (change.Equals("Actual.Duration")) SetEditorValue(Duration, SelectedAssignment.Actual.Duration, Duration.IsEnabled); else if (change.Equals("Actual.Finish")) SetEditorValue(Finish, SelectedAssignment.Actual.Finish, Finish.IsEnabled); if (SelectedAssignment.Actual.Duration < new TimeSpan(0, 15, 0)) { SelectedAssignment.Actual.Duration = new TimeSpan(0, 15, 0); SetEditorValue(Duration, SelectedAssignment.Actual.Duration, Duration.IsEnabled); SelectedAssignment.Actual.Finish = SelectedAssignment.Actual.Start.Add(SelectedAssignment.Actual.Duration); SetEditorValue(Finish, SelectedAssignment.Actual.Finish, Finish.IsEnabled); } if (SelectedAssignment.IsChanged()) { new Client().Save(SelectedAssignment, "", (o, e) => { if (e != null) Logger.Send(LogType.Error, "", String.Format("Error Updating Assignment: {0}\n{1}", e.Message, e.StackTrace)); } ); Calendar.UpdateAssignment(SelectedAssignment); } } private void DumpAssignmentValues(Assignment assignment) { Logger.Send(LogType.Information, "", string.Format("Updating Assignment: Start:{0} Duration={1} Finish={2}", assignment.Actual.Start, assignment.Actual.Duration, assignment.Actual.Finish)); } private void TimeSheetEditorValueChanged(IDynamicEditorControl sender, Dictionary values) { if (RequiredReportIndex < 0 || RequiredReportIndex >= RequiredReports.Count) return; var report = RequiredReports[RequiredReportIndex]; report.Notes = sender.GetValue(sender.ColumnName) as string; var timesheet = new TimeSheet { ID = report.ID, Notes = report.Notes }; new Client().Save(timesheet, "", (o, e) => { }); } private void Activity_OnDefineLookups(ILookupEditorControl sender) { var editor = sender.EditorDefinition as ILookupEditor; var colname = sender.ColumnName; var assignment = new Assignment(); assignment.EmployeeLink.ID = Employee.ID; var values = editor.Values(colname, new[] { assignment }); sender.LoadLookups(values); } private void Task_OnDefineLookups(ILookupEditorControl sender) { var editor = sender.EditorDefinition as ILookupEditor; var colname = sender.ColumnName; var assignment = new Assignment(); assignment.EmployeeLink.ID = Employee.ID; var values = editor.Values(colname, new[] { assignment }); sender.LoadLookups(values); } private void ITP_OnDefineLookups(ILookupEditorControl sender) { var editor = sender.EditorDefinition as ILookupEditor; var colname = sender.ColumnName; var values = editor.Values(colname, SelectedAssignment == null ? new Assignment[] { } : new[] { SelectedAssignment }); sender.LoadLookups(values); } private void FirstDay_Click(object sender, RoutedEventArgs e) { RequiredReportIndex = 0; GotoCurrentRequiredReport(); } private void SetCurrentDay(DateTime date) { bProgramaticallyChanging = true; DatePicker.SelectedDate = date; bProgramaticallyChanging = false; ConfigureBookingsList(); } private void PrevDay_Click(object sender, RoutedEventArgs e) { var requiredreport = RequiredReports.OrderBy(x => x.Date).LastOrDefault(x => x.Date < DatePicker.SelectedDate); if (requiredreport != null) SetCurrentDay(requiredreport.Date); } private void NextDay_Click(object sender, RoutedEventArgs e) { var requiredreport = RequiredReports.OrderBy(x => x.Date).FirstOrDefault(x => x.Date > DatePicker.SelectedDate); if (requiredreport != null) SetCurrentDay(requiredreport.Date); } private void LastDay_Click(object sender, RoutedEventArgs e) { RequiredReportIndex = RequiredReports.Count - 1; GotoCurrentRequiredReport(); } private void DatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) { if (!bProgramaticallyChanging) ConfigureBookingsList(); } private void ConfigureBookingsList() { DatePicker.HighlightedDates = RequiredReports.Select(x => new HighlightedDate(x.Date, "Report Required")).ToList(); FirstDay.IsEnabled = RequiredReports.Count > 0 && DatePicker.SelectedDate > RequiredReports[0].Date; //RequiredReportIndex > 0; FirstDay.Content = new Image { Source = FirstDay.IsEnabled ? PRSDesktop.Resources.first.AsBitmapImage(32, 32) : PRSDesktop.Resources.first.Fade(0.2F).AsBitmapImage(32, 32) }; PrevDay.IsEnabled = RequiredReports.Count > 0 && DatePicker.SelectedDate > RequiredReports[0].Date; //RequiredReportIndex > 0; PrevDay.Content = new Image { Source = PrevDay.IsEnabled ? PRSDesktop.Resources.back.AsBitmapImage(32, 32) : PRSDesktop.Resources.back.Fade(0.2F).AsBitmapImage(32, 32) }; NextDay.IsEnabled = RequiredReports.Count > 0 && DatePicker.SelectedDate < RequiredReports[RequiredReports.Count - 1].Date; //RequiredReportIndex < RequiredReports.Count - 1; NextDay.Content = new Image { Source = NextDay.IsEnabled ? PRSDesktop.Resources.next.AsBitmapImage(32, 32) : PRSDesktop.Resources.next.Fade(0.2F).AsBitmapImage(32, 32) }; LastDay.IsEnabled = RequiredReports.Count > 0 && DatePicker.SelectedDate < RequiredReports[RequiredReports.Count - 1].Date; //RequiredReportIndex < RequiredReports.Count - 1; LastDay.Content = new Image { Source = LastDay.IsEnabled ? PRSDesktop.Resources.last.AsBitmapImage(32, 32) : PRSDesktop.Resources.last.Fade(0.2F).AsBitmapImage(32, 32) }; Calendar.SelectedDate = DatePicker.SelectedDate.Value.Date; // RequiredReports[RequiredReportIndex].Item2.Date; //Assignments.Refresh(); //Assignments.StartHour = 0; //Assignments.EndHour = 24; var start = TimeSpan.FromHours(6); var finish = TimeSpan.FromHours(18); if ((DatePicker.SelectedDate.Value == DateTime.Today) && (DateTime.Now.TimeOfDay > finish)) finish = DateTime.Now.TimeOfDay; String notes = ""; var blocks = Calendar.GetRoster(Employee.ID, DatePicker.SelectedDate.Value)?.GetBlocks(DatePicker.SelectedDate.Value, TimeSpan.FromSeconds(0), TimeSpan.FromDays(1)); if (blocks?.Any() == true) { start = blocks.Aggregate(start, (time, block) => time.Ticks < block.Start.Ticks ? time : block.Start); finish = blocks.Aggregate(finish, (time, block) => time.Ticks > block.Finish.Ticks ? time : block.Start); } var requiredreport = RequiredReports.FirstOrDefault(x => x.Date.Equals(DatePicker.SelectedDate)); //[RequiredReportIndex]; if (requiredreport != null) { start = start > requiredreport.Start ? requiredreport.Start : start; finish = finish < requiredreport.Finish ? requiredreport.Finish : finish; notes = requiredreport.Notes; } else { var row = new Client().Query( new Filter(x => x.Date).IsEqualTo(DatePicker.SelectedDate.Value).And(x => x.EmployeeLink.UserLink.ID).IsEqualTo(ClientFactory.UserGuid), new Columns( x => x.Start, x => x.Finish, x => x.Notes ) ).Rows.FirstOrDefault(); if (row != null) { notes = requiredreport.Notes; var tstart = row.Get(x => x.Start); start = start > tstart ? tstart : start; var tfinish = row.Get(x => x.Finish); finish = finish < tfinish ? tfinish : finish; } } if (IsReady) Calendar.Refresh(); Calendar.GetActiveWindow(Employee.ID, DatePicker.SelectedDate.Value, ref start, ref finish); Calendar.StartHour = start.Floor(TimeSpan.FromHours(1)).Hours; Calendar.EndHour = finish.Ceiling(TimeSpan.FromHours(1)).Hours; Notes.Value = notes; SelectAssignment(null); EnableScreen(requiredreport != null); } private void EnableScreen(bool enabled) { Title.IsEnabled = enabled && (SelectedAssignment != null); ActivityNotes.IsEnabled = enabled && (SelectedAssignment != null); Start.IsEnabled = enabled && (SelectedAssignment != null); Duration.IsEnabled = enabled && (SelectedAssignment != null); Finish.IsEnabled = enabled && (SelectedAssignment != null); Kanban.IsEnabled = enabled && (SelectedAssignment != null); ITP.IsEnabled = enabled && (SelectedAssignment != null); Job.IsEnabled = enabled && (SelectedAssignment != null); Activity.IsEnabled = enabled && (SelectedAssignment != null); Notes.IsEnabled = enabled; ProcessWindowTrackers.IsEnabled = enabled; ImportEmails.IsEnabled = enabled; ConfirmTimesheet.IsEnabled = enabled; Calendar.IsEnabled = enabled; } private void Splitpanel_OnChanged(object sender, DynamicSplitPanelSettings e) { _settings.ActivityColumnWidth = e.AnchorWidth; new UserConfiguration().Save(_settings); } private void ConfirmTimesheet_Click(object sender, RoutedEventArgs e) { var bBlankActivities = false; var bOverlapping = true; var rows = Calendar.GetAssignments(Employee.ID, DatePicker.SelectedDate.Value); foreach (var row in rows) { var id = row.Get(c => c.ID); var date = row.Get(c => c.Date); var start = row.Get(c => c.Actual.Start); var finish = row.Get(c => c.Actual.Finish); if (rows.Any(r => r.Get(c => c.ID) != id && r.Get(c => c.Date) == date && r.Get(c => c.Actual.Finish) > start && r.Get(c => c.Actual.Start) < finish )) bOverlapping = false; if (Security.IsAllowed()) bBlankActivities = rows.Any(r => !Entity.IsEntityLinkValid(x => x.ActivityLink, r)); } if (!bOverlapping) { MessageBox.Show("This report contains overlapping blocks!\n\nPlease correct before confirming this timesheet."); return; } if (bBlankActivities) { MessageBox.Show("All Daily Report entries must have a valid Activity Code!\n\nPlease correct before confirming this timesheet."); return; } if (MessageBox.Show( "Confirming your timesheet will prevent you from making any further changes or additions.\n\nAre you sure you want to do this?", "Confirm TimeSheet", MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes) return; using (new WaitCursor()) { var timesheets = new Client().Query( new Filter(x => x.EmployeeLink.ID).IsEqualTo(Employee.ID).And(x => x.Date).IsEqualTo(Calendar.SelectedDate), new Columns(x => x.ID, x => x.Confirmed) ).Rows.Select(r => r.ToObject()).ToArray(); for (var i = 0; i < timesheets.Length; i++) timesheets[i].Confirmed = DateTime.Now; new Client().Save(timesheets, "Confirmed by Daily Activity Report"); RequiredReports.RemoveAll(x => x.Date.Equals(Calendar.SelectedDate)); if (!RequiredReports.Any()) { var start = TimeSpan.FromSeconds(0); var finish = TimeSpan.FromDays(1); var blocks = Calendar.GetRoster(Employee.ID, DatePicker.SelectedDate.Value)?.GetBlocks(DatePicker.SelectedDate.Value, start, finish); if (blocks?.Any() == true) { start = blocks.Aggregate(start, (time, block) => time.Ticks < block.Start.Ticks ? time : block.Start); finish = blocks.Aggregate(finish, (time, block) => time.Ticks > block.Finish.Ticks ? time : block.Start); } RequiredReports.Add(new RequiredReport(Guid.Empty, DateTime.Today, start, finish, "")); ConfirmDock.Visibility = Visibility.Collapsed; } GotoCurrentRequiredReport(); OnTimeSheetConfirmed?.Invoke(new TimeSheetConfirmedArgs { Date = Calendar.SelectedDate }); } } private void GotoCurrentRequiredReport() { if (RequiredReportIndex >= RequiredReports.Count) RequiredReportIndex = RequiredReports.Count - 1; SetCurrentDay(RequiredReports[RequiredReportIndex].Date); } private void LoadKanbans(string category = null) { if (!string.IsNullOrWhiteSpace(category)) _taskcategory = category; Tasks.ItemsSource = null; var filter = new Filter(x => x.Kanban.Closed).IsEqualTo(DateTime.MinValue).And(x => x.Kanban.Category) .IsEqualTo(_taskcategory); if (ShowPublicTasks.IsChecked != true) filter = filter.And(x => x.Kanban.Private).IsEqualTo(true); filter = filter.And(x => x.Employee.UserLink.ID).IsEqualTo(ClientFactory.UserGuid); filter = filter.And(x => x.Assignee).IsEqualTo(true); new Client().Query( filter, new Columns ( x => x.Kanban.ID, x => x.Kanban.DueDate, x => x.Kanban.Completed, x => x.Kanban.Description, x => x.Kanban.Summary, x => x.Kanban.Category, x => x.Kanban.EmployeeLink.ID, x => x.Kanban.EmployeeLink.UserLink.ID, x => x.Kanban.EmployeeLink.Name, x => x.Kanban.ManagerLink.ID, x => x.Kanban.ManagerLink.UserLink.ID, x => x.Kanban.ManagerLink.Name, x => x.Kanban.Notes, x => x.Kanban.Title, x => x.Kanban.JobLink.ID, x => x.Kanban.JobLink.JobNumber, x => x.Kanban.JobLink.Name, x => x.Kanban.Type.Code, x => x.Kanban.Number ), new SortOrder(x => x.Kanban.DueDate), (kanbans, error) => { Dispatcher.Invoke(() => { foreach (var column in kanbans.Columns) column.ColumnName = column.ColumnName.Replace("Kanban.", ""); Tasks.ItemsSource = kanbans.Rows.Select(x => x.ToObject()); }); } ); } private void OpenTasks_Click(object sender, RoutedEventArgs e) { LoadKanbans("Open"); CurrentTasks.SetValue(Grid.RowProperty, 6); WaitingTasks.SetValue(Grid.RowProperty, 7); ClosedTasks.SetValue(Grid.RowProperty, 8); } private void CurrentTasks_Click(object sender, RoutedEventArgs e) { LoadKanbans("In Progress"); CurrentTasks.SetValue(Grid.RowProperty, 2); WaitingTasks.SetValue(Grid.RowProperty, 7); ClosedTasks.SetValue(Grid.RowProperty, 8); } private void WaitingTasks_Click(object sender, RoutedEventArgs e) { LoadKanbans("Waiting"); CurrentTasks.SetValue(Grid.RowProperty, 2); WaitingTasks.SetValue(Grid.RowProperty, 3); ClosedTasks.SetValue(Grid.RowProperty, 8); } private void ClosedTasks_Click(object sender, RoutedEventArgs e) { LoadKanbans("Complete"); CurrentTasks.SetValue(Grid.RowProperty, 2); WaitingTasks.SetValue(Grid.RowProperty, 3); ClosedTasks.SetValue(Grid.RowProperty, 4); } private void Tasks_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var startPoint = e.GetPosition(null); } // Helper to search up the VisualTree private static T FindAncestor(DependencyObject current) where T : DependencyObject { try { do { if (current is T) return (T)current; current = VisualTreeHelper.GetParent(current); } while (current != null); } catch (Exception e) { Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace)); } return null; } private void Tasks_MouseMove(object sender, MouseEventArgs e) { // Get the current mouse position var mousePos = e.GetPosition(null); var diff = startPoint - mousePos; if (e.LeftButton == MouseButtonState.Pressed && (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance || Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) { // Get the dragged ListViewItem var listView = sender as ListView; var depobj = (DependencyObject)e.OriginalSource; var kanban = listView.SelectedItem as Kanban; if (kanban != null) { var dragData = new DataObject("Comal.Classes.Kanban", kanban); DragDrop.DoDragDrop(depobj, dragData, DragDropEffects.Move); } } } private void NewTask_Click(object sender, RoutedEventArgs e) { var task = new Kanban(); task.EmployeeLink.ID = Employee.ID; task.ManagerLink.ID = Employee.ID; task.Private = true; task.Category = "Open"; if(DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(Kanban)).EditItems(new[] { task })) { using (new WaitCursor()) { /*var task = new Kanban(); task.Title = form.Title; task.Description = form.Description; task.DueDate = DateTime.Today; task.EmployeeLink.ID = Employee.ID; task.ManagerLink.ID = Employee.ID; task.Category = "Open"; task.Private = true;*/ new Client().Save(task, "Created from Daily Report screen"); /*var subscriber = new KanbanSubscriber(); subscriber.Kanban.ID = task.ID; subscriber.Employee.ID = Employee.ID; subscriber.Assignee = true; subscriber.Manager = true; new Client().Save(subscriber, "");*/ LoadKanbans(); } } //var form = new QuickTask(); //if (form.ShowDialog() == true) } private void ShowPublicTasks_Checked(object sender, RoutedEventArgs e) { LoadKanbans(); } private void Tasks_MouseDoubleClick(object sender, MouseButtonEventArgs e) { var listview = sender as ListView; if (listview == null) return; var kanban = listview.SelectedItem as Kanban; if (kanban == null) return; if (kg == null) kg = new KanbanGrid(); var bEdited = kg.EditItems(new[] { kanban }); if (bEdited) LoadKanbans(); } private void TaskMenu_ContextMenuOpening(object sender, ContextMenuEventArgs e) { var kanban = (sender as Border).Tag as Kanban; var menu = (sender as Border).ContextMenu; menu.Items.Clear(); if (!string.Equals(_taskcategory, "Open")) MoveToOpen = CreateTaskMenu(menu, "Move To [Open Tasks]", kanban, MoveTask_Click); if (!string.Equals(_taskcategory, "In Progress")) MoveToCurrent = CreateTaskMenu(menu, "Move To [Tasks In Progress]", kanban, MoveTask_Click); else menu.Items.Add(new Separator()); if (!string.Equals(_taskcategory, "Waiting")) MoveToWaiting = CreateTaskMenu(menu, "Move To [Waiting For Others]", kanban, MoveTask_Click); else menu.Items.Add(new Separator()); if (!string.Equals(_taskcategory, "Complete")) MoveToComplete = CreateTaskMenu(menu, "Move To [Completed Tasks]", kanban, MoveTask_Click); menu.Items.Add(new Separator()); CreateTaskMenu(menu, "Change Due Date", kanban, ChangeKanbanDueDate_Click); } private MenuItem CreateTaskMenu(ContextMenu menu, string header, Kanban kanban, RoutedEventHandler action) { var item = new MenuItem(); item.Header = header; item.Tag = kanban; item.Click += action; menu.Items.Add(item); return item; } private void ChangeKanbanDueDate_Click(object sender, RoutedEventArgs e) { var kanban = (sender as MenuItem)?.Tag as Kanban; var date = kanban.DueDate; if (DateEdit.Execute("Change Due Date", ref date)) { kanban.DueDate = date; new Client().Save(kanban, ""); LoadKanbans(); } } private void MoveTask_Click(object sender, RoutedEventArgs e) { var kanban = (sender as MenuItem)?.Tag as Kanban; if (kanban == null) return; var category = sender == MoveToComplete ? "Complete" : sender == MoveToWaiting ? "Waiting" : sender == MoveToCurrent ? "In Progress" : "Open"; kanban.Category = category; new Client().Save(kanban, ""); LoadKanbans(); } private void Assignments_OnItemEditing(object sender, ICalendarHandledEventArgs args) { args.Status = CalendarHandledStatus.Handled; } } }