Exemple #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OrderDiscount"/> class.
        /// </summary>
        /// <param name="orderDiscount">The order discount.</param>
        /// <param name="orderInfo">The order information.</param>
        internal OrderDiscount(IOrderDiscount orderDiscount, OrderInfo orderInfo)
        {
            var discountOrder = orderDiscount as DiscountOrder;

            if (discountOrder == null)
            {
                discountOrder = IO.Container.Resolve <IOrderDiscountService>().GetAll(orderInfo.Localization).FirstOrDefault(discount => discount.OriginalId == orderDiscount.OriginalId) as DiscountOrder;
            }

            if (discountOrder != null)
            {
                Title       = discountOrder.Title;
                Description = discountOrder.Description;
            }
            //orderInfo.OrderLines.ForEach(line => line.OrderDiscountInCents = 0); // reset hmm
            DiscountAmount = new DiscountAmount(IO.Container.Resolve <IDiscountCalculationService>().DiscountAmountForOrder(orderDiscount, orderInfo), orderInfo.PricesAreIncludingVAT, orderInfo.AverageOrderVatPercentage);

            OriginalDiscountId     = orderDiscount.OriginalId;
            DiscountType           = orderDiscount.DiscountType;
            DiscountValue          = orderDiscount.DiscountValue;
            Condition              = orderDiscount.Condition;
            NumberOfItemsCondition = orderDiscount.NumberOfItemsCondition;
            MinimalOrderAmount     = orderDiscount.MinimumOrderAmount.ValueInCents();
            CouponCode             = orderDiscount.CouponCode;
        }
		internal OrderDiscount(ILocalization localization, IOrderDiscount discountOrder, OrderInfo order) : this(localization)
		{
			Id = discountOrder.Id;
			OriginalId = discountOrder.OriginalId;
			DiscountType = discountOrder.DiscountType;
			DiscountValue = discountOrder.DiscountValue;
			Condition = discountOrder.Condition;
			NumberOfItemsCondition = discountOrder.NumberOfItemsCondition;
			RequiredItemIds = discountOrder.RequiredItemIds ?? new List<int>();
			MinimalOrderAmount = discountOrder.MinimumOrderAmount.ValueInCents();
			// todo: efficiency
			CouponCode = !string.IsNullOrWhiteSpace(discountOrder.CouponCode) ? discountOrder.CouponCode : 
				IO.Container.Resolve<ICouponCodeService>().GetAllForDiscount(discountOrder.Id).Select(c => c.CouponCode).Intersect(order.CouponCodes).FirstOrDefault();
			MemberGroups = discountOrder.MemberGroups;
			AffectedOrderlines = discountOrder.AffectedOrderlines;
			AffectedProductTags = discountOrder.AffectedProductTags == null ? Enumerable.Empty<string>() : discountOrder.AffectedProductTags.ToArray();
			Ranges = discountOrder.Ranges;
			OncePerCustomer = discountOrder.OncePerCustomer;
			IncludeShippingInOrderDiscountableAmount = discountOrder.IncludeShippingInOrderDiscountableAmount;
			TypeAlias = discountOrder.TypeAlias;
		}
        internal OrderDiscount(ILocalization localization, IOrderDiscount discountOrder, OrderInfo order) : this(localization)
        {
            Id                     = discountOrder.Id;
            OriginalId             = discountOrder.OriginalId;
            DiscountType           = discountOrder.DiscountType;
            DiscountValue          = discountOrder.DiscountValue;
            Condition              = discountOrder.Condition;
            NumberOfItemsCondition = discountOrder.NumberOfItemsCondition;
            RequiredItemIds        = discountOrder.RequiredItemIds ?? new List <int>();
            MinimalOrderAmount     = discountOrder.MinimumOrderAmount.ValueInCents();
            // todo: efficiency
            CouponCode = !string.IsNullOrWhiteSpace(discountOrder.CouponCode) ? discountOrder.CouponCode :
                         IO.Container.Resolve <ICouponCodeService>().GetAllForDiscount(discountOrder.Id).Select(c => c.CouponCode).Intersect(order.CouponCodes).FirstOrDefault();
            MemberGroups        = discountOrder.MemberGroups;
            AffectedOrderlines  = discountOrder.AffectedOrderlines;
            AffectedProductTags = discountOrder.AffectedProductTags == null?Enumerable.Empty <string>() : discountOrder.AffectedProductTags.ToArray();

            Ranges          = discountOrder.Ranges;
            OncePerCustomer = discountOrder.OncePerCustomer;
            IncludeShippingInOrderDiscountableAmount = discountOrder.IncludeShippingInOrderDiscountableAmount;
            TypeAlias = discountOrder.TypeAlias;
        }
		/// <summary>
		/// Initializes a new instance of the <see cref="OrderDiscount"/> class.
		/// </summary>
		/// <param name="orderDiscount">The order discount.</param>
		/// <param name="orderInfo">The order information.</param>
		internal OrderDiscount(IOrderDiscount orderDiscount, OrderInfo orderInfo)
		{
			var discountOrder = orderDiscount as DiscountOrder;
			if (discountOrder == null)
			{
				discountOrder = IO.Container.Resolve<IOrderDiscountService>().GetAll(orderInfo.Localization).FirstOrDefault(discount => discount.OriginalId == orderDiscount.OriginalId) as DiscountOrder;
			}

			if (discountOrder != null)
			{
				Title = discountOrder.Title;
				Description = discountOrder.Description;
			}
			//orderInfo.OrderLines.ForEach(line => line.OrderDiscountInCents = 0); // reset hmm
			DiscountAmount = new DiscountAmount(IO.Container.Resolve<IDiscountCalculationService>().DiscountAmountForOrder(orderDiscount, orderInfo), orderInfo.PricesAreIncludingVAT, orderInfo.AverageOrderVatPercentage);

			OriginalDiscountId = orderDiscount.OriginalId;
			DiscountType = orderDiscount.DiscountType;
			DiscountValue = orderDiscount.DiscountValue;
			Condition = orderDiscount.Condition;
			NumberOfItemsCondition = orderDiscount.NumberOfItemsCondition;
			MinimalOrderAmount = orderDiscount.MinimumOrderAmount.ValueInCents();
			CouponCode = orderDiscount.CouponCode;
		}
		public int DiscountAmountForOrder(IOrderDiscount discount, OrderInfo orderInfo, bool applyDiscountEffects = false)//, IAuthenticationProvider authenticationProvider = null)
		{
			if (!string.IsNullOrEmpty(discount.CouponCode) && !orderInfo.CouponCodes.Contains(discount.CouponCode))
			{
				return 0;
			}

			if (orderInfo.Status == OrderStatus.Incomplete)
			{
				var coupons = _couponCodeService.GetAllForDiscount(discount.Id);
				if (coupons.Any()) //
				{
					var availableCoupons = coupons.Where(c => c.NumberAvailable > 0).Select(c => c.CouponCode);
					if (!availableCoupons.Intersect(orderInfo.CouponCodes).Any())
						return 0;
				}
			}

			var authenticationProvider = IO.Container.Resolve<IAuthenticationProvider>();

			if (discount.MemberGroups.Any() && !discount.MemberGroups.Intersect(authenticationProvider.RolesForCurrentUser).Any())
			{
				return 0;
			}

			if (discount.OncePerCustomer && !string.IsNullOrEmpty(authenticationProvider.CurrentLoginName))
			{
				var ordersforCurrentMember = OrderHelper.GetOrdersForCustomer(authenticationProvider.CurrentLoginName).Where(x => x.Status != OrderStatus.Incomplete && x.Status != OrderStatus.Cancelled && x.Status != OrderStatus.Returned);

				if (ordersforCurrentMember.Any(x => x.Discounts.Any(d => d.OriginalId == discount.Id)))
				{
					return 0;
				}
			}
			
			var applicableOrderLines = !discount.AffectedOrderlines.Any() ? orderInfo.OrderLines : _orderService.GetApplicableOrderLines(orderInfo, discount.AffectedOrderlines);

			if (discount.AffectedProductTags != null && discount.AffectedProductTags.Any())
			{
				applicableOrderLines = applicableOrderLines.Where(line => line.ProductInfo.Tags.Intersect(discount.AffectedProductTags).Any()).ToList();
			}
			var isSellableUnitDiscount = discount.AffectedOrderlines.Any() || (discount.AffectedProductTags != null && discount.AffectedProductTags.Any());

			var orderSellableUnits = new List<SellableUnit>();
			foreach (var line in applicableOrderLines)
				//for (var i = 0; i < line.ProductInfo.ItemCount; i++)
					orderSellableUnits.AddRange(line.SellableUnits); // maak een lijst met de prijzen van alle (losse) items van de order

			var numberOfItemsLeftOutOfSets = discount.NumberOfItemsCondition == 0 ? 0 : applicableOrderLines.Sum(line => line.ProductInfo.ItemCount.GetValueOrDefault(1))%discount.NumberOfItemsCondition;
			var applicableSellableUnits = orderSellableUnits.OrderBy(item => item.PriceInCents).Take(orderSellableUnits.Count - numberOfItemsLeftOutOfSets).ToList();

			var rangedDiscountValue = RangedDiscountValueForOrder(discount, orderInfo); // todo: not localized
			var discountAmount = rangedDiscountValue;
			var maximumDiscountableAmount = 0L;
			var timesApplicable = 1;
			if (discount.Condition == DiscountOrderCondition.None)
			{
				maximumDiscountableAmount = applicableOrderLines.Sum(orderline => orderline.AmountInCents - (orderline.GetOriginalAmount(false, true) -  orderline.GetOriginalAmount(true, true)));
				timesApplicable = applicableOrderLines.Sum(orderLine => orderLine.ProductInfo.ItemCount.GetValueOrDefault(1));
			}
			else if (discount.Condition == DiscountOrderCondition.OnTheXthItem && discount.NumberOfItemsCondition > 0)
			{
				isSellableUnitDiscount = true;
				// todo: test
				discountAmount = discountAmount*applicableSellableUnits.Count()/discount.NumberOfItemsCondition;
				applicableSellableUnits = applicableSellableUnits.Take(orderSellableUnits.Count / discount.NumberOfItemsCondition).ToList();
				maximumDiscountableAmount = applicableSellableUnits.Sum(su => su.PriceInCents); // bereken de korting over de x goedkoopste items, waarbij x het aantal sets in de order is
			}
			else if (discount.Condition == DiscountOrderCondition.PerSetOfXItems && discount.NumberOfItemsCondition > 0)
			{
				isSellableUnitDiscount = true;
				timesApplicable = applicableSellableUnits.Count() / discount.NumberOfItemsCondition;
				if (discount.DiscountType == DiscountType.Amount)
				{
					applicableSellableUnits = applicableSellableUnits.Take(orderSellableUnits.Count / discount.NumberOfItemsCondition).ToList();
				}
				discountAmount = discountAmount*applicableSellableUnits.Count()/discount.NumberOfItemsCondition;
				maximumDiscountableAmount = applicableSellableUnits.Sum(su => su.PriceInCents);
			}

			if (discount.IncludeShippingInOrderDiscountableAmount)
			{
				maximumDiscountableAmount += orderInfo.ShippingProviderAmountInCents;
			}

			if (discount.DiscountType == DiscountType.Amount)
			{
				// currently not on SellableUnits, because that would break existing functionality

				if (applyDiscountEffects)
				{
					var amountDiscountEffect = new AmountDiscountEffect {Amount = rangedDiscountValue};
					if (isSellableUnitDiscount)
					{
						foreach (var su in applicableSellableUnits)
						{
							su.SellableUnitDiscountEffects.AddEffect(amountDiscountEffect);
						}
					}
					else
					{
						orderInfo.OrderDiscountEffects.AddEffect(amountDiscountEffect);
					}
				}
				
				return (int)Math.Min(discountAmount, maximumDiscountableAmount);
			}
			if (discount.DiscountType == DiscountType.Percentage)
			{
				// wanneer SellableUnit/OrderLine/Order
				if (applyDiscountEffects)
				{
					var percentageDiscountEffect = new PercentageDiscountEffect {Percentage = rangedDiscountValue/10000m};
					if (isSellableUnitDiscount)
					{
						foreach (var su in applicableSellableUnits)
						{
							su.SellableUnitDiscountEffects.AddEffect(percentageDiscountEffect);
						}
					}
					else
					{
						orderInfo.OrderDiscountEffects.AddEffect(percentageDiscountEffect);
					}
				}
				return DiscountHelper.PercentageCalculation(rangedDiscountValue, maximumDiscountableAmount);
			}
			if (discount.DiscountType == DiscountType.NewPrice)
			{
				if (applyDiscountEffects)
				{
					var newPriceDiscountEffect = new NewPriceDiscountEffect {NewPrice = rangedDiscountValue};
					foreach (var applicableSellableUnit in applicableSellableUnits)
					{
						applicableSellableUnit.SellableUnitDiscountEffects.AddEffect(newPriceDiscountEffect);
					}
				}
				if (discount.Condition == DiscountOrderCondition.OnTheXthItem && discount.NumberOfItemsCondition > 0)
				{
					return applicableSellableUnits.Take(orderSellableUnits.Count/discount.NumberOfItemsCondition).Select(su => Math.Max(0, su.PriceInCents - discountAmount)).Sum();
				}

				return (int)Math.Max(0, maximumDiscountableAmount - rangedDiscountValue*timesApplicable);
			}

			return 0;
		}
        public int DiscountAmountForOrder(IOrderDiscount discount, OrderInfo orderInfo, bool applyDiscountEffects = false)        //, IAuthenticationProvider authenticationProvider = null)
        {
            if (!string.IsNullOrEmpty(discount.CouponCode) && !orderInfo.CouponCodes.Contains(discount.CouponCode))
            {
                return(0);
            }

            if (orderInfo.Status == OrderStatus.Incomplete)
            {
                var coupons = _couponCodeService.GetAllForDiscount(discount.Id);
                if (coupons.Any())                 //
                {
                    var availableCoupons = coupons.Where(c => c.NumberAvailable > 0).Select(c => c.CouponCode);
                    if (!availableCoupons.Intersect(orderInfo.CouponCodes).Any())
                    {
                        return(0);
                    }
                }
            }

            var authenticationProvider = IO.Container.Resolve <IAuthenticationProvider>();

            if (discount.MemberGroups.Any() && !discount.MemberGroups.Intersect(authenticationProvider.RolesForCurrentUser).Any())
            {
                return(0);
            }

            if (discount.OncePerCustomer && !string.IsNullOrEmpty(authenticationProvider.CurrentLoginName))
            {
                var ordersforCurrentMember = OrderHelper.GetOrdersForCustomer(authenticationProvider.CurrentLoginName).Where(x => x.Status != OrderStatus.Incomplete && x.Status != OrderStatus.Cancelled && x.Status != OrderStatus.Returned);

                if (ordersforCurrentMember.Any(x => x.Discounts.Any(d => d.OriginalId == discount.Id)))
                {
                    return(0);
                }
            }

            var applicableOrderLines = !discount.AffectedOrderlines.Any() ? orderInfo.OrderLines : _orderService.GetApplicableOrderLines(orderInfo, discount.AffectedOrderlines);

            if (discount.AffectedProductTags != null && discount.AffectedProductTags.Any())
            {
                applicableOrderLines = applicableOrderLines.Where(line => line.ProductInfo.Tags.Intersect(discount.AffectedProductTags).Any()).ToList();
            }
            var isSellableUnitDiscount = discount.AffectedOrderlines.Any() || (discount.AffectedProductTags != null && discount.AffectedProductTags.Any());

            var orderSellableUnits = new List <SellableUnit>();

            foreach (var line in applicableOrderLines)
            {
                //for (var i = 0; i < line.ProductInfo.ItemCount; i++)
                orderSellableUnits.AddRange(line.SellableUnits);                         // maak een lijst met de prijzen van alle (losse) items van de order
            }
            var numberOfItemsLeftOutOfSets = discount.NumberOfItemsCondition == 0 ? 0 : applicableOrderLines.Sum(line => line.ProductInfo.ItemCount.GetValueOrDefault(1)) % discount.NumberOfItemsCondition;
            var applicableSellableUnits    = orderSellableUnits.OrderBy(item => item.PriceInCents).Take(orderSellableUnits.Count - numberOfItemsLeftOutOfSets).ToList();

            var rangedDiscountValue       = RangedDiscountValueForOrder(discount, orderInfo);       // todo: not localized
            var discountAmount            = rangedDiscountValue;
            var maximumDiscountableAmount = 0L;
            var timesApplicable           = 1;

            if (discount.Condition == DiscountOrderCondition.None)
            {
                maximumDiscountableAmount = applicableOrderLines.Sum(orderline => orderline.AmountInCents - (orderline.GetOriginalAmount(false, true) - orderline.GetOriginalAmount(true, true)));
                timesApplicable           = applicableOrderLines.Sum(orderLine => orderLine.ProductInfo.ItemCount.GetValueOrDefault(1));
            }
            else if (discount.Condition == DiscountOrderCondition.OnTheXthItem && discount.NumberOfItemsCondition > 0)
            {
                isSellableUnitDiscount = true;
                // todo: test
                discountAmount            = discountAmount * applicableSellableUnits.Count() / discount.NumberOfItemsCondition;
                applicableSellableUnits   = applicableSellableUnits.Take(orderSellableUnits.Count / discount.NumberOfItemsCondition).ToList();
                maximumDiscountableAmount = applicableSellableUnits.Sum(su => su.PriceInCents);                 // bereken de korting over de x goedkoopste items, waarbij x het aantal sets in de order is
            }
            else if (discount.Condition == DiscountOrderCondition.PerSetOfXItems && discount.NumberOfItemsCondition > 0)
            {
                isSellableUnitDiscount = true;
                timesApplicable        = applicableSellableUnits.Count() / discount.NumberOfItemsCondition;
                if (discount.DiscountType == DiscountType.Amount)
                {
                    applicableSellableUnits = applicableSellableUnits.Take(orderSellableUnits.Count / discount.NumberOfItemsCondition).ToList();
                }
                discountAmount            = discountAmount * applicableSellableUnits.Count() / discount.NumberOfItemsCondition;
                maximumDiscountableAmount = applicableSellableUnits.Sum(su => su.PriceInCents);
            }

            if (discount.IncludeShippingInOrderDiscountableAmount)
            {
                maximumDiscountableAmount += orderInfo.ShippingProviderAmountInCents;
            }

            if (discount.DiscountType == DiscountType.Amount)
            {
                // currently not on SellableUnits, because that would break existing functionality

                if (applyDiscountEffects)
                {
                    var amountDiscountEffect = new AmountDiscountEffect {
                        Amount = rangedDiscountValue
                    };
                    if (isSellableUnitDiscount)
                    {
                        foreach (var su in applicableSellableUnits)
                        {
                            su.SellableUnitDiscountEffects.AddEffect(amountDiscountEffect);
                        }
                    }
                    else
                    {
                        orderInfo.OrderDiscountEffects.AddEffect(amountDiscountEffect);
                    }
                }

                return((int)Math.Min(discountAmount, maximumDiscountableAmount));
            }
            if (discount.DiscountType == DiscountType.Percentage)
            {
                // wanneer SellableUnit/OrderLine/Order
                if (applyDiscountEffects)
                {
                    var percentageDiscountEffect = new PercentageDiscountEffect {
                        Percentage = rangedDiscountValue / 10000m
                    };
                    if (isSellableUnitDiscount)
                    {
                        foreach (var su in applicableSellableUnits)
                        {
                            su.SellableUnitDiscountEffects.AddEffect(percentageDiscountEffect);
                        }
                    }
                    else
                    {
                        orderInfo.OrderDiscountEffects.AddEffect(percentageDiscountEffect);
                    }
                }
                return(DiscountHelper.PercentageCalculation(rangedDiscountValue, maximumDiscountableAmount));
            }
            if (discount.DiscountType == DiscountType.NewPrice)
            {
                if (applyDiscountEffects)
                {
                    var newPriceDiscountEffect = new NewPriceDiscountEffect {
                        NewPrice = rangedDiscountValue
                    };
                    foreach (var applicableSellableUnit in applicableSellableUnits)
                    {
                        applicableSellableUnit.SellableUnitDiscountEffects.AddEffect(newPriceDiscountEffect);
                    }
                }
                if (discount.Condition == DiscountOrderCondition.OnTheXthItem && discount.NumberOfItemsCondition > 0)
                {
                    return(applicableSellableUnits.Take(orderSellableUnits.Count / discount.NumberOfItemsCondition).Select(su => Math.Max(0, su.PriceInCents - discountAmount)).Sum());
                }

                return((int)Math.Max(0, maximumDiscountableAmount - rangedDiscountValue * timesApplicable));
            }

            return(0);
        }