public SmCalcProduct(SmScenario scenario, int modelId, SmProduct product, List <SmDenseSchedule> schedules, SmDepth depth) { ClientId = scenario.OrganisationId; ModelId = modelId; ScenarioId = scenario.ScenarioId; ProductId = product.ProductId; ProductName = product.Name; PriceLadderId = product.PriceLadder.PriceLadderId; Recommendations = new List <SmCalcRecommendation>(); HierarchyId = product.HierarchyId; HierarchyName = product.HierarchyName; ScheduleCount = schedules.Count; ScheduleCrossProductCount = 0; ScheduleProductMaskFilterCount = 0; ScheduleMaxMarkdownFilterCount = 0; ScheduleExceededFlowlineThresholdFilterCount = 0; HighPredictionCount = 0; NegativeRevenueCount = 0; InvalidMarkdownTypeCount = 0; MinimumAbsolutePriceChangeNotMetCount = 0; MinimumRelativePercentagePriceChangeNotMetCount = 0; DiscountPercentageOutsideAllowedRangeCount = 0; CurrentMarkdownCount = product.CurrentMarkdownCount; CurrentMarkdownType = product.CurrentMarkdownType; CurrentSellingPrice = product.CurrentSellingPrice; OriginalSellingPrice = product.OriginalSellingPrice; CurrentCostPrice = product.CurrentCostPrice; CurrentStock = product.CurrentStock; CurrentSalesQuantity = product.CurrentSalesQuantity; SellThroughTarget = product.SellThrough; SalesFlexFactor = product.SalesFlexFactor; MarkdownTypeConstraint = product.MarkdownTypeConstraint; MinimumAbsolutePriceChange = product.MinimumAbsolutePriceChange; MinimumRelativePercentagePriceChange = product.MinimumRelativePercentagePriceChange; MinDiscountsNew = product.MinDiscountsNew; MinDiscountsFurther = product.MinDiscountsFurther; MaxDiscountsNew = product.MaxDiscountsNew; MaxDiscountsFurther = product.MaxDiscountsFurther; CurrentMarkdownDepth = depth.MarkdownDepth; CurrentDiscountLadderDepth = depth.DiscountLadderDepth; State = ProductState.Fatal; DecisionState = scenario.DefaultDecisionState; }
// TODO return errors here to SmCalcProduct public static SmProduct Build(ILogger logger, Product entity, List <ProductHierarchy> productHierarchies, List <ProductPriceLadder> productPriceLadders, List <SmPriceLadder> priceLadders, Dictionary <int, decimal> hierarchySellThrough, Dictionary <int, Tuple <int, decimal> > productSalesTax, List <ProductParameterValues> productParameterValues, List <ProductMarkdownConstraint> productMarkdownConstraint, List <ProductSalesFlexFactor> salesFlexFactor, List <ProductMinimumAbsolutePriceChange> productMinimumAbsolutePriceChange, List <ProductWeekParameterValues> productWeekParameterValues, List <ProductWeekMarkdownTypeParameterValues> productWeekMarkdownTypeParameterValues) { if (entity == null) { return(null); } try { // TODO support multiple hierarchies var hierarchy = productHierarchies.FirstOrDefault(x => x.ProductId == entity.ProductId); if (hierarchy == null) { logger.Error("Product {ProductId} is missing a ProductHierarchy entry", entity.ProductId); return(null); } // TODO support multiple price ladders var priceLadderId = productPriceLadders.Where(x => x.ProductId == entity.ProductId) .Select(x => x.PriceLadderId).FirstOrDefault(); if (priceLadderId == 0) { logger.Error("Product {ProductId} is missing a ProductPriceLadder entry", entity.ProductId); return(null); } var ladder = priceLadders.FirstOrDefault(x => x.PriceLadderId == priceLadderId); if (ladder == null) { logger.Error("PriceLadders is missing price ladder {PriceLadderId} for product {ProductId}", priceLadderId, entity.ProductId); return(null); } var parameterValues = productParameterValues.FirstOrDefault(x => x.ProductId == entity.ProductId); var markdownTypeConstraints = productMarkdownConstraint.Where(x => x.ProductId == entity.ProductId) .GroupBy(x => new { x.ProductId, x.Week, x.MarkdownTypeId }) .OrderBy(y => y.Key.Week) .Select(y => y.Key.MarkdownTypeId) .ToArray(); var flexFactors = salesFlexFactor .Where(x => x.ProductId == entity.ProductId) .OrderBy(x => x.Week) .Select(x => x.FlexFactor) .ToArray(); if (!flexFactors.Any()) { logger.Error("Product {ProductId} is missing a SalesFlexFactor entry", entity.ProductId); return(null); } var minimumAbsolutePriceChange = productMinimumAbsolutePriceChange.FirstOrDefault(x => x.ProductId == entity.ProductId); var minimumRelativePercentagePriceChanges = productWeekParameterValues .Where(x => x.ProductId == entity.ProductId) .GroupBy(x => new { x.ProductId, x.Week, x.MinimumRelativePercentagePriceChange }) .OrderBy(y => y.Key.Week) .Select(y => y.Key.MinimumRelativePercentagePriceChange) .ToArray(); var minDiscountsNew = productWeekMarkdownTypeParameterValues .Where(x => x.ProductId == entity.ProductId && x.MarkdownTypeId == MarkdownType.New) .GroupBy(x => new { x.ProductId, x.Week, x.MarkdownTypeId, x.MinDiscountPercentage }) .OrderBy(y => y.Key.Week) .Select(y => y.Key.MinDiscountPercentage) .ToArray(); var minDiscountsFurther = productWeekMarkdownTypeParameterValues .Where(x => x.ProductId == entity.ProductId && x.MarkdownTypeId == MarkdownType.Further) .GroupBy(x => new { x.ProductId, x.Week, x.MarkdownTypeId, x.MinDiscountPercentage }) .OrderBy(y => y.Key.Week) .Select(y => y.Key.MinDiscountPercentage) .ToArray(); var maxDiscountsNew = productWeekMarkdownTypeParameterValues .Where(x => x.ProductId == entity.ProductId && x.MarkdownTypeId == MarkdownType.New) .GroupBy(x => new { x.ProductId, x.Week, x.MarkdownTypeId, x.MaxDiscountPercentage }) .OrderBy(y => y.Key.Week) .Select(y => y.Key.MaxDiscountPercentage) .ToArray(); var maxDiscountsFurther = productWeekMarkdownTypeParameterValues .Where(x => x.ProductId == entity.ProductId && x.MarkdownTypeId == MarkdownType.Further) .GroupBy(x => new { x.ProductId, x.Week, x.MarkdownTypeId, x.MaxDiscountPercentage }) .OrderBy(y => y.Key.Week) .Select(y => y.Key.MaxDiscountPercentage) .ToArray(); var result = new SmProduct { ProductId = entity.ProductId, CurrentCostPrice = entity.CurrentCostPrice, CurrentMarkdownCount = entity.CurrentMarkdownCount, CurrentSalesQuantity = entity.CurrentSalesQuantity, CurrentSellingPrice = entity.CurrentSellingPrice, CurrentStock = entity.CurrentStock, HierarchyId = hierarchy.HierarchyId, HierarchyPath = hierarchy.HierarchyPath, HierarchyName = hierarchy.HierarchyName, Name = entity.Name, OriginalSellingPrice = entity.OriginalSellingPrice, PriceLadder = SmProductPriceLadder.Build(ladder), CurrentCover = entity.CurrentCover, ProductScheduleMask = parameterValues?.Mask, ProductMaxMarkdown = parameterValues?.MaxMarkdown, SalesFlexFactor = flexFactors, MarkdownTypeConstraint = markdownTypeConstraints, MinimumAbsolutePriceChange = minimumAbsolutePriceChange.MinimumAbsolutePriceChange, MinimumRelativePercentagePriceChange = minimumRelativePercentagePriceChanges, MinDiscountsNew = minDiscountsNew, MinDiscountsFurther = minDiscountsFurther, MaxDiscountsNew = maxDiscountsNew, MaxDiscountsFurther = maxDiscountsFurther, CurrentMarkdownType = entity.CurrentMarkdownType, ProductHasExceededFlowlineThreshold = parameterValues.HasExceededFlowlineThreshold }; if (productSalesTax.TryGetValue(entity.ProductId, out Tuple <int, decimal> salesTax)) { result.SalesTax = salesTax; } if (hierarchySellThrough.TryGetValue(hierarchy.HierarchyId, out decimal sellThrough)) { result.SellThrough = sellThrough; } return(result); } catch (Exception e) { logger.Error(e, "There was an error building product {ProductId} from partition {PartitionNumber}", entity.ProductId, entity.PartitionNumber); throw; } }