Ejemplo n.º 1
0
        public IShoppingBasket Process(IShoppingBasket shoppingBasket)
        {
            if (shoppingBasket.OfferVoucher == null)
            {
                return(shoppingBasket);
            }

            shoppingBasket = ValidateOfferVoucherForThreshold(shoppingBasket);
            if (!BasketHasErrors(shoppingBasket) && shoppingBasket.OfferVoucher.OfferVoucherType == OfferVoucherType.Basket)
            {
                shoppingBasket.Total = shoppingBasket.Total - shoppingBasket.OfferVoucher.Value;
                _isOfferApplied      = true;
            }

            if (!BasketHasErrors(shoppingBasket) && !_isOfferApplied && shoppingBasket.OfferVoucher.OfferVoucherType == OfferVoucherType.Product)
            {
                shoppingBasket.Total = ValidateOfferVoucherForProducts(shoppingBasket).Total;
            }

            if (!BasketHasErrors(shoppingBasket) && !_isOfferApplied)
            {
                shoppingBasket.Messages.Add($"There are no products in your basket applicable to voucher Voucher {shoppingBasket.OfferVoucher.Code}.");
            }

            return(shoppingBasket);
        }
Ejemplo n.º 2
0
        public IShoppingBasket Process(IShoppingBasket shoppingBasket)
        {
            if (!shoppingBasket.BogofOffers.Any())
            {
                return(shoppingBasket);
            }

            foreach (var basketItem in shoppingBasket.GetBasketItems())
            {
                if (basketItem.Quantity < 2)
                {
                    continue;
                }

                if (shoppingBasket.BogofOffers.All(bogof => bogof.ProductCategory != basketItem.Product.ProductCategory))
                {
                    continue;
                }

                var quantityTodrop     = basketItem.Quantity / 2;
                var bogofOfferDiscount = quantityTodrop * basketItem.Product.Price;
                shoppingBasket.Total -= bogofOfferDiscount;
                shoppingBasket.Messages.Add($"BOGOF discount £{bogofOfferDiscount} applied.");
            }

            return(shoppingBasket);
        }
Ejemplo n.º 3
0
 public void SetUp()
 {
     _productService    = new ProductDemoService();
     _promotionProvider = new PromotionProvider();
     _pricingEngine     = new PricingEngine(_promotionProvider);
     _shoppingBasket    = new ShoppingBasket(_pricingEngine);
 }
Ejemplo n.º 4
0
 private void CalculateTax(IShoppingBasket basket, IShoppingBasketItem basketItem)
 {
     foreach (var taxRule in basketItem.TaxRules)
     {
         taxRule.CalculateTax(basket, basketItem);
     }
 }
        public IShoppingBasket Process(IShoppingBasket shoppingBasket)
        {
            if (shoppingBasket.OfferVoucher == null)
            {
                return(shoppingBasket);
            }

            if (!ValidateOfferVoucherForThreshold(shoppingBasket))
            {
                return(shoppingBasket);
            }

            if (shoppingBasket.OfferVoucher.OfferVoucherType != OfferVoucherType.Basket)
            {
                return(shoppingBasket);
            }


            decimal offerVoucherDiscount = decimal.Round(shoppingBasket.Total *
                                                         shoppingBasket.OfferVoucher.PercentageOffDiscount.ConvertPercentToDecimal(), 2, MidpointRounding.AwayFromZero);

            shoppingBasket.Total -= offerVoucherDiscount;
            shoppingBasket.Messages.Add($"OfferVoucher discount £{offerVoucherDiscount} applied.");

            return(shoppingBasket);
        }
Ejemplo n.º 6
0
 // I probably would have avoided this side effect, but since basket did not have a TaxRules property of its own, I couldn't think of another reason for why the basket was used as a parameter in CalculateTax()
 protected virtual void UpdateTotals(IShoppingBasket basket, IShoppingBasketItem item, decimal tax)
 {
     item.Tax     += tax;
     item.Total   += tax;
     basket.Tax   += tax;
     basket.Total += tax;
 }
Ejemplo n.º 7
0
        public void TotalCost_WithDiscount()
        {
            //Arrange
            _sut = new BusinessCore.Areas.ShoppingBasket.Models.ShoppingBasket
            {
                Items = new List <IItem>
                {
                    new Item {
                        PricePerItem = 10, Qty = 5, Sku = "A"
                    },
                    new Item {
                        PricePerItem = 5, Qty = 2, Sku = "B"
                    }
                },
                Discounts = new List <IDiscount>
                {
                    new Discount {
                        PricePerOffer = -5, Qty = 2, Sku = "A"
                    },
                    new Discount {
                        PricePerOffer = -2.5, Qty = 1, Sku = "B"
                    }
                }
            };

            //Act
            var result = _sut.TotalCost();

            //Assert
            result.Should().Be(47.5);
        }
        public IShoppingBasket Process(IShoppingBasket shoppingBasket)
        {
            shoppingBasket.Total =
                shoppingBasket.GetBasketItems().Sum(basketItem => basketItem.Product.Price * basketItem.Quantity);

            return(shoppingBasket);
        }
 public IShoppingBasket Process(IShoppingBasket shoppingBasket)
 {
     if (shoppingBasket.GiftVouchers != null && shoppingBasket.GiftVouchers.Any())
     {
         shoppingBasket.Total -= shoppingBasket.GiftVouchers.Sum(x => x.Value);
     }
     return(shoppingBasket);
 }
Ejemplo n.º 10
0
        public decimal CalculateTax(IShoppingBasket basket, IShoppingBasketItem item)
        {
            var tax = _unitItemTax * item.Quantity;

            UpdateTotals(basket, item, tax);

            return(_unitItemTax);
        }
Ejemplo n.º 11
0
        public decimal CalculateTax(IShoppingBasket basket, IShoppingBasketItem item)
        {
            var tax = _percentage * item.SubTotal;

            UpdateTotals(basket, item, tax);

            return(tax);
        }
Ejemplo n.º 12
0
        public TransactionRegistrationResponse SendTransaction(IShoppingBasket storeBasket, RequestContext context, User user)
        {
            // Construct a SagePay basket from our Store basket.
            // We don't use the SagePay basket directly from the application as it only requires a subset of the information

            var basket = new ShoppingBasket("Shopping Basket for " + user.Name);

            //Fill the basket. The VAT multiplier is not specified here as it is taken from the web.config
            foreach (var item in storeBasket.GetItemsInBasket())
            {
                basket.Add(new BasketItem(item.Quantity, item.Product.Name, item.Product.Price));
            }

            // Using the same address for billing and shipping.
            // In reality, you would allow the option of specifying either.
            var sagePayAddress = new Address()
            {
                Address1   = user.Address1,
                Address2   = user.Address2,
                Surname    = user.Surname,
                Firstnames = user.Forename,
                City       = user.Town,
                Country    = "GB",
                Phone      = user.Telephone,
                PostCode   = user.Postcode
            };

            var orderId = Guid.NewGuid().ToString();

            var response = _transactionRegistrar.Send(context, orderId, basket, sagePayAddress, sagePayAddress, null);

            if (response.Status != ResponseType.Ok)
            {
                string error = "Transaction {0} did not register successfully. Status returned was {1} ({2})";
                error = string.Format(error, orderId, response.Status, response.StatusDetail);
                throw new Exception(error);
            }

            var order = new Order {
                VendorTxCode    = orderId,
                VpsTxId         = response.VPSTxId,
                SecurityKey     = response.SecurityKey,
                RedirectUrl     = response.NextURL,
                DateInitialised = DateTime.Now
            };

            // In reality you would store more information about the order...
            // ..like the user who made the order and each of the products in the order.

            _orderRepository.StoreOrder(order);

            return(response);
        }
Ejemplo n.º 13
0
		public TransactionRegistrationResponse SendTransaction(IShoppingBasket storeBasket, RequestContext context, User user) {

			// Construct a SagePay basket from our Store basket.
			// We don't use the SagePay basket directly from the application as it only requires a subset of the information

			var basket = new ShoppingBasket("Shopping Basket for " + user.Name);

			//Fill the basket. The VAT multiplier is not specified here as it is taken from the web.config
			foreach (var item in storeBasket.GetItemsInBasket()) {
				basket.Add(new BasketItem(item.Quantity, item.Product.Name, item.Product.Price));
			}

			// Using the same address for billing and shipping.
			// In reality, you would allow the option of specifying either.
			var sagePayAddress = new Address() {
				Address1 = user.Address1,
				Address2 = user.Address2,
				Surname = user.Surname,
				Firstnames = user.Forename,
				City = user.Town,
				Country = "GB",
				Phone = user.Telephone,
				PostCode = user.Postcode
			};

			var orderId = Guid.NewGuid().ToString();

			var response = _transactionRegistrar.Send(context, orderId, basket, sagePayAddress, sagePayAddress, null);

			if (response.Status != ResponseType.Ok) {
				string error = "Transaction {0} did not register successfully. Status returned was {1} ({2})";
				error = string.Format(error, orderId, response.Status, response.StatusDetail);
				throw new Exception(error);
			}

			var order = new Order {
				VendorTxCode = orderId,
				VpsTxId = response.VPSTxId,
				SecurityKey = response.SecurityKey,
				RedirectUrl = response.NextURL,
				DateInitialised = DateTime.Now
			};

			// In reality you would store more information about the order...
			// ..like the user who made the order and each of the products in the order.

			_orderRepository.StoreOrder(order);

			return response;

		}
        public IShoppingBasket Process(IShoppingBasket shoppingBasket)
        {
            if (shoppingBasket.LoyaltyOffer == null)
            {
                return(shoppingBasket);
            }

            decimal loyaltyOfferDiscount = decimal.Round(shoppingBasket.Total *
                                                         shoppingBasket.LoyaltyOffer.PercentageOffDiscount.ConvertPercentToDecimal(), 2, MidpointRounding.AwayFromZero);

            shoppingBasket.Total -= loyaltyOfferDiscount;
            shoppingBasket.Messages.Add($"Loyalty discount £{loyaltyOfferDiscount} applied.");
            return(shoppingBasket);
        }
Ejemplo n.º 15
0
        private static IShoppingBasket ValidateOfferVoucherForThreshold(IShoppingBasket shoppingBasket)
        {
            var basketsTotal = shoppingBasket.GetBasketItems().Where(x => x.Product.Category != Category.GiftVoucher).Sum(basketItem => basketItem.Product.Price * basketItem.Quantity);

            if (basketsTotal < shoppingBasket.OfferVoucher.Threshold)
            {
                var additonalAmountToSpend = shoppingBasket.OfferVoucher.Threshold - basketsTotal + 0.01m;
                shoppingBasket.Messages.Add($"You have not reached the spend threshold for voucher {shoppingBasket.OfferVoucher.Code}. Spend another £{additonalAmountToSpend} to receive £5.00 discount from your basket total.");
                basketsTotal = shoppingBasket.Total;
            }

            shoppingBasket.Total = basketsTotal;

            return(shoppingBasket);
        }
        private static bool ValidateOfferVoucherForThreshold(IShoppingBasket basket)
        {
            var basketsTotal = basket.Total;

            if (basketsTotal >= basket.OfferVoucher.Threshold)
            {
                return(true);
            }

            var additonalAmountToSpend = basket.OfferVoucher.Threshold - basketsTotal + 0.01m;

            basket.Messages.Add($"You have not reached the spend threshold for voucher {basket.OfferVoucher.Code}. Spend another £{additonalAmountToSpend} to receive 10% off on your basket totals.");

            return(false);
        }
        public BasketServiceResponse GetBasketTotal(IShoppingBasket shoppingBasket)
        {
            try
            {
                if (!shoppingBasket.GetBasketItems().Any())
                {
                    return new BasketServiceResponse()
                           {
                               Notifications = new List <string> {
                                   "Your shopping basket is empty"
                               },
                               Success     = true,
                               BasketTotal = 0.0m
                           }
                }
                ;

                _basketProcessors = CreateBasketProcessors();

                foreach (var processor in _basketProcessors)
                {
                    processor.Process(shoppingBasket);
                }

                // TODO: Use automapper for mapping Basket object to BasketServiceResponse object
                return(new BasketServiceResponse
                {
                    Notifications = shoppingBasket.Messages?.ToList(),
                    BasketTotal = shoppingBasket.Total,
                    Success = true
                });
            }
            catch (Exception exception)
            {
                return(new BasketServiceResponse
                {
                    ErrorMessage = $"Failed to calculate basket total {exception.Message}",
                    Success = false,
                    BasketTotal = 0.0m
                });
            }
        }
Ejemplo n.º 18
0
        public decimal CalculateTax(IShoppingBasket basket, IShoppingBasketItem item)
        {
            var unitItemTax = 0m;

            foreach (var band in _taxBands)
            {
                var applicableValue = (band.Cap ?? item.UnitPrice) - band.Threshold;

                var temporaryItem = new DefaultShoppingBasketItem {
                    SubTotal = applicableValue, Quantity = 1
                };                                                                                               // remove explicit instantiation from here
                unitItemTax += band.TaxRule.CalculateTax(basket, temporaryItem);
            }

            var itemTax = unitItemTax * item.Quantity;

            UpdateTotals(basket, item, itemTax);

            return(itemTax);
        }
Ejemplo n.º 19
0
        public void TotalCost_NoDiscount(double itemOnePrice, double itemTwoPrice, int itemOneQty, int itemTwoQty, double expectedResult)
        {
            //Arrange
            _sut = new BusinessCore.Areas.ShoppingBasket.Models.ShoppingBasket
            {
                Items = new List <IItem>
                {
                    new Item {
                        PricePerItem = itemOnePrice, Qty = itemOneQty
                    },
                    new Item {
                        PricePerItem = itemTwoPrice, Qty = itemTwoQty
                    }
                }
            };

            //Act
            var result = _sut.TotalCost();

            //Assert
            result.Should().Be(expectedResult);
        }
Ejemplo n.º 20
0
        public void TotalDiscountCost_Success(double discountOnePrice, double discountTwoPrice, int discountOneQty, int discountTwoQty, double expectedResult)
        {
            //Arrange
            _sut = new BusinessCore.Areas.ShoppingBasket.Models.ShoppingBasket
            {
                Discounts = new List <IDiscount>
                {
                    new Discount {
                        PricePerOffer = discountOnePrice, Qty = discountOneQty
                    },
                    new Discount {
                        PricePerOffer = discountTwoPrice, Qty = discountTwoQty
                    }
                }
            };

            //Act
            var result = _sut.TotalDiscountCost();

            //Assert
            result.Should().Be(expectedResult);
        }
Ejemplo n.º 21
0
        private IShoppingBasket ValidateOfferVoucherForProducts(IShoppingBasket shoppingBasket)
        {
            var basketsTotal = 0.00m;

            foreach (var basketItem in shoppingBasket.GetBasketItems())
            {
                if (basketItem.Product.Category == shoppingBasket.OfferVoucher.ProductCategory && !_isOfferApplied)
                {
                    _isOfferApplied = true;
                    var productPrice = basketItem.Product.Price;
                    productPrice -= shoppingBasket.OfferVoucher.Value;
                    productPrice  = productPrice >= 0 ? productPrice : 0m;

                    basketsTotal += productPrice;
                }
                else
                {
                    basketsTotal += basketItem.Product.Price;
                }
            }

            shoppingBasket.Total = basketsTotal;
            return(shoppingBasket);
        }
 public void WhenANewBasketIsInstantiated()
 {
     // amend to take concretion as parameter
     _shoppingBasket = new DefaultBasket();
 }
Ejemplo n.º 23
0
		public BasketController(IShoppingBasket basket, IProductRepository productRepository, ITransactionService transactionService) {
			_basket = basket;
			_transactionService = transactionService;
			_productRepository = productRepository;
		}
        public ShoppingBasketTest()
        {
            var inventory = new Inventory();

            _shoppingBasket = new ShoppingBasket(inventory, new DiscountService(inventory));
        }
 public FluentBasketItemsBuilder(IShoppingBasket shoppingBasket, int quantity)
 {
     _shoppingBasket = shoppingBasket;
     _quantity       = quantity;
 }
Ejemplo n.º 26
0
 public BasketController(IShoppingBasket basket, IProductRepository productRepository, ITransactionService transactionService)
 {
     _basket             = basket;
     _transactionService = transactionService;
     _productRepository  = productRepository;
 }
Ejemplo n.º 27
0
 private static void SubscribeNotificationSystemsToBasket(IEnumerable <NotificationSystem> notificationSystems, IShoppingBasket shoppingBasket)
 {
     foreach (var notificationSystem in notificationSystems)
     {
         shoppingBasket.Updated += (object basket, ShoppingUpdatedEventArgs e) => notificationSystem.HandleUpdated(basket, e);
     }
 }
Ejemplo n.º 28
0
 public Task UpsertAsync(string id, IShoppingBasket shoppingBasket)
 {
     _memoryCache.Set(GetBasketKey(id), shoppingBasket);
     return(Task.CompletedTask);
 }
Ejemplo n.º 29
0
 public CartController(IShoppingBasket shoppingBasket)
 {
     _shoppingBasket = shoppingBasket;
 }
Ejemplo n.º 30
0
 public InitialStateUnitTests(IocFixture fixture)
 {
     _basket = fixture.ServiceProvider.GetService <IShoppingBasket>();
 }
Ejemplo n.º 31
0
 // Not completely happy with this solution
 protected override void UpdateTotals(IShoppingBasket basket, IShoppingBasketItem item, decimal tax)
 {
     item.Tax   += tax;
     item.Total += tax;
 }
 //TODO:Please provide the implementation of this type to calculate the tax as a percentage of the sub total for the item
 //Unsure as to why need reference to basket and item. With just basket can iterate over all items, or with just item can calculate individually when required
 public decimal CalculateTax(IShoppingBasket basket, IShoppingBasketItem item)
 {
     return(item.SubTotal * 0M); //Add 0% - NoTax Rule from Rules.md
 }