123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using System.Windows;
- using System.Windows.Controls;
- using com.sun.tools.@internal.ws.processor.util;
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Core;
- using InABox.DynamicGrid;
- using InABox.Wpf;
- using InABox.WPF;
- using PRSDesktop.Panels.Products.Locations;
- using Syncfusion.Windows.Controls.RichTextBoxAdv;
- using Exception = System.Exception;
- namespace PRSDesktop;
- public class StockHoldingGrid : DynamicDataGrid<StockHolding>
- {
- private enum MovementAction
- {
- Receive,
- Issue,
- Transfer
- }
- private MovementAction _action;
- private StockHolding? _holding;
-
- private Button IssueButton;
- private Button ReceiveButton;
- private DynamicDataGrid<StockMovement> smg;
- //Button ReserveButton = null;
- private Button TransferButton;
- private Button RecalculateButton;
- private Button AdjustValueButton;
- private Button RelocateButton;
- public StockHoldingGrid() : base()
- {
- ColumnsTag = "StockHolding";
-
- }
- protected override void Init()
- {
- base.Init();
- ReceiveButton = AddButton("Receive", PRSDesktop.Resources.add.AsBitmapImage(), ReceiveStock);
- ReceiveButton.IsEnabled = false;
- IssueButton = AddButton("Issue", PRSDesktop.Resources.delete.AsBitmapImage(), IssueStock);
- IssueButton.IsEnabled = false;
- //ReserveButton = AddButton("Reserve", PRSDesktop.Resources.project.AsBitmapImage(), ReserveStock);
- //ReserveButton.Margin = new Thickness(20, ReserveButton.Margin.Top, ReserveButton.Margin.Right, ReserveButton.Margin.Bottom);
- //ReserveButton.IsEnabled = false;
- TransferButton = AddButton("Transfer", PRSDesktop.Resources.split.AsBitmapImage(), TransferStock);
- 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);
-
- RecalculateButton = AddButton("Recalculate", PRSDesktop.Resources.service.AsBitmapImage(), RecalculateHoldings,
- DynamicGridButtonPosition.Right);
- HiddenColumns.Add(x => x.Product.ID);
- HiddenColumns.Add(x => x.Job.ID);
- HiddenColumns.Add(x => x.Job.JobNumber);
- HiddenColumns.Add(x => x.Job.Name);
- 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.Qty);
- HiddenColumns.Add(x => x.Units);
- HiddenColumns.Add(x => x.Available);
- HiddenColumns.Add(x => x.AverageValue);
- HiddenColumns.Add(x => x.Dimensions.Unit.ID);
- HiddenColumns.Add(x => x.Dimensions.Unit.Description);
- HiddenColumns.Add(x => x.Dimensions.Unit.HasHeight);
- HiddenColumns.Add(x => x.Dimensions.Unit.HasLength);
- HiddenColumns.Add(x => x.Dimensions.Unit.HasWidth);
- HiddenColumns.Add(x => x.Dimensions.Unit.HasHeight);
- HiddenColumns.Add(x => x.Dimensions.Unit.HasQuantity);
- HiddenColumns.Add(x => x.Dimensions.Unit.Format);
- HiddenColumns.Add(x => x.Dimensions.Unit.Formula);
- HiddenColumns.Add(x => x.Dimensions.Length);
- HiddenColumns.Add(x => x.Dimensions.Width);
- HiddenColumns.Add(x => x.Dimensions.Height);
- HiddenColumns.Add(x => x.Dimensions.Quantity);
- HiddenColumns.Add(x => x.Dimensions.Value);
- HiddenColumns.Add(x => x.Dimensions.UnitSize);
- ActionColumns.Add(new DynamicMenuColumn(BuildMenu) { Position = DynamicActionColumnPosition.End });
- }
- private bool AdjustValues(Button arg1, CoreRow[] rows)
- {
- if (rows?.Any() != true)
- return false;
-
- double _newvalue = 0.0;
- if (DoubleEdit.Execute("New Average Value", 0, double.MaxValue, ref _newvalue))
- {
- Progress.ShowModal("Creating Batch", progress =>
- {
- StockMovementBatch _batch = new StockMovementBatch()
- {
- Type = StockMovementBatchType.Transfer,
- Employee = new EmployeeLink() { ID = App.EmployeeID },
- Notes = "Stock Value Adjustment"
- };
- Client.Save(_batch,"Stock value adjusted from holding grid");
-
- progress.Report("Creating Movements");
- List<StockMovement> _updates = new List<StockMovement>();
- foreach (var _row in rows)
- {
- var _holding = _row.ToObject<StockHolding>();
- _holding.AverageValue = _newvalue;
- _holding.Value = _newvalue * _holding.Units;
- Client.Save(_holding,"Stock value adjusted from holding grid");
- _updates.AddRange(_holding.AdjustValue(_newvalue, _batch));
- }
-
- progress.Report("Saving Movements");
- Client.Save(_updates,"Stock value adjusted from holding grid");
- });
- MessageBox.Show("All Done");
- return true;
- }
- return false;
- }
- private bool RecalculateHoldings(Button arg1, CoreRow[] arg2)
- {
- Dictionary<String, int> messages = new();
- void AddMessage(String type)
- {
- messages.TryGetValue(type, out int count);
- messages[type] = ++count;
- }
-
- Progress.ShowModal("Recalculating", progress =>
- {
- progress.Report("Loading Data");
- MultiQuery query = new MultiQuery();
-
- query.Add(
- new Filter<StockHolding>(x => x.Location.ID).IsEqualTo(Location.ID),
- Columns.Required<StockHolding>().Add(x => x.ID)
- .Add(x => x.Product.ID)
- .Add(x => x.Job.ID)
- .Add(x => x.Style.ID)
- .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local)
- .Add(x => x.Units)
- .Add(x => x.AverageValue)
- .Add(x => x.Available)
- .Add(x => x.Qty)
- .Add(x => x.Weight)
- .Add(x => x.Value)
- );
-
- query.Add(
- new Filter<StockMovement>(x => x.Location.ID).IsEqualTo(Location.ID),
- Columns.None<StockMovement>().Add(x => x.ID)
- .Add(x => x.Product.ID)
- .Add(x => x.Job.ID)
- .Add(x => x.Style.ID)
- .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local)
- .Add(x => x.Units)
- .Add(x => x.Cost)
- .Add(x => x.JobRequisitionItem.ID)
- );
- query.Query();
- var holdings = query.Get<StockHolding>().ToObjects<StockHolding>().ToList();
- var toDelete = new List<StockHolding>();
- var movements = query.Get<StockMovement>().ToObjects<StockMovement>().ToList();
- progress.Report("Processing");
- var updates = new List<StockHolding>();
-
- while (movements.Any())
- {
- var first = movements.First();
- var selected = movements.Where(x => x.IsEqualTo(first)).ToList();
- var holding = holdings.FirstOrDefault(x => x.IsEqualTo(first));
- if (holding == null)
- {
- holding = new StockHolding();
- holding.Location.ID = Location.ID;
- holding.Product.ID = first.Product.ID;
- holding.Style.ID = first.Style.ID;
- holding.Job.ID = first.Job.ID;
- holding.Dimensions.CopyFrom(first.Dimensions);
- }
- holding.Recalculate(selected);
- // Removing from the list so that it is not deleted.
- if (holdings.Contains(holding))
- holdings.Remove(holding);
- if (holding.Units.IsEffectivelyEqual(0.0) && holding.Available.IsEffectivelyEqual(0.0))
- {
- if(holding.ID != Guid.Empty)
- {
- toDelete.Add(holding);
- }
- }
- else if (holding.IsChanged())
- {
- AddMessage(holding.ID != Guid.Empty ? "updated" : "added");
- updates.Add(holding);
- }
- movements.RemoveAll(x => selected.Any(s => s.ID == x.ID));
- }
- toDelete.AddRange(holdings);
- foreach (var holding in toDelete)
- AddMessage("deleted");
- if (updates.Any())
- {
- progress.Report($"Updating {updates.Count} Holdings");
- new Client<StockHolding>().Save(updates.Where(x => x.IsChanged()), "Updated by Recalculation");
- }
- if (toDelete.Any())
- {
- progress.Report($"Deleting {toDelete.Count} Holdings");
- new Client<StockHolding>().Delete(toDelete, "Removed by Recalculation");
- }
- });
- MessageWindow.ShowMessage(
- messages.Any()
- ? String.Join("\n", messages.Select(x => $"{x.Value} holdings {x.Key}"))
- : "Nothing to Update!"
- ,"Recalculate");
- return true;
- }
- public override DynamicGridColumns GenerateColumns()
- {
- var columns = new DynamicGridColumns<StockHolding>();
- columns.Add(x => x.Product.Code, 120, "Product Code", "", Alignment.MiddleCenter);
- columns.Add(x => x.Product.Name, 0, "Product Name", "", Alignment.MiddleLeft);
- columns.Add(x => x.Job.JobNumber, 50, "Job", "", Alignment.MiddleCenter);
- columns.Add(x => x.Style.Description, 0, "Style", "", Alignment.MiddleLeft);
- columns.Add(x => x.Dimensions.UnitSize, 100, "Size", "", Alignment.MiddleCenter);
- columns.Add(x => x.Units, 70, "Units", "", Alignment.MiddleCenter);
- columns.Add(x => x.Available, 70, "Available", "", Alignment.MiddleCenter);
- return columns;
- }
- protected override void DoReconfigure(DynamicGridOptions options)
- {
- base.DoReconfigure(options);
- options.AddRows = false;
- options.EditRows = Security.CanEdit<StockHolding>();
- options.DeleteRows = false;
- options.RecordCount = true;
- options.SelectColumns = true;
- options.FilterRows = true;
- }
- private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
- {
- if (row is null) return;
- var holding = row.ToObject<StockHolding>();
- if (holding.Available.IsEffectivelyEqual(holding.Units))
- column.AddItem("(No Requisitions in this Holding", null, null).IsEnabled = false;
- else
- {
- column.AddItem("View Requisition Items", null, ViewRequisitions_Click);
- if (Security.IsAllowed<CanEditAllocatedJobRequisitions>())
- {
- column.GetMenu().AddItem("Release allocated stock", null, holding, ReleaseAllocatedStock_Click);
- }
- }
-
- column.AddSeparator();
-
- column.AddItem("Relocate Items", null, r =>
- {
- var requiitems = holding.LoadRequisitionItems(true).ToArray();
- RelocateItems(holding, requiitems);
- });
- if (holding.Dimensions.Unit.HasDimensions() && holding.Available.IsEffectivelyGreaterThan(0.0))
- column.AddItem("Convert Dimensions", null, r =>
- {
- var calculator = new StockTransformWindow(holding);
- if (calculator.ShowDialog() == true)
- {
- var transferout = holding.CreateMovement();
- transferout.Date = DateTime.Now;
- transferout.Issued = calculator.OldAvailable;
- transferout.Transaction = Guid.NewGuid();
- transferout.Type = StockMovementType.TransferOut;
- var transferin = holding.CreateMovement();
- transferin.Date = transferout.Date.AddTicks(1);
- transferin.Dimensions.CopyFrom(calculator.Dimensions);
- transferin.Received = calculator.NewAvailable;
- transferin.Transaction = transferout.Transaction;
- transferin.Type = StockMovementType.TransferIn;
-
- Client.Save([transferout,transferin], "Converted Dimensions");
-
- Refresh(false,true);
- }
-
- });
- }
- 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.Cost = holding.AverageValue;
- mout.Date = DateTime.Now;
- mout.Employee.ID = App.EmployeeID;
- var min = mout.CreateMovement();
- min.Cost = holding.AverageValue;
- min.Employee.ID = App.EmployeeID;
- min.Date = mout.Date;
- min.Transaction = mout.Transaction;
- if(qty.Value > 0)
- {
- mout.Issued = qty.Value;
- mout.Type = StockMovementType.TransferOut;
- min.Received = qty.Value;
- min.Type = StockMovementType.TransferIn;
- }
- else
- {
- min.Issued = -qty.Value;
- min.Type = StockMovementType.TransferOut;
- mout.Received = -qty.Value;
- mout.Type = StockMovementType.TransferIn;
- }
- 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();
- var win = new StockHoldingRelocationWindow(holding, requiitems, StockHoldingRelocationWindow.RelocationMode.ReleaseAllocations);
- if (win.ShowDialog() == true)
- {
- var quantities = win.GetQuantities();
- DoTransfer(holding, requiitems, x => quantities.TryGetValue(x.ID, out var value) ? value : null, (requi, mout, min) =>
- {
- mout.JobRequisitionItem.ID = requi.ID;
- mout.Notes = $"Released from Job Requisition {requi.Requisition.Number}: {requi.Requisition.Description} for Job {requi.Job.JobNumber}";
- min.JobRequisitionItem.ID = Guid.Empty;
- min.Notes = $"Released from Job Requisition {requi.Requisition.Number}: {requi.Requisition.Description} for Job {requi.Job.JobNumber}";
- });
- }
- }
-
- private void RelocateItems(StockHolding holding, JobRequisitionItem[] requiitems)
- {
- var win = new StockHoldingRelocationWindow(holding, requiitems, StockHoldingRelocationWindow.RelocationMode.Transfer)
- {
- OriginalTarget = new StockLocation
- {
- ID = holding.Location.ID,
- Code = holding.Location.Code,
- Description = holding.Location.Description,
- },
- OriginalJob = new Job
- {
- ID = holding.Job.ID,
- JobNumber = holding.Job.JobNumber,
- Name = holding.Job.Name
- }
- };
- if (win.ShowDialog() == true)
- {
- var quantities = win.GetQuantities();
- var target = win.GetTargetLocation();
- DoTransfer(holding, requiitems, x => quantities.TryGetValue(x.ID, out var qty) ? qty : null, (requi, mout, min) =>
- {
- mout.JobRequisitionItem.ID = requi.ID;
- mout.Notes = $"Moved to {target.Code} by {App.EmployeeName}";
- min.Location.Clear();
- min.Location.ID = target.ID;
- min.Job.CopyFrom(win.Job ?? new());
- min.JobRequisitionItem.ID = requi.ID;
- min.Notes = $"Moved From {holding.Location.Code} by {App.EmployeeName}";
- });
- }
- }
- private void ViewRequisitions_Click(CoreRow? row)
- {
- if (row is null) return;
- var holding = row.ToObject<StockHolding>();
- var grid = (DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(JobRequisitionItem)) as DynamicDataGrid<JobRequisitionItem>)!;
- grid.OnDefineFilter += (type) =>
- {
- if(type == typeof(JobRequisitionItem))
- {
- return new Filter<JobRequisitionItem>(x => x.ID)
- .InQuery(
- StockHolding.GetFilter(holding),
- x => x.JobRequisitionItem.ID)
- // We don't care about stuff which has nothing in stock, which means it's been either issued or cancelled.
- .And(x => x.InStock).IsNotEqualTo(FilterConstant.Zero);
- }
- else
- {
- return null;
- }
- };
- DynamicGridUtils.CreateGridWindow("Job Requisition Items for stock holding", grid).ShowDialog();
- }
- private bool ReceiveStock(Button arg1, CoreRow[] rows)
- {
- var movement = new StockMovement();
- movement.Location.ID = Location.ID;
- movement.Location.Code = Location.Code;
- movement.Job.ID = Location.Job.ID;
- movement.Job.JobNumber = Location.Job.JobNumber;
- movement.Job.Name = Location.Job.Name;
- movement.Location.Description = Location.Description;
- movement.Date = DateTime.Now;
- movement.Employee.ID = App.EmployeeID;
- movement.Type = StockMovementType.Receive;
- movement.CommitChanges();
- var holding = rows.FirstOrDefault()?.ToObject<StockHolding>();
- var smg = CheckStockMovementGrid(MovementAction.Receive, holding);
- var result = smg.EditItems(new[] { movement });
- if (result)
- {
- DoChanged();
- SaveBatch(StockMovementBatchType.Receipt, new StockMovement[] { movement});
- }
-
- return result;
- }
- private bool IssueStock(Button arg1, CoreRow[] rows)
- {
- if (rows?.Length != 1)
- {
- MessageWindow.ShowMessage("Please select an item to issue", "No selected items");
- return false;
- }
-
- var holding = rows.First().ToObject<StockHolding>();
- var items = holding.LoadRequisitionItems(true).AsArray();
- DoIssue(holding, items);
- return false;
- }
- private IEnumerable<StockMovement> CreateIssue(StockHolding holding, IJob? job, double qty, IJobRequisitionItem requi)
- {
- var issue = CreateMovementFromHolding(holding);
- issue.Job.ID = job?.ID ?? Guid.Empty;
- issue.Type = StockMovementType.Issue;
- issue.JobRequisitionItem.ID = requi.ID;
- issue.Issued = qty;
- issue.Notes = $"Issued by {App.EmployeeName}";
- issue.Date = DateTime.Now;
- yield return issue;
- if (holding.Job.ID != issue.Job.ID)
- {
- var xferout = CreateMovementFromHolding(holding);
- xferout.Type = StockMovementType.TransferOut;
- xferout.JobRequisitionItem.ID = requi.ID;
- xferout.Issued = qty;
- xferout.Transaction = issue.Transaction;
- xferout.System = true;
- xferout.Notes = $"Issued by {App.EmployeeName}";
- xferout.Date = issue.Date;
- yield return xferout;
-
- var xferin = CreateMovementFromHolding(holding);
- xferin.Job.ID = issue.Job.ID;
- xferin.Type = StockMovementType.TransferIn;
- xferin.JobRequisitionItem.ID = requi.ID;
- xferin.Received = qty;
- xferin.Transaction = issue.Transaction;
- xferin.System = true;
- xferin.Notes = $"Issued by {App.EmployeeName}";
- xferin.Date = issue.Date;
- yield return xferin;
- }
- }
- private void DoIssue(StockHolding holding, JobRequisitionItem[] requiitems)
- {
- var updates = new List<StockMovement>();
- var win = new StockHoldingRelocationWindow(holding, requiitems, StockHoldingRelocationWindow.RelocationMode.Issue)
- {
- OriginalJob = new Job
- {
- ID = holding.Job.ID,
- JobNumber = holding.Job.JobNumber
- }
- };
- if (win.ShowDialog() == true)
- {
- var quantities = win.GetQuantities();
- foreach(var requi in requiitems)
- {
- if (!quantities.TryGetValue(requi.ID, out var qty) || qty <= 0) continue;
- updates.AddRange(CreateIssue(holding, win.Job, qty, requi));
- }
- SaveBatch(StockMovementBatchType.Issue, updates);
- DoChanged();
- Refresh(false,true);
- }
- }
-
- private bool TransferStock(Button arg1, CoreRow[] rows)
- {
- if (rows?.Length != 1)
- return false;
-
- var holding = rows.First().ToObject<StockHolding>();
- var items = holding.LoadRequisitionItems(true).AsArray();
- RelocateItems(holding, items);
- 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, mThis, mThat) =>
- {
- mThis.JobRequisitionItem.ID = requi.ID;
- mThis.Notes = $"Moved to {target.Code} by {App.EmployeeName}";
- mThat.JobRequisitionItem.ID = requi.ID;
- mThat.Notes = $"Moved to {target.Code} by {App.EmployeeName}";
- mThat.Location.Clear();
- mThat.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>();
- if (holding is null) return;
- var movement = CreateMovementFromHolding(holding);
- movement.Received = holding.Available;
- movement.Type = StockMovementType.TransferIn;
- var smg = CheckStockMovementGrid(MovementAction.Transfer, holding);
- var result = smg.EditItems(new[] { movement });
- var mvts = new List<StockMovement>
- {
- movement
- };
- if (result)
- {
- var other = CreateMovementFromHolding(holding);
- other.Issued = movement.Received;
- other.Transaction = movement.Transaction;
- other.Type = StockMovementType.TransferOut;
- var changes = new List<string>();
- if (movement.Location.ID != other.Location.ID)
- changes.Add(movement.Location.Code);
- if (movement.Job.ID != other.Job.ID)
- changes.Add(string.IsNullOrEmpty(movement.Job.JobNumber) ? "General Stock" : movement.Job.JobNumber);
- if (movement.Style.ID != other.Style.ID)
- changes.Add(movement.Style.Code);
- //other.Notes = "Transferred to "+String.Join(" / ",changes);
- other.Notes = string.Format("Transferred to {0}{1}{2}", string.Join(" / ",
- changes.Where(x => !string.IsNullOrWhiteSpace(x))),
- string.IsNullOrWhiteSpace(movement.Notes) ? "" : "\n",
- string.Join("\n", movement.Notes.Split('\n').Where(x => !x.StartsWith("Transferred from ")))
- );
- other.System = true;
- Client.Save(other, "");
- mvts.Add(other);
- }
- if (result)
- {
- DoChanged();
- SaveBatch(StockMovementBatchType.Transfer, mvts.ToArray());
- }
- 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();
- movement.Date = DateTime.Now;
- movement.Location.ID = Location.ID;
- movement.Location.Code = Location.Code;
- movement.Location.Description = Location.Description;
- movement.Product.ID = holding.Product.ID;
- movement.Job.ID = holding.Job.ID;
- movement.Job.JobNumber = holding.Job.JobNumber;
- movement.Style.ID = holding.Style.ID;
- movement.Style.Code = holding.Style.Code;
- movement.Employee.ID = App.EmployeeID;
- movement.Dimensions.CopyFrom(holding.Dimensions);
- movement.Cost = holding.AverageValue;
- movement.CommitChanges();
- return movement;
- }
- 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");
- }
- #endregion
- #region StockMovementGrid
- private DynamicDataGrid<StockMovement> CheckStockMovementGrid(MovementAction action, StockHolding holding)
- {
- _action = action;
- _holding = holding;
- if (smg == null)
- {
- smg = new DynamicDataGrid<StockMovement>();
- smg.OnCustomiseEditor += StockMovementCustomiseEditor;
- smg.OnValidate += StockMovementValidate;
- smg.OnEditorValueChanged += StockMovementValueChanged;
- }
- return smg;
- }
-
- private Dictionary<string, object?> StockMovementValueChanged(IDynamicEditorForm form, string name, object value)
- {
- var result = new Dictionary<string, object?>();
- if (name.Equals("Location.Job.ID"))
- {
- var editor = form.FindEditor("Job.ID");
- if (!value.Equals(Guid.Empty))
- result = DynamicGridUtils.UpdateEditorValue(form.Items, "Job.ID", value);
- else
- foreach (StockMovement item in form.Items)
- result = DynamicGridUtils.UpdateEditorValue(new[] { item }, "Job.ID",
- item.Job.HasOriginalValue("ID") ? item.Job.GetOriginalValue(x => x.ID) : item.Job.ID);
- editor.IsEnabled = value.Equals(Guid.Empty);
- }
- return result;
- }
-
- private void StockMovementValidate(object sender, StockMovement[] items, List<string> errors)
- {
- if (items.Any(x => x.Received == 0 && x.Issued == 0))
- {
- errors.Add("Quantity may not be zero");
- }
- else if(_action == MovementAction.Issue && _holding is not null && items.Any(x => x.Issued > _holding.Available))
- {
- errors.Add($"Quantity may not be greater than available stock ({_holding.Available})");
- }
- if (items.Any(x => x.Product.ID == Guid.Empty))
- errors.Add("Product may not be blank");
- if (items.Any(x => x.Location.ID == Guid.Empty))
- errors.Add("Location may not be blank");
- if (!errors.Any() && _action == MovementAction.Transfer)
- foreach (var item in items)
- {
- var changes = new List<string>();
- if (item.Location.HasOriginalValue(x => x.ID))
- changes.Add(item.Location.GetOriginalValue(x => x.Code));
- if (item.Job.HasOriginalValue(x => x.ID))
- {
- var job = item.Job.GetOriginalValue(x => x.JobNumber);
- if (string.IsNullOrEmpty(job))
- job = "General Stock";
- changes.Add(job);
- }
- if (item.Style.HasOriginalValue(x => x.ID))
- changes.Add(item.Style.GetOriginalValue(x => x.Code));
- if (changes.Any())
- item.Notes = string.Format("Transferred from {0}{1}{2}",
- string.Join(" / ", changes.Where(x => !string.IsNullOrWhiteSpace(x))),
- string.IsNullOrWhiteSpace(item.Notes) ? "" : "\n", item.Notes);
- else
- errors.Add("Transfers must change either Location, Style or Job");
- }
- }
- private void StockMovementCustomiseEditor(IDynamicEditorForm sender, StockMovement[]? items, DynamicGridColumn column, BaseEditor editor)
- {
- if (column.ColumnName.Equals("Location.ID"))
- editor.Editable = _action == MovementAction.Transfer ? Editable.Enabled : Editable.Hidden;
-
- if (column.ColumnName.Equals("Product.ID"))
- editor.Editable = _action == MovementAction.Receive ? Editable.Enabled : Editable.Disabled;
-
- if (column.ColumnName.Equals("Product.NettCost"))
- editor.Editable = Editable.Hidden;
-
- if (column.ColumnName.Equals("Style.ID"))
- editor.Editable = _action == MovementAction.Receive || _action == MovementAction.Transfer ? Editable.Enabled : Editable.Hidden;
- if (column.ColumnName.Equals("UnitSize"))
- editor.Editable = _action == MovementAction.Receive ? Editable.Enabled : Editable.Hidden;
-
- if (column.ColumnName.Equals("Job.ID"))
- editor.Editable = _action == MovementAction.Receive && items?.FirstOrDefault()?.Job.IsValid() == true ? Editable.Disabled : Editable.Enabled;
-
- if (column.ColumnName.Equals(nameof(StockMovement.Received)))
- {
- editor.Editable = _action == MovementAction.Receive || _action == MovementAction.Transfer ? Editable.Enabled : Editable.Hidden;
- editor.Caption = "Quantity";
- }
- if (column.ColumnName.Equals(nameof(StockMovement.Issued)))
- {
- editor.Editable = _action == MovementAction.Issue ? Editable.Enabled : Editable.Hidden;
- editor.Caption = "Quantity";
- }
-
- }
- #endregion
- }
|