|
@@ -37,10 +37,9 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
//Button ReserveButton = null;
|
|
|
|
|
|
private Button TransferButton;
|
|
|
-
|
|
|
private Button RecalculateButton;
|
|
|
-
|
|
|
private Button AdjustValueButton;
|
|
|
+ private Button RelocateButton;
|
|
|
|
|
|
public StockHoldingGrid() : base()
|
|
|
{
|
|
@@ -66,6 +65,9 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
TransferButton.Margin = new Thickness(20, TransferButton.Margin.Top, TransferButton.Margin.Right, TransferButton.Margin.Bottom);
|
|
|
TransferButton.IsEnabled = false;
|
|
|
|
|
|
+ RelocateButton = AddButton("Relocate", PRSDesktop.Resources.box.AsBitmapImage(), RelocateStock);
|
|
|
+ RelocateButton.IsEnabled = false;
|
|
|
+
|
|
|
AdjustValueButton = AddButton("Adjust Value", PRSDesktop.Resources.receipt.AsBitmapImage(), AdjustValues,
|
|
|
DynamicGridButtonPosition.Right);
|
|
|
AdjustValueButton.Margin = new Thickness(AdjustValueButton.Margin.Left, AdjustValueButton.Margin.Top, 10, AdjustValueButton.Margin.Bottom);
|
|
@@ -144,7 +146,6 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
private bool RecalculateHoldings(Button arg1, CoreRow[] arg2)
|
|
|
{
|
|
|
Dictionary<String, int> messages = new();
|
|
@@ -281,8 +282,6 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
options.FilterRows = true;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
|
|
|
{
|
|
|
if (row is null) return;
|
|
@@ -335,6 +334,45 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
|
|
|
}
|
|
|
|
|
|
+ private void DoTransfer(StockHolding holding, IList<JobRequisitionItem> requiitems, Func<JobRequisitionItem, double?> getQuantity, Action<JobRequisitionItem, StockMovement, StockMovement> modify)
|
|
|
+ {
|
|
|
+ var updates = new List<StockMovement>();
|
|
|
+ DoTransfer(holding, requiitems, getQuantity, modify, updates);
|
|
|
+
|
|
|
+ SaveBatch(StockMovementBatchType.Transfer, updates);
|
|
|
+ DoChanged();
|
|
|
+ Refresh(false, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void DoTransfer(StockHolding holding, IList<JobRequisitionItem> requiitems, Func<JobRequisitionItem, double?> getQuantity, Action<JobRequisitionItem, StockMovement, StockMovement> modify, List<StockMovement> updates)
|
|
|
+ {
|
|
|
+ foreach(var requi in requiitems)
|
|
|
+ {
|
|
|
+ var qty = getQuantity(requi);
|
|
|
+ if (!qty.HasValue || qty.Value <= 0) continue;
|
|
|
+
|
|
|
+ var mout = holding.CreateMovement();
|
|
|
+ mout.Issued = qty.Value;
|
|
|
+ mout.Cost = holding.AverageValue;
|
|
|
+ mout.Date = DateTime.Now;
|
|
|
+ mout.Employee.ID = App.EmployeeID;
|
|
|
+ mout.Type = StockMovementType.TransferOut;
|
|
|
+
|
|
|
+ var min = mout.CreateMovement();
|
|
|
+ min.Received = qty.Value;
|
|
|
+ min.Cost = holding.AverageValue;
|
|
|
+ min.Employee.ID = App.EmployeeID;
|
|
|
+ min.Type = StockMovementType.TransferIn;
|
|
|
+ min.Date = mout.Date;
|
|
|
+ min.Transaction = mout.Transaction;
|
|
|
+
|
|
|
+ modify(requi, mout, min);
|
|
|
+
|
|
|
+ updates.Add(mout);
|
|
|
+ updates.Add(min);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private void ReleaseAllocatedStock_Click(StockHolding holding)
|
|
|
{
|
|
|
var requiitems = holding.LoadRequisitionItems(true).Where(x => x.ID != Guid.Empty).ToList();
|
|
@@ -343,35 +381,14 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
{
|
|
|
var quantities = win.GetQuantities();
|
|
|
|
|
|
- var updates = new List<StockMovement>();
|
|
|
- foreach(var requi in requiitems)
|
|
|
+ DoTransfer(holding, requiitems, x => quantities.TryGetValue(x.ID, out var value) ? value : null, (requi, mout, min) =>
|
|
|
{
|
|
|
- if (!quantities.TryGetValue(requi.ID, out var qty) || qty <= 0) continue;
|
|
|
-
|
|
|
- var mout = holding.CreateMovement();
|
|
|
- mout.Issued = qty;
|
|
|
- mout.Cost = holding.AverageValue;
|
|
|
mout.JobRequisitionItem.ID = requi.ID;
|
|
|
- mout.Date = DateTime.Now;
|
|
|
- mout.Employee.ID = App.EmployeeID;
|
|
|
mout.Notes = $"Released from Job Requisition {requi.Requisition.Number}: {requi.Requisition.Description} for Job {requi.Job.JobNumber}";
|
|
|
- mout.Type = StockMovementType.TransferOut;
|
|
|
|
|
|
- var min = mout.CreateMovement();
|
|
|
- min.Received = qty;
|
|
|
- min.Cost = holding.AverageValue;
|
|
|
min.JobRequisitionItem.ID = Guid.Empty;
|
|
|
- min.Date = DateTime.Now;
|
|
|
- min.Employee.ID = App.EmployeeID;
|
|
|
min.Notes = $"Released from Job Requisition {requi.Requisition.Number}: {requi.Requisition.Description} for Job {requi.Job.JobNumber}";
|
|
|
- min.Type = StockMovementType.TransferIn;
|
|
|
-
|
|
|
- updates.Add(mout);
|
|
|
- updates.Add(min);
|
|
|
- }
|
|
|
- SaveBatch(StockMovementBatchType.Transfer, updates);
|
|
|
- DoChanged();
|
|
|
- Refresh(false, true);
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -397,39 +414,17 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
var quantities = win.GetQuantities();
|
|
|
var target = win.GetTargetLocation();
|
|
|
|
|
|
- var updates = new List<StockMovement>();
|
|
|
- foreach (var requiitem in requiitems)
|
|
|
+ DoTransfer(holding, requiitems, x => quantities.TryGetValue(x.ID, out var qty) ? qty : null, (requi, mout, min) =>
|
|
|
{
|
|
|
- if (!quantities.TryGetValue(requiitem.ID, out var qty)) continue;
|
|
|
-
|
|
|
- var mout = holding.CreateMovement();
|
|
|
- mout.Issued = qty;
|
|
|
- mout.Cost = holding.AverageValue;
|
|
|
- mout.JobRequisitionItem.ID = requiitem.ID;
|
|
|
- mout.Type = StockMovementType.TransferOut;
|
|
|
- mout.Date = DateTime.Now;
|
|
|
- mout.Employee.ID = App.EmployeeID;
|
|
|
+ mout.JobRequisitionItem.ID = requi.ID;
|
|
|
mout.Notes = $"Moved to {target.Code} by {App.EmployeeName}";
|
|
|
- updates.Add(mout);
|
|
|
|
|
|
- var min = holding.CreateMovement();
|
|
|
min.Location.Clear();
|
|
|
min.Location.ID = target.ID;
|
|
|
min.Job.CopyFrom(win.Job ?? new());
|
|
|
-
|
|
|
- min.Received = mout.Issued;
|
|
|
- min.Cost = holding.AverageValue;
|
|
|
- min.JobRequisitionItem.ID = requiitem.ID;
|
|
|
- min.Transaction = mout.Transaction;
|
|
|
- min.Type = StockMovementType.TransferIn;
|
|
|
- min.Date = mout.Date;
|
|
|
- min.Employee.ID = App.EmployeeID;
|
|
|
+ min.JobRequisitionItem.ID = requi.ID;
|
|
|
min.Notes = $"Moved From {holding.Location.Code} by {App.EmployeeName}";
|
|
|
- updates.Add(min);
|
|
|
- }
|
|
|
- SaveBatch(StockMovementBatchType.Transfer, updates);
|
|
|
- DoChanged();
|
|
|
- Refresh(false, true);
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -486,23 +481,6 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
-
|
|
|
- private static void SaveBatch(StockMovementBatchType type, IList<StockMovement> movements)
|
|
|
- {
|
|
|
- var batch = new StockMovementBatch();
|
|
|
- batch.Type = type;
|
|
|
- batch.Notes = batch.Type + " batch created from Desktop Stock Location Screen";
|
|
|
- batch.Employee.ID = App.EmployeeID;
|
|
|
- new Client<StockMovementBatch>().Save(batch, "created from Desktop Stock Location Screen");
|
|
|
-
|
|
|
- foreach (var mvt in movements)
|
|
|
- {
|
|
|
- mvt.Batch.ID = batch.ID;
|
|
|
- }
|
|
|
-
|
|
|
- new Client<StockMovement>().Save(movements, "Updating batch from Desktop Stock Location Screen");
|
|
|
- }
|
|
|
-
|
|
|
private bool IssueStock(Button arg1, CoreRow[] rows)
|
|
|
{
|
|
|
if (rows?.Length != 1)
|
|
@@ -594,6 +572,57 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ private bool RelocateStock(Button btn, CoreRow[] rows)
|
|
|
+ {
|
|
|
+ StockLocation? target = null;
|
|
|
+ while(true)
|
|
|
+ {
|
|
|
+ target = StockHoldingRelocationWindow.LookupLocation();
|
|
|
+ if(target is null)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else if(target.ID == Location.ID)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage($"These items are already in {target.Code}; please select a different location.", "Invalid transfer");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var holdings = rows.ToArray<StockHolding>();
|
|
|
+ var updates = new List<StockMovement>();
|
|
|
+ foreach(var holding in holdings)
|
|
|
+ {
|
|
|
+ var items = holding.LoadRequisitionItems(true).AsIList();
|
|
|
+
|
|
|
+ var rIDs = items.Select(x => x.ID).Where(x => x != Guid.Empty).ToArray();
|
|
|
+ var quantities = Client.Query(
|
|
|
+ StockHolding.GetFilter(holding)
|
|
|
+ .Combine(new Filter<StockMovement>(x => x.JobRequisitionItem.ID).InList(rIDs)),
|
|
|
+ Columns.None<StockMovement>().Add(x => x.Units).Add(x => x.JobRequisitionItem.ID))
|
|
|
+ .ToObjects<StockMovement>().GroupBy(x => x.JobRequisitionItem.ID).ToDictionary(x => x.Key, x => x.Sum(x => x.Units));
|
|
|
+
|
|
|
+ DoTransfer(holding, items, x => x.ID == Guid.Empty ? x.Qty : quantities.GetValueOrDefault(x.ID), (requi, mout, min) =>
|
|
|
+ {
|
|
|
+ mout.JobRequisitionItem.ID = requi.ID;
|
|
|
+ mout.Notes = $"Moved to {target.Code} by {App.EmployeeName}";
|
|
|
+
|
|
|
+ min.JobRequisitionItem.ID = requi.ID;
|
|
|
+ min.Notes = $"Moved to {target.Code} by {App.EmployeeName}";
|
|
|
+ min.Location.Clear();
|
|
|
+ min.Location.ID = target.ID;
|
|
|
+ }, updates);
|
|
|
+ }
|
|
|
+
|
|
|
+ SaveBatch(StockMovementBatchType.Transfer, updates);
|
|
|
+ DoChanged();
|
|
|
+ Refresh(false, true);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
protected override void DoEdit()
|
|
|
{
|
|
|
var holding = SelectedRows.FirstOrDefault()?.ToObject<StockHolding>();
|
|
@@ -647,6 +676,55 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
Refresh(false, true);
|
|
|
}
|
|
|
|
|
|
+ public IStockLocation Location { get; set; }
|
|
|
+
|
|
|
+ protected override void SelectItems(CoreRow[]? rows)
|
|
|
+ {
|
|
|
+ base.SelectItems(rows);
|
|
|
+
|
|
|
+ var nRows = rows?.Length ?? 0;
|
|
|
+
|
|
|
+ ReceiveButton.IsEnabled = Location != null && Location.ID != Guid.Empty;
|
|
|
+ IssueButton.IsEnabled = Location != null && Location.ID != Guid.Empty && nRows > 0;
|
|
|
+
|
|
|
+ if(Location is null || Location.ID == Guid.Empty || nRows == 0)
|
|
|
+ {
|
|
|
+ TransferButton.IsEnabled = false;
|
|
|
+ RelocateButton.IsEnabled = false;
|
|
|
+ }
|
|
|
+ else if(nRows == 1)
|
|
|
+ {
|
|
|
+ TransferButton.IsEnabled = true;
|
|
|
+ RelocateButton.IsEnabled = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TransferButton.IsEnabled = false;
|
|
|
+ RelocateButton.IsEnabled = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ var _groups = rows?.GroupBy(x => new Tuple<Guid, double>(
|
|
|
+ x.Get<StockHolding, Guid>(c => c.Product.ID),
|
|
|
+ x.Get<StockHolding, double>(c => c.Dimensions.Value))
|
|
|
+ );
|
|
|
+ AdjustValueButton.IsEnabled = Location != null && Location.ID != Guid.Empty && _groups?.Count() == 1;
|
|
|
+ RecalculateButton.IsEnabled = Location != null && Location.ID != Guid.Empty;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void Reload(
|
|
|
+ Filters<StockHolding> criteria, Columns<StockHolding> columns, ref SortOrder<StockHolding>? sort,
|
|
|
+ CancellationToken token, Action<CoreTable?, Exception?> action)
|
|
|
+ {
|
|
|
+ ReceiveButton.IsEnabled = Location != null && Location.ID != Guid.Empty;
|
|
|
+ if (Location == null)
|
|
|
+ criteria.Add(new Filter<StockHolding>().None());
|
|
|
+ else
|
|
|
+ criteria.Add(new Filter<StockHolding>(x => x.Location.ID).IsEqualTo(Location.ID));
|
|
|
+ base.Reload(criteria, columns, ref sort, token, action);
|
|
|
+ }
|
|
|
+
|
|
|
+ #region Internal Utilities
|
|
|
+
|
|
|
private StockMovement CreateMovementFromHolding(StockHolding holding)
|
|
|
{
|
|
|
var movement = new StockMovement();
|
|
@@ -665,23 +743,28 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
movement.CommitChanges();
|
|
|
return movement;
|
|
|
}
|
|
|
- public IStockLocation Location { get; set; }
|
|
|
|
|
|
- protected override void SelectItems(CoreRow[]? rows)
|
|
|
+ private static void SaveBatch(StockMovementBatchType type, IList<StockMovement> movements)
|
|
|
{
|
|
|
- base.SelectItems(rows);
|
|
|
+ var batch = new StockMovementBatch();
|
|
|
+ batch.Type = type;
|
|
|
+ batch.Notes = batch.Type + " batch created from Desktop Stock Location Screen";
|
|
|
+ batch.Employee.ID = App.EmployeeID;
|
|
|
+ new Client<StockMovementBatch>().Save(batch, "created from Desktop Stock Location Screen");
|
|
|
|
|
|
- ReceiveButton.IsEnabled = Location != null && Location.ID != Guid.Empty;
|
|
|
- IssueButton.IsEnabled = Location != null && Location.ID != Guid.Empty && rows?.Any() == true;
|
|
|
- TransferButton.IsEnabled = Location != null && Location.ID != Guid.Empty && rows?.Any() == true;
|
|
|
- var _groups = rows?.GroupBy(x => new Tuple<Guid, double>(
|
|
|
- x.Get<StockHolding, Guid>(c => c.Product.ID),
|
|
|
- x.Get<StockHolding, double>(c => c.Dimensions.Value))
|
|
|
- );
|
|
|
- AdjustValueButton.IsEnabled = Location != null && Location.ID != Guid.Empty && _groups?.Count() == 1;
|
|
|
- RecalculateButton.IsEnabled = Location != null && Location.ID != Guid.Empty;
|
|
|
+ foreach (var mvt in movements)
|
|
|
+ {
|
|
|
+ mvt.Batch.ID = batch.ID;
|
|
|
+ }
|
|
|
+
|
|
|
+ new Client<StockMovement>().Save(movements, "Updating batch from Desktop Stock Location Screen");
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region StockMovementGrid
|
|
|
+
|
|
|
private DynamicDataGrid<StockMovement> CheckStockMovementGrid(MovementAction action, StockHolding holding)
|
|
|
{
|
|
|
_action = action;
|
|
@@ -790,17 +873,5 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- protected override void Reload(
|
|
|
- Filters<StockHolding> criteria, Columns<StockHolding> columns, ref SortOrder<StockHolding>? sort,
|
|
|
- CancellationToken token, Action<CoreTable?, Exception?> action)
|
|
|
- {
|
|
|
- ReceiveButton.IsEnabled = Location != null && Location.ID != Guid.Empty;
|
|
|
- if (Location == null)
|
|
|
- criteria.Add(new Filter<StockHolding>().None());
|
|
|
- else
|
|
|
- criteria.Add(new Filter<StockHolding>(x => x.Location.ID).IsEqualTo(Location.ID));
|
|
|
- base.Reload(criteria, columns, ref sort, token, action);
|
|
|
- }
|
|
|
-
|
|
|
+ #endregion
|
|
|
}
|