Przeglądaj źródła

Merged RequisitionItemGrid with JobPickingListItemGrid
Improved Picking List Toggles and Buttons

frogsoftware 1 tydzień temu
rodzic
commit
3cc8772a8d

+ 22 - 3
prs.classes/Entities/Requisition/Requisition.cs

@@ -11,12 +11,27 @@ namespace Comal.Classes
 
         public override AggregateCalculation Calculation => AggregateCalculation.Count;
 
-        public override Dictionary<Expression<Func<RequisitionDocument, object>>, Expression<Func<Requisition, object>>> Links =>
-            new Dictionary<Expression<Func<RequisitionDocument, object>>, Expression<Func<Requisition, object>>>()
+        public override Dictionary<Expression<Func<RequisitionDocument, object?>>, Expression<Func<Requisition, object?>>> Links =>
+            new Dictionary<Expression<Func<RequisitionDocument, object?>>, Expression<Func<Requisition, object?>>>()
             {
-                { RequisitionDocument => RequisitionDocument.EntityLink.ID, Requisition => Requisition.ID }
+                { requisitionDocument => requisitionDocument.EntityLink.ID, requisition => requisition.ID }
             };
     }
+    
+    // public class RequisitionOpenCount : CoreAggregate<Requisition, RequisitionItem, Guid>
+    // {
+    //     public override Expression<Func<RequisitionItem, Guid>> Aggregate => x => x.ID;
+    //
+    //     public override AggregateCalculation Calculation => AggregateCalculation.Count;
+    //
+    //     public override Dictionary<Expression<Func<RequisitionItem, object?>>, Expression<Func<Requisition, object?>>> Links =>
+    //         new Dictionary<Expression<Func<RequisitionItem, object?>>, Expression<Func<Requisition, object?>>>()
+    //         {
+    //             { requisitionItem => requisitionItem.RequisitionLink.ID, requisition => requisition.ID }
+    //         };
+    //
+    //     public override Filter<RequisitionItem>? Filter => new Filter<RequisitionItem>(x => x.Done).IsEqualTo(false);
+    // }
 
     [UserTracking(typeof(StockMovement))]
     public class Requisition : Entity, IRequisition, IPersistent, IRemotable, INumericAutoIncrement<Requisition>, ILicense<ProjectManagementLicense>, IJobScopedItem
@@ -119,6 +134,10 @@ namespace Comal.Classes
         [LoggableProperty]
         public DateTime Archived { get; set; } = DateTime.MinValue;
         
+        // [Aggregate(typeof(RequisitionOpenCount))]
+        // [IntegerEditor(Editable = Editable.Hidden)]
+        // public int OpenItems { get; set; }
+        
         public override string ToString()
         {
             return string.Format("{0}: {1} ({2} - {3})", Number, Title, JobLink.JobNumber, JobLink.Name);

+ 18 - 8
prs.desktop/Panels/Jobs/Picking Lists/JobPickingListGrid.cs

@@ -1,32 +1,42 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
+using System.Drawing;
 using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using com.healthmarketscience.jackcess;
+using System.Windows.Media.Imaging;
 using Comal.Classes;
-using InABox.Clients;
 using InABox.Core;
 using InABox.DynamicGrid;
 using InABox.Wpf;
+using InABox.WPF;
 
 namespace PRSDesktop;
 
 internal class JobPickingListGrid : DynamicDataGrid<Requisition>, IMasterDetailControl<Job,Requisition>
 {
-    public Job? Master { get; set; }
 
+    private readonly BitmapImage forklift = PRSDesktop.Resources.forklift.AsBitmapImage(Color.White);
+    
+    public Job? Master { get; set; }
+    
     public Filter<Requisition> MasterDetailFilter => (Master?.ID ?? Guid.Empty) != Guid.Empty
         ? new Filter<Requisition>(x => x.JobLink.ID).IsEqualTo(Master.ID)
         : new Filter<Requisition>().None();
 
     public JobPickingListGrid()
     {
+        HiddenColumns.Add(Columns.Required<Requisition>());
         HiddenColumns.Add(x => x.ID);
         HiddenColumns.Add(x => x.JobLink.ID);
+        HiddenColumns.Add(x => x.StockUpdated);
+        ActionColumns.Add(new DynamicImageColumn(StockStatus));
     }
+
+    private BitmapImage? StockStatus(CoreRow? row)
+    {
+        return row == null || !row.Get<Requisition, DateTime>(c => c.StockUpdated).IsEmpty()
+            ? forklift
+            : null;
+    }
+
     protected override void DoReconfigure(DynamicGridOptions options)
     {
         base.DoReconfigure(options);

+ 0 - 130
prs.desktop/Panels/Jobs/Picking Lists/JobPickingListItemGrid.cs

@@ -1,130 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reactive.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using Comal.Classes;
-using InABox.Clients;
-using InABox.Core;
-using InABox.DynamicGrid;
-using InABox.Wpf;
-using InABox.WPF;
-using PRSDesktop.Panels.Requisitions;
-
-namespace PRSDesktop;
-
-internal class JobPickingListItemGrid : DynamicDataGrid<RequisitionItem>, ISpecificGrid, IMasterDetailControl<Requisition, RequisitionItem>
-{
-    public Requisition? Master { get; set; }
-
-    private Task<List<Product>>? _products;
-    
-    public Filter<RequisitionItem> MasterDetailFilter => Master != null
-        ? new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(Master.ID)
-        : new Filter<RequisitionItem>().None();
-
-    protected override void Init()
-    {
-        base.Init();
-
-        HiddenColumns.Add(x => x.RequisitionLink.JobLink.ID);
-        HiddenColumns.Add(x => x.Product.ID);
-        HiddenColumns.Add(x => x.Style.ID);
-        HiddenColumns.Add(x => x.JobLink.ID);
-        HiddenColumns.Add(x =>x.Dimensions.Unit.ID);
-        HiddenColumns.Add(x => x.Dimensions.UnitSize);
-        HiddenColumns.Add(x => x.JobRequisitionItem.ID);
-        HiddenColumns.Add(x => x.Location.ID);
-        HiddenColumns.Add(x => x.EditType);
-        HiddenColumns.Add(x => x.Done);
-    }
-    
-    protected override void DoReconfigure(DynamicGridOptions options)
-    {
-        base.DoReconfigure(options);
-        options.SelectColumns = true;
-        options.FilterRows = true;
-    }
-
-    protected override void Reload(
-    	Filters<RequisitionItem> criteria, Columns<RequisitionItem> columns, ref SortOrder<RequisitionItem>? sort,
-    	CancellationToken token, Action<CoreTable?, Exception?> action)
-    {
-        criteria.Add(MasterDetailFilter);
-        base.Reload(criteria, columns, ref sort, token, action);
-    }
-
-    private List<Product> GetProducts()
-    {
-        _products ??= Task.Run(() =>
-        {
-            return Client.Query(null, Columns.None<Product>().Add(x => x.Code).Add(x => x.Name).Add(x => x.ID)).ToList<Product>();
-        });
-        return _products.Result;
-    }
-
-    private void DoEdit(CoreRow? row)
-    {
-        var item = row?.ToObject<RequisitionItem>();
-        if(item is null)
-        {
-            if (!CanCreateItems())
-                return;
-            item = CreateItem();
-        }
-
-        var editor = new RequisitionItemEditor(GetProducts, item, false);
-        if(editor.ShowDialog() == true && editor.Result is not null)
-        {
-            Refresh(false, true);
-            DoChanged();
-        }
-    }
-
-    protected override void DoEdit()
-    {
-        var rows = SelectedRows;
-        if (rows.Length != 1) return;
-
-        if (rows[0].Get<RequisitionItem, bool>(x => x.Done))
-        {
-            base.DoEdit();
-        }
-        else
-        {
-            DoEdit(rows[0]);
-        }
-    }
-    protected override void DoAdd(bool openEditorOnDirectEdit = false)
-    {
-        DoEdit(null);
-    }
-
-    public override void InitialiseEditorForm(IDynamicEditorForm editor, RequisitionItem[] items, Func<Type, CoreTable?>? pageDataHandler = null, bool preloadPages = false)
-    {
-        base.InitialiseEditorForm(editor, items, pageDataHandler, preloadPages);
-
-        if(items.Any(x => x.Done))
-        {
-            editor.ReadOnly = true;
-        }
-    }
-
-    protected override bool CanCreateItems()
-    {
-        return base.CanCreateItems() &&  (Master?.ID ?? Guid.Empty) != Guid.Empty;
-    }
-
-    public override RequisitionItem CreateItem()
-    {
-        var result = base.CreateItem();
-        result.RequisitionLink.ID = Master?.ID ?? Guid.Empty;
-        result.RequisitionLink.Synchronise(Master ?? new Requisition());
-        result.JobLink.ID = Master?.JobLink.ID ?? Guid.Empty;
-        result.JobLink.Synchronise(Master?.JobLink ?? new JobLink());
-        return result;
-    }
-}

+ 2 - 2
prs.desktop/Panels/Jobs/Picking Lists/JobPickingListPanel.xaml

@@ -7,14 +7,14 @@
              xmlns:dynamicgrid="clr-namespace:InABox.DynamicGrid;assembly=InABox.Wpf"
              mc:Ignorable="d" 
              d:DesignHeight="450" d:DesignWidth="800">
-    <dynamicgrid:DynamicSplitPanel AnchorWidth="500" View="Combined" AllowableViews="Combined">
+    <dynamicgrid:DynamicSplitPanel AnchorWidth="400" View="Combined" AllowableViews="Combined">
 
         <dynamicgrid:DynamicSplitPanel.Master>
             <local:JobPickingListGrid x:Name="PickingLists" OnSelectItem="PickingLists_OnSelectItem" />
         </dynamicgrid:DynamicSplitPanel.Master>
 
         <dynamicgrid:DynamicSplitPanel.Detail>
-            <local:JobPickingListItemGrid x:Name="Items" />
+            <local:RequisitionItemGrid x:Name="Items" OnRequisitionChanged="Items_OnOnRequisitionChanged" />
         </dynamicgrid:DynamicSplitPanel.Detail>
 
     </dynamicgrid:DynamicSplitPanel>

+ 5 - 0
prs.desktop/Panels/Jobs/Picking Lists/JobPickingListPanel.xaml.cs

@@ -84,4 +84,9 @@ public partial class JobPickingListPanel : UserControl, IPanel<Requisition>, IMa
         Items.Master = e.Rows?.FirstOrDefault()?.ToObject<Requisition>();
         Items.Refresh(false, true);
     }
+    
+    private void Items_OnOnRequisitionChanged(object? sender, EventArgs e)
+    {
+        PickingLists.Refresh(false, true);
+    }
 }

+ 370 - 0
prs.desktop/Panels/Jobs/Picking Lists/RequisitionItemGrid.cs

@@ -0,0 +1,370 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Reactive.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media.Imaging;
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Core;
+using InABox.DynamicGrid;
+using InABox.Wpf;
+using InABox.WPF;
+using PRSDesktop.Panels.Requisitions;
+
+namespace PRSDesktop;
+
+internal class RequisitionItemGrid : DynamicDataGrid<RequisitionItem>, ISpecificGrid, IMasterDetailControl<Requisition, RequisitionItem>
+{
+    
+    private static readonly BitmapImage tick = PRSDesktop.Resources.tick.AsBitmapImage();
+    private static readonly BitmapImage warning = PRSDesktop.Resources.warning.AsGrayScale().AsBitmapImage();
+    private static readonly BitmapImage plus = PRSDesktop.Resources.plus.AsBitmapImage();
+    private static readonly BitmapImage minus = PRSDesktop.Resources.minus.AsBitmapImage();
+    private static readonly BitmapImage _forklift = PRSDesktop.Resources.forklift.AsBitmapImage(Color.White);
+    
+    public Requisition? Master { get; set; }
+
+    private Task<List<Product>>? _products;
+    
+    public bool StockButtonVisible { get; set; }
+
+    public event EventHandler? OnRequisitionChanged;
+    
+    public Filter<RequisitionItem> MasterDetailFilter => Master != null
+        ? new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(Master.ID)
+        : new Filter<RequisitionItem>().None();
+    
+    private readonly Button _picked;
+    private  readonly Button _stock;
+    
+    public RequisitionItemGrid()
+    {
+        _picked = AddButton("Mark as Picked", tick, MarkAsPicked_Clicked);
+        _picked.Visibility = Visibility.Collapsed;
+        
+        _stock = AddButton("Update Stock", _forklift, UpdateStock_Clicked);
+        _stock.Visibility = Visibility.Collapsed;
+        
+        _products = Task.Run(() =>
+        {
+            return Client.Query(null, Columns.None<Product>().Add(x => x.Code).Add(x => x.Name).Add(x => x.ID)).ToList<Product>();
+        });
+    }
+
+    
+    protected override void Init()
+    {
+        base.Init();
+        
+        HiddenColumns.Add(
+            Columns
+                .Required<RequisitionItem>()
+                .AddDimensionsColumns(x=>x.Dimensions)
+        );
+        
+        HiddenColumns.Add(x => x.RequisitionLink.JobLink.ID);
+        HiddenColumns.Add(x => x.RequisitionLink.ID);
+        HiddenColumns.Add(x => x.RequisitionLink.JobScope.ID);
+        HiddenColumns.Add(x => x.RequisitionLink.Filled);
+        HiddenColumns.Add(x => x.RequisitionLink.Archived);
+        HiddenColumns.Add(x => x.RequisitionLink.StockUpdated);
+        
+        HiddenColumns.Add(x => x.JobLink.ID);
+        HiddenColumns.Add(x => x.JobRequisitionItem.ID);
+        HiddenColumns.Add(x => x.SourceJRI.ID);
+
+        HiddenColumns.Add(x => x.Product.ID);
+        HiddenColumns.Add(x => x.Product.NonStock);
+        HiddenColumns.Add(x => x.Product.DefaultInstance.Style.ID);
+        
+        HiddenColumns.Add(x => x.Style.ID);
+        HiddenColumns.Add(x => x.Style.Code);
+        
+        HiddenColumns.Add(x=>x.Quantity);
+
+        HiddenColumns.Add(x => x.Code);
+        HiddenColumns.Add(x => x.BarCode);
+
+        HiddenColumns.Add(x => x.Location.ID);
+        HiddenColumns.Add(x => x.Location.Code);
+        HiddenColumns.Add(x => x.Location.Description);
+
+        HiddenColumns.Add(x => x.EditType);
+        HiddenColumns.Add(x=>x.ActualQuantity);
+        HiddenColumns.Add(x => x.Done);
+        
+        HiddenColumns.Add(x => x.Image.ID);
+        HiddenColumns.Add(x => x.Image.FileName);
+        
+        ActionColumns.Add(new DynamicImageManagerColumn<RequisitionItem>(this, x => x.Image, true)
+        {
+            Position = DynamicActionColumnPosition.Start
+        });
+        
+        ActionColumns.Add(new DynamicImageColumn(Done_Image, Done_Click)
+        {
+            Position = DynamicActionColumnPosition.End
+        });
+        
+    }
+    
+    private bool MarkAsPicked_Clicked(Button button, CoreRow[] rows)
+    {
+        if (rows?.Any() != true)
+            return false;
+        
+        var _items = rows.Select(x=>x.ToObject<RequisitionItem>()).ToArray();
+        foreach (var _item in _items)
+        {
+            _item.Done = !_item.Done;
+            _item.ActualQuantity = _item.Done ? _item.Quantity : 0.0;
+        }
+        Client.Save(_items,"Pick Status Updated",(o,e) => { });
+        foreach (var row in rows)
+        {
+            var _item = _items.FirstOrDefault(x => x.ID == row.Get<RequisitionItem, Guid>(c => c.ID));
+            if (_item is not null)
+            {
+                row.Set<RequisitionItem, bool>(c => c.Done, _item.Done);
+                row.Set<RequisitionItem, double>(c => c.ActualQuantity, _item.ActualQuantity);
+                InvalidateRow(row);
+            }
+        }
+        CheckStockButton();
+        CheckPickButton();
+        return false;
+    }
+
+    protected override void SelectItems(CoreRow[]? rows)
+    {
+        base.SelectItems(rows);
+        CheckPickButton();
+    }
+
+    private void CheckPickButton()
+    {
+        var _status = SelectedRows?.Select(r => r.Get<RequisitionItem, bool>(c => c.Done)).Distinct().ToArray() ?? [];
+        var blanklocations = SelectedRows?.Any(r => r.Get<RequisitionItem, Guid>(c => c.Location.ID) == Guid.Empty) == true;
+        if (_status.Length != 1 || blanklocations || !(Master?.StockUpdated ?? DateTime.MinValue).IsEmpty())
+        {
+            _picked.Visibility = Visibility.Collapsed;
+            return;
+        }
+
+        if (_status[0] == true)
+            UpdateButton(_picked,minus,"Clear Items");
+        else
+            UpdateButton(_picked,plus,"Mark as Picked");
+        _picked.Visibility = Visibility.Visible;
+    }
+    
+    private bool Done_Click(CoreRow? row)
+    {
+        if (row is null || row.Get<RequisitionItem,Guid>(c=>c.Location.ID) == Guid.Empty || Master?.StockUpdated.IsEmpty() == false) 
+            return false;
+
+        var _item = row.ToObject<RequisitionItem>();
+        _item.Done = !_item.Done;
+        _item.ActualQuantity = _item.Done ? _item.Quantity : 0.0;
+        Client.Save(_item,_item.Done ? "Marked as Picked" : "Marked as unpicked", (o,e) => { });
+        row.Set<RequisitionItem,bool>(c => c.Done,_item.Done);
+        row.Set<RequisitionItem,double>(c => c.ActualQuantity,_item.ActualQuantity);
+        InvalidateRow(row);
+        CheckStockButton();
+        CheckPickButton();
+        return false;
+    }
+
+    private void CheckStockButton()
+    {
+        bool updated = Master?.StockUpdated.IsEmpty() == false;
+        
+        bool alldone = Data.Rows.Any() && Data.Rows.All(r => r.Get<RequisitionItem, bool>(c => c.Done));
+        var blanklocations = SelectedRows?.Any(r => r.Get<RequisitionItem, Guid>(c => c.Location.ID) == Guid.Empty) == true;
+        
+        _stock.Visibility = alldone && !blanklocations && StockButtonVisible
+            ? Visibility.Visible 
+            : Visibility.Collapsed;
+        UpdateButton(_stock,_forklift,updated ? "Clear Stock Movements" : "Update Stock Holdings");
+    }
+    
+    private bool UpdateStock_Clicked(Button button, CoreRow[] rows)
+    {
+        if (Master == null)
+            return false;
+        Master.StockUpdated = Master.StockUpdated.IsEmpty() ? DateTime.Now : DateTime.MinValue;
+        Client.Save(Master,"Updated Stock Movements");
+        OnRequisitionChanged?.Invoke(this, EventArgs.Empty);
+        CheckStockButton();
+        CheckPickButton();
+        return false;
+    }
+    
+    private BitmapImage? Done_Image(CoreRow? row)
+    {
+        return row is null 
+            ? tick 
+            : row.Get<RequisitionItem,Guid>(c => c.ID) == Guid.Empty 
+                ? warning 
+                : row.Get<RequisitionItem, bool>(x => x.Done) == true 
+                    ? tick 
+                    : null;
+    }
+    
+    protected override void DoReconfigure(DynamicGridOptions options)
+    {
+        base.DoReconfigure(options);
+        options.SelectColumns = true;
+        options.FilterRows = true;
+        options.HideDatabaseFilters = true;
+        options.HideDirectEditButton = true;
+        options.RecordCount = true;
+        options.AddRows = true;
+        options.EditRows = true;
+        options.DeleteRows = true;
+    }
+
+    protected override void Reload(
+    	Filters<RequisitionItem> criteria, Columns<RequisitionItem> columns, ref SortOrder<RequisitionItem>? sort,
+    	CancellationToken token, Action<CoreTable?, Exception?> action)
+    {
+        criteria.Add(MasterDetailFilter);
+        sort = new SortOrder<RequisitionItem>(x => x.Created);
+        base.Reload(criteria, columns, ref sort, token, action);
+    }
+
+    protected override void OnAfterRefresh()
+    {
+        base.OnAfterRefresh();
+        CheckStockButton();
+    }
+
+    protected override void DoAfterSave(IDynamicEditorForm editor, RequisitionItem[] items)
+    {
+        base.DoAfterSave(editor, items);
+        CheckStockButton();
+    }
+    
+    private List<Product> GetProducts()
+    {
+        _products ??= Task.Run(() =>
+        {
+            return Client.Query(null, Columns.None<Product>().Add(x => x.Code).Add(x => x.Name).Add(x => x.ID)).ToList<Product>();
+        });
+        return _products.Result;
+    }
+    
+
+
+    private void DoEdit(CoreRow? row)
+    {
+        if (!CanCreateItems())
+            return;
+        
+        var item = row?.ToObject<RequisitionItem>();
+        if(item is null)
+            item = CreateItem();
+        
+        if (item.Done)
+        {
+            MessageWindow.ShowMessage("Cannot edit an item that is marked as done!","Error");
+            return;
+        }
+
+        var editor = new RequisitionItemEditor(GetProducts, item, false);
+        if(editor.ShowDialog() == true && editor.Result is not null)
+        {
+            Refresh(false, true);
+            DoChanged();
+        }
+    }
+
+    protected override void DoEdit()
+    {
+        var rows = SelectedRows;
+        if (rows.Length != 1) 
+            return;
+
+        if (rows[0].Get<RequisitionItem, bool>(x => x.Done))
+            base.DoEdit();
+        else
+            DoEdit(rows[0]);
+    }
+    protected override void DoAdd(bool openEditorOnDirectEdit = false)
+    {
+        DoEdit(null);
+    }
+
+    public override void InitialiseEditorForm(IDynamicEditorForm editor, RequisitionItem[] items, Func<Type, CoreTable?>? pageDataHandler = null, bool preloadPages = false)
+    {
+        base.InitialiseEditorForm(editor, items, pageDataHandler, preloadPages);
+
+        if(items.Any(x => x.Done))
+        {
+            editor.ReadOnly = true;
+        }
+    }
+    
+    protected override bool CanCreateItems()
+    {
+        if (!base.CanCreateItems())
+            return false;
+        
+        if(!Security.CanEdit<Requisition>() || !Security.CanEdit<RequisitionItem>())
+            return false;
+        
+        if(Master is null || Master.ID == Guid.Empty)
+        {
+            MessageWindow.ShowMessage("Please select a requisition.", "No requisition selected");
+            return false;
+        }
+        
+        if (!Master.Filled.IsEmpty())
+        {
+            MessageWindow.ShowMessage("Cannot modify a filled requisition.", "Requisition already filled");
+            return false;
+        }
+        
+        return true;
+    }
+    
+    public override RequisitionItem CreateItem()
+    {
+        var result = base.CreateItem();
+        result.RequisitionLink.ID = Master?.ID ?? Guid.Empty;
+        result.RequisitionLink.Synchronise(Master ?? new Requisition());
+        result.JobLink.ID = Master?.JobLink.ID ?? Guid.Empty;
+        result.JobLink.Synchronise(Master?.JobLink ?? new JobLink());
+        result.Quantity = 1;
+        return result;
+    }
+    
+    protected override bool CanDeleteItems(params CoreRow[] rows)
+    {
+        if (!base.CanDeleteItems(rows))
+            return false;
+        
+        if(!Security.CanEdit<Requisition>() || !Security.CanEdit<RequisitionItem>())
+            return false;
+        
+        if(Master is null || Master.ID == Guid.Empty)
+        {
+            MessageWindow.ShowMessage("Please select a requisition.", "No requisition selected");
+            return false;
+        }
+        
+        if (!Master.Filled.IsEmpty())
+        {
+            MessageWindow.ShowMessage("Cannot modify a filled requisition.", "Requisition already filled");
+            return false;
+        }
+
+        return true;
+    }
+    
+}

+ 0 - 354
prs.desktop/Panels/Requisitions/RequisitionItemGrid.cs

@@ -1,354 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media.Imaging;
-using Comal.Classes;
-using InABox.Clients;
-using InABox.Core;
-using InABox.DynamicGrid;
-using InABox.Wpf;
-using InABox.WPF;
-using Microsoft.Office.Interop.Outlook;
-using PRSDesktop.Panels.Requisitions;
-using Syncfusion.Windows.Tools.Controls;
-using Columns = InABox.Core.Columns;
-using Exception = System.Exception;
-
-namespace PRSDesktop;
-
-public class RequisitionItemGrid : DynamicDataGrid<RequisitionItem>
-{
-    //public int Boxes { get; set; }
-
-    private static readonly BitmapImage tick = PRSDesktop.Resources.tick.AsBitmapImage();
-    private static readonly BitmapImage plus = PRSDesktop.Resources.plus.AsBitmapImage();
-    private static readonly BitmapImage minus = PRSDesktop.Resources.minus.AsBitmapImage();
-
-    private Task<List<Product>> _products;
-    
-    public Requisition? Requisition { get; set; }
-    
-    public RequisitionItemGrid()
-    {
-        HiddenColumns.Add(x => x.Code);
-        HiddenColumns.Add(x => x.BarCode);
-        HiddenColumns.Add(x => x.RequisitionLink.ID);
-        HiddenColumns.Add(x => x.RequisitionLink.JobLink.ID);
-        HiddenColumns.Add(x => x.RequisitionLink.JobScope.ID);
-        HiddenColumns.Add(x => x.RequisitionLink.Filled);
-        HiddenColumns.Add(x => x.RequisitionLink.Archived);
-        HiddenColumns.Add(x => x.Product.ID);
-        HiddenColumns.Add(x => x.Product.DefaultInstance.Style.ID);
-
-        HiddenColumns.Add(x => x.EditType);
-
-        foreach(var column in Columns.None<RequisitionItem>()
-            .AddDimensionsColumns(x => x.Product.DefaultInstance.Dimensions, Dimensions.ColumnsType.Data))
-        {
-            HiddenColumns.Add(column);
-        }
-
-        //HiddenColumns.Add(x => x.Product.Units.ID);
-        HiddenColumns.Add(x => x.Product.NonStock);
-        HiddenColumns.Add(x => x.Location.ID);
-        HiddenColumns.Add(x => x.Location.Code);
-        HiddenColumns.Add(x => x.Location.Description);
-        HiddenColumns.Add(x => x.Style.ID);
-        HiddenColumns.Add(x => x.Style.Code);
-        HiddenColumns.Add(x => x.Done);
-        
-        HiddenColumns.Add(x => x.Image.ID);
-        HiddenColumns.Add(x => x.Image.FileName);
-        HiddenColumns.Add(x => x.SourceJRI.ID);
-        HiddenColumns.Add(x => x.JobRequisitionItem.ID);
-        
-        ActionColumns.Add(new DynamicImageManagerColumn<RequisitionItem>(this, x => x.Image, true) { Position = DynamicActionColumnPosition.Start });
-        ActionColumns.Add(new DynamicImageColumn(Done_Image, Done_Click)
-        {
-            ToolTip = Done_Tooltip
-        });
-        
-        //ActionColumns.Add(new DynamicImageColumn(r => GetImage(r,minus),r => UpdatePick(r,-1.0)));
-        //ActionColumns.Add(new DynamicTextColumn(r => r.Get<RequisitionItem,double>(c=>c.ActualQuantity), UpdatePick) { Format = "F2", Width=50, HeaderText = "Pick"});
-        //ActionColumns.Add(new DynamicImageColumn(plus,r => UpdatePick(r,1.0)));
-
-        _products = Task.Run(() =>
-        {
-            return Client.Query(null, Columns.None<Product>().Add(x => x.Code).Add(x => x.Name).Add(x => x.ID)).ToList<Product>();
-        });
-    }
-
-    private FrameworkElement? Done_Tooltip(DynamicActionColumn column, CoreRow? row)
-    {
-        if(row is null)
-        {
-            return column.TextToolTip("Done?");
-        }
-        return null;
-    }
-
-    private bool Done_Click(CoreRow? row)
-    {
-        if (row is null) 
-            return false;
-
-        var item = LoadItem(row);
-        if (item.Done)
-        {
-            item.Done = false;
-            item.Location.CopyFrom(new StockLocationLink());
-            item.JobLink.CopyFrom(new JobLink());
-            item.SourceJRI.CopyFrom(new JobRequisitionItemLink());
-            item.ActualQuantity = 0.0;
-        }
-        SaveItem(item);
-        return true;
-    }
-
-    private BitmapImage? Done_Image(CoreRow? row)
-    {
-        if (row is null) return tick;
-
-        return row.Get<RequisitionItem, bool>(x => x.Done) == true ? tick : null;
-    }
-
-    private BitmapImage? GetImage(CoreRow? row, BitmapImage image)
-    {
-        return row == null || !row.Get<RequisitionItem, double>(c => c.ActualQuantity).IsEffectivelyEqual(0.0)
-            ? image
-            : null;
-    }
-    
-    
-    //private bool UpdatePick(CoreRow? row, double qty)
-    //{
-    //    if (row == null)
-    //        return false;
-    //    var item = row.ToObject<RequisitionItem>();
-    //    item.ActualQuantity = Math.Max(0.0, item.ActualQuantity + qty);
-    //    item.Picked = !item.ActualQuantity.IsEffectivelyEqual(0.0)
-    //        ? DateTime.Now
-    //        : DateTime.MinValue;
-    //    if (item.IsChanged())
-    //    {
-    //        Client.Save(item, item.Picked.IsEmpty() ? "Item Unpicked" : "Item Picked", (o,e) => { });
-    //        Data.LoadRow(row, item);
-    //        InvalidateRow(row);
-    //        return false;
-    //    }
-    //    return false;
-    //}
-    //
-    //private bool UpdatePick(CoreRow? row)
-    //{
-    //    if(row is null)
-    //        return false;
-    //    var item = row.ToObject<RequisitionItem>();
-
-    //    var quantity = item.ActualQuantity;
-    //    if (DoubleEdit.Execute("Enter actual quantity picked:", 0, double.MaxValue, ref quantity))
-    //    {
-    //        item.ActualQuantity = quantity;
-    //        item.Picked = !item.ActualQuantity.IsEffectivelyEqual(0.0)
-    //            ? DateTime.Now
-    //            : DateTime.MinValue;
-    //    }
-    //    else
-    //        return false;
-
-    //    if (item.IsChanged())
-    //    {
-    //        Client.Save(item, item.Picked.IsEmpty() ? "Item Unpicked" : "Item Picked");
-    //        return true;
-    //    }
-
-    //    return false;
-    //}
-
-    protected override void DoReconfigure(DynamicGridOptions options)
-    {
-        base.DoReconfigure(options);
-        options.RecordCount = true;
-        options.SelectColumns = true;
-        options.AddRows = true;
-        options.EditRows = true;
-        options.DeleteRows = true;
-        options.FilterRows = true;
-    }
-    
-    protected override void Reload(
-    	Filters<RequisitionItem> criteria, Columns<RequisitionItem> columns, ref SortOrder<RequisitionItem>? sort,
-    	CancellationToken token, Action<CoreTable?, Exception?> action)
-    {
-        criteria.Add(
-            new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(Requisition != null ? Requisition.ID : CoreUtils.FullGuid));
-
-        sort = new SortOrder<RequisitionItem>(x => x.Created);
-
-        base.Reload(criteria, columns, ref sort, token, action);
-    }
-
-    protected override bool CanCreateItems()
-    {
-        if(!Security.CanEdit<Requisition>() || !Security.CanEdit<RequisitionItem>())
-        {
-            return false;
-        }
-        else if(Requisition is null || Requisition.ID == Guid.Empty)
-        {
-            MessageWindow.ShowMessage("Please select a requisition.", "No requisition selected");
-            return false;
-        }
-        else if (!Requisition.Filled.IsEmpty())
-        {
-            MessageWindow.ShowMessage("Cannot modify a filled requisition.", "Requisition already filled");
-            return false;
-        }
-        return true;
-    }
-
-    public override RequisitionItem CreateItem()
-    {
-        var item = base.CreateItem();
-        item.RequisitionLink.ID = Requisition?.ID ?? Guid.Empty;
-        item.RequisitionLink.Synchronise(Requisition);
-        item.Quantity = 1;
-        return item;
-    }
-
-    private void DoEdit(CoreRow? row)
-    {
-        var item = row?.ToObject<RequisitionItem>();
-        if(item is null)
-        {
-            if (!CanCreateItems())
-                return;
-            item = CreateItem();
-        }
-
-        if (item.Done)
-        {
-            MessageWindow.ShowMessage("Cannot edit an item that is marked as done!","Error");
-            return;
-        }
-        
-        var editor = new RequisitionItemEditor(() => _products.Result, item, true);
-        if(editor.ShowDialog() == true && editor.Result is not null)
-        {
-            Refresh(false, true);
-            DoChanged();
-        }
-    }
-
-    protected override void DoEdit()
-    {
-        var rows = SelectedRows;
-        if (rows.Length != 1) return;
-
-        DoEdit(rows[0]);
-    }
-    protected override void DoAdd(bool openEditorOnDirectEdit = false)
-    {
-        DoEdit(null);
-    }
-
-    /*
-    public override bool AfterCreate(RequisitionItem item)
-    {
-        var selection = new MultiSelectDialog<StockHolding>
-        (
-            null,
-            new Columns<StockHolding>(
-                x => x.Location.ID,
-                x => x.Location.Code,
-                x => x.Location.Description,
-                x => x.Location.Area.Code,
-                x => x.Location.Area.Description,
-                x => x.Product.ID,
-                x => x.Product.Code,
-                x => x.Product.Name,
-                x => x.Dimensions.UnitSize,
-                x => x.Dimensions.Height,
-                x => x.Dimensions.Width,
-                x => x.Dimensions.Weight,
-                x => x.Dimensions.Quantity,
-                x => x.Dimensions.Length,
-                x => x.Dimensions.Unit.ID,
-                x => x.Dimensions.Unit.Format,
-                x => x.Dimensions.Unit.Formula,
-                x => x.Dimensions.Unit.HasHeight,
-                x => x.Dimensions.Unit.HasWeight,
-                x => x.Dimensions.Unit.HasWidth,
-                x => x.Dimensions.Unit.HasQuantity,
-                x => x.Dimensions.Unit.HasLength,
-                x => x.Style.ID,
-                x => x.Style.Code,
-                x => x.Style.Description,
-                x => x.Job.ID,
-                x => x.Job.Name,
-                x => x.Job.JobNumber,
-                x => x.Units
-            ), 
-            false
-        );
-
-        if (!selection.ShowDialog() || !selection.Data().Rows.Any()) 
-            return false;
-        var row = selection.Data().Rows.First();
-        var holding = row.ToObject<StockHolding>();
-        item.Location.ID = holding.Location.ID;
-        item.Location.Synchronise(holding.Location);
-        item.Product.ID = holding.Product.ID;
-        item.Product.Synchronise(holding.Product);
-        item.Style.ID = holding.Style.ID;
-        item.Style.Synchronise(holding.Style);
-        item.JobLink.ID = holding.Job.ID;
-        item.JobLink.Synchronise(holding.Job);
-        item.Dimensions.CopyFrom(holding.Dimensions, true);
-        return true;
-    }
-    */
-
-    //protected override void CustomiseEditor(RequisitionItem[] items, DynamicGridColumn column, BaseEditor editor)
-    //{
-    //    if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<RequisitionItem, String>(c => c.Description, ".")))
-    //        editor.Editable = Editable.Enabled;
-    //    else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<RequisitionItem, double>(c => c.Quantity, ".")))
-    //        editor.Editable = Editable.Enabled;
-    //    else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<RequisitionItem, Guid>(c => c.JobRequisitionItem.ID, ".")))
-    //        editor.Editable = Editable.Enabled;
-    //    else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<RequisitionItem, double>(c => c.ActualQuantity, ".")))
-    //        editor.Editable = Editable.Hidden;
-    //    else if (column.ColumnName.Equals(CoreUtils.GetFullPropertyName<RequisitionItem, DateTime>(c => c.Picked, ".")))
-    //        editor.Editable = Editable.Hidden;
-    //    else if (editor.Editable == Editable.Enabled)
-    //        editor.Editable = Editable.Disabled;
-    //    base.CustomiseEditor(items, column, editor);
-    //}
-
-    protected override bool CanDeleteItems(params CoreRow[] rows)
-    {
-        if(!Security.CanEdit<Requisition>() || !Security.CanEdit<RequisitionItem>())
-        {
-            return false;
-        }
-        else if(Requisition is null || Requisition.ID == Guid.Empty)
-        {
-            MessageWindow.ShowMessage("Please select a requisition.", "No requisition selected");
-            return false;
-        }
-        else if (!Requisition.Filled.IsEmpty())
-        {
-            MessageWindow.ShowMessage("Cannot modify a filled requisition.", "Requisition already filled");
-            return false;
-        }
-        return base.CanDeleteItems(rows);
-    }
-
-
-}

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

@@ -47,7 +47,7 @@
                     </Border>
                 </dg:DynamicSplitPanel.Header>
                 <dg:DynamicSplitPanel.Master>
-                    <local:RequisitionItemGrid x:Name="Items" Grid.Row="1" Grid.Column="2" />
+                    <local:RequisitionItemGrid x:Name="Items" Grid.Row="1" Grid.Column="2" StockButtonVisible="False" ColumnsTag="RequisitionItem_Logistics" />
                 </dg:DynamicSplitPanel.Master>
                 <dg:DynamicSplitPanel.DetailHeader>
                     <Border 

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

@@ -364,7 +364,7 @@ public partial class RequisitionPanel : UserControl, IPanel<Requisition>
     {
         _requisition = e.Rows?.FirstOrDefault()?.ToObject<Requisition>();
         LoadRequisition();
-        Items.Requisition = _requisition;
+        Items.Master = _requisition;
         Items.Refresh(false, true);
         //lastselection = DateTime.Now;
         //Dispatcher.Invoke(() => { LoadRequisition(); });

+ 12 - 3
prs.desktop/Panels/Reservation Management/ReservationManagementItemGrid.cs

@@ -467,6 +467,10 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
             MessageWindow.ShowMessage("All Items have been picked!", "Error", image: MessageWindow.WarningImage);
             return false;
         }
+
+        var duedate = DateTime.Today.AddDays(1);
+        if (!DateEdit.Execute("Select Due Date", ref duedate))
+            return false;
         
         var _jris = rows.ToObjects<JobRequisitionItem>()
             .GroupBy(x=>new Tuple<Guid,String,String>(x.Requisition.Job.ID, x.Requisition.Job.JobNumber, x.Requisition.Job.Name))
@@ -479,7 +483,11 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
             Task<StockMovement[]> _movementquery = Task.Run(
                 () => Client.Query(
                     new Filter<StockMovement>(x => x.JobRequisitionItem.ID)
-                        .InList(rows.Select(r => r.Get<JobRequisitionItem,Guid>(c=>c.ID)).ToArray())
+                        .InList(rows.Select(r => r.Get<JobRequisitionItem,Guid>(c=>c.ID)).ToArray()),
+                    Columns.None<StockMovement>()
+                        .Add(x=>x.JobRequisitionItem.ID)
+                        .Add(x=>x.Location.ID)
+                        .Add(x=>x.Units)
                     ).ToObjects<StockMovement>()
                     .ToArray()
                 );
@@ -491,7 +499,8 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
                 _pl.JobLink.JobNumber = _job.Key.Item2;
                 _pl.JobLink.Name = _job.Key.Item3;
                 _pl.RequestedBy.ID = App.EmployeeID;
-                _pl.Notes = new string[] { $"Items requested by {App.EmployeeName}" };
+                _pl.Title = $"Picking List Created by {App.EmployeeName}";
+                _pl.Due = duedate;
                 _pls.Add(_pl);
             }
             Client.Save(_pls, "Created from Reservation Management Screen");
@@ -527,7 +536,7 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
                             _plitem.Dimensions.CopyFrom(dimensions);
                             _plitem.Location.ID = _location.Key;
                             _plitem.Quantity = Math.Min(qtyrequired, _location.Sum(x => x.Units));
-                            _plitem.ActualQuantity = _plitem.Quantity;
+                            //_plitem.ActualQuantity = _plitem.Quantity;
                             _plitem.Cost = unitCost;
                             qtyrequired -= qtyrequired;
                             _plitems.Add(_plitem);

+ 1 - 1
prs.desktop/prsdesktop.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 #define MyAppName "PRS Desktop"
-#define MyAppVersion "8.47"
+#define MyAppVersion "8.47c"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSDesktop.exe"

+ 1 - 1
prs.licensing/PRSLicensing.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 #define MyAppName "PRS Licensing"
-#define MyAppVersion "8.47"
+#define MyAppVersion "8.47c"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSLicensing.exe"

+ 1 - 1
prs.server/PRSServer.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 #define MyAppName "PRS Server"
-#define MyAppVersion "8.47"
+#define MyAppVersion "8.47c"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSServer.exe"

+ 1 - 1
prs.stores/RequisitionStore.cs

@@ -280,7 +280,7 @@ namespace Comal.Stores
             batch.Requisition.ID = entity.ID;
             FindSubStore<StockMovementBatch>().Save(batch, "");
             
-            var timestamp = entity.Filled;
+            var timestamp = entity.Filled.IsEmpty() ? DateTime.Now : entity.Filled;
             var updates = new List<StockMovement>();
             foreach (var item in items)
             {