using Comal.Classes; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.DynamicGrid; using InABox.Wpf; using InABox.WPF; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Linq.Expressions; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using Brush = System.Windows.Media.Brush; namespace PRSDesktop; public delegate void JobRequiItemSelect(CoreRow[] rows); public delegate void GridRefresh(); public class ReservationManagementItemGrid : DynamicDataGrid { private readonly ReservationManagementUserSettings _userSettings = new ReservationManagementUserSettings(); private Button ArchiveButton; public bool ShowColors { get; set; } public int DueDateAlert { get; set; } public int DueDateWarning { get; set; } protected override bool ShowSequenceButtons => false; private class UIComponent : DynamicGridGridUIComponent { private ReservationManagementItemGrid Grid; public UIComponent(ReservationManagementItemGrid grid) { Grid = grid; Parent = grid; } protected override Brush? GetCellBackground(CoreRow row, DynamicColumnBase column) { if (!Grid.ShowColors) return null; if (column is DynamicGridColumn col) { if (String.Equals(col.ColumnName, CoreUtils.GetFullPropertyName(x => x.Requisition.DueDate, "."))) { var due = row.Get(x => x.Requisition.DueDate); if (!due.IsEmpty()) { var background = DateTime.Today > due.Date ? Colors.LightSalmon : DateTime.Today.AddDays(Grid.DueDateWarning) >= due.Date ? Colors.Orange : DateTime.Today.AddDays(Grid.DueDateAlert) >= due.Date ? Colors.LightYellow : Colors.LightGreen; return new SolidColorBrush(background) { Opacity = 0.5 }; } } } else if(column is DynamicActionColumn dac) { if (dac == Grid.InStockColumn || dac == Grid.OnOrderColumn) { return Colors.LightBlue.ToBrush(0.5); } else if (dac == Grid.TreatmentRequiredColumn || dac == Grid.TreatmentOnOrderColumn) { return Colors.Plum.ToBrush(0.5); } } var qty = row.Get(x => x.Qty); if(row.Get(x => x.Issued) >= qty) { return Colors.Silver.ToBrush(0.5); } else if(row.Get(x => x.Allocated) + row.Get(x => x.Issued) >= qty) { return Colors.LightGreen.ToBrush(0.5); } else if(row.Get(x => x.InStock) + row.Get(x => x.Issued) >= qty) { return Colors.Orange.ToBrush(0.5); } else { return Colors.LightSalmon.ToBrush(0.5); } } } private DynamicActionColumn InStockColumn; private DynamicActionColumn OnOrderColumn; private DynamicActionColumn TreatmentRequiredColumn; private DynamicActionColumn TreatmentOnOrderColumn; private DynamicActionColumn AllocatedColumn; private DynamicActionColumn IssuedColumn; public ReservationManagementItemGrid() { _userSettings = new UserConfiguration().Load(); FilterComponent.SetSettings(_userSettings.Filters, false); HiddenColumns.Add(x => x.ID); HiddenColumns.Add(x => x.Qty); HiddenColumns.Add(x => x.InStock); HiddenColumns.Add(x => x.OnOrder); HiddenColumns.Add(x => x.TreatmentOnOrder); HiddenColumns.Add(x => x.TreatmentRequired); HiddenColumns.Add(x => x.Allocated); HiddenColumns.Add(x => x.Issued); HiddenColumns.Add(x => x.Product.ID); HiddenColumns.Add(x => x.Product.Code); HiddenColumns.Add(x => x.Product.Group.ID); HiddenColumns.Add(x => x.Product.Group.Code); HiddenColumns.Add(x => x.Product.Group.Description); HiddenColumns.Add(x => x.Style.ID); HiddenColumns.Add(x => x.Style.Code); HiddenColumns.Add(x => x.Style.Description); HiddenColumns.Add(x => x.Status); HiddenColumns.Add(x => x.Requisition.ID); HiddenColumns.Add(x => x.Requisition.Job.ID); HiddenColumns.Add(x => x.Requisition.Job.JobNumber); HiddenColumns.Add(x => x.Requisition.Job.Name); HiddenColumns.Add(x => x.Requisition.Number); HiddenColumns.Add(x => x.Requisition.DueDate); HiddenColumns.Add(x => x.Job.ID); HiddenColumns.Add(x => x.Job.Name); HiddenColumns.Add(x => x.Job.JobNumber); HiddenColumns.Add(x => x.Dimensions.UnitSize); HiddenColumns.Add(x => x.Dimensions.Length); HiddenColumns.Add(x => x.Dimensions.Width); HiddenColumns.Add(x => x.Dimensions.Height); HiddenColumns.Add(x => x.Dimensions.Weight); HiddenColumns.Add(x => x.Dimensions.Quantity); HiddenColumns.Add(x => x.Dimensions.Value); HiddenColumns.Add(x => x.Dimensions.Unit.ID); HiddenColumns.Add(x => x.Dimensions.Unit.HasLength); HiddenColumns.Add(x => x.Dimensions.Unit.HasHeight); HiddenColumns.Add(x => x.Dimensions.Unit.HasWidth); HiddenColumns.Add(x => x.Dimensions.Unit.HasWeight); HiddenColumns.Add(x => x.Dimensions.Unit.HasQuantity); HiddenColumns.Add(x => x.Dimensions.Unit.Formula); HiddenColumns.Add(x => x.Dimensions.Unit.Format); HiddenColumns.Add(x => x.Dimensions.Unit.Code); HiddenColumns.Add(x => x.Dimensions.Unit.Description); AddDoubleColumn(x => x.Qty, "Qty."); InStockColumn = AddDoubleColumn(x => x.InStock, "Stk."); OnOrderColumn = AddDoubleColumn(x => x.OnOrder, "Ord."); TreatmentRequiredColumn = AddDoubleColumn(x => x.TreatmentRequired, "Req."); TreatmentOnOrderColumn = AddDoubleColumn(x => x.TreatmentOnOrder, "Ord."); AllocatedColumn = AddDoubleColumn(x => x.Allocated, "Stk."); IssuedColumn = AddDoubleColumn(x => x.Issued, "Iss."); if (Security.CanEdit()) ActionColumns.Add(new DynamicMenuColumn(BuildMenu)); ColumnsTag = "JobRequisitionReview"; FilterComponent.OnFiltersSelected += GridOnFilterSelected; ArchiveButton = AddButton("Archive", PRSDesktop.Resources.archive.AsBitmapImage(), ArchiveButton_Clicked); ArchiveButton.IsEnabled = false; } private DynamicActionColumn AddDoubleColumn(Expression> property, string header) { var col = new DynamicTextColumn(property) { Format = "F2", HeaderText = header, Width = 50 }; ActionColumns.Add(col); return col; } protected override IDynamicGridUIComponent CreateUIComponent() { return new UIComponent(this); } protected override void DoReconfigure(DynamicGridOptions options) { base.DoReconfigure(options); options.FilterRows = true; options.SelectColumns = true; options.RecordCount = true; options.DragSource = true; options.AddRows = false; options.ImportData = false; options.ExportData = false; options.Print = false; options.ShowHelp = false; } private void GridOnFilterSelected(DynamicGridSelectedFilterSettings settings) { new UserConfiguration().Save(new ReservationManagementUserSettings { Filters = settings }); Refresh(false, true); } public override DynamicGridColumns GenerateColumns() { var columns = new DynamicGridColumns(); columns.Add(x => x.Requisition.DueDate, 80, "Due", "", Alignment.MiddleCenter); columns.Add(x => x.Requisition.Job.JobNumber, 70, "Job", "", Alignment.MiddleCenter); columns.Add(x => x.Requisition.Number, 50, "Requi", "", Alignment.MiddleCenter); columns.Add(x => x.Product.Code, 100, "Product Code", "", Alignment.MiddleLeft); columns.Add(x => x.Product.Name, 0, "Product Name", "", Alignment.MiddleLeft); columns.Add(x => x.Style.Code, 100, "Style", "", Alignment.MiddleLeft); columns.Add(x => x.Dimensions.UnitSize, 70, "Size", "", Alignment.MiddleLeft); columns.Add(x => x.Status, 90, "Status", "", Alignment.MiddleCenter); return columns; } protected override void ConfigureColumnGroups() { GetColumnGrouping() .AddGroup("Stock", InStockColumn, OnOrderColumn) .AddGroup("Treatment", TreatmentRequiredColumn, TreatmentOnOrderColumn) .AddGroup("Allocated", AllocatedColumn, IssuedColumn); } protected override void SelectItems(CoreRow[]? rows) { base.SelectItems(rows); if(rows?.Any() == true) { ArchiveButton.IsEnabled = true; } } #region Action Column Buttons private void BuildMenu(DynamicMenuColumn column, CoreRow? row) { column.AddItem("Order Required", PRSDesktop.Resources.purchase, OrderRequired_Clicked); column.AddItem("Split Line", PRSDesktop.Resources.split, SplitLine_Clicked); column.AddItem("Archive", PRSDesktop.Resources.archive, Archive_Clicked); if (Security.CanView()) { column.AddSeparator(); column.AddItem("View Stock Movements", PRSDesktop.Resources.forklift, ViewStockMovements); } } private bool CheckValidAction(JobRequisitionItem item) { bool valid = true; if (item.Status == JobRequisitionItemStatus.Allocated) { MessageWindow.ShowMessage("Item has already been reserved!", "Error", image: MessageWindow.WarningImage); return false; } else if (item.Status == JobRequisitionItemStatus.OnOrder) { MessageWindow.ShowMessage("Item is already on order!", "Error", image: MessageWindow.WarningImage); return false; } else if (item.InStock >= item.Qty) { MessageWindow.ShowMessage("Item is already in stock!", "Error", image: MessageWindow.WarningImage); return false; } return valid; } private void SplitLine(JobRequisitionItem item, double oldItemQty, double newItemQty, string notes) { var items = new List(); var newItem = new JobRequisitionItem(); newItem.Job.CopyFrom(item.Job); newItem.Requisition.ID = item.Requisition.ID; newItem.Requisition.Job.ID = item.Requisition.Job.ID; newItem.Product.ID = item.Product.ID; newItem.Dimensions.CopyFrom(item.Dimensions); newItem.Style.ID = item.Style.ID; newItem.Notes = item.Notes + Environment.NewLine + notes; item.Notes = newItem.Notes; item.Qty = oldItemQty; newItem.Qty = newItemQty; items.Add(newItem); items.Add(item); Client.Save(items, "Split lines from Job Requi Item Review Dashboard"); MessageWindow.ShowMessage($"Line split - original line Qty is now {item.Qty}. New line Qty is {newItem.Qty}", "Lines split"); Refresh(false, true); } private void SplitLine_Clicked(CoreRow? row) { if (row is null) return; var item = row.ToObject(); if (CheckValidAction(item)) { var units = item.Qty - item.InStock; if(DoubleEdit.Execute("Enter amount to split", 1, units, ref units)) { SplitLine(item, item.Qty - units, units, "Line split"); } } } private static bool Archive(IEnumerable items) { var itemsList = items.AsIList(); var toChange = new List(); foreach(var item in itemsList) { if (item.Status != JobRequisitionItemStatus.Allocated) { var win = MessageWindow.New() .Message($"Requisition item for requisition {item.Requisition.Number} is not fully allocated; " + $"its current status is {item.Status}. Are you sure you wish to archive this item?") .Title("Confirm Archive") .AddYesButton("Archive"); if(itemsList.Count > 1) { win.AddNoButton("Skip"); } var result = win .AddCancelButton() .Display().Result; if (result == MessageWindowResult.Cancel) { return false; } else if(result == MessageWindowResult.Yes) { toChange.Add(item); } } else { toChange.Add(item); } } if(toChange.Count == 0) { MessageWindow.ShowMessage("No items archived.", "Cancelled"); return false; } foreach(var item in toChange) { item.Archived = DateTime.Now; item.Notes += Environment.NewLine + "Line marked as Archived by " + App.EmployeeName + " on " + DateTime.Now.ToString("dd MMM yy"); } Client.Save(toChange, "Updated From Job Requisition Review Dashboard"); return true; } private bool ArchiveButton_Clicked(Button _btn, CoreRow[] rows) { return Archive(rows.ToObjects()); } private void Archive_Clicked(CoreRow? row) { if (row is null) return; if (Archive(CoreUtils.One(row.ToObject()))) { Refresh(false, true); } } private void OrderRequired_Clicked(CoreRow? row) { if (row is null) return; var item = row.ToObject(); if (CheckValidAction(item)) { item.OrderRequired = DateTime.Now; item.Notes += Environment.NewLine + "Line marked as Order Required by " + App.EmployeeName + " on " + DateTime.Now.ToString("dd MMM yy"); Client.Save(item, "Updated From Job Requisition Review Dashboard"); Refresh(false, true); } } private void ViewStockMovements(CoreRow? row) { if (row is null) return; var requiID = row.Get(x => x.ID); DynamicDataGrid grid; if (DynamicGridUtils.TryFindDynamicGrid(typeof(DynamicDataGrid<>), typeof(StockMovement), out var gridType)) { grid = (Activator.CreateInstance(gridType) as DynamicDataGrid)!; } else { grid = new DynamicDataGrid(); grid.OnReconfigure += (options) => { options.SelectColumns = true; }; grid.Reconfigure(); } grid.OnDefineFilter += (t) => new Filter(x => x.JobRequisitionItem.ID).IsEqualTo(requiID); var window = DynamicGridUtils.CreateGridWindow("Stock movements", grid); window.ShowDialog(); } #endregion protected override void Reload(Filters criteria, Columns columns, ref SortOrder? sort, Action action) { criteria.Add(new Filter(x => x.Requisition.Approved).IsNotEqualTo(DateTime.MinValue)); criteria.Add(new Filter(x => x.Archived).IsEqualTo(DateTime.MinValue)); criteria.Add(new Filter(x => x.Cancelled).IsEqualTo(DateTime.MinValue)); sort = new SortOrder(x => x.Requisition.Number, SortDirection.Descending); base.Reload(criteria, columns, ref sort, action); } protected override DragDropEffects OnRowsDragStart(CoreRow[] rows) { // Only allow dragging the selected rows. var selected = SelectedRows.Select(x => x.Get(x => x.ID)).ToHashSet(); var draggedRows = rows.Where(x => selected.Contains(x.Get(x => x.ID))).ToArray(); if(draggedRows.Length == 0) { return DragDropEffects.None; } else { return base.OnRowsDragStart(draggedRows); } } } public class JobRequiReviewDashboardFilterItem { public Guid SupplierID { get; set; } public Guid ProductID { get; set; } public string Text { get; set; } public JobRequiReviewDashboardFilterItem() { SupplierID = Guid.Empty; ProductID = Guid.Empty; Text = ""; } }