소스 검색

Added "Replace Stock" and "Return Location" to Factory Stock Panel

frogsoftware 1 년 전
부모
커밋
6bf1791046
3개의 변경된 파일313개의 추가작업 그리고 113개의 파일을 삭제
  1. 144 35
      prs.desktop/Panels/Factory/FactoryPackGrid.cs
  2. 111 63
      prs.desktop/Panels/Factory/FactoryPanel.xaml
  3. 58 15
      prs.desktop/Panels/Factory/FactoryPanel.xaml.cs

+ 144 - 35
prs.desktop/Panels/Factory/FactoryPackGrid.cs

@@ -19,20 +19,10 @@ namespace PRSDesktop;
 
 public class FactoryPackGrid : DynamicDataGrid<StockHolding>
 {
-    public Guid AreaID { get; set; }
+    public StockArea? Area { get; set; }
     
     public ManufacturingPacket? CurrentPacket { get; set; }
-
-    public String AreaDescription
-    {
-        get => _holding.HeaderText;
-        set
-        {
-            _holding.HeaderText = value;
-            Refresh(true,false);
-        }
-    }
-
+    
     private readonly Dictionary<Guid, byte[]> _images = new();
 
     private readonly DynamicActionColumn _holding;
@@ -87,16 +77,21 @@ public class FactoryPackGrid : DynamicDataGrid<StockHolding>
     {
         Task<CoreTable> imagetask = Task.Run(() =>
         {
+            if (Area == null)
+                return new Client<Document>().Query(new Filter<Document>().None());
+            
             return new Client<Document>().Query(
                 new Filter<Document>(x => x.ID)
-                    .InQuery(new Filter<StockHolding>(x => x.Location.Area.ID).IsEqualTo(AreaID),
+                    .InQuery(new Filter<StockHolding>(x => x.Location.Area.ID).IsEqualTo(Area.ID),
                         x => x.Product.Image.ID),
                 new Columns<Document>(x => x.ID).Add(x => x.Data)
             );
         });
-        
-        criteria.Add(new Filter<StockHolding>(x => x.Location.Area.ID).IsEqualTo(AreaID));
-        
+
+        criteria.Add(Area == null
+            ? new Filter<StockHolding>().None()
+            : new Filter<StockHolding>(x => x.Location.Area.ID).IsEqualTo(Area.ID));
+
         base.Reload(criteria, columns, ref sort, (o,e) =>
         {
             if (o != null)
@@ -224,6 +219,27 @@ public class FactoryPackGrid : DynamicDataGrid<StockHolding>
         
         return grid;
     }
+
+    private class FactoryFloorReturn : BaseObject
+    {
+        
+        [EditorSequence(1)]
+        public ProductLink Product { get; set; }
+        
+        [EditorSequence(2)]
+        public ProductStyleLink Style { get; set; }
+        
+        [EditorSequence(3)]
+        [DimensionsEditor(typeof(StockDimensions), AllowEditingUnit = false)]
+        public StockDimensions Dimensions { get; set;}
+        
+        [EditorSequence(4)] 
+        public double Qty { get; set; }
+
+        [EditorSequence(5)]
+        public JobLink Job { get; set; }
+
+    }
     
     private class FactoryFloorIssue : BaseObject
     {
@@ -258,7 +274,114 @@ public class FactoryPackGrid : DynamicDataGrid<StockHolding>
         [EditorSequence(2)]
         public double Qty { get; set; }
     }
+
+    public void ReplaceStock()
+    {
+        var holdingrow = SelectedRows.FirstOrDefault();
+        var receive = holdingrow == null
+            ? new StockMovement()
+            : holdingrow.ToObject<StockHolding>().CreateMovement();
+        
+        receive.Type = StockMovementType.Receive;
+        receive.Date = DateTime.Now;
+        receive.Employee.ID = App.EmployeeID;
+        receive.Notes = "Returned from Manufacturing";
+        receive.Received = 1.0F;
+            
+        var smg = new DynamicDataGrid<StockMovement>();
+        smg.OnCustomiseEditor += StockMovementCustomiseEditor;
+        smg.OnValidate += StockMovementValidate;
+        smg.OnEditorValueChanged += StockMovementValueChanged;
+        if (smg.EditItems(new StockMovement[] { receive }))
+        {
+            receive.Batch.ID = CheckStockMovementBatch();
+            new Client<StockMovement>().Save(receive,"Issued Stock to Factory Floor");
+            Refresh(false,true);
+        }
+        
+    }
+    
+    private Dictionary<string, object?> StockMovementValueChanged(IDynamicEditorForm form, string name, object value)
+    {
+        var result = new Dictionary<string, object?>();
+        if (name.Equals("Location.Job.ID"))
+        {
+            var editor = form.FindEditor("Job.ID");
+            if (!value.Equals(Guid.Empty))
+                result = DynamicGridUtils.UpdateEditorValue(form.Items, "Job.ID", value);
+            else
+                foreach (StockMovement item in form.Items)
+                    result = DynamicGridUtils.UpdateEditorValue(new[] { item }, "Job.ID",
+                        item.Job.HasOriginalValue("ID") ? item.Job.GetOriginalValue(x => x.ID) : item.Job.ID);
+            editor.IsEnabled = value.Equals(Guid.Empty);
+        }
+
+        return result;
+    }
     
+    private void StockMovementValidate(object sender, StockMovement[] items, List<string> errors)
+    {
+        
+        if (items.Any(x => x.Product.ID == Guid.Empty))
+            errors.Add("Product may not be blank");
+        if (items.Any(x => x.Location.ID == Guid.Empty))
+            errors.Add("Location may not be blank");
+        if (items.Any(x => x is { Received: 0, Issued: 0 }))
+            errors.Add("Quantity may not be zero");
+    }
+
+    private void StockMovementCustomiseEditor(IDynamicEditorForm sender, StockMovement[]? items, DynamicGridColumn column, BaseEditor editor)
+    {
+        if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,double>(x=>x.Cost,".")))
+            editor.Editable = Editable.Hidden;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,DateTime>(x=>x.Date,".")))
+            editor.Editable = Editable.Hidden;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,double>(x=>x.Issued,".")))
+            editor.Editable = Editable.Hidden;        
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,Guid>(x=>x.Employee.ID,".")))
+            editor.Editable = Editable.Hidden;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,String>(x=>x.Notes,".")))
+            editor.Editable = Editable.Hidden;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,Guid>(x=>x.Location.ID,".")))
+            editor.EditorSequence = 1;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,Guid>(x=>x.Product.ID,".")))
+            editor.EditorSequence = 2;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,Guid>(x=>x.Style.ID,".")))
+            editor.EditorSequence = 3;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,Guid>(x=>x.Job.ID,".")))
+            editor.EditorSequence = 4;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement,StockDimensions>(x=>x.Dimensions,".")))
+            editor.EditorSequence = 5;
+        else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<StockMovement, double>(x => x.Received, ".")))
+        {
+            editor.EditorSequence = 6;
+            editor.Caption = "Quantity";
+        }
+
+
+    }
+
+    private static Guid CheckStockMovementBatch()
+    {
+        var _settings = new LocalConfiguration<FactoryFloorLocalSettings>().Load();
+        if (_settings.CurrentBatchDate != DateTime.Today)
+        {
+            StockMovementBatch batch = new StockMovementBatch
+            {
+                Type = StockMovementBatchType.Issue,
+                TimeStamp = DateTime.Now,
+                Notes = "Manufacturing Consumption"
+            };
+            batch.Employee.ID = App.EmployeeID;
+            new Client<StockMovementBatch>().Save(batch,"Created on Factory Floor Screen");
+            _settings.CurrentBatchDate = DateTime.Today;
+            _settings.CurrentBatchID = batch.ID;
+            new LocalConfiguration<FactoryFloorLocalSettings>().Save(_settings);
+        }
+
+        return _settings.CurrentBatchID;
+    }
+
     private void UseStock(object sender, RoutedEventArgs e)
     {
         
@@ -298,21 +421,7 @@ public class FactoryPackGrid : DynamicDataGrid<StockHolding>
         if (!ffg.EditItems([ffi]))
             return;
 
-        var _settings = new LocalConfiguration<FactoryFloorLocalSettings>().Load();
-        if (_settings.CurrentBatchDate != DateTime.Today)
-        {
-            StockMovementBatch batch = new StockMovementBatch
-            {
-                Type = StockMovementBatchType.Issue,
-                TimeStamp = DateTime.Now,
-                Notes = "Manufacturing Consumption"
-            };
-            batch.Employee.ID = App.EmployeeID;
-            new Client<StockMovementBatch>().Save(batch,"Created on Factory Floor Screen");
-            _settings.CurrentBatchDate = DateTime.Today;
-            _settings.CurrentBatchID = batch.ID;
-            new LocalConfiguration<FactoryFloorLocalSettings>().Save(_settings);
-        }
+        var batchid = CheckStockMovementBatch();
         
         List<StockMovement> updates = new();
         Guid transactionid = Guid.NewGuid();
@@ -322,7 +431,7 @@ public class FactoryPackGrid : DynamicDataGrid<StockHolding>
             
             var transferout = holding.CreateMovement();
             transferout.JobRequisitionItem.ID = ffi.RequisitionID;
-            transferout.Batch.ID = _settings.CurrentBatchID;
+            transferout.Batch.ID = batchid;
             transferout.Type = StockMovementType.TransferOut;
             transferout.Issued = ffi.Qty;
             transferout.Transaction = transactionid;
@@ -333,7 +442,7 @@ public class FactoryPackGrid : DynamicDataGrid<StockHolding>
             
             var transferin = holding.CreateMovement();
             transferin.JobRequisitionItem.ID = ffi.RequisitionID;
-            transferin.Batch.ID = _settings.CurrentBatchID;
+            transferin.Batch.ID = batchid;
             transferin.Type = StockMovementType.TransferIn;
             transferin.Received = ffi.Qty;
             transferin.Job.ID = CurrentPacket.SetoutLink.JobLink.ID;
@@ -348,7 +457,7 @@ public class FactoryPackGrid : DynamicDataGrid<StockHolding>
         
         var issue = holding.CreateMovement();
         issue.JobRequisitionItem.ID = ffi.RequisitionID;
-        issue.Batch.ID = _settings.CurrentBatchID;
+        issue.Batch.ID = batchid;
         issue.Type = StockMovementType.Issue;
         issue.Issued = ffi.Qty;
         issue.Job.ID = CurrentPacket.SetoutLink.JobLink.ID;
@@ -362,7 +471,7 @@ public class FactoryPackGrid : DynamicDataGrid<StockHolding>
         new Client<StockMovement>().Save(updates,"Issued Stock to Factory Floor", (_,_) => { });
         if (issue.JobRequisitionItem.ID == Guid.Empty)
             UpdateRow<StockHolding, double>(holdingrow, x=>x.Available, holding.Available - ffi.Qty,false);
-        UpdateRow<StockHolding,double>(holdingrow, x => x.Units, holding.Units - ffi.Qty,true);
+        UpdateRow<StockHolding,double>(holdingrow, x => x.Units, holding.Units - ffi.Qty);
 
     }
 }

+ 111 - 63
prs.desktop/Panels/Factory/FactoryPanel.xaml

@@ -67,7 +67,7 @@
             <RowDefinition Height="30" />
             <RowDefinition Height="30" />
             <RowDefinition Height="*" />
-            <RowDefinition Height="Auto" x:Name="MfgRow" />
+            <RowDefinition Height="50" x:Name="MfgRow" />
         </Grid.RowDefinitions>
 
         <Border x:Name="LostTimeActive" Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="0" Grid.RowSpan="4"
@@ -94,16 +94,26 @@
             <ComboBox x:Name="Station" Grid.Column="1" Margin="5,0,0,0" SelectionChanged="Station_SelectionChanged"
                       VerticalContentAlignment="Center" Padding="5" />
         </Grid>
-
-        <Grid Grid.Row="1" Grid.Column="0" Margin="0,4,0,0">
-            <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="Auto" />
-                <ColumnDefinition Width="*" />
-            </Grid.ColumnDefinitions>
-            <Button Grid.Column="0" Content="Search" IsEnabled="False" Padding="5" />
-            <TextBox x:Name="Search" Grid.Column="1" Margin="5,0,0,0" KeyUp="Search_KeyUp" Padding="5" />
-        </Grid>
-
+        
+        <syncfusion:SfTextBoxExt
+            x:Name="Search"
+            Grid.Row="1"
+            BorderThickness="0.75"
+            BorderBrush="Gray"
+            Background="LightYellow"
+            HorizontalContentAlignment="Left"
+            VerticalContentAlignment="Center"
+            Margin="0,4,0,0"
+            KeyUp="Search_KeyUp">
+            <syncfusion:SfTextBoxExt.Watermark>
+                <Label 
+                    Content="Search" 
+                    HorizontalAlignment="Left" 
+                    VerticalAlignment="Center" 
+                    Opacity="0.5"/>
+            </syncfusion:SfTextBoxExt.Watermark>
+        </syncfusion:SfTextBoxExt>
+        
         <ListBox x:Name="Kanban" Grid.Row="2" Grid.RowSpan="2" Grid.Column="0" VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.VirtualizationMode="Recycling" HorizontalContentAlignment="Stretch"
                  ScrollViewer.HorizontalScrollBarVisibility="Disabled" Margin="0,4,0,0">
@@ -386,77 +396,115 @@
             Background="Transparent">
             
             <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="Auto"/>
                 <ColumnDefinition Width="*"/>
-                <ColumnDefinition Width="Auto"/>
-                <ColumnDefinition Width="Auto"/>
             </Grid.ColumnDefinitions>
             
             <Grid.RowDefinitions>
+                <RowDefinition Height="30"/>
                 <RowDefinition Height="30"/>
                 <RowDefinition Height="*"/>
+                <RowDefinition Height="50"/>
             </Grid.RowDefinitions>
             
-            <Button
-                x:Name="_selectPackArea"
+            <Border
                 Grid.Row="0"
                 Grid.Column="0"
-                Padding="10,0"
-                Margin="0,0,5,0"
-                BorderThickness="0.75"
-                Content="Change Area"
-                Click="_selectPackArea_OnClick"/> 
-            
-
-                <syncfusion:SfTextBoxExt
-                    x:Name="_packSearch"
-                    Grid.Row="0"
-                    Grid.Column="1"
-                    BorderThickness="0.75"
-                    BorderBrush="Gray"
-                    Background="LightYellow"
-                    HorizontalContentAlignment="Left"
+                BorderBrush="Gray"
+                BorderThickness="0.75">
+                <Label 
+                    HorizontalAlignment="Center"
                     VerticalContentAlignment="Center"
-                    TextChanged="_packSearch_OnTextChanged">
-                    <syncfusion:SfTextBoxExt.Watermark>
-                        <Label 
-                            Content="Search" 
-                            HorizontalAlignment="Left" 
-                            VerticalAlignment="Center" 
-                            Opacity="0.5"/>
-                    </syncfusion:SfTextBoxExt.Watermark>
-                </syncfusion:SfTextBoxExt>
-
-            <CheckBox
-                x:Name="_packLinked"
-                Grid.Row="0"
-                Grid.Column="2"
-                Margin="5,0,0,0"
-                VerticalContentAlignment="Center"
-                Content="Linked"
-                IsChecked="True"
-                Checked="_packLinked_OnChecked"
-                Unchecked="_packLinked_OnChecked"
-                /> 
+                    FontWeight="Bold"
+                    Content="Materials Usage" />
+            </Border>
             
-            <Button
-                x:Name="_addPack"
-                Grid.Row="0"
-                Grid.Column="3"
-                Padding="10,0"
-                Margin="5,0,0,0"
+            <syncfusion:SfTextBoxExt
+                x:Name="_packSearch"
+                Grid.Row="1"
                 BorderThickness="0.75"
-                Content="Add Location"
-                Click="_addPack_OnClick"/> 
+                BorderBrush="Gray"
+                Background="LightYellow"
+                HorizontalContentAlignment="Left"
+                VerticalContentAlignment="Center"
+                Margin="0,4,0,0"
+                TextChanged="_packSearch_OnTextChanged">
+                <syncfusion:SfTextBoxExt.Watermark>
+                    <Label 
+                        Content="Search" 
+                        HorizontalAlignment="Left" 
+                        VerticalAlignment="Center" 
+                        Opacity="0.5"/>
+                </syncfusion:SfTextBoxExt.Watermark>
+            </syncfusion:SfTextBoxExt>
             
             <prsDesktop:FactoryPackGrid
                 x:Name="_packGrid"
-                Grid.Row="1"
-                Grid.Column="0"
-                Grid.ColumnSpan="4"
+                Grid.Row="2"
                 Margin="0,4,0,0"
+                HeaderHeight="0"
                 OnFilterRecord="_packGrid_OnOnFilterRecord"/>
             
+            <DockPanel
+                Grid.Row="3"
+                Margin="0,4,0,0">
+                
+                <Button
+                    x:Name="_selectPackArea"
+                    DockPanel.Dock="Left"
+                    Padding="10,0"
+                    BorderThickness="0.75"
+                    Width="100"
+                    Click="_selectPackArea_OnClick">
+                    <TextBlock x:Name="_areaDescription" TextWrapping="WrapWithOverflow" Text = "Set Area" TextAlignment="Center" />
+                </Button>
+                
+                <Button
+                    x:Name="_addPack"
+                    DockPanel.Dock="Left"
+                    Padding="10,0"
+                    Margin="5,0,0,0"
+                    BorderThickness="0.75"
+                    Width="100"
+                    Click="_addPack_OnClick">
+                    <TextBlock TextWrapping="WrapWithOverflow" Text = "Retrieve From Warehouse" TextAlignment="Center" />
+                </Button>
+                
+                <Button
+                    x:Name="_returnPack"
+                    DockPanel.Dock="Left"
+                    Padding="10,0"
+                    Margin="5,0,0,0"
+                    BorderThickness="0.75"
+                    Width="100"
+                    Click="_returnPack_OnClick">
+                    <TextBlock TextWrapping="WrapWithOverflow" Text = "Return To Warehouse" TextAlignment="Center" />
+                </Button> 
+                
+                <Button
+                    x:Name="_replaceStock"
+                    DockPanel.Dock="Right"
+                    Padding="10,0"
+                    Margin="5,0,0,0"
+                    BorderThickness="0.75"
+                    Width="80"
+                    Click="_replaceStock_OnClick">
+                    <TextBlock TextWrapping="WrapWithOverflow" Text = "Replace Stock" TextAlignment="Center" />
+                </Button> 
+                
+                <CheckBox
+                    x:Name="_packLinked"
+                    DockPanel.Dock="Left"
+                    Margin="5,0,0,0"
+                    VerticalContentAlignment="Center"
+                    HorizontalAlignment="Center"
+                    Content="Linked"
+                    IsChecked="True"
+                    Checked="_packLinked_OnChecked"
+                    Unchecked="_packLinked_OnChecked"/> 
+                
+            </DockPanel>
+             
+            
         </Grid>
         
         <DockPanel 

+ 58 - 15
prs.desktop/Panels/Factory/FactoryPanel.xaml.cs

@@ -179,24 +179,23 @@ namespace PRSDesktop
                 var area = setups.Get<StockArea>().ToObjects<StockArea>().FirstOrDefault();
                 if (area != null)
                 {
-                    _packGrid.AreaID = _settings.AreaID;
-                    _packGrid.AreaDescription = $"{area.Code}: {area.Description}";
+                    _packGrid.Area = area;
+                    _areaDescription.Text = $"{area.Code}";
                     _addPack.IsEnabled = true;
                 }
                 else
                 {
-                    _packGrid.AreaID = CoreUtils.FullGuid;
-                    _packGrid.AreaDescription = "(No Area Selected)";
+                    _packGrid.Area = null;
+                    _areaDescription.Text = "Set\r\nArea";
                     _settings.AreaID = Guid.Empty;
                     new LocalConfiguration<FactoryFloorLocalSettings>().Save(_settings);
                     _addPack.IsEnabled = false;
                 }
-                
             }
             else
             {
-                _packGrid.AreaID = CoreUtils.FullGuid;
-                _packGrid.AreaDescription = "(No Area Selected)";
+                _packGrid.Area = null;
+                _areaDescription.Text = "Set\r\nArea";
             }
 
             _packGrid.Refresh(true,true);
@@ -2664,12 +2663,11 @@ namespace PRSDesktop
                 false);
             if (dlg.ShowDialog("Select Area"))
             {
-                _settings.AreaID = dlg.IDs().FirstOrDefault();
+                _settings.AreaID = dlg.IDs().First();
+                var area = dlg.Items().First();
                 new LocalConfiguration<FactoryFloorLocalSettings>().Save(_settings);
-                _packGrid.AreaDescription =
-                    dlg.Items(new Columns<StockArea>(x => x.Code).Add(x => x.Description))
-                        .Select(x => $"{x.Code}: {x.Description}").FirstOrDefault() ?? "(No Area Selected)";
-                _packGrid.AreaID = _settings.AreaID;
+                _areaDescription.Text = $"{area.Code}";
+                _packGrid.Area = area;
                 _packGrid.Refresh(false,true);
             }
         }
@@ -2686,7 +2684,7 @@ namespace PRSDesktop
                 if (location != null)
                 {
                     location.Area.ID = _settings.AreaID;
-                    new Client<StockLocation>().Save(location,"Moved To Manufacturing");
+                    new Client<StockLocation>().Save(location,$"Moved To Manufacturing ({_packGrid.Area?.Code})");
                     _packGrid.Refresh(false,true);
                 }
             }
@@ -2730,7 +2728,52 @@ namespace PRSDesktop
         {
             _packGrid?.Refresh(false, false);
         }
-        
-        
+
+
+        private void _returnPack_OnClick(object sender, RoutedEventArgs e)
+        {
+            ContextMenu _menu = new ContextMenu();
+            var dict = _packGrid.Data
+                .ToDictionary<StockHolding, Guid, String>(
+                    x => x.Location.ID,
+                    (row) =>
+                        $"{row.Get<StockHolding, String>(c => c.Location.Code)}: {row.Get<StockHolding, String>(c => c.Location.Description)}"
+                );
+            if (!dict.Any())
+                return;
+            foreach (var key in dict.Keys)
+            {
+                MenuItem item = new MenuItem() { Header = dict[key], DataContext = key };
+                item.Click += (o, args) =>
+                {
+                    var dlg = new MultiSelectDialog<StockArea>(
+                        new Filter<StockArea>(x => x.Active).IsEqualTo(true).And(x => x.ID).IsNotEqualTo(_settings.AreaID),
+                        new Columns<StockArea>(x => x.ID).Add(x => x.Warehouse.Code).Add(x => x.Code)
+                            .Add(x => x.Description),
+                        false);
+                    if (dlg.ShowDialog("Select Area"))
+                    {
+                        var location = new StockLocation() { ID = key };
+                        location.CommitChanges();
+                        location.Area.ID = dlg.IDs().First();
+                        new Client<StockLocation>().Save(location,
+                            $"Returned From Manufacturing ({_packGrid.Area?.Code})");
+                        _packGrid.Refresh(false, true);
+                    }
+                };
+                _menu.Items.Add(item);
+            }
+            _menu.IsOpen = true;
+        }
+
+        private void _replaceStock_OnClick(object sender, RoutedEventArgs e)
+        {
+            _packGrid.ReplaceStock();
+        }
+
+        private void _packGrid_OnOnSelectItem(object sender, DynamicGridSelectionEventArgs e)
+        {
+            _replaceStock.IsEnabled = e.Rows?.Any() == true;
+        }
     }
 }