Browse Source

Made Kanban.CreatedBy to be optionally visible
Fixed crashes in Job, Bill, Tasks and Digital Forms Modules
Improved Issues Grid

frankvandenbos 10 tháng trước cách đây
mục cha
commit
6278b1108f

+ 7 - 0
prs.classes/Entities/Kanban/Kanban.cs

@@ -165,6 +165,13 @@ namespace Comal.Classes
         [Obsolete("Replaced with Status",true)]
         public string Category { get; set; }
         
+        [TextBoxEditor(Editable = Editable.Hidden)]
+        public override string CreatedBy
+        {
+            get => base.CreatedBy;
+            set => base.CreatedBy = value;
+        }
+        
         public Expression<Func<Kanban, int>> AutoIncrementField()
         {
             return x => x.Number;

+ 4 - 1
prs.desktop/Dashboards/Common/DigitalFormsDashboard.xaml.cs

@@ -596,7 +596,8 @@ public partial class DigitalFormsDashboard : UserControl,
 
         string changeableJobLink = "";
         string changeableScopeLink = "";
-        if (changeableLinks.TryGetValue(FormType, out Tuple<string,string> _tuple))
+        
+        if ((FormType != null) && changeableLinks.TryGetValue(FormType, out Tuple<string,string> _tuple))
         {
             changeableJobLink = _tuple.Item1;
             changeableScopeLink = _tuple.Item2;
@@ -1248,6 +1249,8 @@ public partial class DigitalFormsDashboard : UserControl,
 
     private string GetJobLink(string prefix, Type type, bool recursive)
     {
+        if (type == null)
+            return "null";
         var props = type.GetProperties().Where(x =>
             x.PropertyType.BaseType != null && x.PropertyType.BaseType.IsGenericType &&
             x.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(EntityLink<>));

+ 111 - 20
prs.desktop/Forms/Issues/IssuesGrid.cs

@@ -13,6 +13,7 @@ using System.Linq;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using System.Windows.Media;
 
 namespace PRSDesktop.Forms.Issues;
 
@@ -22,24 +23,34 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
 
     public IQueryProviderFactory ClientFactory { get; set; }
 
-    private IQueryProvider<Kanban> _client;
-    private IQueryProvider<Kanban> Client
+    private IQueryProvider<Kanban>? _kanbanClient;
+    private IQueryProvider<Kanban> KanbanClient
     {
         get
         {
-            _client ??= ClientFactory.Create<Kanban>();
-            return _client;
+            _kanbanClient ??= ClientFactory.Create<Kanban>();
+            return _kanbanClient;
+        }
+    }
+    
+    private IQueryProvider<Job>? _jobClient;
+    private IQueryProvider<Job> JobClient
+    {
+        get
+        {
+            _jobClient ??= ClientFactory.Create<Job>();
+            return _jobClient;
         }
     }
 
     public Guid CustomerID { get; set; }
 
-    public static CustomProperty CustomerProperty = new CustomProperty
-    {
-        Name = "CustomerID",
-        PropertyType = typeof(string),
-        ClassType = typeof(Kanban)
-    };
+    // public static CustomProperty CustomerProperty = new CustomProperty
+    // {
+    //     Name = "CustomerID",
+    //     PropertyType = typeof(string),
+    //     ClassType = typeof(Kanban)
+    // };
 
     public IssuesGrid() : base()
     {
@@ -53,6 +64,38 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
 
         ActionColumns.Add(new DynamicMenuColumn(BuildMenu) { Position = DynamicActionColumnPosition.End });
     }
+    
+    private class UIComponent : DynamicGridGridUIComponent<Kanban>
+    {
+        private IssuesGrid Grid;
+
+        public UIComponent(IssuesGrid grid)
+        {
+            Grid = grid;
+            Parent = grid;
+        }
+
+        protected override Brush? GetCellBackground(CoreRow row, DynamicColumnBase column)
+        {
+            var status = row.Get<Kanban, KanbanStatus>(x => x.Status);
+            var color = status == KanbanStatus.Open
+                ? Colors.Orange
+                : status == KanbanStatus.InProgress
+                    ? Colors.Plum
+                    : status == KanbanStatus.Waiting
+                        ? Colors.LightGreen
+                        : Colors.Silver;
+            return color.ToBrush(0.5);
+        }
+    }
+
+    
+    protected override IDynamicGridUIComponent<Kanban> CreateUIComponent()
+    {
+        return new UIComponent(this);
+    }
+    
+
 
     protected override void Init()
     {
@@ -63,6 +106,8 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
         options.Clear();
         options.AddRows = true;
         options.EditRows = true;
+        options.FilterRows = true;
+        options.HideDatabaseFilters = true;
     }
 
     private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
@@ -99,7 +144,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
         var item = base.CreateItem();
         item.UserProperties["CustomerID"] = CustomerID.ToString();
         item.Notes = [
-            $"Created on PRS {CoreUtils.GetVersion()}"
+            $"Created on PRS {CoreUtils.GetVersion()} by {App.EmployeeName} ({App.EmployeeEmail})"
             ];
         // item.Status = KanbanStatus.Open;
         return item;
@@ -226,8 +271,12 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
     protected override DynamicGridColumns LoadColumns()
     {
         var columns = new DynamicGridColumns<Kanban>();
-        columns.Add(x => x.Number);
+        columns.Add(x => x.Number, caption: "Ticket", width: 60, alignment: Alignment.MiddleCenter);
         columns.Add(x => x.Title);
+        columns.Add(x => x.CreatedBy, caption: "Created By", width: 150);
+        columns.Add(x => x.EmployeeLink.Name, caption: "Assigned To", width: 150);
+        columns.Add(x => x.Type.Description, caption: "Type", width: 100, alignment: Alignment.MiddleCenter);
+        columns.Add(x => x.Status, caption: "Status", width: 80, alignment: Alignment.MiddleCenter);
         return columns;
     }
 
@@ -245,7 +294,11 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
         CancellationToken token, Action<CoreTable?, Exception?> action)
     {
         criteria.Add(new Filter<Kanban>(x => x.Closed).IsEqualTo(Guid.Empty));
-        criteria.Add(new Filter<Kanban>(CustomerProperty).IsEqualTo(CustomerID.ToString()));
+        criteria.Add(new Filter<Kanban>(x => x.Status).IsNotEqualTo(KanbanStatus.Complete));
+        criteria.Add(new Filter<Kanban>(x => x.JobLink.Customer.ID).IsEqualTo(CustomerID));
+        
+        //criteria.Add(new Filter<Kanban>(CustomerProperty).IsEqualTo(CustomerID.ToString()));
+        
         if(Options.PageSize > 0)
         {
             var inSort = sort;
@@ -260,7 +313,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
                 {
                     try
                     {
-                        var data = Client.Query(filter, columns, inSort, page);
+                        var data = KanbanClient.Query(filter, columns, inSort, page);
                         data.Offset = page.Offset;
                         IsPaging = data.Rows.Count == page.Limit;
 
@@ -288,7 +341,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
         }
         else
         {
-            Client.Query(criteria.Combine(), columns, sort, null, action);
+            KanbanClient.Query(criteria.Combine(), columns, sort, null, action);
         }
     }
 
@@ -301,7 +354,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
             var filter = new Filter<Kanban>(x => x.ID).InList(chunk.Select(x => x.Get<Kanban, Guid>(x => x.ID)).ToArray());
 
             var columns = DynamicGridUtils.LoadEditorColumns(Columns.None<Kanban>());
-            var data = Client.Query(filter, columns);
+            var data = KanbanClient.Query(filter, columns);
             results.AddRange(data.ToObjects<Kanban>());
         }
 
@@ -311,7 +364,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
     public override Kanban LoadItem(CoreRow row)
     {
         var id = row.Get<Kanban, Guid>(x => x.ID);
-        return Client.Query(
+        return KanbanClient.Query(
             new Filter<Kanban>(x => x.ID).IsEqualTo(id),
             DynamicGridUtils.LoadEditorColumns(Columns.None<Kanban>())).ToObjects<Kanban>().FirstOrDefault()
             ?? throw new Exception($"No Kanban with ID {id}");
@@ -319,12 +372,50 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
 
     public override void SaveItem(Kanban item)
     {
-        Client.Save(item, "Edited by User");
+        CheckJob(item);
+        KanbanClient.Save(item, "Edited by User");
+    }
+
+    private void CheckJob(Kanban item)
+    {
+        if (item.ID == Guid.Empty)
+        {
+            item.CreatedBy = App.EmployeeName;
+            
+            // Check if there is an open Project Job (ie installation or periodic billing) for this Client
+            var job = JobClient.Query(
+                new Filter<Job>(x => x.Customer.ID).IsEqualTo(CustomerID)
+                    .And(x => x.JobType).IsEqualTo(JobType.Project)
+                    .And(x => x.JobStatus.Active).IsEqualTo(true),
+                Columns.None<Job>()
+                    .Add(x => x.ID)
+                    .Add(x=>x.DefaultScope.ID)
+            ).ToObjects<Job>().FirstOrDefault();
+            
+            // No Job ?  Create a service job for this ticket
+            if (job == null)
+            {
+                job = new Job();
+                job.Name = item.Title;
+                job.Customer.ID = CustomerID;
+                job.JobType = JobType.Service;
+                job.Notes = item.Notes?.ToList().ToArray() ?? [];
+                job.UserProperties.Clear();
+                JobClient.Save(job, "Created by Client Issues Screen");
+            }
+
+            // Created Tickets should always have a job #!
+            item.JobLink.ID = job.ID;
+            item.JobScope.ID = job.DefaultScope.ID;
+        }
     }
 
     public override void SaveItems(IEnumerable<Kanban> items)
     {
-        Client.Save(items, "Edited by User");
+        var list = items.ToArray();
+        foreach (var item in list)
+            CheckJob(item);
+        KanbanClient.Save(list, "Edited by User");
     }
 
     public override void DeleteItems(params CoreRow[] rows)
@@ -340,7 +431,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
             deletes.Add(delete);
         }
 
-        Client.Delete(deletes, "Deleted on User Request");
+        KanbanClient.Delete(deletes, "Deleted on User Request");
     }
 
     #endregion

+ 3 - 2
prs.desktop/Forms/Issues/IssuesWindow.xaml

@@ -5,8 +5,9 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:PRSDesktop.Forms.Issues"
         mc:Ignorable="d"
-        Title="PRS Issues" Height="450" Width="800"
-        Loaded="Window_Loaded">
+        Title="PRS Issues" Height="800" Width="1200"
+        Loaded="Window_Loaded"
+        WindowStartupLocation="CenterScreen">
     <Grid Margin="5">
         <local:IssuesGrid x:Name="Grid"/>
     </Grid>

+ 20 - 8
prs.desktop/Forms/Issues/IssuesWindow.xaml.cs

@@ -61,34 +61,46 @@ public partial class IssuesWindow : Window
             MessageWindow.ShowMessage("Could not connect to PRS digital database.", "Connection error.");
             return;
         }
+        
+        // var transport = new RpcClientSocketTransport(["127.0.0.1:8000"]);
+        // var client = new RpcClient<Kanban>(transport);
+        // if(client.Validate("frank", "frank", Guid.Empty).Status != InABox.Clients.ValidationStatus.VALID)
+        // {
+        //     MessageWindow.ShowMessage("Could not connect to PRS digital database.", "Connection error.");
+        //     return;
+        // }
 
         var issues = new IssuesWindow();
 
         // Save the old property if it exists.
-        var prop = DatabaseSchema.Property(typeof(Kanban), IssuesGrid.CustomerProperty.Name) as CustomProperty;
+        //var prop = DatabaseSchema.Property(typeof(Kanban), IssuesGrid.CustomerProperty.Name) as CustomProperty;
 
         // Load the new property.
-        DatabaseSchema.Load([IssuesGrid.CustomerProperty]);
+        //DatabaseSchema.Load([IssuesGrid.CustomerProperty]);
 
         issues.Grid.CustomerID = customerID;
         issues.ClientFactory = new _Factory(transport);
         issues.ShowDialog();
 
         // Return DB schema to what it was.
-        DatabaseSchema.Unload([IssuesGrid.CustomerProperty]);
-        if(prop is not null)
-        {
-            DatabaseSchema.Load([prop]);
-        }
+        // DatabaseSchema.Unload([IssuesGrid.CustomerProperty]);
+        // if(prop is not null)
+        // {
+        //     DatabaseSchema.Load([prop]);
+        // }
     }
 
     private class _Factory(IRpcClientTransport transport) : IQueryProviderFactory
     {
+        public bool ExcludeCustomProperties => true;
+        
         IRpcClientTransport Transport = transport;
 
         public InABox.Core.IQueryProvider Create(Type T)
         {
-            return (Activator.CreateInstance(typeof(RpcClient<>).MakeGenericType(T), Transport) as IClient)!;
+            var result = (IClient)Activator.CreateInstance(typeof(RpcClient<>).MakeGenericType(T), Transport);
+            result.ExcludeCustomProperties = ExcludeCustomProperties;
+            return result;
         }
     }
 }

+ 1 - 1
prs.desktop/prsdesktop.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 #define MyAppName "PRS Desktop"
-#define MyAppVersion "8.28"
+#define MyAppVersion "8.28b"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSDesktop.exe"

+ 1 - 1
prs.licensing/PRSLicensing.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 #define MyAppName "PRS Licensing"
-#define MyAppVersion "8.28"
+#define MyAppVersion "8.28b"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSLicensing.exe"

+ 1 - 1
prs.server/PRSServer.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 #define MyAppName "PRS Server"
-#define MyAppVersion "8.28"
+#define MyAppVersion "8.28b"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSServer.exe"

+ 1 - 2
prs.stores/JobStore.cs

@@ -24,8 +24,7 @@ namespace Comal.Stores
                             final = account;
                     }
                 }
-
-                entity.Account.Synchronise(final);
+                entity.Account.Synchronise(final ?? new Customer());
             }
 
             StoreUtils.Geocode(entity.SiteAddress);