/// <summary> /// Implements the IPricingCalculator interface to calculate item price trade agreement prices. /// </summary> /// <param name="salesLines">The item lines which need prices.</param> /// <param name="priceContext">The configuration of the overall pricing context for the calculation.</param> /// <param name="pricingDataManager">Instance of pricing data manager to access pricing data.</param> /// <returns>Sets of possible price lines keyed by item line Id.</returns> public Dictionary <string, IEnumerable <PriceLine> > CalculatePriceLines( IEnumerable <SalesLine> salesLines, PriceContext priceContext, IPricingDataAccessor pricingDataManager) { Tuple <DateTimeOffset, DateTimeOffset> dateRange = PricingEngine.GetMinAndMaxActiveDates(salesLines, priceContext.ActiveDate); // look up all trade agreements for given items and context HashSet <string> itemIds = new HashSet <string>(salesLines.Select(s => s.ItemId).Distinct(), StringComparer.OrdinalIgnoreCase); ReadOnlyCollection <TradeAgreement> tradeAgreements = pricingDataManager.ReadPriceTradeAgreements( itemIds, PriceContextHelper.GetAllPriceGroupsForPrice(priceContext), priceContext.CustomerAccount, dateRange.Item1, dateRange.Item2, priceContext.CurrencyCode, QueryResultSettings.AllRecords) as ReadOnlyCollection <TradeAgreement>; if (priceContext.IsDiagnosticsCollected && tradeAgreements.Any()) { priceContext.PricingEngineDiagnosticsObject.AddTradeAgreementsConsidered(tradeAgreements.ToList()); } var agreementsByItemId = IndexAgreementsByItemId(tradeAgreements); var discountParameters = DiscountParameters.CreateAndInitialize(priceContext.PriceParameters); Dictionary <string, IEnumerable <PriceLine> > itemPriceLines; Dictionary <string, decimal> itemQuantites = null; if (priceContext.PriceCalculationMode == PricingCalculationMode.Transaction) { itemQuantites = GetItemQuantities(salesLines); } itemPriceLines = new Dictionary <string, IEnumerable <PriceLine> >(StringComparer.OrdinalIgnoreCase); foreach (SalesLine salesLine in salesLines) { Tuple <decimal, string> priceCustPriceGroup = CalculateAgreementPriceLine(salesLines, salesLine, priceContext, agreementsByItemId, discountParameters, itemQuantites); if (priceCustPriceGroup.Item1 != decimal.Zero) { itemPriceLines.Add(salesLine.LineId, new List <PriceLine>(1) { ConstructTradeAgreementPriceLine(priceCustPriceGroup) }); } } return(itemPriceLines); }
/// <summary> /// Implements the IPricingCalculator interface to calculate item price adjustment prices. /// </summary> /// <param name="salesLines">The item lines which need prices.</param> /// <param name="priceContext">The configuration of the overall pricing context for the calculation.</param> /// <param name="pricingDataManager">Instance of pricing data manager to access pricing data.</param> /// <returns>Sets of possible price lines keyed by item line Id.</returns> public Dictionary <string, IEnumerable <PriceLine> > CalculatePriceLines( IEnumerable <SalesLine> salesLines, PriceContext priceContext, IPricingDataAccessor pricingDataManager) { // get pairs of product Id and distinct variant Id from lines to search by var productIds = salesLines .Select(sl => new ItemUnit { ItemId = sl.ItemId, VariantInventoryDimensionId = sl.InventoryDimensionId ?? string.Empty, DistinctProductVariant = sl.Variant != null ? sl.Variant.DistinctProductVariantId : 0, Product = sl.MasterProductId == 0 ? sl.ProductId : sl.MasterProductId }) .Distinct().ToList(); Tuple <DateTimeOffset, DateTimeOffset> dateRange = PricingEngine.GetMinAndMaxActiveDates(salesLines, priceContext.ActiveDate); // datetime to use depends on listing/cart scenario if (priceContext.PriceCalculationMode == PricingCalculationMode.Independent) { dateRange = new Tuple <DateTimeOffset, DateTimeOffset>(dateRange.Item1, dateRange.Item2); } // fetch all price adjustments (and any related validation periods) ISet <string> allPriceGroups = PriceContextHelper.GetAllPriceGroupsForPrice(priceContext); IEnumerable <PriceAdjustment> adjustments = pricingDataManager.ReadPriceAdjustments( productIds, allPriceGroups, dateRange.Item1, dateRange.Item2, QueryResultSettings.AllRecords) as IEnumerable <PriceAdjustment>; if (priceContext.IsDiagnosticsCollected && adjustments.Any()) { priceContext.PricingEngineDiagnosticsObject.AddPriceAdjustmentsConsidered(adjustments.Select(x => x.OfferId).ToList()); } HashSet <string> offerIds = new HashSet <string>(); foreach (PriceAdjustment adjustment in adjustments) { offerIds.Add(adjustment.OfferId); } IDictionary <string, IList <PriceGroup> > adjustmentPriceGroupDictionary = PriceContextHelper.GetRetailDiscountPriceGroupDictionaryFilteredByTransaction( pricingDataManager, offerIds, allPriceGroups); FixAdjustmentPriorityFromPriceGroups(adjustments, adjustmentPriceGroupDictionary); // "index" adjustments by item Id & dimensions var adjustmentDict = adjustments .GroupBy(a => GetItemIdInventDimIdKey(a.ItemId, a.InventoryDimensionId)) .ToDictionary(grp => grp.Key, grp => grp.ToList(), StringComparer.OrdinalIgnoreCase); var promotionLines = new Dictionary <string, IList <PriceAdjustment> >(StringComparer.OrdinalIgnoreCase); foreach (var line in salesLines) { // get item price adjustments, continue to next item if none found var key = GetItemIdInventDimIdKey(line.ItemId, line.InventoryDimensionId); List <PriceAdjustment> itemAdjustments; if (!adjustmentDict.TryGetValue(key, out itemAdjustments)) { continue; } List <PriceAdjustment> allApplicablePriceAdjustmentsForItem = new List <PriceAdjustment>(); foreach (var a in itemAdjustments) { IList <PriceGroup> priceGroups = null; adjustmentPriceGroupDictionary.TryGetValue(a.OfferId, out priceGroups); HashSet <string> priceGroupIdSet = new HashSet <string>(StringComparer.OrdinalIgnoreCase); priceGroupIdSet.AddRange(priceGroups.Select(p => p.GroupId)); if (PriceContextHelper.IsApplicableForPrice(priceContext, priceGroupIdSet, line.CatalogIds) && IsAdjustmentActiveOnSalesLine(line, a, priceContext.ActiveDate) && IsMatchUnitOfMeasure(line, a) && IsMatchCurrency(priceContext.CurrencyCode, a)) { allApplicablePriceAdjustmentsForItem.Add(a); } } if (allApplicablePriceAdjustmentsForItem.Any()) { // We apply price adjustment from only those with highest priority. int highestPriority = allApplicablePriceAdjustmentsForItem.Max(p => p.PricingPriorityNumber); IEnumerable <PriceAdjustment> priceAdjustmentsWithHighestPriorityForItem = allApplicablePriceAdjustmentsForItem.Where(p => p.PricingPriorityNumber == highestPriority); // filter price adjustments by active validation periods before adding to dictionary foreach (var a in priceAdjustmentsWithHighestPriorityForItem) { IList <PriceAdjustment> promos; if (!promotionLines.TryGetValue(line.LineId, out promos)) { promos = new List <PriceAdjustment>(); promotionLines.Add(line.LineId, promos); } promos.Add(a); } } } // convert price adjustments to price lines for the sales lines var priceLines = PriceAdjustmentsToPriceLines(salesLines, promotionLines); return(priceLines); }