/// <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);
        }
Пример #2
0
        /// <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);
        }