Quellcode durchsuchen

Allowed stealing from other jobs on Reservation Management screen.
Removed CancelItems button from JRIGrid

Kenric Nugteren vor 11 Monaten
Ursprung
Commit
b2d753c18e

+ 5 - 0
prs.classes/SecurityDescriptors/Project_Descriptors.cs

@@ -71,4 +71,9 @@ namespace Comal.Classes
     public class CanReleaseJobReserves : DisabledSecurityDescriptor<ProjectManagementLicense, Job>
     {
     }
+
+    [Caption("Can edit allocated job requisitions")]
+    public class CanEditAllocatedJobRequisitions : DisabledSecurityDescriptor<ProjectManagementLicense, JobRequisitionItem>
+    {
+    }
 }

+ 102 - 102
prs.desktop/Panels/Jobs/Requisitions/JobRequisitionItemGrid.cs

@@ -24,7 +24,7 @@ internal class JobRequisitionItemGrid : DynamicDataGrid<JobRequisitionItem>, IMa
         set
         {
             _master = value;
-            CheckVisibility();
+            // CheckVisibility();
             Reconfigure();
         }
     }
@@ -37,112 +37,112 @@ internal class JobRequisitionItemGrid : DynamicDataGrid<JobRequisitionItem>, IMa
             ? new Filter<JobRequisitionItem>(x => x.Requisition.Job.ID).IsEqualTo(Job.ID)
             : new Filter<JobRequisitionItem>().None();
 
-    private Button CancelItemsButton;
+    // private Button CancelItemsButton;
 
     public JobRequisitionItemGrid()
     {
-        CancelItemsButton = AddButton("Cancel Items", PRSDesktop.Resources.disabled.AsBitmapImage(), CancelItems);
-        CheckVisibility();
+        //CancelItemsButton = AddButton("Cancel Items", PRSDesktop.Resources.disabled.AsBitmapImage(), CancelItems);
+        // CheckVisibility();
     }
 
-    private void CheckVisibility()
-    {
-        CancelItemsButton.Visibility = Master is not null && Security.CanEdit<JobRequisition>() && Security.CanEdit<JobRequisitionItem>()
-            ? System.Windows.Visibility.Visible
-            : System.Windows.Visibility.Hidden;
-    }
-
-    protected override void SelectItems(CoreRow[]? rows)
-    {
-        base.SelectItems(rows);
-
-        CancelItemsButton.IsEnabled = rows is not null && rows.Length > 0;
-    }
-
-    private bool CancelItems(Button button, CoreRow[] rows)
-    {
-        if (Master is null) return false;
-
-        if(rows.Length == 0)
-        {
-            MessageWindow.ShowMessage("Please select at least one item to cancel.", "Select items");
-            return false;
-        }
-
-        // Reloading so I can ensure the correct columns without having to add hidden columns to JobRequisitionGrid.
-        var oldRequi = Client.Query(
-            new Filter<JobRequisition>(x => x.ID).IsEqualTo(Master?.ID ?? Guid.Empty),
-            Columns.None<JobRequisition>().Add(x => x.Description)
-					.Add(x => x.Number)
-                .Add(x => x.DueDate))
-            .ToObjects<JobRequisition>()
-            .First();
-
-        var oldRequiItems = Client.Query(
-            new Filter<JobRequisitionItem>(x => x.ID).InList(rows.Select(x => x.Get<JobRequisitionItem, Guid>(x => x.ID)).ToArray()),
-            Columns.None<JobRequisitionItem>().Add(x => x.Qty)
-                .Add(x => x.Sequence)
-                .Add(x => x.Job.ID)
-                .Add(x => x.Product.ID)
-                .Add(x => x.Product.Code)
-                .Add(x => x.Style.ID)
-                .Add(x => x.Style.Code)
-                .Add(x => x.Style.Description)
-                .Add(x => x.Dimensions.Unit.ID)
-                .Add(x => x.Dimensions.Quantity)
-                .Add(x => x.Dimensions.Length)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.Dimensions.Height)
-                .Add(x => x.Dimensions.Weight)
-                .Add(x => x.Dimensions.UnitSize)
-                .Add(x => x.Supplier.ID));
-
-        var requisition = new JobRequisition
-        {
-            Description = $"Adjustment Requisition for Requisition {oldRequi.Number}",
-            DueDate = oldRequi.DueDate
-        };
-        requisition.Job.ID = Master.Job.ID;
-        requisition.Job.Synchronise(Master.Job);
-
-        var requiItems = new List<JobRequisitionItem>();
-        foreach(var oldItem in oldRequiItems.ToObjects<JobRequisitionItem>())
-        {
-            var newItem = new JobRequisitionItem
-            {
-                Notes = "Adjustment Requisition item",
-                Qty = -oldItem.Qty,
-                Sequence = oldItem.Sequence
-            };
-            newItem.Job.ID = requisition.Job.ID;
-            newItem.Product.ID = oldItem.Product.ID;
-            newItem.Style.ID = oldItem.Style.ID;
-            newItem.Supplier.ID = oldItem.Supplier.ID;
-            requiItems.Add(newItem);
-        }
-
-        var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicGrid<>), typeof(JobRequisition));
-        if (grid.EditItems(new JobRequisition[] { requisition }, t =>
-        {
-            if (t == typeof(JobRequisitionItem))
-            {
-                var table = new CoreTable();
-
-                table.LoadColumns(new Columns<JobRequisitionItem>(ColumnTypeFlags.Local | ColumnTypeFlags.IncludeAggregates | ColumnTypeFlags.IncludeFormulae | ColumnTypeFlags.Required));
-                table.LoadRows(requiItems);
-                return table;
-            }
-            return null;
-        }))
-        {
-            MessageWindow.ShowMessage($"Created requisition {requisition.Number}", "Created Requisition");
-            return true;
-        }
-        else
-        {
-            return false;
-        }
-    }
+    // private void CheckVisibility()
+    // {
+    //     CancelItemsButton.Visibility = Master is not null && Security.CanEdit<JobRequisition>() && Security.CanEdit<JobRequisitionItem>()
+    //         ? System.Windows.Visibility.Visible
+    //         : System.Windows.Visibility.Hidden;
+    // }
+
+    // protected override void SelectItems(CoreRow[]? rows)
+    // {
+    //     base.SelectItems(rows);
+
+    //     CancelItemsButton.IsEnabled = rows is not null && rows.Length > 0;
+    // }
+
+    //private bool CancelItems(Button button, CoreRow[] rows)
+    //{
+    //    if (Master is null) return false;
+
+    //    if(rows.Length == 0)
+    //    {
+    //        MessageWindow.ShowMessage("Please select at least one item to cancel.", "Select items");
+    //        return false;
+    //    }
+
+    //    // Reloading so I can ensure the correct columns without having to add hidden columns to JobRequisitionGrid.
+    //    var oldRequi = Client.Query(
+    //        new Filter<JobRequisition>(x => x.ID).IsEqualTo(Master?.ID ?? Guid.Empty),
+    //        Columns.None<JobRequisition>().Add(x => x.Description)
+	//				.Add(x => x.Number)
+    //            .Add(x => x.DueDate))
+    //        .ToObjects<JobRequisition>()
+    //        .First();
+
+    //    var oldRequiItems = Client.Query(
+    //        new Filter<JobRequisitionItem>(x => x.ID).InList(rows.Select(x => x.Get<JobRequisitionItem, Guid>(x => x.ID)).ToArray()),
+    //        Columns.None<JobRequisitionItem>().Add(x => x.Qty)
+    //            .Add(x => x.Sequence)
+    //            .Add(x => x.Job.ID)
+    //            .Add(x => x.Product.ID)
+    //            .Add(x => x.Product.Code)
+    //            .Add(x => x.Style.ID)
+    //            .Add(x => x.Style.Code)
+    //            .Add(x => x.Style.Description)
+    //            .Add(x => x.Dimensions.Unit.ID)
+    //            .Add(x => x.Dimensions.Quantity)
+    //            .Add(x => x.Dimensions.Length)
+    //            .Add(x => x.Dimensions.Width)
+    //            .Add(x => x.Dimensions.Height)
+    //            .Add(x => x.Dimensions.Weight)
+    //            .Add(x => x.Dimensions.UnitSize)
+    //            .Add(x => x.Supplier.ID));
+
+    //    var requisition = new JobRequisition
+    //    {
+    //        Description = $"Adjustment Requisition for Requisition {oldRequi.Number}",
+    //        DueDate = oldRequi.DueDate
+    //    };
+    //    requisition.Job.ID = Master.Job.ID;
+    //    requisition.Job.Synchronise(Master.Job);
+
+    //    var requiItems = new List<JobRequisitionItem>();
+    //    foreach(var oldItem in oldRequiItems.ToObjects<JobRequisitionItem>())
+    //    {
+    //        var newItem = new JobRequisitionItem
+    //        {
+    //            Notes = "Adjustment Requisition item",
+    //            Qty = -oldItem.Qty,
+    //            Sequence = oldItem.Sequence
+    //        };
+    //        newItem.Job.ID = requisition.Job.ID;
+    //        newItem.Product.ID = oldItem.Product.ID;
+    //        newItem.Style.ID = oldItem.Style.ID;
+    //        newItem.Supplier.ID = oldItem.Supplier.ID;
+    //        requiItems.Add(newItem);
+    //    }
+
+    //    var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicGrid<>), typeof(JobRequisition));
+    //    if (grid.EditItems(new JobRequisition[] { requisition }, t =>
+    //    {
+    //        if (t == typeof(JobRequisitionItem))
+    //        {
+    //            var table = new CoreTable();
+
+    //            table.LoadColumns(new Columns<JobRequisitionItem>(ColumnTypeFlags.Local | ColumnTypeFlags.IncludeAggregates | ColumnTypeFlags.IncludeFormulae | ColumnTypeFlags.Required));
+    //            table.LoadRows(requiItems);
+    //            return table;
+    //        }
+    //        return null;
+    //    }))
+    //    {
+    //        MessageWindow.ShowMessage($"Created requisition {requisition.Number}", "Created Requisition");
+    //        return true;
+    //    }
+    //    else
+    //    {
+    //        return false;
+    //    }
+    //}
 
     protected override void DoReconfigure(DynamicGridOptions options)
     {

+ 1 - 1
prs.desktop/Panels/Products/Locations/StockHoldingRelocationWindow.xaml.cs

@@ -225,7 +225,7 @@ public partial class StockHoldingRelocationWindow : Window, INotifyPropertyChang
                 MaxValue = item.ID == Guid.Empty ? double.MaxValue : qty,
                 Text = item.ID == Guid.Empty
                     ? "Unrequisitioned Items"
-                    : $"{item.Job.JobNumber}:{item.Requisition.Number} {item.Requisition.Description} ({qty})",
+                    : $"{item.Job.JobNumber}: {item.Requisition.Number} {item.Requisition.Description} ({qty})",
                 ID = item.ID,
                 JRI = item
             };

+ 21 - 32
prs.desktop/Panels/Reservation Management/ReservationManagementHoldingsGrid.xaml.cs

@@ -2,6 +2,7 @@
 using InABox.Clients;
 using InABox.Core;
 using InABox.Wpf;
+using java.sql;
 using org.omg.PortableInterceptor;
 using System;
 using System.Collections.Generic;
@@ -108,9 +109,9 @@ public partial class ReservationManagementHoldingsGrid
                 model.StockOfOtherStyles.AddRange(mvts);
             }
         }
-        model.UnitsOfCurrentStyle = Math.Max(model.StockOfCurrentStyle.Sum(x => x.Units), 0);
-        model.UnitsOfNoStyle = Math.Max(model.StockOfNoStyle.Sum(x => x.Units), 0);
-        model.UnitsOfOtherStyles = Math.Max(model.StockOfOtherStyles.Sum(x => x.Units), 0);
+        model.UnitsOfCurrentStyle = Math.Round(Math.Max(model.StockOfCurrentStyle.Sum(x => x.Units), 0));
+        model.UnitsOfNoStyle = Math.Round(Math.Max(model.StockOfNoStyle.Sum(x => x.Units), 0));
+        model.UnitsOfOtherStyles = Math.Round(Math.Max(model.StockOfOtherStyles.Sum(x => x.Units), 0));
     }
 
     private void CalculateHoldings()
@@ -119,7 +120,7 @@ public partial class ReservationManagementHoldingsGrid
         {
             var stockMovements = Client.Query(
                 new Filter<StockMovement>(x => x.Product.ID).IsEqualTo(item.Product.ID)
-                    .And(x => x.Dimensions.UnitSize).IsEqualTo(item.Dimensions.UnitSize)
+                    .And(x => x.Dimensions).DimensionEquals(item.Dimensions)
                     .And(x => x.Location.ID).IsNotEqualTo(Guid.Empty),
                 Columns.None<StockMovement>().Add(
                     x => x.ID,
@@ -243,14 +244,14 @@ public partial class ReservationManagementHoldingsGrid
     {
         if (Item is null) return;
 
-        var locationIDs = new List<Guid>();
-        var holdings = new List<StockHolding>();
+        var holdings = new Dictionary<(Guid locationID, Guid requiItemID), StockHolding>();
 
         foreach (var mvt in mvts)
         {
-            if (!locationIDs.Contains(mvt.Location.ID))
+            if(!holdings.TryGetValue(new(mvt.Location.ID, mvt.JobRequisitionItem.ID), out var holding))
             {
-                var holding = new StockHolding();
+                holding = new StockHolding();
+
                 holding.Location.ID = mvt.Location.ID;
                 holding.Location.Description = mvt.Location.Description;
                 holding.Location.Area.Description = mvt.Location.Area.Description;
@@ -258,35 +259,23 @@ public partial class ReservationManagementHoldingsGrid
                 holding.Style.Description = mvt.Style.Description;
                 holding.Style.Code = mvt.Style.Code;
                 holding.Dimensions.CopyFrom(mvt.Dimensions);
-                if (mvt.JobRequisitionItem.ID != Guid.Empty && model.AlreadyAllocated)
-                {
-                    holding.Units = mvt.Units;
-                    holdings.Add(holding);
-                    locationIDs.Add(mvt.Location.ID);
-                }
-                else if (mvt.JobRequisitionItem.ID == Guid.Empty && !model.AlreadyAllocated)
-                {
-                    holding.Units = mvt.Units;
-                    holdings.Add(holding);
-                    locationIDs.Add(mvt.Location.ID);
-                }
+
+                holdings.Add(new(mvt.Location.ID, mvt.JobRequisitionItem.ID), holding);
+            }
+            if (mvt.JobRequisitionItem.ID != Guid.Empty && model.AlreadyAllocated)
+            {
+                holding.Units += mvt.Units;
+            }
+            else if (mvt.JobRequisitionItem.ID == Guid.Empty && !model.AlreadyAllocated)
+            {
+                holding.Units += mvt.Units;
             }
             else
             {
-                if (mvt.JobRequisitionItem.ID != Guid.Empty && model.AlreadyAllocated)
-                {
-                    var holding = holdings.First(x => x.Location.ID == mvt.Location.ID);
-                    holding.Units += mvt.Units;
-                }
-                else if (mvt.JobRequisitionItem.ID == Guid.Empty && !model.AlreadyAllocated)
-                {
-                    var holding = holdings.First(x => x.Location.ID == mvt.Location.ID);
-                    holding.Units += mvt.Units;
-                }
-
+                // Shouldn't be possible.
             }
         }
-        var filteredHoldings = holdings.Where(x => x.Units > 0);
+        var filteredHoldings = holdings.Where(x => x.Value.Units.IsEffectivelyGreaterThan(0)).Select(x => new StockSelectionPage.Holding(x.Value, x.Key.requiItemID));
 
         var page = new StockSelectionPage(
             filteredHoldings,

+ 62 - 25
prs.desktop/Panels/Reservation Management/StockSelectionPage.xaml

@@ -5,9 +5,13 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:PRSDesktop"
         xmlns:wpf="clr-namespace:InABox.Wpf;assembly=InABox.Wpf"
+        xmlns:WPF="clr-namespace:InABox.WPF;assembly=InABox.Wpf"
         mc:Ignorable="d" Title="Requisition Stock for Line"
-        Height="500" Width="1400"
+        Height="500" Width="1000"
                     x:Name="Window">
+    <wpf:ThemableWindow.Resources>
+        <WPF:BooleanToVisibilityConverter x:Key="boolToVisibilityConverter" TrueValue="Visible" FalseValue="Collapsed"/>
+    </wpf:ThemableWindow.Resources>
 
     <Grid DataContext="{Binding ElementName=Window}">
         <Grid.RowDefinitions>
@@ -24,22 +28,38 @@
         <Grid Grid.Row="1">
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="0.4*"/>
+                <ColumnDefinition>
+                    <ColumnDefinition.Style>
+                        <Style TargetType="ColumnDefinition">
+                            <Setter Property="Width" Value="0"/>
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding ElementName=Window,Path=ShowRequisition}" Value="True">
+                                    <Setter Property="Width" Value="0.4*"/>
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </ColumnDefinition.Style>
+                </ColumnDefinition>
                 <ColumnDefinition Width="0.4*"/>
-                <ColumnDefinition Width="*"/>
-                <ColumnDefinition Width="0.1*"/>
-                <ColumnDefinition Width="60"/>
-                <ColumnDefinition Width="60"/>
-                <ColumnDefinition Width="60"/>
+                <ColumnDefinition Width="0.6*"/>
+                <ColumnDefinition Width="0.1*" MinWidth="100"/>
+                <ColumnDefinition Width="30"/>
                 <ColumnDefinition Width="60"/>
+                <ColumnDefinition Width="30"/>
+                <ColumnDefinition Width="40"/>
                 <ColumnDefinition Width="8"/>
             </Grid.ColumnDefinitions>
             <TextBlock Grid.Column="0" Text="Area" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="DemiBold" FontSize="14"/>
-            <TextBlock Grid.Column="1" Text="Location" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="DemiBold" FontSize="14"/>
-            <TextBlock Grid.Column="2" Text="Style" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="DemiBold" FontSize="14"/>
-            <TextBlock Grid.Column="3" x:Name="availableUnitsLbl" Text="Available Units" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center"
+            <TextBlock Grid.Column="1" Text="Requisition Item" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="DemiBold" FontSize="14"/>
+            <TextBlock Grid.Column="2" Text="Location" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="DemiBold" FontSize="14"/>
+            <TextBlock Grid.Column="3" Text="Style" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="DemiBold" FontSize="14"/>
+            <TextBlock Grid.Column="4" x:Name="availableUnitsLbl" Text="Available Units" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center"
                        FontWeight="DemiBold" FontSize="14" Margin="0,0,0,0"/>
-            <TextBlock Grid.Column="4" Grid.ColumnSpan="3" Text="Amount to Allocate" HorizontalAlignment="Center" TextAlignment="Center"
-                       VerticalAlignment="Center" FontWeight="DemiBold" FontSize="14" TextWrapping="Wrap"/>
+            <TextBlock x:Name="allocateLabel" Text="Allocate"
+                       Grid.Column="5" Grid.ColumnSpan="3"
+                       HorizontalAlignment="Center" TextAlignment="Center"
+                       VerticalAlignment="Center"
+                       FontWeight="DemiBold" FontSize="14" TextWrapping="Wrap"/>
         </Grid>
 
         <ListView x:Name="listView" ItemsSource="{Binding ViewModels}"
@@ -47,48 +67,65 @@
                   HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center">
             <ListView.ItemTemplate>
                 <DataTemplate DataType="local:StockSelectionViewModel">
-                    <Grid>
+                    <Grid IsEnabled="{Binding ElementName=Window,Path=CanEdit}">
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="0.4*"/>
+                            <ColumnDefinition>
+                                <ColumnDefinition.Style>
+                                    <Style TargetType="ColumnDefinition">
+                                        <Setter Property="Width" Value="0"/>
+                                        <Style.Triggers>
+                                            <DataTrigger Binding="{Binding ElementName=Window,Path=ShowRequisition}" Value="True">
+                                                <Setter Property="Width" Value="0.4*"/>
+                                            </DataTrigger>
+                                        </Style.Triggers>
+                                    </Style>
+                                </ColumnDefinition.Style>
+                            </ColumnDefinition>
                             <ColumnDefinition Width="0.4*"/>
-                            <ColumnDefinition Width="*"/>
-                            <ColumnDefinition Width="0.1*"/>
-                            <ColumnDefinition Width="60"/>
-                            <ColumnDefinition Width="60"/>
-                            <ColumnDefinition Width="60"/>
+                            <ColumnDefinition Width="0.6*"/>
+                            <ColumnDefinition Width="0.1*" MinWidth="100"/>
+                            <ColumnDefinition Width="30"/>
                             <ColumnDefinition Width="60"/>
+                            <ColumnDefinition Width="30"/>
+                            <ColumnDefinition Width="40"/>
                         </Grid.ColumnDefinitions>
                         <Border Grid.Column="0" BorderThickness="0.75" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
-                            <TextBlock Grid.Column="0" Text="{Binding Area}" HorizontalAlignment="Center" TextAlignment="Center"
+                            <TextBlock Text="{Binding Area}" HorizontalAlignment="Center" TextAlignment="Center"
                                            VerticalAlignment="Center" TextWrapping="Wrap"/>
                         </Border>
                         
                         <Border Grid.Column="1" BorderThickness="0.75" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
-                            <TextBlock Grid.Column="0" Text="{Binding Location}" HorizontalAlignment="Center" TextAlignment="Center"
+                            <TextBlock Text="{Binding Requisition}" HorizontalAlignment="Center" TextAlignment="Center"
+                                       Visibility="{Binding ElementName=Window,Path=ShowRequisition,Converter={StaticResource boolToVisibilityConverter}}"
                                            VerticalAlignment="Center" TextWrapping="Wrap"/>
                         </Border>
                         <Border Grid.Column="2" BorderThickness="0.75" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
-                            <TextBlock Grid.Column="1" Text="{Binding Style}" HorizontalAlignment="Center" TextAlignment="Center"
+                            <TextBlock Text="{Binding Location}" HorizontalAlignment="Center" TextAlignment="Center"
                                            VerticalAlignment="Center" TextWrapping="Wrap"/>
                         </Border>
                         <Border Grid.Column="3" BorderThickness="0.75" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
-                            <TextBlock  Text="{Binding Units}" HorizontalAlignment="Center" TextAlignment="Center"
+                            <TextBlock Text="{Binding Style}" HorizontalAlignment="Center" TextAlignment="Center"
+                                           VerticalAlignment="Center" TextWrapping="Wrap"/>
+                        </Border>
+                        <Border Grid.Column="4" BorderThickness="0.75" BorderBrush="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
+                            <TextBlock Text="{Binding Units}" HorizontalAlignment="Center" TextAlignment="Center"
                                            VerticalAlignment="Center" TextWrapping="Wrap"/>
                         </Border>
 
 
-                        <Button Grid.Column="4" Content="-" Width="60"  Height="25" Click="Minus_Click" FontWeight="Bold"
+                        <Button Grid.Column="5" Content="-" Width="25"  Height="25" Click="Minus_Click" FontWeight="Bold"
                                 Tag="{Binding}"/>
-                        <TextBox Grid.Column="5" Width="60" Height="25"
+                        <TextBox Grid.Column="6" Width="60" Height="25"
                                  TextChanged="TextBox_TextChanged"
                                  HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
                                  HorizontalAlignment="Center" VerticalAlignment="Center"
                                  Text="{Binding ChosenUnits}"
                                  Tag="{Binding}"/>
                         
-                        <Button Grid.Column="6" Content="+"  Width="60"  Height="25" Click="Plus_Click" FontWeight="Bold"
+                        <Button Grid.Column="7" Content="+"  Width="25"  Height="25" Click="Plus_Click" FontWeight="Bold"
                                 Tag="{Binding}"/>
-                        <Button Grid.Column="7" Content="All" Width="60"  Height="25" Click="All_Clicked"
+                        <Button Grid.Column="8" Content="All" Width="40"  Height="25" Click="All_Clicked"
                                 Tag="{Binding}"/>
 
                     </Grid>

+ 84 - 16
prs.desktop/Panels/Reservation Management/StockSelectionPage.xaml.cs

@@ -21,22 +21,61 @@ namespace PRSDesktop;
 /// </summary>
 public partial class StockSelectionPage : ThemableWindow, INotifyPropertyChanged
 {
+    public class Holding(StockHolding holding, Guid jobRequisitionItemID)
+    {
+        public StockHolding StockHolding { get; set; } = holding;
+
+        public Guid JobRequisitionItemID { get; set; } = jobRequisitionItemID;
+    }
+
     public ObservableCollection<StockSelectionViewModel> ViewModels { get; } = new ObservableCollection<StockSelectionViewModel>();
 
     private readonly JobRequisitionItem Item;
 
     public Guid IssuingJobID { get; set; }
 
-    public bool Allocated = false;
+    private bool Allocated = false;
 
     public double TotalChosen => ViewModels.Sum(x => x.ChosenUnits);
 
-    public StockSelectionPage(IEnumerable<StockHolding> holdings, JobRequisitionItem item, Job issuingJob, bool requisitioned = false)
+    private bool _canEdit = true;
+    public bool CanEdit
+    {
+        get => _canEdit;
+        private set
+        {
+            _canEdit = value;
+            OnPropertyChanged();
+        }
+    }
+
+    private bool _showRequisition = false;
+    public bool ShowRequisition
+    {
+        get => _showRequisition;
+        set
+        {
+            _showRequisition = value;
+            OnPropertyChanged();
+        }
+    }
+
+    public StockSelectionPage(IEnumerable<Holding> holdings, JobRequisitionItem item, Job issuingJob, bool allocated = false)
     {
         Item = item;
+
+        var jris = Client.Query(
+            new Filter<JobRequisitionItem>(x => x.ID).InList(holdings.Select(x => x.JobRequisitionItemID).ToArray()),
+            Columns.None<JobRequisitionItem>()
+                .Add(x => x.ID)
+                .Add(x => x.Job.JobNumber)
+                .Add(x => x.Requisition.Number)
+                .Add(x => x.Requisition.Description))
+            .ToObjects<JobRequisitionItem>().ToDictionary(x => x.ID);
+
         foreach (var holding in holdings)
         {
-            ViewModels.Add(new StockSelectionViewModel(holding));
+            ViewModels.Add(new StockSelectionViewModel(holding.StockHolding, jris.GetValueOrDefault(holding.JobRequisitionItemID)));
         }
 
         InitializeComponent();
@@ -44,11 +83,17 @@ public partial class StockSelectionPage : ThemableWindow, INotifyPropertyChanged
         IssuingJobID = issuingJob.ID;
         jobLbl.Text = $"Taking stock from Job: {issuingJob.Name} ({issuingJob.JobNumber})";
 
-        if (requisitioned)
+        Allocated = allocated;
+
+        if (allocated)
         {
+            CanEdit = Security.IsAllowed<CanEditAllocatedJobRequisitions>();
+            ShowRequisition = true;
             availableUnitsLbl.Text = "Allocated";
-            listView.IsEnabled = false;
-            okButton.IsEnabled = false;
+            if (CanEdit)
+            {
+                allocateLabel.Text = "Take";
+            }
         }
     }
 
@@ -56,9 +101,19 @@ public partial class StockSelectionPage : ThemableWindow, INotifyPropertyChanged
     {
         if(TotalChosen <= 0)
         {
-            MessageWindow.ShowMessage("Please select at least from at least one holding to reserve.", "Error", image: MessageWindow.WarningImage);
+            MessageWindow.ShowMessage("Please select from at least one holding to reserve.", "Error", image: MessageWindow.WarningImage);
             return;
         }
+        if (Allocated)
+        {
+            var result = MessageWindow.ShowYesNoCancel("You are attempting to take reserved stock that has already been allocated to job requisition items. " +
+                "Are you sure you wish to proceed? (This will decrease the allocation for the job requisition item being taken from.)",
+                "Confirm re-allocation");
+            if(result != MessageWindowResult.Yes)
+            {
+                return;
+            }
+        }
 
         var models = ViewModels.Where(x => x.ChosenUnits > 0);
 
@@ -80,12 +135,13 @@ public partial class StockSelectionPage : ThemableWindow, INotifyPropertyChanged
         };
         Client.Save(batch, "Created for requisitioning stock");
 
-        var issuing = CreateBaseMovement(model, batch.ID);
+        var issuing = CreateBaseMovement(model, batch.ID, model.JRI);
         issuing.Job.ID = IssuingJobID;
         issuing.Issued = model.ChosenUnits;
+        issuing.JobRequisitionItem.ID = model.JRI?.ID ?? Guid.Empty;
         issuing.Type = StockMovementType.TransferOut;
 
-        var receiving = CreateBaseMovement(model, batch.ID);
+        var receiving = CreateBaseMovement(model, batch.ID, model.JRI);
         receiving.Job.ID = Item.Job.ID;
         receiving.Received = model.ChosenUnits;
         receiving.JobRequisitionItem.ID = Item.ID;
@@ -95,18 +151,24 @@ public partial class StockSelectionPage : ThemableWindow, INotifyPropertyChanged
         Client.Save(new StockMovement[] { issuing, receiving }, "Created from Reservation Management Screen");
     }
 
-    private StockMovement CreateBaseMovement(StockSelectionViewModel model, Guid batchid)
+    private StockMovement CreateBaseMovement(StockSelectionViewModel model, Guid batchid, JobRequisitionItem? fromJRI)
     {
-        var mvt = new StockMovement();
+        var mvt = model.Holding.CreateMovement();
 
-        mvt.Style.ID = model.Holding.Style.ID;
-        mvt.Location.ID = model.Holding.Location.ID;
-        mvt.Dimensions.CopyFrom(model.Holding.Dimensions);
         mvt.Batch.ID = batchid;
         mvt.Employee.ID = App.EmployeeID;
         mvt.Date = DateTime.Now;
         mvt.Product.ID = Item.Product.ID;
-        mvt.Notes = $"Reservation Management Screen - allocating to Job {Item.Job.JobNumber} for Requisition Line";
+
+        if(fromJRI is null)
+        {
+            mvt.Notes = $"Reservation Management Screen - allocating to Job {Item.Job.JobNumber} for Requisition Line";
+        }
+        else
+        {
+            mvt.Notes = $"Reservation Management Screen - allocating to Job {Item.Job.JobNumber} for Requisition Line from " +
+                $"requisition '{fromJRI.Requisition.Number} - {fromJRI.Requisition.Description}' for Job {fromJRI.Job.JobNumber}";
+        }
 
         return mvt;
     }
@@ -174,6 +236,9 @@ public partial class StockSelectionPage : ThemableWindow, INotifyPropertyChanged
 public class StockSelectionViewModel : INotifyPropertyChanged
 {
     public event PropertyChangedEventHandler? PropertyChanged;
+    public string Requisition => JRI is null
+        ? "Unrequisitioned Items"
+        : $"{JRI.Job.JobNumber}: {JRI.Requisition.Number} {JRI.Requisition.Description}";
     public string Location => Holding.Location.Description;
     public string Area => Holding.Location.Area.Description;
     public string Style => Holding.Style.Description;
@@ -192,9 +257,12 @@ public class StockSelectionViewModel : INotifyPropertyChanged
 
     public StockHolding Holding { get; set; }
 
-    public StockSelectionViewModel(StockHolding holding)
+    public JobRequisitionItem? JRI { get; set; }
+
+    public StockSelectionViewModel(StockHolding holding, JobRequisitionItem? jri)
     {
         Holding = holding;
+        JRI = jri;
         ChosenUnits = 0;
     }