private IEnumerable<PromotionRecord> CalculateCartDiscounts()
		{
			var records = new List<PromotionRecord>();
			foreach (var form in CurrentOrderGroup.OrderForms)
			{
				var set = GetPromotionEntrySetFromOrderForm(form);

				// create context 
				var ctx = new Dictionary<string, object> { { PromotionEvaluationContext.TargetSet, set } };

				var couponCode = CustomerSessionService.CustomerSession.CouponCode;

				//1. Prepare marketing context
				var evaluationContext = new PromotionEvaluationContext
				{
					ContextObject = ctx,
					CustomerId = CustomerSessionService.CustomerSession.CustomerId,
					CouponCode = CustomerSessionService.CustomerSession.CouponCode,
					PromotionType = PromotionType.CartPromotion,
					Currency = CustomerSessionService.CustomerSession.Currency,
					Store = CustomerSessionService.CustomerSession.StoreId,
					IsRegisteredUser = CustomerSessionService.CustomerSession.IsRegistered,
					IsFirstTimeBuyer = CustomerSessionService.CustomerSession.IsFirstTimeBuyer
				};

				//2. Evaluate 
				//var evaluator = new DefaultPromotionEvaluator(MarketingRepository, PromotionUsageProvider, new IEvaluationPolicy[] { new GlobalExclusivityPolicy(), new CartSubtotalRewardCombinePolicy(), new ShipmentRewardCombinePolicy() }, CacheRepository);
				var promotions = PromotionEvaluator.EvaluatePromotion(evaluationContext);
				var rewards = promotions.SelectMany(x => x.Rewards);

				//3. Generate warnings
				if (!string.IsNullOrEmpty(couponCode) && !promotions.Any(p => (p.CouponId != null && p.Coupon.Code == couponCode)
					|| (p.CouponSetId != null && p.CouponSet.Coupons.Any(c => c.Code == couponCode))))
				{
					RegisterWarning(WorkflowMessageCodes.COUPON_NOT_APPLIED, "Coupon doesn't exist or is not applied");
				}

				records.AddRange(rewards.Select(reward => new PromotionRecord
					{
						AffectedEntriesSet = set,
						TargetEntriesSet = set,
						Reward = reward,
						PromotionType = PromotionType.CartPromotion
					}));
			}

			return records.ToArray();
		}
		private IEnumerable<PromotionRecord> CalculateLineItemDiscounts()
		{
			var records = new List<PromotionRecord>();
			foreach (var form in CurrentOrderGroup.OrderForms)
			{
				foreach (var lineItem in form.LineItems)
				{
					var set = new PromotionEntrySet();
					var entry = GetPromotionEntryFromLineItem(lineItem);
					set.Entries.Add(entry);

					// create context 
					var ctx = new Dictionary<string, object> { { PromotionEvaluationContext.TargetSet, set } };

					//1. Prepare marketing context
					var evaluationContext = new PromotionEvaluationContext
						{
							ContextObject = ctx,
							CustomerId = CustomerSessionService.CustomerSession.CustomerId,
							CouponCode = CustomerSessionService.CustomerSession.CouponCode,
							Currency = CustomerSessionService.CustomerSession.Currency,
							PromotionType = PromotionType.CatalogPromotion,
							Store = CustomerSessionService.CustomerSession.StoreId,
							IsRegisteredUser = CustomerSessionService.CustomerSession.IsRegistered,
							IsFirstTimeBuyer = CustomerSessionService.CustomerSession.IsFirstTimeBuyer
						};

					//2. Evaluate 
					var promotions = PromotionEvaluator.EvaluatePromotion(evaluationContext);
					var rewards = promotions.SelectMany(x => x.Rewards);

					records.AddRange(rewards.Select(reward => new PromotionRecord
						{
							AffectedEntriesSet = set,
							TargetEntriesSet = set,
							Reward = reward,
							PromotionType = PromotionType.CatalogPromotion
						}));
				}
			}

			return records.ToArray();
		}
		public decimal GetItemDiscountPrice(Item item, Price lowestPrice, Hashtable tags = null)
		{
			var price = lowestPrice.Sale ?? lowestPrice.List;

			var session = _customerSession.CustomerSession;

			// apply discounts
			// create context 
			var ctx = new Dictionary<string, object>();
			var set = GetPromotionEntrySetFromItem(item, price, tags);
			ctx.Add(PromotionEvaluationContext.TargetSet, set);

			var evaluationContext = new PromotionEvaluationContext
				{
					ContextObject = ctx,
					CustomerId = session.CustomerId,
					CouponCode = null,
					Currency = session.Currency,
					PromotionType = PromotionType.CatalogPromotion,
					Store = session.StoreId,
					IsRegisteredUser = session.IsRegistered,
					IsFirstTimeBuyer = session.IsFirstTimeBuyer
				};

			var promotions = _evaluator.EvaluatePromotion(evaluationContext);
            var rewards = promotions.SelectMany(x => x.Rewards).ToArray();
            var records = new List<PromotionRecord>();

            records.AddRange(rewards.Select(reward => new PromotionRecord
            {
                AffectedEntriesSet = set,
                TargetEntriesSet = set,
                Reward = reward,
                PromotionType = PromotionType.CatalogPromotion
            }));

            //Filter by policies
		    var allRecords = _evaluator.EvaluatePolicies(records.ToArray());

            var lineItemRewards = allRecords.Select(x=>x.Reward).OfType<CatalogItemReward>().ToArray();

			var discountTotal = 0m;
			foreach (var reward in lineItemRewards)
			{
				if (reward.QuantityLimit > 1) // skip everything for higher quantity
				{
					continue;
				}

				if (!String.IsNullOrEmpty(reward.SkuId)) // filter out free item rewards
				{
					if (!item.ItemId.Equals(reward.SkuId, StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
				}

				var discountAmount = 0m;
				const int quantity = 1;
				if (reward.AmountTypeId == (int)RewardAmountType.Relative)
				{
					discountAmount = Math.Round(quantity*price*reward.Amount*0.01m,2);
				}
				else if (reward.AmountTypeId == (int)RewardAmountType.Absolute)
				{
					discountAmount =  Math.Round(quantity*reward.Amount,2);
				}
				discountTotal += discountAmount;
			}

			return discountTotal;
		}