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); }
public IHttpActionResult EvaluatePrices([ModelBinder(typeof(PriceEvaluationContextBinder))] coreModel.PriceEvaluationContext evalContext) { var retVal = _pricingService.EvaluateProductPrices(evalContext) .Select(x => x.ToWebModel()) .ToArray(); return(Ok(retVal)); }
public IHttpActionResult EvaluatePriceLists(coreModel.PriceEvaluationContext evalContext) { var retVal = _pricingService.EvaluatePriceLists(evalContext) .Select(x => x.ToWebModel()) .ToArray(); return(Ok(retVal)); }
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); }
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; }
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); }
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); } } } }
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); } } }
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); }
/// <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); }
/// <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)); }
/// <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); }
/// <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); }