/// <summary> /// Evaluation product prices. /// Will get either all prices or one price per currency depending on the settings in evalContext. /// </summary> /// <param name="evalContext"></param> /// <returns></returns> public virtual async Task <IEnumerable <Price> > EvaluateProductPricesAsync(PriceEvaluationContext evalContext) { if (evalContext == null) { throw new ArgumentNullException(nameof(evalContext)); } if (evalContext.ProductIds == null) { throw new MissingFieldException("ProductIds"); } var result = new List <Price>(); Price[] prices; using (var repository = _repositoryFactory()) { //Get a price range satisfying by passing context var query = repository.Prices.Include(x => x.Pricelist) .Where(x => evalContext.ProductIds.Contains(x.ProductId)) .Where(x => evalContext.Quantity >= x.MinQuantity || evalContext.Quantity == 0); if (evalContext.PricelistIds.IsNullOrEmpty()) { evalContext.PricelistIds = (await EvaluatePriceListsAsync(evalContext)).Select(x => x.Id).ToArray(); } query = query.Where(x => evalContext.PricelistIds.Contains(x.PricelistId)); // Filter by date expiration // Always filter on date, so that we limit the results to process. var certainDate = evalContext.CertainDate ?? DateTime.UtcNow; query = query.Where(x => (x.StartDate == null || x.StartDate <= certainDate) && (x.EndDate == null || x.EndDate > certainDate)); var queryResult = await query.AsNoTracking().ToArrayAsync(); prices = queryResult.Select(x => x.ToModel(AbstractTypeFactory <Price> .TryCreateInstance())).ToArray(); } //Apply pricing filtration strategy for found prices result.AddRange(_pricingPriorityFilterPolicy.FilterPrices(prices, evalContext)); //Then variation inherited prices if (_productService != null) { var productIdsWithoutPrice = evalContext.ProductIds.Except(result.Select(x => x.ProductId).Distinct()).ToArray(); //Try to inherit prices for variations from their main product //Need find products without price it may be a variation without implicitly price defined and try to get price from main product if (productIdsWithoutPrice.Any()) { var variations = (await _productService.GetByIdsAsync(productIdsWithoutPrice, ItemResponseGroup.ItemInfo.ToString())).Where(x => x.MainProductId != null).ToList(); evalContext = evalContext.Clone() as PriceEvaluationContext; evalContext.ProductIds = variations.Select(x => x.MainProductId).Distinct().ToArray(); if (!evalContext.ProductIds.IsNullOrEmpty()) { var inheritedPrices = await EvaluateProductPricesAsync(evalContext); foreach (var inheritedPrice in inheritedPrices) { foreach (var variation in variations.Where(x => x.MainProductId == inheritedPrice.ProductId)) { var variationPrice = inheritedPrice.Clone() as Price; //Reset id for correct override price in possible update variationPrice.Id = null; variationPrice.ProductId = variation.Id; result.Add(variationPrice); } } } } } return(result); }
/// <summary> /// Evaluation product prices. /// Will get either all prices or one price per currency depending on the settings in evalContext. /// </summary> /// <param name="evalContext"></param> /// <returns></returns> public virtual IEnumerable <coreModel.Price> EvaluateProductPrices(coreModel.PriceEvaluationContext evalContext) { if (evalContext == null) { throw new ArgumentNullException(nameof(evalContext)); } if (evalContext.ProductIds == null) { throw new MissingFieldException(nameof(evalContext.ProductIds)); } var retVal = new List <coreModel.Price>(); coreModel.Price[] prices; using (var repository = _repositoryFactory()) { repository.DisableChangesTracking(); //Get a price range satisfying by passing context var query = repository.Prices.Include(x => x.Pricelist) .Where(x => evalContext.ProductIds.Contains(x.ProductId)) .Where(x => evalContext.Quantity >= x.MinQuantity || evalContext.Quantity == 0); if (evalContext.PricelistIds.IsNullOrEmpty()) { evalContext.PricelistIds = EvaluatePriceLists(evalContext).Select(x => x.Id).ToArray(); } // Filter by date expiration // Always filter on date, so that we limit the results to process. var certainDate = evalContext.CertainDate ?? DateTime.UtcNow; query = query.Where(x => (x.StartDate == null || x.StartDate <= certainDate) && (x.EndDate == null || x.EndDate > certainDate)); prices = query.ToArray().Select(x => x.ToModel(AbstractTypeFactory <coreModel.Price> .TryCreateInstance())).ToArray(); } var priceListOrdererList = evalContext.PricelistIds?.ToList(); //Apply pricing filtration strategy for found prices retVal.AddRange(_pricingPriorityFilterPolicy.FilterPrices(prices, evalContext)); //Then variation inherited prices if (_productService != null) { var productIdsWithoutPrice = evalContext.ProductIds.Except(retVal.Select(x => x.ProductId).Distinct()).ToArray(); //Variation price inheritance //Need find products without price it may be a variation without implicitly price defined and try to get price from main product if (productIdsWithoutPrice.Any()) { var variations = _productService.GetByIds(productIdsWithoutPrice, Domain.Catalog.Model.ItemResponseGroup.ItemInfo).Where(x => x.MainProductId != null).ToList(); evalContext.ProductIds = variations.Select(x => x.MainProductId).Distinct().ToArray(); foreach (var inheritedPrice in EvaluateProductPrices(evalContext)) { foreach (var variation in variations.Where(x => x.MainProductId == inheritedPrice.ProductId)) { var jObject = JObject.FromObject(inheritedPrice); var variationPrice = (coreModel.Price)jObject.ToObject(inheritedPrice.GetType()); //For correct override price in possible update variationPrice.Id = null; variationPrice.ProductId = variation.Id; retVal.Add(variationPrice); } } } } return(retVal); }