RequisitionStore.cs 14 KB

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