private static string GetPriceFieldName(string prefix, IPriceValue price, bool includeMarket) { return((includeMarket ? string.Format("{0}{1}_{2}", prefix, price.UnitPrice.Currency.CurrencyCode, price.MarketId.Value) : string.Format("{0}{1}", prefix, price.UnitPrice.Currency.CurrencyCode)) .ToLowerInvariant()); }
public IPriceValue GetDiscountPrice(IPriceValue price, EntryContentBase entry, Currency currency, PromotionHelperFacade promotionHelper) { var promotionEntry = CreatePromotionEntry(entry, price); var filter = new PromotionFilter { IgnoreConditions = false, IgnorePolicy = false, IgnoreSegments = false, IncludeCoupons = false }; var sourceSet = new PromotionEntriesSet(); sourceSet.Entries.Add(promotionEntry); var promotionContext = promotionHelper.Evaluate(filter, sourceSet, sourceSet, false); if (promotionContext.PromotionResult.PromotionRecords.Count > 0) { return new PriceValue { CatalogKey = price.CatalogKey, CustomerPricing = CustomerPricing.AllCustomers, MarketId = price.MarketId, MinQuantity = 1, UnitPrice = new Money(price.UnitPrice.Amount - GetDiscountPrice(promotionContext), currency), ValidFrom = DateTime.UtcNow, ValidUntil = null }; } return price; }
private void Populate(PromotionEntry entry, EntryContentBase catalogEntry, IPriceValue price) { entry.Quantity = 1; entry.Owner = catalogEntry; entry["Id"] = catalogEntry.Code; if (catalogEntry.Property != null) { foreach (var prop in catalogEntry.Property.Where(x => x.IsPropertyData)) { entry[prop.Name] = prop.Value; } } entry["ExtendedPrice"] = price.UnitPrice.Amount; var inventories = _inventoryService.List(price.CatalogKey, _warehouseRepository.List()).ToList(); if (!inventories.Any()) { return; } entry["AllowBackordersAndPreorders"] = inventories.Any(i => i.AllowBackorder) && inventories.Any(i => i.AllowPreorder); entry["InStockQuantity"] = inventories.Sum(i => i.InStockQuantity - i.ReservedQuantity); entry["PreorderQuantity"] = inventories.Sum(i => i.PreorderQuantity); entry["BackorderQuantity"] = inventories.Sum(i => i.BackorderQuantity); entry["InventoryStatus"] = inventories.First().InventoryStatus; }
private void Populate(PromotionEntry entry, EntryContentBase catalogEntry, IPriceValue price) { entry.Quantity = 1; entry.Owner = catalogEntry; entry["Id"] = catalogEntry.Code; if (catalogEntry.Property != null) { foreach (var prop in catalogEntry.Property.Where(x => x.IsPropertyData)) { entry[prop.Name] = prop.Value; } } entry["ExtendedPrice"] = price.UnitPrice.Amount; var inventories = _inventoryService.QueryByEntry(new [] { price.CatalogKey.CatalogEntryCode }).ToList(); if (!inventories.Any()) { return; } entry["AllowBackordersAndPreorders"] = inventories.Any(i => i.CanBackorder(DateTime.UtcNow)) && inventories.Any(i => i.CanPreorder(DateTime.UtcNow)); entry["InStockQuantity"] = inventories.Sum(i => i.BackorderAvailableQuantity); entry["PreorderQuantity"] = inventories.Sum(i => i.PreorderAvailableQuantity); entry["BackorderQuantity"] = inventories.Sum(i => i.BackorderAvailableQuantity); }
public IPriceValue GetDiscountPrice(IPriceValue price, EntryContentBase entry, Currency currency, PromotionHelperFacade promotionHelper) { var promotionEntry = CreatePromotionEntry(entry, price); var filter = new PromotionFilter { IgnoreConditions = false, IgnorePolicy = false, IgnoreSegments = false, IncludeCoupons = false }; var sourceSet = new PromotionEntriesSet(); sourceSet.Entries.Add(promotionEntry); var promotionContext = promotionHelper.Evaluate(filter, sourceSet, sourceSet, false); if (promotionContext.PromotionResult.PromotionRecords.Count > 0) { return(new PriceValue { CatalogKey = price.CatalogKey, CustomerPricing = CustomerPricing.AllCustomers, MarketId = price.MarketId, MinQuantity = 1, UnitPrice = new Money(price.UnitPrice.Amount - GetDiscountPrice(promotionContext), currency), ValidFrom = DateTime.UtcNow, ValidUntil = null }); } return(price); }
private Money?GetDiscountPrice(IPriceValue defaultPrice, IMarket market, Currency currency) { if (defaultPrice == null) { return(null); } return(_promotionService.GetDiscountPrice(defaultPrice.CatalogKey, market.MarketId, currency).UnitPrice); }
/// <summary> /// Constuctor to copy value from /// </summary> /// <param name="from"></param> public ReadOnlyPriceValue(IPriceValue from) { this.CatalogKey = new CatalogKey(from.CatalogKey.ApplicationId, from.CatalogKey.CatalogEntryCode); this.MarketId = from.MarketId; this.MinQuantity = from.MinQuantity; this.UnitPrice = from.UnitPrice; this.CustomerPricing = from.CustomerPricing; this.ValidFrom = from.ValidFrom; this.ValidUntil = from.ValidUntil; }
protected Money?GetItemPrice(CatalogEntryDto.CatalogEntryRow entry, LineItem lineItem, CustomerContact customerContact) { Currency currency = new Currency(lineItem.Parent.Parent.BillingCurrency); List <CustomerPricing> customerPricing = new List <CustomerPricing>(); customerPricing.Add(CustomerPricing.AllCustomers); if (customerContact != null) { var userKey = _mapUserKey.ToUserKey(customerContact.UserId); if (userKey != null && !string.IsNullOrWhiteSpace(userKey.ToString())) { customerPricing.Add(new CustomerPricing(CustomerPricing.PriceType.UserName, userKey.ToString())); } if (!string.IsNullOrEmpty(customerContact.EffectiveCustomerGroup)) { customerPricing.Add(new CustomerPricing(CustomerPricing.PriceType.PriceGroup, customerContact.EffectiveCustomerGroup)); } } IPriceService priceService = ServiceLocator.Current.GetInstance <IPriceService>(); PriceFilter priceFilter = new PriceFilter() { Currencies = new List <Currency>() { currency }, Quantity = lineItem.Quantity, CustomerPricing = customerPricing, ReturnCustomerPricing = false // just want one value }; // Get the lowest price among all the prices matching the parameters IPriceValue priceValue = priceService .GetPrices(lineItem.Parent.Parent.MarketId, FrameworkContext.Current.CurrentDateTime, new CatalogKey(entry), priceFilter) .OrderBy(pv => pv.UnitPrice) .FirstOrDefault(); if (priceValue != null) { return(priceValue.UnitPrice); } if (lineItem.PlacedPrice != 0) { return(new Money(lineItem.PlacedPrice, currency)); } return(null); }
private PromotionEntry CreatePromotionEntry(EntryContentBase entry, IPriceValue price) { var catalogNodes = string.Empty; var catalogs = string.Empty; foreach (var node in entry.GetNodeRelations(_linksRepository).Select(x => _contentLoader.Get<NodeContent>(x.Target))) { var entryCatalogName = _catalogSystem.GetCatalogDto(node.CatalogId).Catalog[0].Name; catalogs = string.IsNullOrEmpty(catalogs) ? entryCatalogName : catalogs + ";" + entryCatalogName; catalogNodes = string.IsNullOrEmpty(catalogNodes) ? node.Code : catalogNodes + ";" + node.Code; } var promotionEntry = new PromotionEntry(catalogs, catalogNodes, entry.Code, price.UnitPrice.Amount); Populate(promotionEntry, entry, price); return promotionEntry; }
private Money GetDiscountPrice(EntryContentBase content, IPriceValue defaultPrice, IMarket market, Currency currency) { if (defaultPrice == null) { return(new Money(0, currency)); } if (_promotionHelper == null) { _promotionHelper = new PromotionHelperFacade(); } _promotionHelper.Reset(); return(_promotionEntryService.GetDiscountPrice(defaultPrice, content, currency, _promotionHelper).UnitPrice); }
private PromotionEntry CreatePromotionEntry(EntryContentBase entry, IPriceValue price) { var catalogNodes = string.Empty; var catalogs = string.Empty; foreach (var node in entry.GetNodeRelations(_linksRepository).Select(x => _contentLoader.Get <NodeContent>(x.Target))) { var entryCatalogName = _catalogSystem.GetCatalogDto(node.CatalogId).Catalog[0].Name; catalogs = string.IsNullOrEmpty(catalogs) ? entryCatalogName : catalogs + ";" + entryCatalogName; catalogNodes = string.IsNullOrEmpty(catalogNodes) ? node.Code : catalogNodes + ";" + node.Code; } var promotionEntry = new PromotionEntry(catalogs, catalogNodes, entry.Code, price.UnitPrice.Amount); Populate(promotionEntry, entry, price); return(promotionEntry); }
private static IEnumerable <Tuple <string, decimal> > CreatePrices(IPriceValue price) { const string listPrice = "listprice"; const string salePrice = "saleprice"; var amount = price.UnitPrice.Amount; yield return(new Tuple <string, decimal>(GetPriceFieldName(salePrice, price, true), amount)); yield return(new Tuple <string, decimal>(GetPriceFieldName(salePrice, price, false), amount)); if (price.MinQuantity == 0 && price.CustomerPricing.PriceTypeId == CustomerPricing.PriceType.AllCustomers) { yield return(new Tuple <string, decimal>(GetPriceFieldName(listPrice, price, true), amount)); yield return(new Tuple <string, decimal>(GetPriceFieldName(listPrice, price, false), amount)); } }
protected void SetPrices(string code, List <Price> prices) { if (code == null) { throw new ArgumentNullException("code"); } if (prices == null) { return; } CatalogKey key = new CatalogKey(Mediachase.Commerce.Core.AppContext.Current.ApplicationId, code); var catalogEntryPrices = _priceService.GetCatalogEntryPrices(key); //.ToList(); List <IPriceValue> priceValues = new List <IPriceValue>(catalogEntryPrices); foreach (Price price in prices) { // Already there? IPriceValue priceValue = priceValues.FirstOrDefault(p => p.MarketId.Value == price.marketId); if (priceValue == null) { // No - add it PriceValue newPrice = new PriceValue() { CatalogKey = key, MarketId = price.marketId, UnitPrice = new Money(price.price, new Currency(price.currency)), ValidFrom = DateTime.Now, CustomerPricing = CustomerPricing.AllCustomers, MinQuantity = 0 }; priceValues.Add(newPrice); } else { // We don't touch prices for the same market } } _log.Debug("Saving {0} prices for {1}", priceValues.Count, code); // Save prices back _priceService.SetCatalogEntryPrices(key, priceValues); }
public IPriceValue GetDiscountPrice(IPriceValue price, EntryContentBase entry, Currency currency, IMarket market) { var discountedPrice = _promotionEngine.GetDiscountPrices(new[] { entry.ContentLink }, market, currency, _referenceConverter, _lineItemCalculator); if (discountedPrice.Any()) { var highestDiscount = discountedPrice.SelectMany(x => x.DiscountPrices).OrderBy(x => x.Price).FirstOrDefault().Price; return new PriceValue { CatalogKey = price.CatalogKey, CustomerPricing = CustomerPricing.AllCustomers, MarketId = price.MarketId, MinQuantity = 1, UnitPrice = highestDiscount, ValidFrom = DateTime.UtcNow, ValidUntil = null }; } return price; }
/// <summary> /// Gets the sale price. /// </summary> /// <param name="entry">The entry used to fetch prices.</param> /// <param name="quantity">The quantity.</param> /// <param name="market">The market.</param> /// <param name="currency">The currency.</param> /// <returns></returns> public static Price GetSalePrice(Entry entry, decimal quantity, IMarket market, Currency currency) { List <CustomerPricing> customerPricing = new List <CustomerPricing>(); customerPricing.Add(CustomerPricing.AllCustomers); var principal = PrincipalInfo.CurrentPrincipal; if (principal != null) { if (!string.IsNullOrEmpty(principal.Identity.Name)) { customerPricing.Add(new CustomerPricing(CustomerPricing.PriceType.UserName, principal.Identity.Name)); } CustomerContact currentUserContact = principal.GetCustomerContact(); if (currentUserContact != null && !string.IsNullOrEmpty(currentUserContact.EffectiveCustomerGroup)) { customerPricing.Add(new CustomerPricing(CustomerPricing.PriceType.PriceGroup, currentUserContact.EffectiveCustomerGroup)); } } IPriceService priceService = ServiceLocator.Current.GetInstance <IPriceService>(); PriceFilter filter = new PriceFilter() { Quantity = quantity, Currencies = new Currency[] { currency }, CustomerPricing = customerPricing }; // return less price value IPriceValue priceValue = priceService.GetPrices(market.MarketId, FrameworkContext.Current.CurrentDateTime, new CatalogKey(entry), filter) .OrderBy(pv => pv.UnitPrice) .FirstOrDefault(); if (priceValue != null) { return(new Price(priceValue.UnitPrice)); } return(null); }
public IPriceValue GetDiscountPrice(IPriceValue price, ContentReference contentLink, Currency currency, IMarket market) { var discountedPrice = _promotionEngine.GetDiscountPrices(new[] { contentLink }, market, currency, _referenceConverter, _lineItemCalculator); if (discountedPrice.Any()) { var highestDiscount = discountedPrice.SelectMany(x => x.DiscountPrices).OrderBy(x => x.Price).FirstOrDefault().Price; return(new PriceValue { CatalogKey = price.CatalogKey, CustomerPricing = CustomerPricing.AllCustomers, MarketId = price.MarketId, MinQuantity = 1, UnitPrice = highestDiscount, ValidFrom = DateTime.UtcNow, ValidUntil = null }); } return(price); }
/// <summary> /// Initializes a new instance of the <see cref="Price" /> class. /// </summary> /// <param name="entry">tThe entry content base.</param> /// <param name="priceValue">The price value.</param> public Price(IPriceValue priceValue) { CatalogEntryCode = priceValue.CatalogKey.CatalogEntryCode; CustomerPricing = (priceValue.CustomerPricing != null) ? new CustomerPricing(priceValue.CustomerPricing.PriceTypeId, priceValue.CustomerPricing.PriceCode) : null; MarketId = priceValue.MarketId; MinQuantity = priceValue.MinQuantity; UnitPrice = priceValue.UnitPrice; ValidFrom = priceValue.ValidFrom .ToLocalTime(); // make sure the time has been converted from UTC to local, to avoid mismatch between Commerce manager and Catalog Mode ValidUntil = priceValue.ValidUntil.HasValue ? priceValue.ValidUntil.Value.ToLocalTime() : priceValue .ValidUntil; // make sure the time has been converted from UTC to local, to avoid mismatch between Commerce manager and Catalog Mode }
private LineItem CreateLineItem(Entry entry, IOrderGroup g) { var priceService = ServiceLocator.Current.GetInstance <IPriceService>(); LineItem item = new LineItem(); if (entry.ParentEntry != null) { item.DisplayName = string.Format("{0}: {1}", entry.ParentEntry.Name, entry.Name); item.ParentCatalogEntryId = entry.ParentEntry.ID; } else { item.DisplayName = entry.Name; } item[Constants.Metadata.LineItem.ImageUrl] = "/globalassets/catalogs/photo/accessories/memory-card/sandisk-extreme-pro/824140.jpg?preset=listsmall"; MarketId marketId = g.Market.MarketId.Value; IPriceValue value2 = priceService.GetDefaultPrice(marketId, FrameworkContext.Current.CurrentDateTime, new CatalogKey(entry), g.Currency); item.Code = entry.ID; item.Quantity = 1; if (value2 != null) { item.ListPrice = value2.UnitPrice.Amount; item.PlacedPrice = value2.UnitPrice.Amount; item.ExtendedPrice = value2.UnitPrice.Amount; } else { item.ListPrice = item.PlacedPrice; } return(item); }
/// <summary> /// This is done for calculating a discounted price on "Customer Pricing" prices /// By default the "DefaultPrice is used" /// </summary> public override IOrderGroup CreateInMemoryOrderGroup( ContentReference entryLink , IMarket market , Currency marketCurrency) { // this is where you can reference your own pricing calculator to retrieve... // ..."the right" sale price var theEntry = _contentLoader.Get <EntryContentBase>(entryLink); var orderGroup = new InMemoryOrderGroup(market, marketCurrency); //IPriceValue price = BestPricingCalculatorEver.GetSalePrice(entryLink); IPriceValue price = _myPriceCalculator.GetSalePrice(theEntry, 1); if (price != null && price.UnitPrice.Amount != 0) { orderGroup.Forms.First().Shipments.First().LineItems.Add(new InMemoryLineItem { Quantity = 1, Code = price.CatalogKey.CatalogEntryCode, PlacedPrice = price.UnitPrice.Amount }); } return(orderGroup); }
public override IOrderGroup CreateInMemoryOrderGroup( ContentReference entryLink, IMarket market, Mediachase.Commerce.Currency marketCurrency) { InMemoryOrderGroup memoryOrderGroup = new InMemoryOrderGroup(market, marketCurrency); memoryOrderGroup.CustomerId = PrincipalInfo.CurrentPrincipal.GetContactId(); string code = this._referenceConverter.GetCode(entryLink); IPriceValue price = PriceCalculationService.GetSalePrice(code, market.MarketId, marketCurrency); if (price != null && price.UnitPrice != null) { decimal priceAmount = price.UnitPrice.Amount; memoryOrderGroup.Forms.First <IOrderForm>().Shipments.First <IShipment>().LineItems.Add((ILineItem) new InMemoryLineItem() { Quantity = 1M, Code = code, PlacedPrice = priceAmount }); } return((IOrderGroup)memoryOrderGroup); }
// Where it happens for the new Promos/Cust-Pricing...need to clean this mess upp public static Price GetDiscountPrice( EntryContentBase contentReference, int quantity, decimal promoPrice /*, string catalogName, string categoryName*/) { // some basic validation if (contentReference == null) { throw new NullReferenceException("entry object can't be null"); } if (contentReference as IPricing == null) { throw new InvalidCastException("entry object must implement IPricing"); } // Define the PriceFilter PriceFilter filter = new PriceFilter() { Quantity = 0M, // need improvements here Currencies = new Currency[] { _currentMarket.Service.GetCurrentMarket().Currencies.FirstOrDefault() }, // only have one at the moment... CustomerPricing = GetCustomerPricingList(), // changed ReturnCustomerPricing = true // // ... if true; gets all that applies }; // The rest needed, CatKey, Market, TimeStamp CatalogKey catalogKey = new CatalogKey(contentReference.Code); // 3 overloads #region This is old stuff, may not use /* more hassle to get it working you could say, but used in the right way ... * ...it could simplyfy ... but it's still old */ //ItemCollection<Price> prices = pricingSKU.GetPrices( // _readOnlyPricingLoader.Service // , _currentMarket.Service.GetCurrentMarket().MarketId // , customerPricing); #endregion // ToDo: Get all applicable prices //IEnumerable<IPriceValue> prices = null; // starter IEnumerable <IPriceValue> prices = // Solution _priceService.Service.GetPrices(_currentMarket.Service.GetCurrentMarket().MarketId , DateTime.Now, catalogKey , filter); //ToDo: Identify the lowest price when the "base-price is excluded" // Outcommented is starter-code to make things work ... // ...exchange the below for lab-code //Price p = new Price(); //IPriceValue lowPrice = p.ToPriceValue(); // Solution IPriceValue lowPrice = prices.Where(x => x.MinQuantity <= quantity && x.CustomerPricing.PriceTypeId != (CustomerPricing.PriceType) 3) // do not look on "BasePrice" .OrderBy(pv => pv.UnitPrice).FirstOrDefault(); //ToDO: Get the base price (which is the lowest possible price) //IPriceValue basePrice = null; // is the starter // use as solution IPriceValue basePrice = prices.Where( x => x.CustomerPricing.PriceTypeId == (CustomerPricing.PriceType) 3).First(); // ...should check the RG... and reload if not filled with nodes Entry entry = contentReference.LoadEntry(CatalogEntryResponseGroup.ResponseGroup.Nodes); //get the discount price and return the highest of the discounted price and base price Price discountedPrice = GetDiscountPriceInternal(contentReference, entry, lowPrice, null, null); // sending empty... for now // As starter have the fork but return null...in both //ToDO: Add logic to set the discounted price to the base price if its lower than the base price // starter //if (basePrice != null && discountedPrice != null) // Solution, messy rewritten to us the new "promo-system" //if (basePrice != null && discountedPrice != null && basePrice.UnitPrice.Amount if (basePrice != null && basePrice.UnitPrice.Amount //> discountedPrice.UnitPrice.Amount) // old promos > promoPrice) // new promos { return(new Price(basePrice)); } else { // returning the promo-Price ... need a re-work return(new Price { UnitPrice = new Money(promoPrice, _currentMarket.Service.GetCurrentMarket().DefaultCurrency), ValidFrom = lowPrice.ValidFrom, ValidUntil = lowPrice.ValidUntil, MinQuantity = lowPrice.MinQuantity, MarketId = lowPrice.MarketId, EntryContent = contentReference, CustomerPricing = lowPrice.CustomerPricing }); } }
private void SetDefaultPriceService(IPriceValue returnedPrice) { _priceServiceMock .Setup(x => x.GetDefaultPrice(It.IsAny<MarketId>(), It.IsAny<DateTime>(), It.IsAny<CatalogKey>(), _defaultCurrency)) .Returns(returnedPrice); }
// Old stuff... no demo... Legacy Promos // This is a slightly-refactored version of the StoreHelper.GetDiscountPrice() method // catalogName and catalogNodeCode... can be used to filter out certain nodes or catalogs private static Price GetDiscountPriceInternal(EntryContentBase contentSku, Entry sku, IPriceValue price, string catalogName, string catalogNodeCode) { string catalogNodes = String.Empty; string catalogs = String.Empty; // Now cycle through all the catalog nodes where this entry is present filtering by specified catalog and node code // Note: The nodes are only populated when Full or Nodes response group is specified. if (sku.Nodes != null && sku.Nodes.CatalogNode != null && sku.Nodes.CatalogNode.Length > 0) { foreach (CatalogNode node in sku.Nodes.CatalogNode) { string entryCatalogName = CatalogContext.Current.GetCatalogDto(node.CatalogId).Catalog[0].Name; // Skip filtered catalogs if (!String.IsNullOrEmpty(catalogName) && !entryCatalogName.Equals(catalogName)) { continue; } // Skip filtered catalogs nodes if (!String.IsNullOrEmpty(catalogNodeCode) && !node.ID.Equals(catalogNodeCode, StringComparison.OrdinalIgnoreCase)) { continue; } if (String.IsNullOrEmpty(catalogs)) { catalogs = entryCatalogName; } else { catalogs += ";" + entryCatalogName; } if (String.IsNullOrEmpty(catalogNodes)) { catalogNodes = node.ID; } else { catalogNodes += ";" + node.ID; } } } if (String.IsNullOrEmpty(catalogs)) { catalogs = catalogName; } if (String.IsNullOrEmpty(catalogNodes)) { catalogNodes = catalogNodeCode; } // Get current context Dictionary <string, object> context = MarketingContext.Current.MarketingProfileContext; // Create filter PromotionFilter filter = new PromotionFilter { IgnoreConditions = false, IgnorePolicy = false, IgnoreSegments = false, IncludeCoupons = false }; // Create new entry // Note: catalogNodes is determined by GetParentNodes(entry) PromotionEntry result = new PromotionEntry(catalogs, catalogNodes, sku.ID, price.UnitPrice.Amount); var promotionEntryPopulateService = (IPromotionEntryPopulate)MarketingContext.Current.PromotionEntryPopulateFunctionClassInfo.CreateInstance(); promotionEntryPopulateService.Populate(result, sku, _currentMarket.Service.GetCurrentMarket().MarketId, _currentMarket.Service.GetCurrentMarket().DefaultCurrency); PromotionEntriesSet sourceSet = new PromotionEntriesSet(); sourceSet.Entries.Add(result); // Create new promotion helper, which will initialize PromotionContext object for us and setup context dictionary PromotionHelper helper = new PromotionHelper(); // Only target entries helper.PromotionContext.TargetGroup = PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Entry).Key; // Configure promotion context helper.PromotionContext.SourceEntriesSet = sourceSet; helper.PromotionContext.TargetEntriesSet = sourceSet; // Execute the promotions and filter out basic collection of promotions, we need to execute with cache disabled, so we get latest info from the database helper.Eval(filter); Money discountedAmount; // Check the count, and get new price if promotion is applied if (helper.PromotionContext.PromotionResult.PromotionRecords.Count > 0) { discountedAmount = new Money(price.UnitPrice.Amount - GetDiscountPriceFromPromotionResult( helper.PromotionContext.PromotionResult), _currentMarket.Service.GetCurrentMarket().DefaultCurrency); return(new Price { UnitPrice = discountedAmount, ValidFrom = price.ValidFrom, ValidUntil = price.ValidUntil, MinQuantity = price.MinQuantity, MarketId = price.MarketId, EntryContent = contentSku, CustomerPricing = price.CustomerPricing }); } else { return(new Price(price)); } }
// Where it happens for the new Promos/Cust-Pricing...need to clean this mess upp public Price CheckDiscountPrice( EntryContentBase entry, decimal quantity, decimal promoPrice) { // Get the list var customerPricing = GetCustomerPricingList(); // Add BasePrice - Lowest possible customerPricing.Add(new CustomerPricing((CustomerPricing.PriceType) 3, string.Empty)); // Define the PriceFilter PriceFilter filter = new PriceFilter() { Quantity = quantity, // need improvements here Currencies = new Currency[] { _currentMarket.GetCurrentMarket().Currencies.FirstOrDefault() }, // only have one at the moment... CustomerPricing = customerPricing, // changed ReturnCustomerPricing = true // // ... if true; gets all that applies }; // The rest needed, CatKey, Market, TimeStamp CatalogKey catalogKey = new CatalogKey(entry.Code); // 3 overloads #region This is old stuff, may not use /* more hassle to get it working you could say, but used in the right way ... * ...it could simplyfy ... but it's still old */ //ItemCollection<Price> prices = pricingSKU.GetPrices( // _readOnlyPricingLoader.Service // , _currentMarket.Service.GetCurrentMarket().MarketId // , customerPricing); #endregion // ToDo: Get all applicable prices //IEnumerable<IPriceValue> prices = null; // starter IEnumerable <IPriceValue> prices = // Solution _priceService.GetPrices(_currentMarket.GetCurrentMarket().MarketId , DateTime.Now, catalogKey , filter); #region Old garbage //ToDo: Identify the lowest price when the "base-price is excluded" // Outcommented is starter-code to make things work ... // ...exchange the below for lab-code //Price p = new Price(); //IPriceValue lowPrice = p.ToPriceValue(); // Solution //IPriceValue lowPrice = prices.Where(x => x.MinQuantity <= quantity // && x.CustomerPricing.PriceTypeId != (CustomerPricing.PriceType)3) // do not look on "BasePrice" // .OrderBy(pv => pv.UnitPrice).FirstOrDefault(); #endregion //ToDO: Get the base price (which is the lowest possible price) //IPriceValue basePrice = null; // is the starter #region New garbage //_priceService.GetPrices() //IPriceValue basePrice2 = null; //if (prices.Where(p => p.CustomerPricing.PriceTypeId == (CustomerPricing.PriceType)3).Any()) //{ #endregion // whatever price comes out IPriceValue lowestPrice = prices.Where (p => p.CustomerPricing.PriceTypeId != (CustomerPricing.PriceType) 3).First(); // get the base price IPriceValue basePrice = prices.Where( x => x.CustomerPricing.PriceTypeId == (CustomerPricing.PriceType) 3).First(); // Solution, pick the base price if promos goes below if (basePrice != null && basePrice.UnitPrice.Amount >= promoPrice) // new promos { return(new Price(basePrice)); } else { // returning the promo-Price ... comes as an arg. (decimal) return(new Price { UnitPrice = new Money(promoPrice, _currentMarket.GetCurrentMarket().DefaultCurrency), ValidFrom = lowestPrice.ValidFrom, ValidUntil = lowestPrice.ValidUntil, MinQuantity = lowestPrice.MinQuantity, MarketId = lowestPrice.MarketId, EntryContent = entry, CustomerPricing = lowestPrice.CustomerPricing }); } }
private void SetDiscountPriceService(IPriceValue returnedPrice) { _mockPromotionService .Setup(x => x.GetDiscountPrice(It.IsAny <CatalogKey>(), It.IsAny <MarketId>(), _defaultCurrency)) .Returns(returnedPrice); }
private void SetDiscountPriceService(IPriceValue returnedPrice) { _mockPromotionService .Setup(x => x.GetDiscountPrice(It.IsAny<CatalogKey>(), It.IsAny<MarketId>(), _defaultCurrency)) .Returns(returnedPrice); }
private void SetDefaultPriceService(IPriceValue returnedPrice) { _priceServiceMock .Setup(x => x.GetDefaultPrice(It.IsAny <MarketId>(), It.IsAny <DateTime>(), It.IsAny <CatalogKey>(), _defaultCurrency)) .Returns(returnedPrice); }
private void SetDiscountPriceService(IPriceValue returnedPrice) { _pricingServiceMock.Setup(x => x.GetDiscountPrice(It.IsAny <string>())).Returns(returnedPrice); }
public ActionResult Index(ShirtVariation currentContent) { IsOnLine = CheckIfOnLine.IsInternetAvailable; // Need to know... for Find CheckWarehouses(currentContent); // WH-info on the Page var startPage = _contentLoader.Get <StartPage>(ContentReference.StartPage); var cartUrl = _urlResolver.GetUrl(startPage.Settings.cartPage, currentContent.Language.Name); var wUrl = _urlResolver.GetUrl(startPage.Settings.cartPage, currentContent.Language.Name); PricingService pSrvs = new PricingService( _priceService, _currentMarket, _priceDetailService); // used elsewere //currentContent.GetCustomerPrices() // works with the R/O-pricingLoader, would miss the custom SaleTypes //currentContent.GetPrices() // this one also uses the R/O-Loader ... unusable #region Newpromotions // New promotions decimal savedMoney = 0; string rewardDescription = String.Empty; //IEnumerable<RewardDescription> rewards; // get prices incl. "BasePrice" //IPriceValue salePrice = BestPricingCalculatorEver.GetSalePrice(currentContent.ContentLink);// IPriceValue salePrice = _myPriceCalculator.GetSalePrice(currentContent, 1); // the below does the second "Evaluate" var descr = _promotionEngine.Evaluate(currentContent.ContentLink).ToList(); if (descr.Count == 0) // No promos { var d = new RewardDescription( FulfillmentStatus.NotFulfilled, null, null, 0, 0, RewardType.None, "No promo"); descr.Add(d); rewardDescription = descr.First().Description; // ...just to show } else { foreach (var item in descr) { rewardDescription += item.Description; } } // previous way if (descr.Count() >= 1) { savedMoney = descr.First().Percentage *salePrice.UnitPrice.Amount / 100; //rewardDescription = descr.First().Description; Session["SavedMoney"] = savedMoney; } else { savedMoney = 0; //rewardDescription = "No discount"; } // ...this goes to PriceCalc-discount var promoPrice = salePrice.UnitPrice.Amount - savedMoney; #endregion #region just checking on promos //List<RewardDescription> rewards = new List<RewardDescription>(); //rewards = _promotionEngine.Evaluate(currentContent.ContentLink).ToList(); //IEnumerable<DiscountedEntry> entries = _promotionEngine.GetDiscountPrices(currentContent.ContentLink, _currentMarket.GetCurrentMarket()); #endregion #region FindStuff // new Find-Stuff - need to check this out... // FindQueries Qs = new FindQueries(); // Qs.NewExtensionMethods(currentContent); // Qs.SDKExamples(currentContent.ContentLink); #endregion #region Checking some for routing and http-ctx /* * var str = currentContent.GetOriginalType().Name; // not for redirect * var x = ServiceLocator.Current.GetInstance<TemplateResolver>(); * * RequestContext requestContext = new RequestContext(base.HttpContext, base.RouteData); * var parentStack = requestContext.HttpContext.Items[ContentContext.ContentContextKey] as * Stack<ContentContext.ContentPropertiesStack>; * * string controller = requestContext.GetController(); * var t = x.Resolve(requestContext.HttpContext, new CartPage(), TemplateTypeCategories.MvcController); // could use .Name */ #endregion #region LookingAround (incl. new and old Promo-engine) //LoadingExamples(currentContent); //CheckPrices(currentContent); // Have to fake a cart... but it looks good //string rewardDescription = String.Empty; //decimal savedMoney = CheckBetaPromotions(currentContent, out rewardDescription); //var theProxy = currentContent.GetType(); //var yourClass = currentContent.GetOriginalType(); //StoreHelper.GetDiscountPrice(currentContent.LoadEntry()); //StoreHelper.GetSalePrice(currentContent.LoadEntry() #endregion #region Relations, parent - child, etc. CheckOnRelations(currentContent); #endregion #region RoCe - check this // quick-fix - nothing back ICart dummyCart = _orderRepository.LoadOrCreateCart <ICart>(new Guid(), "DummyCart"); ILineItem lineItem = _orderGroupFactory.CreateLineItem(currentContent.Code, dummyCart); var c2 = _lineItemCalculator.GetExtendedPrice(lineItem, _currentMarket.GetCurrentMarket().DefaultCurrency); var check = _lineItemCalculator.GetDiscountedPrice( lineItem, _currentMarket.GetCurrentMarket().DefaultCurrency).Amount; // Should check the BasePrice here (new way) // BestPricingCalc is the old way // should override the LI-calculator #endregion //_currentMarket.GetCurrentMarket().DefaultCurrency.Format(cu) //Currency.SetFormat(_currentMarket.GetCurrentMarket().DefaultCurrency.Format.CurrencySymbol); string thePriceString = string.Empty; if (currentContent.GetDefaultPrice().UnitPrice.Amount == 0) { thePriceString = "no default price"; } else { thePriceString = currentContent.GetDefaultPrice().UnitPrice.ToString(); } var model = new ShirtVariationViewModel { MainBody = currentContent.MainBody, // Pricing priceString = thePriceString, //theRightPriceToPlace = GetThePriceToPlace(currentContent), // tiered pricing...old, not in use CustomerPricingPrice = GetCustomerPricingPrice(currentContent), //discountPrice = CustomStoreHelper.GetDiscountPrice(currentContent.LoadEntry(CatalogEntryResponseGroup.ResponseGroup.Nodes)), discountPriceNew = _lineItemCalculator.GetDiscountedPrice(lineItem, _currentMarket.GetCurrentMarket().DefaultCurrency).Amount, image = GetDefaultAsset((IAssetContainer)currentContent), CanBeMonogrammed = currentContent.CanBeMonogrammed, ProductArea = currentContent.ProductArea, CartUrl = cartUrl, // new stuff - not yet in course WishlistUrl = wUrl, // new stuff - not yet in course // Added for Adv. below //labPrice = BestPricingCalculatorEver.GetDiscountPrice(currentContent, 1, promoPrice), // , "Fashion", "Shirts" labPrice = _myPriceCalculator.CheckDiscountPrice(currentContent, 1, promoPrice), overridePrices = pSrvs.GetPrices(currentContent.Code), PromoString = rewardDescription, // in #region LookingAround betaDiscountPrice = savedMoney, // in #region LookingAround // warehouse info (Lists get filled up in the entrance of "Index-method") generalWarehouseInfo = this.generalWarehouseInfo, specificWarehouseInfo = this.specificWarehouseInfo, // Fills up "Specific-List" localMarketWarehouses = GetLocalMarketWarehouses(), entryCode = currentContent.Code, //Markets currentMarket = GetCurrentMarket(), marketOwner = GetMarketOwner(), // Associations //Associations = GetAssociatedEntries(currentContent), // IEnumerable<ContentReference> // Remove when Aggregation is done //AssociationMetaData = GetAssociationMetaData(currentContent), // string // Remove when Aggregation is done AssocAggregated = GetAggregatedAssocciations(currentContent), // Dictionary<string, ContentReference> // The final thing // Searchendizing ... need to be OnLine to use BoughtThisBoughtThat = GetOtherEntries(currentContent.Code), // Taxes Tax = GetTaxOldSchool(currentContent), TaxString = GetTaxStrings(currentContent), TaxNewSchool = GetTaxNewSchool(currentContent), // info about the variation VariationAvailability = currentContent.IsAvailableInCurrentMarket(), VariationInfo = "Info: " + CollectInfo() }; return(View(model)); }
// Demo - Fund public void CheckPrices(EntryContentBase CurrentContent) { // Pricing, a long story with many alternative /* * Two services are available for interacting with price data. * - The IPriceService API is typically used by order processing to fetch prices for actual use * - IPriceDetailService is typically used in "integration" and interface/code for display (all prices) and edit prices. * * The difference between these APIs is that the IPriceService works with optimized sets of price data, * while the IPriceDetailService works with "the truth". * The optimization in the IPriceService * removes prices that will cannot be used, and trims or splits prices that overlap. */ #region StoreHelper...does this /*Steps in StoreHelper * * Check CurrentMarket * Add AllCustomers * Add PriceType.USerName (IPrincipal) * Check Cust-Group, add ...Effiective-Cust-Group * Get the service * Set the filter * Fetch ... priceService.GetPrices + get the cheapest (note: always cheapest we want) * Get a ... IPriceValue and then... * ....return new Price(priceValue.UnitPrice); * * ...the one that does the job * public static Price GetSalePrice(Entry entry, decimal quantity, IMarket market, Currency currency) * */ #endregion // ... look in VariantController for nice extensions #region GetDefaultPrice...does this /* * Could have a look at .GetDefaultPrice in Reflector * PricingExtensions (EPiServer.Commerce.Catalog.ContentTypes) * - GetDefaultPrice() // gets the R/O-loader * - tries to figure out the Currency * - tries to figure out Market, DateTime, CatalogKey... and does... * - IPriceValue GetDefaultPrice(MarketId market, DateTime validOn, CatalogKey catalogKey, Currency currency); * ...goes to the concrete impl. för the R/O-provider and in there...creates a PriceFilter * ....and gets a "default price" for a catalog entry. The "default price" for a * ....market, currency, and catalog entry is the price available to * "all customers" at a minimum quantity of 0. * ...that in turn goes to the Provider and say GetPrices() ... with all the stuff found */ #endregion // PriceDetails ... administrative stuff, don´t use for retrieving prices for the web // 3 overloads... the 3:rd with filter & Market List <IPriceDetailValue> priceList1 = _priceDetailService.List(CurrentContent.ContentLink).ToList(); Price ppp = new Price(priceList1.First()); // this price class takes a IPriceValue in .ctor (there are 3 different Price-classes) Price aPrice = new Price(priceList1.FirstOrDefault()); // just checking // ...have a CreatePrice("theCode"); // further below /* dbo.PriceType.sql * 0 All Customers * 1 Customer * 2 Customer Price Group * ...can add custom PriceTypes */ // PriceDetail - "R/W" // PriceValue, PriceGroup - "R/O" (...but it´s not, did write to it) // Replicate...changes between the two services // !! Note: don't get it by the ServiceLocator, use injected or .ctor-injection !! // DB-side paging, GetPrices() takes start-count, is R/O ... it´s a Loader PricingLoader detailedPricingLoader = ServiceLocator.Current.GetInstance <PricingLoader>(); // detailedPricingLoader.GetPrices() // Good set of methods, no paging (GetChildrenPrices-obsoleted), gets allmost all ReadOnlyPricingLoader readOnlyPricingLoader = ServiceLocator.Current.GetInstance <ReadOnlyPricingLoader>(); // detailedPricingLoader. as the service //readOnlyPricingLoader.GetChildrenPrices(...) // deprecated var p = readOnlyPricingLoader.GetDefaultPrice(CurrentContent.ContentLink); // could use this "loader" on the front-end...instead of the service // PriceService R/O-pricing ("the optimized service" (from the good old R3-era ´:`)) // ... that´s why we have some confusing stuff left in the system (it entered here before the "Content-Model" was in place) CatalogKey catKey = new CatalogKey(CurrentContent.Code); // Catalogkey... example of legacy // Note: CatalogKey is gone when using the new Inventory system. There you can go by "code" // ...will probably file a blemish-bug on this // return full sets of price data for the specified catalog entries? // ...also takes an Enumerable var pricesByKey = _priceService.GetCatalogEntryPrices(catKey); // need catalogKey ( or IEnumerable of those ) var priceByDefault = _priceService.GetDefaultPrice( // Market, time, CatKey & Currency currentMarket.Service.GetCurrentMarket().MarketId.Value , DateTime.UtcNow , catKey , new Currency("usd")); //priceService.GetPrices( //...3:rd overload takes an IEnumerable of CatalogKeyAndQuantity // The GetPrices methods return filtered data for the specified catalog entries. Returned price values // ...will match all specified The CatalogKeyAndQuantity class may be used to get prices // ...for multiple entries, with different quantities for each, in a single request // for the R/O-PriceService CatalogKeyAndQuantity keyAndQtyExample = new CatalogKeyAndQuantity(catKey, 12); // second as an IEnumerable of keys // third as an IEnumerable of "KeysAndQty" //_priceService.GetPrices(); // If custom built "Optimized"... // ...then need a mechanism for synchronizing with a custom detail service, then it must call // IPriceDetailService.ReplicatePriceServiceChanges on all edits to update the optimized data store #region ... not much of a demo - PrintToPage and Housekeeping //Response.Write("<br/>"); //Response.Write("ContentTypeID" + CurrentContent.ContentTypeID + "<br/>"); //Response.Write("PriceRef.ID: " + CurrentContent.PriceReference.ID + "<br/>"); //Response.Write("PriceDetails <br/>"); //p1.ForEach(p => Response.Write("UnitPrice: " + p.UnitPrice.Amount.ToString() + "<br/>")); //Response.Write("PriceValueId: " + p1.FirstOrDefault().PriceValueId + "<br/>"); //Response.Write("UnitPrice: " + p1.FirstOrDefault().UnitPrice.Amount.ToString() + "<br/>"); //Response.Write("<br/>"); //Response.Write("PriceService <br/>"); // + "<br/>" //p2.ToList().ForEach(p => Response.Write("UnitPrice: " + p.UnitPrice.Amount.ToString() + "<br/>")); //Response.Write("<br/>"); //// node //Response.Write("PriceList at ParentNode: " + contentLoader.Get<IContent>(CurrentContent.ParentLink).Name + "<br/>"); //List<IPriceDetailValue> listFromNode = priceDetails.List(CurrentContent.ParentLink).ToList(); //listFromNode.ForEach(nl => Response.Write( // "CatalogKey: " + nl.CatalogKey.CatalogEntryCode // + " :: " + // "UnitPrice: " + nl.UnitPrice.Amount.ToString() + "<br/>")); //Response.Write("<br/>"); // EPiServer.Commerce.Catalog.ContentTypes.PricingExtensions // ...getPrices() ... by the "ReadOnlyPricingLoader" // Below, get all prices //EPiServer.Commerce.SpecializedProperties.ItemCollection // <EPiServer.Commerce.SpecializedProperties.Price> // prices = CurrentContent.GetPrices(); // 5 overloads, the third takes "Market" and "CustomerPricing" //var pp = CurrentContent.GetPrices(MarketId.Default, new CustomerPricing(CustomerPricing.PriceType.PriceGroup, "SpecialFriends")); //// PriceType & PriceCode in API , SaleType & SaleCode in UI //// should have the qty here ... ? //Response.Write("By Extesion methods <br/>"); //prices.ToList().ForEach(p => Response.Write(p.UnitPrice.Amount + "<br/>")); //pp.ToList().ForEach(p => Response.Write("SpecialFriends: " + p.UnitPrice.Amount.ToString() + "<br/>")); #endregion /* Price Filter - good stuff */ List <Currency> currencies = new List <Currency>(); List <CustomerPricing> custprices = new List <CustomerPricing>(); // SaleCode (UI) or PriceGroup (code) (string) ... the Cust-Group // CM / CMS UI: SaleType - SaleCode // API: PriceType, PriceCode (string) PriceFilter filter = new PriceFilter() { Quantity = 2, Currencies = new Currency[] { "USD", "SEK" }, CustomerPricing = new CustomerPricing[] { new CustomerPricing(CustomerPricing.PriceType.AllCustomers, null), new CustomerPricing(CustomerPricing.PriceType.UserName, "Kalle"), new CustomerPricing(CustomerPricing.PriceType.PriceGroup, "MyBuddies") // or several... // may also want to add the personal account and/or custom price-types }, ReturnCustomerPricing = false // ...see below for info // interpretation of the CustomerPricing property... if true; gets all that applies }; #region Info ReturnCustomerPricing /* The ReturnCustomerPricing property controls the interpretation of the CustomerPricing property. * If the value of this property is false, and multiple price values that are identical except for the customer pricing * (but both match the prices targeted by the method call) could be returned, then only the entry in that grouping with * the lowest price will be returned (this is the more common use case). If the value of this property is true, * then all prices will be returned individually. The default value is false. As an example, * suppose a catalog entry has a price of $10.00 for all customers, and $9.00 for one particular customer. * A call to a GetPrices method that would match both prices, and has ReturnCustomerPricing set to false, * would only get the $9.00 price in the result set. If ReturnCustomerPricing was set to true for the same call, * both the $9.00 and $10.00 price would be returned. */ #endregion // The rest needed, CatKey, Market, TimeStamp CatalogKey catalogKey = new CatalogKey(CurrentContent.Code); // 4 overloads App-ID is gone IEnumerable <IPriceValue> priceValues = _priceService.GetPrices( // overloaded - one or more CatKey or CatalogKeyAndQuantity MarketId.Default, FrameworkContext.Current.CurrentDateTime , catalogKey, filter); Price pp = new Price(priceValues.First()); PriceValue pv2 = new PriceValue(priceValues.First()); // ppp is a Price (above), created from an IPriceDetailValue IPriceValue PV3 = ppp.ToPriceValue(); // // just checking decimal onePrice = priceValues.FirstOrDefault().UnitPrice.Amount; }
public static ProductTileViewModel GetProductTileViewModel(this EntryContentBase entry, IMarket market, Currency currency, bool isFeaturedProduct = false) { var entryRecommendations = entry as IProductRecommendations; var product = entry; var entryUrl = ""; var firstCode = ""; var type = typeof(GenericProduct); if (entry is GenericProduct) { var variants = GetProductVariants(entry); if (variants != null && variants.Any()) { firstCode = variants.First().Code; } entryUrl = UrlResolver.Value.GetUrl(entry.ContentLink); } if (entry is GenericBundle) { type = typeof(GenericBundle); firstCode = product.Code; entryUrl = UrlResolver.Value.GetUrl(product.ContentLink); } if (entry is GenericPackage) { type = typeof(GenericPackage); firstCode = product.Code; entryUrl = UrlResolver.Value.GetUrl(product.ContentLink); } if (entry is GenericVariant) { var variantEntry = entry as GenericVariant; type = typeof(GenericVariant); firstCode = entry.Code; var parentLink = entry.GetParentProducts().FirstOrDefault(); if (ContentReference.IsNullOrEmpty(parentLink)) { product = ContentLoader.Value.Get <EntryContentBase>(variantEntry.ContentLink); entryUrl = UrlResolver.Value.GetUrl(variantEntry.ContentLink); } else { product = ContentLoader.Value.Get <EntryContentBase>(parentLink) as GenericProduct; entryUrl = UrlResolver.Value.GetUrl(product.ContentLink) + "?variationCode=" + variantEntry.Code; } } IPriceValue price = PriceCalculationService.GetSalePrice(firstCode, market.MarketId, currency); if (price == null) { price = GetEmptyPrice(entry, market, currency); } IPriceValue discountPrice = price; if (price.UnitPrice.Amount > 0 && !string.IsNullOrEmpty(firstCode)) { discountPrice = PromotionService.Value.GetDiscountPrice(new CatalogKey(firstCode), market.MarketId, currency); } bool isAvailable = price.UnitPrice.Amount > 0; return(new ProductTileViewModel { ProductId = product.ContentLink.ID, Brand = entry.Property.Keys.Contains("Brand") ? entry.Property["Brand"]?.Value?.ToString() ?? "" : "", Code = product.Code, DisplayName = entry.DisplayName, Description = entry.Property.Keys.Contains("Description") ? entry.Property["Description"]?.Value != null ? ((XhtmlString)entry.Property["Description"].Value).ToHtmlString() : "" : "", LongDescription = ShortenLongDescription(entry.Property.Keys.Contains("LongDescription") ? entry.Property["LongDescription"]?.Value != null ? ((XhtmlString)entry.Property["LongDescription"].Value).ToHtmlString() : "" : ""), PlacedPrice = price.UnitPrice, DiscountedPrice = discountPrice.UnitPrice, FirstVariationCode = firstCode, ImageUrl = AssetUrlResolver.Value.GetAssetUrl <IContentImage>(entry), VideoAssetUrl = AssetUrlResolver.Value.GetAssetUrl <IContentVideo>(entry), Url = entryUrl, IsAvailable = isAvailable, OnSale = entry.Property.Keys.Contains("OnSale") && ((bool?)entry.Property["OnSale"]?.Value ?? false), NewArrival = entry.Property.Keys.Contains("NewArrival") && ((bool?)entry.Property["NewArrival"]?.Value ?? false), ShowRecommendations = entryRecommendations != null ? entryRecommendations.ShowRecommendations : true, EntryType = type, ProductStatus = entry.Property.Keys.Contains("ProductStatus") ? entry.Property["ProductStatus"]?.Value?.ToString() ?? "Active" : "Active", Created = entry.Created, IsFeaturedProduct = isFeaturedProduct }); }