using Comal.Classes; using InABox.Core; using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using InABox.Clients; using InABox.Configuration; using InABox.DynamicGrid; using System.Diagnostics; using System.IO; using InABox.WPF; using InABox.Wpf; using System.ComponentModel; using InABox.Scripting; using System.Reflection; using System.Collections.Immutable; using StagingManufacturingPacketComponent = Comal.Classes.StagingManufacturingPacketComponent; using System.Threading.Tasks; using NPOI.SS.Formula.Functions; using Columns = InABox.Core.Columns; namespace PRSDesktop { [Caption("Staging Panel Settings")] public class StagingPanellSettings : BaseObject, IGlobalConfigurationSettings { [Caption("PDF Markup Program Pathway", IncludePath = false)] [FileNameEditor] public string MarkupPathway { get; set; } [FolderEditor(Environment.SpecialFolder.CommonDocuments)] public string SetoutsFolder { get; set; } [ScriptEditor] public string? Script { get; set; } [IntegerEditor(Caption = "Maximum Document Size (MB)", ToolTip = "The user will be warned when uploading documents which are larger than this size in megabytes. Set to zero for no maximum.")] public int MaximumDocumentSize { get; set; } public StagingPanellSettings() { MarkupPathway = ""; SetoutsFolder = ""; Script = null; MaximumDocumentSize = 0; } public string DefaultScript() { return @" using PRSDesktop; using InABox.Core; using System.Collections.Generic; public class Module { /*public void CustomiseSetouts(CustomiseSetoutsArgs args) { // Perform customisation on the setouts when they are added to the 'Staged Documents' grid. }*/ }"; } } public class CustomiseSetoutsArgs { public IReadOnlyList> Setouts; public CustomiseSetoutsArgs(IReadOnlyList> setouts) { Setouts = setouts; } } /// /// Interaction logic for StagingPanel.xaml /// public partial class StagingPanel : UserControl, IPanel { private StagingPanellSettings _settings = new StagingPanellSettings(); /// /// The currently selected setout. /// private StagingSetout? selectedSetout; /// /// All currently selected setouts; will be a member of this list. /// private List selectedSetouts = new(); private CoreTable _templateGroups = null!; #region Script Stuff private MethodInfo? _customiseSetoutsMethod; private MethodInfo? CustomiseSetoutsMethod { get { EnsureScript(); return _customiseSetoutsMethod; } } private object? _scriptObject; private object? ScriptObject { get { EnsureScript(); return _scriptObject; } } private ScriptDocument? _script; private ScriptDocument? Script { get { EnsureScript(); return _script; } } private void EnsureScript() { if (_script is null && !_settings.Script.IsNullOrWhiteSpace()) { _script = new ScriptDocument(_settings.Script); if (!_script.Compile()) { throw new Exception("Script in Staging Panel Settings failed to compile!"); } _scriptObject = _script?.GetObject(); _customiseSetoutsMethod = _script?.GetMethod(methodName: "CustomiseSetouts"); } } #endregion public StagingPanel() { InitializeComponent(); SectionName = nameof(StagingPanel); } public void Setup() { _settings = new GlobalConfiguration().Load(); _templateGroups = new Client().Query(); MarkUpButton.Visibility = Security.IsAllowed() ? Visibility.Visible : Visibility.Hidden; RejectButton.Visibility = Security.IsAllowed() ? Visibility.Visible : Visibility.Hidden; ApproveButton.Visibility = Security.IsAllowed() ? Visibility.Visible : Visibility.Hidden; ProcessButton.Visibility = Security.IsAllowed() ? Visibility.Visible : Visibility.Hidden; //stagingSetoutGrid.ScanFiles(_settings.SetoutsFolder); stagingSetoutGrid.PanelSettings = _settings; stagingSetoutGrid.Refresh(true, false); SetoutComponentGrid.Refresh(true, false); } private bool CanViewPackets() => MainPanel.View != DynamicSplitPanelView.Master && NestedPanel.View != DynamicSplitPanelView.Master; private void NestedPanel_OnChanged(object sender, DynamicSplitPanelSettings e) { if(CanViewPackets()) { ManufacturingPacketList.Setout = selectedSetout; SetoutComponentGrid.StagingSetout = selectedSetout; } } #region Document Viewer public enum DocumentMode { Markup, Complete, Locked } private DocumentMode _mode; private DocumentMode Mode { get => _mode; set => SetMode(value); } private void SetMode(DocumentMode mode) { _mode = mode; if (_mode == DocumentMode.Markup) { MarkUpButton.Content = "Mark Up"; MarkUpButton.IsEnabled = Document != null && !Document.Approved; UpdateOriginalButton.Visibility = Document != null && !String.Equals(Document.DocumentLink.CRC, selectedSetout?.OriginalCRC) ? Visibility.Visible : Visibility.Collapsed; ProcessButton.IsEnabled = Document != null && Document.Approved; RejectButton.IsEnabled = Document != null && !Document.Approved; ApproveButton.IsEnabled = Document != null; } else if (_mode == DocumentMode.Complete) { MarkUpButton.Content = "Complete"; MarkUpButton.IsEnabled = Document != null; UpdateOriginalButton.Visibility = Visibility.Collapsed; ProcessButton.IsEnabled = false; RejectButton.IsEnabled = false; ApproveButton.IsEnabled = false; } else if (_mode == DocumentMode.Locked) { MarkUpButton.Content = "Locked"; MarkUpButton.IsEnabled = false; UpdateOriginalButton.Visibility = Visibility.Collapsed; ProcessButton.IsEnabled = false; RejectButton.IsEnabled = false; ApproveButton.IsEnabled = false; } } private StagingSetoutDocument? _document; private StagingSetoutDocument? Document { get => _document; set { _document = value; if(_document is not null) { ApproveButton.Content = _document.Approved ? "Unapprove" : "Approve"; } } } private byte[]? _documentdata = null; private void ClearDocuments() { Document = null; RenderDocuments(null); } private List? GetDocuments(StagingSetoutDocument? document) { if(document is null) { return null; } var table = new Client().Query( new Filter(x => x.ID).IsEqualTo(document.DocumentLink.ID), Columns.None().Add(x => x.Data)); var first = table.Rows.FirstOrDefault(); if (first is null) return null; _documentdata = first.Get(x => x.Data); return ImageUtils.RenderPDFToImageBytes(_documentdata); } private void RenderDocuments(List? documents) { DocumentViewer.Children.Clear(); if(documents is not null) { foreach (var image in documents) { DocumentViewer.Children.Add(new Image { Source = ImageUtils.LoadImage(image), Margin = new Thickness(0, 0, 0, 20) }); } } } private void ProcessButton_Click(object sender, RoutedEventArgs e) { bool bulkApprove = false; if (selectedSetouts.Count > 1) { if (MessageBox.Show("Bulk approve? (Skip individual setout approval)", "Continue?", MessageBoxButton.OKCancel) == MessageBoxResult.OK) { bulkApprove = true; Progress.Show("Approving Setouts.."); } } if (selectedSetouts.Any(x => x.UnapprovedDocuments > 0)) { MessageBox.Show("Cannot process setouts with unapproved documents."); Progress.Close(); return; } if (selectedSetouts.Any(x => x.JobLink.ID == Guid.Empty)) { MessageBox.Show("Cannot process setout without a linked job."); Progress.Close(); return; } if (ManufacturingPacketList.Packets.Any(x => x.Template.ID == Guid.Empty)) { MessageBox.Show("Cannot process manufacturing packets without templates."); Progress.Close(); return; } if (selectedSetouts.Any(x => x.Packets == 0)) { if (MessageBox.Show("Warning: some setouts do not have any manufacturing packets: are you sure you wish to proceed?", "Warning", MessageBoxButton.YesNoCancel) != MessageBoxResult.Yes) { Progress.Close(); return; } } string message = ""; foreach (var item in selectedSetouts) { if (bulkApprove) Progress.Show("Working on " + item.Number); var returnstring = ApproveSetout(item, bulkApprove); if (!string.IsNullOrWhiteSpace(returnstring)) message = message + returnstring + Environment.NewLine; } if (bulkApprove) Progress.Close(); new Client().Save(selectedSetouts, "Updated from staging screen"); selectedSetout = null; Refresh(); if (!message.IsNullOrWhiteSpace()) { MessageBox.Show($"Result:\n{message}"); } MainPanel.View = DynamicSplitPanelView.Combined; NestedPanel.View = DynamicSplitPanelView.Master; } private string ApproveSetout(StagingSetout item, bool bulkapprove) { if (item.Group.ID == Guid.Empty) { var message = "Setout has no group assigned"; if (Security.IsAllowed()) { if (MessageBox.Show(message + ", continue?", "Continue?", MessageBoxButton.OKCancel) != MessageBoxResult.OK) return ""; } else { MessageBox.Show(message + ", please assign a group!"); return ""; } } var setoutDocument = new Client() .Query( new Filter(x => x.EntityLink.ID).IsEqualTo(item.ID), Columns.None().Add(x => x.ID, x => x.DocumentLink.ID, x => x.DocumentLink.FileName)) .ToObjects().FirstOrDefault(); if (setoutDocument is null) return ""; var setout = new Client() .Query( new Filter(x => x.Number).IsEqualTo(item.Number), Columns.Required().Add(x => x.ID)) .ToObjects().FirstOrDefault(); string result; //setout already exists - create new setoutdoc and supercede old ones if (setout is not null) { if (!bulkapprove) if (MessageBox.Show("Supercede existing documents?", "Proceed?", MessageBoxButton.YesNo) != MessageBoxResult.Yes) return ""; setout.Group.ID = item.Group.ID; item.Setout.ID = setout.ID; var setoutdoc = new SetoutDocument(); setoutdoc.EntityLink.ID = setout.ID; setoutdoc.DocumentLink.ID = setoutDocument.DocumentLink.ID; var setoutdocs = new List { setoutdoc }; CoreTable oldDocsTable = new Client().Query( new Filter(x => x.EntityLink.ID).IsEqualTo((Guid)setout.ID) .And(x => x.DocumentLink.ID).IsNotEqualTo(item.Group.OptimizationDocument.ID) ); foreach (var row in oldDocsTable.Rows) { var oldDoc = row.ToObject(); if (oldDoc.Superceded == DateTime.MinValue) { oldDoc.Superceded = DateTime.Now; setoutdocs.Add(oldDoc); } } new Client().Save(setoutdocs, "Updated from Staging Screen"); new Client().Save((Setout)setout, "Updated from Staging Screen"); result = item.Number + " Superceded"; } //no setout for this pdf - create new else { setout = new Setout { Number = item.Number }; setout.JobLink.ID = item.JobLink.ID; setout.Group.ID = item.Group.ID; var editor = new DynamicDataGrid(); editor.OnAfterSave += (editor, items) => { CreateSetoutDocument(setout, item, setoutDocument); }; if (!bulkapprove) { if (!editor.EditItems(new[] { setout })) { MessageBox.Show("Setout Creation Cancelled"); return ""; } else result = item.Number + " Created"; } else { new Client().Save(setout, "Added from staging screen"); CreateSetoutDocument(setout, item, setoutDocument); result = item.Number + " Created"; } } var tuples = new List>(); var stagingPackets = new Client() .Query( new Filter(x => x.StagingSetout.ID).IsEqualTo(item.ID), Columns.Required().Add(x => x.ID) .Add(x => x.Serial) .Add(x => x.Title) .Add(x => x.Quantity) .Add(x => x.BarcodeQuantity) .Add(x => x.Watermark) .Add(x => x.Group.Watermark) .Add(x => x.Location) .Add(x => x.ITP.ID) .Add(x => x.Job.ID) .Add(x => x.Template.ID)); foreach(var stagingPacket in stagingPackets.ToObjects()) { if(stagingPacket.ManufacturingPacket.ID != Guid.Empty) { MessageBox.Show($"A manufacturing packet already exists for {stagingPacket.Serial}; skipping packet."); continue; } var packet = new ManufacturingPacket { Serial = stagingPacket.Serial, Title = stagingPacket.Title, Quantity = stagingPacket.Quantity, BarcodeQty = string.IsNullOrWhiteSpace(stagingPacket.BarcodeQuantity) ? stagingPacket.Quantity : int.Parse(stagingPacket.BarcodeQuantity), WaterMark = string.IsNullOrWhiteSpace(stagingPacket.Watermark) ? stagingPacket.Group.Watermark : stagingPacket.Watermark, Location = stagingPacket.Location }; packet.SetoutLink.ID = setout.ID; packet.ITP.ID = stagingPacket.ITP.ID; packet.JobLink.ID = stagingPacket.Job.ID; packet.ManufacturingTemplateLink.ID = stagingPacket.Template.ID; tuples.Add(new(packet, stagingPacket)); } new Client().Save(tuples.Select(x => x.Item1), "Created from Design Management Panel"); var newStages = new List(); var newComponents = new List(); var newTreatments = new List(); foreach(var (packet, stagingPacket) in tuples) { stagingPacket.ManufacturingPacket.ID = packet.ID; var stages = new Client() .Query( new Filter(x => x.Packet.ID).IsEqualTo(stagingPacket.ID), IManufacturingPacketGeneratorExtensions.GetPacketGeneratorRequiredColumns()); newStages.AddRange(stages.ToObjects() .Select(x => { var stage = x.CreateManufacturingPacketStage(); stage.Parent.ID = packet.ID; return stage; })); var components = new Client() .Query( new Filter(x => x.Packet.ID).IsEqualTo(stagingPacket.ID), Columns.None().Add(x=>x.Packet.ID) .Add(x => x.Product.ID) .Add(x => x.Quantity) .Add(x => x.Dimensions.Unit.ID) .Add(x => x.Dimensions.Quantity) .Add(x => x.Dimensions.Length) .Add(x => x.Dimensions.Width) .Add(x => x.Dimensions.Height) .Add(x => x.Dimensions.Weight) .Add(x => x.Dimensions.Value) .Add(x => x.Dimensions.UnitSize) ); newComponents.AddRange(components.ToObjects() .Select(x => x.CreateComponent(packet.ID))); var treatments = new Client() .Query( new Filter(x => x.Packet.ID).IsEqualTo(stagingPacket.ID), Columns.None().Add(x=>x.Packet.ID) .Add(x=>x.Product.ID) .Add(x=>x.Parameter) ); newTreatments.AddRange(treatments.ToObjects() .Select(x => x.CreateTreatment(packet.ID))); } new Client().Save(newStages, "Created from Design Management"); new Client().Save(newComponents, "Created from Design Management"); new Client().Save(newTreatments, "Created from Design Management"); new Client().Save(tuples.Select(x => x.Item2), "Created from Design Management"); //currently not creating packets due to temporary change in requirements - to uncomment and check for validity when required //CreatePackets(setout); return result; } private static void CreateSetoutDocument(Setout setout, StagingSetout item, StagingSetoutDocument stagingsetoutdocument) { item.Setout.ID = setout.ID; var setoutdoc = new SetoutDocument(); setoutdoc.EntityLink.ID = setout.ID; setoutdoc.DocumentLink.ID = stagingsetoutdocument.DocumentLink.ID; new Client().Save(setoutdoc, "Added from staging screen"); } private void RejectButton_Click(object sender, RoutedEventArgs e) { if (selectedSetout is null || Document is null) { MessageBox.Show("Please select a setout"); return; } //dont create setout - setout.id remains blank //create kanban and populate task.id - this prevents it from appearing on the stagingsetout grid, and allows a new staging setout to be created when the file is saved to the folder again //attach the document to the task for reference var task = new Kanban { Title = "Setout Review Task (setout rejected)", Description = "Please review the attached document for setout " + selectedSetout.Number }; task.ManagerLink.ID = App.EmployeeID; var page = new TaskGrid(); if (page.EditItems(new[] { task })) { var doc = new KanbanDocument(); doc.EntityLink.ID = task.ID; doc.DocumentLink.ID = Document.DocumentLink.ID; new Client().Save(doc, "Created from staging screen"); selectedSetout.Task.ID = task.ID; new Client().Save(selectedSetout, "Updated from staging screen"); MessageBox.Show("Success - Task Created for Document " + selectedSetout.Number + " (Task no. " + task.Number + " assigned to " + task.EmployeeLink.Name + ")"); selectedSetout = null; ClearDocuments(); refreshing = true; stagingSetoutGrid.Refresh(false, true); } else { MessageBox.Show("Task creation cancelled - setout not rejected"); } } private void MarkUpButton_Click(object sender, RoutedEventArgs e) { if (Mode == DocumentMode.Markup) { Mode = DocumentMode.Complete; MessageBox.Show("IMPORTANT - press save in your document editor, then press the Complete Button in PRS"); OnMarkupSelected(); } else { OnMarkupComplete(); Mode = DocumentMode.Markup; } } private void UpdateOriginalButton_Click(object sender, RoutedEventArgs e) { if ((_documentdata?.Any() == true) && !String.IsNullOrWhiteSpace(selectedSetout?.OriginalPath)) { try { File.WriteAllBytes(selectedSetout.OriginalPath, _documentdata); selectedSetout.OriginalCRC = CoreUtils.CalculateCRC(_documentdata); new Client().Save(selectedSetout,"Updated Source File with markups"); UpdateOriginalButton.Visibility = Visibility.Collapsed; } catch (Exception _exception) { MessageBox.Show($"Unable to update {selectedSetout?.OriginalPath}!\n\n{_exception.Message}"); } return; } MessageBox.Show("Please select a design first!"); } private void ApproveButton_Click(object sender, RoutedEventArgs e) { if (Document is null || selectedSetout is null) { MessageBox.Show("Please select a setout first."); return; } if (selectedSetouts.Count > 1) { var msg = Document.Approved ? "Bulk unapprove?" : "Bulk approve? (Skip individual setout approval)"; if (MessageBox.Show(msg, "Continue?", MessageBoxButton.OKCancel) == MessageBoxResult.OK) { Progress.Show("Approving Setouts.."); var documents = Client.Query( new Filter(x => x.EntityLink.ID).InList(selectedSetouts.Select(x => x.ID).ToArray()), Columns.Required().Add(x => x.ID, x => x.Approved) ).ToObjects().ToList(); foreach(var document in documents) { document.Approved = !Document.Approved; } Client.Save(documents, "Approved by user."); Progress.Close(); refreshing = true; stagingSetoutGrid.Refresh(false, true); } } else { Document.Approved = !Document.Approved; new Client().Save(Document, ""); refreshing = true; stagingSetoutGrid.Refresh(false, true); } } private void OnMarkupSelected() { if (Document is null || selectedSetout is null) { MessageBox.Show("Please select a setout first."); return; } var doc = new Client() .Query( new Filter(x => x.ID).IsEqualTo(Document.DocumentLink.ID)) .ToObjects().FirstOrDefault(); if (doc is null) { Logger.Send(LogType.Error, "", $"Document with ID {Document.DocumentLink.ID} could not be found."); MessageBox.Show("Error: the selected document could not be found in the database."); return; } var tempdocpath = Path.Combine(Path.GetTempPath(), doc.FileName); selectedSetout.SavePath = tempdocpath; selectedSetout.LockedBy.ID = App.EmployeeID; selectedSetout.LockedBy.Name = App.EmployeeName; new Client().Save(selectedSetout, "Locked from Staging Screen"); File.WriteAllBytes(tempdocpath, doc.Data); using (var p = new Process()) { p.StartInfo = new ProcessStartInfo() { UseShellExecute = true, FileName = tempdocpath }; p.Start(); } refreshing = true; stagingSetoutGrid.Refresh(false, true); } private void OnMarkupComplete() { if (selectedSetout is null) { MessageBox.Show("Please select a setout first."); return; } StagingSetoutGrid.ReloadFile(selectedSetout); refreshing = true; stagingSetoutGrid.Refresh(false, true); } #endregion private bool refreshing = false; private void stagingSetoutGrid_AfterRefresh(object sender, AfterRefreshEventArgs args) { refreshing = false; } private void StagingSetoutGrid_OnSelectItem(object sender, InABox.DynamicGrid.DynamicGridSelectionEventArgs e) { var newSetouts = new List(); foreach (var row in e.Rows ?? Enumerable.Empty()) newSetouts.Add(row.ToObject()); if(!refreshing && (selectedSetouts.Count == newSetouts.Count && !selectedSetouts.Any(x => !newSetouts.Any(y => x.ID == y.ID)))) { selectedSetouts = newSetouts; selectedSetout = selectedSetouts.FirstOrDefault(); return; } selectedSetouts = newSetouts; selectedSetout = selectedSetouts.FirstOrDefault(); AddPacketButton.IsEnabled = selectedSetout is not null; if(selectedSetout is null) { ClearDocuments(); ManufacturingPacketList.Setout = null; CollapsePacketsButton.IsEnabled = false; SetoutComponentGrid.StagingSetout = null; SetMode(DocumentMode.Markup); return; } var doc = new Client() .Query( new Filter(x => x.EntityLink.ID).IsEqualTo(selectedSetout.ID), Columns.None().Add(x => x.ID) .Add(x => x.DocumentLink.ID) .Add(x => x.DocumentLink.FileName) .Add(x => x.Approved) .Add(x=>x.DocumentLink.CRC) ).ToObjects().FirstOrDefault(); if(doc is null) { MessageBox.Show("No document found for this setout."); ClearDocuments(); ManufacturingPacketList.Setout = null; CollapsePacketsButton.IsEnabled = false; SetoutComponentGrid.StagingSetout = null; return; } Document = doc; var docTask = Task.Run(() => GetDocuments(doc)); if(CanViewPackets()) { ManufacturingPacketList.Setout = selectedSetout; SetoutComponentGrid.StagingSetout = selectedSetout; } CollapsePacketsButton.IsEnabled = true; var mode = selectedSetout.LockedBy.ID == Guid.Empty ? DocumentMode.Markup : selectedSetout.LockedBy.ID == App.EmployeeID ? DocumentMode.Complete : DocumentMode.Locked; docTask.Wait(); RenderDocuments(docTask.Result); SetMode(mode); } public bool IsReady { get; set; } public string SectionName { get; } public event DataModelUpdateEvent? OnUpdateDataModel; #region Settings public void CreateToolbarButtons(IPanelHost host) { ProjectSetupActions.JobStatuses(host); ProjectSetupActions.DrawingTemplates(host); host.CreateSetupSeparator(); ProjectSetupActions.JobSpreadsheetTemplates(host); host.CreateSetupSeparator(); ProjectSetupActions.SetoutGroups(host); host.CreateSetupSeparator(); host.CreateSetupAction( new PanelAction() { Caption = "Setouts Configuration", Image = PRSDesktop.Resources.specifications, OnExecute = ConfigSettingsClick } ); host.CreateSetupAction( new PanelAction() { Caption = "Component Import Profiles", Image = PRSDesktop.Resources.doc_xls, OnExecute = ConfigComponentProfiles }); host.CreateSetupAction( new PanelAction() { Caption = "Template Products", Image = PRSDesktop.Resources.specifications, OnExecute = action => { var list = new MasterList(typeof(ManufacturingTemplateGroupProducts)); list.ShowDialog(); } } ); SystemSetupActions.ERPStatuses(host); } private void ConfigComponentProfiles(PanelAction obj) { var list = new DynamicImportList( typeof(StagingSetoutComponent), Guid.Empty, canImport: false ); list.ShowDialog(); } private void ConfigSettingsClick(PanelAction obj) { var grid = new DynamicItemsListGrid(); grid.OnCustomiseEditor += Grid_OnCustomiseEditor; if(grid.EditItems(new[] { _settings })) { new GlobalConfiguration().Save(_settings); _script = null; } } private void Grid_OnCustomiseEditor(IDynamicEditorForm sender, StagingPanellSettings[]? items, DynamicGridColumn column, BaseEditor editor) { if (items?.FirstOrDefault() is not StagingPanellSettings settings) return; if (column.ColumnName == nameof(StagingPanellSettings.Script) && editor is ScriptEditor scriptEditor) { scriptEditor.Type = ScriptEditorType.TemplateEditor; scriptEditor.OnEditorClicked += () => { var script = settings.Script.NotWhiteSpaceOr() ?? settings.DefaultScript(); var editor = new ScriptEditorWindow(script, SyntaxLanguage.CSharp); if (editor.ShowDialog() == true) { sender.SetEditorValue(column.ColumnName, editor.Script); settings.Script = editor.Script; } }; } } #endregion public void Heartbeat(TimeSpan time) { } public void Refresh() { //stagingSetoutGrid.ScanFiles(_settings.SetoutsFolder); refreshing = true; stagingSetoutGrid.Refresh(false, true); /*Document = null; selectedSetout = null; ManufacturingPacketList.Setout = null; SetoutComponentGrid.StagingSetout = null;*/ CalculateTime(); } private void stagingSetoutGrid_OnRefreshPackets() { if (CanViewPackets()) { ManufacturingPacketList.Refresh(); } } public Dictionary Selected() { return new(); } public void Shutdown(CancelEventArgs? cancel) { } public DataModel DataModel(Selection selection) { return new AutoDataModel(new Filter().All()); } private void AddPacketButton_Click(object sender, RoutedEventArgs e) { if (_templateGroups.Rows.Any() == true) { ContextMenu menu = new ContextMenu(); foreach (var row in _templateGroups.Rows) { menu.AddItem( $"{row.Get(x => x.Code)}: {row.Get(x => x.Description)}", null, () => { ManufacturingPacketList.Add( selectedSetout?.JobLink.ID ?? Guid.Empty, row.ToObject() ); UpdateStagingSetoutGrid(); }); } menu.AddSeparator(); menu.AddItem("Miscellaneous Item", null, () => { ManufacturingPacketList.Add( selectedSetout?.JobLink.ID ?? Guid.Empty, null ); UpdateStagingSetoutGrid(); }); menu.IsOpen = true; } else { ManufacturingPacketList.Add( selectedSetout?.JobLink.ID ?? Guid.Empty, null ); UpdateStagingSetoutGrid(); } } private void UpdateStagingSetoutGrid() { var selected = stagingSetoutGrid.SelectedRows.FirstOrDefault(); if (selected != null) { var packets = ManufacturingPacketList.Packets; selected.Set(x => x.Packets, packets.Length); selected.Set(x => x.UnprocessedPackets, packets.Count(x => x.ManufacturingPacket.ID == Guid.Empty)); stagingSetoutGrid.InvalidateRow(selected); } } private void CollapsePacketsButton_Click(object sender, RoutedEventArgs e) { if (ManufacturingPacketList.Collapsed()) { ManufacturingPacketList.Uncollapse(); } else { ManufacturingPacketList.Collapse(); } } private void ManufacturingPacketList_OnCollapsed(bool collapsed) { if (collapsed) { CollapsePacketsButton.Content = "Expand"; } else { CollapsePacketsButton.Content = "Collapse"; } } private void stagingSetoutGrid_OnCustomiseSetouts(IReadOnlyList setouts) { if(CustomiseSetoutsMethod != null && ScriptObject != null) { CustomiseSetoutsMethod?.Invoke(ScriptObject, new object?[] { new CustomiseSetoutsArgs(setouts.Select(x => new Tuple(x.Setout, x.Document)).ToImmutableList()) }); } } private void StagingSetoutGrid_OnOnDoubleClick(object sender, HandledEventArgs args) { ManufacturingPacketList.Setout = selectedSetout; SetoutComponentGrid.StagingSetout = selectedSetout; MainPanel.View = DynamicSplitPanelView.Detail; NestedPanel.View = DynamicSplitPanelView.Combined; args.Handled = true; } private void CalculateTime() { if (selectedSetout != null) { var time = ManufacturingPacketList.TimeRequired(); TimeRequired.Content = $"{time.TotalHours:F2} hours"; } else TimeRequired.Content = "N/A"; } private void ManufacturingPacketList_OnChanged(object? sender, EventArgs e) { CalculateTime(); UpdateStagingSetoutGrid(); } private void DoImport(Importer importer, string? componentFileName, Guid setoutID) { var success = DynamicImportGrid.CreateImporter(importer, ref componentFileName, out var iimporter); if (!success) { return; } var errors = new List(); var stagingSetoutComponents = new List(); iimporter.OnLoad += Iimporter_OnLoad; iimporter.OnSave += (_, entity) => stagingSetoutComponents.Add((entity as StagingSetoutComponent)!); iimporter.OnError += (_, error) => errors.Add(error); using var stream = new FileStream(componentFileName!, FileMode.Open, FileAccess.Read); if (iimporter.Open(stream)) { if (iimporter.ReadHeader()) { var mismatches = iimporter.Mappings.Where(x => !string.IsNullOrWhiteSpace(x.Field) && !iimporter.Fields.Contains(x.Field) ).Select(x => x.Field).ToArray(); if (!mismatches.Any()) { var imported = iimporter.Import(); if (errors.Any()) { MessageBox.Show($"Import for component file {componentFileName} failed:\nSome errors occurred: {string.Join('\n', errors)}", "Import failed"); } else { var valid = true; var conflicts = false; if (setoutID != Guid.Empty) { var newComponents = new List(); foreach (var component in stagingSetoutComponents) { if (component.StagingSetout.ID == Guid.Empty) { component.StagingSetout.ID = setoutID; newComponents.Add(component); } else if (component.StagingSetout.ID != setoutID) { conflicts = true; // Ignoring this item. } else { newComponents.Add(component); } } stagingSetoutComponents = newComponents; if (conflicts) { MessageBox.Show($"Warning: the lines in this file have conflicting setout numbers.", "Warning"); } } if (valid) { foreach (var component in stagingSetoutComponents) { if (component.StagingSetout.ID == Guid.Empty) { MessageBox.Show($"Component with no related setout cannot be imported."); valid = false; break; } else if (component.Description.IsNullOrWhiteSpace()) { MessageBox.Show($"Component with no description cannot be imported."); valid = false; break; } else if (component.Dimensions.Unit.ID == Guid.Empty) { MessageBox.Show($"Component with no dimensions unit cannot be imported."); valid = false; break; } } } if (valid) { new Client().Save(stagingSetoutComponents, $"Imported from {componentFileName}"); SetoutComponentGrid.Refresh(false, true); } else { MessageBox.Show($"Import for component file {componentFileName} failed.", "Import failed"); } } } else { MessageBox.Show("Import Mappings do not match file headers!\n\n- " + string.Join("\n- ", mismatches), "Import Failed"); } } else { MessageBox.Show("Unable to Read Headers from {0}", Path.GetFileName(componentFileName)); } } else { MessageBox.Show("Unable to Open {0}", Path.GetFileName(componentFileName)); } iimporter.Close(); } private CoreTable Iimporter_OnLoad(object sender, Type type, string[] fields, string ID) { var result = new CoreTable(); result.LoadColumns(Columns.None().Add(fields)); return result; } private void stagingSetoutGrid_OnParseComponentFile(string componentFileName, Guid setoutID) { try { var entityName = typeof(StagingSetoutComponent).EntityName(); var importers = new Client() .Query( new Filter(x => x.EntityName).IsEqualTo(entityName), Columns.None().Add(x => x.ID)); if (importers.Rows.Count == 0) { var importer = new Importer { EntityName = entityName, FileName = componentFileName }; var form = new DynamicImportForm(importer); if (form.ShowDialog() == true) { new Client().Save(importer, ""); DoImport(importer, componentFileName, setoutID); return; } } else if (importers.Rows.Count == 1) { var importer = new Client().Load(new Filter(x => x.ID).IsEqualTo(importers.Rows[0].Get(x => x.ID))).First(); DoImport(importer, componentFileName, setoutID); } else { var list = new PopupList( typeof(Importer), Guid.Empty, Array.Empty()); list.OnDefineFilter += t => new Filter(x => x.EntityName).IsEqualTo(entityName); if (list.ShowDialog() == true) { var importer = new Client().Load(new Filter(x => x.ID).IsEqualTo(list.ID)).First(); DoImport(importer, componentFileName, setoutID); } } } catch(Exception e) { Logger.Send(LogType.Error, "", $"Error in file {componentFileName}: {CoreUtils.FormatException(e)}"); MessageBox.Show($"Error opening {componentFileName}: {e.Message}"); } } } }