123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 |
- using com.sun.corba.se.spi.orbutil.threadpool;
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Core;
- using InABox.DynamicGrid;
- using InABox.WPF;
- using InABox.Wpf;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Media;
- using PRSDesktop.Panels.Jobs.Summary;
- using System.Threading;
- namespace PRSDesktop;
- internal class JobSummaryGrid : DynamicDataGrid<JobMaterial>, IMasterDetailControl<Job,JobMaterial>, IDataModelSource
- {
- Guid empID = Guid.Empty;
- string empName = "";
- private List<DetailsColumn> DetailsColumns;
- private Job? _master;
-
- private Button _cancelRequisitions;
- private Button _releaseStock;
- public Job? Master
- {
- get => _master;
- set
- {
- _master = value;
- _cancelRequisitions.IsEnabled = Master?.JobStatus.Active == false;
- }
- }
- public Filter<JobMaterial> MasterDetailFilter => (Master?.ID ?? Guid.Empty) != Guid.Empty
- ? new Filter<JobMaterial>(x => x.Job.ID).IsEqualTo(Master.ID)
- .And(x => x.Product.ID).IsNotEqualTo(Guid.Empty)
- : new Filter<JobMaterial>().None();
- public bool IncludeReserves { get; set; }
- public bool ShowIssues { get; set; }
-
- public JobSummaryGrid() : base()
- {
- ColumnsTag = nameof(JobSummaryGrid);
- OnCellDoubleClick += JobSummaryGrid_OnCellDoubleClick;
- SetupDetailsColumns();
-
- _cancelRequisitions = AddButton("Cancel Requisitions", PRSDesktop.Resources.archive.AsBitmapImage(),
- CancelRequisitions);
-
- _releaseStock = AddButton("Release Stock", PRSDesktop.Resources.archive.AsBitmapImage(),
- ReleaseStock);
- }
- public Dictionary<StockHolding,IEnumerable<JobRequisitionItem>> GetHoldings(CoreRow[] rows)
- {
- var result = new Dictionary<StockHolding,IEnumerable<JobRequisitionItem>>();
- foreach (var row in rows)
- {
- var material = row.ToObject<JobMaterial>();
- var filter = new Filter<StockHolding>(x => x.Product.ID).IsEqualTo(material.Product.ID);
- if (StyleColumnVisible())
- filter = filter.And(x => x.Style.ID).IsEqualTo(material.Style.ID);
- if(DimensionsColumnVisible())
- filter = filter.And(x => x.Dimensions).DimensionEquals(material.Dimensions);
- var columns = Columns.None<StockHolding>().Add(x => x.Location.ID)
- .Add(x => x.Product.ID)
- .Add(x => x.Style.ID)
- .AddDimensionsColumns(x=>x.Dimensions);
- foreach (var holding in new Client<StockHolding>().Query(filter, columns).ToObjects<StockHolding>())
- result[holding] = holding.LoadRequisitionItems(true);
- }
- return result;
- }
- private bool ReleaseStock(System.Windows.Controls.Button btn, CoreRow[] rows)
- {
- if (rows?.Any() != true)
- return false;
-
- if(MessageWindow.ShowYesNoCancel("This will release any stock holdings for the selected items!\n\nAre you sure you wish to do this? ", "Confirm") != MessageWindowResult.Yes)
- return false;
-
- var updates = new List<StockMovement>();
- Progress.ShowModal("Loading Holdings", progress =>
- {
- var holdings = GetHoldings(rows);
- foreach (var (holding, items) in holdings)
- {
- foreach (var item in items)
- {
- var from = holding.CreateMovement();
- //from.OrderItem.ID = group.Key.OrderItem;
- from.JobRequisitionItem.ID = item.ID;
- from.Cost = StockRelease == StockReleaseWriteDownMethod.AverageCost
- ? holding.AverageValue
- : 0.0;
- from.Type = StockMovementType.TransferOut;
- from.Job.ID = Master.ID;
- from.Issued = item.Qty;
- var to = holding.CreateMovement();
- to.Cost = StockRelease == StockReleaseWriteDownMethod.AverageCost
- ? holding.AverageValue
- : 0.0;
- //to.OrderItem.ID = group.Key.OrderItem;
- //to.JobRequisitionItem.ID = item.ID;
- to.Job.ID = Guid.Empty;
- to.Type = StockMovementType.TransferIn;
- to.Transaction = from.Transaction;
- to.Received = item.Qty;
- to.Notes = $"Released from job {Master.JobNumber}";
- updates.Add(from);
- updates.Add(to);
- }
- }
- progress.Report("Saving Movements");
- if (updates.Any())
- Client.Save(updates, $"Stock Released from {Master.JobNumber} on Job Summary Screen");
- });
- MessageWindow.ShowMessage("The selected stock holdings have been cancelled.","Done");
- return updates.Any();
- }
-
- private bool CancelRequisitions(System.Windows.Controls.Button btn, CoreRow[] rows)
- {
- if (rows?.Any() != true)
- return false;
-
- if(MessageWindow.ShowYesNoCancel("This will cancel all outstanding requisitions for the selected items!\n\nAre you sure you wish to do this? ", "Confirm") != MessageWindowResult.Yes)
- return false;
-
- var updates = new List<JobRequisitionItem>();
- Progress.ShowModal("Loading Holdings", progress =>
- {
- var holdings = GetHoldings(rows);
- foreach (var holding in holdings)
- {
- var items = holding.Value.Where(
- x => x.ID != Guid.Empty
- && x.Status != JobRequisitionItemStatus.Cancelled
- && x.Status != JobRequisitionItemStatus.Issued
- && x.Status != JobRequisitionItemStatus.Archived
- );
- foreach (var item in items)
- {
- item.Cancelled = DateTime.Now;
- updates.Add(item);
- }
- progress.Report("Cancelling Requisitions");
- Client.Save(updates, $"Requsition cancelled for {Master.JobNumber} from Job Summary Screen");
- }
- });
- MessageWindow.ShowMessage("The selected requisitions have been cancelled.","Done");
- return updates.Any();
- }
- private class UIComponent : DynamicGridGridUIComponent<JobMaterial>
- {
- private Column<JobMaterial> _jobshortage = new Column<JobMaterial>(x => x.JobShortage);
- private Column<JobMaterial> _stockshortage = new Column<JobMaterial>(x => x.FreeStockShortage);
- protected override Brush? GetCellBackground(CoreRow row, DynamicColumnBase column)
- {
- if (column is DynamicGridColumn col)
- {
- if (_jobshortage.IsEqualTo(col.ColumnName))
- return row.Get<JobMaterial, double>(x => x.JobShortage) > 0.0F
- ? new SolidColorBrush(Colors.LightSalmon) { Opacity = 0.5 }
- : null;
- if (_stockshortage.IsEqualTo(col.ColumnName))
- return row.Get<JobMaterial, double>(x => x.FreeStockShortage) > 0.0F
- ? new SolidColorBrush(Colors.LightSalmon) { Opacity = 0.5 }
- : null;
- }
- return null;
- }
- }
- protected override IDynamicGridUIComponent<JobMaterial> CreateUIComponent()
- {
- return new UIComponent()
- {
- Parent = this
- };
- }
- protected override void Init()
- {
- base.Init();
- HiddenColumns.Add(x => x.Product.ID);
- HiddenColumns.Add(x => x.Style.ID);
- HiddenColumns.Add(x => x.Dimensions.UnitSize);
- HiddenColumns.Add(x => x.Dimensions.Value);
- HiddenColumns.Add(x => x.BillOfMaterials);
- HiddenColumns.Add(x => x.Requisitions);
- HiddenColumns.Add(x => x.PickingLists);
- HiddenColumns.Add(x => x.Issued);
- HiddenColumns.Add(x => x.ReservedStock);
- HiddenColumns.Add(x => x.OnOrder);
- HiddenColumns.Add(x => x.JobShortage);
- HiddenColumns.Add(x => x.FreeOnHand);
- HiddenColumns.Add(x => x.FreeOnOrder);
- HiddenColumns.Add(x => x.FreeStockTotal);
- HiddenColumns.Add(x => x.FreeStockShortage);
- HiddenColumns.Add(x => x.Product.Image.ID);
- HiddenColumns.Add(x => x.Product.Image.FileName);
- ActionColumns.Add(new DynamicImageManagerColumn<JobMaterial>(this, x => x.Product.Image, false)
- { Position = DynamicActionColumnPosition.Start });
- ActionColumns.Add(new DynamicMenuColumn(BuildMenu));
- AddButton("Create PO", null, CreatePO);
- }
- protected override void DoReconfigure(DynamicGridOptions options)
- {
- base.DoReconfigure(options);
- options.RecordCount = true;
- options.SelectColumns = true;
- options.FilterRows = true;
- options.ExportData = true;
- options.MultiSelect = true;
- }
- private bool StyleColumnVisible()
- {
- var styleColumn = CoreUtils.GetFullPropertyName<JobMaterial, ProductStyleLink>(x => x.Style, ".");
- return VisibleColumns.Any(x => x.ColumnName.StartsWith(styleColumn));
- }
- private bool DimensionsColumnVisible()
- {
- var dimColumn = CoreUtils.GetFullPropertyName<JobMaterial, StockDimensions>(x => x.Dimensions, ".");
- return VisibleColumns.Any(x => x.ColumnName.StartsWith(dimColumn));
- }
- private bool? _hasUnitSize;
- private bool UnitSizeColumnVisible()
- {
- if (_hasUnitSize.HasValue)
- {
- return _hasUnitSize.Value;
- }
- var dimColumn = CoreUtils.GetFullPropertyName<JobMaterial, string>(x => x.Dimensions.UnitSize, ".");
- _hasUnitSize = VisibleColumns.Any(x => x.ColumnName.Equals(dimColumn));
- return _hasUnitSize.Value;
- }
- protected override DynamicGridColumns LoadColumns()
- {
- _hasUnitSize = null;
- return base.LoadColumns();
- }
- public override DynamicGridColumns GenerateColumns()
- {
- var columns = new DynamicGridColumns();
- columns.Add<JobMaterial, string>(x => x.Product.Group.Code, 120, "Group Code", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, string>(x => x.Product.Code, 200, "Product Code", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, string>(x => x.Product.Name, 0, "Product Name", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, string>(x => x.Dimensions.UnitSize, 120, "UOM", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.BillOfMaterials, 80, "BOM", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.Requisitions, 80, "Req.", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.PickingLists, 80, "P/L", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.Issued, 80, "Issued", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.ReservedStock, 80, "Reserved", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.OnOrder, 80, "Ordered", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.JobShortage, 80, "Job Short", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.FreeStockTotal, 80, "Free Stock", "", Alignment.MiddleCenter);
- columns.Add<JobMaterial, double>(x => x.FreeStockShortage, 80, "Stk Short", "", Alignment.MiddleCenter);
- return columns;
- }
- private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
- {
- if (row is null) return;
- var menu = column.GetMenu();
- menu.AddItem("View Stock Movements", PRSDesktop.Resources.forklift, row, ViewStockMovements_Click);
- foreach(var col in DetailsColumns)
- {
- menu.AddItem(col.MenuText, null, row, col.Action);
- }
- }
- private void ViewStockMovements_Click(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- var productID = item.Product.ID;
- Guid? styleID = StyleColumnVisible() ? item.Style.ID : null;
- var dimensions = DimensionsColumnVisible() ? item.Dimensions : null;
- /*ShowDetailGrid<StockMovement>(
- args.Column.ColumnName,
- x => x.Product.ID,
- productid,
- x => x.Style.ID,
- styleid,
- x => x.Dimensions.UnitSize,
- unitsize,
- x => x.Job.ID,
- new Filter<StockMovement>(x => x.IsTransfer).IsEqualTo(false).And(x => x.Issued).IsNotEqualTo(0.0F),
- null
- );
- var movements = Client.Query<StockMovement>(
- );*/
- var grid = (Activator.CreateInstance(typeof(DynamicDataGrid<>).MakeGenericType(typeof(StockMovement))) as DynamicDataGrid<StockMovement>);
- if (grid == null)
- {
- MessageBox.Show($"Cannot create Grid for [{typeof(StockMovement).Name}]");
- return;
- }
- grid.ColumnsTag = $"{ColumnsTag}.Transactions";
- grid.Reconfigure(options =>
- {
- options.Clear();
- options.FilterRows = true;
- options.SelectColumns = true;
- });
- grid.OnReload += (object sender, Filters<StockMovement> criteria, Columns<StockMovement> columns, ref SortOrder<StockMovement>? sortby) =>
- {
- var filter = criteria.Combine();
- // We want to show entire transactions.
- criteria.Clear();
- criteria.Add(new Filter<StockMovement>(x => x.Transaction).InQuery(filter, x => x.Transaction));
- };
- grid.OnDefineFilter += t =>
- {
- var filter = new Filter<StockMovement>(x => x.Product.ID).IsEqualTo(productID);
- if(dimensions is not null)
- filter = filter.And(x => x.Dimensions).DimensionEquals(dimensions);
- if (styleID.HasValue)
- filter = filter.And(x => x.Style.ID).IsEqualTo(styleID);
- filter = filter.And(x => x.Job.ID).IsEqualTo(Master?.ID ?? Guid.Empty);
- return filter;
- };
- var window = DynamicGridUtils.CreateGridWindow($"Stock Movements", grid);
- window.ShowDialog();
- }
- private void ShowDetailGrid<TEntity>(
- String columnname,
- Expression<Func<TEntity, object?>> productcol,
- Guid productid,
- Expression<Func<TEntity, object?>> stylecol,
- Guid? styleid,
- Expression<Func<TEntity, IDimensions>> dimcol,
- IDimensions? dimensions,
- Expression<Func<TEntity, object?>>? jobcol,
- Filter<TEntity>? extrafilter,
- Func<CoreRow, bool>? rowfilter
- )
- {
- var grid = (Activator.CreateInstance(typeof(DynamicDataGrid<>).MakeGenericType(typeof(TEntity))) as IDynamicDataGrid);
- if (grid == null)
- {
- MessageBox.Show($"Cannot create Grid for [{typeof(TEntity).Name}]");
- return;
- }
- grid.ColumnsTag = $"{ColumnsTag}.{columnname}";
- grid.Reconfigure(options =>
- {
- options.Clear();
- options.FilterRows = true;
- options.SelectColumns = true;
- });
- grid.OnDefineFilter += t =>
- {
- var filter = new Filter<TEntity>(productcol).IsEqualTo(productid);
- if(dimensions is not null)
- filter = filter.And(CoreUtils.GetFullPropertyName(dimcol, ".")).DimensionEquals(dimensions);
- if (styleid.HasValue)
- filter = filter.And(stylecol).IsEqualTo(styleid);
- if (jobcol != null)
- filter = filter.And(jobcol).IsEqualTo(Master?.ID ?? Guid.Empty);
- if (extrafilter != null)
- filter = filter.And(extrafilter);
- return filter;
- };
- grid.OnFilterRecord += row => rowfilter?.Invoke(row) ?? true;
- var window = DynamicGridUtils.CreateGridWindow($"Viewing {CoreUtils.Neatify(columnname)} Calculation", grid);
- window.ShowDialog();
- }
- private static readonly Column<JobMaterial> BOMColumn = new Column<JobMaterial>(x => x.BillOfMaterials);
- private static readonly Column<JobMaterial> RequisitionsColumn = new Column<JobMaterial>(x => x.Requisitions);
- private static readonly Column<JobMaterial> PickingListsColumn = new Column<JobMaterial>(x => x.PickingLists);
- private static readonly Column<JobMaterial> IssuedColumn = new Column<JobMaterial>(x => x.Issued);
- private static readonly Column<JobMaterial> ReservedStockColumn = new Column<JobMaterial>(x => x.ReservedStock);
- private static readonly Column<JobMaterial> OnOrderColumn = new Column<JobMaterial>(x => x.OnOrder);
- private static readonly Column<JobMaterial> FreeOnHandColumn = new Column<JobMaterial>(x => x.FreeOnHand);
- private static readonly Column<JobMaterial> FreeOnOrderColumn = new Column<JobMaterial>(x => x.FreeOnOrder);
- private void ViewBillOfMaterials(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- ShowDetailGrid<JobBillOfMaterialsItem>(
- BOMColumn.Property,
- x => x.Product.ID,
- item.Product.ID,
- x => x.Style.ID,
- StyleColumnVisible() ? item.Style.ID : null,
- x => x.Dimensions,
- DimensionsColumnVisible() ? item.Dimensions : null,
- x => x.Job.ID,
- new Filter<JobBillOfMaterialsItem>(x => x.BillOfMaterials.Approved).IsNotEqualTo(DateTime.MinValue),
- null
- );
- }
- private void ViewRequisitions(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- Guid? styleID = StyleColumnVisible() ? item.Style.ID : null;
- var dimensions = DimensionsColumnVisible() ? item.Dimensions : null;
- var grid = new JobRequisitionItemSummaryGrid();
- grid.OnDefineFilter += t =>
- {
- var filter = new Filter<JobRequisitionItem>(x => x.Product.ID).IsEqualTo(item.Product.ID)
- .And(x => x.Requisition.Approved).IsNotEqualTo(DateTime.MinValue)
- .And(x => x.Cancelled).IsEqualTo(DateTime.MinValue);
- if(dimensions is not null)
- {
- filter = filter.And(x => x.Dimensions).DimensionEquals(item.Dimensions);
- }
- if (styleID.HasValue)
- {
- filter = filter.And(x => x.Style.ID).IsEqualTo(styleID.Value);
- }
- filter = filter.And(x => x.Requisition.Job.ID).IsEqualTo(Master?.ID ?? Guid.Empty);
- return filter;
- };
- var window = DynamicGridUtils.CreateGridWindow($"Viewing Requisition Calculation", grid);
- window.ShowDialog();
- }
- private void ViewPickingLists(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- ShowDetailGrid<RequisitionItem>(
- PickingListsColumn.Property,
- x => x.Product.ID,
- item.Product.ID,
- x => x.Style.ID,
- StyleColumnVisible() ? item.Style.ID : null,
- x => x.Dimensions,
- DimensionsColumnVisible() ? item.Dimensions : null,
- x => x.JobLink.ID,
- new Filter<RequisitionItem>(x => x.RequisitionLink.Filled).IsEqualTo(DateTime.MinValue),
- null
- );
- }
- private void ViewIssued(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- ShowDetailGrid<StockMovement>(
- IssuedColumn.Property,
- x => x.Product.ID,
- item.Product.ID,
- x => x.Style.ID,
- StyleColumnVisible() ? item.Style.ID : null,
- x => x.Dimensions,
- DimensionsColumnVisible() ? item.Dimensions : null,
- x => x.Job.ID,
- new Filter<StockMovement>(x => x.Type).IsEqualTo(StockMovementType.Issue),
- null
- );
- }
- private void ViewReservedStock(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- ShowDetailGrid<StockHolding>(
- ReservedStockColumn.Property,
- x => x.Product.ID,
- item.Product.ID,
- x => x.Style.ID,
- StyleColumnVisible() ? item.Style.ID : null,
- x => x.Dimensions,
- DimensionsColumnVisible() ? item.Dimensions : null,
- x => x.Job.ID,
- new Filter<StockHolding>(x => x.Units).IsGreaterThan(0.1),
- null
- );
- }
- private void ViewOnOrder(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- ShowDetailGrid<PurchaseOrderItemAllocation>(
- OnOrderColumn.Property,
- x => x.Item.Product.ID,
- item.Product.ID,
- x => x.Item.Style.ID,
- StyleColumnVisible() ? item.Style.ID : null,
- x => x.Item.Dimensions,
- DimensionsColumnVisible() ? item.Dimensions : null,
- x => x.Job.ID,
- null,
- null
- );
- }
- private void ViewFreeOnHand(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- ShowDetailGrid<StockHolding>(
- FreeOnHandColumn.Property,
- x => x.Product.ID,
- item.Product.ID,
- x => x.Style.ID,
- StyleColumnVisible() ? item.Style.ID : null,
- x => x.Dimensions,
- DimensionsColumnVisible() ? item.Dimensions : null,
- null,
- new Filter<StockHolding>(x => x.Units).IsNotEqualTo(0.0F)
- .And(
- IncludeReserves
- ? new Filter<StockHolding>(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)
- : new Filter<StockHolding>(x => x.Job.JobStatus.Active).IsEqualTo(false)
- ),
- null
- );
- }
- private void ViewFreeOnOrder(CoreRow row)
- {
- var item = row.ToObject<JobMaterial>();
- ShowDetailGrid<PurchaseOrderItemAllocation>(
- FreeOnOrderColumn.Property,
- x => x.Item.Product.ID,
- item.Product.ID,
- x => x.Item.Style.ID,
- StyleColumnVisible() ? item.Style.ID : null,
- x => x.Item.Dimensions,
- DimensionsColumnVisible() ? item.Dimensions : null,
- null,
- IncludeReserves
- ? new Filter<PurchaseOrderItemAllocation>(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)
- : new Filter<PurchaseOrderItemAllocation>(x => x.Job.JobStatus.Active).IsEqualTo(false),
- null
- );
- }
- [MemberNotNull(nameof(DetailsColumns))]
- private void SetupDetailsColumns()
- {
- DetailsColumns = new List<DetailsColumn>
- {
- new(BOMColumn, ViewBillOfMaterials, "View bill of materials"),
- new(RequisitionsColumn, ViewRequisitions, "View requisitions"),
- new(PickingListsColumn, ViewPickingLists, "View picking lists"),
- new(IssuedColumn, ViewIssued, "View issued"),
- new(ReservedStockColumn, ViewReservedStock, "View reserved stock"),
- new(OnOrderColumn, ViewOnOrder, "View on order"),
- new(FreeOnHandColumn, ViewFreeOnHand, "View free on hand"),
- new(FreeOnOrderColumn, ViewFreeOnOrder, "View free on order"),
- };
- }
- private class DetailsColumn
- {
- public Column<JobMaterial> Column { get; set; }
- public Action<CoreRow> Action { get; set; }
- public string MenuText { get; set; }
- public DetailsColumn(Column<JobMaterial> column, Action<CoreRow> action, string menuText)
- {
- Column = column;
- Action = action;
- MenuText = menuText;
- }
- }
- private void JobSummaryGrid_OnCellDoubleClick(object sender, DynamicGridCellClickEventArgs args)
- {
- if (args?.Column is DynamicGridColumn col)
- {
- foreach (var column in DetailsColumns)
- {
- if (column.Column.IsEqualTo(col.ColumnName))
- {
- column.Action(args.Row);
- break;
- }
- }
- }
- }
- public event DataModelUpdateEvent? OnUpdateDataModel;
- public string SectionName => "Job Summary";
-
- public StockReleaseWriteDownMethod StockRelease { get; set; }
- public DataModel DataModel(Selection selection)
- {
- return new AutoDataModel<JobMaterial>(MasterDetailFilter);
- }
-
- public override JobMaterial CreateItem()
- {
- var result = base.CreateItem();
- result.Job.ID = Master?.ID ?? Guid.Empty;
- result.Job.Synchronise(Master ?? new Job());
- return result;
- }
- private class Key(Guid jobID, Guid productID, Guid? styleID, IDimensions? dimensions)
- {
- public Guid JobID { get; set; } = jobID;
- public Guid ProductID { get; set; } = productID;
- public Guid? StyleID { get; set; } = styleID;
- public IDimensions? Dimensions { get; set; } = dimensions;
- public override bool Equals(object? obj)
- {
- return obj is Key key
- && JobID == key.JobID
- && ProductID == key.ProductID
- && StyleID == key.StyleID
- && Equals(Dimensions, key.Dimensions);
- }
- public override int GetHashCode()
- {
- return HashCode.Combine(
- JobID, ProductID, StyleID, Dimensions);
- }
- }
- private Key[] GetKeys(IEnumerable<CoreRow> rows, Columns<JobMaterial> columns, bool hasstyle, bool hasDimensions)
- {
- int jobcol = columns.IndexOf(x => x.Job.ID);
- int productcol = columns.IndexOf(x => x.Product.ID);
- int stylecol = hasstyle ? columns.IndexOf(x => x.Style.ID) : -1;
- var dimCols = hasDimensions ? Dimensions.GetFilterColumnIndices<JobMaterial>(columns, x => x.Dimensions) : null;
- var result = rows.Select(r => new Key(
- (Guid)(r.Values[jobcol] ?? Guid.Empty),
- (Guid)(r.Values[productcol] ?? Guid.Empty),
- (stylecol != -1) ? (Guid)(r.Values[stylecol] ?? Guid.Empty) : null,
- dimCols is not null ? r.ToDimensions<StockDimensions>(dimCols) : null)
- ).Distinct().ToArray();
- return result;
- }
-
- private CoreRow[] GetAllocationRows(IEnumerable<CoreRow> rows, Columns<PurchaseOrderItemAllocation> columns, Guid? jobID, Key key, Func<CoreRow, bool>? extrafilter = null)
- {
- int jobcol = columns.IndexOf(x => x.Job.ID);
- int productcol = columns.IndexOf(x => x.Item.Product.ID);
- int stylecol = key.StyleID.HasValue ? columns.IndexOf(x => x.Item.Style.ID) : -1;
- int unitcol = columns.IndexOf(x => x.Item.Dimensions.UnitSize);
- var dimCols = Dimensions.GetFilterColumnIndices<PurchaseOrderItemAllocation>(columns, x => x.Item.Dimensions);
- var subset = rows
- .Where(r =>
- (!jobID.HasValue || Guid.Equals(jobID, r.Values[jobcol]))
- && Guid.Equals(key.ProductID, r.Values[productcol])
- && (!key.StyleID.HasValue || Guid.Equals(key.StyleID, r.Values[stylecol]))
- && (key.Dimensions is null || key.Dimensions.Equals(r.ToDimensions<StockDimensions>(dimCols)))
- && ((extrafilter == null) || extrafilter(r))
- );
- return subset.ToArray();
- }
- private CoreRow[] GetRows<TSource>(IEnumerable<CoreRow> rows, Columns<TSource> columns, Guid? jobID, Key key, Func<CoreRow, bool>? extrafilter = null) where TSource : IJobMaterial
- {
- int jobcol = columns.IndexOf(x => x.Job.ID);
- int productcol = columns.IndexOf(x => x.Product.ID);
- int stylecol = key.StyleID.HasValue ? columns.IndexOf(x => x.Style.ID) : -1;
- int unitcol = columns.IndexOf(x => x.Dimensions.UnitSize);
- var dimCols = Dimensions.GetFilterColumnIndices<TSource>(columns, x => x.Dimensions);
- var subset = rows
- .Where(r =>
- (!jobID.HasValue || Guid.Equals(jobID, r.Values[jobcol]))
- && Guid.Equals(key.ProductID, r.Values[productcol])
- && (!key.StyleID.HasValue || Guid.Equals(key.StyleID, r.Values[stylecol]))
- && (key.Dimensions is null || key.Dimensions.Equals(r.ToDimensions<StockDimensions>(dimCols)))
- && ((extrafilter == null) || extrafilter(r))
- );
- return subset.ToArray();
- }
- private double Aggregate<TSource>(IEnumerable<CoreRow> rows, Columns<TSource> columns, bool hasstyle, bool hasjob, Expression<Func<TSource, object>> source, CoreRow target, Expression<Func<JobMaterial, object>> aggregate)
- {
- int srcol = columns.IndexOf(source);
- if (srcol == -1)
- return 0.00;
- var total = rows.Aggregate(0d, (value, row) => value + (double)(row.Values[srcol] ?? 0.0d));
- target.Set(aggregate, total);
- return total;
- }
- protected override void Reload(
- Filters<JobMaterial> criteria, Columns<JobMaterial> columns, ref SortOrder<JobMaterial>? sort,
- CancellationToken token, Action<CoreTable?, Exception?> action)
- {
- criteria.Add(MasterDetailFilter);
- criteria.Add(FilterComponent.GetFilter());
- var orderby = sort;
- Progress.ShowModal("Loading Data",
- (progress) =>
- {
- var table = new CoreTable();
- table.LoadColumns(columns);
- var data = new Client<JobMaterial>().Query(criteria.Combine(), columns, orderby);
- var pids = data.ExtractValues<JobMaterial, Guid>(x => x.Product.ID).ToArray();
- if (pids.Any())
- {
- var results = Client.QueryMultiple(
- new KeyedQueryDef<StockHolding>(
- new Filter<StockHolding>(x => x.Product.ID).InList(pids)
- .And(x => x.Units).IsNotEqualTo(0.0F)
- .And(new Filter<StockHolding>(x => x.Job.ID).IsEqualTo(Guid.Empty).Or(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)),
- Columns.None<StockHolding>().Add(x => x.Product.ID)
- .Add(x => x.Style.ID)
- .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local)
- .Add(x => x.Units)
- .Add(x => x.Job.ID)
- .Add(x => x.Job.JobStatus.Active)),
- new KeyedQueryDef<PurchaseOrderItemAllocation>(
- new Filter<PurchaseOrderItemAllocation>(x => x.Item.ReceivedDate).IsEqualTo(DateTime.MinValue)
- .And(x => x.Item.Product.ID).InList(pids)
- .And(new Filter<PurchaseOrderItemAllocation>(x => x.Job.ID).IsEqualTo(Guid.Empty).Or(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)),
- Columns.None<PurchaseOrderItemAllocation>().Add(x => x.Item.Product.ID)
- .Add(x => x.Item.Style.ID)
- .AddDimensionsColumns(x => x.Item.Dimensions, Dimensions.ColumnsType.Local)
- .Add(x => x.Quantity)
- .Add(x => x.Job.ID)
- .Add(x => x.Job.JobStatus.Active)));
- var freestock = results.Get<StockHolding>();
- var freestockcolumns = Columns.None<StockHolding>().Add(freestock.Columns.Select(x => x.ColumnName));
- var freeorders = results.Get<PurchaseOrderItemAllocation>();
- var freeordercolumns = Columns.None<PurchaseOrderItemAllocation>().Add(freeorders.Columns.Select(x => x.ColumnName));
- var hasStyle = StyleColumnVisible();
- var hasDimensions = DimensionsColumnVisible();
- var hasUnitSize = UnitSizeColumnVisible();
- var keys = GetKeys(data.Rows, columns, hasStyle, hasDimensions);
- foreach (var key in keys)
- {
- var rows = GetRows(data.Rows, columns, key.JobID, key);
- if (rows.Length != 0)
- {
- if (!hasUnitSize)
- {
- foreach(var row in rows)
- {
- var multFactor = row.Get<JobMaterial, double>(x => x.Dimensions.Value);
- row.Update<JobMaterial, double>(x => x.BillOfMaterials, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.Requisitions, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.PickingLists, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.Issued, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.ReservedStock, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.OnOrder, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.JobShortage, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.FreeOnHand, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.FreeOnOrder, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.FreeStockTotal, x => x * multFactor);
- row.Update<JobMaterial, double>(x => x.FreeStockShortage, x => x * multFactor);
- }
- }
- CoreRow newrow = table.NewRow();
- newrow.LoadValues(rows.First().Values);
- var bom = Aggregate(rows, columns, hasStyle, true, x => x.BillOfMaterials, newrow,
- x => x.BillOfMaterials);
- var requi = Aggregate(rows, columns, hasStyle, true, x => x.Requisitions, newrow, x => x.Requisitions);
- var picklist = Aggregate(rows, columns, hasStyle, true, x => x.PickingLists, newrow,
- x => x.PickingLists);
- var issued = Aggregate(rows, columns, hasStyle, true, x => x.Issued, newrow, x => x.Issued);
- var reserved = Aggregate(rows, columns, hasStyle, true, x => x.ReservedStock, newrow,
- x => x.ReservedStock);
- var ordered = Aggregate(rows, columns, hasStyle, true, x => x.OnOrder, newrow, x => x.OnOrder);
- var shortage = Math.Max(0, Math.Max(0, (requi - issued)) - (reserved + ordered));
- newrow.Set<JobMaterial, double>(x => x.JobShortage, shortage);
- var freestockrows = GetRows(freestock.Rows, freestockcolumns, null, key,
- IncludeReserves ? null : (r) => !r.Get<StockHolding, bool>(x => x.Job.JobStatus.Active));
- var freeonhand = Aggregate(freestockrows, freestockcolumns, hasStyle, false, x => x.Units, newrow,
- x => x.FreeOnHand);
- newrow.Set<JobMaterial, double>(x => x.FreeOnHand, freeonhand);
- var freeorderrows = GetAllocationRows(freeorders.Rows, freeordercolumns, null, key,
- IncludeReserves ? null : (r) => !r.Get<PurchaseOrderItemAllocation, bool>(x => x.Job.JobStatus.Active));
- var freeonorder = Aggregate(freeorderrows, freeordercolumns, hasStyle, false, x => x.Quantity, newrow,
- x => x.FreeOnOrder);
- newrow.Set<JobMaterial, double>(x => x.FreeOnOrder, freeonorder);
- newrow.Set<JobMaterial, double>(x => x.FreeStockTotal, freeonhand + freeonorder);
- newrow.Set<JobMaterial, double>(x => x.FreeStockShortage, Math.Max(0, shortage - (freeonhand + freeonorder)));
- table.Rows.Add(newrow);
- }
- }
- }
- action?.Invoke(table, null);
- }
- );
- }
- protected override bool FilterRecord(CoreRow row)
- {
- var result = base.FilterRecord(row)
- && (
- row.Get<JobMaterial, double>(x => x.BillOfMaterials) != 0.0F ||
- row.Get<JobMaterial, double>(x => x.Requisitions) != 0.0F ||
- row.Get<JobMaterial, double>(x => x.PickingLists) != 0.0F ||
- row.Get<JobMaterial, double>(x => x.Issued) != 0.0F ||
- row.Get<JobMaterial, double>(x => x.ReservedStock) != 0.0F ||
- row.Get<JobMaterial, double>(x => x.OnOrder) != 0.0F
- );
- if (ShowIssues)
- {
- result = result && (
- row.Get<JobMaterial, double>(x => x.JobShortage) > 0.0F ||
- row.Get<JobMaterial, double>(x => x.FreeStockShortage) > 0.0F);
- }
- return result;
- }
- #region Create PO
- private bool CreatePO(System.Windows.Controls.Button btn, CoreRow[] rows)
- {
- if (!rows.Any())
- {
- MessageBox.Show("Please select at least one row to add to PO");
- return false;
- }
- PurchaseOrder purchaseOrder = new PurchaseOrder();
- purchaseOrder.Description = "Created from Job Summary Screen" + System.Environment.NewLine;
- purchaseOrder.RaisedBy.ID = empID;
- var page = new SupplierPurchaseOrders();
- page.OnAfterSave += (form, items) =>
- {
- PurchaseOrderOnSave(form, items.Cast<PurchaseOrder>().ToArray());
- MessageBox.Show("Success - New Purchase Order Created (" + purchaseOrder.PONumber + ")");
-
- };
- return page.EditItems(new[] { purchaseOrder }, LoadPurchaseOrderItems, true);
- }
- private CoreTable LoadPurchaseOrderItems(Type arg)
- {
- Progress.Show("Working");
- var result = new CoreTable();
- result.LoadColumns(typeof(PurchaseOrderItem));
- List<PurchaseOrderItem> items = new List<PurchaseOrderItem>();
- foreach (CoreRow row in SelectedRows)
- {
- JobMaterial material = row.ToObject<JobMaterial>();
- PurchaseOrderItem POItem = new PurchaseOrderItem();
- POItem.Product.ID = material.Product.ID;
- POItem.Product.Code = material.Product.Code;
- POItem.Product.Name = material.Product.Name;
- POItem.Description = material.Product.Name;
- POItem.Qty = 0;
- POItem.Dimensions.CopyFrom(material.Dimensions);
- POItem.Style.ID = material.Style.ID;
- POItem.Style.Code = material.Style.Code;
- POItem.Style.Description = material.Style.Description;
- POItem.Dimensions.UnitSize = material.Dimensions.UnitSize;
- items.Add(POItem);
- }
- result.LoadRows(items);
- Progress.Close();
- return result;
- }
-
- private void PurchaseOrderOnSave(IDynamicEditorForm form, PurchaseOrder[] items)
- {
- Progress.ShowModal("Working", progress =>
- {
-
- var poItems = new Client<PurchaseOrderItem>().Query(
- new Filter<PurchaseOrderItem>(x => x.PurchaseOrderLink.ID).InList(items.Select(x=>x.ID).ToArray()),
- Columns.None<PurchaseOrderItem>()
- .Add(x => x.ID)
- .Add(x => x.Product.ID)
- .Add(x => x.Qty)
- .Add(x => x.Dimensions.UnitSize)
- .Add(x => x.Dimensions.Value)
- .Add(x => x.Style.ID)
- .Add(x => x.DueDate)
- ).Rows.ToObjects<PurchaseOrderItem>().ToArray();
- if (poItems.Any())
- {
- List<PurchaseOrderItemAllocation> poias = new();
- var jobID = Master?.ID ?? Guid.Empty;
- if(jobID != Guid.Empty)
- {
- foreach (var poItem in poItems)
- {
- var poia = new PurchaseOrderItemAllocation();
- poia.Item.ID = poItem.ID;
- poia.Job.ID = jobID;
- poia.Quantity = poItem.Qty;
- poias.Add(poia);
- }
- }
- if (poias.Any())
- Client.Save(poias, "Updated on Create Purchase Order from BOM Dashboard");
- }
- });
- }
- #endregion
- }
|