Parcourir la source

Made Bill IPostable

Kenric Nugteren il y a 1 an
Parent
commit
2bfb7ed12d

+ 4 - 1
prs.classes/Entities/Bill/Bill.cs

@@ -4,7 +4,7 @@ using InABox.Core;
 namespace Comal.Classes
 {
     [UserTracking("Accounts Payable")]
-    public class Bill : Entity, IPersistent, IRemotable, ILicense<AccountsPayableLicense>, IScannable
+    public class Bill : Entity, IPersistent, IRemotable, ILicense<AccountsPayableLicense>, IScannable, IPostable
     {
         
         [EditorSequence(1)]
@@ -59,6 +59,9 @@ namespace Comal.Classes
         [IntegerEditor(Editable = Editable.Hidden)]
         public int Documents { get; set; }
 
+        public DateTime Posted { get; set; }
+        public PostedStatus PostedStatus { get; set; }
+
         protected override void Init()
         {
             base.Init();

+ 1 - 1
prs.desktop/Panels/Invoices/InvoicePanel.xaml.cs

@@ -65,7 +65,7 @@ namespace PRSDesktop
         {
             PostUtils.CreateToolbarButtons(
                 host,
-                () => Invoices.SelectedRows.Select(x => x.ToObject<Invoice>()),
+                () => (DataModel(Selection.Selected) as IDataModel<Invoice>)!,
                 () => Invoices.Refresh(false, true),
                 true);
         }

+ 2 - 1
prs.desktop/Panels/Suppliers/SupplierBillPanel.xaml

@@ -7,7 +7,8 @@
              xmlns:dynamicGrid="clr-namespace:InABox.DynamicGrid;assembly=InABox.Wpf"
              mc:Ignorable="d"
              d:DesignHeight="300" d:DesignWidth="1000">
-    <dynamicGrid:DynamicSplitPanel View="Combined" AnchorWidth="500">
+    <dynamicGrid:DynamicSplitPanel View="Combined" AnchorWidth="500"
+                                   x:Name="SplitPanel">
         
         <dynamicGrid:DynamicSplitPanel.Header>
             <Border BorderBrush="Gray" BorderThickness="0.75" Background="WhiteSmoke">

+ 10 - 3
prs.desktop/Panels/Suppliers/SupplierBillPanel.xaml.cs

@@ -20,7 +20,7 @@ namespace PRSDesktop
         
         public bool IsReady { get; set; }
 
-        public event DataModelUpdateEvent OnUpdateDataModel;
+        public event DataModelUpdateEvent? OnUpdateDataModel;
 
         public Dictionary<string, object[]> Selected()
         {
@@ -29,6 +29,10 @@ namespace PRSDesktop
 
         public void CreateToolbarButtons(IPanelHost host)
         {
+            PostUtils.CreateToolbarButtons(host,
+                () => (DataModel(Selection.Selected) as IDataModel<Bill>)!,
+                () => Bills.Refresh(false, true),
+                true);
         }
 
         public string SectionName => "Supplier Bills";
@@ -66,11 +70,14 @@ namespace PRSDesktop
             };
         }
 
-        private Bill[] _bills = null;
+        private Bill[]? _bills = null;
         
         private void Bills_OnOnSelectItem(object sender, DynamicGridSelectionEventArgs e)
         {
-            ReloadBills();
+            if(SplitPanel.View != DynamicSplitPanelView.Master)
+            {
+                ReloadBills();
+            }
         }
 
         private void ReloadBills()

+ 37 - 2
prs.desktop/Panels/Suppliers/SupplierBills.cs

@@ -1,23 +1,58 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Windows;
 using System.Windows.Media.Imaging;
 using Comal.Classes;
 using InABox.Core;
 using InABox.DynamicGrid;
 using InABox.WPF;
+using Syncfusion.UI.Xaml.Diagram.Controls;
 
 namespace PRSDesktop
 {
     public class SupplierBills : DynamicDataGrid<Bill>
     {
+        private static readonly BitmapImage? tick = PRSDesktop.Resources.tick.AsBitmapImage();
+        private static readonly BitmapImage? warning = PRSDesktop.Resources.warning.AsBitmapImage();
         private readonly BitmapImage pdf = PRSDesktop.Resources.doc_pdf.AsBitmapImage();
 
         public SupplierBills()
         {
+            HiddenColumns.Add(x => x.PostedStatus);
+
+            ActionColumns.Add(new DynamicImageColumn(Posted_Image, null)
+            {
+                ToolTip = Posted_ToolTip
+            });
+        }
+
+        private FrameworkElement? Posted_ToolTip(DynamicActionColumn column, CoreRow? row)
+        {
+            if (row is null)
+            {
+                return column.TextToolTip("Bill Processed Status");
+            }
+            return column.TextToolTip(row.Get<Bill, PostedStatus>(x => x.PostedStatus) switch
+            {
+                PostedStatus.PostFailed => "Processing Failed",
+                PostedStatus.Posted => "Processed",
+                PostedStatus.NeverPosted or _ => "Not posted yet",
+            });
         }
-        
-        public Bill[] LoadBills(CoreRow[]? rows)
+
+        private BitmapImage? Posted_Image(CoreRow? row)
+        {
+            if (row is null) return tick;
+            return row.Get<Bill, PostedStatus>(x => x.PostedStatus) switch
+            {
+                PostedStatus.PostFailed => warning,
+                PostedStatus.Posted => tick,
+                PostedStatus.NeverPosted or _ => null,
+            };
+        }
+
+        public Bill[] LoadBills(CoreRow[] rows)
         {
             return LoadItems(rows);
         }

+ 11 - 13
prs.desktop/Utils/PostUtils.cs

@@ -18,18 +18,12 @@ namespace PRSDesktop
     {
         private static readonly Inflector.Inflector inflector = new(new CultureInfo("en"));
 
-        public static void PostEntities<T>(IEnumerable<T> entities, Action refresh, Action? configurePost = null)
+        public static void PostEntities<T>(IDataModel<T> model, 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))
+                if (PosterUtils.Process(model))
                 {
                     MessageBox.Show("Processing successful!");
                     refresh();
@@ -40,6 +34,10 @@ namespace PRSDesktop
                     refresh();
                 }
             }
+            catch (EmptyPostException)
+            {
+                MessageBox.Show($"Please select at least one {typeof(T).Name}.");
+            }
             catch (RepostedException)
             {
                 MessageBox.Show("At least one of the items you selected has already been processed. Processing cancelled.");
@@ -74,11 +72,11 @@ namespace PRSDesktop
             }
         }
 
-        public static void CreateToolbarButtons<T>(IPanelHost host, Func<IEnumerable<T>> entities, Action refresh, Action? configurePost = null)
+        public static void CreateToolbarButtons<T>(IPanelHost host, Func<IDataModel<T>> model, Action refresh, Action? configurePost = null)
             where T : Entity, IPostable, IRemotable, IPersistent, new()
         {
             var postSettings = PosterUtils.LoadPostableSettings<T>();
-            if (Security.CanPost<T>())
+            if (Security.CanPost<T>() && !postSettings.PosterType.IsNullOrWhiteSpace())
             {
                 Bitmap? image = null;
                 if (postSettings.Thumbnail.ID != Guid.Empty)
@@ -97,7 +95,7 @@ namespace PRSDesktop
                     OnExecute = action =>
                     {
                         PostEntities(
-                            entities(),
+                            model(),
                             refresh,
                             configurePost);
                     }
@@ -129,10 +127,10 @@ namespace PRSDesktop
             }
         }
 
-        public static void CreateToolbarButtons<T>(IPanelHost host, Func<IEnumerable<T>> entities, Action refresh, bool allowConfig)
+        public static void CreateToolbarButtons<T>(IPanelHost host, Func<IDataModel<T>> model, Action refresh, bool allowConfig)
             where T : Entity, IPostable, IRemotable, IPersistent, new()
         {
-            CreateToolbarButtons(host, entities, refresh, allowConfig ? ConfigurePost<T> : null);
+            CreateToolbarButtons(host, model, refresh, allowConfig ? ConfigurePost<T> : null);
         }
     }
 }

+ 12 - 8
prs.server/Engines/WebEngine/WebListener.cs

@@ -140,15 +140,19 @@ namespace PRSServer
             return _dataModel.HasTable<TType>(alias);
         }
 
-        public void LoadModel(IEnumerable<string> requiredTables, Dictionary<string, IQueryDef>? requiredQueries = null)
+        public void LoadModel(IEnumerable<string>? requiredTables, Dictionary<string, IQueryDef>? requiredQueries = null)
         {
             _dataModel.LoadModel(requiredTables, requiredQueries);
         }
 
-        public void LoadModel(IEnumerable<string> requiredTables, params IDataModelQueryDef[] requiredQueries)
+        public void LoadModel(IEnumerable<string>? requiredTables, params IDataModelQueryDef[] requiredQueries)
         {
             _dataModel.LoadModel(requiredTables, requiredQueries);
         }
+        public void LoadModel()
+        {
+            _dataModel.LoadModel();
+        }
 
         public TType[] ExtractValues<TSource, TType>(Expression<Func<TSource, TType>> column, bool distinct = true, string? alias = null)
         {
@@ -175,7 +179,7 @@ namespace PRSServer
 
     public class RazorReferenceResolver : IReferenceResolver
     {
-        public IEnumerable<CompilerReference> GetReferences(TypeContext context, IEnumerable<CompilerReference> includeAssemblies = null)
+        public IEnumerable<CompilerReference> GetReferences(TypeContext context, IEnumerable<CompilerReference>? includeAssemblies = null)
         {
             foreach(var reference in new UseCurrentAssembliesReferenceResolver().GetReferences(context, includeAssemblies))
             {
@@ -870,9 +874,9 @@ Model.LoadModel(
 
         #region Edit
 
-        public static Dictionary<string, object> SerializeEntityForEditing(Type entityType, Entity entity)
+        public static Dictionary<string, object?> SerializeEntityForEditing(Type entityType, Entity entity)
         {
-            var data = new Dictionary<string, object>();
+            var data = new Dictionary<string, object?>();
             foreach (var property in DatabaseSchema.Properties(entityType))
             {
                 var editor = EditorUtils.GetPropertyEditor(entityType, property);
@@ -930,7 +934,7 @@ Model.LoadModel(
                 return request.Respond().Status(ResponseStatus.NotFound);
             if (request.Content == null)
                 return request.Respond().Status(ResponseStatus.BadRequest);
-            if (request.ContentType.KnownType != ContentType.ApplicationJson) return request.Respond().Status(ResponseStatus.UnsupportedMediaType);
+            if (request.ContentType?.KnownType != ContentType.ApplicationJson) return request.Respond().Status(ResponseStatus.UnsupportedMediaType);
 
             var user = GetClientUser(request);
             if (user == null)
@@ -956,8 +960,8 @@ Model.LoadModel(
             }
 
             var dictionary = Serialization.Deserialize<Dictionary<string, object>>(request.Content);
-            var entity = typeof(WebHandler).GetMethod("DeserializeEditedEntity", BindingFlags.Static | BindingFlags.Public)
-                .MakeGenericMethod(entityType).Invoke(this, new object[] { dictionary }) as Entity;
+            var entity = (typeof(WebHandler).GetMethod(nameof(WebHandler.DeserializeEditedEntity), BindingFlags.Static | BindingFlags.Public)!
+                .MakeGenericMethod(entityType).Invoke(this, new object?[] { dictionary }) as Entity)!;
 
             var client = ClientFactory.CreateClient(entityType);
             client.Save(entity, string.Format("Edited by {0} from the web", user.UserID));

+ 40 - 0
prs.shared/Posters/BillCSVPoster.cs

@@ -0,0 +1,40 @@
+using Comal.Classes;
+using InABox.Core;
+using InABox.Poster.CSV;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace PRS.Shared
+{
+    public class BillCSVPoster : ICSVPoster<Bill>
+    {
+        public bool BeforePost(IDataModel<Bill> model)
+        {
+            return true;
+        }
+
+        public ICSVExport Process(IDataModel<Bill> model)
+        {
+            var export = new CSVExport<Bill>();
+            export.DefineMapping(new()
+            {
+                new("Number", x => x.Number),
+                new("SupplierCode", x => x.SupplierLink.Code),
+                new("Date", x => x.BillDate),
+                new("ExTax", x => x.ExTax),
+                new("Tax", x => x.Tax),
+                new("IncTax", x => x.IncTax)
+            });
+            foreach (var bill in model.GetTable<Bill>().ToObjects<Bill>())
+            {
+                export.Add(bill);
+            }
+            return export;
+        }
+        public void AfterPost(IDataModel<Bill> model)
+        {
+        }
+
+    }
+}

+ 12 - 3
prs.shared/Posters/InvoiceCSVPoster.cs

@@ -9,7 +9,12 @@ namespace PRS.Shared
 {
     public class InvoiceCSVPoster : ICSVPoster<Invoice>
     {
-        public ICSVExport Process(IEnumerable<Invoice> entities)
+        public bool BeforePost(IDataModel<Invoice> model)
+        {
+            return true;
+        }
+
+        public ICSVExport Process(IDataModel<Invoice> model)
         {
             var export = new CSVExport<Invoice>();
             export.DefineMapping(new()
@@ -21,11 +26,15 @@ namespace PRS.Shared
                 new("Tax", x => x.Tax),
                 new("IncTax", x => x.IncTax)
             });
-            foreach(var entity in entities)
+            foreach (var invoice in model.GetTable<Invoice>().ToObjects<Invoice>())
             {
-                export.Add(entity);
+                export.Add(invoice);
             }
             return export;
         }
+        public void AfterPost(IDataModel<Invoice> model)
+        {
+        }
+
     }
 }