StockForecastOrderScreen.xaml.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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 IEnumerable<StockForecastOrderingResult> Results => Grid.Results;
  58. public StockForecastOrderScreen(List<StockForecastOrderData> items, bool allowstockOrder = true)
  59. {
  60. settings = new GlobalConfiguration<StockForecastOrderScreenSettings>().Load();
  61. InitializeComponent();
  62. if (allowstockOrder)
  63. {
  64. OrderType = settings.OrderingType;
  65. OrderTypeBox.ItemsSource = Enum.GetValues<StockForecastOrderingType>()
  66. .Select(x => new KeyValuePair<StockForecastOrderingType, string>(x, CoreUtils.Neatify(x.ToString())));
  67. OrderTypeBox.SelectedValuePath = "Key";
  68. OrderTypeBox.DisplayMemberPath = "Value";
  69. OrderTypeBox.VerticalContentAlignment = VerticalAlignment.Center;
  70. OrderTypeBox.Bind(ComboBox.SelectedValueProperty, this, x => x.OrderType);
  71. }
  72. else
  73. {
  74. OrderType = StockForecastOrderingType.Breakup;
  75. OrderTypeBox.Visibility = System.Windows.Visibility.Collapsed;
  76. OrderTypeLabel.Visibility = System.Windows.Visibility.Collapsed;
  77. }
  78. Strategy = settings.OrderingStrategy;
  79. OrderStrategyBox.ItemsSource = Enum.GetValues<StockForecastOrderingStrategy>()
  80. .Select(x => new KeyValuePair<StockForecastOrderingStrategy, string>(x, CoreUtils.Neatify(x.ToString())));
  81. OrderStrategyBox.SelectedValuePath = "Key";
  82. OrderStrategyBox.DisplayMemberPath = "Value";
  83. OrderStrategyBox.VerticalContentAlignment = VerticalAlignment.Center;
  84. OrderStrategyBox.Bind(ComboBox.SelectedValueProperty, this, x => x.Strategy);
  85. Grid.OrderData = items;
  86. Grid.Refresh(true, true);
  87. }
  88. private void CancelButton_Click(object sender, RoutedEventArgs e)
  89. {
  90. DialogResult = false;
  91. Close();
  92. }
  93. private void OKButton_Click(object sender, RoutedEventArgs e)
  94. {
  95. DialogResult = true;
  96. Close();
  97. }
  98. public event PropertyChangedEventHandler? PropertyChanged;
  99. protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
  100. {
  101. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  102. }
  103. private void Grid_OnChanged(object sender, EventArgs e)
  104. {
  105. CanSave = Grid.TotalQuantity > 0;
  106. }
  107. private void OrderTypeBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  108. {
  109. if (Grid.OrderData == null)
  110. return;
  111. settings.OrderingType = (StockForecastOrderingType)OrderTypeBox.SelectedValue;
  112. new GlobalConfiguration<StockForecastOrderScreenSettings>().Save(settings);
  113. }
  114. private void OrderStrategyBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  115. {
  116. if (Grid.OrderData == null)
  117. return;
  118. settings.OrderingStrategy = (StockForecastOrderingStrategy)OrderStrategyBox.SelectedValue;
  119. new GlobalConfiguration<StockForecastOrderScreenSettings>().Save(settings);
  120. }
  121. public void CreateOrders(string screenName)
  122. {
  123. var orders = new List<Tuple<PurchaseOrder, Dictionary<StockForecastOrderingResult,PurchaseOrderItem>>>();
  124. Progress.ShowModal("Creating Orders", progress =>
  125. {
  126. int iOrder = 1;
  127. foreach(var perSupplier in Results.GroupBy(x => x.Supplier.ID))
  128. {
  129. progress.Report($"Creating Orders ({iOrder++}/{Results.ToArray().Length})");
  130. var order = new PurchaseOrder();
  131. order.Description = $"Purchase Order created from {screenName} Screen";
  132. order.RaisedBy.ID = App.EmployeeID;
  133. LookupFactory.DoLookup<PurchaseOrder, Supplier, SupplierLink>(order, x => x.SupplierLink, perSupplier.Key);
  134. var orderItems = new Dictionary<StockForecastOrderingResult,PurchaseOrderItem>();
  135. var results = perSupplier.ToArray();
  136. foreach(var item in results)
  137. {
  138. var orderItem = new PurchaseOrderItem();
  139. orderItem.Product.ID = item.Item.Product.ID;
  140. orderItem.Style.ID = item.Item.Style.ID;
  141. orderItem.Job.ID = item.SupplierProduct.Job.ID;
  142. orderItems[item] = orderItem;
  143. }
  144. LookupFactory.DoLookups<PurchaseOrderItem, Job, JobLink>(
  145. orderItems.Values.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Job.ID)),
  146. x => x.Job);
  147. LookupFactory.DoLookups<PurchaseOrderItem, Product, ProductLink>(
  148. orderItems.Values.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Product.ID)),
  149. x => x.Product);
  150. LookupFactory.DoLookups<PurchaseOrderItem, ProductStyle, ProductStyleLink>(
  151. orderItems.Values.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Style.ID)),
  152. x => x.Style);
  153. LookupFactory.DoLookups<PurchaseOrderItem, TaxCode, TaxCodeLink>(
  154. orderItems.Values.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.TaxCode.ID)),
  155. x => x.TaxCode);
  156. foreach(var item in results)
  157. {
  158. var orderItem = orderItems[item];
  159. orderItem.Dimensions.CopyFrom(item.SupplierProduct.Dimensions);
  160. orderItem.Qty = item.Quantity;
  161. orderItem.ForeignCurrencyCost = item.SupplierProduct.ForeignCurrencyPrice;
  162. orderItem.Cost = item.SupplierProduct.CostPrice;
  163. }
  164. orders.Add(new(order, orderItems));
  165. }
  166. progress.Report($"Saving {orders.Count} Orders");
  167. Client.Save(orders.Select(x => x.Item1), $"Created from {screenName} screen");
  168. foreach(var (order, orderItems) in orders)
  169. {
  170. foreach(var pair in orderItems)
  171. pair.Value.PurchaseOrderLink.ID = order.ID;
  172. }
  173. Client.Save(orders.SelectMany(x => x.Item2.Values), $"Created from {screenName} screen");
  174. var allocations = new List<PurchaseOrderItemAllocation>();
  175. progress.Report($"Processing Breakups");
  176. foreach(var (order, orderItems) in orders)
  177. {
  178. foreach(var (result, poi) in orderItems)
  179. {
  180. foreach (var breakup in result.Breakups)
  181. {
  182. // Skip the nominated job.
  183. if (breakup.JobID == poi.Job.ID && breakup.JobRequiItemID == Guid.Empty) continue;
  184. var alloc = new PurchaseOrderItemAllocation();
  185. alloc.Item.ID = poi.ID;
  186. alloc.Job.ID = breakup.JobID;
  187. alloc.JobRequisitionItem.ID = breakup.JobRequiItemID;
  188. alloc.Quantity = breakup.Quantity;
  189. allocations.Add(alloc);
  190. }
  191. }
  192. }
  193. if (allocations.Count != 0)
  194. Client.Save(allocations, $"Created from {screenName} Screen");
  195. });
  196. MessageWindow.ShowMessage($"The following orders were created:\n- {string.Join("\n- ",orders.Select(x=>x.Item1.PONumber))}", $"Created {orders.Count} orders");
  197. }
  198. private void StyleSelectButton_Click(object sender, RoutedEventArgs e)
  199. {
  200. var dlg = new MultiSelectDialog<ProductStyle>(
  201. null,
  202. Columns.None<ProductStyle>().Add(x => x.ID).Add(x => x.Code),
  203. multiselect: false);
  204. var result = dlg.ShowDialog();
  205. if(result == true)
  206. {
  207. Grid.SetStyle(dlg.Data().ToObjects<ProductStyle>().First());
  208. }
  209. else if(result == false)
  210. {
  211. Grid.SetStyle(null);
  212. }
  213. }
  214. private void Grid_OnSelectItem(object sender, InABox.DynamicGrid.DynamicGridSelectionEventArgs e)
  215. {
  216. StyleSelectButton.IsEnabled = e.Rows is not null && e.Rows.Length > 0;
  217. }
  218. }