|
@@ -1,388 +0,0 @@
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
-using System.Linq;
|
|
|
-using System.Linq.Expressions;
|
|
|
-using InABox.Core;
|
|
|
-using PRSClasses;
|
|
|
-
|
|
|
-namespace Comal.Classes
|
|
|
-{
|
|
|
-
|
|
|
- // public class StockHoldingUnitAggregate : CoreAggregate<StockHolding, StockMovement, double>
|
|
|
- // {
|
|
|
- // public override Expression<Func<StockMovement, double>> Aggregate => x => x.Units;
|
|
|
- //
|
|
|
- // public override Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<StockHolding, object>>> Links =>
|
|
|
- // new Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<StockHolding, object>>>()
|
|
|
- // {
|
|
|
- // { StockMovement => StockMovement.Product.ID, StockHolding => StockHolding.Product.ID },
|
|
|
- // { StockMovement => StockMovement.Job.ID, StockHolding => StockHolding.Job.ID },
|
|
|
- // { StockMovement => StockMovement.Location.ID, StockHolding => StockHolding.Location.ID },
|
|
|
- // { StockMovement => StockMovement.Style.ID, StockHolding => StockHolding.Style.ID },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Unit.ID, StockHolding => StockHolding.Dimensions.Unit.ID },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Quantity, StockHolding => StockHolding.Dimensions.Quantity },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Length, StockHolding => StockHolding.Dimensions.Length },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Width, StockHolding => StockHolding.Dimensions.Width },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Height, StockHolding => StockHolding.Dimensions.Height },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Weight, StockHolding => StockHolding.Dimensions.Weight },
|
|
|
- // };
|
|
|
- //
|
|
|
- // public override AggregateCalculation Calculation => AggregateCalculation.Sum;
|
|
|
- // }
|
|
|
- //
|
|
|
- // public class StockHoldingValueAggregate : CoreAggregate<StockHolding, StockMovement, double>
|
|
|
- // {
|
|
|
- // public override Expression<Func<StockMovement, double>> Aggregate => x => x.Value;
|
|
|
- //
|
|
|
- // public override Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<StockHolding, object>>> Links =>
|
|
|
- // new Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<StockHolding, object>>>()
|
|
|
- // {
|
|
|
- // { StockMovement => StockMovement.Product.ID, StockHolding => StockHolding.Product.ID },
|
|
|
- // { StockMovement => StockMovement.Job.ID, StockHolding => StockHolding.Job.ID },
|
|
|
- // { StockMovement => StockMovement.Location.ID, StockHolding => StockHolding.Location.ID },
|
|
|
- // { StockMovement => StockMovement.Style.ID, StockHolding => StockHolding.Style.ID },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Unit.ID, StockHolding => StockHolding.Dimensions.Unit.ID },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Quantity, StockHolding => StockHolding.Dimensions.Quantity },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Length, StockHolding => StockHolding.Dimensions.Length },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Width, StockHolding => StockHolding.Dimensions.Width },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Height, StockHolding => StockHolding.Dimensions.Height },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Weight, StockHolding => StockHolding.Dimensions.Weight },
|
|
|
- // };
|
|
|
- //
|
|
|
- // public override AggregateCalculation Calculation => AggregateCalculation.Sum;
|
|
|
- // }
|
|
|
- //
|
|
|
- // public class StockHoldingAverageValueFormula : IFormula<StockHolding, double>
|
|
|
- // {
|
|
|
- // public Expression<Func<StockHolding, double>> Value => x => x.Value;
|
|
|
- //
|
|
|
- // public Expression<Func<StockHolding, double>>[] Modifiers => new Expression<Func<StockHolding, double>>[] { x => x.Units };
|
|
|
- //
|
|
|
- // public FormulaOperator Operator => FormulaOperator.Divide;
|
|
|
- //
|
|
|
- // public FormulaType Type => FormulaType.Virtual;
|
|
|
- // }
|
|
|
- //
|
|
|
- // public class StockHoldingQuantityAggregate : CoreAggregate<StockHolding, StockMovement, double>
|
|
|
- // {
|
|
|
- // public override Expression<Func<StockMovement, double>> Aggregate => x => x.Qty;
|
|
|
- //
|
|
|
- // public override Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<StockHolding, object>>> Links =>
|
|
|
- // new Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<StockHolding, object>>>()
|
|
|
- // {
|
|
|
- // { StockMovement => StockMovement.Product.ID, StockHolding => StockHolding.Product.ID },
|
|
|
- // { StockMovement => StockMovement.Job.ID, StockHolding => StockHolding.Job.ID },
|
|
|
- // { StockMovement => StockMovement.Location.ID, StockHolding => StockHolding.Location.ID },
|
|
|
- // { StockMovement => StockMovement.Style.ID, StockHolding => StockHolding.Style.ID },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Unit.ID, StockHolding => StockHolding.Dimensions.Unit.ID },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Quantity, StockHolding => StockHolding.Dimensions.Quantity },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Length, StockHolding => StockHolding.Dimensions.Length },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Width, StockHolding => StockHolding.Dimensions.Width },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Height, StockHolding => StockHolding.Dimensions.Height },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Weight, StockHolding => StockHolding.Dimensions.Weight },
|
|
|
- // };
|
|
|
- //
|
|
|
- // public override AggregateCalculation Calculation => AggregateCalculation.Sum;
|
|
|
- // }
|
|
|
-
|
|
|
-
|
|
|
- // public class StockHoldingAvailableAggregate : CoreAggregate<StockHolding, StockMovement, double>
|
|
|
- // {
|
|
|
- // public override Expression<Func<StockMovement, double>> Aggregate => x => x.Units;
|
|
|
- //
|
|
|
- // public override Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<StockHolding, object>>> Links =>
|
|
|
- // new Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<StockHolding, object>>>()
|
|
|
- // {
|
|
|
- // { StockMovement => StockMovement.Product.ID, StockHolding => StockHolding.Product.ID },
|
|
|
- // { StockMovement => StockMovement.Job.ID, StockHolding => StockHolding.Job.ID },
|
|
|
- // { StockMovement => StockMovement.Location.ID, StockHolding => StockHolding.Location.ID },
|
|
|
- // { StockMovement => StockMovement.Style.ID, StockHolding => StockHolding.Style.ID },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Unit.ID, StockHolding => StockHolding.Dimensions.Unit.ID },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Quantity, StockHolding => StockHolding.Dimensions.Quantity },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Length, StockHolding => StockHolding.Dimensions.Length },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Width, StockHolding => StockHolding.Dimensions.Width },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Height, StockHolding => StockHolding.Dimensions.Height },
|
|
|
- // { StockMovement => StockMovement.Dimensions.Weight, StockHolding => StockHolding.Dimensions.Weight },
|
|
|
- // };
|
|
|
- //
|
|
|
- // public override AggregateCalculation Calculation => AggregateCalculation.Sum;
|
|
|
- //
|
|
|
- // public override Filter<StockMovement>? Filter => new Filter<StockMovement>(x => x.JobRequisitionItem.ID).IsEqualTo(Guid.Empty);
|
|
|
- // }
|
|
|
-
|
|
|
- // public class StockHoldingWeightFormula : IFormula<StockHolding, double>
|
|
|
- // {
|
|
|
- // public Expression<Func<StockHolding, double>> Value => x => x.Qty;
|
|
|
- //
|
|
|
- // public Expression<Func<StockHolding, double>>[] Modifiers => new Expression<Func<StockHolding, double>>[] { x => x.Dimensions.Weight };
|
|
|
- //
|
|
|
- // public FormulaOperator Operator => FormulaOperator.Multiply;
|
|
|
- //
|
|
|
- // public FormulaType Type => FormulaType.Virtual;
|
|
|
- // }
|
|
|
- //
|
|
|
- // public class StockHoldingIsRemnantCondition : ICondition<StockHolding, double, object>
|
|
|
- // {
|
|
|
- // public Expression<Func<StockHolding, double>> Left => x => x.Dimensions.Value;
|
|
|
- //
|
|
|
- // public Condition Condition => Condition.LessThan;
|
|
|
- //
|
|
|
- // public Expression<Func<StockHolding, double>> Right => x => x.Product.DefaultInstance.Dimensions.Value;
|
|
|
- //
|
|
|
- // public Expression<Func<StockHolding, object>> True => x => true;
|
|
|
- //
|
|
|
- // public Expression<Func<StockHolding, object>> False => x => null;
|
|
|
- //
|
|
|
- // public ConditionType Type => ConditionType.Virtual;
|
|
|
- // }
|
|
|
-
|
|
|
- // public class StockHoldingUnionGenerator : AutoEntityUnionGenerator<IStockHolding>
|
|
|
- // {
|
|
|
- // protected override void Configure()
|
|
|
- // {
|
|
|
- // AddTable<StockMovement>();
|
|
|
- // }
|
|
|
- //
|
|
|
- // public override bool Distinct => true;
|
|
|
- //
|
|
|
- // public override Column<IStockHolding>[] IDColumns => Columns;
|
|
|
- //
|
|
|
- // public static Column<IStockHolding>[] Columns => new Column<IStockHolding>[]
|
|
|
- // {
|
|
|
- // new Column<IStockHolding>(x => x.Job.ID),
|
|
|
- // new Column<IStockHolding>(x => x.Location.ID),
|
|
|
- // new Column<IStockHolding>(x => x.Product.ID),
|
|
|
- // new Column<IStockHolding>(x => x.Style.ID),
|
|
|
- // new Column<IStockHolding>(x => x.Dimensions.Unit.ID),
|
|
|
- // new Column<IStockHolding>(x => x.Dimensions.Quantity),
|
|
|
- // new Column<IStockHolding>(x => x.Dimensions.Length),
|
|
|
- // new Column<IStockHolding>(x => x.Dimensions.Width),
|
|
|
- // new Column<IStockHolding>(x => x.Dimensions.Height),
|
|
|
- // new Column<IStockHolding>(x => x.Dimensions.Weight),
|
|
|
- // };
|
|
|
- //
|
|
|
- // public static Filter<StockMovement>? GetFilter(IStockHolding holding)
|
|
|
- // {
|
|
|
- // var filter = new Filters<StockMovement>();
|
|
|
- //
|
|
|
- // foreach(var column in Columns)
|
|
|
- // {
|
|
|
- // filter.Add(new Filter<StockMovement>(column.Cast<StockMovement>()).IsEqualTo(CoreUtils.GetPropertyValue(holding, column.Property)));
|
|
|
- // }
|
|
|
- //
|
|
|
- // return filter.Combine();
|
|
|
- // }
|
|
|
- // }
|
|
|
- //
|
|
|
- // [UserTracking(typeof(StockMovement))]
|
|
|
- // [AutoEntity(typeof(StockHoldingUnionGenerator))]
|
|
|
- // public class StockHoldingView : StockEntity, IRemotable, IPersistent, IOneToMany<StockLocation>, IOneToMany<Product>,
|
|
|
- // IStockHolding, ILicense<WarehouseLicense>
|
|
|
- // {
|
|
|
- //
|
|
|
- // public override ProductLink Product { get; set; }
|
|
|
- //
|
|
|
- // public ProductStyleLink Style { get; set; }
|
|
|
- //
|
|
|
- // public StockLocationLink Location { get; set; }
|
|
|
- //
|
|
|
- // public JobLink Job { get; set; }
|
|
|
- //
|
|
|
- // [RequiredColumn]
|
|
|
- // [DimensionsEditor(typeof(StockDimensions), AllowEditingUnit = false)]
|
|
|
- // public override StockDimensions Dimensions { get; set; }
|
|
|
- //
|
|
|
- // [Condition(typeof(StockHoldingIsRemnantCondition))]
|
|
|
- // [NullEditor]
|
|
|
- // public bool IsRemnant { get; set; }
|
|
|
- //
|
|
|
- // [Aggregate(typeof(StockHoldingUnitAggregate))]
|
|
|
- // [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- // public double Units { get; set; }
|
|
|
- //
|
|
|
- // [Aggregate(typeof(StockHoldingQuantityAggregate))]
|
|
|
- // [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- // public double Qty { get; set; }
|
|
|
- //
|
|
|
- // [Formula(typeof(StockHoldingWeightFormula))]
|
|
|
- // [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- // public double Weight { get; set; }
|
|
|
- //
|
|
|
- // [Aggregate(typeof(StockHoldingValueAggregate))]
|
|
|
- // [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- // public double Value { get; set; }
|
|
|
- //
|
|
|
- // [Formula(typeof(StockHoldingAverageValueFormula))]
|
|
|
- // [DoubleEditor(Editable = Editable.Disabled)]
|
|
|
- // public double AverageValue { get; set; }
|
|
|
- // }
|
|
|
-
|
|
|
- // FV 6/2/24: This used to be a view (see above), but we were running into performance issues trying to
|
|
|
- // get aggregates fof stock locations (ie show me how many holdings in a given location was taking upwrds of
|
|
|
- // 20 seconds. Have moved update logic to StockHoldingStore / StockMovementStore so updates are a bit slower,
|
|
|
- // but reads are now much faster.
|
|
|
- [UserTracking(typeof(StockMovement))]
|
|
|
- [Unrecoverable]
|
|
|
- public class StockHolding : StockEntity, IRemotable, IPersistent, IOneToMany<StockLocation>, IOneToMany<Product>,
|
|
|
- IStockHolding, ILicense<WarehouseLicense>
|
|
|
- {
|
|
|
-
|
|
|
- [Editable(Editable.Disabled)]
|
|
|
- [EditorSequence(1)]
|
|
|
- public StockLocationLink Location { get; set; }
|
|
|
-
|
|
|
- private class ProductLookupGenerator : LookupDefinitionGenerator<Product, StockHolding>
|
|
|
- {
|
|
|
- public override Filter<Product>? DefineFilter(StockHolding[] items)
|
|
|
- => LookupFactory.DefineFilter<Product>().And(x => x.NonStock).IsEqualTo(false);
|
|
|
- }
|
|
|
- [Editable(Editable.Disabled)]
|
|
|
- [EditorSequence(2)]
|
|
|
- [LookupDefinition(typeof(ProductLookupGenerator))]
|
|
|
- public override ProductLink Product { get; set; }
|
|
|
-
|
|
|
- [DimensionsEditor(typeof(StockDimensions), AllowEditingUnit = false)]
|
|
|
- [Editable(Editable.Disabled)]
|
|
|
- [EditorSequence(3)]
|
|
|
- public override StockDimensions Dimensions { get; set; }
|
|
|
-
|
|
|
- [Editable(Editable.Disabled)]
|
|
|
- [EditorSequence(4)]
|
|
|
- public ProductStyleLink Style { get; set; }
|
|
|
-
|
|
|
- [Editable(Editable.Disabled)]
|
|
|
- [EditorSequence(4)]
|
|
|
- public JobLink Job { get; set; }
|
|
|
-
|
|
|
- [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- [EditorSequence(5)]
|
|
|
- public double Units { get; set; }
|
|
|
-
|
|
|
- [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- [EditorSequence(6)]
|
|
|
- public double Qty { get; set; }
|
|
|
-
|
|
|
- [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- [EditorSequence(7)]
|
|
|
- public double Weight { get; set; }
|
|
|
-
|
|
|
- [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- [EditorSequence(8)]
|
|
|
- public double Value { get; set; }
|
|
|
-
|
|
|
- [DoubleEditor(Editable = Editable.Disabled)]
|
|
|
- [EditorSequence(9)]
|
|
|
- public double AverageValue { get; set; }
|
|
|
-
|
|
|
- [DoubleEditor(Editable = Editable.Disabled, Summary = Summary.Sum)]
|
|
|
- [EditorSequence(10)]
|
|
|
- public double Available { get; set; }
|
|
|
-
|
|
|
- public static Column<IStockHolding>[] Columns => new Column<IStockHolding>[]
|
|
|
- {
|
|
|
- new Column<IStockHolding>(x => x.Job.ID),
|
|
|
- new Column<IStockHolding>(x => x.Location.ID),
|
|
|
- new Column<IStockHolding>(x => x.Product.ID),
|
|
|
- new Column<IStockHolding>(x => x.Style.ID),
|
|
|
- new Column<IStockHolding>(x => x.Dimensions.Unit.ID),
|
|
|
- new Column<IStockHolding>(x => x.Dimensions.Quantity),
|
|
|
- new Column<IStockHolding>(x => x.Dimensions.Length),
|
|
|
- new Column<IStockHolding>(x => x.Dimensions.Width),
|
|
|
- new Column<IStockHolding>(x => x.Dimensions.Height),
|
|
|
- new Column<IStockHolding>(x => x.Dimensions.Weight),
|
|
|
- };
|
|
|
-
|
|
|
- public static Filter<StockMovement>? GetFilter(IStockHolding holding)
|
|
|
- {
|
|
|
- var filter = new Filters<StockMovement>();
|
|
|
-
|
|
|
- foreach(var column in Columns)
|
|
|
- {
|
|
|
- filter.Add(new Filter<StockMovement>(column.Cast<StockMovement>()).IsEqualTo(CoreUtils.GetPropertyValue(holding, column.Property)));
|
|
|
- }
|
|
|
-
|
|
|
- return filter.Combine();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public static class StockHoldingExtensions
|
|
|
- {
|
|
|
- /// <summary>
|
|
|
- /// Create a new stock movement from an <see cref="IStockHolding"/>, copying across the "key" properties;
|
|
|
- /// that is, the job, product, style, location and dimensions.
|
|
|
- /// </summary>
|
|
|
- /// <param name="holding"></param>
|
|
|
- /// <returns></returns>
|
|
|
- public static StockMovement CreateMovement(this IStockHolding holding)
|
|
|
- {
|
|
|
- var movement = new StockMovement();
|
|
|
- movement.Job.ID = holding.Job.ID;
|
|
|
- movement.Job.Synchronise(holding.Job);
|
|
|
- movement.Product.ID = holding.Product.ID;
|
|
|
- movement.Product.Synchronise(holding.Product);
|
|
|
- movement.Style.ID = holding.Style.ID;
|
|
|
- movement.Style.Synchronise(holding.Style);
|
|
|
- movement.Location.ID = holding.Location.ID;
|
|
|
- movement.Location.Synchronise(holding.Location);
|
|
|
- movement.Dimensions.CopyFrom(holding.Dimensions);
|
|
|
- return movement;
|
|
|
- }
|
|
|
-
|
|
|
- public static IEnumerable<StockHolding> GroupMovements(IEnumerable<StockMovement> movements)
|
|
|
- {
|
|
|
- var grouped = new List<StockHolding>();
|
|
|
-
|
|
|
- var toGroup = movements.AsList();
|
|
|
- while (toGroup.Count > 0)
|
|
|
- {
|
|
|
- var first = toGroup.First();
|
|
|
- var selected = toGroup.Where(x => x.IsEqualTo(first)).ToList();
|
|
|
-
|
|
|
- var holding = grouped.FirstOrDefault(x => x.IsEqualTo(first));
|
|
|
- if (holding == null)
|
|
|
- {
|
|
|
- holding = new StockHolding();
|
|
|
- holding.Location.ID = first.Location.ID;
|
|
|
- holding.Product.ID = first.Product.ID;
|
|
|
- holding.Style.ID = first.Style.ID;
|
|
|
- holding.Job.ID = first.Job.ID;
|
|
|
- holding.Dimensions.CopyFrom(first.Dimensions);
|
|
|
- }
|
|
|
- holding.Recalculate(selected);
|
|
|
-
|
|
|
- toGroup.RemoveAll(x => selected.Any(s => s.ID == x.ID));
|
|
|
- }
|
|
|
- return grouped;
|
|
|
- }
|
|
|
-
|
|
|
- public static bool IsEqualTo(this IStockHolding h1, IStockHolding h2)
|
|
|
- {
|
|
|
- return h1.Product.ID == h2.Product.ID
|
|
|
- && h1.Location.ID == h2.Location.ID
|
|
|
- && h1.Job.ID == h2.Job.ID
|
|
|
- && h1.Style.ID == h2.Style.ID
|
|
|
- && h1.Dimensions.Unit.ID == h2.Dimensions.Unit.ID
|
|
|
- && h1.Dimensions.Length.IsEffectivelyEqual(h2.Dimensions.Length)
|
|
|
- && h1.Dimensions.Width.IsEffectivelyEqual(h2.Dimensions.Width)
|
|
|
- && h1.Dimensions.Height.IsEffectivelyEqual(h2.Dimensions.Height)
|
|
|
- && h1.Dimensions.Quantity.IsEffectivelyEqual(h2.Dimensions.Quantity)
|
|
|
- && h1.Dimensions.Weight.IsEffectivelyEqual(h2.Dimensions.Weight);
|
|
|
- }
|
|
|
-
|
|
|
- public static void Recalculate(this StockHolding holding, IEnumerable<StockMovement> movements)
|
|
|
- {
|
|
|
- movements = movements.AsIList();
|
|
|
- var units = movements.Sum(x => x.Units);
|
|
|
- var cost = movements.Select(x => x.Units * x.Cost).Sum();
|
|
|
- var available = movements.Where(x => x.JobRequisitionItem.ID == Guid.Empty).Sum(x => x.Units);
|
|
|
- holding.Units = units;
|
|
|
- holding.Available = available;
|
|
|
- holding.Qty = movements.Sum(x => x.Units * x.Dimensions.Value);
|
|
|
- holding.Value = cost;
|
|
|
-
|
|
|
- holding.AverageValue = units.IsEffectivelyEqual(0.0F) ? 0.0d : cost / units;
|
|
|
- holding.Weight = holding.Qty * holding.Dimensions.Weight;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-}
|