QuickPickModule.xaml.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Comal.Classes;
  7. using Comal.Classes.SecurityDescriptors;
  8. using InABox.Core;
  9. using InABox.Mobile;
  10. using Xamarin.Essentials;
  11. using Xamarin.Forms;
  12. using Xamarin.Forms.Xaml;
  13. using XF.Material.Forms.UI.Dialogs;
  14. using Result = ZXing.Result;
  15. namespace PRS.Mobile
  16. {
  17. public class HoldingUnitCalculator : AbstractConverter<StockHoldingShell, double>
  18. {
  19. public RequisitionItemModel RequisitionItems { get; set; }
  20. protected override double Convert(StockHoldingShell shell, object? parameter = null)
  21. {
  22. return Calculate(shell, RequisitionItems);
  23. }
  24. public static double Calculate(StockHoldingShell holding, RequisitionItemModel? items)
  25. {
  26. var instock = holding.Units;
  27. var picked = items?.Items.Where(x =>
  28. x.LocationID == holding.LocationID
  29. && x.ProductID == holding.ProductID
  30. && x.StyleID == holding.StyleID
  31. && x.JobID == holding.JobID
  32. && x.DimensionsLength == holding.DimensionsLength
  33. && x.DimensionsWidth == holding.DimensionsWidth
  34. && x.DimensionsHeight == holding.DimensionsHeight
  35. && x.DimensionsWeight == holding.DimensionsWeight
  36. && holding.DimensionsQuantity == x.DimensionsQuantity)
  37. .Sum(x => x.ActualQuantity) ?? 0.0;
  38. return instock - picked;
  39. }
  40. }
  41. public class QuickPickViewModel : BindableObject
  42. {
  43. public bool HasItems { get; set; }
  44. public StockHoldingModel Holdings { get; private set; }
  45. public RequisitionItemModel RequisitionItems { get; private set; }
  46. public JobShell Job { get; set; }
  47. public QuickPickViewModel()
  48. {
  49. Holdings = new StockHoldingModel(App.Data, () => new Filter<StockHolding>().None());
  50. RequisitionItems = new RequisitionItemModel(App.Data, () => new Filter<RequisitionItem>().None());
  51. Job = App.Data.Jobs.CreateItem();
  52. }
  53. }
  54. [XamlCompilation(XamlCompilationOptions.Compile)]
  55. public partial class QuickPickModule : MobilePage
  56. {
  57. public QuickPickModule()
  58. {
  59. InitializeComponent();
  60. UnitCalculator.RequisitionItems = _viewModel.RequisitionItems;
  61. var options = new ZXing.Mobile.MobileBarcodeScanningOptions()
  62. {
  63. PossibleFormats = new List<ZXing.BarcodeFormat>() { ZXing.BarcodeFormat.QR_CODE },
  64. AutoRotate = false,
  65. TryInverted = true,
  66. TryHarder = true,
  67. };
  68. _scanView.Options = options;
  69. _scanView.IsAnalyzing = false;
  70. _scanView.IsScanning = true;
  71. }
  72. protected override void OnAppearing()
  73. {
  74. base.OnAppearing();
  75. try
  76. {
  77. _scanView.IsAnalyzing = _tabStrip.SelectedIndex == 0;
  78. }
  79. catch (Exception e)
  80. {
  81. InABox.Mobile.MobileLogging.Log(e);
  82. }
  83. }
  84. protected override void OnDisappearing()
  85. {
  86. try
  87. {
  88. _scanView.IsAnalyzing = false;
  89. }
  90. catch (Exception e)
  91. {
  92. InABox.Mobile.MobileLogging.Log(e);
  93. }
  94. base.OnDisappearing();
  95. }
  96. private void _tabStrip_OnSelectionChanged(object sender, EventArgs e)
  97. {
  98. _scanView.IsAnalyzing = _tabStrip.SelectedIndex == 0;
  99. _viewModel.HasItems = _viewModel.RequisitionItems.Any();
  100. }
  101. private bool bProcessing = false;
  102. private Guid _lastGuid = Guid.Empty;
  103. private async void ScanView_OnScanResult(ZXing.Result result)
  104. {
  105. if (bProcessing)
  106. return;
  107. if (!Guid.TryParse(result.Text, out Guid id) || id == Guid.Empty || id == _lastGuid)
  108. return;
  109. _lastGuid = id;
  110. bProcessing = true;
  111. using (await MaterialDialog.Instance.LoadingDialogAsync($"Processing..."))
  112. {
  113. Vibration.Vibrate();
  114. SearchLocationID(id);
  115. bProcessing = false;
  116. }
  117. }
  118. private void SearchLocationID(Guid id)
  119. {
  120. //App.Data.StockLocations.Refresh(false);
  121. //var location = App.Data.StockLocations.FirstOrDefault(x => Guid.Equals(x.ID,id));
  122. //if (location != null)
  123. //{
  124. _viewModel.Holdings.Filter = () =>
  125. new Filter<StockHolding>(x => x.Location.ID).IsEqualTo(id).Or(x=>x.Product.ID).IsEqualTo(id);
  126. _viewModel.Holdings.Refresh(true);
  127. //}
  128. }
  129. private void SelectFromHolding_Click(object sender, EventArgs e)
  130. {
  131. var holding = (sender as MobileCard)?.BindingContext as StockHoldingShell;
  132. if (holding == null)
  133. return;
  134. ShowPopup(() =>
  135. {
  136. var qty = HoldingUnitCalculator.Calculate(holding, _viewModel.RequisitionItems);
  137. var editor = new SelectFromHoldingView(holding, qty, _viewModel.RequisitionItems);
  138. editor.OnSave += (o, args) =>
  139. {
  140. if (args.Quantity.IsEffectivelyGreaterThan(0.0))
  141. {
  142. var requiItem = _viewModel.RequisitionItems.CreateItem();
  143. requiItem.LocationID = args.Holding.LocationID;
  144. requiItem.ProductID = args.Holding.ProductID;
  145. requiItem.ProductCode = args.Holding.ProductCode;
  146. requiItem.ProductName = args.Holding.ProductName;
  147. requiItem.StyleID = args.Holding.StyleID;
  148. requiItem.StyleCode = args.Holding.StyleCode;
  149. requiItem.StyleDescription = args.Holding.StyleDescription;
  150. requiItem.JobID = args.Holding.JobID;
  151. requiItem.DimensionsUnitID = args.Holding.DimensionsUnitID;
  152. requiItem.DimensionsHeight = args.Holding.DimensionsHeight;
  153. requiItem.DimensionsWidth = args.Holding.DimensionsWidth;
  154. requiItem.DimensionsLength = args.Holding.DimensionsLength;
  155. requiItem.DimensionsQuantity = args.Holding.DimensionsQuantity;
  156. requiItem.DimensionsWeight = args.Holding.DimensionsWeight;
  157. requiItem.DimensionsValue = args.Holding.DimensionsValue;
  158. requiItem.DimensionsUnitSize = args.Holding.DimensionsUnitSize;
  159. requiItem.ImageID = args.Holding.ImageID;
  160. if (args.Holding.Parent.Images.TryGetValue(args.Holding.ImageID, out var _image))
  161. _viewModel.RequisitionItems.Images[args.Holding.ImageID] = _image;
  162. requiItem.SourceJRI = args.JobRequisitionItemID;
  163. requiItem.TargetJRI = args.JobRequisitionItemID;
  164. requiItem.Quantity = args.Quantity;
  165. requiItem.ActualQuantity = args.Quantity;
  166. requiItem.Cost = args.Holding.AverageCost;
  167. requiItem.Done = true;
  168. _viewModel.RequisitionItems.CommitItem(requiItem);
  169. _viewModel.Holdings.Refresh(false);
  170. DismissPopup();
  171. }
  172. };
  173. editor.OnCancel += (o, args) => DismissPopup();
  174. return editor;
  175. },
  176. new PopupManagerConfiguration()
  177. {
  178. RequestedHeight = Math.Min(700,500 + (holding.Allocations.Length * 55))
  179. });
  180. }
  181. private void SelectJob_Clicked(object sender, MobileButtonClickEventArgs args)
  182. {
  183. ShowPopup(() => SelectionView.Execute<JobShell>(
  184. (columns) =>
  185. {
  186. columns.Add(new MobileGridTextColumn<JobShell>()
  187. {
  188. Column = x => x.JobNumber,
  189. Width = GridLength.Auto,
  190. Caption = "#",
  191. Alignment = TextAlignment.Center
  192. });
  193. columns.Add(new MobileGridTextColumn<JobShell>()
  194. {
  195. Column = x => x.Name,
  196. Width = GridLength.Star,
  197. Caption = "Select Job",
  198. Alignment = TextAlignment.Start
  199. });
  200. },
  201. (refresh) => App.Data.Jobs.Refresh(false),
  202. (jobs) =>
  203. {
  204. _viewModel.Job = jobs.FirstOrDefault() ?? App.Data.Jobs.CreateItem();
  205. DismissPopup();
  206. }));
  207. }
  208. private async void SaveList_Click(object sender, MobileMenuButtonClickedEventArgs args)
  209. {
  210. if (_viewModel.Job.ID == Guid.Empty && !Security.IsAllowed<AllowMobileQuickPickWithoutJob>())
  211. {
  212. await MaterialDialog.Instance.AlertAsync("Please select a Job before saving!", "Error");
  213. return;
  214. }
  215. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Saving"))
  216. {
  217. try
  218. {
  219. var _requiModel = new RequisitionModel(App.Data, () => new Filter<Requisition>().None());
  220. var requi = _requiModel.CreateItem();
  221. requi.Title = $"Quick Pick by {App.Data.Me.Name}";
  222. requi.RequestedByID = App.Data.Me.ID;
  223. requi.Due = DateTime.Now;
  224. requi.JobID = _viewModel.Job.ID;
  225. _requiModel.CommitItem(requi);
  226. _requiModel.Save("Requisition Created from Mobile Quick Pick Module");
  227. foreach (var _item in _viewModel.RequisitionItems.Items)
  228. {
  229. if (_viewModel.Job.ID != _item.JobID)
  230. _item.TargetJRI = Guid.Empty;
  231. _item.RequisitionID = requi.ID;
  232. }
  233. _viewModel.RequisitionItems.Save("Created from Mobile Quick Pick Module");
  234. requi.Filled = requi.Due;
  235. requi.StockUpdated = requi.Filled;
  236. _requiModel.Save("Stock Movements created from Mobile Quick Pick Module");
  237. }
  238. catch (Exception e)
  239. {
  240. InABox.Mobile.MobileLogging.Log(e);
  241. }
  242. }
  243. Navigation.PopAsync();
  244. }
  245. private async void DeleteRequisitionItem(object sender, MobileMenuButtonClickedEventArgs args)
  246. {
  247. var shell = ((sender as MobileMenuButton)?.BindingContext as RequisitionItemShell);
  248. if (shell == null)
  249. return;
  250. if (await MaterialDialog.Instance.ConfirmAsync("Delete Picked Item?", "Confirm") == true)
  251. {
  252. _viewModel.RequisitionItems.DeleteItem(shell);
  253. }
  254. }
  255. }
  256. }