public async void DeleteConfirmed_NonZeroInventories_OnlyRemovesEmptyProductLocationInventories()
        {
            Game game = new Game
            {
                Id = gameId,
                GameSKUs = new List<GameProduct>
                {
                    new PhysicalGameProduct
                    {
                        Id = gameSKUId,
                        GameId = gameId
                    }
                }
            };

            var matchingEmptyInventory = new ProductLocationInventory
            {
                ProductId = gameSKUId,
                LocationId = new Guid("B5055382-1AC6-4306-8830-CF3225D55E36"),
                NewOnHand = 0,
                UsedOnHand = 0,
                NewOnOrder = 0
            };

            var inventories = new List<ProductLocationInventory>
            {
                matchingEmptyInventory,
                new ProductLocationInventory
                {
                    ProductId = gameSKUId,
                    LocationId = new Guid("26226470-8CB5-4408-B9FF-20CD35DAF7B9"),
                    NewOnHand = 1,
                    UsedOnHand = 0,
                    NewOnOrder = 0
                },
                new ProductLocationInventory
                {
                    ProductId = gameSKUId,
                    LocationId = new Guid("3817326F-77F1-46E9-93DB-6C8F13FAB135"),
                    NewOnHand = 0,
                    UsedOnHand = 1,
                    NewOnOrder = 0
                },
                new ProductLocationInventory
                {
                    ProductId = gameSKUId,
                    LocationId = new Guid("7625893A-CA94-42CB-9DF0-3D8CA1380405"),
                    NewOnHand = 0,
                    UsedOnHand = 0,
                    NewOnOrder = 1
                },
                new ProductLocationInventory
                {
                    ProductId = gameSKUId,
                    LocationId = new Guid("F341600E-EA96-4CDB-9EEE-62E42B8007D4"),
                    NewOnHand = -1,
                    UsedOnHand = 0,
                    NewOnOrder = 0
                },
                new ProductLocationInventory
                {
                    ProductId = gameSKUId,
                    LocationId = new Guid("964A866D-E6D1-43C6-A473-2C3AF6693473"),
                    NewOnHand = 0,
                    UsedOnHand = -1,
                    NewOnOrder = 0
                },
                new ProductLocationInventory
                {
                    ProductId = gameSKUId,
                    LocationId = new Guid("548DD025-F261-4BE3-AC5B-F59C08E5B033"),
                    NewOnHand = 0,
                    UsedOnHand = 0,
                    NewOnOrder = -1
                }
            };

            var deletedInventories = new List<ProductLocationInventory>();

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();

            Mock<DbSet<Game>> gameDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<Game> { game }.AsQueryable());
            gameDbSetStub.SetupForInclude();
            gameDbSetStub.
                Setup(gdb => gdb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(game);

            Mock<DbSet<ProductLocationInventory>> inventoriesDbSetStub = TestHelpers.GetFakeAsyncDbSet(inventories.AsQueryable());
            inventoriesDbSetStub.
                Setup(idb => idb.RemoveRange(It.IsAny<IEnumerable<ProductLocationInventory>>())).
                Returns<IEnumerable<ProductLocationInventory>>(val => val).
                Callback<IEnumerable<ProductLocationInventory>>(val => deletedInventories = val.ToList());

            Mock<DbSet<GameProduct>> gameProductDbSetStub =
                TestHelpers.GetFakeAsyncDbSet(new List<GameProduct>().AsQueryable());

            dbStub.
                Setup(db => db.GameProducts).
                Returns(gameProductDbSetStub.Object);

            dbStub.
                Setup(db => db.ProductLocationInventories).
                Returns(inventoriesDbSetStub.Object);

            dbStub.
                Setup(db => db.Games).
                Returns(gameDbSetStub.Object);

            dbStub.
                Setup(db => db.SaveChangesAsync()).
                ReturnsAsync(1);

            GamesController controller = new GamesController(dbStub.Object, idGetter: null);

            await controller.DeleteGameConfirmed(game.Id);

            Assert.That(deletedInventories, Has.Count.EqualTo(1));
            Assert.That(deletedInventories, Has.Member(matchingEmptyInventory));
        }
        /// <summary>
        /// Saves a new Game Product and attaches it to a game.
        /// </summary>
        /// <param name="gameId">The Id of the game this product belongs to</param>
        /// <param name="gameProduct">The new gameProduct to save</param>
        /// <returns>Redirects to the details page for the game.</returns>
        private async Task<ActionResult> SaveGameProduct(Guid gameId, GameProduct gameProduct)
        {
            gameProduct.Game = await db.Games.FindAsync(gameId);
            db.GameProducts.Add(gameProduct);

            await db.SaveChangesAsync();

            if (gameProduct is PhysicalGameProduct)
            {
                ProductLocationInventory onlineInventory = new ProductLocationInventory
                {
                    ProductId = gameProduct.Id,
                    LocationId = await db.Locations.
                        Where(l => l.SiteName == Location.ONLINE_WAREHOUSE_NAME).
                        Select(l => l.Id).
                        FirstOrDefaultAsync(),
                    NewOnHand = 0,
                    UsedOnHand = 0,
                    NewOnOrder = 0
                };

                db.ProductLocationInventories.Add(onlineInventory);

                await db.SaveChangesAsync();
            }

            this.AddAlert(AlertType.Success, "Successfully added a new SKU.");

            return RedirectToAction("Details", "Games", new { id = gameId });
        }
        public async void Cancel_UserIsMember_ValidCancellation_SaveChangesFails_RedirectsToDetails()
        {
            List<WebOrder> orders = new List<WebOrder>
            {
                new WebOrder
                {
                    Id = 1,
                    MemberId = UserId,
                    OrderStatus = OrderStatus.PendingProcessing,
                    OrderItems = new List<OrderItem>
                    {
                        new OrderItem
                        {
                            IsNew = true,
                            ProductId = Id,
                            Quantity = 2
                        },
                        new OrderItem
                        {
                            IsNew = false,
                            ProductId = Id,
                            Quantity = 1
                        },
                    }
                }
            };

            ProductLocationInventory inventory = new ProductLocationInventory
            {
                Location = new Location
                {
                    SiteName = Location.ONLINE_WAREHOUSE_NAME
                },
                ProductId = Id,
                NewOnHand = 0,
                UsedOnHand = 0
            };

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            dbStub.Setup(db => db.SaveChangesAsync()).Throws(new DataException());

            Mock<DbSet<WebOrder>> webOrdersDbSetStub = TestHelpers.GetFakeAsyncDbSet(orders.AsQueryable());
            webOrdersDbSetStub.Setup(wo => wo.FindAsync(orders[0].Id)).ReturnsAsync(orders[0]);
            dbStub.Setup(db => db.WebOrders).Returns(webOrdersDbSetStub.Object);

            Mock<DbSet<ProductLocationInventory>> inventoryDbSetStub =
                TestHelpers.GetFakeAsyncDbSet(new List<ProductLocationInventory> { inventory }.AsQueryable());
            dbStub.Setup(db => db.ProductLocationInventories).Returns(inventoryDbSetStub.Object);

            Mock<ControllerContext> context = new Mock<ControllerContext>();
            context.Setup(c => c.HttpContext.User.Identity).Returns<IIdentity>(null);
            context.Setup(c => c.HttpContext.User.Identity.IsAuthenticated).Returns(true);

            Mock<IGuidUserIdGetter> idGetterStub = new Mock<IGuidUserIdGetter>();
            idGetterStub.Setup(id => id.GetUserId(It.IsAny<IIdentity>())).Returns(UserId);

            Mock<IStripeService> stripeServiceStub = new Mock<IStripeService>();
            stripeServiceStub.Setup(s => s.RefundCharge(It.IsAny<string>())).Returns(true);

            WebOrdersController controller = new WebOrdersController(dbStub.Object, idGetterStub.Object, stripeServiceStub.Object, userManager: null)
            {
                ControllerContext = context.Object
            };

            var result = await controller.Cancel(1) as RedirectToRouteResult;

            Assert.That(result != null);
            Assert.That(result.RouteValues["action"], Is.EqualTo("Details"));
        }
        public async void SetStatusCancelled_CurrentStatusValid_RedirectsToDetails(OrderStatus status)
        {
            List<WebOrder> orders = new List<WebOrder>
            {
                new WebOrder
                {
                    Id = 1,
                    MemberId = UserId,
                    OrderStatus = status,
                    OrderItems = new List<OrderItem>
                    {
                        new OrderItem
                        {
                            IsNew = true,
                            ProductId = Id,
                            Quantity = 2
                        },
                        new OrderItem
                        {
                            IsNew = false,
                            ProductId = Id,
                            Quantity = 1
                        },
                    }
                }
            };

            ProductLocationInventory inventory = new ProductLocationInventory
            {
                Location = new Location
                {
                    SiteName = Location.ONLINE_WAREHOUSE_NAME
                },
                ProductId = Id,
                NewOnHand = 0,
                UsedOnHand = 0
            };

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();

            Mock<IUserStore<User, Guid>> userStoreStub = new Mock<IUserStore<User, Guid>>();
            dbStub.Setup(db => db.UserStore).Returns(userStoreStub.Object);

            Mock<DbSet<WebOrder>> webOrdersDbSetStub = TestHelpers.GetFakeAsyncDbSet(orders.AsQueryable());
            webOrdersDbSetStub.Setup(wo => wo.FindAsync(orders[0].Id)).ReturnsAsync(orders[0]);
            dbStub.Setup(db => db.WebOrders).Returns(webOrdersDbSetStub.Object);

            Mock<DbSet<ProductLocationInventory>> inventoryDbSetStub =
                TestHelpers.GetFakeAsyncDbSet(new List<ProductLocationInventory> { inventory }.AsQueryable());
            dbStub.Setup(db => db.ProductLocationInventories).Returns(inventoryDbSetStub.Object);

            Mock<IStripeService> stripeServiceStub = new Mock<IStripeService>();
            stripeServiceStub.Setup(s => s.RefundCharge(It.IsAny<string>())).Returns(true);

            Mock<VeilUserManager> userManagerMock = new Mock<VeilUserManager>(dbStub.Object, null /*messageService*/, null /*dataProtectionProvider*/);
            userManagerMock.
                Setup(um => um.SendEmailAsync(It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<string>())).
                Returns(Task.FromResult(0)).
                Verifiable();

            Mock<ControllerContext> context = new Mock<ControllerContext>();

            Mock<IView> partialViewStub = new Mock<IView>();
            Mock<IViewEngine> viewEngineStub = new Mock<IViewEngine>();
            var viewEngineResult = new ViewEngineResult(partialViewStub.Object, viewEngineStub.Object);
            viewEngineStub.Setup(ve => ve.FindPartialView(It.IsAny<ControllerContext>(), It.IsAny<string>(), It.IsAny<bool>())).Returns(viewEngineResult);
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(viewEngineStub.Object);

            WebOrdersController controller = new WebOrdersController(dbStub.Object, null, stripeServiceStub.Object, userManagerMock.Object)
            {
                ControllerContext = context.Object
            };

            var result = await controller.SetStatusCancelled(1, "TestReason", true) as RedirectToRouteResult;

            Assert.That(result != null);
            Assert.That(result.RouteValues["action"], Is.EqualTo("Details"));
            Assert.That(orders[0].OrderStatus, Is.EqualTo(OrderStatus.EmployeeCancelled));
            Assert.That(orders[0].ReasonForCancellationMessage, Is.EqualTo("TestReason"));
            Assert.That(inventory.NewOnHand, Is.EqualTo(2));
            Assert.That(inventory.UsedOnHand, Is.EqualTo(1));

            Assert.That(
                () =>
                    userManagerMock.Verify(um => um.SendEmailAsync(It.Is<Guid>(val => val == orders[0].MemberId), It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(1)),
                Throws.Nothing);
        }
        public void Cancel_UserIsMember_ValidCancellation_RefundFailsDueToApiKey_ThrowsInternalServerError()
        {
            List<WebOrder> orders = new List<WebOrder>
            {
                new WebOrder
                {
                    Id = 1,
                    MemberId = UserId,
                    OrderStatus = OrderStatus.PendingProcessing,
                    OrderItems = new List<OrderItem>
                    {
                        new OrderItem
                        {
                            IsNew = true,
                            ProductId = Id,
                            Quantity = 2
                        },
                        new OrderItem
                        {
                            IsNew = false,
                            ProductId = Id,
                            Quantity = 1
                        },
                    }
                }
            };

            ProductLocationInventory inventory = new ProductLocationInventory
            {
                Location = new Location
                {
                    SiteName = Location.ONLINE_WAREHOUSE_NAME
                },
                ProductId = Id,
                NewOnHand = 0,
                UsedOnHand = 0
            };

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<WebOrder>> webOrdersDbSetStub = TestHelpers.GetFakeAsyncDbSet(orders.AsQueryable());
            webOrdersDbSetStub.Setup(wo => wo.FindAsync(orders[0].Id)).ReturnsAsync(orders[0]);
            dbStub.Setup(db => db.WebOrders).Returns(webOrdersDbSetStub.Object);

            Mock<DbSet<ProductLocationInventory>> inventoryDbSetStub =
                TestHelpers.GetFakeAsyncDbSet(new List<ProductLocationInventory> { inventory }.AsQueryable());
            dbStub.Setup(db => db.ProductLocationInventories).Returns(inventoryDbSetStub.Object);

            Mock<ControllerContext> context = new Mock<ControllerContext>();
            context.Setup(c => c.HttpContext.User.Identity).Returns<IIdentity>(null);
            context.Setup(c => c.HttpContext.User.Identity.IsAuthenticated).Returns(true);

            Mock<IGuidUserIdGetter> idGetterStub = new Mock<IGuidUserIdGetter>();
            idGetterStub.Setup(id => id.GetUserId(It.IsAny<IIdentity>())).Returns(UserId);

            Mock<IStripeService> stripeServiceStub = new Mock<IStripeService>();
            stripeServiceStub.Setup(s => s.RefundCharge(It.IsAny<string>())).Throws(new StripeServiceException("message", StripeExceptionType.ApiKeyError));

            WebOrdersController controller = new WebOrdersController(dbStub.Object, idGetterStub.Object, stripeServiceStub.Object, userManager: null)
            {
                ControllerContext = context.Object
            };

            Assert.That(async () => await controller.Cancel(1) as RedirectToRouteResult, 
                Throws.InstanceOf<HttpException>().And.Matches<HttpException>(ex => ex.GetHttpCode() >= (int)HttpStatusCode.InternalServerError));
        }