Browse Source

Merge remote-tracking branch 'origin/kenric' into nick

Nick-PRSDigital@bitbucket.org 2 years ago
parent
commit
3e651aaa75

+ 10 - 1
prs.classes/Entities/Invoice/Invoice.cs

@@ -81,7 +81,7 @@ namespace Comal.Classes
     }
 
     [UserTracking("Accounts Receivable")]
-    public class Invoice : Entity, IPersistent, IRemotable, INumericAutoIncrement<Invoice>, ILicense<AccountsReceivableLicense>, IExportable
+    public class Invoice : Entity, IPersistent, IRemotable, INumericAutoIncrement<Invoice>, ILicense<AccountsReceivableLicense>, IExportable, IPostable
     {
         [EditorSequence(1)]
         [IntegerEditor(Visible = Visible.Default, Editable = Editable.Enabled)]
@@ -136,6 +136,14 @@ namespace Comal.Classes
         [Formula(typeof(InvoiceBalance))]
         public double Balance { get; set; }
 
+        [NullEditor]
+        [LoggableProperty]
+        public PostedStatus PostedStatus { get; set; }
+
+        [NullEditor]
+        [LoggableProperty]
+        public DateTime Posted { get; set; }
+
         public Expression<Func<Invoice, int>> AutoIncrementField()
         {
             return x => x.Number;
@@ -152,6 +160,7 @@ namespace Comal.Classes
             JobLink = new JobLink();
             CustomerLink = new CustomerLink();
             Date = DateTime.Today;
+            PostedStatus = PostedStatus.NeverPosted;
         }
 
         public override string ToString()

+ 4 - 5
prs.classes/PRSClasses.csproj

@@ -11,11 +11,6 @@
       <DefineConstants>TRACE; </DefineConstants>
     </PropertyGroup>
 
-    <ItemGroup>
-      <ProjectReference Include="..\..\InABox\InABox.Configuration\InABox.Configuration.csproj" />
-      <ProjectReference Include="..\..\InABox\InABox.Core\InABox.Core.csproj" />
-    </ItemGroup>
-
     <ItemGroup>
       <None Remove=".gitignore" />
       <None Remove="PRSClasses\**" />
@@ -37,4 +32,8 @@
       <PackageReference Include="PropertyChanged.Fody" Version="3.4.1" />
     </ItemGroup>
 
+    <ItemGroup>
+      <ProjectReference Include="..\..\inabox\InABox.Core\InABox.Core.csproj" />
+    </ItemGroup>
+
 </Project>

+ 3 - 0
prs.desktop/MainWindow.xaml.cs

@@ -261,6 +261,7 @@ namespace PRSDesktop
                     Task.Run(() => CoreUtils.RegisterClasses(typeof(KanbanGrid).Assembly)),
                     Task.Run(() => CoreUtils.RegisterClasses()),
                     Task.Run(() => ComalUtils.RegisterClasses()),
+                    Task.Run(() => PRSSharedUtils.RegisterClasses()),
                     Task.Run(() => ReportUtils.RegisterClasses()),
                     Task.Run(() => ConfigurationUtils.RegisterClasses()),
                     Task.Run(() => DynamicGridUtils.RegisterClasses()),
@@ -652,6 +653,8 @@ namespace PRSDesktop
                         || Security.CanView<TimeSheet>()
                         || Security.CanView<GPSTracker>();
 
+            SetupActions.Clear();
+
             Progress.ShowModal(
                 new ProgressSection(
                     "Configuring Main Screen",

+ 6 - 2
prs.desktop/PRSDesktop.csproj

@@ -26,11 +26,13 @@
 
     <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - DB|AnyCPU'">
       <NoWarn />
+      <DefineConstants>$(DefineConstants);RPC</DefineConstants>
     </PropertyGroup>
     
     
     <ItemGroup>
         <None Remove="Resources\001-box.png" />
+        <None Remove="Resources\pdficon.png" />
         <Resource Include="Resources\001-box.png">
             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
         </Resource>
@@ -466,6 +468,9 @@
             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
         </Resource>
         <None Remove="Resources\pencil.png" />
+        <Resource Include="Resources\pdficon.png">
+          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+        </Resource>
         <Resource Include="Resources\pencil.png">
             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
         </Resource>
@@ -777,8 +782,6 @@
       <ProjectReference Include="..\..\InABox\InABox.Client.Local\InABox.Client.Local.csproj" />
       <ProjectReference Include="..\..\inabox\inabox.client.rest\InABox.Client.Rest\InABox.Client.Rest.csproj" />
       <ProjectReference Include="..\..\inabox\InABox.Client.RPC\InABox.Client.RPC.csproj" />
-      <ProjectReference Include="..\..\InABox\InABox.Configuration\InABox.Configuration.csproj" />
-      <ProjectReference Include="..\..\InABox\InABox.Core\InABox.Core.csproj" />
       <ProjectReference Include="..\..\InABox\InABox.Database.SQLite\InABox.Database.SQLite.csproj" />
       <ProjectReference Include="..\..\InABox\InABox.DatabaseProxy\InABox.DatabaseProxy.csproj" />
       <ProjectReference Include="..\..\InABox\InABox.Database\InABox.Database.csproj" />
@@ -786,6 +789,7 @@
       <ProjectReference Include="..\..\InABox\InABox.Logging\InABox.Logging.csproj" />
       <ProjectReference Include="..\..\InABox\InABox.Mailer.Exchange\InABox.Mailer.Exchange.csproj" />
       <ProjectReference Include="..\..\InABox\inabox.mailer.imap\InABox.Mailer.IMAP.csproj" />
+      <ProjectReference Include="..\..\inabox\InABox.Poster.CSV\InABox.Poster.CSV.csproj" />
       <ProjectReference Include="..\..\InABox\InABox.Scripting\InABox.Scripting.csproj" />
       <ProjectReference Include="..\..\InABox\inabox.wpf\InABox.Wpf.csproj" />
       <ProjectReference Include="..\PRS.Classes\PRSClasses.csproj" />

+ 0 - 18
prs.desktop/Panels/DailyReports/DailyReport.xaml.cs

@@ -259,24 +259,6 @@ namespace PRSDesktop
             else if (editor == ITP) ITP_OnDefineLookups(editor);
         }
 
-        public Document? FindDocument(string filename)
-        {
-            return new Client<Document>().Load(new Filter<Document>(x => x.FileName).IsEqualTo(filename)).FirstOrDefault();
-        }
-
-        public Document? GetDocument(Guid id)
-        {
-            Document? doc = null;
-            if (id != Guid.Empty)
-                doc = new Client<Document>().Load(new Filter<Document>(x => x.ID).IsEqualTo(id)).FirstOrDefault();
-            return doc;
-        }
-
-        public void SaveDocument(Document document)
-        {
-            new Client<Document>().Save(document, "");
-        }
-
         object?[] IDynamicEditorHost.GetItems() => new object?[] { SelectedAssignment };
 
         public BaseEditor? GetEditor(DynamicGridColumn column) => column.Editor.CloneEditor();

+ 0 - 6
prs.desktop/Panels/DataEntry/DataEntryPanel.xaml.cs

@@ -147,12 +147,6 @@ namespace PRSDesktop
             sender.LoadLookups(values);
         }
 
-        public Document? FindDocument(string filename) => null;
-
-        public Document? GetDocument(Guid id) => null;
-
-        public void SaveDocument(Document document) { }
-
         object?[] IDynamicEditorHost.GetItems() => Editor.Items;
 
         public BaseEditor? GetEditor(DynamicGridColumn column) => column.Editor.CloneEditor();

+ 41 - 1
prs.desktop/Panels/Invoices/InvoiceListGrid.cs

@@ -10,19 +10,59 @@ using InABox.Reports;
 using InABox.Core.Reports;
 using InABox.Wpf.Reports;
 using InABox.WPF;
+using System.Windows.Media.Imaging;
+using com.sun.org.apache.xpath.@internal;
 
 namespace PRSDesktop
 {
     public class InvoiceListGrid : DynamicDataGrid<Invoice>
     {
+        private static readonly BitmapImage? tick = PRSDesktop.Resources.tick.AsBitmapImage();
+        private static readonly BitmapImage? warning = PRSDesktop.Resources.warning.AsBitmapImage();
+
         public InvoiceListGrid()
         {
             Options.AddRange(DynamicGridOption.RecordCount, DynamicGridOption.AddRows, DynamicGridOption.DeleteRows, DynamicGridOption.EditRows,
-                DynamicGridOption.SelectColumns);
+                DynamicGridOption.SelectColumns, DynamicGridOption.FilterRows);
             AddButton("Print", PRSDesktop.Resources.printer.AsBitmapImage(), PrintInvoice2);
             AddButton("Email", PRSDesktop.Resources.email.AsBitmapImage(), EmailInvoice2);
             HiddenColumns.Add(x => x.CustomerLink.ID);
             HiddenColumns.Add(x => x.JobLink.ID);
+            HiddenColumns.Add(x => x.PostedStatus);
+            ActionColumns.Add(new DynamicImageColumn(Posted_Image, Posted_Click)
+            {
+                ToolTip = Posted_ToolTip
+            });
+        }
+
+        private bool Posted_Click(CoreRow? arg)
+        {
+            return false;
+        }
+
+        private FrameworkElement? Posted_ToolTip(DynamicActionColumn column, CoreRow? row)
+        {
+            if (row is null)
+            {
+                return column.TextToolTip("Invoice Processed Status");
+            }
+            return column.TextToolTip(row.Get<Invoice, PostedStatus>(x => x.PostedStatus) switch
+            {
+                PostedStatus.PostFailed => "Processing Failed",
+                PostedStatus.Posted => "Processed",
+                PostedStatus.NeverPosted or _ => "Not posted yet",
+            });
+        }
+
+        private BitmapImage? Posted_Image(CoreRow? arg)
+        {
+            if(arg is null) return tick;
+            return arg.Get<Invoice, PostedStatus>(x => x.PostedStatus) switch
+            {
+                PostedStatus.PostFailed => warning,
+                PostedStatus.Posted => tick,
+                PostedStatus.NeverPosted or _ => null,
+            };
         }
 
         public Guid JobID { get; set; }

+ 12 - 0
prs.desktop/Panels/Invoices/InvoicePanel.xaml.cs

@@ -1,9 +1,16 @@
 using System;
 using System.Collections.Generic;
+using System.Drawing;
 using System.Linq;
+using System.Windows;
 using System.Windows.Controls;
+using com.sun.corba.se.impl.protocol.giopmsgheaders;
+using com.sun.security.ntlm;
 using Comal.Classes;
+using InABox.Clients;
+using InABox.Configuration;
 using InABox.Core;
+using InABox.Core.Postable;
 using InABox.DynamicGrid;
 
 namespace PRSDesktop
@@ -43,6 +50,11 @@ namespace PRSDesktop
 
         public void CreateToolbarButtons(IPanelHost host)
         {
+            PostUtils.CreateToolbarButtons(
+                host,
+                () => Invoices.SelectedRows.Select(x => x.ToObject<Invoice>()),
+                () => Invoices.Refresh(false, true),
+                true);
         }
 
         public void Setup()

+ 0 - 6
prs.desktop/Panels/Products/Reservation Management/JobRequisitionPurchasing.xaml.cs

@@ -284,12 +284,6 @@ namespace PRSDesktop
             sender.LoadLookups(values);
         }
 
-        public Document? FindDocument(string filename) => null;
-
-        public Document? GetDocument(Guid id) => null;
-
-        public void SaveDocument(Document document) { }
-
         object?[] IDynamicEditorHost.GetItems() => Editor.Items;
 
         public BaseEditor? GetEditor(DynamicGridColumn column) => column.Editor.CloneEditor();

+ 0 - 18
prs.desktop/Panels/Quotes/QuoteDetails.xaml.cs

@@ -229,24 +229,6 @@ namespace PRSDesktop
             //else if (editor == ITP) ITP_OnDefineLookups(editor);
         }
 
-        public Document? FindDocument(string filename)
-        {
-            return new Client<Document>().Load(new Filter<Document>(x => x.FileName).IsEqualTo(filename)).FirstOrDefault();
-        }
-
-        public Document? GetDocument(Guid id)
-        {
-            Document? doc = null;
-            if (id != Guid.Empty)
-                doc = new Client<Document>().Load(new Filter<Document>(x => x.ID).IsEqualTo(id)).FirstOrDefault();
-            return doc;
-        }
-
-        public void SaveDocument(Document document)
-        {
-            new Client<Document>().Save(document, "");
-        }
-
         object?[] IDynamicEditorHost.GetItems() => new object?[] { new Quote() };
 
         public BaseEditor? GetEditor(DynamicGridColumn column) => column.Editor.CloneEditor();

+ 138 - 0
prs.desktop/Utils/PostUtils.cs

@@ -0,0 +1,138 @@
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Core;
+using InABox.Core.Postable;
+using InABox.DynamicGrid;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace PRSDesktop
+{
+    public static class PostUtils
+    {
+        private static readonly Inflector.Inflector inflector = new(new CultureInfo("en"));
+
+        public static void PostEntities<T>(IEnumerable<T> entities, Action refresh, Action? configurePost = null)
+            where T : Entity, IPostable, IRemotable, IPersistent, new()
+        {
+            var items = entities.AsList();
+            if (!items.Any())
+            {
+                MessageBox.Show($"Please select at least one {typeof(T).Name}.");
+                return;
+            }
+            try
+            {
+                if (PosterUtils.Process(items))
+                {
+                    MessageBox.Show("Processing successful!");
+                    refresh();
+                }
+                else
+                {
+                    MessageBox.Show("Processing failed.");
+                    refresh();
+                }
+            }
+            catch (RepostedException)
+            {
+                MessageBox.Show("At least one of the items you selected has already been processed. Processing cancelled.");
+            }
+            catch (PostCancelledException)
+            {
+                MessageBox.Show("Processing cancelled.");
+            }
+            catch (MissingSettingsException)
+            {
+                if (configurePost is not null && Security.CanConfigurePost<T>())
+                {
+                    if (MessageBox.Show($"Processing has not been configured for {inflector.Pluralize(typeof(T).Name)}. Would you like to configure this now?",
+                        "Configure Processing?", MessageBoxButton.YesNoCancel) == MessageBoxResult.Yes)
+                    {
+                        configurePost();
+                    }
+                    else
+                    {
+                        MessageBox.Show("Processing cancelled.");
+                    }
+                }
+                else
+                {
+                    MessageBox.Show($"Processing has not been configured for {inflector.Pluralize(typeof(T).Name)}!");
+                }
+            }
+            catch (Exception e)
+            {
+                MessageBox.Show($"Processing failed: {e.Message}");
+                refresh();
+            }
+        }
+
+        public static void CreateToolbarButtons<T>(IPanelHost host, Func<IEnumerable<T>> entities, Action refresh, Action? configurePost = null)
+            where T : Entity, IPostable, IRemotable, IPersistent, new()
+        {
+            var postSettings = PosterUtils.LoadPostableSettings<T>();
+            if (Security.CanPost<T>())
+            {
+                Bitmap? image = null;
+                if (postSettings.Thumbnail.ID != Guid.Empty)
+                {
+                    var icon = new Client<Document>()
+                        .Load(new Filter<Document>(x => x.ID).IsEqualTo(postSettings.Thumbnail.ID)).FirstOrDefault();
+                    if (icon is not null)
+                    {
+                        image = new ImageConverter().ConvertFrom(icon.Data) as Bitmap;
+                    }
+                }
+                host.CreatePanelAction(new PanelAction
+                {
+                    Caption = postSettings.ButtonName.NotWhiteSpaceOr($"Process {inflector.Pluralize(typeof(T).Name)}"),
+                    Image = image ?? PRSDesktop.Resources.edit,
+                    OnExecute = action =>
+                    {
+                        PostEntities(
+                            entities(),
+                            refresh,
+                            configurePost);
+                    }
+                });
+            }
+
+            if (configurePost is not null && Security.CanConfigurePost<T>())
+            {
+                host.CreateSetupAction(new PanelAction
+                {
+                    Caption = $"Configure {typeof(T).Name} Processing",
+                    OnExecute = action =>
+                    {
+                        configurePost();
+                    }
+                });
+            }
+        }
+
+        public static void ConfigurePost<T>()
+            where T : Entity, IPostable, IRemotable, IPersistent, new()
+        {
+            var postSettings = PosterUtils.LoadPostableSettings<T>();
+
+            var grid = (DynamicGridUtils.CreateDynamicGrid(typeof(DynamicGrid<>), typeof(PostableSettings)) as DynamicGrid<PostableSettings>)!;
+            if (grid.EditItems(new PostableSettings[] { postSettings }))
+            {
+                PosterUtils.SavePostableSettings<T>(postSettings);
+            }
+        }
+
+        public static void CreateToolbarButtons<T>(IPanelHost host, Func<IEnumerable<T>> entities, Action refresh, bool allowConfig)
+            where T : Entity, IPostable, IRemotable, IPersistent, new()
+        {
+            CreateToolbarButtons(host, entities, refresh, allowConfig ? ConfigurePost<T> : null);
+        }
+    }
+}

+ 1 - 0
prs.server/Engines/Database/DatabaseEngine.cs

@@ -151,6 +151,7 @@ namespace PRSServer
             StoreUtils.RegisterClasses();
             CoreUtils.RegisterClasses();
             ComalUtils.RegisterClasses();
+            PRSSharedUtils.RegisterClasses();
             ReportUtils.RegisterClasses();
             ConfigurationUtils.RegisterClasses();
 

+ 3 - 1
prs.server/Engines/GPS/GPSEngine.cs

@@ -22,6 +22,7 @@ using InABox.IPC;
 using InABox.Rpc;
 using PRSServer.Engines;
 using System.Timers;
+using PRS.Shared;
 
 namespace PRSServer
 {
@@ -279,7 +280,8 @@ namespace PRSServer
 
             CoreUtils.RegisterClasses();
             ComalUtils.RegisterClasses();
-            
+            PRSSharedUtils.RegisterClasses();
+
             //ClientFactory.SetClientType(typeof(IPCClient<>), Platform.GPSEngine, Version, DatabaseServerProperties.GetPipeName(Properties.Server,false));
             var transport = new RpcClientPipeTransport(DatabaseServerProperties.GetPipeName(Properties.Server, true));
             ClientFactory.SetClientType(typeof(RpcClient<>), Platform.GPSEngine, Version, transport);

+ 2 - 0
prs.server/Engines/WebEngine/WebEngine.cs

@@ -8,6 +8,7 @@ using InABox.Configuration;
 using InABox.Core;
 using InABox.Wpf.Reports;
 using InABox.Rpc;
+using PRS.Shared;
 
 namespace PRSServer
 {
@@ -40,6 +41,7 @@ namespace PRSServer
             StoreUtils.RegisterClasses();
             CoreUtils.RegisterClasses();
             ComalUtils.RegisterClasses();
+            PRSSharedUtils.RegisterClasses();
             ReportUtils.RegisterClasses();
             ConfigurationUtils.RegisterClasses();
             

+ 1 - 0
prs.server/Forms/Configuration.xaml.cs

@@ -54,6 +54,7 @@ namespace PRSServer
                 StoreUtils.RegisterClasses();
                 CoreUtils.RegisterClasses();
                 ComalUtils.RegisterClasses();
+                PRSSharedUtils.RegisterClasses();
                 ReportUtils.RegisterClasses();
                 ConfigurationUtils.RegisterClasses();
 

+ 0 - 2
prs.server/PRSServer.csproj

@@ -88,8 +88,6 @@
         <ProjectReference Include="..\..\InABox\InABox.Client.Local\InABox.Client.Local.csproj" />
         <ProjectReference Include="..\..\inabox\inabox.client.rest\InABox.Client.Rest\InABox.Client.Rest.csproj" />
         <ProjectReference Include="..\..\inabox\InABox.Client.RPC\InABox.Client.RPC.csproj" />
-        <ProjectReference Include="..\..\InABox\InABox.Configuration\InABox.Configuration.csproj" />
-        <ProjectReference Include="..\..\InABox\InABox.Core\InABox.Core.csproj" />
         <ProjectReference Include="..\..\InABox\InABox.Database.SQLite\InABox.Database.SQLite.csproj" />
         <ProjectReference Include="..\..\InABox\InABox.Database\InABox.Database.csproj" />
         <ProjectReference Include="..\..\InABox\inabox.logging.shared\InABox.Logging.Shared.csproj">

+ 1 - 1
prs.shared/PRS.Shared.csproj

@@ -10,8 +10,8 @@
 
   <ItemGroup>
     <ProjectReference Include="..\..\inabox\inabox.client.rest\InABox.Client.Rest\InABox.Client.Rest.csproj" />
-    <ProjectReference Include="..\..\InABox\InABox.Core\InABox.Core.csproj" />
     <ProjectReference Include="..\..\InABox\InABox.Database\InABox.Database.csproj" />
+    <ProjectReference Include="..\..\inabox\InABox.Poster.CSV\InABox.Poster.CSV.csproj" />
     <ProjectReference Include="..\..\InABox\InABox.WPF\InABox.Wpf.csproj" />
     <ProjectReference Include="..\PRS.Classes\PRSClasses.csproj" />
   </ItemGroup>

+ 19 - 0
prs.shared/PRSSharedUtils.cs

@@ -0,0 +1,19 @@
+using Comal.Classes;
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PRS.Shared
+{
+    [LibraryInitializer]
+    public static class PRSSharedUtils
+    {
+        public static void RegisterClasses()
+        {
+            CoreUtils.RegisterClasses(typeof(PRSSharedUtils).Assembly);
+        }
+    }
+}

+ 31 - 0
prs.shared/Posters/InvoiceCSVPoster.cs

@@ -0,0 +1,31 @@
+using Comal.Classes;
+using InABox.Core;
+using InABox.Poster.CSV;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace PRS.Shared
+{
+    public class InvoiceCSVPoster : ICSVPoster<Invoice>
+    {
+        public ICSVExport Process(IEnumerable<Invoice> entities)
+        {
+            var export = new CSVExport<Invoice>();
+            export.DefineMapping(new()
+            {
+                new("Number", x => x.Number),
+                new("Date", x => x.Date),
+                new("Description", x => x.Description),
+                new("ExTax", x => x.ExTax),
+                new("Tax", x => x.Tax),
+                new("IncTax", x => x.IncTax)
+            });
+            foreach(var entity in entities)
+            {
+                export.Add(entity);
+            }
+            return export;
+        }
+    }
+}

+ 0 - 1
prs.shared/Update.cs

@@ -4,7 +4,6 @@ using InABox.Core;
 using InABox.DynamicGrid;
 using InABox.WPF;
 using RestSharp;
-using Syncfusion.Windows.Shared;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;