using System; using System.Collections.Generic; using System.Linq.Expressions; using InABox.Core; namespace Comal.Classes { public class KanbanDocumentCount : CoreAggregate { public override Expression> Aggregate => x => x.ID; public override AggregateCalculation Calculation => AggregateCalculation.Count; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>> () { { KanbanDocument => KanbanDocument.EntityLink.ID, Kanban => Kanban.ID } }; } public class KanbaAssignmentDuration : CoreAggregate { public override Expression> Aggregate => x => x.Actual.Duration; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { Assignment => Assignment.Task.ID, Kanban => Kanban.ID } }; } public enum KanbanStatus { Open, InProgress, Waiting, Complete } [UserTracking("Task Management")] [Caption("Tasks")] public class Kanban : Entity, IPersistent, IRemotable, IKanban, IScheduleAction, IOneToMany, INumericAutoIncrement, IOneToMany, ILicense, IExportable, IImportable, IJobScopedItem { private bool bChanging; [NullEditor] public DeliveryLink Delivery { get; set; } [IntegerEditor(Editable = Editable.Disabled)] [EditorSequence(-1)] public int Number { get; set; } [TextBoxEditor] [EditorSequence(0)] public string Title { get; set; } [EditorSequence(1)] public JobLink JobLink { get; set; } private class JobScopeLookup : LookupDefinitionGenerator { public override Filter DefineFilter(Kanban[] items) { var item = items?.Length == 1 ? items[0] : null; if (item != null) return new Filter(x => x.Job.ID).IsEqualTo(item.JobLink.ID).And(x => x.Status.Approved).IsEqualTo(true); return new Filter(x => x.ID).None(); } public override Columns DefineFilterColumns() => new Columns(x => x.JobLink.ID); } [LookupDefinition(typeof(JobScopeLookup))] [EditorSequence(2)] public JobScopeLink JobScope { get; set; } [RichTextEditor] [EditorSequence(3)] public string Description { get; set; } [NotesEditor] [EditorSequence(4)] public string[] Notes { get; set; } = Array.Empty(); [MemoEditor(Visible = Visible.Optional, Editable = Editable.Hidden)] [EditorSequence(5)] public string Summary { get; set; } [EditorSequence(6)] [Caption("Task Type")] public KanbanTypeLink Type { get; set; } [DateEditor] [EditorSequence(7)] public DateTime DueDate { get; set; } = DateTime.Today; // Same lookup right now used for manager and employee. private class EmployeeLookup : LookupDefinitionGenerator { public override Filter DefineFilter(Kanban[] items) { var result = LookupFactory.DefineFilter(); result.Ands.Add(new Filter(x => x.CanAllocateTasks).IsEqualTo(true)); return result; } public override Columns DefineFilterColumns() => new Columns(); } [LookupDefinition(typeof(EmployeeLookup))] [EditorSequence(8)] [Caption("Assigned To")] public EmployeeLink EmployeeLink { get; set; } [EditorSequence(9)] [Caption("Allocated By")] [LookupDefinition(typeof(EmployeeLookup))] public EmployeeLink ManagerLink { get; set; } [DateTimeEditor(Editable = Editable.Hidden)] [EditorSequence(10)] public DateTime Completed { get; set; } = DateTime.MinValue; [EditorSequence("Other", 1)] [Caption("Equipment Item")] public EquipmentLink Equipment { get; set; } [DateEditor] [EditorSequence("Other", 2)] public DateTime StartDate { get; set; } = DateTime.Today; [DurationEditor] [EditorSequence("Other", 3)] public TimeSpan EstimatedTime { get; set; } = TimeSpan.FromHours(1); [Aggregate(typeof(KanbaAssignmentDuration))] [EditorSequence("Other", 4)] public TimeSpan ActualTime { get; set; } [CheckBoxEditor] [EditorSequence("Other", 5)] public bool Private { get; set; } [EditorSequence("Other", 6)] [CheckBoxEditor] public bool Locked { get; set; } [EditorSequence("Other", 7)] [LoggableProperty] [EnumLookupEditor(typeof(KanbanStatus))] public KanbanStatus Status { get; set; } [SecondaryIndex] [NullEditor] public DateTime Closed { get; set; } = DateTime.MinValue; [NullEditor] [Aggregate(typeof(KanbanDocumentCount))] public int Attachments { get; set; } [NullEditor] [Obsolete("Replaced with Status",true)] public string Category { get; set; } public Expression> AutoIncrementField() { return x => x.Number; } public Filter? AutoIncrementFilter() { return null; } [NullEditor] public ScheduleLink ScheduleLink { get; set; } private bool IsCompleted(object? value) { if (value == null) return false; if (value is DateTime dateTime) return !dateTime.IsEmpty(); if (value is KanbanStatus category) return category == KanbanStatus.Complete; return false; } protected override void DoPropertyChanged(string name, object? before, object? after) { base.DoPropertyChanged(name, before, after); if (bChanging) return; bChanging = true; if (name.Equals(nameof(Completed))) // set the completed date { Status = IsCompleted(after) ? KanbanStatus.Complete : IsCompleted(Status) ? KanbanStatus.InProgress : Status; } else if (name.Equals(nameof(Status))) // set the completed date { Completed = IsCompleted(after) ? IsCompleted(Completed) ? Completed : DateTime.Now : DateTime.MinValue; } else if (name.Equals(nameof(Description))) { var summary = after as string; Summary = CoreUtils.StripHTML(summary); } bChanging = false; } static Kanban() { Classes.JobScope.LinkScopeProperties(); } } }