浏览代码

Added properties to ManufacturingPanel for an optimisation script when doing picking lists.
Improved picking list code.

Kenric Nugteren 1 年之前
父节点
当前提交
2c306de095

+ 2 - 2
prs.desktop/Panels/Manufacturing/ManufacturingKanban.cs

@@ -13,7 +13,7 @@ namespace PRSDesktop
         public string JobName { get; set; }
         public DateTime CreatedDate { get; set; }
         public DateTime DueDate { get; set; }
-        public BitmapImage Image { get; set; }
+        public BitmapImage? Image { get; set; }
         public bool Checked { get; set; }
         public Guid SetoutID { get; set; }
         public string Status { get; set; }
@@ -28,7 +28,7 @@ namespace PRSDesktop
         public TimeSpan Time { get; set; }
         public double PercentageComplete { get; set; }
         public string Issues { get; set; }
-        public BitmapImage IssuesImage { get; set; }
+        public BitmapImage? IssuesImage { get; set; }
         public Guid TemplateID { get; set; }
         public Guid GroupID { get; set; }
 

+ 8 - 3
prs.desktop/Panels/Manufacturing/ManufacturingPanel.xaml.cs

@@ -18,8 +18,8 @@ using System.ComponentModel;
 
 namespace PRSDesktop
 {
-
-    public partial class ManufacturingPanel : UserControl, IPanel<ManufacturingPacket>
+    public partial class ManufacturingPanel : UserControl, IPanel<ManufacturingPacket>, IPropertiesPanel<ManufacturingPanelProperties
+        >
     {
         private readonly List<IManufacturingPanelColumn> _columns = new();
 
@@ -36,6 +36,8 @@ namespace PRSDesktop
 
         private ManufacturingSettings settings = new();
 
+        public ManufacturingPanelProperties Properties { get; set; }
+
         #endregion
 
         private readonly DispatcherTimer columnsizer = new();
@@ -113,6 +115,9 @@ namespace PRSDesktop
                 .ToArray(); //new Client<ManufacturingTemplate>().Load(null, new SortOrder<ManufacturingTemplate>(x=>x.Code));
             Data.Jobs = tables[3]; //.Rows.Select(x => x.ToObject<Job>()).ToArray();
             Data.ITPs = tables[4]; //.Rows.Select(x => x.ToObject<JobITP>()).ToArray();
+
+            Data.Properties = Properties;
+
             foreach (var orderrow in tables[5].Rows)
             {
                 var id = orderrow.Get<PurchaseOrderItem, Guid>(x => x.ID);
@@ -153,7 +158,7 @@ namespace PRSDesktop
                 FactoryImages = new Client<Document>().Load(imageFilter);
             }
             else
-                FactoryImages = new Document[] { };
+                FactoryImages = Array.Empty<Document>();
 
             var iFact = 1;
             foreach (var Factory in Data.Factories)

+ 1 - 1
prs.desktop/Panels/Manufacturing/ManufacturingPanelColumn.xaml

@@ -121,8 +121,8 @@
                                   Tag="{Binding}" />
                         <Separator x:Name="ViewSetoutSeparator" />
 
-                        <MenuItem x:Name="IssueSetout" Header="Issue Item" Click="IssueSetout_Click" Tag="{Binding}" />
                         <MenuItem x:Name="CreatePickingList" Header="Create Picking List" Click="CreatePickingList_Click" Tag="{Binding}" />
+                        <MenuItem x:Name="IssueSetout" Header="Issue Item" Click="IssueSetout_Click" Tag="{Binding}" />
                         <MenuItem x:Name="IssueGroup" Header="Issue Optimization Group" Click="IssueGroup_Click" Tag="{Binding}" />
                         <MenuItem x:Name="ProgressSetout" Header="Progress Item" Click="ProgressSetout_Click"
                                   Tag="{Binding}" />

+ 79 - 19
prs.desktop/Panels/Manufacturing/ManufacturingPanelColumn.xaml.cs

@@ -16,7 +16,8 @@ using InABox.Reports;
 using InABox.Core.Reports;
 using InABox.Wpf.Reports;
 using InABox.WPF;
-
+using InABox.Scripting;
+using System.Threading;
 
 namespace PRSDesktop
 {
@@ -311,7 +312,7 @@ namespace PRSDesktop
                     model.TemplateID = packet.ManufacturingTemplateLink.ID;
 
                     model.Image = !barcodeprinted.IsEmpty() ? barcode : barcodetype == BarcodeType.None ? disabled : null;
-                    model.Tags = new string[] { };
+                    model.Tags = Array.Empty<string>();
                     model.Category = completed != DateTime.MinValue ? CoreUtils.FullGuid : sectionid;
 
                     if (priority)
@@ -428,8 +429,8 @@ namespace PRSDesktop
         {
             var menu = sender as ContextMenu;
 
-            var issue = menu.Items[2] as MenuItem;
-            var createPickingList = menu.Items[3] as MenuItem;
+            var createPickingList = menu.Items[2] as MenuItem;
+            var issue = menu.Items[3] as MenuItem;
             var issuegroup = menu.Items[4] as MenuItem;
             var progress = menu.Items[5] as MenuItem;
             var split = menu.Items[6] as MenuItem;
@@ -709,18 +710,51 @@ namespace PRSDesktop
                 ProgressPacket(model, date, Guid.Empty);
         }
 
+        private List<RequisitionItem>? CustomisePickingList(Requisition requisition, List<RequisitionItem> items)
+        {
+            var script = Data.Properties.PickingListOptimisationScript;
+            if (!script.IsNullOrWhiteSpace())
+            {
+                var scriptDocument = new ScriptDocument(script);
+                if (!scriptDocument.Compile())
+                {
+                    throw new Exception("Script failed to compile!");
+                }
+
+                var method = scriptDocument.GetMethod(methodName: ManufacturingPanelProperties.PickingListOptimisationMethodName())
+                    ?? throw new Exception($"Script has no method {ManufacturingPanelProperties.PickingListOptimisationMethodName()}()!");
+                var result = (method.Invoke(scriptDocument.GetObject(), new object?[] { requisition, items }) as List<RequisitionItem>)!;
+                return result;
+            }
+            return items;
+        }
+
         private void CreatePickingList_Click(object sender, RoutedEventArgs e)
         {
             var item = (MenuItem)sender;
             var model = (ManufacturingKanban)item.Tag;
 
             var pkts = GetSelectedPackets(model.ID).ToList();
+            if(pkts.Count == 0)
+            {
+                MessageBox.Show("Cannot create picking list: no packets selected.");
+                return;
+            }
+
+            var jobs = pkts.Select(x => x.SetoutLink.JobLink.ID).Distinct().ToArray();
+            if(jobs.Length > 1)
+            {
+                MessageBox.Show("Cannot create picking list: packets from more than one job are selected.");
+                return;
+            }
+            var jobID = jobs.First();
 
             var components =
                 Client.Query(
                     new Filter<ManufacturingPacketComponent>(x => x.Packet.ID).InList(pkts.Select(x => x.ID).ToArray()),
                     new Columns<ManufacturingPacketComponent>()
                         .Add(x => x.ID)
+                        .Add(x => x.Description)
                         .Add(x => x.Packet.ID)
                         .Add(x => x.Product.ID)
                         .Add(x => x.Product.Code)
@@ -737,8 +771,7 @@ namespace PRSDesktop
                         .Add(x => x.Dimensions.Width)
                         .Add(x => x.Dimensions.Height)
                         .Add(x => x.Dimensions.Weight)
-                        .Add(x => x.Dimensions.UnitSize)
-                        )
+                        .Add(x => x.Dimensions.UnitSize))
                 .ToObjects<ManufacturingPacketComponent>();
 
             var requisitionItems = new List<RequisitionItem>();
@@ -751,9 +784,10 @@ namespace PRSDesktop
                 }
                 var requisitionItem = new RequisitionItem
                 {
-                    Quantity = component.Quantity
+                    Quantity = component.Quantity,
+                    Description = component.Description
                 };
-                requisitionItem.Job.ID = packet.SetoutLink.JobLink.ID;
+                requisitionItem.Job.ID = jobID;
                 requisitionItem.Product.ID = component.Product.ID;
                 requisitionItem.Product.Synchronise(component.Product);
                 requisitionItem.Style.Synchronise(component.Product.DefaultStyle);
@@ -763,22 +797,48 @@ namespace PRSDesktop
                 requisitionItems.Add(requisitionItem);
             }
 
-            var requisition = new Requisition();
+            var requisition = new Requisition
+            {
+                Title = $"Materials for {string.Join(',', pkts.Select(x => x.Serial))}"
+            };
+            requisition.Notes = new[] { requisition.Title };
             requisition.RequestedBy.ID = App.EmployeeID;
-            var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicGrid<>), typeof(Requisition));
-            if(grid.EditItems(new Requisition[] { requisition }, t =>
+            requisition.JobLink.ID = jobID;
+            requisition.Due = DateTime.Now;
+
+            try
             {
-                if(t == typeof(RequisitionItem))
+                requisitionItems = CustomisePickingList(requisition, requisitionItems);
+                if (requisitionItems is null)
+                {
+                    MessageBox.Show("Creating picking list cancelled.");
+                    return;
+                }
+
+                var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicGrid<>), typeof(Requisition));
+                if (grid.EditItems(new Requisition[] { requisition }, t =>
+                {
+                    if (t == typeof(RequisitionItem))
+                    {
+                        var table = new CoreTable();
+                        table.LoadColumns(typeof(RequisitionItem));
+                        table.LoadRows(requisitionItems);
+                        return table;
+                    }
+                    return null;
+                }))
                 {
-                    var table = new CoreTable();
-                    table.LoadColumns(typeof(RequisitionItem));
-                    table.LoadRows(requisitionItems);
-                    return table;
+                    foreach (var component in components)
+                    {
+                        component.Requisition.ID = requisition.ID;
+                    }
+                    new Client<ManufacturingPacketComponent>().Save(components, $"Created picking list for requisition {requisition.Number}.");
+                    MessageBox.Show($"Created requisition {requisition.Number}");
                 }
-                return null;
-            }))
+            }
+            catch(Exception err)
             {
-                MessageBox.Show($"Created requisition {requisition.Number}");
+                MessageBox.Show($"Error: {err.Message}");
             }
         }
 

+ 4 - 2
prs.desktop/Panels/Manufacturing/ManufacturingPanelData.cs

@@ -12,9 +12,11 @@ namespace PRSDesktop
     {
         public readonly List<Tuple<Guid, DateTime, string>> OrderItems = new();
 
-        public CoreTable Jobs;
+        public ManufacturingPanelProperties Properties { get; set; } = new();
 
-        public CoreTable ITPs;
+        public CoreTable Jobs = new();
+
+        public CoreTable ITPs = new();
 
         public ManufacturingTemplate[] Templates = Array.Empty<ManufacturingTemplate>();
 

+ 69 - 0
prs.desktop/Panels/Manufacturing/ManufacturingPanelProperties.cs

@@ -0,0 +1,69 @@
+using InABox.Configuration;
+using InABox.Core;
+using InABox.DynamicGrid;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PRSDesktop
+{
+    public class ManufacturingPanelProperties : BaseObject, IGlobalConfigurationSettings
+    {
+        [ScriptEditor]
+        public string PickingListOptimisationScript { get; set; } = "";
+
+        public static string PickingListOptimisationMethodName() => "CustomisePickingList";
+
+        public static string DefaultPickingListOptimisationScript()
+        {
+            return
+@"using InABox.Core;
+using Comal.Classes;
+using PRSDesktop;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+public class Module
+{
+    public List<RequisitionItem>? " + PickingListOptimisationMethodName() + @"(Requisition requisition, List<RequisitionItem> requisitionItems)
+    {
+        return requisitionItems;
+    }
+}";
+        }
+    }
+
+    public class ManufacturingPanelPropertiesGrid : DynamicItemsListGrid<ManufacturingPanelProperties>
+    {
+        public ManufacturingPanelPropertiesGrid()
+        {
+            OnCustomiseEditor += ManufacturingPanelPropertiesGrid_OnCustomiseEditor;
+        }
+
+        private void ManufacturingPanelPropertiesGrid_OnCustomiseEditor(IDynamicEditorForm sender, ManufacturingPanelProperties[]? items, DynamicGridColumn column, BaseEditor editor)
+        {
+            if (items?.FirstOrDefault() is not ManufacturingPanelProperties properties) return;
+
+            if (column.ColumnName == nameof(ManufacturingPanelProperties.PickingListOptimisationScript) && editor is ScriptEditor scriptEditor)
+            {
+                scriptEditor.Type = ScriptEditorType.TemplateEditor;
+                scriptEditor.OnEditorClicked += () =>
+                {
+                    var script = properties.PickingListOptimisationScript.NotWhiteSpaceOr()
+                        ?? ManufacturingPanelProperties.DefaultPickingListOptimisationScript();
+
+                    var editor = new ScriptEditorWindow(script, SyntaxLanguage.CSharp);
+                    if (editor.ShowDialog() == true)
+                    {
+                        sender.SetEditorValue(column.ColumnName, editor.Script);
+                        properties.PickingListOptimisationScript = editor.Script;
+                    }
+                };
+            }
+        }
+    }
+}