コード例 #1
0
        public IEnumerable <coreModel.Pricelist> EvaluatePriceLists(coreModel.PriceEvaluationContext evalContext)
        {
            IEnumerable <coreModel.Pricelist> retVal;

            using (var repository = _repositoryFactory())
            {
                var query = repository.PricelistAssignments.Include(x => x.Pricelist);

                //filter by catalog
                query = query.Where(x => (x.CatalogId == evalContext.CatalogId));

                if (evalContext.Currency != null)
                {
                    //filter by currency
                    query = query.Where(x => x.Pricelist.Currency == evalContext.Currency.ToString());
                }
                if (evalContext.CertainDate != null)
                {
                    //filter by date expiration
                    query = query.Where(x => (x.StartDate == null || evalContext.CertainDate >= x.StartDate) && (x.EndDate == null || x.EndDate >= evalContext.CertainDate));
                }
                // sort content by type and priority
                retVal = query.OrderByDescending(x => x.Priority).ThenByDescending(x => x.Name)
                         .ToArray().Select(x => x.Pricelist.ToCoreModel());
            }

            return(retVal);
        }
コード例 #2
0
        public IHttpActionResult EvaluatePrices([ModelBinder(typeof(PriceEvaluationContextBinder))] coreModel.PriceEvaluationContext evalContext)
        {
            var retVal = _pricingService.EvaluateProductPrices(evalContext)
                         .Select(x => x.ToWebModel())
                         .ToArray();

            return(Ok(retVal));
        }
コード例 #3
0
        public IHttpActionResult EvaluatePriceLists(coreModel.PriceEvaluationContext evalContext)
        {
            var retVal = _pricingService.EvaluatePriceLists(evalContext)
                         .Select(x => x.ToWebModel())
                         .ToArray();

            return(Ok(retVal));
        }
コード例 #4
0
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(coreModel.PriceEvaluationContext))
            {
                return(false);
            }

            var qs = HttpUtility.ParseQueryString(actionContext.Request.RequestUri.Query as string);

            var result = new coreModel.PriceEvaluationContext();

            result.StoreId = qs.Get("store") ?? qs.Get("evalContext.storeId");

            result.CatalogId  = qs.Get("catalog") ?? qs.Get("evalContext.catalogId");
            result.ProductIds = qs.GetValues("products");
            if (result.ProductIds == null)
            {
                var productIds = qs.Get("evalContext.productIds");
                if (!String.IsNullOrEmpty(productIds))
                {
                    result.ProductIds = productIds.Split(',');
                }
            }

            result.PricelistIds = qs.GetValues("pricelists");
            if (result.PricelistIds == null)
            {
                var pricelistIds = qs.Get("evalContext.pricelistIds");
                if (!String.IsNullOrEmpty(pricelistIds))
                {
                    result.PricelistIds = pricelistIds.Split(',');
                }
            }

            var currency = qs.Get("currency") ?? qs.Get("evalContext.currency");

            if (currency != null)
            {
                result.Currency = EnumUtility.SafeParse(currency, CurrencyCodes.USD);
            }
            result.Quantity       = qs.GetValue <decimal>("quantity", 0);
            result.CustomerId     = qs.Get("customer") ?? qs.Get("evalContext.customerId");
            result.OrganizationId = qs.Get("organization");
            var certainDate = qs.Get("date");

            if (certainDate != null)
            {
                result.CertainDate = Convert.ToDateTime(certainDate, CultureInfo.InvariantCulture);
            }

            bindingContext.Model = result;
            return(true);
        }
コード例 #5
0
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(coreModel.PriceEvaluationContext))
            {
                return false;
            }

            var qs = HttpUtility.ParseQueryString(actionContext.Request.RequestUri.Query as string);

            var result = new coreModel.PriceEvaluationContext();

            result.StoreId = qs.Get("store") ?? qs.Get("evalContext.storeId");

            result.CatalogId = qs.Get("catalog") ?? qs.Get("evalContext.catalogId");
            result.ProductIds = qs.GetValues("products");
            if(result.ProductIds == null)
            {
                var productIds = qs.Get("evalContext.productIds");
                if(!String.IsNullOrEmpty(productIds))
                {
                    result.ProductIds = productIds.Split(',');
                }
            }
         
            result.PricelistIds = qs.GetValues("pricelists");
            if (result.PricelistIds == null)
            {
                var pricelistIds = qs.Get("evalContext.pricelistIds");
                if (!String.IsNullOrEmpty(pricelistIds))
                {
                    result.PricelistIds = pricelistIds.Split(',');
                }
            }

            var currency = qs.Get("currency") ?? qs.Get("evalContext.currency");
            if (currency != null)
            {
                result.Currency = EnumUtility.SafeParse(currency, CurrencyCodes.USD);
            }
            result.Quantity = qs.GetValue<decimal>("quantity", 0);
            result.CustomerId = qs.Get("customer") ?? qs.Get("evalContext.customerId");
            result.OrganizationId = qs.Get("organization");
            var certainDate = qs.Get("date");
            if(certainDate != null)
            {
                result.CertainDate = Convert.ToDateTime(certainDate, CultureInfo.InvariantCulture);
            }

            bindingContext.Model = result;
            return true;
        } 
コード例 #6
0
        public IEnumerable <coreModel.Pricelist> EvaluatePriceLists(coreModel.PriceEvaluationContext evalContext)
        {
            var retVal = new List <coreModel.Pricelist>();

            using (var repository = _repositoryFactory())
            {
                var query = repository.PricelistAssignments.Include(x => x.Pricelist);

                //filter by catalog
                query = query.Where(x => (x.CatalogId == evalContext.CatalogId));

                if (evalContext.Currency != null)
                {
                    //filter by currency
                    query = query.Where(x => x.Pricelist.Currency == evalContext.Currency.ToString());
                }
                if (evalContext.CertainDate != null)
                {
                    //filter by date expiration
                    query = query.Where(x => (x.StartDate == null || evalContext.CertainDate >= x.StartDate) && (x.EndDate == null || x.EndDate >= evalContext.CertainDate));
                }
                var assinments = query.OrderByDescending(x => x.Priority).ThenByDescending(x => x.Name).ToArray();
                retVal.AddRange(assinments.Where(x => x.ConditionExpression == null).Select(x => x.Pricelist.ToCoreModel()));

                foreach (var assignment in assinments.Where(x => x.ConditionExpression != null))
                {
                    try
                    {
                        //Next step need filter assignments contains dynamicexpression
                        var condition = SerializationUtil.DeserializeExpression <Func <IEvaluationContext, bool> >(assignment.ConditionExpression);
                        if (condition(evalContext))
                        {
                            retVal.Add(assignment.Pricelist.ToCoreModel());
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex);
                    }
                }
            }

            return(retVal);
        }
コード例 #7
0
		public void DoExport(Stream outStream, CsvExportInfo exportInfo, Action<ExportImportProgressInfo> progressCallback)
		{
			var prodgressInfo = new ExportImportProgressInfo
			{
				Description = "loading products..."
			};

			var streamWriter = new StreamWriter(outStream, Encoding.UTF8, 1024, true);
			streamWriter.AutoFlush = true;

			using (var csvWriter = new CsvWriter(streamWriter))
			{
				//Notification
				progressCallback(prodgressInfo);

				//Load all products to export
				var products = LoadProducts(exportInfo.CatalogId, exportInfo.CategoryIds, exportInfo.ProductIds);
				var allProductIds = products.Select(x => x.Id).ToArray();

				//Load prices for products
				var allProductPrices = new List<Price>();

				prodgressInfo.Description = "loading prices...";
				progressCallback(prodgressInfo);

				var priceEvalContext = new PriceEvaluationContext
				{
					ProductIds = allProductIds,
					PricelistIds = exportInfo.PriceListId == null ? null : new string[] { exportInfo.PriceListId },
					Currency = exportInfo.Currency
				};
				allProductPrices = _pricingService.EvaluateProductPrices(priceEvalContext).ToList();


				//Load inventories
				var allProductInventories = new List<InventoryInfo>();

				prodgressInfo.Description = "loading inventory information...";
				progressCallback(prodgressInfo);

				allProductInventories = _inventoryService.GetProductsInventoryInfos(allProductIds).Where(x => exportInfo.FulfilmentCenterId == null ? true : x.FulfillmentCenterId == exportInfo.FulfilmentCenterId).ToList();


				//Export configuration
				exportInfo.Configuration.PropertyCsvColumns = products.SelectMany(x => x.PropertyValues).Select(x => x.PropertyName).Distinct().ToArray();

				csvWriter.Configuration.Delimiter = exportInfo.Configuration.Delimiter;
				csvWriter.Configuration.RegisterClassMap(new CsvProductMap(exportInfo.Configuration));

				//Write header
				csvWriter.WriteHeader<CsvProduct>();

				prodgressInfo.TotalCount = products.Count();
				var notifyProductSizeLimit = 50;
				var counter = 0;
				foreach (var product in products)
				{
					try
					{
						var csvProduct = new CsvProduct(product, _blobUrlResolver, allProductPrices.FirstOrDefault(x => x.ProductId == product.Id), allProductInventories.FirstOrDefault(x => x.ProductId == product.Id));
						csvWriter.WriteRecord(csvProduct);
					}
					catch (Exception ex)
					{
						prodgressInfo.Errors.Add(ex.ToString());
						progressCallback(prodgressInfo);
					}

					//Raise notification each notifyProductSizeLimit products
					counter++;
					prodgressInfo.ProcessedCount = counter;
					prodgressInfo.Description = string.Format("{0} of {1} products processed", prodgressInfo.ProcessedCount, prodgressInfo.TotalCount);
					if (counter % notifyProductSizeLimit == 0 || counter == prodgressInfo.TotalCount)
					{
						progressCallback(prodgressInfo);
					}
				}
			}
		}
コード例 #8
0
		public virtual void DoExport(string catalogId, string[] exportedCategories, string[] exportedProducts, string pricelistId, string fulfilmentCenterId, CurrencyCodes currency, string languageCode, ExportNotification notification)
		{
			var memoryStream = new MemoryStream();
			var streamWriter = new StreamWriter(memoryStream);
			streamWriter.AutoFlush = true;
			var productPropertyInfos = typeof(CatalogProduct).GetProperties(BindingFlags.Instance | BindingFlags.Public);
			string catalogName = null;
			using (var csvWriter = new CsvWriter(streamWriter))
			{
				csvWriter.Configuration.Delimiter = ";";

				//Notification
				notification.Description = "loading products...";
				_notifier.Upsert(notification);

				try
				{
					//Load all products to export
					var products = LoadProducts(catalogId, exportedCategories, exportedProducts);

					//Notification
					notification.Description = "loading prices...";
					_notifier.Upsert(notification);
					var allProductIds = products.Select(x=>x.Id).ToArray();
					//Load prices for products
					var priceEvalContext = new  PriceEvaluationContext {
						ProductIds = allProductIds,
						PricelistIds = pricelistId == null ? null : new string[] { pricelistId },
						Currency = currency
					};

					var allProductPrices = _pricingService.EvaluateProductPrices(priceEvalContext).ToArray();
					foreach(var product in products)
					{
						product.Prices = allProductPrices.Where(x => x.ProductId == product.Id).ToList();
					}
					//Load inventories
					notification.Description = "loading inventory information...";
					_notifier.Upsert(notification);
					var allProductInventories = _inventoryService.GetProductsInventoryInfos(allProductIds);
					foreach (var product in products)
					{
						product.Inventories = allProductInventories.Where(x => x.ProductId == product.Id)
							.Where(x => fulfilmentCenterId == null ? true : x.FulfillmentCenterId == fulfilmentCenterId).ToList();
					}

					notification.TotalCount = products.Count();
					//populate export configuration
					Dictionary<string, Func<CatalogProduct, string>> exportConfiguration = new Dictionary<string, Func<CatalogProduct, string>>();
					PopulateProductExportConfiguration(exportConfiguration, products);

					//Write header
					foreach (var cfgItem in exportConfiguration)
					{
						csvWriter.WriteField(cfgItem.Key);
					}
					csvWriter.NextRecord();

					var notifyProductSizeLimit = 50;
					var counter = 0;
					//Write products
					foreach (var product in products)
					{
						if(catalogName == null && product.Catalog != null)
						{
							catalogName = product.Catalog.Name;
						}

						try
						{
							foreach (var cfgItem in exportConfiguration)
							{
								var fieldValue = String.Empty;
								if (cfgItem.Value == null)
								{
									var propertyInfo = productPropertyInfos.FirstOrDefault(x => x.Name == cfgItem.Key);
									if (propertyInfo != null)
									{
										var objValue = propertyInfo.GetValue(product);
										fieldValue = objValue != null ? objValue.ToString() : fieldValue;
									}
								}
								else
								{
									fieldValue = cfgItem.Value(product);
								}
								csvWriter.WriteField(fieldValue);
							}
							csvWriter.NextRecord();
						}
						catch(Exception ex)
						{
							notification.ErrorCount++;
							notification.Errors.Add(ex.ToString());
							_notifier.Upsert(notification);
						}

						//Raise notification each notifyProductSizeLimit products
						counter++;
						notification.ProcessedCount = counter;
						notification.Description = string.Format("{0} of {1} products processed", notification.ProcessedCount, notification.TotalCount);
						if (counter % notifyProductSizeLimit == 0)
						{
							_notifier.Upsert(notification);
						}
					}
					memoryStream.Position = 0;
					//Upload result csv to blob storage
					var uploadInfo = new UploadStreamInfo
					{
						FileName = "Catalog-" + (catalogName ?? catalogId) + "-export.csv",
						FileByteStream = memoryStream,
						FolderName = "temp"
					};
					var blobKey = _blobStorageProvider.Upload(uploadInfo);
					//Get a download url
					notification.DownloadUrl = _blobUrlResolver.GetAbsoluteUrl(blobKey);
					notification.Description = "Export finished";
				}
				catch(Exception ex)
				{
					notification.Description = "Export error";
					notification.ErrorCount++;
					notification.Errors.Add(ex.ToString());
				}
				finally
				{
					notification.Finished = DateTime.UtcNow;
					_notifier.Upsert(notification);
				}
		
			}
			
		}
コード例 #9
0
        public IEnumerable <coreModel.Price> EvaluateProductPrices(coreModel.PriceEvaluationContext evalContext)
        {
            if (evalContext == null)
            {
                throw new ArgumentNullException("evalContext");
            }
            if (evalContext.ProductIds == null)
            {
                throw new MissingFieldException("ProductIds");
            }

            var retVal = new List <coreModel.Price>();

            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 != null)
                {
                    query = query.Where(x => evalContext.PricelistIds.Contains(x.PricelistId));
                }
                else if (evalContext.Currency != null)
                {
                    query = query.Where(x => x.Pricelist.Currency == evalContext.Currency.ToString());
                }
                var prices = query.ToArray().Select(x => x.ToCoreModel());

                foreach (var currencyPricesGroup in prices.GroupBy(x => x.Currency))
                {
                    var groupPrices = currencyPricesGroup.OrderBy(x => 1);
                    if (evalContext.PricelistIds != null)
                    {
                        //Construct ordered groups of list prices (ordered by pricelist priority taken from pricelistid array as index)
                        groupPrices = groupPrices.OrderBy(x => Array.IndexOf(evalContext.PricelistIds, x.PricelistId));
                    }
                    //Order by  price value
                    var orderedPrices = groupPrices.OrderBy(x => Math.Min(x.Sale.HasValue ? x.Sale.Value : x.List, x.List));
                    retVal.AddRange(orderedPrices);
                }

                if (_productService != null)
                {
                    //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
                    var productIdsWithoutPrice = evalContext.ProductIds.Except(retVal.Select(x => x.ProductId).Distinct()).ToArray();
                    if (productIdsWithoutPrice.Any())
                    {
                        var variations = _productService.GetByIds(productIdsWithoutPrice, Domain.Catalog.Model.ItemResponseGroup.ItemInfo).Where(x => x.MainProductId != null);
                        evalContext.ProductIds = variations.Select(x => x.MainProductId).Distinct().ToArray();
                        foreach (var inheritedPrice in EvaluateProductPrices(evalContext))
                        {
                            var variation = variations.First(x => x.MainProductId == inheritedPrice.ProductId);
                            //For correct override price in possible update
                            inheritedPrice.Id        = null;
                            inheritedPrice.ProductId = variation.Id;
                            retVal.Add(inheritedPrice);
                        }
                    }
                }
            }

            return(retVal);
        }
コード例 #10
0
        /// <summary>
        /// Evaluate pricelists for special context. All resulting pricelists ordered by priority
        /// </summary>
        /// <param name="evalContext"></param>
        /// <returns></returns>
        public IEnumerable <coreModel.Pricelist> EvaluatePriceLists(coreModel.PriceEvaluationContext evalContext)
        {
            var retVal = new List <coreModel.Pricelist>();

            var query = _cacheManager.Get("PricingServiceImpl.EvaluatePriceLists", "PricingModuleRegion", () =>
            {
                using (var repository = _repositoryFactory())
                {
                    var allAssignments = repository.PricelistAssignments.Include(x => x.Pricelist).ToArray().Select(x => x.ToCoreModel()).ToArray();
                    foreach (var assignment in allAssignments)
                    {
                        try
                        {
                            //Deserialize conditions
                            assignment.Condition = SerializationUtil.DeserializeExpression <Func <IEvaluationContext, bool> >(assignment.ConditionExpression);
                        }
                        catch (Exception ex)
                        {
                            _logger.Error(ex);
                        }
                    }
                    return(allAssignments);
                }
            }).AsQueryable();

            if (evalContext.CatalogId != null)
            {
                //filter by catalog
                query = query.Where(x => x.CatalogId == evalContext.CatalogId);
            }

            if (evalContext.Currency != null)
            {
                //filter by currency
                query = query.Where(x => x.Pricelist.Currency == evalContext.Currency.ToString());
            }
            if (evalContext.CertainDate != null)
            {
                //filter by date expiration
                query = query.Where(x => (x.StartDate == null || evalContext.CertainDate >= x.StartDate) && (x.EndDate == null || x.EndDate >= evalContext.CertainDate));
            }
            var assinments = query.OrderByDescending(x => x.Priority).ThenByDescending(x => x.Name).ToArray();

            retVal.AddRange(assinments.Where(x => x.Condition == null).Select(x => x.Pricelist));

            foreach (var assignment in assinments.Where(x => x.Condition != null))
            {
                try
                {
                    if (assignment.Condition(evalContext))
                    {
                        if (!retVal.Any(p => p.Id == assignment.Pricelist.Id))
                        {
                            retVal.Add(assignment.Pricelist);
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.Error(ex);
                }
            }

            return(retVal);
        }
コード例 #11
0
        /// <summary>
        /// Evaluate pricelists for special context. All resulting pricelists ordered by priority
        /// </summary>
        /// <param name="evalContext"></param>
        /// <returns></returns>
        public virtual IEnumerable <coreModel.Pricelist> EvaluatePriceLists(coreModel.PriceEvaluationContext evalContext)
        {
            coreModel.PricelistAssignment[] assignmentsGetters()
            {
                var allAssignments = GetAllPricelistAssignments();

                foreach (var assignment in allAssignments.Where(x => !string.IsNullOrEmpty(x.ConditionExpression)))
                {
                    try
                    {
                        //Deserialize conditions
                        assignment.Condition = _expressionSerializer.DeserializeExpression <Func <IEvaluationContext, bool> >(assignment.ConditionExpression);
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex);
                    }
                }
                return(allAssignments);
            }

            IQueryable <coreModel.PricelistAssignment> query = null;

            if (_cacheManager != null)
            {
                query = _cacheManager.Get("PricingServiceImpl.EvaluatePriceLists", "PricingModuleRegion", assignmentsGetters).AsQueryable();
            }
            else
            {
                query = assignmentsGetters().AsQueryable();
            }

            if (evalContext.CatalogId != null)
            {
                //filter by catalog
                query = query.Where(x => x.CatalogId == evalContext.CatalogId);
            }

            if (evalContext.Currency != null)
            {
                //filter by currency
                query = query.Where(x => x.Pricelist.Currency == evalContext.Currency.ToString());
            }

            if (evalContext.CertainDate != null)
            {
                //filter by date expiration
                query = query.Where(x => (x.StartDate == null || evalContext.CertainDate >= x.StartDate) && (x.EndDate == null || x.EndDate > evalContext.CertainDate));
            }

            var assignments         = query.ToArray();
            var assignmentsToReturn = assignments.Where(x => x.Condition == null).ToList();

            foreach (var assignment in assignments.Where(x => x.Condition != null))
            {
                try
                {
                    if (assignment.Condition(evalContext))
                    {
                        if (assignmentsToReturn.All(x => x.PricelistId != assignment.PricelistId))
                        {
                            assignmentsToReturn.Add(assignment);
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.Error(ex);
                }
            }

            return(assignmentsToReturn.OrderByDescending(x => x.Priority).ThenByDescending(x => x.Name).Select(x => x.Pricelist));
        }
コード例 #12
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);
        }
コード例 #13
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("evalContext");
            }
            if (evalContext.ProductIds == null)
            {
                throw new MissingFieldException("ProductIds");
            }

            var retVal = new List <coreModel.Price>();

            coreModel.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 = EvaluatePriceLists(evalContext).Select(x => x.Id).ToArray();
                }
                query  = query.Where(x => evalContext.PricelistIds.Contains(x.PricelistId));
                prices = query.ToArray().Select(x => x.ToModel(AbstractTypeFactory <coreModel.Price> .TryCreateInstance())).ToArray();
            }

            var priceListOrdererList = evalContext.PricelistIds?.ToList();

            foreach (var productId in evalContext.ProductIds)
            {
                var productPrices = prices.Where(x => x.ProductId == productId);
                if (evalContext.ReturnAllMatchedPrices)
                {
                    // Get all prices, ordered by currency and amount.
                    var orderedPrices = productPrices.OrderBy(x => x.Currency).ThenBy(x => Math.Min(x.Sale ?? x.List, x.List));
                    retVal.AddRange(orderedPrices);
                }
                else if (!priceListOrdererList.IsNullOrEmpty())
                {
                    // as priceListOrdererList is sorted by priority (descending), we save PricelistId's index as Priority
                    var priceTuples = productPrices
                                      .Select(x => new { Price = x, x.Currency, x.MinQuantity, Priority = priceListOrdererList.IndexOf(x.PricelistId) })
                                      .Where(x => x.Priority > -1);

                    // Group by Currency and by MinQuantity
                    foreach (var pricesGroupByCurrency in priceTuples.GroupBy(x => x.Currency))
                    {
                        var minAcceptablePriority = int.MaxValue;
                        // take prices with lower MinQuantity first
                        foreach (var pricesGroupByMinQuantity in pricesGroupByCurrency.GroupBy(x => x.MinQuantity).OrderBy(x => x.Key))
                        {
                            // take minimal price from most prioritized Pricelist
                            var groupAcceptablePrice = pricesGroupByMinQuantity.OrderBy(x => x.Priority)
                                                       .ThenBy(x => Math.Min(x.Price.Sale ?? x.Price.List, x.Price.List))
                                                       .First();

                            if (minAcceptablePriority >= groupAcceptablePrice.Priority)
                            {
                                minAcceptablePriority = groupAcceptablePrice.Priority;
                                retVal.Add(groupAcceptablePrice.Price);
                            }
                        }
                    }
                }
            }

            //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);
        }