public async Task <IStatusGeneric <Order> >          //#A
        CreateOrderAndSaveAsync(PlaceOrderInDto dto)         //#B
        {
            var status = new StatusGenericHandler <Order>(); //#C

            if (!dto.AcceptTAndCs)                           //#D
            {
                return(status.AddError("You must accept the T&Cs to place an order."));
            }
            if (!dto.LineItems.Any())                 //#D
            {
                return(status.AddError("No items in your basket."));
            }

            var booksDict = await _dbAccess                            //#E
                            .FindBooksByIdsAsync                       //#E
                                (dto.LineItems.Select(x => x.BookId)); //#E

            var linesStatus = FormLineItemsWithErrorChecking           //#F
                                  (dto.LineItems, booksDict);          //#F

            if (status.CombineStatuses(linesStatus).HasErrors)         //#G
            {
                return(status);                                        //#G
            }
            var orderStatus = Order.CreateOrder(                       //#H
                dto.UserId, linesStatus.Result);                       //#H

            if (status.CombineStatuses(orderStatus).HasErrors)         //#I
            {
                return(status);                                        //#I
            }
            await _dbAccess.AddAndSave(orderStatus.Result);            //#J

            return(status.SetResult(orderStatus.Result));              //#K
        }
        public async Task TestCreateOrderOneBookOk()
        {
            //SETUP
            var userId  = Guid.NewGuid();
            var options = SqliteInMemory.CreateOptions <OrderDbContext>();

            options.StopNextDispose();
            using var context = new OrderDbContext(options, new FakeUserIdService(userId));

            context.Database.EnsureCreated();
            var bookIds = context.SeedFourBookDdPartWithOptionalDbSchemaAdd(true);
            var service = new PlaceOrderBizLogic(new PlaceOrderDbAccess(context));
            //ATTEMPT
            var lineItems = new List <OrderLineItem>
            {
                new OrderLineItem {
                    BookId = 1, NumBooks = 4
                },
            };
            var dto    = new PlaceOrderInDto(true, userId, lineItems.ToImmutableList());
            var status = await service.CreateOrderAndSaveAsync(dto);

            //VERIFY
            status.IsValid.ShouldBeTrue(status.GetAllErrors());
            context.ChangeTracker.Clear();
            var order    = context.Orders.Include(x => x.LineItems).Single();
            var lineItem = order.LineItems.Single();

            lineItem.BookId.ShouldEqual(1);
            lineItem.NumBooks.ShouldEqual((short)4);
            lineItem.BookPrice.ShouldEqual(40);
        }
        public async Task TestCreateOrderTAndCsBad()
        {
            //SETUP
            var userId  = Guid.NewGuid();
            var options = SqliteInMemory.CreateOptions <OrderDbContext>();

            using var context = new OrderDbContext(options, new FakeUserIdService(userId));

            context.Database.EnsureCreated();
            var service = new PlaceOrderBizLogic(new PlaceOrderDbAccess(context));

            //ATTEMPT
            var lineItems = new List <OrderLineItem>
            {
                new OrderLineItem {
                    BookId = 1, NumBooks = 4
                },
            };
            var dto    = new PlaceOrderInDto(false, userId, lineItems.ToImmutableList());
            var status = await service.CreateOrderAndSaveAsync(dto);

            //VERIFY
            status.IsValid.ShouldBeFalse();
            status.GetAllErrors().ShouldEqual("You must accept the T&Cs to place an order.");
        }
示例#4
0
        /// <summary>
        /// This validates the input and if OK creates
        /// an order and calls the _dbAccess to add to orders
        /// </summary>
        /// <param name="dto"></param>
        /// <returns>returns an Order. Will be null if there are errors</returns>
        public Order BizAction(PlaceOrderInDto dto)
        {
            if (!dto.AcceptTAndCs)
            {
                AddError("You must accept the T&Cs to place an order.");
                return(null);
            }
            if (!dto.LineItems.Any())
            {
                AddError("No items in your basket.");
                return(null);
            }

            var booksDict = _dbAccess.FindBooksByIdsWithPriceOffers
                                (dto.LineItems.Select(x => x.BookId));
            var order = new Order
            {
                CustomerName         = dto.UserId,
                ExpectedDeliveryDate = DateTime.Today.AddDays(5),
                LineItems            = FormLineItemsWithErrorChecking(dto.LineItems, booksDict)
            };

            if (!HasErrors)
            {
                _dbAccess.Add(order);
            }

            return(HasErrors ? null : order);
        }
示例#5
0
        public IActionResult PlaceOrder(PlaceOrderInDto dto,
                                        [FromServices] IActionService <IRepository, IPlaceOrderAction> service)
        {
            if (!ModelState.IsValid)
            {
                //model errors so return to checkout page, showing the basket
                return(View("Index", FormCheckoutDtoFromCookie(HttpContext)));
            }

            //This runs my business logic using the service injected into the Action's parameters
            var orderDto = service.RunBizAction <OrderIdDto>(dto);

            if (!service.Status.HasErrors)
            {
                //If successful I need to clear the line items from the basket cookie
                ClearCheckoutCookie(HttpContext);
                SetupTraceInfo();       //Used to update the logs
                return(RedirectToAction("ConfirmOrder", "Orders",
                                        new { orderDto.OrderId, Message = "Your order is confirmed" }));
            }

            //Otherwise errors, so I need to redisplay the basket from the cookie
            var checkoutDto = FormCheckoutDtoFromCookie(HttpContext);

            //This copies the errors to the ModelState
            service.Status.CopyErrorsToModelState(ModelState, checkoutDto);

            SetupTraceInfo();       //Used to update the logs
            return(View("Index", checkoutDto));
        }
        public void TestAddOrderViaBizLogicOk()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();
                context.SeedDatabaseFourBooks();

                var service = new PlaceOrderAction(new PlaceOrderDbAccess(context));
                var dto     = new PlaceOrderInDto
                {
                    AcceptTAndCs      = true,
                    CheckoutLineItems = new List <OrderLineItem>
                    {
                        new OrderLineItem {
                            BookId = 1, NumBooks = 2
                        }
                    }
                };

                //ATTEMPT
                var order = service.BizAction(dto);

                //VERIFY
                service.HasErrors.ShouldBeFalse();
                order.LineItems.Count().ShouldEqual(1);
                order.LineItems.Single().BookPrice.ShouldEqual(context.Books.Find(1).ActualPrice);
            }
        }
示例#7
0
        public Order Action(PlaceOrderInDto dto)
        {
            if (!dto.AcceptTAndCs)
            {
                AddError("You must accept the T&Cs to place an order.");
                return(null);
            }

            if (dto.LineItems.Count == 0)
            {
                AddError("No items in your basket.");
                return(null);
            }

            var bookIds = dto.LineItems.Select(lineItem => lineItem.BookId);
            //to present the data as an in-memory set(in this case, a dictionary)
            var booksDict = dbAccess.FindBooksByIdsWithPriceOffers(bookIds);
            var order     = new Order
            {
                CustomerName = dto.UserId,
                LineItems    = FormLineItemsWithErrorChecking(dto.LineItems, booksDict)
            };

            if (!HasErrors)
            {
                dbAccess.Add(order);
            }

            return(HasErrors ? null : order);
        }
示例#8
0
        public int PlaceOrder(bool acceptTAndCs)
        {
            var checkoutService = new CheckoutCookieService(checkoutCookie.GetValue());
            var placeOrderInDto = new PlaceOrderInDto(acceptTAndCs, checkoutService.UserId, checkoutService.LineItems);
            var order           = runner.RunAction(placeOrderInDto);

            if (runner.HasErrors)
            {
                return(0);
            }

            checkoutService.ClearAllLineItems();
            checkoutCookie.AddOrUpdateCookie(checkoutService.EncodeForCookie());

            return(order.OrderId);
        }
        public async Task TestCreateOrderEmptyBasketBad()
        {
            //SETUP
            var userId  = Guid.NewGuid();
            var options = SqliteInMemory.CreateOptions <OrderDbContext>();

            using var context = new OrderDbContext(options, new FakeUserIdService(userId));

            context.Database.EnsureCreated();
            var service = new PlaceOrderBizLogic(new PlaceOrderDbAccess(context));

            //ATTEMPT
            var dto    = new PlaceOrderInDto(true, userId, (new List <OrderLineItem>()).ToImmutableList());
            var status = await service.CreateOrderAndSaveAsync(dto);

            //VERIFY
            status.IsValid.ShouldBeFalse();
            status.GetAllErrors().ShouldEqual("No items in your basket.");
        }
        /// <summary>
        /// This validates the input and if OK creates
        /// an order and calls the _dbAccess to add to orders
        /// </summary>
        /// <param name="dto"></param>
        /// <returns>returns an Order. Will be null if there are errors</returns>
        public Order BizAction(PlaceOrderInDto dto)
        {
            if (!dto.AcceptTAndCs)
            {
                AddError("You must accept the T&Cs to place an order.");
                return(null);
            }

            var bookOrders  = dto.CheckoutLineItems.Select(x => _dbAccess.BuildBooksDto(x.BookId, x.NumBooks));
            var orderStatus = Order.CreateOrderFactory(dto.UserId, DateTime.Today.AddDays(5), bookOrders);

            CombineErrors(orderStatus);

            if (!HasErrors)
            {
                _dbAccess.Add(orderStatus.Result);
            }

            return(orderStatus.Result);
        }
示例#11
0
        public Part1ToPart2Dto Action(PlaceOrderInDto dto)
        {
            if (!dto.AcceptTAndCs)
            {
                AddError("You must accept the T&Cs to place an order.");
            }

            if (dto.LineItems.Count == 0)
            {
                AddError("No items in your basket.");
            }

            Order order = new Order {
                CustomerName = dto.UserId
            };

            if (!HasErrors)
            {
                dbAccess.Add(order);
            }

            return(new Part1ToPart2Dto(dto.LineItems, order));
        }
示例#12
0
        public void ExampleOfMockingOk()
        {
            //SETUP                                           //#A
            var lineItems = new List <OrderLineItem>          //#A
            {                                                 //#A
                new OrderLineItem {
                    BookId = 1, NumBooks = 4
                },                                                         //#A
            };                                                             //#A
            var userId = Guid.NewGuid();                                   //#A
            var input  = new PlaceOrderInDto(true, userId,                 //#A
                                             lineItems.ToImmutableList()); //#A

            var mockDbA = new MockPlaceOrderDbAccess();                    //#B
            var service = new PlaceOrderAction(mockDbA);                   //#C

            //ATTEMPT
            service.Action(input); //#D

            //VERIFY
            service.Errors.Any().ShouldEqual(false); //#
            mockDbA.AddedOrder.CustomerId            //#F
            .ShouldEqual(userId);                    //#F
        }
示例#13
0
        public Part1ToPart2Dto BizAction(PlaceOrderInDto dto)
        {
            if (!dto.AcceptTAndCs)
            {
                AddError("You must accept the T&Cs to place an order.");
            }

            if (!dto.LineItems.Any())
            {
                AddError("No items in your basket.");
            }

            var order = new Order
            {
                CustomerName = dto.UserId
            };

            if (!HasErrors)
            {
                _dbAccess.Add(order);
            }

            return(new Part1ToPart2Dto(dto.LineItems.ToImmutableList(), order));
        }
        public void TestAddOrderNoAcceptBad()
        {
            //SETUP
            var options = SqliteInMemory.CreateOptions <EfCoreContext>();

            using (var context = new EfCoreContext(options))
            {
                context.Database.EnsureCreated();
                context.SeedDatabaseFourBooks();

                var service = new PlaceOrderAction(new PlaceOrderDbAccess(context));
                var dto     = new PlaceOrderInDto
                {
                    AcceptTAndCs = false,
                };

                //ATTEMPT
                var order = service.BizAction(dto);

                //VERIFY
                service.HasErrors.ShouldBeTrue();
                service.Errors.Single().ErrorResult.ErrorMessage.ShouldEqual("You must accept the T&Cs to place an order.");
            }
        }