using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using InABox.Core; namespace Comal.Classes { public class StockLocationHoldings : CoreAggregate { public override Expression> Aggregate => x => x.Product.ID; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { StockHolding => StockHolding.Location.ID, StockLocation => StockLocation.ID }, }; public override AggregateCalculation Calculation => AggregateCalculation.Count; } public enum StockTakeFrequency { Never, Daily, Weekly, Fortnightly, Monthly, Quarterly, TwiceYearly, Yearly } [UserTracking(typeof(StockMovement))] public class StockLocation : Entity, IRemotable, IPersistent, IStockLocation, ILicense, IExportable, IImportable { [UniqueCodeEditor(Visible = Visible.Default, Editable = Editable.Enabled)] [EditorSequence(1)] public string Code { get; set; } [TextBoxEditor] [EditorSequence(2)] public string Description { get; set; } [EntityRelationship(DeleteAction.SetNull)] [EditorSequence(3)] public StockWarehouseLink Warehouse { get; set; } private class StockAreaLookup : LookupDefinitionGenerator { public override Filter DefineFilter(StockLocation[] items) { var ids = items.Select(x => x.Warehouse.ID).Distinct().ToArray(); if (ids.Length == 1) return new Filter(x => x.Warehouse.ID).IsEqualTo(ids[0]).And(x => x.Active).IsEqualTo(true); return new Filter(x => x.ID).IsEqualTo(CoreUtils.FullGuid); } public override Columns DefineFilterColumns() => new Columns(x => x.Warehouse.ID); } [LookupDefinition(typeof(StockAreaLookup))] [EntityRelationship(DeleteAction.SetNull)] [EditorSequence(4)] public StockAreaLink Area { get; set; } [EditorSequence(5)] public JobLink Job { get; set; } /// /// Is the location a "shelf" (ie permanent) or "pack" (ie transient) /// [EnumLookupEditor(typeof(StockLocationType))] [EditorSequence(6)] public StockLocationType Type { get; set; } /// /// Is the Stock Location Active? /// [EditorSequence(7)] public bool Active { get; set; } /// /// Mark this location as the default receival location for the warehouse /// [EditorSequence(8)] public bool Default { get; set; } /// /// Mark this location as a favourite which shows up in Timebench Transfer module for quick selection /// [EditorSequence(9)] public bool Favourite { get; set; } = false; [Aggregate(typeof(StockLocationHoldings))] [DoubleEditor(Editable = Editable.Hidden)] [EditorSequence(10)] public double Holdings { get; set; } [DateEditor] [EditorSequence("Stocktake",1)] public DateTime LastStocktake { get; set; } = DateTime.MinValue; [EnumLookupEditor(typeof(StockTakeFrequency))] [EditorSequence("Stocktake",2)] public StockTakeFrequency StocktakeFrequency { get; set; } = StockTakeFrequency.Never; [DateEditor] [EditorSequence("Stocktake",3)] public DateTime NextStocktake { get; set; } = DateTime.MaxValue; [EditorSequence("Stocktake",4)] [DateEditor] public DateTime CurrentStocktake { get; set; } = DateTime.MinValue; private static DateTime CalculateNextStockTake(DateTime last, StockTakeFrequency frequency) { DateTime CheckDate(DateTime date, Func action) => date.IsEmpty() ? DateTime.Today : action(); return frequency switch { StockTakeFrequency.Daily => CheckDate(last,() => last.AddDays(1)), StockTakeFrequency.Weekly => CheckDate(last,() => last.AddDays(1)), StockTakeFrequency.Fortnightly => CheckDate(last,() => last.AddDays(1)), StockTakeFrequency.Monthly => CheckDate(last,() => last.AddMonths(1)), StockTakeFrequency.Quarterly => CheckDate(last,() => last.AddMonths(3)), StockTakeFrequency.TwiceYearly => CheckDate(last,() => last.AddMonths(6)), StockTakeFrequency.Yearly => CheckDate(last,() => last.AddYears(1)), _ => DateTime.MinValue }; } protected override void DoPropertyChanged(string name, object? before, object? after) { base.DoPropertyChanged(name, before, after); if (String.Equals(name, nameof(LastStocktake))) NextStocktake = CalculateNextStockTake((DateTime)(after ?? DateTime.MinValue), StocktakeFrequency); else if (String.Equals(name, nameof(StocktakeFrequency))) NextStocktake = CalculateNextStockTake(LastStocktake, (StockTakeFrequency)(after ?? StockTakeFrequency.Never)); } } }