Browse Source

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

frankvandenbos 6 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);