public void PlaceOrder_AllProductsInStock_DoesNotThrowException()
        {
            // Arrange
            _customerRepository.Stub(c => c.Get(Arg<int>.Is.Anything)).Return(new Customer());
            _orderFulfillmentService.Stub(or => _orderFulfillmentService.Fulfill(Arg<Order>.Is.Anything)).Return(new OrderConfirmation());
            _taxRateService.Stub(t => t.GetTaxEntries(Arg<String>.Is.Anything, Arg<String>.Is.Anything)).Return(new List<TaxEntry> { new TaxEntry() });

            _productRepository.Expect(pr => pr.IsInStock("apple")).Return(true);
            _productRepository.Expect(pr => pr.IsInStock("apple2")).Return(true);

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                CustomerId = 1,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem { Product = new Product { Sku = "apple" } },
                    new OrderItem { Product = new Product { Sku = "apple2" } }
                }
            };

            // Act
            var result = orderService.PlaceOrder(order);

            // Assert
            _productRepository.VerifyAllExpectations();
        }
        public OrderSummary PlaceOrder(Order order)
        {
            List<OrderItem> orderItems = order.OrderItems;
            Customer customer = RetrieveCustomer(order.CustomerId);

            if (OrderIsValid(order, orderItems))
            {
                OrderConfirmation orderConfirmation =_orderFulfillmentService.Fulfill(order);

                IEnumerable<TaxEntry> applicableTaxes = RetrieveTaxEntries(customer).ToList();
                decimal netTotal = CalculateNetTotal(order);
                decimal orderTotal = CalculateOrderTotal(netTotal, applicableTaxes);

                OrderSummary orderSummary= new OrderSummary
                {
                    OrderNumber = orderConfirmation.OrderNumber,
                    OrderId = orderConfirmation.OrderId,
                    CustomerId = orderConfirmation.CustomerId,
                    Taxes = applicableTaxes,
                    NetTotal = netTotal,
                    Total = orderTotal,
                };

                _emailService.SendOrderConfirmationEmail(orderSummary.CustomerId, orderSummary.OrderId);
                return orderSummary;
            }
            else
                throw new Exception(_reasonsForInvalidOrder);
        }
        public OrderSummary PlaceOrder(Order order)
        {
            ValidateOrder(order);

            var fulfillment = _orderFulfillmentService.Fulfill(order);

            var customer = _customerRepository.Get(order.CustomerId);

            var netTotal = CalculateNetTotal(order);

            var listOfTaxEntries = CreateListOfTaxEntries(customer);

            var orderTotal = CalculateOrderTotal(listOfTaxEntries, netTotal);

            var orderSummary = new OrderSummary()
            {
                OrderNumber = fulfillment.OrderNumber,
                OrderId = fulfillment.OrderId,
                Taxes = listOfTaxEntries,
                NetTotal = netTotal,
                Total = orderTotal
            };

            SendConfirmationEmail(order, orderSummary);

            return orderSummary;
        }
 private decimal CalculateNetTotal(Order order)
 {
     decimal netTotal = 0;
     foreach (var orderItem in order.OrderItems)
     {
         netTotal += orderItem.Product.Price*orderItem.Quantity;
     }
     return netTotal;
 }
        public void PlaceOrder_AllProductsNotInStock_DoesThrowException()
        {
            // Arrange
            _productRepository.Expect(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(false);

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                OrderItems = new List<OrderItem>
                {
                    new OrderItem { Product = new Product { Sku = "apple" } },
                    new OrderItem { Product = new Product { Sku = "apple2" } }
                }
            };

            // Act // Assert
            var exception = Assert.Throws<Exception>(() => orderService.PlaceOrder(order));
            Assert.That(exception.Message, Is.StringContaining("Not all products are in stock."));
        }
        public void OrderIsNotValidIdAnyProductsAreOutOfStock()
        {
            // Arrange
            var beerOrder = new Order();
            beerOrder.OrderItems.Add(new OrderItem
            {
                Product = new Product(_productRepo) { Sku = "1234" },
                Quantity = 2
            });
            beerOrder.OrderItems.Add(new OrderItem
            {
                Product = new Product(_productRepo) { Sku = "2345" },
                Quantity = 5
            });

            // Act
            var orderValid = beerOrder.OrderItemsAreUnique();

            // Assert
            Assert.That(orderValid, Is.True);
        }
        public void OrderIsNotValidIfOrdersAreNotUniqueByProductSku()
        {
            // Arrange
            var beerOrder = new Order();
            beerOrder.OrderItems.Add(new OrderItem
            {
                Product = new Product(_productRepo) { Sku = "1234"},
                Quantity = 2
            });
            beerOrder.OrderItems.Add(new OrderItem
            {
                Product = new Product(_productRepo) { Sku = "1234"},
                Quantity = 5
            });

            // Act
            var orderValid = beerOrder.OrderItemsAreUnique();

            // Assert
            Assert.That(orderValid, Is.False);
        }
        public void PlaceOrder_CustomerIsInCustomerRepository_DoesNotThrowException()
        {
            // Arrange
            var expectedCustomerId = 1;

            _productRepository.Stub(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(true);
            _orderFulfillmentService.Stub(or => or.Fulfill(Arg<Order>.Is.Anything)).Return(new OrderConfirmation());
            _taxRateService.Stub(t => t.GetTaxEntries(Arg<String>.Is.Anything, Arg<String>.Is.Anything)).Return(new List<TaxEntry> { new TaxEntry() });

            _customerRepository.Expect(c => c.Get(expectedCustomerId)).Return(new Customer {CustomerId = expectedCustomerId});

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                CustomerId = 1,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple", Price = (decimal) 2.00},
                        Quantity = 2
                    },
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple2", Price = (decimal) 2.50 },
                        Quantity = 1
                    }
                }
            };

            // Act
            var result = orderService.PlaceOrder(order);

            // Assert
            _customerRepository.VerifyAllExpectations();
        }
        public void PlaceOrder_OrderIsValid_OrderSummaryContainsApplicableTaxes()
        {
            // Arrange
            var expectedCustomerId = 1;
            var customer = new Customer{ CustomerId = expectedCustomerId};

            _customerRepository.Stub(c => c.Get(Arg<int>.Is.Anything)).Return(customer);
            _productRepository.Stub(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(true);
            _orderFulfillmentService.Stub(or => _orderFulfillmentService.Fulfill(Arg<Order>.Is.Anything))
                .Return(new OrderConfirmation());
            _taxRateService.Stub(t => t.GetTaxEntries(customer.PostalCode, customer.Country))
                .Return(new List<TaxEntry> {new TaxEntry {Description = "USA"} });

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                CustomerId = expectedCustomerId,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem { Product = new Product { Sku = "apple" } },
                    new OrderItem { Product = new Product { Sku = "apple2" } }
                }
            };

            // Act
            var result = orderService.PlaceOrder(order);

            // Assert
            Assert.That(result.Taxes.ToList().Exists(tax => tax.Description == "USA"));
        }
        public void PlaceOrder_OrderIsValid_OrderSummaryContainsNetTotal()
        {
            // Arrange
            _customerRepository.Stub(c => c.Get(Arg<int>.Is.Anything)).Return(new Customer());
            _orderFulfillmentService.Stub(or => or.Fulfill(Arg<Order>.Is.Anything)).Return(new OrderConfirmation());
            _productRepository.Stub(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(true);
            _taxRateService.Stub(t => t.GetTaxEntries(Arg<String>.Is.Anything, Arg<String>.Is.Anything)).Return(new List<TaxEntry> { new TaxEntry() });

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                CustomerId = 1,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple", Price = (decimal) 2.00},
                        Quantity = 2
                    },
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple2", Price = (decimal) 2.50 },
                        Quantity = 1
                    }
                }
            };

            // Act
            var result = orderService.PlaceOrder(order);

            // Assert
            Assert.AreEqual(6.50, result.NetTotal);
        }
 private bool OrderIsValid(Order order, List<OrderItem> orderItems)
 {
     if (!orderItemsAreUnique(orderItems))
         _reasonsForInvalidOrder += "The orderItems are not unique by Sku. \n";
     if (!ItemsAreInStock(orderItems))
         _reasonsForInvalidOrder += "Not all products are in stock. \n";
     if (!IsCustomerValid(order.CustomerId))
         _reasonsForInvalidOrder += "The customer is null or cannot be retrieved.";
     return _reasonsForInvalidOrder.Length == 0;
 }
        public virtual void ValidateOrder(Order order)
        {
            var reasons = new List<string>();
            if (order == null)
            {
                reasons.Add("Order is null");
                throw new InvalidOrderException(reasons);
            }

            if (!order.OrderItemsAreUnique())
            {
                reasons.Add("Order skus are not unique");

                if (!order.AllProductsAreInStock())
                {
                    reasons.Add("Some products are not in stock");
                }
                throw new InvalidOrderException(reasons);
            }

            if (!order.AllProductsAreInStock())
            {
                reasons.Add("Some products are not in stock");
                throw new InvalidOrderException(reasons);
            }
        }
 private void SendConfirmationEmail(Order order, OrderSummary orderSummary)
 {
     _emailService.SendOrderConfirmationEmail(order.CustomerId, orderSummary.OrderId);
 }
        public void PlaceOrder_OrderIsValid_OrderSummaryContainsOrderId()
        {
            // Arrange
            var expectedOrderId = 1;
            _customerRepository.Stub(c => c.Get(Arg<int>.Is.Anything)).Return(new Customer());
            _productRepository.Stub(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(true);
            _taxRateService.Stub(t => t.GetTaxEntries(Arg<String>.Is.Anything, Arg<String>.Is.Anything)).Return(new List<TaxEntry> { new TaxEntry() });

            var order = new Order
            {
                CustomerId = 1,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem { Product = new Product { Sku = "apple" } },
                    new OrderItem { Product = new Product { Sku = "apple2" } },
                }
            };

            _orderFulfillmentService.Stub(or => or.Fulfill(order)).Return(new OrderConfirmation{OrderNumber = "1", OrderId = 1, });

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            // Act
            var result = orderService.PlaceOrder(order);

            // Assert
            Assert.That(result.OrderId, Is.EqualTo(expectedOrderId), "OrderId");
        }
        private Order GetOrderFrom(params Product[] products)
        {
            var order = new Order();

            foreach (var product in products)
            {
                var orderItem = new OrderItem { Product = product, Quantity = 17 };
                order.OrderItems.Add(orderItem);
            }

            order.CustomerId = _bestCustomer.CustomerId.Value;

            return order;
        }
        public void PlaceOrder_OrderIsNotValid_ThrowsExceptionWithListOfWhyNotValid()
        {
            // Arrange
            _productRepository.Expect(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(false);

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                OrderItems = new List<OrderItem>
                {
                    new OrderItem { Product = new Product { Sku = "apple" } },
                    new OrderItem { Product = new Product { Sku = "apple2" } }
                }
            };

            // Act // Assert
            Assert.Throws<Exception>(() => orderService.PlaceOrder(order));
        }
        public void PlaceOrder__NotUniqueByProductSKU__DoesThrowException()
        {
            // Arrange
            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                OrderItems = new List<OrderItem>
                {
                    new OrderItem { Product = new Product {Sku = "apple"} },
                    new OrderItem { Product = new Product {Sku = "apple"} },
                }
            };

            // Act // Assert
            var exception = Assert.Throws<Exception>(() => orderService.PlaceOrder(order));
            Assert.That(exception.Message, Is.StringContaining("The orderItems are not unique by Sku."));
        }
        public void PlaceOrder_TaxesNotInTaxRateService_TaxesIsEmpty()
        {
            // Arrange
            var customerId = 1;

            _productRepository.Stub(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(true);
            _orderFulfillmentService.Stub(or => or.Fulfill(Arg<Order>.Is.Anything)).Return(new OrderConfirmation());
            _customerRepository.Stub(c => c.Get(customerId)).Return(new Customer {CustomerId = customerId});

            _taxRateService.Expect(t => t.GetTaxEntries(Arg<String>.Is.Anything, Arg<String>.Is.Anything))
                .Return(new List<TaxEntry>());

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                CustomerId = customerId,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple", Price = (decimal) 2.00},
                        Quantity = 2
                    },
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple2", Price = (decimal) 2.50 },
                        Quantity = 1
                    }
                }
            };

            // Act
            var result = orderService.PlaceOrder(order);

            // Assert
            Assert.That(result.Taxes, Is.Empty);
        }
        public void PlaceOrder_OrderIsValid_ReturnOrderSummary()
        {
            // Arrange
            _customerRepository.Stub(c => c.Get(Arg<int>.Is.Anything)).Return(new Customer());
            _productRepository.Stub(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(true);
            _orderFulfillmentService.Stub(or => _orderFulfillmentService.Fulfill(Arg<Order>.Is.Anything)).Return(new OrderConfirmation());
            _taxRateService.Stub(t => t.GetTaxEntries(Arg<String>.Is.Anything, Arg<String>.Is.Anything)).Return(new List<TaxEntry> { new TaxEntry() });

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                CustomerId = 1,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem { Product = new Product { Sku = "apple" } },
                    new OrderItem { Product = new Product { Sku = "apple2" } }
                }
            };

            // Act // Assert
            var actual = orderService.PlaceOrder(order);
            Assert.IsInstanceOf<OrderSummary>(actual);
        }
        public void PlaceOrder_OrderIsValid_OrderSummaryContainsOrderTotal()
        {
            // Arrange
            var customer = new Customer { CustomerId = 1 };
            var taxRate1 = 1.5;
            var taxRate2 = 2.5;
            var netTotal = 6.50;

            _customerRepository.Stub(c => c.Get(Arg<int>.Is.Anything)).Return(customer);
            _orderFulfillmentService.Stub(or => or.Fulfill(Arg<Order>.Is.Anything)).Return(new OrderConfirmation());
            _productRepository.Stub(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(true);
            _taxRateService.Stub(t => t.GetTaxEntries(customer.PostalCode, customer.Country))
                .Return(new List<TaxEntry>
                {
                    new TaxEntry {Rate = (decimal) taxRate1},
                    new TaxEntry {Rate = (decimal) taxRate2},
                });

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                CustomerId = 1,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple", Price = (decimal) 2.00},
                        Quantity = 2
                    },
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple2", Price = (decimal) 2.50 },
                        Quantity = 1
                    }
                }
            };
            var expectedOrderTotal = netTotal * taxRate1 + netTotal * taxRate2;

            // Act
            var result = orderService.PlaceOrder(order);

            // Assert
            Assert.AreEqual(expectedOrderTotal, result.Total);
        }
 public OrderSummary PlaceOrder(Order order)
 {
     return null;
 }
        public void PlaceOrder_CustomerNotInCustomerRepository_DoesThrowException()
        {
            // Arrange
            _customerRepository.Stub(c => c.Get(Arg<int>.Is.Anything)).Return(null);
            _productRepository.Stub(pr => pr.IsInStock(Arg<string>.Is.Anything)).Return(true);

            var orderService = new OrderService(_productRepository, _orderFulfillmentService, _emailService, _customerRepository, _taxRateService);

            var order = new Order
            {
                CustomerId = 1,
                OrderItems = new List<OrderItem>
                {
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple", Price = (decimal) 2.00},
                        Quantity = 2
                    },
                    new OrderItem
                    {
                        Product = new Product { Sku = "apple2", Price = (decimal) 2.50 },
                        Quantity = 1
                    }
                }
            };
            // Act  // Assert
            var exception = Assert.Throws<Exception>(() => orderService.PlaceOrder(order));
            Assert.That(exception.Message, Is.StringContaining("The customer is null or cannot be retrieved."));
        }