Procházet zdrojové kódy

PRS DESKTOP - create stock location from puchase order items

Nick-PRSDigital@bitbucket.org před 2 roky
rodič
revize
741f362fbe

+ 1 - 5
prs.classes/Entities/PurchaseOrder/PurchaseOrderItem.cs

@@ -149,7 +149,7 @@ namespace Comal.Classes
         [Aggregate(typeof(PurchaseOrderItemOpenForms))]
         public int OpenForms { get; set; }
 
-        [NullEditor]
+        
         public StockLocationLink StockLocation { get; set; }
 
         [CurrencyEditor(Visible = Visible.Default, Summary = Summary.Sum)]
@@ -237,9 +237,5 @@ namespace Comal.Classes
             bChanging = false;
             base.DoPropertyChanged(name, before, after);
         }
-
-
-        
-        
     }
 }

+ 2 - 667
prs.desktop/Dashboards/Projects/Job Requisition Items Review Dashboard/JobRequisitionReviewDashboard.xaml.cs

@@ -39,7 +39,6 @@ namespace PRSDesktop
         {
             InitializeComponent();
             Grid.Refresh(true, true);
-            LoadFilters();
         }
         public void Refresh()
         {
@@ -59,674 +58,10 @@ namespace PRSDesktop
             Grid.RefreshOnFilterChanged(item.SupplierID);
         }
 
-        private void LoadFilters()
-        {
-            List<Guid> productIDs = new List<Guid>();
-            CoreTable productsTable = new Client<JobRequisitionItem>().Query(new Filter<JobRequisitionItem>(x => x.Product).LinkValid(),
-                new Columns<JobRequisitionItem>(x => x.Product.ID));
-            foreach (CoreRow row1 in productsTable.Rows)
-            {
-                productIDs.Add(Guid.Parse(row1.Values[0].ToString()));
-            }
-            CoreTable table = new Client<SupplierProduct>().Query(
-                new Filter<SupplierProduct>(x => x.Product).LinkValid()
-                    .And(x => x.SupplierLink).LinkValid(),
-                new Columns<SupplierProduct>(x => x.SupplierLink.ID, x => x.Product.ID, x => x.SupplierLink.Name, x => x.SupplierLink.Code));
-            if (table.Rows.Any())
-            {
-                JobRequiReviewDashboardFilterItem firstItem = new JobRequiReviewDashboardFilterItem
-                {
-                    Text = "No Filter"
-                };
-                filterItems.Add(firstItem);
-                foreach (CoreRow row in table.Rows)
-                {
-                    JobRequiReviewDashboardFilterItem filterItem = new JobRequiReviewDashboardFilterItem
-                    {
-                        SupplierID = Guid.Parse(row.Values[0].ToString()),
-                        ProductID = Guid.Parse(row.Values[1].ToString()),
-                    };
-                    if (row.Values[3] != null)
-                    {
-                        filterItem.Text = row.Values[3].ToString();
-                        if (row.Values[2] != null)
-                        {
-                            filterItem.Text = filterItem.Text + " " + row.Values[2].ToString();
-                        }
-                    }
-
-                    var founditem = filterItems.Find(x => x.SupplierID == filterItem.SupplierID);
-                    if (founditem == null)
-                    {
-                        if (productIDs.Contains(filterItem.ProductID))
-                            filterItems.Add(filterItem);
-                    }
-                }
-            }
-            filterComboBox.ItemsSource = filterItems;
-        }
+       
     }
 
-    public class JobRequisitionReviewGrid : DynamicDataGrid<JobRequisitionItem>
-    {
-        List<Guid> filterProductIDs = new List<Guid>();
-        Guid empID = new Guid();
-        string empName = "";
-        bool bIncludeArchived = false;
-        bool bViewCancelled = false;
-
-        public JobRequisitionReviewGrid()
-        {
-            Options.AddRange(
-            DynamicGridOption.FilterRows,
-            DynamicGridOption.SelectColumns,
-            DynamicGridOption.RecordCount,
-            DynamicGridOption.MultiSelect
-            );
-            HiddenColumns.Add(x => x.ID);
-            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.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.PurchaseOrderItem.PurchaseOrderLink.ID);
-            HiddenColumns.Add(x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber);
-            HiddenColumns.Add(x => x.PurchaseOrderItem.DueDate);
-            HiddenColumns.Add(x => x.Job.ID);
-            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);
-
-            if (Security.CanEdit<JobRequisitionItem>())
-                ActionColumns.Add(new DynamicMenuColumn(BuildMenu, EmptyReturnFunction));
-            if (Security.CanEdit<PurchaseOrder>())
-                AddButton("Create Purchase Order", null, CreatePurchaseOrder);
-            if (Security.CanEdit<PurchaseOrder>())
-                AddButton("Create Treatment PO", null, CreateTreatmentPO);
-
-            AddButton("Include Archived", null, ViewArchived);
-            AddButton("Include Cancelled", null, ViewCancelled);
-
-            ActionColumns.Add(new DynamicImageColumn(PRSDesktop.Resources.rack.AsBitmapImage(), null) { ToolTip = ShowStockToolTip });
-
-            ColumnsTag = "JobRequisitionReview";
-
-            CoreTable table = new Client<Employee>().Query(new Filter<Employee>(x => x.UserLink.UserID).IsEqualTo(ClientFactory.UserID), new Columns<Employee>(x => x.ID, x => x.Name));
-            if (table.Rows.Any())
-            {
-                empID = Guid.Parse(table.Rows.FirstOrDefault().Values[0].ToString());
-                empName = table.Rows.FirstOrDefault().Values[1].ToString();
-            }        
-        }
-      
-
-        private bool ViewCancelled(Button button, CoreRow[] rows)
-        {
-            if (bViewCancelled)
-            {
-                bViewCancelled = false;
-                button.Content = "Includ Cancelled";
-            }
-            else
-            {
-                bViewCancelled = true;
-                button.Content = "Exclude Cancelled";
-            }
-
-            Dispatcher.BeginInvoke(() =>
-            {
-                Refresh(true, true);
-            });
-
-            return true;
-        }
-
-        private bool ViewArchived(Button button, CoreRow[] rows)
-        {
-            if (bIncludeArchived)
-            {
-                bIncludeArchived = false;
-                button.Content = "Include Archived";
-            }
-            else
-            {
-                bIncludeArchived = true;
-                button.Content = "Exclude Archived";
-            }
-
-            Dispatcher.BeginInvoke(() =>
-            {
-                Refresh(true, true);
-            });
-
-            return true;
-        }
-
-        private FrameworkElement ShowStockToolTip(DynamicActionColumn arg1, CoreRow row)
-        {
-            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
-            var holdings = new StockHoldingToolTipGrid(item.Product.ID, item.Job.ID, item.ID, item.Requisition.Number.ToString());
-            holdings.Refresh(true, true);
-
-            Frame frame = new Frame();
-            frame.Background = new SolidColorBrush(Colors.LightYellow);
-            frame.Padding = new Thickness(10);
-            frame.BorderBrush = new SolidColorBrush(Colors.DarkGray);
-            frame.BorderThickness = new Thickness(1);
-            frame.Content = holdings;
-
-            return frame;
-        }
-
-        private bool CreateTreatmentPO(Button button, CoreRow[] rows)
-        {
-            return true;
-        }
-
-        protected override void GenerateColumns(DynamicGridColumns columns)
-        {
-            columns.Add<JobRequisitionItem, DateTime>(x => x.Created, 80, "Date", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.Requisition.Job.JobNumber, 70, "Job", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, int>(x => x.Requisition.Number, 50, "NO.", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.Product.Code, 70, "Code", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.Product.Name, 200, "Product Name", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.Style.Description, 150, "Style", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, double>(x => x.Qty, 50, "Qty", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.Dimensions.UnitSize, 50, "Size", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber, 80, "PO Number", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderItem.PONumber, 80, "PO Number", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, DateTime>(x => x.PurchaseOrderItem.DueDate, 80, "Due", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, DateTime>(x => x.PurchaseOrderItem.ReceivedDate, 80, "Received", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, JobRequisitionItemStatus>(x => x.Status, 80, "Status", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.Notes, 300, "Notes", "", Alignment.MiddleLeft);
-        }
-
-        private DynamicMenuStatus EmptyReturnFunction(CoreRow row)
-        {
-            return DynamicMenuStatus.Enabled;
-        }
-
-        #region Action Column Buttons
-        private bool CheckValidAction(JobRequisitionItem item, bool bypassReserved)
-        {
-            bool valid = true;
-            if (item.Status == JobRequisitionItemStatus.Reserved && !bypassReserved)
-            {
-                MessageBox.Show("Error. Item has already been reserved!");
-                return false;
-            }
-            else if (item.Status == JobRequisitionItemStatus.OnOrder)
-            {
-                MessageBox.Show("Error. Item is already on order!");
-                return false;
-            }
-            if (item.Status == JobRequisitionItemStatus.Received)
-            {
-                MessageBox.Show("Error. Item has already been recieved!");
-                return false;
-            }
-            return valid;
-        }
-
-        private void Reserve_Clicked(CoreRow row)
-        {
-            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
-
-            CoreTable table = new Client<StockHolding>().Query
-                (
-                new Filter<StockHolding>(x => x.Product.ID).IsEqualTo(item.Product.ID)
-                    .And(x => x.Job).NotLinkValid(),
-                new Columns<StockHolding>(x => x.Units)
-                );
-            if (table.Rows.Count == 0)
-            {
-                MessageBox.Show("No free stock found for this product.");
-                return;
-            }
-
-            double units = 0.0;
-            foreach (CoreRow corerow in table.Rows)
-            {
-                List<Object> list = corerow.Values;
-                if (list[0] == null) list[0] = 0;
-                double holdingUnits = double.Parse(list[0].ToString());
-                units = units + holdingUnits;
-            }
-
-
-            if (item.Qty > units)
-            {
-                var result = MessageBox.Show("Current free stock for this product is " + units + ". Amount required for this requisition line is " + item.Qty +
-                ". Do you want to split this requisition line?", "Alert", MessageBoxButton.YesNo);
-                switch (result)
-                {
-                    case MessageBoxResult.Yes:
-                        SplitLine(item, units, item.Qty - units, "line split due to insufficient stock holdings");
-                        return;
-                    case MessageBoxResult.No:
-                        break;
-                    default:
-                        return;
-                }
-            }
-            Dispatcher.BeginInvoke(() =>
-            {
-                JobRequisitionReserveWindow window = new JobRequisitionReserveWindow();
-                JobRequisitionItemStockHoldingReserverGrid holdings = new JobRequisitionItemStockHoldingReserverGrid
-                (
-                    item.Product.ID, item.Requisition.Job.ID, item.ID, item.Requisition.Job.JobNumber + " (" + item.Requisition.Number + ")"
-                );
-                holdings.Refresh(true, true);
-                window.grid.Children.Add(holdings);
-                window.SizeToContent = SizeToContent.WidthAndHeight;
-
-                window.ShowDialog();
-                if (holdings.StockReserved || window.StockReserved)
-                    SaveRow(row, JobRequisitionItemStatus.Reserved, "Line marked reserved by " + empName + " on " + DateTime.Now.ToString("dd MMM yy"));
-            });
-
-        }
-
-        private void SplitLine(JobRequisitionItem item, double oldItemQty, double newItemQty, string notes)
-        {
-            List<JobRequisitionItem> items = new List<JobRequisitionItem>();
-            JobRequisitionItem newItem = new JobRequisitionItem();
-            newItem.Requisition.ID = item.Requisition.ID;
-            newItem.Requisition.Job.ID = item.Requisition.Job.ID;
-            newItem.Requisition.Job.JobNumber = item.Requisition.Job.JobNumber;
-            newItem.Requisition.Job.Name = item.Requisition.Job.Name;
-            newItem.Product.ID = item.Product.ID;
-            newItem.Product.Name = item.Product.Name;
-            newItem.Product.Code = item.Product.Code;
-            newItem.Product.Group.ID = item.Product.Group.ID;
-            newItem.Product.Group.Description = item.Product.Group.Description;
-            newItem.Dimensions.CopyFrom(item.Dimensions);
-            newItem.Style.ID = item.Style.ID;
-            newItem.Style.Description = item.Style.Description;
-            newItem.Style.Code = item.Style.Code;
-            newItem.Notes = item.Notes + Environment.NewLine + notes;
-            item.Notes = newItem.Notes;
-
-            item.Qty = oldItemQty;
-            newItem.Qty = newItemQty;
-
-            items.Add(newItem);
-            items.Add(item);
-            new Client<JobRequisitionItem>().Save(items, "Split lines from Job Requi Item Review Dashboard");
-            MessageBox.Show("Line split - original line Qty is now " + item.Qty + ". New line Qty is " + newItem.Qty, "Success");
-            Dispatcher.BeginInvoke(() =>
-            {
-                Refresh(true, true);
-            });
-        }
-
-        private void SplitLine_Clicked(CoreRow row)
-        {
-            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
-            if (CheckValidAction(item, false))
-            {
-                int units = Convert.ToInt32(item.Qty);
-                if (NumberEdit.Execute("Enter amount to split", 1, units, ref units))
-                {
-                    SplitLine(item, item.Qty - units, units, "Line split");
-                }
-            }
-        }
-
-        private void Archive_Clicked(CoreRow row)
-        {
-            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
-
-            SaveRow(row, JobRequisitionItemStatus.Archived, "Line marked as Archived by " + empName + " on " + DateTime.Now.ToString("dd MMM yy"));
-        }
-
-        private void OrderRequired_Clicked(CoreRow row)
-        {
-            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
-            if (CheckValidAction(item, false))
-                SaveRow(row, JobRequisitionItemStatus.OrderRequired, "Line marked as Order Required by " + empName + " on " + DateTime.Now.ToString("dd MMM yy"));
-        }
 
-        private void TreatmentRequired_Clicked(CoreRow row)
-        {
-            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
-            if (item.Status != JobRequisitionItemStatus.Reserved)
-            {
-                MessageBox.Show("Stock must first be reserved for this item");
-                return;
-            }
-            SaveRow(row, JobRequisitionItemStatus.TreatmentRequired, "Line marked as Treatment Required by " + empName + " on " + DateTime.Now.ToString("dd MMM yy"));
-        }
-
-        private void Uncheck_Clicked(CoreRow row)
-        {
-            string extraMessage = "";
-            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
-            if (!CheckValidAction(item, true))
-                return;
-            CoreTable table = new Client<StockMovement>().Query
-                (
-                new Filter<StockMovement>(x => x.JobRequisitionItem.ID).IsEqualTo(item.ID),
-                new Columns<StockMovement>(x => x.ID)
-                );
-            if (table.Rows.Any())
-            {
-                var result = MessageBox.Show("This will reverse stock movements already created for this Requisition Item. Proceed?", "Alert", MessageBoxButton.YesNo);
-                switch (result)
-                {
-                    case MessageBoxResult.Yes:
-                        break;
-                    case MessageBoxResult.No:
-                        return;
-                    default:
-                        return;
-                }
-                List<StockMovement> movements = new List<StockMovement>();
-                foreach (CoreRow stockmovementRow in table.Rows)
-                {
-                    StockMovement movement = new StockMovement();
-                    movement.ID = Guid.Parse(stockmovementRow.Values[0].ToString());
-                    movements.Add(movement);
-                }
-                new Client<StockMovement>().Delete(movements, "Stock movements reversed from Job Requisition Item Review Dashboard");
-                extraMessage = " and Stock Movements Reversed ";
-            }
-            SaveRow(row, JobRequisitionItemStatus.NotChecked, "Line marked as Not Checked by " + empName + extraMessage + " on " + DateTime.Now.ToString("dd MMM yy"));
-        }
-
-        private bool CreatePurchaseOrder(Button btn, CoreRow[] rows)
-        {
-            if (!rows.Any())
-            {
-                MessageBox.Show("Please select at least one row to add to Purchase Order!");
-                return false;
-            }
-
-            PurchaseOrder purchaseOrder = new PurchaseOrder();
-            purchaseOrder.Notes = "Created from Job Requi Item Review Screen" + System.Environment.NewLine;
-            purchaseOrder.RaisedBy.ID = empID;
-            var page = new SupplierPurchaseOrders();
-            page.OnAfterSave += (form, items) =>
-            {
-                PurchaseOrderOnSave(form, items.Cast<PurchaseOrder>().ToArray());
-            };
-            return page.EditItems(new[] { purchaseOrder }, LoadPurchaseOrderItems, true);
-        }
 
-        private void PurchaseOrderOnSave(IDynamicEditorForm form, PurchaseOrder[] items)
-        {
-            Progress.Show("Working");
-
-            Guid POID = items[0].ID;
-
-            CoreTable table = new Client<PurchaseOrderItem>().Query(new Filter<PurchaseOrderItem>(x => x.PurchaseOrderLink.ID).IsEqualTo(POID),
-                new Columns<PurchaseOrderItem>(x => x.ID, x => x.Product.ID, x => x.Qty, x => x.Dimensions.UnitSize, x => x.DueDate, x => x.Job.ID));
-            if (table.Rows.Any())
-            {
-                var poItems = AddPOItems(table, new List<PurchaseOrderItem>());
-
-                var requiItems = MatchRequiItems(poItems, new List<JobRequisitionItem>());
-
-                if (requiItems.Count > 0)
-                    SaveAndRefreshScreen(requiItems);
-            }
-            Progress.Close();
-        }
-
-        private void SaveAndRefreshScreen(List<JobRequisitionItem> requiItems)
-        {
-            new Client<JobRequisitionItem>().Save(requiItems, "Updated on Create Purchase Order from Job Requi Dashboard");
-            Dispatcher.BeginInvoke(() =>
-            {
-                Refresh(false, true);
-            });
-        }
-
-        private List<PurchaseOrderItem> AddPOItems(CoreTable table, List<PurchaseOrderItem> poItems)
-        {
-            foreach (CoreRow row in table.Rows)
-            {
-                PurchaseOrderItem poItem = row.ToObject<PurchaseOrderItem>();
-                poItems.Add(poItem);
-            }
-            return poItems;
-        }
-
-        private List<JobRequisitionItem> MatchRequiItems(List<PurchaseOrderItem> poItems, List<JobRequisitionItem> requiItems)
-        {
-            foreach (CoreRow row in SelectedRows)
-            {
-                JobRequisitionItem JobReqItem = row.ToObject<JobRequisitionItem>();
-                foreach (var item in poItems)
-                {
-                    if (string.IsNullOrWhiteSpace(JobReqItem.Dimensions.UnitSize))
-                        JobReqItem.Dimensions.UnitSize = QueryUnitSize(JobReqItem.Product.ID);
-
-                    if (string.IsNullOrWhiteSpace(item.Dimensions.UnitSize))
-                        item.Dimensions.UnitSize = QueryUnitSize(item.Product.ID);
-
-                    if (JobReqItem.Job.ID == Guid.Empty)
-                        JobReqItem.Job.ID = QueryJobID(JobReqItem.Requisition.ID);
-
-                    if (item.Job.ID == Guid.Empty)
-                        item.Job.ID = QueryJobID(JobReqItem.Requisition.ID);
-
-                    if (MatchReqItemToPOItem(JobReqItem, item))
-                        requiItems.Add(UpdateJobReqItemWithPODetails(JobReqItem, item));
-                }
-            }
-            return requiItems;
-        }
-
-
-
-        private JobRequisitionItem UpdateJobReqItemWithPODetails(JobRequisitionItem JobReqItem, PurchaseOrderItem item)
-        {
-            JobReqItem.PurchaseOrderItem.ID = item.ID;
-            JobReqItem.PurchaseOrderItem.DueDate = item.DueDate;
-            JobReqItem.Status = JobRequisitionItemStatus.OnOrder;
-            JobReqItem.Notes = JobReqItem.Notes + Environment.NewLine + "Line marked as On Order by " + empName + " on " + DateTime.Now.ToString("dd MMM yy");
-            return JobReqItem;
-        }
-
-        private bool MatchReqItemToPOItem(JobRequisitionItem JobReqItem, PurchaseOrderItem item)
-        {
-            if (JobReqItem.Product.ID == item.Product.ID &&                                
-                                JobReqItem.Dimensions.UnitSize == item.Dimensions.UnitSize &&
-                                JobReqItem.Job.ID == item.Job.ID)
-                return true;
-            else
-                return false;
-        }
-
-        private string QueryUnitSize(Guid productID)
-        {
-            CoreTable table = new Client<Product>().Query(new Filter<Product>(x => x.ID).IsEqualTo(productID),
-                new Columns<Product>(x => x.Dimensions.UnitSize));
-            return table.Rows.FirstOrDefault().Get<string>("Dimensions.UnitSize");
-        }
-
-        private Guid QueryJobID(Guid iD)
-        {
-            CoreTable table = new Client<JobRequisition>().Query(new Filter<JobRequisition>(x => x.ID).IsEqualTo(iD),
-                new Columns<JobRequisition>(x => x.Job.ID));
-            return table.Rows.FirstOrDefault().Get<Guid>("Job.ID");
-        }
-
-        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)
-            {
-                JobRequisitionItem JobReqItem = row.ToObject<JobRequisitionItem>();
-                PurchaseOrderItem POItem = new PurchaseOrderItem();
-                POItem.Product.ID = JobReqItem.Product.ID;
-                POItem.Product.Code = JobReqItem.Product.Code;
-                POItem.Product.Name = JobReqItem.Product.Name;
-                POItem.Description = JobReqItem.Product.Name;
-                POItem.Qty = JobReqItem.Qty;
-                POItem.Dimensions.CopyFrom(JobReqItem.Dimensions);
-                POItem.Style.ID = JobReqItem.Style.ID;
-                POItem.Style.Code = JobReqItem.Style.Code;
-                POItem.Style.Description = JobReqItem.Style.Description;
-                POItem.Job.ID = JobReqItem.Requisition.Job.ID;
-                POItem.Dimensions.UnitSize = JobReqItem.Dimensions.UnitSize;
-                items.Add(POItem);
-            }
-            result.LoadRows(items);
-            Progress.Close();
-            return result;
-        }
-        #endregion
-
-        #region Utils
-        private void SaveRow(CoreRow row, JobRequisitionItemStatus status, string note)
-        {
-            if (row == null)
-                return;
-            var id = row.Get<JobRequisitionItem, Guid>(c => c.ID);
-            JobRequisitionItem item = Data.Rows.Where(r => r.Get<JobRequisitionItem, Guid>(c => c.ID).Equals(id)).FirstOrDefault().ToObject<JobRequisitionItem>();
-            item.Status = status;
-            item.Notes = item.Notes + Environment.NewLine + note;
-            new Client<JobRequisitionItem>().Save(item, "Updated From Job Requisition Review Dashboard");
-            Dispatcher.BeginInvoke(() =>
-            {
-                Refresh(true, true);
-            });
-        }
-
-        private void SaveItem(JobRequisitionItem item, JobRequisitionItemStatus status, string note)
-        {
-            item.Status = status;
-            item.Notes = item.Notes + Environment.NewLine + note;
-            new Client<JobRequisitionItem>().Save(item, "Updated From Job Requisition Review Dashboard");
-            Dispatcher.BeginInvoke(() =>
-            {
-                Refresh(true, true);
-            });
-        }
-
-        private void MultiSaveRows(CoreRow[] rows, JobRequisitionItemStatus status, string note)
-        {
-            List<JobRequisitionItem> items = new List<JobRequisitionItem>();
-            foreach (CoreRow row in rows)
-            {
-                var id = row.Get<JobRequisitionItem, Guid>(c => c.ID);
-                JobRequisitionItem item = Data.Rows.Where(r => r.Get<JobRequisitionItem, Guid>(c => c.ID).Equals(id)).FirstOrDefault().ToObject<JobRequisitionItem>();
-                item.Status = status;
-                item.Notes = item.Notes + Environment.NewLine + note;
-                items.Add(item);
-            }
-            new Client<JobRequisitionItem>().Save(items, "Updated From Job Requisition Review Dashboard");
-            Dispatcher.BeginInvoke(() =>
-            {
-                Refresh(true, true);
-            });
-        }
-
-
-        protected override void Reload(Filters<JobRequisitionItem> criteria, Columns<JobRequisitionItem> columns, ref SortOrder<JobRequisitionItem> sort,
-            Action<CoreTable, Exception> action)
-        {
-            criteria.Add(new Filter<JobRequisitionItem>(x => x.Requisition.Approved).IsNotEqualTo(DateTime.MinValue));
-
-            if (!bViewCancelled)
-                criteria.Add(new Filter<JobRequisitionItem>(x => x.Status).IsNotEqualTo(JobRequisitionItemStatus.Cancelled));
-
-            if (!bIncludeArchived)
-                criteria.Add(new Filter<JobRequisitionItem>(x => x.Status).IsNotEqualTo(JobRequisitionItemStatus.Archived));
-
-            if (filterProductIDs.Count > 0)
-            {
-                Filter<JobRequisitionItem> filter = new Filter<JobRequisitionItem>(x => x.Product.ID).IsEqualTo(filterProductIDs.FirstOrDefault());
-                foreach (Guid id in filterProductIDs)
-                {
-                    if (id != filterProductIDs[0])
-                        filter = filter.Or(x => x.Product.ID).IsEqualTo(id);
-                }
-                criteria.Add(filter);
-            }
-            sort = new SortOrder<JobRequisitionItem>(x => x.Requisition.Number, SortDirection.Descending);
-            base.Reload(criteria, columns, ref sort, action);
-        }
-
-        public void RefreshOnFilterChanged(Guid id)
-        {
-            filterProductIDs.Clear();
-            if (id != Guid.Empty)
-            {
-                CoreTable table = new Client<SupplierProduct>().Query(
-                    new Filter<SupplierProduct>(x => x.SupplierLink.ID).IsEqualTo(id)
-                        .And(x => x.Product).LinkValid(),
-                    new Columns<SupplierProduct>(x => x.Product.ID));
-                if (table.Rows.Any())
-                {
-                    foreach (CoreRow row in table.Rows)
-                    {
-                        filterProductIDs.Add(Guid.Parse(row.Values[0].ToString()));
-                    }
-                }
-            }
-            Dispatcher.BeginInvoke(() =>
-            {
-                Refresh(true, true);
-            });
-        }
-
-        private void BuildMenu(DynamicMenuColumn column, CoreRow row)
-        {
-            column.AddItem("Reserve", PRSDesktop.Resources.project, Reserve_Clicked);
-            column.AddItem("Treatment Required", PRSDesktop.Resources.palette, TreatmentRequired_Clicked);
-            column.AddItem("Order Required", PRSDesktop.Resources.purchase, OrderRequired_Clicked);
-            column.AddItem("Mark as Not Checked", PRSDesktop.Resources.disabled, Uncheck_Clicked);
-            column.AddItem("Split Line", PRSDesktop.Resources.split, SplitLine_Clicked);
-            column.AddItem("Archive", PRSDesktop.Resources.archive, Archive_Clicked);
-        }
-
-
-        #endregion
-
-
-
-
-    }
-
-    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 = "";
-        }
-    }
+    
 }

+ 633 - 0
prs.desktop/JobRequisitionReviewGrid.cs

@@ -0,0 +1,633 @@
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Core;
+using InABox.DynamicGrid;
+using InABox.WPF;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+
+namespace PRSDesktop
+{
+    public class JobRequisitionReviewGrid : DynamicDataGrid<JobRequisitionItem>
+    {
+        List<Guid> filterProductIDs = new List<Guid>();
+        Guid empID = new Guid();
+        string empName = "";
+        bool bIncludeArchived = false;
+        bool bViewCancelled = false;
+
+        public JobRequisitionReviewGrid()
+        {
+            Options.AddRange(
+            DynamicGridOption.FilterRows,
+            DynamicGridOption.SelectColumns,
+            DynamicGridOption.RecordCount,
+            DynamicGridOption.MultiSelect
+            );
+            HiddenColumns.Add(x => x.ID);
+            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.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.PurchaseOrderItem.PurchaseOrderLink.ID);
+            HiddenColumns.Add(x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber);
+            HiddenColumns.Add(x => x.PurchaseOrderItem.DueDate);
+            HiddenColumns.Add(x => x.Job.ID);
+            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);
+
+            if (Security.CanEdit<JobRequisitionItem>())
+                ActionColumns.Add(new DynamicMenuColumn(BuildMenu, EmptyReturnFunction));
+            if (Security.CanEdit<PurchaseOrder>())
+                AddButton("Create Purchase Order", null, CreatePurchaseOrder);
+            if (Security.CanEdit<PurchaseOrder>())
+                AddButton("Create Treatment PO", null, CreateTreatmentPO);
+
+            AddButton("Include Archived", null, ViewArchived);
+            AddButton("Include Cancelled", null, ViewCancelled);
+
+            ActionColumns.Add(new DynamicImageColumn(PRSDesktop.Resources.rack.AsBitmapImage(), null) { ToolTip = ShowStockToolTip });
+
+            ColumnsTag = "JobRequisitionReview";
+
+            CoreTable table = new Client<Employee>().Query(new Filter<Employee>(x => x.UserLink.UserID).IsEqualTo(ClientFactory.UserID), new Columns<Employee>(x => x.ID, x => x.Name));
+            if (table.Rows.Any())
+            {
+                empID = Guid.Parse(table.Rows.FirstOrDefault().Values[0].ToString());
+                empName = table.Rows.FirstOrDefault().Values[1].ToString();
+            }
+        }
+
+
+        private bool ViewCancelled(Button button, CoreRow[] rows)
+        {
+            if (bViewCancelled)
+            {
+                bViewCancelled = false;
+                button.Content = "Includ Cancelled";
+            }
+            else
+            {
+                bViewCancelled = true;
+                button.Content = "Exclude Cancelled";
+            }
+
+            Dispatcher.BeginInvoke(() =>
+            {
+                Refresh(true, true);
+            });
+
+            return true;
+        }
+
+        private bool ViewArchived(Button button, CoreRow[] rows)
+        {
+            if (bIncludeArchived)
+            {
+                bIncludeArchived = false;
+                button.Content = "Include Archived";
+            }
+            else
+            {
+                bIncludeArchived = true;
+                button.Content = "Exclude Archived";
+            }
+
+            Dispatcher.BeginInvoke(() =>
+            {
+                Refresh(true, true);
+            });
+
+            return true;
+        }
+
+        private FrameworkElement ShowStockToolTip(DynamicActionColumn arg1, CoreRow row)
+        {
+            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
+            var holdings = new StockHoldingToolTipGrid(item.Product.ID, item.Job.ID, item.ID, item.Requisition.Number.ToString());
+            holdings.Refresh(true, true);
+
+            Frame frame = new Frame();
+            frame.Background = new SolidColorBrush(Colors.LightYellow);
+            frame.Padding = new Thickness(10);
+            frame.BorderBrush = new SolidColorBrush(Colors.DarkGray);
+            frame.BorderThickness = new Thickness(1);
+            frame.Content = holdings;
+
+            return frame;
+        }
+
+        private bool CreateTreatmentPO(Button button, CoreRow[] rows)
+        {
+            return true;
+        }
+
+        protected override void GenerateColumns(DynamicGridColumns columns)
+        {
+            columns.Add<JobRequisitionItem, DateTime>(x => x.Created, 80, "Date", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, string>(x => x.Requisition.Job.JobNumber, 70, "Job", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, int>(x => x.Requisition.Number, 50, "NO.", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, string>(x => x.Product.Code, 70, "Code", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, string>(x => x.Product.Name, 200, "Product Name", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, string>(x => x.Style.Description, 150, "Style", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, double>(x => x.Qty, 50, "Qty", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, string>(x => x.Dimensions.UnitSize, 50, "Size", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber, 80, "PO Number", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderItem.PONumber, 80, "PO Number", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, DateTime>(x => x.PurchaseOrderItem.DueDate, 80, "Due", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, DateTime>(x => x.PurchaseOrderItem.ReceivedDate, 80, "Received", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, JobRequisitionItemStatus>(x => x.Status, 80, "Status", "", Alignment.MiddleLeft);
+            columns.Add<JobRequisitionItem, string>(x => x.Notes, 300, "Notes", "", Alignment.MiddleLeft);
+        }
+
+        private DynamicMenuStatus EmptyReturnFunction(CoreRow row)
+        {
+            return DynamicMenuStatus.Enabled;
+        }
+
+        #region Action Column Buttons
+        private bool CheckValidAction(JobRequisitionItem item, bool bypassReserved)
+        {
+            bool valid = true;
+            if (item.Status == JobRequisitionItemStatus.Reserved && !bypassReserved)
+            {
+                MessageBox.Show("Error. Item has already been reserved!");
+                return false;
+            }
+            else if (item.Status == JobRequisitionItemStatus.OnOrder)
+            {
+                MessageBox.Show("Error. Item is already on order!");
+                return false;
+            }
+            if (item.Status == JobRequisitionItemStatus.Received)
+            {
+                MessageBox.Show("Error. Item has already been recieved!");
+                return false;
+            }
+            return valid;
+        }
+
+        private void Reserve_Clicked(CoreRow row)
+        {
+            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
+
+            CoreTable table = new Client<StockHolding>().Query
+                (
+                new Filter<StockHolding>(x => x.Product.ID).IsEqualTo(item.Product.ID)
+                    .And(x => x.Job).NotLinkValid(),
+                new Columns<StockHolding>(x => x.Units)
+                );
+            if (table.Rows.Count == 0)
+            {
+                MessageBox.Show("No free stock found for this product.");
+                return;
+            }
+
+            double units = 0.0;
+            foreach (CoreRow corerow in table.Rows)
+            {
+                List<Object> list = corerow.Values;
+                if (list[0] == null) list[0] = 0;
+                double holdingUnits = double.Parse(list[0].ToString());
+                units = units + holdingUnits;
+            }
+
+
+            if (item.Qty > units)
+            {
+                var result = MessageBox.Show("Current free stock for this product is " + units + ". Amount required for this requisition line is " + item.Qty +
+                ". Do you want to split this requisition line?", "Alert", MessageBoxButton.YesNo);
+                switch (result)
+                {
+                    case MessageBoxResult.Yes:
+                        SplitLine(item, units, item.Qty - units, "line split due to insufficient stock holdings");
+                        return;
+                    case MessageBoxResult.No:
+                        break;
+                    default:
+                        return;
+                }
+            }
+            Dispatcher.BeginInvoke(() =>
+            {
+                JobRequisitionReserveWindow window = new JobRequisitionReserveWindow();
+                JobRequisitionItemStockHoldingReserverGrid holdings = new JobRequisitionItemStockHoldingReserverGrid
+                (
+                    item.Product.ID, item.Requisition.Job.ID, item.ID, item.Requisition.Job.JobNumber + " (" + item.Requisition.Number + ")"
+                );
+                holdings.Refresh(true, true);
+                window.grid.Children.Add(holdings);
+                window.SizeToContent = SizeToContent.WidthAndHeight;
+
+                window.ShowDialog();
+                if (holdings.StockReserved || window.StockReserved)
+                    SaveRow(row, JobRequisitionItemStatus.Reserved, "Line marked reserved by " + empName + " on " + DateTime.Now.ToString("dd MMM yy"));
+            });
+
+        }
+
+        private void SplitLine(JobRequisitionItem item, double oldItemQty, double newItemQty, string notes)
+        {
+            List<JobRequisitionItem> items = new List<JobRequisitionItem>();
+            JobRequisitionItem newItem = new JobRequisitionItem();
+            newItem.Requisition.ID = item.Requisition.ID;
+            newItem.Requisition.Job.ID = item.Requisition.Job.ID;
+            newItem.Requisition.Job.JobNumber = item.Requisition.Job.JobNumber;
+            newItem.Requisition.Job.Name = item.Requisition.Job.Name;
+            newItem.Product.ID = item.Product.ID;
+            newItem.Product.Name = item.Product.Name;
+            newItem.Product.Code = item.Product.Code;
+            newItem.Product.Group.ID = item.Product.Group.ID;
+            newItem.Product.Group.Description = item.Product.Group.Description;
+            newItem.Dimensions.CopyFrom(item.Dimensions);
+            newItem.Style.ID = item.Style.ID;
+            newItem.Style.Description = item.Style.Description;
+            newItem.Style.Code = item.Style.Code;
+            newItem.Notes = item.Notes + Environment.NewLine + notes;
+            item.Notes = newItem.Notes;
+
+            item.Qty = oldItemQty;
+            newItem.Qty = newItemQty;
+
+            items.Add(newItem);
+            items.Add(item);
+            new Client<JobRequisitionItem>().Save(items, "Split lines from Job Requi Item Review Dashboard");
+            MessageBox.Show("Line split - original line Qty is now " + item.Qty + ". New line Qty is " + newItem.Qty, "Success");
+            Dispatcher.BeginInvoke(() =>
+            {
+                Refresh(true, true);
+            });
+        }
+
+        private void SplitLine_Clicked(CoreRow row)
+        {
+            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
+            if (CheckValidAction(item, false))
+            {
+                int units = Convert.ToInt32(item.Qty);
+                if (NumberEdit.Execute("Enter amount to split", 1, units, ref units))
+                {
+                    SplitLine(item, item.Qty - units, units, "Line split");
+                }
+            }
+        }
+
+        private void Archive_Clicked(CoreRow row)
+        {
+            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
+
+            SaveRow(row, JobRequisitionItemStatus.Archived, "Line marked as Archived by " + empName + " on " + DateTime.Now.ToString("dd MMM yy"));
+        }
+
+        private void OrderRequired_Clicked(CoreRow row)
+        {
+            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
+            if (CheckValidAction(item, false))
+                SaveRow(row, JobRequisitionItemStatus.OrderRequired, "Line marked as Order Required by " + empName + " on " + DateTime.Now.ToString("dd MMM yy"));
+        }
+
+        private void TreatmentRequired_Clicked(CoreRow row)
+        {
+            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
+            if (item.Status != JobRequisitionItemStatus.Reserved)
+            {
+                MessageBox.Show("Stock must first be reserved for this item");
+                return;
+            }
+            SaveRow(row, JobRequisitionItemStatus.TreatmentRequired, "Line marked as Treatment Required by " + empName + " on " + DateTime.Now.ToString("dd MMM yy"));
+        }
+
+        private void Uncheck_Clicked(CoreRow row)
+        {
+            string extraMessage = "";
+            JobRequisitionItem item = row.ToObject<JobRequisitionItem>();
+            if (!CheckValidAction(item, true))
+                return;
+            CoreTable table = new Client<StockMovement>().Query
+                (
+                new Filter<StockMovement>(x => x.JobRequisitionItem.ID).IsEqualTo(item.ID),
+                new Columns<StockMovement>(x => x.ID)
+                );
+            if (table.Rows.Any())
+            {
+                var result = MessageBox.Show("This will reverse stock movements already created for this Requisition Item. Proceed?", "Alert", MessageBoxButton.YesNo);
+                switch (result)
+                {
+                    case MessageBoxResult.Yes:
+                        break;
+                    case MessageBoxResult.No:
+                        return;
+                    default:
+                        return;
+                }
+                List<StockMovement> movements = new List<StockMovement>();
+                foreach (CoreRow stockmovementRow in table.Rows)
+                {
+                    StockMovement movement = new StockMovement();
+                    movement.ID = Guid.Parse(stockmovementRow.Values[0].ToString());
+                    movements.Add(movement);
+                }
+                new Client<StockMovement>().Delete(movements, "Stock movements reversed from Job Requisition Item Review Dashboard");
+                extraMessage = " and Stock Movements Reversed ";
+            }
+            SaveRow(row, JobRequisitionItemStatus.NotChecked, "Line marked as Not Checked by " + empName + extraMessage + " on " + DateTime.Now.ToString("dd MMM yy"));
+        }
+
+        private bool CreatePurchaseOrder(Button btn, CoreRow[] rows)
+        {
+            if (!rows.Any())
+            {
+                MessageBox.Show("Please select at least one row to add to Purchase Order!");
+                return false;
+            }
+
+            PurchaseOrder purchaseOrder = new PurchaseOrder();
+            purchaseOrder.Notes = "Created from Job Requi Item Review Screen" + System.Environment.NewLine;
+            purchaseOrder.RaisedBy.ID = empID;
+            var page = new SupplierPurchaseOrders();
+            page.OnAfterSave += (form, items) =>
+            {
+                PurchaseOrderOnSave(form, items.Cast<PurchaseOrder>().ToArray());
+            };
+            return page.EditItems(new[] { purchaseOrder }, LoadPurchaseOrderItems, true);
+        }
+
+        private void PurchaseOrderOnSave(IDynamicEditorForm form, PurchaseOrder[] items)
+        {
+            Progress.Show("Working");
+
+            Guid POID = items[0].ID;
+
+            CoreTable table = new Client<PurchaseOrderItem>().Query(new Filter<PurchaseOrderItem>(x => x.PurchaseOrderLink.ID).IsEqualTo(POID),
+                new Columns<PurchaseOrderItem>(x => x.ID, x => x.Product.ID, x => x.Qty, x => x.Dimensions.UnitSize, x => x.DueDate, x => x.Job.ID));
+            if (table.Rows.Any())
+            {
+                var poItems = AddPOItems(table, new List<PurchaseOrderItem>());
+
+                var requiItems = MatchRequiItems(poItems, new List<JobRequisitionItem>());
+
+                if (requiItems.Count > 0)
+                    SaveAndRefreshScreen(requiItems);
+            }
+            Progress.Close();
+        }
+
+        private void SaveAndRefreshScreen(List<JobRequisitionItem> requiItems)
+        {
+            new Client<JobRequisitionItem>().Save(requiItems, "Updated on Create Purchase Order from Job Requi Dashboard");
+            Dispatcher.BeginInvoke(() =>
+            {
+                Refresh(false, true);
+            });
+        }
+
+        private List<PurchaseOrderItem> AddPOItems(CoreTable table, List<PurchaseOrderItem> poItems)
+        {
+            foreach (CoreRow row in table.Rows)
+            {
+                PurchaseOrderItem poItem = row.ToObject<PurchaseOrderItem>();
+                poItems.Add(poItem);
+            }
+            return poItems;
+        }
+
+        private List<JobRequisitionItem> MatchRequiItems(List<PurchaseOrderItem> poItems, List<JobRequisitionItem> requiItems)
+        {
+            foreach (CoreRow row in SelectedRows)
+            {
+                JobRequisitionItem JobReqItem = row.ToObject<JobRequisitionItem>();
+                foreach (var item in poItems)
+                {
+                    if (string.IsNullOrWhiteSpace(JobReqItem.Dimensions.UnitSize))
+                        JobReqItem.Dimensions.UnitSize = QueryUnitSize(JobReqItem.Product.ID);
+
+                    if (string.IsNullOrWhiteSpace(item.Dimensions.UnitSize))
+                        item.Dimensions.UnitSize = QueryUnitSize(item.Product.ID);
+
+                    if (JobReqItem.Job.ID == Guid.Empty)
+                        JobReqItem.Job.ID = QueryJobID(JobReqItem.Requisition.ID);
+
+                    if (item.Job.ID == Guid.Empty)
+                        item.Job.ID = QueryJobID(JobReqItem.Requisition.ID);
+
+                    if (MatchReqItemToPOItem(JobReqItem, item))
+                        requiItems.Add(UpdateJobReqItemWithPODetails(JobReqItem, item));
+                }
+            }
+            return requiItems;
+        }
+
+
+
+        private JobRequisitionItem UpdateJobReqItemWithPODetails(JobRequisitionItem JobReqItem, PurchaseOrderItem item)
+        {
+            JobReqItem.PurchaseOrderItem.ID = item.ID;
+            JobReqItem.PurchaseOrderItem.DueDate = item.DueDate;
+            JobReqItem.Status = JobRequisitionItemStatus.OnOrder;
+            JobReqItem.Notes = JobReqItem.Notes + Environment.NewLine + "Line marked as On Order by " + empName + " on " + DateTime.Now.ToString("dd MMM yy");
+            return JobReqItem;
+        }
+
+        private bool MatchReqItemToPOItem(JobRequisitionItem JobReqItem, PurchaseOrderItem item)
+        {
+            if (JobReqItem.Product.ID == item.Product.ID &&
+                                JobReqItem.Dimensions.UnitSize == item.Dimensions.UnitSize &&
+                                JobReqItem.Job.ID == item.Job.ID)
+                return true;
+            else
+                return false;
+        }
+
+        private string QueryUnitSize(Guid productID)
+        {
+            CoreTable table = new Client<Product>().Query(new Filter<Product>(x => x.ID).IsEqualTo(productID),
+                new Columns<Product>(x => x.Dimensions.UnitSize));
+            return table.Rows.FirstOrDefault().Get<string>("Dimensions.UnitSize");
+        }
+
+        private Guid QueryJobID(Guid iD)
+        {
+            CoreTable table = new Client<JobRequisition>().Query(new Filter<JobRequisition>(x => x.ID).IsEqualTo(iD),
+                new Columns<JobRequisition>(x => x.Job.ID));
+            return table.Rows.FirstOrDefault().Get<Guid>("Job.ID");
+        }
+
+        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)
+            {
+                JobRequisitionItem JobReqItem = row.ToObject<JobRequisitionItem>();
+                PurchaseOrderItem POItem = new PurchaseOrderItem();
+                POItem.Product.ID = JobReqItem.Product.ID;
+                POItem.Product.Code = JobReqItem.Product.Code;
+                POItem.Product.Name = JobReqItem.Product.Name;
+                POItem.Description = JobReqItem.Product.Name;
+                POItem.Qty = JobReqItem.Qty;
+                POItem.Dimensions.CopyFrom(JobReqItem.Dimensions);
+                POItem.Style.ID = JobReqItem.Style.ID;
+                POItem.Style.Code = JobReqItem.Style.Code;
+                POItem.Style.Description = JobReqItem.Style.Description;
+                POItem.Job.ID = JobReqItem.Requisition.Job.ID;
+                POItem.Dimensions.UnitSize = JobReqItem.Dimensions.UnitSize;
+                items.Add(POItem);
+            }
+            result.LoadRows(items);
+            Progress.Close();
+            return result;
+        }
+        #endregion
+
+        #region Utils
+        private void SaveRow(CoreRow row, JobRequisitionItemStatus status, string note)
+        {
+            if (row == null)
+                return;
+            var id = row.Get<JobRequisitionItem, Guid>(c => c.ID);
+            JobRequisitionItem item = Data.Rows.Where(r => r.Get<JobRequisitionItem, Guid>(c => c.ID).Equals(id)).FirstOrDefault().ToObject<JobRequisitionItem>();
+            item.Status = status;
+            item.Notes = item.Notes + Environment.NewLine + note;
+            new Client<JobRequisitionItem>().Save(item, "Updated From Job Requisition Review Dashboard");
+            Dispatcher.BeginInvoke(() =>
+            {
+                Refresh(true, true);
+            });
+        }
+
+        private void SaveItem(JobRequisitionItem item, JobRequisitionItemStatus status, string note)
+        {
+            item.Status = status;
+            item.Notes = item.Notes + Environment.NewLine + note;
+            new Client<JobRequisitionItem>().Save(item, "Updated From Job Requisition Review Dashboard");
+            Dispatcher.BeginInvoke(() =>
+            {
+                Refresh(true, true);
+            });
+        }
+
+        private void MultiSaveRows(CoreRow[] rows, JobRequisitionItemStatus status, string note)
+        {
+            List<JobRequisitionItem> items = new List<JobRequisitionItem>();
+            foreach (CoreRow row in rows)
+            {
+                var id = row.Get<JobRequisitionItem, Guid>(c => c.ID);
+                JobRequisitionItem item = Data.Rows.Where(r => r.Get<JobRequisitionItem, Guid>(c => c.ID).Equals(id)).FirstOrDefault().ToObject<JobRequisitionItem>();
+                item.Status = status;
+                item.Notes = item.Notes + Environment.NewLine + note;
+                items.Add(item);
+            }
+            new Client<JobRequisitionItem>().Save(items, "Updated From Job Requisition Review Dashboard");
+            Dispatcher.BeginInvoke(() =>
+            {
+                Refresh(true, true);
+            });
+        }
+
+
+        protected override void Reload(Filters<JobRequisitionItem> criteria, Columns<JobRequisitionItem> columns, ref SortOrder<JobRequisitionItem> sort,
+            Action<CoreTable, Exception> action)
+        {
+            criteria.Add(new Filter<JobRequisitionItem>(x => x.Requisition.Approved).IsNotEqualTo(DateTime.MinValue));
+
+            if (!bViewCancelled)
+                criteria.Add(new Filter<JobRequisitionItem>(x => x.Status).IsNotEqualTo(JobRequisitionItemStatus.Cancelled));
+
+            if (!bIncludeArchived)
+                criteria.Add(new Filter<JobRequisitionItem>(x => x.Status).IsNotEqualTo(JobRequisitionItemStatus.Archived));
+
+            if (filterProductIDs.Count > 0)
+            {
+                Filter<JobRequisitionItem> filter = new Filter<JobRequisitionItem>(x => x.Product.ID).IsEqualTo(filterProductIDs.FirstOrDefault());
+                foreach (Guid id in filterProductIDs)
+                {
+                    if (id != filterProductIDs[0])
+                        filter = filter.Or(x => x.Product.ID).IsEqualTo(id);
+                }
+                criteria.Add(filter);
+            }
+            sort = new SortOrder<JobRequisitionItem>(x => x.Requisition.Number, SortDirection.Descending);
+            base.Reload(criteria, columns, ref sort, action);
+        }
+
+        public void RefreshOnFilterChanged(Guid id)
+        {
+            filterProductIDs.Clear();
+            if (id != Guid.Empty)
+            {
+                CoreTable table = new Client<SupplierProduct>().Query(
+                    new Filter<SupplierProduct>(x => x.SupplierLink.ID).IsEqualTo(id)
+                        .And(x => x.Product).LinkValid(),
+                    new Columns<SupplierProduct>(x => x.Product.ID));
+                if (table.Rows.Any())
+                {
+                    foreach (CoreRow row in table.Rows)
+                    {
+                        filterProductIDs.Add(Guid.Parse(row.Values[0].ToString()));
+                    }
+                }
+            }
+            Dispatcher.BeginInvoke(() =>
+            {
+                Refresh(true, true);
+            });
+        }
+
+        private void BuildMenu(DynamicMenuColumn column, CoreRow row)
+        {
+            column.AddItem("Reserve", PRSDesktop.Resources.project, Reserve_Clicked);
+            column.AddItem("Treatment Required", PRSDesktop.Resources.palette, TreatmentRequired_Clicked);
+            column.AddItem("Order Required", PRSDesktop.Resources.purchase, OrderRequired_Clicked);
+            column.AddItem("Mark as Not Checked", PRSDesktop.Resources.disabled, Uncheck_Clicked);
+            column.AddItem("Split Line", PRSDesktop.Resources.split, SplitLine_Clicked);
+            column.AddItem("Archive", PRSDesktop.Resources.archive, Archive_Clicked);
+        }
+        #endregion
+    }
+
+    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 = "";
+        }
+    }
+}

+ 2 - 0
prs.desktop/Panels/Consignments/ConsignmentItemGrid.cs

@@ -24,6 +24,8 @@ public class ConsignmentItemGrid : DynamicDataGrid<PurchaseOrderItem>
         receiveall.IsEnabled = false;
         receiveselected = AddButton("Receive Selected", null, ReceiveSelected);
         receiveselected.IsEnabled = false;
+
+        AddButton("Assign Location", null,  SupplierPurchaseOrderItems.AssignLocation);
     }
 
     public Guid ConsignmentID { get; set; }

+ 40 - 0
prs.desktop/Panels/Products/JobRequisitionReviewPage.xaml

@@ -0,0 +1,40 @@
+<Page x:Class="PRSDesktop.JobRequisitionReviewPage"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+      xmlns:local="clr-namespace:PRSDesktop"
+      mc:Ignorable="d" 
+      d:DesignHeight="450" d:DesignWidth="800"
+      Title="JobRequisitionReviewPage">
+
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="auto"/>
+            <RowDefinition Height="*"/>
+        </Grid.RowDefinitions>
+
+        <Grid Grid.Row="0">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="auto"/>
+                <ColumnDefinition Width="auto"/>
+            </Grid.ColumnDefinitions>
+
+            <Label Grid.Row="0" Content="Supplier: " VerticalAlignment="Center"/>
+
+            <ComboBox Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" SelectionChanged="Filter_SelectionChanged" HorizontalContentAlignment="Left"
+                      Width="300"
+                  x:Name="filterComboBox">
+                <ComboBox.ItemTemplate>
+                    <DataTemplate>
+                        <TextBlock Text="{Binding Text}"/>
+                    </DataTemplate>
+                </ComboBox.ItemTemplate>
+            </ComboBox>
+        </Grid>
+
+
+        <local:JobRequisitionReviewGrid Grid.Row="1"
+            x:Name="Grid"/>
+    </Grid>
+</Page>

+ 86 - 0
prs.desktop/Panels/Products/JobRequisitionReviewPage.xaml.cs

@@ -0,0 +1,86 @@
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace PRSDesktop
+{
+    /// <summary>
+    /// Interaction logic for JobRequisitionReviewPage.xaml
+    /// </summary>
+    public partial class JobRequisitionReviewPage : Page
+    {
+        public List<JobRequiReviewDashboardFilterItem> filterItems = new List<JobRequiReviewDashboardFilterItem>();
+        public JobRequisitionReviewPage()
+        {
+            InitializeComponent();
+            Grid.Refresh(true, true);
+        }
+
+        private void Filter_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            var item = filterComboBox.SelectedItem as JobRequiReviewDashboardFilterItem;
+            Grid.RefreshOnFilterChanged(item.SupplierID);
+        }
+
+        private void LoadFilters()
+        {
+            List<Guid> productIDs = new List<Guid>();
+            CoreTable productsTable = new Client<JobRequisitionItem>().Query(new Filter<JobRequisitionItem>(x => x.Product).LinkValid(),
+                new Columns<JobRequisitionItem>(x => x.Product.ID));
+            foreach (CoreRow row1 in productsTable.Rows)
+            {
+                productIDs.Add(Guid.Parse(row1.Values[0].ToString()));
+            }
+            CoreTable table = new Client<SupplierProduct>().Query(
+                new Filter<SupplierProduct>(x => x.Product).LinkValid()
+                    .And(x => x.SupplierLink).LinkValid(),
+                new Columns<SupplierProduct>(x => x.SupplierLink.ID, x => x.Product.ID, x => x.SupplierLink.Name, x => x.SupplierLink.Code));
+            if (table.Rows.Any())
+            {
+                JobRequiReviewDashboardFilterItem firstItem = new JobRequiReviewDashboardFilterItem
+                {
+                    Text = "No Filter"
+                };
+                filterItems.Add(firstItem);
+                foreach (CoreRow row in table.Rows)
+                {
+                    JobRequiReviewDashboardFilterItem filterItem = new JobRequiReviewDashboardFilterItem
+                    {
+                        SupplierID = Guid.Parse(row.Values[0].ToString()),
+                        ProductID = Guid.Parse(row.Values[1].ToString()),
+                    };
+                    if (row.Values[3] != null)
+                    {
+                        filterItem.Text = row.Values[3].ToString();
+                        if (row.Values[2] != null)
+                        {
+                            filterItem.Text = filterItem.Text + " " + row.Values[2].ToString();
+                        }
+                    }
+
+                    var founditem = filterItems.Find(x => x.SupplierID == filterItem.SupplierID);
+                    if (founditem == null)
+                    {
+                        if (productIDs.Contains(filterItem.ProductID))
+                            filterItems.Add(filterItem);
+                    }
+                }
+            }
+            filterComboBox.ItemsSource = filterItems;
+        }
+    }
+}

+ 56 - 7
prs.desktop/Panels/Suppliers/SupplierPurchaseOrderItems.cs

@@ -8,6 +8,7 @@ using Comal.Classes;
 using InABox.Clients;
 using InABox.Core;
 using InABox.DynamicGrid;
+using InABox.Wpf;
 using InABox.WPF;
 
 namespace PRSDesktop
@@ -19,7 +20,7 @@ namespace PRSDesktop
         private readonly Button? consign;
         private readonly Button receive;
         private readonly Button? viewconsign;
-        
+
         public Guid OrderID { get; set; }
         public Guid SupplierID { get; set; }
         public bool Closed { get; set; }
@@ -52,7 +53,7 @@ namespace PRSDesktop
             HiddenColumns.Add(x => x.Product.Image.ID);
             HiddenColumns.Add(x => x.Product.Image.FileName);
             ActionColumns.Add(new DynamicImageManagerColumn<PurchaseOrderItem>(this, x => x.Product.Image, true)
-                { Position = DynamicActionColumnPosition.Start });
+            { Position = DynamicActionColumnPosition.Start });
 
             HiddenColumns.Add(x => x.FormCount);
             HiddenColumns.Add(x => x.OpenForms);
@@ -73,9 +74,57 @@ namespace PRSDesktop
 
             bill = AddButton("Enter Bill", null, EnterBill);
             bill.IsEnabled = false;
+
+            AddButton("Assign Location", null, AssignLocation);
         }
 
+        public static bool AssignLocation(Button btn, CoreRow[] rows)
+        {
+            if (!rows.Any())
+            {
+                MessageBox.Show("Please select at least one row to assign");
+                return false;
+            }
+
+            if (MessageBox.Show("Create new location?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+            {
+                var grid = new StockLocationGrid();
+                var location = new StockLocation();
+                if (grid.EditItems(new StockLocation[] { location }))
+                    AssignLocationToItems(location.ID, rows);               
+            }
+            else
+            {
+                var popup = new PopupList(typeof(StockLocation), Guid.Empty, new string[] { });
 
+                if (popup.ShowDialog() == true)
+                    AssignLocationToItems(popup.ID, rows);
+               
+            }
+            return true;
+        }
+
+        private static void AssignLocationToItems(Guid locationID, CoreRow[] rows)
+        {
+            List<PurchaseOrderItem> items = new List<PurchaseOrderItem>();
+            foreach (CoreRow row in rows)
+            {
+                var item = row.ToObject<PurchaseOrderItem>();
+                item.StockLocation.ID = locationID;
+                items.Add(item);
+            }
+            new Client<PurchaseOrderItem>().Save(items, "Added stock location from PurchaseOrderItem Grid");
+        }
+
+        private StockLocation[] QueryLocations()
+        {
+            CoreTable table = new Client<StockLocation>().Query(new Filter<StockLocation>(x => x.Active).IsEqualTo(true), new Columns<StockLocation>(x => x.ID));
+            List<StockLocation> locations = new List<StockLocation>();
+            foreach (CoreRow row in table.Rows)
+                locations.Add(row.ToObject<StockLocation>());
+
+            return locations.ToArray();
+        }
 
         private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
         {
@@ -142,7 +191,7 @@ namespace PRSDesktop
                     && !rows.Any(r => Entity.IsEntityLinkValid<PurchaseOrderItem, ConsignmentLink>(x => x.Consignment, r))
                     && !rows.Any(r => r.Get<PurchaseOrderItem, DateTime>(c => c.ReceivedDate).IsEmpty() == false);
 
-                viewconsign.Visibility = 
+                viewconsign.Visibility =
                     rows == null || consign.IsEnabled || rows.Select(r => r.Get<PurchaseOrderItem, Guid>(x => x.Consignment.ID)).Distinct().Count() != 1
                         ? Visibility.Collapsed
                         : Visibility.Visible;
@@ -169,7 +218,7 @@ namespace PRSDesktop
             criteria.Add(new Filter<PurchaseOrderItem>(x => x.PurchaseOrderLink.ID).IsEqualTo(OrderID));
             base.Reload(criteria, columns, ref sort, action);
         }
-        
+
         protected override PurchaseOrderItem CreateItem()
         {
             var result = base.CreateItem();
@@ -202,7 +251,7 @@ namespace PRSDesktop
                 DynamicGridUtils.UpdateEditorValue(items, "TaxCode.ID", (Guid)value, results);
             return results;
         }
-        
+
         protected override void OnAfterEditorValueChanged(DynamicEditorGrid grid, PurchaseOrderItem[] items, String name, Dictionary<String, object?> changes)
         {
             base.OnAfterEditorValueChanged(grid, items, name, changes);
@@ -236,7 +285,7 @@ namespace PRSDesktop
         protected override bool CanCreateItems() => CheckPOStatus(() => base.CanCreateItems());
 
         protected override bool CanDeleteItems(CoreRow[] rows) => CheckPOStatus(() => base.CanDeleteItems(rows));
-        
+
         private bool CreateConsignment(Button sender, CoreRow[] rows)
         {
             if (!rows.Any())
@@ -308,7 +357,7 @@ namespace PRSDesktop
                 return LoadBillLines(type, rows);
             }, true);
         }
-        
+
         public static CoreTable LoadBillLines(Type type, CoreRow[] rows)
         {
             var result = new CoreTable();