using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.Wpf; using InABox.WPF; using java.sql; using org.omg.PortableInterceptor; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Windows; using System.Windows.Controls; namespace PRSDesktop; public delegate void HoldingsReviewRefresh(); /// /// Interaction logic for JobRequisitionHoldingsReview.xaml /// public partial class ReservationManagementHoldingsGrid { private ProductStyleLink companyDefaultStyle = new ProductStyleLink(); public ProductStyleLink CompanyDefaultStyle { get => companyDefaultStyle; set { companyDefaultStyle = value; DefaultOrNoStyleText.Text = String.IsNullOrWhiteSpace(companyDefaultStyle?.Code) ? "No Style" : $"{companyDefaultStyle.Code} / None"; } } public event HoldingsReviewRefresh? OnHoldingsReviewRefresh; private JobRequisitionItem? item; public JobRequisitionItem? Item { get { return item; } set { if(item?.ID != value?.ID) { item = value; CalculateHoldings(); SetStyle(); SetProductName(); } } } private void SetProductName() { productLbl.Text = Item != null ? Item.Product.Name + " (" + Item.Product.Code + ")" : "No Product Selected"; } private void SetStyle() { if ((Item != null) && (Item.Style.ID != Guid.Empty)) styleLbl.Text = Item.Style.Description + " (" + Item.Style.Code + ")"; else styleLbl.Text = "No Style Selected"; } public ReservationManagementHoldingsGrid() { InitializeComponent(); greenList.CollectionChanged += (s, e) => { availableTab.Visibility = greenList.Count > 0 ? Visibility.Visible : Visibility.Collapsed; }; yellowList.CollectionChanged += (s, e) => { reservedTab.Visibility = yellowList.Count > 0 ? Visibility.Visible : Visibility.Collapsed; }; redList.CollectionChanged += (s, e) => { requisitionedTab.Visibility = redList.Count > 0 ? Visibility.Visible : Visibility.Collapsed; }; } private readonly ObservableCollection greenList = new(); private readonly ObservableCollection yellowList = new(); private readonly ObservableCollection redList = new(); private void DistributeMovements(Dictionary>? movements, Guid selectedStyleID, ReservationManagementHoldingsModel model) { if (movements is null) return; foreach(var (id, mvts) in movements) { if(id == Guid.Empty || id == CompanyDefaultStyle.ID) { model.StockOfNoStyle.AddRange(mvts); } else if (id == selectedStyleID) { model.StockOfCurrentStyle.AddRange(mvts); } else { model.StockOfOtherStyles.AddRange(mvts); } } model.UnitsOfCurrentStyle = Math.Round(model.StockOfCurrentStyle.Sum(x => x.Units)); model.UnitsOfNoStyle = Math.Round(model.StockOfNoStyle.Sum(x => x.Units)); model.UnitsOfOtherStyles = Math.Round(model.StockOfOtherStyles.Sum(x => x.Units)); } private void CalculateHoldings() { if(item is not null) { var stockMovements = Client.Query( new Filter(x => x.Product.ID).IsEqualTo(item.Product.ID) .And(x => x.Dimensions).DimensionEquals(item.Dimensions) .And(x => x.Location.ID).IsNotEqualTo(Guid.Empty), Columns.None().Add( x => x.ID, x => x.Style.ID, x => x.Style.Description, x => x.Style.Code, x => x.Units, x => x.Location.ID, x => x.Location.Code, x => x.Location.Description, x => x.Location.Area.Code, x => x.Job.ID, x => x.JobRequisitionItem.ID) .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Data)) .ToObjects() .GroupBy(x => new { JobID = x.Job.ID, Allocated = x.JobRequisitionItem.ID != Guid.Empty }) .ToDictionary( x => x.Key, x => x.GroupBy(x => x.Style.ID) .Select(x => { var mvts = x.ToList(); return new { Style = x.Key, Movements = mvts }; }) .ToDictionary( x => x.Style, x => x.Movements)); var jobs = Client.Query( new Filter(x => x.ID).InList(stockMovements.Keys.Select(x => x.JobID).ToArray()), Columns.None().Add(x => x.ID).Add(x => x.JobNumber).Add(x => x.Name)) .ToObjects() .ToDictionary(x => x.ID, x => x); if(!stockMovements.ContainsKey(new { JobID = item.Job.ID, Allocated = false })) { stockMovements.Add(new { JobID = item.Job.ID, Allocated = false }, new Dictionary>()); } if (!stockMovements.ContainsKey(new { JobID = Guid.Empty, Allocated = false })) { stockMovements.Add(new { JobID = Guid.Empty, Allocated = false }, new Dictionary>()); } greenList.Clear(); yellowList.Clear(); redList.Clear(); foreach (var (key, movements) in stockMovements) { var job = jobs.GetValueOrDefault(key.JobID); ReservationManagementHoldingsModel holding; if (key.Allocated) { holding = new ReservationManagementHoldingsModel(key.JobID, job?.JobNumber ?? "", job?.Name ?? "") { AlreadyAllocated = true }; DistributeMovements(movements, item.Style.ID, holding); if (!holding.Empty) { redList.Add(holding); } } else if (key.JobID == Guid.Empty) { holding = new ReservationManagementHoldingsModel(Guid.Empty, "Free Stock", "Free Stock"); DistributeMovements(movements, item.Style.ID, holding); greenList.Add(holding); } else if(key.JobID == item.Job.ID) { holding = new ReservationManagementHoldingsModel(item.Job.ID, item.Job.JobNumber, item.Job.Name); DistributeMovements(movements, item.Style.ID, holding); greenList.Add(holding); } else { holding = new ReservationManagementHoldingsModel(key.JobID, job?.JobNumber ?? "", job?.Name ?? ""); DistributeMovements(movements, item.Style.ID, holding); if (!holding.Empty) { yellowList.Add(holding); } } } if (greenList.Count == 1) greenList.Add(new ReservationManagementHoldingsModel()); if (redList.Count == 1) redList.Add(new ReservationManagementHoldingsModel()); if (yellowList.Count == 1) yellowList.Add(new ReservationManagementHoldingsModel()); } else { greenList.Clear(); yellowList.Clear(); redList.Clear(); } listViewGreen.ItemsSource = greenList; listViewYellow.ItemsSource = yellowList; listViewRed.ItemsSource = redList; } private void Take_RightClick(object sender, System.Windows.Input.MouseButtonEventArgs e) { if (sender is not FrameworkElement element || element.DataContext is not ReservationManagementHoldingsModel model || element.Tag is not List mvts) return; if (model.AlreadyAllocated) return; if (mvts == model.StockOfCurrentStyle && model.UnitsOfCurrentStyle > 0 || mvts == model.StockOfNoStyle && model.UnitsOfNoStyle > 0 || mvts == model.StockOfOtherStyles && model.UnitsOfOtherStyles > 0) { return; } var menu = new ContextMenu(); menu.AddItem("Take Anyway", null, () => LaunchStockSelectionPage(model, mvts)); menu.IsOpen = true; } private void Take_Click(object sender, RoutedEventArgs e) { if (sender is not FrameworkElement element || element.DataContext is not ReservationManagementHoldingsModel model || element.Tag is not List mvts) return; if (mvts == model.StockOfCurrentStyle && model.UnitsOfCurrentStyle <= 0 || mvts == model.StockOfNoStyle && model.UnitsOfNoStyle <= 0 || mvts == model.StockOfOtherStyles && model.UnitsOfOtherStyles <= 0) { return; } LaunchStockSelectionPage(model, mvts); } private void LaunchStockSelectionPage(ReservationManagementHoldingsModel model, List mvts) { if (Item is null) return; var holdings = new Dictionary<(Guid locationID, Guid requiItemID), StockHolding>(); foreach (var mvt in mvts) { if(!holdings.TryGetValue(new(mvt.Location.ID, mvt.JobRequisitionItem.ID), out var holding)) { holding = new StockHolding(); holding.Location.CopyFrom(mvt.Location); holding.Style.CopyFrom(mvt.Style); holding.Dimensions.CopyFrom(mvt.Dimensions); 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 { // Shouldn't be possible. } } var filteredHoldings = holdings.Where(x => !model.AlreadyAllocated || x.Value.Units.IsEffectivelyGreaterThan(0)) .Select(x => new StockSelectionPage.Holding(x.Value, x.Key.requiItemID)); var page = new StockSelectionPage( filteredHoldings, Item, new Job { ID = model.JobID, Name = model.JobName, JobNumber = model.JobNumber }, model.AlreadyAllocated); if (page.ShowDialog() == true) { //MessageWindow.ShowMessage("Success - stock allocated to requisition line", "Success"); CalculateHoldings(); OnHoldingsReviewRefresh?.Invoke(); } } }