| 
					
				 | 
			
			
				@@ -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}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |