123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Configuration;
- using InABox.Core;
- using InABox.DynamicGrid;
- using InABox.WPF;
- using Microsoft.Win32;
- using NPOI.SS.Formula.Functions;
- using NPOI.SS.UserModel;
- using NPOI.SS.Util;
- using NPOI.XSSF.UserModel;
- using org.omg.PortableInterceptor;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Windows;
- using System.Windows.Controls;
- namespace PRSDesktop
- {
- /// <summary>
- /// Interaction logic for StockTakeWindow.xaml
- /// </summary>
- public partial class StockTakeWindow : Window
- {
- #region Fields / constructor
- CoreRow[] Rows;
- List<StockTakeHolding> StockTakeHoldings = new List<StockTakeHolding>();
- List<StockHolding> OriginalHoldings = new List<StockHolding>();
- Guid EmployeeID = Guid.Empty;
- public StockTakeWindow(CoreRow[] rows)
- {
- InitializeComponent();
- Rows = rows;
- Setup();
- }
- #endregion
- #region Setup
- private void Setup()
- {
- SetupStockHoldingGrid();
- Progress.ShowModal("Loading", (progress) =>
- {
- EmployeeID = new Client<Employee>().Query(new Filter<Employee>(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid)).Rows.FirstOrDefault().Get<Employee, Guid>(x => x.ID);
- QueryList(Rows.Select(x => x.Get<StockLocation, Guid>(c => c.ID)));
- Dispatcher.Invoke(() =>
- {
- Holdings.Items = StockTakeHoldings;
- Holdings.Refresh(true, true);
- });
- });
- }
- private void SetupStockHoldingGrid()
- {
- Holdings.Reconfigure(options =>
- {
- options.Remove(DynamicGridOption.EditRows);
- options.Remove(DynamicGridOption.DeleteRows);
- options.Remove(DynamicGridOption.ImportData);
- options.Remove(DynamicGridOption.ExportData);
- options.Remove(DynamicGridOption.SelectColumns);
- options.Add(DynamicGridOption.RecordCount);
- options.Add(DynamicGridOption.AddRows);
- options.Add(DynamicGridOption.DirectEdit);
- });
- Holdings.OnCustomiseEditor += Page_OnCustomiseEditor;
- Holdings.OnValidate += Page_OnValidate;
- Holdings.OnBeforeSave += Page_OnSave;
- Holdings.AddButton("Pre-Fill Actual Qty", PRSDesktop.Resources.copy.AsBitmapImage(), FillValues);
- Holdings.AddButton("Reset Actual Qty to Zero", PRSDesktop.Resources.refresh.AsBitmapImage(), ClearValues);
- Holdings.AddButton("Export", PRSDesktop.Resources.doc_xls.AsBitmapImage(), Export);
- }
- private void QueryList(IEnumerable<Guid> ids)
- {
- CoreTable table = new Client<StockHolding>().Query(new Filter<StockHolding>(x => x.Location.ID).InList(ids.ToArray())
- .And(x => x.Dimensions.UnitSize).IsNotEqualTo(null)
- .And(x => x.Qty).IsGreaterThan(0.1),
- new Columns<StockHolding>(
- x => x.ID,
- x => x.Qty,
- x => x.Units,
- x => x.Job.ID,
- x => x.Job.JobNumber,
- x => x.Product.ID,
- x => x.Product.Code,
- x => x.Product.Name,
- x => x.Style.ID,
- x => x.Style.Code,
- x => x.Style.Description,
- x => x.Location.ID,
- x => x.Location.Code,
- x => x.Location.Description,
- x => x.Dimensions.Unit.ID,
- x => x.Dimensions.UnitSize,
- x => x.Dimensions.Unit.Format,
- x => x.Dimensions.Unit.Formula,
- x => x.Dimensions.Unit.HasLength,
- x => x.Dimensions.Unit.HasHeight,
- x => x.Dimensions.Unit.HasWeight,
- x => x.Dimensions.Unit.HasWidth,
- x => x.Dimensions.Unit.HasQuantity,
- x => x.Dimensions.Quantity,
- x => x.Dimensions.Length,
- x => x.Dimensions.Height,
- x => x.Dimensions.Width,
- x => x.Dimensions.Weight
- ));
- foreach (CoreRow row in table.Rows)
- {
- StockHolding holding = row.ToObject<StockHolding>();
- OriginalHoldings.Add(holding);
- StockTakeHolding displayHolding = new StockTakeHolding();
- displayHolding.ID = holding.ID;
- displayHolding.OriginalQty = holding.Units;
- displayHolding.Job.ID = holding.Job.ID;
- displayHolding.Job.JobNumber = holding.Job.JobNumber;
- displayHolding.Product.ID = holding.Product.ID;
- displayHolding.Product.Code = holding.Product.Code;
- displayHolding.Product.Name = holding.Product.Name;
- displayHolding.Style.ID = holding.Style.ID;
- displayHolding.Style.Code = holding.Style.Code;
- displayHolding.Style.Description = holding.Style.Description;
- displayHolding.Location.ID = holding.Location.ID;
- displayHolding.Location.Code = holding.Location.Code;
- displayHolding.Location.Description = holding.Location.Description;
- displayHolding = CopyDimensions(displayHolding, holding);
- StockTakeHoldings.Add(displayHolding);
- }
- }
- private StockTakeHolding CopyDimensions(StockTakeHolding display, StockHolding holding)
- {
- display.Dimensions.Unit.ID = holding.Dimensions.Unit.ID;
- display.Dimensions.Unit.HasQuantity = holding.Dimensions.Unit.HasQuantity;
- display.Dimensions.Unit.HasLength = holding.Dimensions.Unit.HasLength;
- display.Dimensions.Unit.HasHeight = holding.Dimensions.Unit.HasHeight;
- display.Dimensions.Unit.HasWeight = holding.Dimensions.Unit.HasWeight;
- display.Dimensions.Unit.HasWidth = holding.Dimensions.Unit.HasWidth;
- display.Dimensions.Quantity = holding.Dimensions.Quantity;
- display.Dimensions.Length = holding.Dimensions.Length;
- display.Dimensions.Height = holding.Dimensions.Height;
- display.Dimensions.Weight = holding.Dimensions.Weight;
- display.Dimensions.Width = holding.Dimensions.Width;
- display.Dimensions.Unit.Format = holding.Dimensions.Unit.Format;
- display.Dimensions.Unit.Formula = holding.Dimensions.Unit.Formula;
- return display;
- }
- #region Editor Setup
- private void Page_OnSave(IDynamicEditorForm editor, BaseObject[] items)
- {
- foreach (StockTakeHolding item in items.Cast<StockTakeHolding>())
- {
- item.UpdateDimensions();
- }
- }
- private void Page_OnValidate(object sender, StockTakeHolding[] items, List<string> errors)
- {
- var bQty = false;
- var bProd = false;
- var bLocn = false;
- foreach (var item in items)
- {
- bQty = bQty || item.NewQty <= 0.0001F;
- bProd = bProd || !item.Product.IsValid();
- bLocn = bLocn || !item.Location.IsValid();
- }
- if (bQty)
- errors.Add("Quantity may not be zero");
- if (bProd)
- errors.Add("Product may not be blank");
- if (bLocn)
- errors.Add("Location may not be blank");
- }
- private void Page_OnCustomiseEditor(IDynamicEditorForm sender, StockTakeHolding[]? items, DynamicGridColumn column, BaseEditor editor)
- {
- if (column.ColumnName.Equals("OriginalQty"))
- editor.Editable = Editable.Hidden;
- if (column.ColumnName.Equals("NewQty"))
- editor.Caption = "Qty";
- if (column.ColumnName.Equals("Dimensions.Quantity"))
- editor.Editable = Editable.Hidden;
- if (column.ColumnName.Equals("Dimensions.Length"))
- editor.Editable = Editable.Hidden;
- if (column.ColumnName.Equals("Dimensions.Weight"))
- editor.Editable = Editable.Hidden;
- if (column.ColumnName.Equals("Dimensions.Height"))
- editor.Editable = Editable.Hidden;
- if (column.ColumnName.Equals("Dimensions.Width"))
- editor.Editable = Editable.Hidden;
- }
- #endregion
- #region Added Buttons
- private bool ClearValues(Button arg1, CoreRow[] arg2)
- {
- var result = MessageBox.Show("This will clear all new quantities entered. Proceed?", "Warning", MessageBoxButton.YesNo);
- if (result != MessageBoxResult.Yes)
- return false;
- foreach (var holding in Holdings.Items)
- holding.ClearQty();
- return true;
- }
- private bool FillValues(Button arg1, CoreRow[] rows)
- {
- var result = MessageBox.Show("This will prefill all new quantities with the original quantity. Proceed?", "Warning", MessageBoxButton.YesNo);
- if (result != MessageBoxResult.Yes)
- return false;
- foreach (var holding in Holdings.Items)
- holding.PreFillQty();
- return true;
- }
- private void Cancel_Button_Click(object sender, RoutedEventArgs e)
- {
- bool changes = false;
- foreach (var holding in StockTakeHoldings)
- {
- if (holding.NewQty != 0)
- changes = true;
- }
- if (changes)
- {
- var result = MessageBox.Show("Warning - any unsaved changes will be lost. Continue?", "Warning", MessageBoxButton.YesNo);
- if (result == MessageBoxResult.Yes)
- Close();
- }
- else
- Close();
- }
- private bool Export(Button arg1, CoreRow[] arg2)
- {
- var result = AddColumns();
- result.LoadRows(Holdings.Items);
- ExcelExporter.DoExport<StockTakeHolding>(result, "Stock Take " + DateTime.Now.ToString("HH:mm dd MMM yy"));
- return true;
- }
- private CoreTable AddColumns()
- {
- var result = new CoreTable();
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "Location.Code",
- DataType = typeof(string)
- });
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "Product.Code",
- DataType = typeof(string)
- });
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "Product.Name",
- DataType = typeof(string)
- });
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "Dimensions.UnitSize",
- DataType = typeof(string)
- });
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "Job.JobNumber",
- DataType = typeof(string)
- });
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "Job.Name",
- DataType = typeof(string)
- });
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "Style.Description",
- DataType = typeof(string)
- });
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "OriginalQty",
- DataType = typeof(double)
- });
- result.Columns.Add(
- new CoreColumn()
- {
- ColumnName = "NewQty",
- DataType = typeof(double)
- });
- return result;
- }
- #endregion
- #endregion
- #region Saving Stocktake
- #region Button Press / Validate
- private void Ok_Button_Click(object sender, RoutedEventArgs e)
- {
- var result = MessageBox.Show("This will now generate stock movements for each line, whether the quantity has changed or not. Proceed?", "Information", MessageBoxButton.YesNo);
- if (result != MessageBoxResult.Yes)
- return;
- if (!ValidateQty())
- return;
- CreateMovements();
- MessageBox.Show("Success - Stocktake complete");
- Close();
- }
- private bool ValidateQty()
- {
- bool zerosPresent = false;
- foreach (var holding in StockTakeHoldings)
- {
- if (holding.NewQty < 0)
- {
- MessageBox.Show("Negative quantities are not allowed!");
- return false;
- }
- if (holding.NewQty < 0.001)
- zerosPresent = true;
- }
- if (zerosPresent)
- {
- var result = MessageBox.Show("One or more rows have been left as Zero. This will create an issuing stock movement of any existing stock for that row. Proceed?", "Warning", MessageBoxButton.YesNo);
- if (result != MessageBoxResult.Yes)
- return false;
- }
- return true;
- }
- #endregion
- #region Stock Movements
- private void CreateMovements()
- {
- var batch = CreateBatch();
- var movements = CompareHoldingsAndCreateMovements(batch.ID);
- new Client<StockMovement>().Save(movements, "Created on Desktop Stocktake");
- }
- private StockMovementBatch CreateBatch()
- {
- StockMovementBatch batch = new StockMovementBatch();
- batch.Notes = "Stocktake";
- batch.Employee.ID = EmployeeID;
- batch.Type = StockMovementBatchType.Stocktake;
- new Client<StockMovementBatch>().Save(batch, "Created on Desktop Stocktake");
- return batch;
- }
- private List<StockMovement> CompareHoldingsAndCreateMovements(Guid batchID)
- {
- List<StockMovement> movements = new List<StockMovement>();
- foreach (var holding in StockTakeHoldings)
- {
- StockHolding original = OriginalHoldings.Find(x => x.ID == holding.ID);
- if (holding.NewQty < 0.001 && holding.NewQty > 0)
- holding.NewQty = 0;
- if (original != null)
- movements.Add(CreateMovement(holding, holding.NewQty - holding.OriginalQty, batchID));
- else
- movements.Add(CreateMovement(holding, holding.NewQty, batchID));
- }
- return movements;
- }
- private StockMovement CreateMovement(StockTakeHolding holding, double qty, Guid batchID)
- {
- var movement = CreateBaseMovement(holding, batchID);
- return DetermineMovementType(movement, qty);
- }
- private StockMovement CreateBaseMovement(StockTakeHolding holding, Guid batchID)
- {
- var movement = new StockMovement();
- movement.Batch.ID = batchID;
- movement.IsTransfer = false;
- movement.Issued = 0;
- movement.Received = 0;
- movement.Product.ID = holding.Product.ID;
- movement.Job.ID = holding.Job.ID;
- movement.Style.ID = holding.Style.ID;
- movement.Employee.ID = EmployeeID;
- movement.Notes = holding.Notes;
- movement = CopyDimensions(movement, holding);
- movement.Date = DateTime.Now;
- movement.Location.ID = holding.Location.ID;
- movement.IsRemnant = false;
- movement.Type = StockMovementType.StockTake;
- return movement;
- }
- private static StockMovement CopyDimensions(StockMovement movement, StockTakeHolding holding)
- {
- movement.Dimensions.Unit.ID = holding.Dimensions.Unit.ID;
- movement.Dimensions.Unit.HasQuantity = holding.Dimensions.Unit.HasQuantity;
- movement.Dimensions.Unit.HasLength = holding.Dimensions.Unit.HasLength;
- movement.Dimensions.Unit.HasHeight = holding.Dimensions.Unit.HasHeight;
- movement.Dimensions.Unit.HasWeight = holding.Dimensions.Unit.HasWeight;
- movement.Dimensions.Unit.HasWidth = holding.Dimensions.Unit.HasWidth;
- movement.Dimensions.Quantity = holding.Dimensions.Quantity;
- movement.Dimensions.Length = holding.Dimensions.Length;
- movement.Dimensions.Height = holding.Dimensions.Height;
- movement.Dimensions.Weight = holding.Dimensions.Weight;
- movement.Dimensions.Width = holding.Dimensions.Width;
- movement.Dimensions.Unit.Format = holding.Dimensions.Unit.Format;
- movement.Dimensions.Unit.Formula = holding.Dimensions.Unit.Formula;
- return movement;
- }
- private static StockMovement DetermineMovementType(StockMovement movement, double qty)
- {
- if (qty < 0)
- {
- movement.Issued = 0 - qty;
- }
- if (qty > 0)
- {
- movement.Received = qty;
- }
- if (movement.Issued != 0 || movement.Received != 0)
- movement.Notes = string.IsNullOrWhiteSpace(movement.Notes) ? "Updated Qty on Stocktake" : movement.Notes + ". Updated Qty on Stocktake";
- else
- movement.Notes = "Correct Qty during Stocktake";
- return movement;
- }
- #endregion
- #endregion
- }
- #region Intermediate Class
- public class StockTakeHolding : BaseObject
- {
- [DoubleEditor(Editable = Editable.Disabled)]
- public double OriginalQty { get; set; } = 0;
- [DoubleEditor(Editable = Editable.Enabled)]
- public double NewQty { get; set; } = 0.00000000000000000000001;
- [NullEditor]
- public Guid ID { get; set; } = Guid.Empty;
- public ProductLink Product { get; set; }
- public ProductStyleLink Style { get; set; }
- public StockLocationLink Location { get; set; }
- public JobLink Job { get; set; }
- public StockDimensions Dimensions { get; set; }
- [MemoEditor(Editable = Editable.Enabled)]
- public string Notes { get; set; } = "Stocktake: ";
- public void UpdateDimensions()
- {
- if (Product.ID != Guid.Empty)
- {
- CoreTable table = new Client<Product>().Query(new Filter<Product>(x => x.ID).IsEqualTo(Product.ID),
- new Columns<Product>(
- x => x.Dimensions.Unit.ID,
- x => x.Dimensions.Unit.HasQuantity,
- x => x.Dimensions.Unit.HasLength,
- x => x.Dimensions.Unit.HasHeight,
- x => x.Dimensions.Unit.HasWeight,
- x => x.Dimensions.Unit.HasWidth,
- x => x.Dimensions.Quantity,
- x => x.Dimensions.Length,
- x => x.Dimensions.Height,
- x => x.Dimensions.Weight,
- x => x.Dimensions.Width,
- x => x.Dimensions.Unit.Format,
- x => x.Dimensions.Unit.Formula,
- x => x.Dimensions.UnitSize
- ));
- Product product = table.Rows.FirstOrDefault().ToObject<Product>();
- Dimensions.Unit.ID = product.Dimensions.Unit.ID;
- Dimensions.Unit.HasQuantity = product.Dimensions.Unit.HasQuantity;
- Dimensions.Unit.HasLength = product.Dimensions.Unit.HasLength;
- Dimensions.Unit.HasHeight = product.Dimensions.Unit.HasHeight;
- Dimensions.Unit.HasWeight = product.Dimensions.Unit.HasWeight;
- Dimensions.Unit.HasWidth = product.Dimensions.Unit.HasWidth;
- Dimensions.Quantity = product.Dimensions.Quantity;
- Dimensions.Length = product.Dimensions.Length;
- Dimensions.Height = product.Dimensions.Height;
- Dimensions.Weight = product.Dimensions.Weight;
- Dimensions.Width = product.Dimensions.Width;
- Dimensions.Unit.Format = product.Dimensions.Unit.Format;
- Dimensions.Unit.Formula = product.Dimensions.Unit.Formula;
- Dimensions.UnitSize = product.Dimensions.UnitSize;
- }
- }
- public void PreFillQty()
- {
- if (OriginalQty != 0)
- NewQty = OriginalQty;
- }
- public void ClearQty()
- {
- NewQty = 0.00000000000000000000001;
- }
- }
- #endregion
- #region Grid
- public class StockTakeHoldingGrid : DynamicItemsListGrid<StockTakeHolding>
- {
- protected override void Reload(Filters<StockTakeHolding> criteria, Columns<StockTakeHolding> columns, ref SortOrder<StockTakeHolding>? sort, Action<CoreTable?, Exception?> action)
- {
- base.Reload(criteria, columns, ref sort, action);
- }
- protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
- {
- base.DoAdd(true);
- }
- protected override DynamicGridColumns LoadColumns()
- {
- var columns = new DynamicGridColumns();
- columns.Add<StockTakeHolding, string>(x => x.Location.Code, 150, "Location Code", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, string>(x => x.Product.Code, 100, "Product Code", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, string>(x => x.Product.Name, 0, "Product Name", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, string>(x => x.Dimensions.UnitSize, 80, "Dimensions Unit", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, string>(x => x.Job.JobNumber, 80, "Job Number", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, string>(x => x.Job.Name, 80, "Job Name", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, string>(x => x.Style.Description, 80, "Style", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, double>(x => x.OriginalQty, 80, "Original Qty", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, double>(x => x.NewQty, 80, "Actual Qty", "", Alignment.MiddleCenter);
- columns.Add<StockTakeHolding, string>(x => x.Notes, 200, "Notes (Optional)", "", Alignment.MiddleCenter);
- return columns;
- }
- }
- #endregion
- }
|