RequisitionStore.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using Comal.Classes;
  6. using H.Pipes.Extensions;
  7. using InABox.Core;
  8. using PRSClasses;
  9. using Syncfusion.Windows.Tools.Controls;
  10. namespace Comal.Stores
  11. {
  12. internal class RequisitionStore : BaseStore<Requisition>
  13. {
  14. private readonly bool _debug = true;
  15. private void Log(string format, params object[] values)
  16. {
  17. if (_debug)
  18. Logger.Send(LogType.Information, UserID, string.Format("- RequisitionStore:" + format, values));
  19. }
  20. private bool NeedsUpdating<T>(Requisition entity, Expression<Func<Requisition, T>> property)
  21. {
  22. // If this is a new Requisition, we don't need to do anything
  23. if (entity.HasOriginalValue(x => x.ID))
  24. {
  25. var originalid = entity.GetOriginalValue(x => x.ID);
  26. if (originalid == Guid.Empty)
  27. {
  28. Log("NeedsUpdating() return false - original id is empty");
  29. return false;
  30. }
  31. }
  32. // if the Property has not changed, we don't need to do anything
  33. if (!entity.HasOriginalValue(property))
  34. {
  35. Log("NeedsUpdating() return false - {0} has not changed", property.ToString());
  36. return false;
  37. }
  38. return true;
  39. }
  40. private bool LoadRequisitionItems(Requisition entity, ref IEnumerable<RequisitionItem> requisitionitems)
  41. {
  42. if (requisitionitems == null)
  43. requisitionitems = Provider.Query(
  44. new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(entity.ID)
  45. ).Rows.Select(x => x.ToObject<RequisitionItem>());
  46. return requisitionitems.Any();
  47. }
  48. private bool LoadDeliveryItems(Requisition entity, ref IEnumerable<DeliveryItem> deliveryitems)
  49. {
  50. if (deliveryitems == null)
  51. deliveryitems = Provider.Query(
  52. new Filter<DeliveryItem>(x => x.RequisitionLink.ID).IsEqualTo(entity.ID),
  53. new Columns<DeliveryItem>(x => x.ID, x => x.DeliveredDate)
  54. ).Rows.Select(x => x.ToObject<DeliveryItem>());
  55. return deliveryitems.Any();
  56. }
  57. #region TakenBy
  58. private void UpdateTakenBy(Requisition entity, ref IEnumerable<RequisitionItem> items, ref IEnumerable<DeliveryItem> deliveryitems)
  59. {
  60. Log("UpdateTakenBy() - starting");
  61. if (!NeedsUpdating(entity, x => x.TakenBy))
  62. return;
  63. if (!LoadDeliveryItems(entity, ref deliveryitems))
  64. {
  65. Log("UpdateTakenBy() - no delivery items to update");
  66. return;
  67. }
  68. foreach (var deliveryitem in deliveryitems)
  69. if (entity.TakenBy.IsValid() && deliveryitem.DeliveredDate.IsEmpty())
  70. {
  71. Log("UpdateTakenBy() - Setting DeliveryDate");
  72. deliveryitem.DeliveredDate = DateTime.Now;
  73. }
  74. else if (!entity.TakenBy.IsValid() && !deliveryitem.DeliveredDate.IsEmpty())
  75. {
  76. Log("UpdateTakenBy() - Clearing DeliveryDate");
  77. deliveryitem.DeliveredDate = DateTime.MinValue;
  78. }
  79. var updates = deliveryitems.Where(x => x.IsChanged());
  80. if (updates.Any())
  81. FindSubStore<DeliveryItem>().Save(updates,
  82. entity.TakenBy.IsValid() ? "Requisition taken by " + entity.TakenBy.Code : "Requisition [TakenBy] has been cleared");
  83. Log("UpdateTakenBy() - done");
  84. }
  85. #endregion
  86. protected override void BeforeSave(Requisition entity)
  87. {
  88. base.BeforeSave(entity);
  89. if (entity.TakenBy.IsValid() || entity.Delivery.Completed != DateTime.MinValue || entity.Delivery.Delivered != DateTime.MinValue)
  90. {
  91. if (entity.Archived.IsEmpty())
  92. entity.Archived = DateTime.Now;
  93. }
  94. else
  95. {
  96. if (!entity.Archived.IsEmpty())
  97. entity.Archived = DateTime.MinValue;
  98. }
  99. }
  100. protected override void AfterSave(Requisition entity)
  101. {
  102. base.AfterSave(entity);
  103. IEnumerable<RequisitionItem> requisitionitems = null;
  104. IEnumerable<DeliveryItem> deliveryitems = null;
  105. UpdateDeliveryItems(entity, ref requisitionitems, ref deliveryitems);
  106. UpdateTakenBy(entity, ref requisitionitems, ref deliveryitems);
  107. UpdateStockBatches(entity, ref requisitionitems);
  108. UpdateTrackingKanban<RequisitionKanban, Requisition, RequisitionLink>(entity, e =>
  109. {
  110. if (!entity.Archived.Equals(DateTime.MinValue) || entity.TakenBy.IsValid())
  111. return KanbanCategory.Complete;
  112. if (entity.Delivery.IsValid())
  113. {
  114. if (entity.Delivery.Completed != DateTime.MinValue)
  115. {
  116. return KanbanCategory.Complete;
  117. }
  118. }
  119. if (!entity.Filled.Equals(DateTime.MinValue))
  120. return KanbanCategory.Waiting;
  121. if (Provider.Query(
  122. new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(entity.ID),
  123. new Columns<RequisitionItem>(x => x.ID)
  124. ).Rows.Any()
  125. )
  126. return KanbanCategory.InProgress;
  127. return KanbanCategory.Open;
  128. });
  129. }
  130. protected override void BeforeDelete(Requisition entity)
  131. {
  132. UnlinkTrackingKanban<RequisitionKanban, Requisition, RequisitionLink>(entity);
  133. }
  134. #region Delivery Items
  135. private void CreateDeliveryItems(Requisition entity, ref IEnumerable<RequisitionItem> requisitionitems,
  136. ref IEnumerable<DeliveryItem> deliveryitems)
  137. {
  138. if (!LoadRequisitionItems(entity, ref requisitionitems))
  139. {
  140. Log("CreateDeliveryItems() - no requisition items to update");
  141. return;
  142. }
  143. var updates = new List<DeliveryItem>();
  144. foreach (var item in requisitionitems)
  145. updates.Add(item.CreateDeliveryItem(entity));
  146. if (updates.Any())
  147. FindSubStore<DeliveryItem>().Save(updates, "Requisition [Filled] flag has been set");
  148. deliveryitems = updates;
  149. }
  150. private void ClearDeliveryItems(Requisition entity, ref IEnumerable<DeliveryItem> deliveryitems)
  151. {
  152. if (!LoadDeliveryItems(entity, ref deliveryitems))
  153. {
  154. Log("ClearDeliveryItems() - no delivery items to update");
  155. return;
  156. }
  157. if (deliveryitems.Any())
  158. FindSubStore<DeliveryItem>().Delete(deliveryitems, "Requisition [Filled] flag has been cleared");
  159. deliveryitems = new List<DeliveryItem>();
  160. }
  161. private void UpdateDeliveryItems(Requisition entity, ref IEnumerable<RequisitionItem> requisitionitems,
  162. ref IEnumerable<DeliveryItem> deliveryitems)
  163. {
  164. Log("UpdateDeliveryItems() - starting");
  165. if (!NeedsUpdating(entity, x => x.Filled))
  166. {
  167. Log("UpdateDeliveryItems() - NeedsUpdate() return false");
  168. return;
  169. }
  170. var oldfilled = entity.GetOriginalValue(x => x.Filled);
  171. var newfilled = entity.Filled;
  172. // Gone from Blank to Filled -> Create a Batch
  173. if (oldfilled.IsEmpty() && !newfilled.IsEmpty())
  174. {
  175. Log("UpdateDeliveryItems() - Filled has been set");
  176. ClearDeliveryItems(entity, ref deliveryitems);
  177. CreateDeliveryItems(entity, ref requisitionitems, ref deliveryitems);
  178. }
  179. // Gone from Filled to Blank -> Clear Out the Batch
  180. else if (newfilled.IsEmpty() && !oldfilled.IsEmpty())
  181. {
  182. Log("UpdateDeliveryItems() - Filled has been cleared");
  183. ClearDeliveryItems(entity, ref deliveryitems);
  184. }
  185. // Do nothing - filled flag has been updated, not set or cleared
  186. Log("UpdateDeliveryItems() - done");
  187. }
  188. #endregion
  189. #region StockMovements
  190. private StockMovement CreateStockMovement(Guid employeeid, DateTime date, Guid batchid, Guid productid, Guid locationid,
  191. Guid styleid, Guid jobid, double qty, IDimensions dimensions, Guid txnid, bool system, string note)
  192. {
  193. var movement = new StockMovement();
  194. movement.Batch.ID = batchid;
  195. movement.Product.ID = productid;
  196. movement.Location.ID = locationid;
  197. movement.Style.ID = styleid;
  198. movement.Job.ID = jobid;
  199. movement.Issued = qty < 0.0F ? Math.Abs(qty) : 0.0F;
  200. movement.Received = qty > 0.0F ? qty : 0.0F;
  201. movement.Type = movement.Issued > 0 ? StockMovementType.TransferOut : StockMovementType.TransferIn;
  202. movement.Qty = qty;
  203. movement.Units = qty;
  204. movement.Dimensions.CopyFrom(dimensions);
  205. movement.System = system;
  206. movement.Transaction = txnid;
  207. movement.Notes = note;
  208. movement.Date = date;
  209. movement.Employee.ID = employeeid;
  210. return movement;
  211. }
  212. private void CreateStockBatch(Requisition entity, ref IEnumerable<RequisitionItem> items)
  213. {
  214. LoadRequisitionItems(entity, ref items);
  215. if (!items.Any())
  216. {
  217. Log("CreateStockBatch() - no items to update!");
  218. return;
  219. }
  220. var batch = new StockMovementBatch
  221. {
  222. Type = StockMovementBatchType.Issue,
  223. TimeStamp = entity.Filled,
  224. Notes = string.Format("Requisition #{0}", entity.Number)
  225. };
  226. batch.Employee.ID = entity.Employee.ID;
  227. batch.Requisition.ID = entity.ID;
  228. FindSubStore<StockMovementBatch>().Save(batch, "");
  229. var updates = new List<StockMovement>();
  230. foreach (var item in items)
  231. {
  232. var locationid = item.Location.ID;
  233. var productid = item.Product.ID;
  234. var styleid = item.Style.ID;
  235. var unitsize = item.Dimensions.UnitSize;
  236. var jobid = entity.JobLink.ID;
  237. var holdings = Provider.Query<StockHolding>(
  238. new Filter<StockHolding>(x => x.Location.ID).IsEqualTo(locationid)
  239. .And(x => x.Product.ID).IsEqualTo(productid)
  240. .And(x => x.Style.ID).IsEqualTo(styleid)
  241. .And(x => x.Dimensions.UnitSize).IsEqualTo(unitsize)
  242. );
  243. var holdingrow = holdings.Rows.FirstOrDefault(r => r.Get<StockHolding, Guid>(c => c.Job.ID).Equals(jobid));
  244. if (holdingrow == null)
  245. holdingrow = holdings.Rows.FirstOrDefault(r => r.Get<StockHolding, Guid>(c => c.Job.ID).Equals(Guid.Empty));
  246. if (holdingrow == null)
  247. holdingrow = holdings.Rows.FirstOrDefault();
  248. Guid holdingjobid = holdingrow != null
  249. ? holdingrow.Get<StockHolding, Guid>(c => c.Job.ID)
  250. : Guid.Empty;
  251. var qty = item.Quantity;
  252. var dimensions = item.Product.Dimensions;
  253. var txnid = Guid.Empty;
  254. if (jobid != holdingjobid)
  255. {
  256. txnid = Guid.NewGuid();
  257. updates.Add(CreateStockMovement(entity.Employee.ID, DateTime.Now, batch.ID, productid, locationid, styleid, holdingjobid,
  258. -qty, dimensions, txnid, true, string.Format("Requisition #{0} Internal Transfer", entity.Number)));
  259. updates.Add(CreateStockMovement(entity.Employee.ID, DateTime.Now, batch.ID, productid, locationid, styleid, jobid, qty, dimensions, txnid, true,
  260. string.Format("Requisition #{0} Internal Transfer", entity.Number)));
  261. }
  262. updates.Add(CreateStockMovement(entity.Employee.ID, DateTime.Now, batch.ID, productid, locationid, styleid, jobid, 0.0F - qty, dimensions, txnid,
  263. false,
  264. string.Format("Requisition #{0}", entity.Number)));
  265. }
  266. FindSubStore<StockMovement>().Save(updates, "");
  267. }
  268. private void ClearStockBatch(Requisition entity)
  269. {
  270. Log("ClearStockBatch()");
  271. var batches = Provider.Query(
  272. new Filter<StockMovementBatch>(x => x.Requisition.ID).IsEqualTo(entity.ID),
  273. new Columns<StockMovementBatch>(x => x.ID)
  274. ).Rows.Select(x => x.ToObject<StockMovementBatch>());
  275. if (batches.Any())
  276. FindSubStore<StockMovementBatch>().Delete(batches, "");
  277. }
  278. private void UpdateStockBatches(Requisition entity, ref IEnumerable<RequisitionItem> items)
  279. {
  280. Log("UpdateStockBatch() - starting");
  281. if (!NeedsUpdating(entity, x => x.StockUpdated))
  282. return;
  283. var oldupdate = entity.GetOriginalValue(x => x.StockUpdated);
  284. var newupdate = entity.StockUpdated;
  285. // Gone from Blank to Updated -> Create a Batch
  286. if (oldupdate.IsEmpty() && !newupdate.IsEmpty())
  287. {
  288. Log("UpdateStockBatch() - creating batch");
  289. ClearStockBatch(entity);
  290. CreateStockBatch(entity, ref items);
  291. }
  292. // Gone from Updated to Blank -> Clear Out the Batch
  293. else if (newupdate.IsEmpty() && !oldupdate.IsEmpty())
  294. {
  295. Log("UpdateStockBatch() - clearing batch");
  296. ClearStockBatch(entity);
  297. }
  298. // Do nothing - Updated flag has been updated, not set or cleared
  299. Log("UpdateStockBatch() - done");
  300. }
  301. #endregion
  302. }
  303. }