示例#1
0
        public CartOffer ProcessCart(int profileId, string shippingCountryCode, string promoCode = "", int testOfferRuleId = 0)
        {
            promoCode = promoCode.ToLower().Trim();
            CartOffer cartOffer = new CartOffer();

            var cartRules = _offerBuilder.GetActiveOfferRulesByType(OfferRuleType.Cart);

            if (testOfferRuleId > 0)
            {
                var testRule = _offerBuilder.PrepareTestOfferRule(testOfferRuleId);
                cartRules = _offerBuilder.CloneActiveOfferRulesByType(OfferRuleType.Cart);
                cartRules.Remove(testRule);
                cartRules.Add(testRule);
                cartRules = cartRules.OrderBy(x => x.Priority).ToList();
            }

            if (cartRules.Count > 0)
            {
                // Get all items by profile ID
                var items = _cartItemRepository.Table
                            .Where(x => x.ProfileId == profileId)
                            .ToList()
                            .Select(x => _cartItemBuilder.Build(x))
                            .ToList();

                // Do a basket cleanup
                items = _cartUtility.RemoveFreeItemWithOffers(items, cartRules.Select(x => x.Id).ToArray());

                for (int i = 0; i < cartRules.Count; i++)
                {
                    // Check status and dates
                    // In theory, all inactive / expired rules will not be loaded from database
                    if ((cartRules[i].IsActive) &&
                        ((cartRules[i].StartDate.HasValue == false || cartRules[i].StartDate.Value.CompareTo(DateTime.Now) <= 0) &&
                         (cartRules[i].EndDate.HasValue == false || cartRules[i].EndDate.Value.CompareTo(DateTime.Now) >= 0)))
                    {
                        bool proceed = true;

                        if (profileId != 0 && !string.IsNullOrEmpty(promoCode) && promoCode.CompareTo(cartRules[i].PromoCode.ToLower()) == 0)
                        {
                            int orderQuantity = _cartUtility.GetNumberOfPaidOrders(promoCode, profileId);

                            // Check promocode and uses per customer
                            // value <= 0 will be considered as proceed
                            proceed = cartRules[i].UsesPerCustomer <= 0 || orderQuantity < cartRules[i].UsesPerCustomer;

                            if (cartRules[i].NewCustomerOnly && orderQuantity > 0)
                            {
                                proceed = false;
                            }
                        }

                        // Set html message from this offer
                        if (string.IsNullOrEmpty(cartRules[i].PromoCode) == false && cartRules[i].PromoCode.ToLower().CompareTo(promoCode) == 0)
                        {
                            cartOffer.Description = cartRules[i].HtmlMessage;
                        }

                        // If entered promocode is empty and promocode from offer is not empty, do not proceed
                        if (string.IsNullOrEmpty(cartRules[i].PromoCode) == false && string.IsNullOrEmpty(promoCode))
                        {
                            proceed = false;
                        }

                        bool conditionMatched = false;

                        if (proceed)
                        {
                            conditionMatched = _cartUtility.ProcessCartCondition(items, cartRules[i].Condition, cartRules[i].OfferedItemIncluded, cartRules[i].UseInitialPrice);

                            if (conditionMatched)
                            {
                                // If cart rule does not have promocode, proceed
                                // If cart rule does not match the given promocode, do not proceed
                                if (string.IsNullOrEmpty(cartRules[i].PromoCode) ||
                                    cartRules[i].PromoCode.ToLower().CompareTo(promoCode) == 0)
                                {
                                    // Run action here
                                    cartOffer = _cartUtility.ProcessCartOfferAction(profileId, items, shippingCountryCode, cartRules[i], cartRules[i].Action, cartOffer);
                                }
                            }

                            if (!cartRules[i].ProceedForNext)
                            {
                                break;
                            }
                        }
                    }
                }

                // Update all cart items in database at the end of the loop.
                foreach (var item in items)
                {
                    if (item.Id > 0)
                    {
                        _cartItemRepository.Update(item);
                    }
                    else
                    {
                        _cartItemRepository.Create(item);
                    }
                }
            }

            return(cartOffer);
        }
示例#2
0
        public CartOffer ProcessCartOfferAction(int profileId, IList <CartItem> items, string shippingCountryCode, OfferRule offerRule, OfferAction action, CartOffer cartOffer)
        {
            if (action == null)
            {
                return(cartOffer);
            }

            List <CartItem> list;
            decimal         matchedAmount = 0M;
            decimal         discount      = 0M;
            int             steps         = 0;
            Country         country       = _countryRepository.Table.Where(x => x.ISO3166Code == shippingCountryCode).FirstOrDefault();

            cartOffer.FreeDelivery = action.FreeShipping;
            cartOffer.RewardPoint += action.RewardPoint;

            switch (action.OfferActionAttributeId)
            {
                #region FIXED_PERCENT_DISCOUNT_FOR_PRODUCT_SUBSELECTION

            case FIXED_PERCENT_DISCOUNT_FOR_PRODUCT_SUBSELECTION:
                // Run acton condition first
                if (offerRule.Action.Condition != null && offerRule.Action.Condition.ChildOfferConditions.Count > 0)
                {
                    matchedAmount = CalculateActionMatchedAmount(items, offerRule, action.Condition, country.IsEC);
                }
                else     // Else use condition from offer rule..
                {
                    matchedAmount = CalculateActionMatchedAmount(items, offerRule, offerRule.Condition, country.IsEC);
                }

                discount = matchedAmount / 100M * action.DiscountAmount.Value;
                cartOffer.Discounts.Add(offerRule.Id, discount);
                cartOffer.DiscountAmount += discount;
                cartOffer.IsValid         = true;
                break;

                #endregion

                #region FIXED_PERCENT_DISCOUNT_FOR_WHOLE_CART

            case FIXED_PERCENT_DISCOUNT_FOR_WHOLE_CART:
                if (country.IsEC)
                {
                    discount = items.Select(x => x.ProductPrice.OfferPriceInclTax * x.Quantity)
                               .DefaultIfEmpty(0).Sum() * Convert.ToInt32(action.DiscountAmount.Value) / 100;
                }
                else
                {
                    discount = items.Select(x => x.ProductPrice.OfferPriceExclTax * x.Quantity)
                               .DefaultIfEmpty(0).Sum() * Convert.ToInt32(action.DiscountAmount.Value) / 100;
                }

                cartOffer.DiscountAmount += discount;
                cartOffer.Discounts.Add(offerRule.Id, discount);

                cartOffer.IsValid = true;
                break;

                #endregion

                #region FIXED_AMOUNT_DISCOUNT_FOR_WHOLE_CART

            case FIXED_AMOUNT_DISCOUNT_FOR_WHOLE_CART:
                cartOffer.DiscountAmount += action.DiscountAmount.Value;
                cartOffer.Discounts.Add(offerRule.Id, action.DiscountAmount.Value);
                cartOffer.IsValid = true;
                break;

                #endregion

                #region FREE_ITEM_OFFER

            case FREE_ITEM_OFFER:
                bool proceed = false;

                if (action.MinimumAmount.HasValue)
                {
                    if (action.Condition == null)
                    {
                        proceed = true;
                    }
                    else
                    {
                        proceed = CalculateActionMatchedAmount(items, offerRule, action.Condition, country.IsEC) > action.MinimumAmount.Value;
                    }
                }
                else
                {
                    proceed = true;
                }

                int qtyStep  = 1;
                int qtyFound = 1;

                if (action.DiscountQtyStep.HasValue && proceed)
                {
                    // To calculate how many free items need to be added
                    qtyStep = action.DiscountQtyStep.Value;

                    if (action.Condition == null || action.Condition.ChildOfferConditions.Count == 0)
                    {
                        qtyFound = CalculateActionMatchedQty(items, offerRule, offerRule.Condition);
                    }
                    else
                    {
                        qtyFound = CalculateActionMatchedQty(items, offerRule, action.Condition);
                    }

                    proceed = qtyFound > 0;
                }

                bool isByOption = action.OptionOperator != null;

                var foundList = new List <CartItem>();

                // If there is an action condition
                if (offerRule.Action.Condition != null && offerRule.Action.Condition.ChildOfferConditions.Count > 0)
                {
                    foundList = GetActionMatchedItems(items, offerRule, action.Condition);
                }
                else     // Else use condition from offer rule
                {
                    foundList = GetActionMatchedItems(items, offerRule, offerRule.Condition);
                }

                list = new List <CartItem>();

                if (isByOption)
                {
                    for (int i = 0; i < foundList.Count; i++)
                    {
                        if (foundList[i].ProductPrice.OfferRuleId <= 0)
                        {
                            string targetOption = foundList[i].ProductPrice.Option;
                            bool   isOkay       = _attributeUtility.ValidateAttribute(targetOption, action.OptionOperator.Operator, action.OptionOperand);

                            if (isOkay)
                            {
                                list.Add(foundList[i]);
                            }
                        }
                    }

                    if (list.Count > 0)
                    {
                        proceed = true;
                    }
                }
                else
                {
                    list = foundList;
                }

                if (proceed)
                {
                    // TODO: Do we need to prevent other process?
                    // Flag item with offer rule id to prevent other process
                    //FlagOfferRuleIdInBasket(action.OfferRuleId, list.Select(x => x.Id).ToList());

                    // Add free item
                    if (action.FreeProductItself.Value)
                    {
                        for (int i = 0; i < list.Count; i++)
                        {
                            if (list[i].Product == null)
                            {
                                _logger.InsertLog(LogLevel.Warning, string.Format("Free item could not be loaded. Product ID={{{0}}}", list[i].ProductId));
                                break;
                            }

                            if (list[i].ProductPrice == null)
                            {
                                _logger.InsertLog(LogLevel.Warning, string.Format("Product price for free item could not be loaded. Product Price ID={{{0}}}", list[i].ProductPriceId));
                                break;
                            }

                            if (list[i].Product.Brand == null)
                            {
                                _logger.InsertLog(LogLevel.Warning, string.Format("Brand for free item could not be loaded. Brand ID={{{0}}}", list[i].Product.BrandId));
                                break;
                            }

                            var message = _cartValidator.ValidateCartItem(
                                profileId,
                                list[i].ProductId,
                                list[i].Product.BrandId,
                                shippingCountryCode,
                                list[i].Product.IsPharmaceutical,
                                list[i].Product.Discontinued,
                                list[i].ProductPrice.Stock,
                                list[i].Product.Name,
                                list[i].Product.EnforceStockCount,
                                list[i].Product.Brand.EnforceStockCount,
                                list[i].Product.Enabled,
                                list[i].ProductPrice.Enabled,
                                list[i].Quantity,
                                list[i].Quantity / qtyStep,
                                list[i].Product.StepQuantity,
                                list[i].Product.IsPhoneOrder,
                                list[i].ProductPrice.OfferPriceExclTax,
                                allowZeroPrice: true);

                            // Empty message is ok status from cart item validation
                            if (string.IsNullOrEmpty(message))
                            {
                                var cartItem = new CartItem
                                {
                                    ProfileId      = profileId,
                                    ProductPriceId = list[i].ProductPriceId,
                                    ProductId      = list[i].ProductId,
                                    Quantity       = list[i].Quantity / qtyStep,
                                    Product        = list[i].Product,
                                    ProductPrice   = list[i].ProductPrice,
                                    CartItemMode   = (int)CartItemMode.FreeItem
                                };

                                items.Add(cartItem);
                            }
                        }
                    }
                    else
                    {
                        // Load free item
                        var freeItem = _productBuilder.Build(action.FreeProductId.Value);
                        if (freeItem == null)
                        {
                            _logger.InsertLog(LogLevel.Warning, string.Format("Free item could not be loaded. Product ID={{{0}}}", action.FreeProductId.Value));
                            break;
                        }

                        var freeItemPriceOption = freeItem.ProductPrices.Where(x => x.Id == action.FreeProductPriceId).FirstOrDefault();
                        if (freeItemPriceOption == null)
                        {
                            _logger.InsertLog(LogLevel.Warning, string.Format("Product price for free item could not be loaded. Product Price ID={{{0}}}", action.FreeProductPriceId));
                            break;
                        }

                        if (freeItem.Brand == null)
                        {
                            _logger.InsertLog(LogLevel.Warning, string.Format("Brand for free item could not be loaded. Brand ID={{{0}}}", freeItem.BrandId));
                            break;
                        }

                        // While stock lasts
                        if (freeItemPriceOption.Stock > 0)
                        {
                            var message = _cartValidator.ValidateCartItem(
                                profileId,
                                freeItem.Id,
                                freeItem.BrandId,
                                shippingCountryCode,
                                freeItem.IsPharmaceutical,
                                freeItem.Discontinued,
                                freeItemPriceOption.Stock,
                                freeItem.Name,
                                freeItem.EnforceStockCount,
                                freeItem.Brand.EnforceStockCount,
                                freeItem.Enabled,
                                freeItemPriceOption.Enabled,
                                0,
                                action.FreeProductQty.Value * (qtyFound / qtyStep),
                                freeItem.StepQuantity,
                                freeItem.IsPhoneOrder,
                                freeItemPriceOption.OfferPriceExclTax,
                                allowZeroPrice: true);

                            // Empty message is ok status from cart item validation
                            if (string.IsNullOrEmpty(message))
                            {
                                var cartItem = new CartItem
                                {
                                    ProfileId      = profileId,
                                    ProductPriceId = freeItemPriceOption.Id,
                                    ProductId      = freeItem.Id,
                                    Quantity       = action.FreeProductQty.Value * (qtyFound / qtyStep),
                                    Product        = freeItem,
                                    ProductPrice   = freeItemPriceOption,
                                    CartItemMode   = (int)CartItemMode.FreeItem
                                };

                                items.Add(cartItem);
                            }
                        }
                    }
                }

                cartOffer.IsValid = true;

                break;

                #endregion

                #region DO_NOTHING

            case DO_NOTHING:
                // do nothing
                cartOffer.IsValid = true;
                break;

                #endregion

                #region BUY_X_QUANTITY_FOR_Y_QUANTITY

            case BUY_X_QUANTITY_FOR_Y_QUANTITY:

                // Must have X quantity
                // Must have Y quantity
                // X > Y
                if (offerRule.Action.XValue.HasValue && offerRule.Action.YValue.HasValue &&
                    offerRule.Action.XValue > offerRule.Action.YValue)
                {
                    list = new List <CartItem>();

                    if (offerRule.Action.Condition != null && offerRule.Action.Condition.ChildOfferConditions.Count > 0)     // If there is condition for action
                    {
                        list = GetActionMatchedItems(items, offerRule, action.Condition);
                    }
                    else     // Else use condition from offer rule..
                    {
                        list = GetActionMatchedItems(items, offerRule, offerRule.Condition);
                    }

                    // Revert to old price if necessary
                    if (offerRule.UseInitialPrice)
                    {
                        SetToUseInitialPrice(list);
                    }

                    // List down individual price
                    List <decimal> listIndividualPrice = new List <decimal>();

                    for (int i = 0; i < list.Count; i++)
                    {
                        for (int j = 0; j < list[i].Quantity; j++)
                        {
                            if (country.IsEC)
                            {
                                listIndividualPrice.Add(list[i].ProductPrice.OfferPriceInclTax);
                            }
                            else
                            {
                                listIndividualPrice.Add(list[i].ProductPrice.OfferPriceExclTax);
                            }
                        }
                    }

                    // Calculate how many steps for X quantity
                    steps = listIndividualPrice.Count / offerRule.Action.XValue.Value;

                    // Find quantity X of total value
                    decimal totalXValue = 0M;

                    for (int i = 0; i < offerRule.Action.XValue.Value; i++)
                    {
                        if (i < listIndividualPrice.Count)
                        {
                            totalXValue += listIndividualPrice[i];
                        }
                    }

                    // Find quantity Y of total value
                    decimal totalYValue = 0M;

                    for (int i = 0; i < offerRule.Action.YValue.Value; i++)
                    {
                        if (i < listIndividualPrice.Count)
                        {
                            totalYValue += listIndividualPrice[i];
                        }
                    }

                    // Get the difference
                    decimal differenceValue = totalXValue - totalYValue;

                    discount = steps * differenceValue;

                    cartOffer.DiscountAmount += discount;
                    cartOffer.Discounts.Add(offerRule.Id, discount);
                }

                cartOffer.IsValid = true;
                break;

                #endregion

                #region BUY_X_QUANTITY_FOR_Y_PRICE

            case BUY_X_QUANTITY_FOR_Y_PRICE:

                // Must have X quantity
                // Must have Y price
                if (offerRule.Action.XValue.HasValue && offerRule.Action.YValue.HasValue)
                {
                    list = new List <CartItem>();

                    if (offerRule.Action.Condition != null && offerRule.Action.Condition.ChildOfferConditions.Count > 0)     // If there is condition for action
                    {
                        list = GetActionMatchedItems(items, offerRule, action.Condition);
                    }
                    else     // Else use condition from offer rule..
                    {
                        list = GetActionMatchedItems(items, offerRule, offerRule.Condition);
                    }

                    // Revert to old price if necessary
                    if (offerRule.UseInitialPrice)
                    {
                        SetToUseInitialPrice(list);
                    }

                    // List down individual price
                    List <decimal> listIndividualPrice = new List <decimal>();
                    decimal        totalValue          = 0M;

                    for (int i = 0; i < list.Count; i++)
                    {
                        for (int j = 0; j < list[i].Quantity; j++)
                        {
                            if (country.IsEC)
                            {
                                listIndividualPrice.Add(list[i].ProductPrice.OfferPriceInclTax);
                                totalValue += list[i].ProductPrice.OfferPriceInclTax;
                            }
                            else
                            {
                                listIndividualPrice.Add(list[i].ProductPrice.OfferPriceExclTax);
                                totalValue += list[i].ProductPrice.OfferPriceExclTax;
                            }
                        }
                    }

                    // Calculate how many steps for X quantity
                    steps = listIndividualPrice.Count / offerRule.Action.XValue.Value;

                    // Find total value
                    int lastRemoveCount = listIndividualPrice.Count % offerRule.Action.XValue.Value;

                    if (lastRemoveCount != 0)
                    {
                        for (int i = 0; i < lastRemoveCount; i++)
                        {
                            totalValue -= listIndividualPrice[listIndividualPrice.Count - 1 - i];
                        }
                    }

                    // Find total value of Y in current currency
                    decimal totalYValue = steps * (offerRule.Action.YValue.Value);

                    // Get the difference
                    discount = totalValue - totalYValue;

                    cartOffer.DiscountAmount += discount;
                    cartOffer.Discounts.Add(offerRule.Id, discount);
                }

                cartOffer.IsValid = true;

                break;

                #endregion

                #region BUY_X_QUANTITY_CHEAPEST_FREE

            case BUY_X_QUANTITY_CHEAPEST_FREE:

                // Must have X quantity
                if (offerRule.Action.XValue.HasValue)
                {
                    list = new List <CartItem>();

                    if (offerRule.Action.Condition != null && offerRule.Action.Condition.ChildOfferConditions.Count > 0)     // If there is condition for action
                    {
                        list = GetActionMatchedItems(items, offerRule, action.Condition);
                    }
                    else     // Else use condition from offer rule..
                    {
                        list = GetActionMatchedItems(items, offerRule, offerRule.Condition);
                    }

                    // List down individual price
                    List <decimal> listIndividualPrice = new List <decimal>();
                    decimal        totalValue          = 0M;

                    for (int i = 0; i < list.Count; i++)
                    {
                        for (int j = 0; j < list[i].Quantity; j++)
                        {
                            if (country.IsEC)
                            {
                                listIndividualPrice.Add(list[i].ProductPrice.OfferPriceInclTax);
                                totalValue += list[i].ProductPrice.OfferPriceInclTax;
                            }
                            else
                            {
                                listIndividualPrice.Add(list[i].ProductPrice.OfferPriceExclTax);
                                totalValue += list[i].ProductPrice.OfferPriceExclTax;
                            }
                        }
                    }

                    // Calculate how many steps for X quantity
                    steps = listIndividualPrice.Count / offerRule.Action.XValue.Value;

                    // Get the smallest price
                    listIndividualPrice.Sort(delegate(decimal price1, decimal price2)
                    {
                        return(price1.CompareTo(price2));
                    });

                    for (int i = 0; i < steps; i++)
                    {
                        discount += listIndividualPrice[i];
                    }

                    cartOffer.DiscountAmount += discount;
                    cartOffer.Discounts.Add(offerRule.Id, discount);
                }

                cartOffer.IsValid = true;
                break;

                #endregion
            }

            cartOffer.DiscountAmount = Math.Round(cartOffer.DiscountAmount, 2, MidpointRounding.AwayFromZero);

            return(cartOffer);
        }