Browse Source

Merge remote-tracking branch 'origin/frank' into nick

Nick-PRSDigital@bitbucket.org 2 years ago
parent
commit
934434c150

+ 1 - 1
prs.classes/Entities/Equipment/Equipment.cs

@@ -84,7 +84,7 @@ namespace Comal.Classes
         [EditorSequence(13)]
         public DateTime ManufacturedDate { get; set; }
 
-        private CustomerLink Customer { get; set; }
+        public CustomerLink Customer { get; set; }
 
         [EntityRelationship(DeleteAction.SetNull)]
         [EditorSequence("Counters", 1)]

+ 2 - 1
prs.classes/Entities/Product/ProductLink.cs

@@ -47,6 +47,7 @@ namespace Comal.Classes
         public ProductStyleLink DefaultStyle { get; set; }
 
         [NullEditor]
+        [RequiredColumn]
         public StockLocationLink DefaultLocation { get; set; }
 
         [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
@@ -84,7 +85,7 @@ namespace Comal.Classes
             base.Init();
             DefaultStyle = new ProductStyleLink(LinkedEntity);
             Units = new ProductUOMLink();
-            DefaultLocation = new StockLocationLink();
+            DefaultLocation = new StockLocationLink(LinkedEntity);
             TaxCode = new TaxCodeLink(LinkedEntity);
             NonStock = true;
             Image = new ImageDocumentLink();

+ 15 - 7
prs.classes/Entities/Requisition/RequisitionItem.cs

@@ -21,13 +21,11 @@ namespace Comal.Classes
         public JobLink Job { get; set; }
 
         [EditorSequence(1)]
+        [RequiredColumn]
         public override ProductLink Product { get; set; }
         
-        [NullEditor]
-        public string BarCode { get; set; }
-
         [EditorSequence(3)]
-        [CodeEditor(Visible = Visible.Hidden, Editable = Editable.Hidden)]
+        [CodeEditor(Visible = Visible.Optional)]
         public string Code { get; set; }
 
         [MemoEditor]
@@ -35,17 +33,27 @@ namespace Comal.Classes
         public string Description { get; set; }
 
         [EditorSequence(5)]
+        [RequiredColumn]
         public ProductStyleLink Style { get; set; }
 
         [EditorSequence(6)]
+        [RequiredColumn]
         public override StockDimensions Dimensions { get; set; }
 
         [EditorSequence(7)]
         public double Quantity { get; set; }
 
         [EditorSequence(8)]
+        [RequiredColumn]
         public StockLocationLink Location { get; set; }
+
+        [EditorSequence(9)]
+        [TimestampEditor]
+        public DateTime Picked { get; set; }
         
+        [NullEditor]
+        public string BarCode { get; set; }
+
         public Expression<Func<RequisitionItem, int>> AutoIncrementField()
         {
             return x => x.Sequence;
@@ -62,16 +70,16 @@ namespace Comal.Classes
             RequisitionLink = new RequisitionLink();
             Job = new JobLink();
             Location = new StockLocationLink();
-            Style = new ProductStyleLink();
+            Style = new ProductStyleLink(() => this);
         }
 
         static RequisitionItem()
         {
             LinkedProperties.Register<RequisitionItem, ProductLink, String>(x => x.Product, x => x.Code, x => x.Code);
             LinkedProperties.Register<RequisitionItem, ProductLink, String>(x => x.Product, x => x.Name, x => x.Description);
-            StockEntity.LinkStockDimensions<RequisitionItem>();
             LinkedProperties.Register<RequisitionItem, ProductStyleLink, Guid>(x=>x.Product.DefaultStyle, x => x.ID, x => x.Style.ID);
-            
+            LinkedProperties.Register<RequisitionItem, StockLocationLink, Guid>(x=>x.Product.DefaultLocation, x => x.ID, x => x.Location.ID);
+            StockEntity.LinkStockDimensions<RequisitionItem>();
         }
     }
 }

+ 9 - 0
prs.classes/Entities/Stock/StockLocation/StockLocationLink.cs

@@ -5,6 +5,15 @@ namespace Comal.Classes
 {
     public class StockLocationLink : EntityLink<StockLocation>, IStockLocation
     {
+        
+        public StockLocationLink() : this(null)
+        {
+        }
+
+        public StockLocationLink(Func<Entity>? entity) : base(entity)
+        {
+        }
+        
         public StockAreaLink Area { get; set; }
 
         [CodePopupEditor(typeof(StockLocation))]

+ 1 - 1
prs.classes/Entities/Stock/StockMovement.cs

@@ -165,7 +165,7 @@ namespace Comal.Classes
         protected override void Init()
         {
             base.Init();
-            Style = new ProductStyleLink();
+            Style = new ProductStyleLink(() => this);
             Location = new StockLocationLink();
             Employee = new EmployeeLink();
             Job = new JobLink();

+ 1 - 0
prs.desktop/Panels/Jobs/JobRequisitionGrid.cs

@@ -100,6 +100,7 @@ namespace PRSDesktop
             }
             Progress.Close();
             var page = new KanbanGrid();
+            page.MyID = App.EmployeeID;
             page.OnAfterSave += (form, items) =>
             {
                 KanbanAfterSave(form, items);

+ 37 - 3
prs.desktop/Panels/Products/Locations/StockLocationPanel.xaml

@@ -4,9 +4,44 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:local="clr-namespace:PRSDesktop"
+             xmlns:dynamic="clr-namespace:InABox.DynamicGrid;assembly=InABox.DynamicGrid"
              mc:Ignorable="d"
              d:DesignHeight="450" d:DesignWidth="800">
-    <Grid>
+    <dynamic:DynamicSplitPanel MasterCaption="Stock Location List" DetailCaption="Location Summary" MasterWidth="500"
+                               View="Combined">
+        <dynamic:DynamicSplitPanel.Header>
+            <Border CornerRadius="5,5,0,0" BorderBrush="Gray" BorderThickness="0.75" DockPanel.Dock="Top"
+                    Background="WhiteSmoke">
+                <Label Content="Stock Location List" HorizontalContentAlignment="Center" />
+            </Border>
+        </dynamic:DynamicSplitPanel.Header>
+        <dynamic:DynamicSplitPanel.Master>
+            <local:StockLocationGrid x:Name="Locations" DockPanel.Dock="Top" Margin="0,2,0,0" />
+        </dynamic:DynamicSplitPanel.Master>
+
+        <dynamic:DynamicSplitPanel.DetailHeader>
+            <Border CornerRadius="5,5,0,0" BorderBrush="Gray" BorderThickness="0.75" DockPanel.Dock="Top"
+                    Background="WhiteSmoke">
+                <Label Content="Location Summary" HorizontalContentAlignment="Center" />
+            </Border>
+        </dynamic:DynamicSplitPanel.DetailHeader>
+        <dynamic:DynamicSplitPanel.Detail>
+            <local:StockHoldingGrid x:Name="Holdings" DockPanel.Dock="Top" Margin="0,2,0,0" />
+        </dynamic:DynamicSplitPanel.Detail>
+
+        <dynamic:DynamicSplitPanel.SecondaryDetail>
+            <DockPanel>
+                <Border CornerRadius="0,0,0,0" BorderBrush="Gray" BorderThickness="0.75" DockPanel.Dock="Top"
+                    Background="WhiteSmoke">
+                    <Label Content="Stock Movements" HorizontalContentAlignment="Center" />
+                </Border>
+                <local:StockMovementGrid x:Name="Movements" Margin="0,2,0,0" DockPanel.Dock="Top" AllowNullLocation="False"
+                                     AllowNullBatch="True" />
+
+            </DockPanel>
+        </dynamic:DynamicSplitPanel.SecondaryDetail>
+    </dynamic:DynamicSplitPanel>
+    <!--Grid>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="0.3*" />
             <ColumnDefinition Width="0.7*" />
@@ -20,7 +55,6 @@
                     Background="WhiteSmoke">
                 <Label Content="Stock Location List" HorizontalContentAlignment="Center" />
             </Border>
-            <local:StockLocationGrid x:Name="Locations" DockPanel.Dock="Top" Margin="0,2,0,0" />
         </DockPanel>
 
         <DockPanel Grid.Column="1" Grid.Row="0" Margin="2,0,0,0">
@@ -40,5 +74,5 @@
                                      AllowNullBatch="True" />
 
         </DockPanel>
-    </Grid>
+    </Grid-->
 </UserControl>

+ 1 - 1
prs.desktop/Panels/Requisitions/RequisitionGrid.cs

@@ -89,8 +89,8 @@ namespace PRSDesktop
 
             ActionColumns.Add(new DynamicImageColumn(DocumentsImage, DocumentsClick) { Position = DynamicActionColumnPosition.Start });
             ActionColumns.Add(new DynamicImageColumn(FilledImage));
-            ActionColumns.Add(new DynamicImageColumn(StockImage));
             ActionColumns.Add(new DynamicImageColumn(DeliveryImage));
+            ActionColumns.Add(new DynamicImageColumn(StockImage));
             //ActionColumns.Add(new DynamicImageColumn() { Action = LabelClick, Image = GetLabelImage });
             //ActionColumns.Add(new DynamicImageColumn() { Action = DeliveryDocketClick, Image = GetPrinterImage });
 

+ 89 - 204
prs.desktop/Panels/Requisitions/RequisitionItemGrid.cs

@@ -18,12 +18,21 @@ namespace PRSDesktop
 
         public RequisitionItemGrid()
         {
-            Options.AddRange(DynamicGridOption.RecordCount, DynamicGridOption.SelectColumns, DynamicGridOption.EditRows,
-                DynamicGridOption.MultiSelect);
+            Options.BeginUpdate()
+                .Add(DynamicGridOption.RecordCount)
+                .Add(DynamicGridOption.SelectColumns)
+                .Add(DynamicGridOption.AddRows)
+                .Add(DynamicGridOption.EditRows)
+                .Add(DynamicGridOption.DeleteRows)
+                .Add(DynamicGridOption.FilterRows)
+                .Add(DynamicGridOption.MultiSelect)
+                .EndUpdate();
             HiddenColumns.Add(x => x.Code);
             HiddenColumns.Add(x => x.BarCode);
             HiddenColumns.Add(x => x.RequisitionLink.JobLink.ID);
             HiddenColumns.Add(x => x.RequisitionLink.ID);
+            HiddenColumns.Add(x => x.RequisitionLink.Filled);
+            HiddenColumns.Add(x => x.RequisitionLink.Archived);
             HiddenColumns.Add(x => x.Product.ID);
             HiddenColumns.Add(x => x.Product.Deleted);
             HiddenColumns.Add(x => x.Product.DefaultStyle.ID);
@@ -47,8 +56,74 @@ namespace PRSDesktop
             HiddenColumns.Add(x => x.Location.Code);
             HiddenColumns.Add(x => x.Location.Description);
             HiddenColumns.Add(x => x.Location.Deleted);
+            HiddenColumns.Add(x => x.Style.ID);
+            HiddenColumns.Add(x => x.Style.Code);
+            HiddenColumns.Add(x => x.Picked);
+            ActionColumns.Add(new DynamicMenuColumn(SelectHolding,
+                (row) => (row.Get<RequisitionItem,Guid>(c=>c.Product.ID) == Guid.Empty) || row.Get<RequisitionItem, bool>(c => c.Product.NonStock) == true
+                    ? DynamicMenuStatus.Hidden 
+                    : DynamicMenuStatus.Enabled)
+            );
         }
 
+        private void SelectHolding(DynamicMenuColumn column, CoreRow? row)
+        {
+            using (new WaitCursor())
+            {
+                var holdings = new Client<StockHolding>().Query(
+                    new Filter<StockHolding>(x => x.Product.ID).IsEqualTo(row.Get<RequisitionItem, Guid>(c => c.Product.ID)),
+                    new Columns<StockHolding>(x => x.Location.ID)
+                        .Add(x => x.Location.Code)
+                        .Add(x => x.Style.ID)
+                        .Add(x => x.Style.Code)
+                        .Add(x => x.Job.ID)
+                        .Add(x => x.Job.JobNumber)
+                        .Add(x => x.Dimensions.Unit.ID)
+                        .Add(x => x.Dimensions.Length)
+                        .Add(x => x.Dimensions.Width)
+                        .Add(x => x.Dimensions.Height)
+                        .Add(x => x.Dimensions.Weight)
+                        .Add(x => x.Dimensions.UnitSize)
+                        .Add(x => x.Dimensions.Value)
+                        .Add(x => x.Dimensions.Unit.HasQuantity)
+                        .Add(x => x.Dimensions.Unit.HasLength)
+                        .Add(x => x.Dimensions.Unit.HasWidth)
+                        .Add(x => x.Dimensions.Unit.HasWeight)
+                        .Add(x => x.Dimensions.Unit.HasHeight)
+                        .Add(x => x.Dimensions.Unit.Formula)
+                        .Add(x => x.Dimensions.Unit.Format)
+                        .Add(x => x.Units),
+                    new SortOrder<StockHolding>(x => x.Location.Code).ThenBy(x => x.Style.Code).ThenBy(x => x.Dimensions.UnitSize)
+                );
+
+                foreach (var holding in holdings.Rows)
+                {
+                    String text =
+                        $"{holding.Get<StockHolding, String>(c => c.Location.Code)}: {holding.Get<StockHolding, double>(c => c.Units)} @ {holding.Get<StockHolding, String>(c => c.Dimensions.UnitSize)}";
+                    String style = holding.Get<StockHolding, String>(c => c.Style.Code);
+                    if (!String.IsNullOrWhiteSpace(style))
+                        text = $"{text} ({style})";
+                    column.AddItem(text, null, (sel) => SelectLocation(holding,sel));
+                }
+            }
+            
+        }
+
+        private void SelectLocation(CoreRow holdingrow, CoreRow itemrow)
+        {
+            var item = itemrow.ToObject<RequisitionItem>();
+            var holding = holdingrow.ToObject<StockHolding>();
+            item.Location.ID = holding.Location.ID;
+            item.Location.Code = holding.Location.Code;
+            item.Dimensions.CopyFrom(holding.Dimensions, true);
+            item.Style.ID = holding.Style.ID;
+            item.Style.Code = holding.Style.Code;
+            new Client<RequisitionItem>().Save(item, "Changed due to stock holding selection");
+            Data.LoadRow(itemrow, item);
+            InvalidateRow(itemrow);
+        }
+
+
         public Requisition Requisition { get; set; }
 
         protected override void Reload(Filters<RequisitionItem> criteria, Columns<RequisitionItem> columns, ref SortOrder<RequisitionItem>? sort,
@@ -104,6 +179,15 @@ namespace PRSDesktop
             return base.EditItems(items, PageDataHandler, PreloadPages);
         }
 
+        protected override RequisitionItem CreateItem()
+        {
+            var item = base.CreateItem();
+            item.RequisitionLink.ID = Requisition.ID;
+            item.RequisitionLink.Synchronise(Requisition);
+            item.Quantity = 1;
+            return item;
+        }
+
         protected override void DoAdd()
         {
             if (Requisition == null || Requisition.ID.Equals(Guid.Empty))
@@ -118,209 +202,10 @@ namespace PRSDesktop
                 return;
             }
 
-            var dialog = new MultiSelectDialog<Product>(
-                null, //new Filter<Product>(x=>x.DefaultLocation.ID).IsNotEqualTo(Guid.Empty),
-                new Columns<Product>(
-                    x => x.Code,
-                    x => x.Name,
-                    x => x.DefaultStyle.ID,
-                    x => x.Dimensions.Unit.ID,
-                    x => x.Dimensions.Length,
-                    x => x.Dimensions.Width,
-                    x => x.Dimensions.Height,
-                    x => x.Dimensions.Weight,
-                    x => x.Dimensions.UnitSize,
-                    x => x.Dimensions.Value,
-                    x => x.Dimensions.Unit.HasQuantity,
-                    x => x.Dimensions.Unit.HasLength,
-                    x => x.Dimensions.Unit.HasWidth,
-                    x => x.Dimensions.Unit.HasWeight,
-                    x => x.Dimensions.Unit.HasHeight,
-                    x => x.Dimensions.Unit.Formula,
-                    x => x.Dimensions.Unit.Format,
-                    //x => x.Units.ID,
-                    x => x.DefaultLocation.ID,
-                    x => x.UnitQty,
-                    x => x.NonStock
-                )
-            );
-            if (dialog.ShowDialog())
-            {
-                var products = dialog.Data();
-
-                Progress.Show("Adding Products");
-
-                var reqitems = new Client<RequisitionItem>().Load(
-                    new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(Requisition.ID) /*.And(x => x.BoxNumber).IsEqualTo(Boxes) */
-                );
-                var ritems = new List<RequisitionItem>();
-
-                foreach (var product in products.Rows)
-                {
-                    var p = product.ToObject<Product>();
-                    // var productid = product.Get<Product, Guid>(x => x.ID);
-                    // var code = product.Get<Product, string>(c => c.Code);
-                    // var name = product.Get<Product, string>(c => c.Name);
-                    // var styleid = product.Get<Product, Guid>(c => c.DefaultStyle.ID);
-                    // var locationid = product.Get<Product, Guid>(c => c.DefaultLocation.ID);
-                    // var unitid = product.Get<Product, Guid>(c => c.Units.ID);
-                    // var unitsize = product.Get<Product, double>(c => c.UnitSize);
-                    // var unitqty = product.Get<Product, double>(c => c.UnitQty);
-                    // var nonstock = product.Get<Product, bool>(c => c.NonStock);
-
-                    var item = reqitems.FirstOrDefault(x => x.Code.Equals(p.Code));
-                    if (item != null)
-                    {
-                        item.Quantity += 1;
-                        ritems.Add(item);
-                    }
-                    else
-                    {
-                        item = new RequisitionItem
-                        {
-                            //BoxNumber = Boxes,
-                            Code = p.Code,
-                            Description = p.Name,
-                            BarCode = p.Code,
-                            Quantity = 1
-                        };
-                        item.RequisitionLink.ID = Requisition.ID;
-                        item.RequisitionLink.Number = Requisition.Number;
-                        item.RequisitionLink.JobLink.ID = Requisition.JobLink.ID;
-                        item.Product.ID = p.ID;
-                        item.Product.DefaultStyle.ID = p.DefaultStyle.ID;
-                        item.Product.Dimensions.CopyFrom(p.Dimensions);
-                        item.Product.DefaultLocation.ID = p.DefaultLocation.ID;
-                        item.Product.NonStock = p.NonStock;
-                        item.Product.DefaultStyle.ID = p.DefaultStyle.ID;
-                        item.Style.ID = p.DefaultStyle.ID;
-
-                        if (!p.NonStock)
-                            FindHolding(p.ID, p.DefaultStyle.ID, Requisition.JobLink.ID, p.Dimensions.UnitSize, p.DefaultLocation.ID, item);
-
-
-                        ritems.Add(item);
-                    }
-                }
-
-                if (ritems.Any())
-                    new Client<RequisitionItem>().Save(ritems, "Manually Added to Requisition");
-                Refresh(false, true);
-                Progress.Close();
-                //MessageBox.Show(String.Format("{0} products added", products.Rows.Count));
-            }
-        }
-
-        private void FindHolding(Guid productid, Guid styleid, Guid jobid, String unitsize, Guid defaultlocationid, params RequisitionItem[] items)
-        {
-            if (Requisition == null)
-                return;
-
-            // Try and Find a suitable default holding for this item
-            var holdings = new Client<StockHolding>().Query(
-                new Filter<StockHolding>(x => x.Product.ID).IsEqualTo(productid)
-                    .And(x => x.Style.ID).IsEqualTo(styleid)
-                    .And(x => x.Dimensions.UnitSize).IsEqualTo(unitsize),
-                new Columns<StockHolding>(x => x.ID)
-                    .Add(x => x.Job.ID)
-                    .Add(x => x.Location.ID)
-                    .Add(x => x.Location.Code)
-            );
-
-            // Is there a job reserve in the default location?
-            var holdingrows = holdings.Rows.Where(r =>
-                r.Get<StockHolding, Guid>(c => c.Location.ID).Equals(defaultlocationid) &&
-                r.Get<StockHolding, Guid>(c => c.Job.ID).Equals(jobid)).ToArray();
-
-            // Is there a job reserve anywhere?
-            if (!holdingrows.Any())
-                holdingrows = holdings.Rows.Where(r => r.Get<StockHolding, Guid>(c => c.Job.ID).Equals(jobid)).ToArray();
-
-            // Is there Free Stock in the Default Location?
-            if (!holdingrows.Any())
-                holdingrows = holdings.Rows.Where(r =>
-                        r.Get<StockHolding, Guid>(c => c.Location.ID).Equals(defaultlocationid) &&
-                        !Entity.IsEntityLinkValid<StockHolding, JobLink>(x => x.Job, r))
-                    .ToArray();
-
-            // Is there Free Stock Anywhere?
-            if (!holdingrows.Any())
-                holdingrows = holdings.Rows.Where(r => !Entity.IsEntityLinkValid<StockHolding, JobLink>(x => x.Job, r)).ToArray();
-
-            // Only Update the Requi Holding if there is a single location
-            foreach (var item in items)
-            {
-                item.Location.ID = holdingrows.SingleOrDefault()?.Get<StockHolding, Guid>(c => c.Location.ID) ?? Guid.Empty;
-                item.Location.Code = holdingrows.SingleOrDefault()?.Get<StockHolding, String>(c => c.Location.Code) ?? "";
-            }
-        }
-
-        protected override Dictionary<string, object?> EditorValueChanged(IDynamicEditorForm editor, RequisitionItem[] items, string name, object value)
-        {
-            var result = base.EditorValueChanged(editor, items, name, value);
-            if (string.Equals(name, "Product.ID"))
-            {
-                var productid = (Guid)value;
-                var code = "";
-                var description = "";
-                var style = Guid.Empty;
-                var location = Guid.Empty;
-                var nonstock = true;
-                var unitsize = "";
-
-                if (productid != Guid.Empty)
-                {
-                    var lookup = new Client<Product>().Query(
-                        new Filter<Product>(x => x.ID).IsEqualTo(productid),
-                        new Columns<Product>(x => x.Code, x => x.Name, x => x.DefaultStyle.ID, x => x.DefaultLocation.ID, x => x.NonStock)
-                    ).Rows.FirstOrDefault();
-                    code = lookup != null ? lookup.Get<Product, string>(x => x.Code) : "";
-                    description = lookup != null ? lookup.Get<Product, string>(x => x.Name) : "";
-                    style = lookup != null ? lookup.Get<Product, Guid>(x => x.DefaultStyle.ID) : Guid.Empty;
-                    location = lookup != null ? lookup.Get<Product, Guid>(x => x.DefaultLocation.ID) : Guid.Empty;
-                    unitsize = lookup != null ? lookup.Get<Product, String>(x => x.Dimensions.UnitSize) : "";
-                    nonstock = lookup != null ? lookup.Get<Product, bool>(x => x.NonStock) : true;
-                    if (!nonstock)
-                    {
-                        location = lookup != null ? lookup.Get<Product, Guid>(x => x.DefaultStyle.ID) : Guid.Empty;
-                        FindHolding(productid, style, Requisition.JobLink.ID, unitsize, location, items);
-                    }
-                }
-
-                editor.FindEditor("Code").SetValue(code);
-                editor.FindEditor("Description").SetValue(description);
-                editor.FindEditor("Style.ID").SetValue(style);
-                foreach (var item in items)
-                    item.Location.ID = location;
-                editor.FindEditor("Location.ID").Configure();
-            }
-            else if (string.Equals(name, "Style.ID"))
-            {
-                var reqi = items.First();
-                var productid = reqi.Product.ID;
-                var nonstock = reqi.Product.NonStock;
-                var styleid = reqi.Style.ID;
-                var locationid = reqi.Product.DefaultLocation.ID;
-                var unitsize = reqi.Dimensions.UnitSize;
-                if (reqi.Product.IsValid() || !nonstock)
-                {
-                    FindHolding(productid, styleid, Requisition.JobLink.ID, unitsize, locationid, items);
-                    editor.FindEditor("Holding.ID").Configure();
-                }
-            }
+            base.DoAdd();
 
-            return result;
         }
-
-        // protected override void LookupsDefined(ILookupEditorControl sender, RequisitionItem[] items)
-        // {
-        //     base.LookupsDefined(sender, items);
-        //     if (string.Equals(sender.ColumnName, "Holding.ID") && sender.Loaded)
-        //     {
-        //         var id = items.Select(x => x.Holding.ID).Distinct().SingleOrDefault();
-        //         if (!Equals(id, sender.GetValue()))
-        //             sender.SetValue(id);
-        //     }
-        // }
+        
+        
     }
 }

+ 30 - 1
prs.desktop/Panels/Requisitions/RequisitionPanel.xaml.cs

@@ -388,11 +388,40 @@ namespace PRSDesktop
                 return;
             }
 
-            _requisition.Filled = _requisition.Filled.IsEmpty() ? DateTime.Now : DateTime.MinValue;
+            DateTime filltime = DateTime.Now;
+            
+            var unpickeditems = Items.Data.Rows.Where(r =>
+                _requisition.Filled.IsEmpty()
+                && (r.Get<RequisitionItem, Guid>(x => x.Product.ID) != Guid.Empty)
+                && (r.Get<RequisitionItem, bool>(x => x.Product.NonStock) != true)
+                && (r.Get<RequisitionItem, DateTime>(x => x.Picked).IsEmpty())
+            );
+            if (unpickeditems.Any())
+            {
+                var confirm = MessageBox.Show("Unpicked items exist on this requisition!\n\nDo you want to mark them as picked now?",
+                    "Unpicked Items", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
+                if (confirm == MessageBoxResult.Cancel)
+                    return;
+                filltime = DateTime.Now;
+                if (confirm == MessageBoxResult.Yes)
+                {
+                    List<RequisitionItem> updates = new List<RequisitionItem>();
+                    foreach (var row in unpickeditems)
+                    {
+                        var item = row.ToObject<RequisitionItem>();
+                        item.Picked = filltime;
+                        updates.Add(item);
+                    }
+                    new Client<RequisitionItem>().Save(updates, "Marked as Picked because Requisition was marked as filled");
+                }
+            }
+
+            _requisition.Filled = _requisition.Filled.IsEmpty() ? filltime : DateTime.MinValue;
             Progress.Show(_requisition.Filled.IsEmpty() ? "Clearing Delivery Items" : "Creating Delivery Items");
             new Client<Requisition>().Save(_requisition, "Updated Filled Flag");
             Requisitions.UpdateRow<Requisition, DateTime>(Requisitions.SelectedRows.First(), x => x.Filled, _requisition.Filled);
             LoadRequisition();
+            Items.Refresh(false, true);
             Progress.Close();
         }
 

+ 1 - 1
prs.desktop/prsdesktop.iss

@@ -5,7 +5,7 @@
 #pragma verboselevel 9
 
 #define MyAppName "PRS Desktop"
-#define MyAppVersion "6.44"
+#define MyAppVersion "6.45"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSDesktop.exe"

+ 34 - 13
prs.server/Forms/Deletions/DeletedEntityGrid.cs

@@ -9,17 +9,18 @@ using System.Linq;
 using System.Reflection;
 using System.Text;
 using System.Threading.Tasks;
+using System.Windows.Forms;
 
 namespace PRSServer.Forms
 {
     class DeletedEntityGrid<T> : DynamicGrid<T>, ISpecificGrid where T : Entity, new()
     {
 
-        private Deletion Deletion { get; set; }
+        private CoreTable Table { get; set; }
 
-        public DeletedEntityGrid(Deletion deletion)
+        public DeletedEntityGrid(CoreTable table)
         {
-            Deletion = deletion;
+            Table = table;
 
             HiddenColumns.Add(x => x.ID);
 
@@ -30,20 +31,32 @@ namespace PRSServer.Forms
         protected override DynamicGridColumns LoadColumns()
         {
             var result = base.LoadColumns();
-            result.RemoveAll(x =>
+
+            var deletionColumns = DeletionData.DeletionColumns<T>();
+
+            var columns = new DynamicGridColumns();
+            foreach(var column in deletionColumns.GetColumns())
+            {
+                var resultColumn = result.FirstOrDefault(x => x.ColumnName == column.Property);
+                if(resultColumn is not null)
+                {
+                    columns.Add(resultColumn);
+                }
+            }
+
+            if(columns.Count == 0)
             {
-                var prop = CoreUtils.GetProperty(typeof(T), x.ColumnName);
-                return prop.GetCustomAttribute<DoNotSerialize>() != null && prop.GetCustomAttribute<DoNotPersist>() != null;
-            });
-            return result;
+                columns.Add<T, Guid>(x => x.ID, 0, "ID", "", Alignment.MiddleLeft);
+            }
+
+            return columns;
         }
 
         protected override void Reload(Filters<T> criteria, Columns<T> columns, ref SortOrder<T>? sort, Action<CoreTable?, Exception?> action)
         {
             try
             {
-                var table = DbFactory.Provider.QueryDeleted(Deletion, criteria.Combine(), columns, sort);
-                action(table, null);
+                action(Table, null);
             }
             catch(Exception e)
             {
@@ -53,9 +66,7 @@ namespace PRSServer.Forms
 
         protected override T LoadItem(CoreRow row)
         {
-            var id = row.Get<T, Guid>(x => x.ID);
-            var filter = new Filter<T>(x => x.ID).IsEqualTo(id);
-            return DbFactory.Provider.QueryDeleted(Deletion, filter, null).Rows.FirstOrDefault()?.ToObject<T>();
+            return Table.Rows[row.Index].ToObject<T>();
         }
 
         protected override void DoEdit()
@@ -67,11 +78,21 @@ namespace PRSServer.Forms
 
             var editor = new DynamicEditorForm(typeof(T));
             editor.ReadOnly = true;
+            editor.OnCustomiseColumns += Editor_OnCustomiseColumns;
             editor.OnDefineLookups += sender => DefineLookups(sender, Array.Empty<T>());
             editor.Items = new BaseObject[] { item };
             editor.ShowDialog();
         }
 
+        private DynamicGridColumns Editor_OnCustomiseColumns(object sender, DynamicGridColumns? source)
+        {
+            var columns = new DynamicGridColumns();
+            columns.ExtractColumns(typeof(T));
+            var deletionColumns = DeletionData.DeletionColumns<T>();
+            columns.RemoveAll(x => !deletionColumns.GetColumns().Any(y => y.Property == x.ColumnName));
+            return columns;
+        }
+
         public override void SaveItem(T item)
         {
             // No saving allowed

+ 1 - 0
prs.server/Forms/Deletions/DeletionsGrid.cs

@@ -26,6 +26,7 @@ namespace PRSServer.Forms
                 .EndUpdate();
 
             HiddenColumns.Add(x => x.ID);
+            HiddenColumns.Add(x => x.Data);
 
             Refresh = AddButton("", Properties.Resources.refresh.AsBitmapImage(), RefreshItems);
             Recover = AddButton("Recover", null, RecoverItems);

+ 7 - 4
prs.server/Forms/Deletions/ViewDeletionWindow.xaml.cs

@@ -27,6 +27,7 @@ namespace PRSServer.Forms
     {
 
         private Deletion Deletion { get; set; }
+        private DeletionData DeletionData { get; set; }
 
         private HashSet<DynamicTabItem> _loaded = new();
 
@@ -35,6 +36,7 @@ namespace PRSServer.Forms
             InitializeComponent();
 
             Deletion = deletion;
+            DeletionData = Serialization.Deserialize<DeletionData>(deletion.Data) ?? new();
 
             Pages.SelectionChanged += PagesSelectionChanged;
 
@@ -54,13 +56,14 @@ namespace PRSServer.Forms
 
         private void LoadPages()
         {
-            var entityTypes = DbFactory.Provider.GetDeletionTypes(Deletion);
-            foreach(var type in entityTypes)
+            foreach(var (entityName, cascade) in DeletionData.Cascades)
             {
-                var title = new Inflector.Inflector(new CultureInfo("en")).Pluralize(CoreUtils.GetCaption(type));
+                if (!CoreUtils.TryGetEntity(entityName, out var entityType)) continue;
+
+                var title = new Inflector.Inflector(new CultureInfo("en")).Pluralize(CoreUtils.GetCaption(entityType));
                 var tab = new DynamicTabItem() { Header = title };
 
-                var grid = Activator.CreateInstance(typeof(DeletedEntityGrid<>).MakeGenericType(type), Deletion) as IDynamicGrid;
+                var grid = Activator.CreateInstance(typeof(DeletedEntityGrid<>).MakeGenericType(entityType), cascade) as IDynamicGrid;
                 grid.Refresh(true, true);
                 tab.Content = grid;
 

+ 1 - 1
prs.server/PRSServer.iss

@@ -5,7 +5,7 @@
 #pragma verboselevel 9
 
 #define MyAppName "PRS Server"
-#define MyAppVersion "6.44"
+#define MyAppVersion "6.45"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSServer.exe"

+ 2 - 1
prs.stores/RequisitionItemStore.cs

@@ -19,7 +19,8 @@ namespace Comal.Stores
                 if (!r.Filled.Equals(DateTime.MinValue))
                     return KanbanCategory.Waiting;
                 if (Provider.Query(
-                        new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(r.ID),
+                        new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(r.ID)
+                            .And(x=>x.Picked).IsNotEqualTo(DateTime.MinValue),
                         new Columns<RequisitionItem>(x => x.ID)
                     ).Rows.Any()
                    )

+ 4 - 4
prs.stores/RequisitionStore.cs

@@ -5,6 +5,7 @@ using System.Linq.Expressions;
 using Comal.Classes;
 using H.Pipes.Extensions;
 using InABox.Core;
+using Syncfusion.Windows.Tools.Controls;
 
 namespace Comal.Stores
 {
@@ -119,7 +120,7 @@ namespace Comal.Stores
 
             IEnumerable<RequisitionItem> requisitionitems = null;
             IEnumerable<DeliveryItem> deliveryitems = null;
-
+            
             UpdateDeliveryItems(entity, ref requisitionitems, ref deliveryitems);
             UpdateTakenBy(entity, ref requisitionitems, ref deliveryitems);
             UpdateStockBatches(entity, ref requisitionitems);
@@ -146,13 +147,12 @@ namespace Comal.Stores
                 return KanbanCategory.Open;
             });
         }
-
-
+        
         protected override void BeforeDelete(Requisition entity)
         {
             UnlinkTrackingKanban<RequisitionKanban, Requisition, RequisitionLink>(entity);
         }
-
+        
         #region Delivery Items
 
         private void CreateDeliveryItems(Requisition entity, ref IEnumerable<RequisitionItem> requisitionitems,