public static Price DefaultPrice(this ProductContent productContent, ReadOnlyPricingLoader pricingLoader, IRelationRepository relationRepository) { var maxPrice = new Price(); var variationLinks = productContent.GetVariants(relationRepository); foreach (var variationLink in variationLinks) { var defaultPrice = pricingLoader.GetDefaultPrice(variationLink); if (defaultPrice.UnitPrice.Amount > maxPrice.UnitPrice.Amount) { maxPrice = defaultPrice; } } return(maxPrice); }
private Price DefaultPrice(IEnumerable <ContentReference> variationLinks, ReadOnlyPricingLoader pricingLoader) { if (pricingLoader == null) { throw new ArgumentNullException(nameof(pricingLoader)); } var maxPrice = new Price(); foreach (var variationLink in variationLinks) { var defaultPrice = pricingLoader.GetDefaultPrice(variationLink); if (defaultPrice.UnitPrice.Amount > maxPrice.UnitPrice.Amount) { maxPrice = defaultPrice; } } return(maxPrice); }
// 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; }
// 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 * * - Add AllCustomers * Check Cust-Group * ...Effective-Cust-Group * Get the service * Set the filter * Fetch ... priceService.GetPrices + get the cheapest (note: always cheapest) * Get a ... IPriceValue and then... * ....return new Price(priceValue.UnitPrice); * * 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 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 store // 3 overloads... the 3:rd with filter & Market List <IPriceDetailValue> priceList1 = _priceDetailService.List(CurrentContent.ContentLink).ToList(); EPiServer.Commerce.SpecializedProperties.Price aPrice = new EPiServer.Commerce.SpecializedProperties.Price(priceList1.FirstOrDefault()); // just checking // ...have a CreatePrice("theCode"); // further below /* dbo.PriceType.sql * 0 All Customers * 1 Customer * 2 Customer Price Group */ // 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 it all ReadOnlyPricingLoader readOnlyPricingLoader = ServiceLocator.Current.GetInstance <ReadOnlyPricingLoader>(); // detailedPricingLoader. as the service var p = readOnlyPricingLoader.GetDefaultPrice(CurrentContent.ContentLink); // 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 // 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 // ...better than MarketId.Default , DateTime.UtcNow , catKey , new Currency("usd")); CatalogKeyAndQuantity keyAndQtyExample = new CatalogKeyAndQuantity(catKey, 12); // first overload as GetDefaultPrice // second as an IEnumerable of keys // third as an IEnumerable of keysAndQty // 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 /* Price Filter */ 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 = 2M, Currencies = new Currency[] { "USD", "SEK" }, CustomerPricing = new CustomerPricing[] { new CustomerPricing(CustomerPricing.PriceType.AllCustomers, null), new CustomerPricing(CustomerPricing.PriceType.PriceGroup, "MyBuddies") // or several... }, ReturnCustomerPricing = true // ...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); // 2 useful overloads IEnumerable <IPriceValue> priceValues = _priceService.GetPrices( MarketId.Default, FrameworkContext.Current.CurrentDateTime, catalogKey, filter); decimal onePrice = priceValues.FirstOrDefault().UnitPrice.Amount; // just checking }