StockLocation.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using InABox.Core;
  6. namespace Comal.Classes
  7. {
  8. public class StockLocationHoldings : CoreAggregate<StockLocation, StockHolding, Guid>
  9. {
  10. public override Expression<Func<StockHolding, Guid>> Aggregate => x => x.Product.ID;
  11. public override Dictionary<Expression<Func<StockHolding, object>>, Expression<Func<StockLocation, object>>> Links =>
  12. new Dictionary<Expression<Func<StockHolding, object>>, Expression<Func<StockLocation, object>>>()
  13. {
  14. { StockHolding => StockHolding.Location.ID, StockLocation => StockLocation.ID },
  15. };
  16. public override AggregateCalculation Calculation => AggregateCalculation.Count;
  17. }
  18. public enum StockTakeStatus
  19. {
  20. Inactive,
  21. InProgress
  22. }
  23. public enum StockTakeFrequency
  24. {
  25. Never,
  26. Daily,
  27. Weekly,
  28. Fortnightly,
  29. Monthly,
  30. Quarterly,
  31. TwiceYearly,
  32. Yearly
  33. }
  34. [UserTracking(typeof(StockMovement))]
  35. public class StockLocation : Entity, IRemotable, IPersistent, IStockLocation, ILicense<WarehouseLicense>, IExportable, IImportable
  36. {
  37. [UniqueCodeEditor(Visible = Visible.Default, Editable = Editable.Enabled)]
  38. [EditorSequence(1)]
  39. public string Code { get; set; }
  40. [TextBoxEditor]
  41. [EditorSequence(2)]
  42. public string Description { get; set; }
  43. [EntityRelationship(DeleteAction.SetNull)]
  44. [EditorSequence(3)]
  45. public StockWarehouseLink Warehouse { get; set; }
  46. private class StockAreaLookup : LookupDefinitionGenerator<StockArea, StockLocation>
  47. {
  48. public override Filter<StockArea> DefineFilter(StockLocation[] items)
  49. {
  50. var ids = items.Select(x => x.Warehouse.ID).Distinct().ToArray();
  51. if (ids.Length == 1)
  52. return new Filter<StockArea>(x => x.Warehouse.ID).IsEqualTo(ids[0]).And(x => x.Active).IsEqualTo(true);
  53. return new Filter<StockArea>(x => x.ID).IsEqualTo(CoreUtils.FullGuid);
  54. }
  55. public override Columns<StockLocation> DefineFilterColumns()
  56. => new Columns<StockLocation>(x => x.Warehouse.ID);
  57. }
  58. [LookupDefinition(typeof(StockAreaLookup))]
  59. [EntityRelationship(DeleteAction.SetNull)]
  60. [EditorSequence(4)]
  61. public StockAreaLink Area { get; set; }
  62. [EditorSequence(5)]
  63. public JobLink Job { get; set; }
  64. /// <summary>
  65. /// Is the location a "shelf" (ie permanent) or "pack" (ie transient)
  66. /// </summary>
  67. [EnumLookupEditor(typeof(StockLocationType))]
  68. [EditorSequence(6)]
  69. public StockLocationType Type { get; set; }
  70. /// <summary>
  71. /// Is the Stock Location Active?
  72. /// </summary>
  73. [EditorSequence(7)]
  74. public bool Active { get; set; }
  75. /// <summary>
  76. /// Mark this location as the default receival location for the warehouse
  77. /// </summary>
  78. [EditorSequence(8)]
  79. public bool Default { get; set; }
  80. /// <summary>
  81. /// Mark this location as a favourite which shows up in Timebench Transfer module for quick selection
  82. /// </summary>
  83. [EditorSequence(9)]
  84. public bool Favourite { get; set; } = false;
  85. [Aggregate(typeof(StockLocationHoldings))]
  86. [DoubleEditor(Editable = Editable.Hidden)]
  87. [EditorSequence(10)]
  88. public double Holdings { get; set; }
  89. [EnumLookupEditor(typeof(StockTakeStatus))]
  90. [EditorSequence(11)]
  91. public StockTakeStatus StocktakeStatus { get; set; } = StockTakeStatus.Inactive;
  92. [DateEditor]
  93. [EditorSequence(12)]
  94. public DateTime LastStocktake { get; set; } = DateTime.MinValue;
  95. [EnumLookupEditor(typeof(StockTakeFrequency))]
  96. [EditorSequence(13)]
  97. public StockTakeFrequency StocktakeFrequency { get; set; } = StockTakeFrequency.Never;
  98. [DateEditor(Editable = Editable.Disabled)]
  99. [EditorSequence(12)]
  100. public DateTime NextStocktake { get; set; } = DateTime.MaxValue;
  101. private static DateTime CalculateNextStockTake(DateTime last, StockTakeFrequency frequency)
  102. {
  103. if (frequency == StockTakeFrequency.Never)
  104. return DateTime.MaxValue;
  105. if (last.IsEmpty())
  106. return DateTime.Today;
  107. return frequency switch
  108. {
  109. StockTakeFrequency.Daily => last.AddDays(1),
  110. StockTakeFrequency.Weekly => last.AddDays(7),
  111. StockTakeFrequency.Fortnightly => last.AddDays(14),
  112. StockTakeFrequency.Monthly => last.AddMonths(1),
  113. StockTakeFrequency.Quarterly => last.AddMonths(3),
  114. StockTakeFrequency.TwiceYearly => last.AddMonths(6),
  115. StockTakeFrequency.Yearly => last.AddYears(1),
  116. _ => DateTime.MaxValue
  117. };
  118. }
  119. protected override void DoPropertyChanged(string name, object? before, object? after)
  120. {
  121. base.DoPropertyChanged(name, before, after);
  122. if (String.Equals(name, nameof(LastStocktake)))
  123. NextStocktake = CalculateNextStockTake((DateTime)(after ?? DateTime.MinValue), StocktakeFrequency);
  124. else if (String.Equals(name, nameof(StocktakeFrequency)))
  125. NextStocktake = CalculateNextStockTake(LastStocktake, (StockTakeFrequency)(after ?? StockTakeFrequency.Never));
  126. }
  127. }
  128. }