JobRequisitionItemStore.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using Comal.Classes;
  2. using Comal.Stores;
  3. using InABox.Core;
  4. using InABox.Database;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. namespace PRSStores;
  9. public class JobRequisitionItemStore : BaseStore<JobRequisitionItem>
  10. {
  11. protected override void BeforeSave(JobRequisitionItem item)
  12. {
  13. if (item.ID != Guid.Empty)
  14. {
  15. var newStatus = CalculateStatus(this, item);
  16. if(newStatus != null)
  17. {
  18. item.Status = newStatus.Value;
  19. }
  20. }
  21. base.BeforeSave(item);
  22. }
  23. public static Columns<JobRequisitionItem> StatusRequiredColumns()
  24. {
  25. return new Columns<JobRequisitionItem>(
  26. x => x.ID,
  27. x => x.Archived,
  28. x => x.Cancelled,
  29. x => x.OrderRequired,
  30. x => x.Status,
  31. x => x.Style.ID,
  32. x => x.Product.ID,
  33. x => x.Qty);
  34. }
  35. /// <summary>
  36. /// Ensure that the columns of <paramref name="item"/> match <see cref="StatusRequiredColumns"/>.
  37. /// </summary>
  38. /// <param name="store"></param>
  39. /// <param name="item"></param>
  40. /// <returns></returns>
  41. public static JobRequisitionItemStatus? CalculateStatus(IStore store, JobRequisitionItem item)
  42. {
  43. if (item.Archived != DateTime.MinValue)
  44. {
  45. return JobRequisitionItemStatus.Archived;
  46. }
  47. else if (item.Cancelled != DateTime.MinValue)
  48. {
  49. return JobRequisitionItemStatus.Cancelled;
  50. }
  51. else
  52. {
  53. var stockMovements = store.Provider.Query(
  54. new Filter<StockMovement>(x => x.JobRequisitionItem.ID).IsEqualTo(item.ID),
  55. new Columns<StockMovement>(
  56. x => x.Units,
  57. x => x.Style.ID))
  58. .ToObjects<StockMovement>();
  59. var styleTotal = 0.0;
  60. var total = 0.0;
  61. foreach (var mvt in stockMovements)
  62. {
  63. if (mvt.Style.ID == item.Style.ID)
  64. {
  65. styleTotal += mvt.Units;
  66. }
  67. total += mvt.Units;
  68. }
  69. var remStyle = item.Qty - styleTotal;
  70. var remTotal = item.Qty - total;
  71. if (remStyle <= 0)
  72. {
  73. return JobRequisitionItemStatus.Allocated;
  74. }
  75. else if (remTotal <= 0)
  76. {
  77. // Find all unreceived POItems for this guy that are treatments (i.e., wrong product ID).
  78. var jriPois = store.Provider.Query(
  79. new Filter<JobRequisitionItemPurchaseOrderItem>(x => x.JobRequisitionItem.ID).IsEqualTo(item.ID)
  80. .And(x => x.PurchaseOrderItem.ReceivedDate).IsEqualTo(DateTime.MinValue)
  81. .And(x => x.PurchaseOrderItem.Product.ID).IsNotEqualTo(item.Product.ID),
  82. new Columns<JobRequisitionItemPurchaseOrderItem>(x => x.ID));
  83. if (jriPois.Rows.Count > 0)
  84. {
  85. return JobRequisitionItemStatus.TreatmentOnOrder;
  86. }
  87. else
  88. {
  89. return JobRequisitionItemStatus.TreatmentRequired;
  90. }
  91. }
  92. else
  93. {
  94. // Find all unreceived POItems for this guy.
  95. var jriPois = store.Provider.Query(
  96. new Filter<JobRequisitionItemPurchaseOrderItem>(x => x.JobRequisitionItem.ID).IsEqualTo(item.ID)
  97. .And(x => x.PurchaseOrderItem.ReceivedDate).IsEqualTo(DateTime.MinValue),
  98. new Columns<JobRequisitionItemPurchaseOrderItem>(x => x.PurchaseOrderItem.Product.ID)
  99. .Add(x => x.PurchaseOrderItem.Qty))
  100. .ToObjects<JobRequisitionItemPurchaseOrderItem>()
  101. .ToList();
  102. var stockOrders = jriPois.Where(x => x.PurchaseOrderItem.Product.ID == item.Product.ID).ToList();
  103. var treatmentOrders = jriPois.Where(x => x.PurchaseOrderItem.Product.ID != item.Product.ID).ToList();
  104. remTotal -= stockOrders.Sum(x => x.PurchaseOrderItem.Qty);
  105. if (remTotal <= 0)
  106. {
  107. if (stockOrders.Count > 0)
  108. {
  109. return JobRequisitionItemStatus.OnOrder;
  110. }
  111. else
  112. {
  113. // This should be impossible to reach. We are at this point because remTotal <= 0, but stockOrders was an empty list. Therefore
  114. // remTotal is was <= 0 before checking PurchaseOrderItems, but then we should be TreatmentRequired, as above.
  115. Logger.Send(LogType.Error, store.UserID, $"Internal assertion failed: there is enough stock, but we didn't reach the correct clause.");
  116. if (treatmentOrders.Count > 0)
  117. {
  118. return JobRequisitionItemStatus.TreatmentOnOrder;
  119. }
  120. else
  121. {
  122. return JobRequisitionItemStatus.TreatmentRequired;
  123. }
  124. }
  125. }
  126. else if (item.OrderRequired != DateTime.MinValue)
  127. {
  128. return JobRequisitionItemStatus.OrderRequired;
  129. }
  130. else
  131. {
  132. // Even after all the orders have come through, we still don't have enough. We must order more.
  133. return JobRequisitionItemStatus.NotChecked;
  134. }
  135. }
  136. }
  137. }
  138. public static JobRequisitionItemStatus? CalculateStatus(IStore store, Guid jobRequiItemID)
  139. {
  140. var item = store.Provider.Query(
  141. new Filter<JobRequisitionItem>(x => x.ID).IsEqualTo(jobRequiItemID),
  142. StatusRequiredColumns())
  143. .ToObjects<JobRequisitionItem>()
  144. .FirstOrDefault();
  145. if(item is null)
  146. {
  147. Logger.Send(LogType.Error, store.UserID, $"No {nameof(JobRequisitionItem)} with ID {jobRequiItemID}");
  148. return null;
  149. }
  150. return CalculateStatus(store, item);
  151. }
  152. public static void UpdateStatus(IStore store, Guid jobRequiItemID)
  153. {
  154. var item = store.Provider.Query(
  155. new Filter<JobRequisitionItem>(x => x.ID).IsEqualTo(jobRequiItemID),
  156. StatusRequiredColumns())
  157. .ToObjects<JobRequisitionItem>()
  158. .FirstOrDefault();
  159. if (item is null)
  160. {
  161. Logger.Send(LogType.Error, store.UserID, $"No {nameof(JobRequisitionItem)} with ID {jobRequiItemID}");
  162. }
  163. else
  164. {
  165. var newStatus = CalculateStatus(store, item);
  166. if (newStatus.HasValue)
  167. {
  168. item.Status = newStatus.Value;
  169. store.Provider.Save(item);
  170. }
  171. }
  172. }
  173. }