StockForecastOrderScreen.xaml.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. using Comal.Classes;
  2. using InABox.Core;
  3. using InABox.Wpf;
  4. using InABox.WPF;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.ComponentModel;
  8. using System.Linq;
  9. using System.Runtime.CompilerServices;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using System.Windows;
  13. using System.Windows.Controls;
  14. using System.Windows.Data;
  15. using System.Windows.Documents;
  16. using System.Windows.Input;
  17. using System.Windows.Media;
  18. using System.Windows.Media.Imaging;
  19. using System.Windows.Shapes;
  20. using InABox.Configuration;
  21. using InABox.Clients;
  22. using InABox.DynamicGrid;
  23. namespace PRSDesktop;
  24. public class StockForecastOrderScreenSettings : IGlobalConfigurationSettings
  25. {
  26. public StockForecastOrderingType OrderingType { get; set; } =
  27. StockForecastOrderingType.StockOrder;
  28. public StockForecastOrderingStrategy OrderingStrategy { get; set; } =
  29. StockForecastOrderingStrategy.LowestOverallPrice;
  30. }
  31. /// <summary>
  32. /// Interaction logic for StockForecastOrderScreen.xaml
  33. /// </summary>
  34. public partial class StockForecastOrderScreen : Window, INotifyPropertyChanged
  35. {
  36. private StockForecastOrderScreenSettings settings;
  37. private bool _canSave;
  38. public bool CanSave
  39. {
  40. get => _canSave;
  41. set
  42. {
  43. _canSave = true;
  44. OnPropertyChanged();
  45. }
  46. }
  47. public StockForecastOrderingType OrderType
  48. {
  49. get => Grid.OrderType;
  50. set => Grid.OrderType = value;
  51. }
  52. public StockForecastOrderingStrategy Strategy
  53. {
  54. get => Grid.OrderStrategy;
  55. set => Grid.OrderStrategy = value;
  56. }
  57. public StockForecastCombineMode CombineMode
  58. {
  59. get => Grid.CombineMode;
  60. set => Grid.CombineMode = value;
  61. }
  62. public IEnumerable<StockForecastOrderingResult> Results => Grid.Results;
  63. public StockForecastOrderScreen(List<StockForecastOrderData> items, bool allowstockOrder = true)
  64. {
  65. settings = new GlobalConfiguration<StockForecastOrderScreenSettings>().Load();
  66. InitializeComponent();
  67. if (allowstockOrder)
  68. {
  69. OrderType = settings.OrderingType;
  70. OrderTypeBox.ItemsSource = Enum.GetValues<StockForecastOrderingType>()
  71. .Select(x => new KeyValuePair<StockForecastOrderingType, string>(x, CoreUtils.Neatify(x.ToString())));
  72. OrderTypeBox.SelectedValuePath = "Key";
  73. OrderTypeBox.DisplayMemberPath = "Value";
  74. OrderTypeBox.VerticalContentAlignment = VerticalAlignment.Center;
  75. OrderTypeBox.Bind(ComboBox.SelectedValueProperty, this, x => x.OrderType);
  76. }
  77. else
  78. {
  79. OrderType = StockForecastOrderingType.Breakup;
  80. OrderTypeBox.Visibility = System.Windows.Visibility.Collapsed;
  81. OrderTypeLabel.Visibility = System.Windows.Visibility.Collapsed;
  82. }
  83. Strategy = settings.OrderingStrategy;
  84. OrderStrategyBox.ItemsSource = Enum.GetValues<StockForecastOrderingStrategy>()
  85. .Select(x => new KeyValuePair<StockForecastOrderingStrategy, string>(x, CoreUtils.Neatify(x.ToString())));
  86. OrderStrategyBox.SelectedValuePath = "Key";
  87. OrderStrategyBox.DisplayMemberPath = "Value";
  88. OrderStrategyBox.VerticalContentAlignment = VerticalAlignment.Center;
  89. OrderStrategyBox.Bind(ComboBox.SelectedValueProperty, this, x => x.Strategy);
  90. CombineModeBox.ItemsSource = Enum.GetValues<StockForecastCombineMode>()
  91. .Select(x => new KeyValuePair<StockForecastCombineMode, string>(x, CoreUtils.Neatify(x.ToString())));
  92. CombineModeBox.SelectedValuePath = "Key";
  93. CombineModeBox.DisplayMemberPath = "Value";
  94. CombineModeBox.VerticalContentAlignment = VerticalAlignment.Center;
  95. CombineModeBox.Bind(ComboBox.SelectedValueProperty, this, x => x.CombineMode);
  96. Grid.OrderData = items;
  97. Grid.Refresh(true, true);
  98. }
  99. private void CancelButton_Click(object sender, RoutedEventArgs e)
  100. {
  101. DialogResult = false;
  102. Close();
  103. }
  104. private void OKButton_Click(object sender, RoutedEventArgs e)
  105. {
  106. DialogResult = true;
  107. Close();
  108. }
  109. public event PropertyChangedEventHandler? PropertyChanged;
  110. protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
  111. {
  112. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  113. }
  114. private void Grid_OnChanged(object sender, EventArgs e)
  115. {
  116. CanSave = Grid.TotalQuantity > 0;
  117. }
  118. private void OrderTypeBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  119. {
  120. if (Grid.OrderData == null)
  121. return;
  122. settings.OrderingType = (StockForecastOrderingType)OrderTypeBox.SelectedValue;
  123. new GlobalConfiguration<StockForecastOrderScreenSettings>().Save(settings);
  124. }
  125. private void OrderStrategyBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  126. {
  127. if (Grid.OrderData == null)
  128. return;
  129. settings.OrderingStrategy = (StockForecastOrderingStrategy)OrderStrategyBox.SelectedValue;
  130. new GlobalConfiguration<StockForecastOrderScreenSettings>().Save(settings);
  131. }
  132. public void CreateOrders(string screenName)
  133. {
  134. var orders = new List<Tuple<PurchaseOrder, Dictionary<StockForecastOrderingResult,PurchaseOrderItem>>>();
  135. Progress.ShowModal("Creating Orders", progress =>
  136. {
  137. int iOrder = 1;
  138. foreach(var perSupplier in Results.GroupBy(x => x.Supplier.ID))
  139. {
  140. progress.Report($"Creating Orders ({iOrder++}/{Results.ToArray().Length})");
  141. var order = new PurchaseOrder();
  142. order.Description = $"Purchase Order created from {screenName} Screen";
  143. order.RaisedBy.ID = App.EmployeeID;
  144. LookupFactory.DoLookup<PurchaseOrder, Supplier, SupplierLink>(order, x => x.SupplierLink, perSupplier.Key);
  145. var orderItems = new Dictionary<StockForecastOrderingResult,PurchaseOrderItem>();
  146. var results = perSupplier.ToArray();
  147. foreach(var item in results)
  148. {
  149. var orderItem = new PurchaseOrderItem();
  150. orderItem.Product.ID = item.Item.Product.ID;
  151. orderItem.Style.ID = item.Item.Style.ID;
  152. orderItem.Job.ID = item.SupplierProduct.Job.ID;
  153. orderItems[item] = orderItem;
  154. }
  155. var jobIDs = orderItems.Values.ToArray(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Job.ID));
  156. var productIDs = orderItems.Values.ToArray(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Product.ID));
  157. var styleIDs = orderItems.Values.ToArray(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Style.ID));
  158. var taxCodeIDs = orderItems.Values.ToArray(x => new Tuple<PurchaseOrderItem, Guid>(x, x.TaxCode.ID));
  159. LookupFactory.DoLookups<PurchaseOrderItem, Job, JobLink>(jobIDs, x => x.Job);
  160. LookupFactory.DoLookups<PurchaseOrderItem, Product, ProductLink>(productIDs, x => x.Product);
  161. LookupFactory.DoLookups<PurchaseOrderItem, ProductStyle, ProductStyleLink>(styleIDs, x => x.Style);
  162. LookupFactory.DoLookups<PurchaseOrderItem, TaxCode, TaxCodeLink>(taxCodeIDs, x => x.TaxCode);
  163. foreach(var item in results)
  164. {
  165. var orderItem = orderItems[item];
  166. orderItem.Dimensions.CopyFrom(item.SupplierProduct.Dimensions);
  167. orderItem.Qty = item.Quantity;
  168. orderItem.ForeignCurrencyCost = item.SupplierProduct.ForeignCurrencyPrice;
  169. orderItem.Cost = item.SupplierProduct.CostPrice;
  170. }
  171. orders.Add(new(order, orderItems));
  172. }
  173. progress.Report($"Saving {orders.Count} Orders");
  174. Client.Save(orders.Select(x => x.Item1), $"Created from {screenName} screen");
  175. foreach(var (order, orderItems) in orders)
  176. {
  177. foreach(var pair in orderItems)
  178. pair.Value.PurchaseOrderLink.ID = order.ID;
  179. }
  180. Client.Save(orders.SelectMany(x => x.Item2.Values), $"Created from {screenName} screen");
  181. var allocations = new List<PurchaseOrderItemAllocation>();
  182. progress.Report($"Processing Breakups");
  183. foreach(var (order, orderItems) in orders)
  184. {
  185. foreach(var (result, poi) in orderItems)
  186. {
  187. foreach (var breakup in result.Breakups)
  188. {
  189. // Skip the nominated job.
  190. if (breakup.JobID == poi.Job.ID && breakup.JobRequiItemID == Guid.Empty) continue;
  191. var alloc = new PurchaseOrderItemAllocation();
  192. alloc.Item.ID = poi.ID;
  193. alloc.Job.ID = breakup.JobID;
  194. alloc.JobRequisitionItem.ID = breakup.JobRequiItemID;
  195. alloc.Quantity = breakup.Quantity;
  196. allocations.Add(alloc);
  197. }
  198. }
  199. }
  200. if (allocations.Count != 0)
  201. Client.Save(allocations, $"Created from {screenName} Screen");
  202. });
  203. MessageWindow.ShowMessage($"The following orders were created:\n- {string.Join("\n- ",orders.Select(x=>x.Item1.PONumber))}", $"Created {orders.Count} orders");
  204. }
  205. private void StyleSelectButton_Click(object sender, RoutedEventArgs e)
  206. {
  207. var dlg = new MultiSelectDialog<ProductStyle>(
  208. null,
  209. Columns.None<ProductStyle>().Add(x => x.ID).Add(x => x.Code),
  210. multiselect: false);
  211. var result = dlg.ShowDialog();
  212. if(result == true)
  213. {
  214. Grid.SetStyle(dlg.Data().ToObjects<ProductStyle>().First());
  215. }
  216. else if(result == false)
  217. {
  218. Grid.SetStyle(null);
  219. }
  220. }
  221. private void Grid_OnSelectItem(object sender, InABox.DynamicGrid.DynamicGridSelectionEventArgs e)
  222. {
  223. StyleSelectButton.IsEnabled = e.Rows is not null && e.Rows.Length > 0;
  224. }
  225. private void CollapseModeBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
  226. {
  227. }
  228. }