public async void DeleteAddress_IdInDb_CallsSaveChangesAsync()
        {
            MemberAddress addressToDelete = new MemberAddress
            {
                Id = addressId
            };

            Mock<IVeilDataAccess> dbMock = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToDelete);
            addressDbSetStub.
                Setup(adb => adb.Remove(It.IsAny<MemberAddress>())).
                Returns<MemberAddress>(val => val);

            dbMock.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);
            dbMock.
                Setup(db => db.SaveChangesAsync()).
                ReturnsAsync(1).
                Verifiable();

            ManageController controller = CreateManageController(veilDataAccess: dbMock.Object);

            await controller.DeleteAddress(addressId);

            Assert.That(
                () =>
                    dbMock.Verify(db => db.SaveChangesAsync(),
                    Times.Once),
                Throws.Nothing);
        }
        public async void EditAddressGET_IdInDb_SetsUpViewModelWithCountries()
        {
            MemberAddress addressToEdit = new MemberAddress { Address = new Address() };
            List<Country> countries = GetCountries();

            Mock<IVeilDataAccess> dbStub = SetupVeilDataAccessFakeWithCountries(countries);
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit);

            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            var result = await controller.EditAddress(addressId) as ViewResult;

            Assert.That(result != null);
            Assert.That(result.Model, Is.InstanceOf<AddressViewModel>());

            var model = (AddressViewModel)result.Model;

            Assert.That(model.Countries, Is.Not.Empty);
            Assert.That(model.Countries, Has.Count.EqualTo(countries.Count));
        }
        /// <summary>
        ///     Gets a new <see cref="MemberAddress"/> populated with the shipping information
        ///     from the <see cref="orderCheckoutDetails"/>
        /// </summary>
        /// <param name="orderCheckoutDetails">
        ///     The <see cref="WebOrderCheckoutDetails"/> to use for retrieving the address information
        /// </param>
        /// <returns>
        ///     A new <see cref="MemberAddress"/> populated with the shipping address information.
        ///     If unsuccessful, null with be returned with an error alert already added
        /// </returns>
        private async Task<MemberAddress> GetShippingAddress(WebOrderCheckoutDetails orderCheckoutDetails)
        {
            MemberAddress memberAddress;

            if (orderCheckoutDetails.MemberAddressId != null)
            {
                memberAddress = await db.MemberAddresses.
                    Include(ma => ma.Province).
                    Include(ma => ma.Country).
                    SingleOrDefaultAsync(ma => ma.Id == orderCheckoutDetails.MemberAddressId);
            }
            else
            {
                memberAddress = new MemberAddress
                {
                    Address = orderCheckoutDetails.Address,
                    ProvinceCode = orderCheckoutDetails.ProvinceCode,
                    CountryCode = orderCheckoutDetails.CountryCode
                };

                memberAddress.Province = await db.Provinces.
                    Include(p => p.Country).
                    FirstOrDefaultAsync(
                        p => p.ProvinceCode == memberAddress.ProvinceCode &&
                            p.CountryCode == memberAddress.CountryCode);

                memberAddress.Country = memberAddress.Province.Country;
            }

            if (memberAddress == null)
            {
                this.AddAlert(AlertType.Error, "The shipping address you selected could not be found.");
            }

            return memberAddress;
        }
        public async Task<ActionResult> NewShippingInfo(AddressViewModel model, bool saveAddress,
            bool returnToConfirm = false)
        {
            Guid memberId = GetUserId();

            RedirectToRouteResult invalidStateResult = await EnsureCartNotEmptyAsync(memberId);
            if (invalidStateResult != null)
            {
                return invalidStateResult;
            }

            if (!ModelState.IsValid)
            {
                model.UpdatePostalCodeModelError(ModelState);

                this.AddAlert(AlertType.Error, "Some address information was invalid.");

                await model.SetupAddressesAndCountries(db, memberId);

                return View("ShippingInfo", model);
            }

            bool validCountry = await db.Countries.AnyAsync(c => c.CountryCode == model.CountryCode);
            bool validProvince = true;

            if (!validCountry)
            {
                this.AddAlert(AlertType.Error, "The Country you selected isn't valid.");
            }
            else
            {
                validProvince = await db.Provinces.
                AnyAsync(p => p.CountryCode == model.CountryCode &&
                        p.ProvinceCode == model.ProvinceCode);

                if (!validProvince)
                {
                    this.AddAlert(AlertType.Error,
                        "The Province/State you selected isn't in the Country you selected.");
                }
            }

            if (!validCountry || !validProvince)
            {
                await model.SetupAddressesAndCountries(db, memberId);

                return View("ShippingInfo", model);
            }

            var orderCheckoutDetails =  Session[OrderCheckoutDetailsKey] as WebOrderCheckoutDetails ??
                new WebOrderCheckoutDetails();

            model.FormatPostalCode();

            if (saveAddress)
            {
                var newAddress = new MemberAddress
                {
                    MemberId = memberId,
                    Address = model.MapToNewAddress(),
                    CountryCode = model.CountryCode,
                    ProvinceCode = model.ProvinceCode
                };

                db.MemberAddresses.Add(newAddress);

                await db.SaveChangesAsync();

                this.AddAlert(AlertType.Success, "Successfully add the new address.");

                orderCheckoutDetails.MemberAddressId = newAddress.Id;
            }
            else
            {
                orderCheckoutDetails.Address = model.MapToNewAddress();
                orderCheckoutDetails.CountryCode = model.CountryCode;
                orderCheckoutDetails.ProvinceCode = model.ProvinceCode;
            }

            Session[OrderCheckoutDetailsKey] = orderCheckoutDetails;

            if (returnToConfirm)
            {
                return RedirectToAction("ConfirmOrder");
            }

            return RedirectToAction("BillingInfo");
        }
        public void SetupBase()
        {
            memberId = new Guid("59EF92BE-D71F-49ED-992D-DF15773DAF98");
            addressId = new Guid("53BE47E4-0C74-4D49-97BB-7246A7880B39");
            creditCardId = new Guid("D9A69026-E3DA-4748-816B-293D9BE3E43F");
            cartProduct1Id = new Guid("3882D242-A62A-4E99-BA11-D6EF340C2EE8");
            cartProduct2Id = new Guid("7413D131-7337-42DC-A7E4-1155EB91E8C9");

            memberAddress = new MemberAddress
            {
                Address = new Address
                {
                    City = "Waterloo",
                    PostalCode = "N2L 6R2",
                    StreetAddress = "445 Wes Graham Way"
                },
                CountryCode = "CA",
                Country = new Country { CountryCode = "CA", CountryName = "Canada", FederalTaxRate = 0.05m },
                ProvinceCode = "ON",
                Province = new Province { CountryCode = "CA", ProvinceCode = "ON", ProvincialTaxRate = 0.08m },
                MemberId = memberId,
                Id = addressId
            };

            game = new Game
            {
                Name = "A game"
            };

            platform = new Platform
            {
                PlatformCode = "XONE",
                PlatformName = "Xbox One"
            };

            cartProduct1 = new PhysicalGameProduct
            {
                Id = cartProduct1Id,
                NewWebPrice = 60.00m,
                ProductAvailabilityStatus = AvailabilityStatus.Available,
                ReleaseDate = new DateTime(635835582902643008L, DateTimeKind.Local),
                UsedWebPrice = 10.00m,
                Game = game,
                Platform = platform
            };

            cartProduct2 = new PhysicalGameProduct
            {
                Id = cartProduct2Id,
                NewWebPrice = 59.99m,
                ProductAvailabilityStatus = AvailabilityStatus.Available,
                ReleaseDate = new DateTime(635837213100050176L, DateTimeKind.Local),
                Game = game,
                Platform = platform
            };

            newProduct1CartItem = new CartItem
            {
                IsNew = true,
                MemberId = memberId,
                Product = cartProduct1,
                ProductId = cartProduct1.Id,
                Quantity = 1
            };

            usedProduct1CartItem = new CartItem
            {
                IsNew = false,
                MemberId = memberId,
                Product = cartProduct1,
                ProductId = cartProduct1.Id,
                Quantity = 1
            };

            newProduct2CartItem = new CartItem
            {
                IsNew = true,
                MemberId = memberId,
                Product = cartProduct2,
                ProductId = cartProduct2.Id,
                Quantity = 1
            };

            validNotSavedShippingDetails = new WebOrderCheckoutDetails
            {
                Address = new Address
                {
                    City = "Waterloo",
                    PostalCode = "N2L 6R2",
                    POBoxNumber = "123",
                    StreetAddress = "445 Wes Graham Way"
                },
                ProvinceCode = "ON",
                CountryCode = "CA"
            };

            validAddressViewModel = new AddressViewModel
            {
                City = "Waterloo",
                CountryCode = "CA",
                ProvinceCode = "ON",
                POBoxNumber = "1234",
                PostalCode = "N2L 6R2",
                StreetAddress = "445 Wes Graham Way"
            };

            memberCreditCard = new MemberCreditCard
            {
                Id = creditCardId,
                CardholderName = "John Doe",
                ExpiryMonth = 11,
                ExpiryYear = 2015,
                Last4Digits = "4242",
                Member = member,
                MemberId = memberId,
                StripeCardId = "cardToken"
            };

            member = new Member
            {
                UserId = memberId,
                CreditCards = new List<MemberCreditCard>
                {
                    memberCreditCard
                }
            };

            memberUser = new User
            {
                FirstName = "John",
                LastName = "Doe",
                Id = memberId,
                PhoneNumber = "800-555-0199",
            };
            
            validNotSavedShippingBillingDetails = new WebOrderCheckoutDetails
            {
                Address = new Address
                {
                    City = "Waterloo",
                    PostalCode = "N2L 6R2",
                    POBoxNumber = "123",
                    StreetAddress = "445 Wes Graham Way"
                },
                ProvinceCode = "ON",
                CountryCode = "CA",
                StripeCardToken = "card_token"
            };

            validSavedShippingBillingDetails = new WebOrderCheckoutDetails
            {
                MemberCreditCardId = creditCardId,
                MemberAddressId = addressId
            };

            cartWithNewAndUsed = new Cart
            {
                Items = new List<CartItem>
                {
                    newProduct1CartItem,
                    usedProduct1CartItem
                },
                Member = member,
                MemberId = memberId
            };
        }
        public async void DeleteAddress_IdInDb_ReturnsRedirectionToManageAddresses()
        {
            MemberAddress addressToDelete = new MemberAddress
            {
                Id = addressId
            };

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToDelete);

            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            var result = await controller.DeleteAddress(addressId) as RedirectToRouteResult;

            Assert.That(result != null);
            Assert.That(result.RouteValues["Action"], Is.EqualTo(nameof(ManageController.ManageAddresses)));
            Assert.That(result.RouteValues["Controllers"], Is.Null.Or.EqualTo("Manage"));
        }
        public async void EditAddressGET_IdInDb_MapsMatchingAddressToViewModel()
        {
            MemberAddress addressToEdit = new MemberAddress
            {
                Address = new Address
                {
                    StreetAddress = "445 Wes Graham Way",
                    City = "Waterloo",
                    POBoxNumber = "123",
                    PostalCode = "N2L 6R2"
                },
                Id = addressId,
                CountryCode = "CA",
                ProvinceCode = "ON",
            };

            Mock<IVeilDataAccess> dbStub = SetupVeilDataAccessFakeWithCountries();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit);
            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            var result = await controller.EditAddress(addressId) as ViewResult;

            Assert.That(result != null);
            Assert.That(result.Model, Is.InstanceOf<AddressViewModel>());

            var model = (AddressViewModel)result.Model;

            Assert.That(model.StreetAddress, Is.EqualTo(addressToEdit.Address.StreetAddress));
            Assert.That(model.City, Is.EqualTo(addressToEdit.Address.City));
            Assert.That(model.POBoxNumber, Is.EqualTo(addressToEdit.Address.POBoxNumber));
            Assert.That(model.PostalCode, Is.EqualTo(addressToEdit.Address.PostalCode));
            Assert.That(model.Id, Is.EqualTo(addressToEdit.Id));
            Assert.That(model.CountryCode, Is.EqualTo(addressToEdit.CountryCode));
            Assert.That(model.ProvinceCode, Is.EqualTo(addressToEdit.ProvinceCode));
        }
        public async void EditAddress_ValidModel_MapsViewModelToNewModel()
        {
            MemberAddress addressToEdit = new MemberAddress { Address = new Address() };
            AddressViewModel viewModel = new AddressViewModel
            {
                City = "Waterloo",
                CountryCode = "CA",
                ProvinceCode = "ON",
                PostalCode = "N2L 6R2",
                StreetAddress = "445 Wes Graham Way",
                POBoxNumber = "123"
            };

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit);
            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            await controller.EditAddress(addressId, viewModel);

            Assert.That(addressToEdit != null);
            Assert.That(addressToEdit.Address.City, Is.EqualTo(viewModel.City));
            Assert.That(addressToEdit.CountryCode, Is.EqualTo(viewModel.CountryCode));
            Assert.That(addressToEdit.ProvinceCode, Is.EqualTo(viewModel.ProvinceCode));
            Assert.That(addressToEdit.Address.PostalCode, Is.EqualTo(viewModel.PostalCode));
            Assert.That(addressToEdit.Address.StreetAddress, Is.EqualTo(viewModel.StreetAddress));
            Assert.That(addressToEdit.Address.POBoxNumber, Is.EqualTo(viewModel.POBoxNumber));
        }
        public async void EditAddress_ValidModel_CallsFindAsyncWithPassedId()
        {
            MemberAddress addressToEdit = new MemberAddress();
            AddressViewModel viewModel = new AddressViewModel();

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit).
                Verifiable();

            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            await controller.EditAddress(addressId, viewModel);

            Assert.That(
                () =>
                    addressDbSetStub.Verify(adb => adb.FindAsync(addressId),
                    Times.Exactly(1)),
                Throws.Nothing);
        }
        public async void EditAddress_SuccessfulSave_RedirectsToManageAddress()
        {
            MemberAddress addressToEdit = new MemberAddress();
            AddressViewModel viewModel = new AddressViewModel();

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit);

            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);
            dbStub.
                Setup(db => db.SaveChangesAsync()).
                ReturnsAsync(1);

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            var result = await controller.EditAddress(addressId, viewModel) as RedirectToRouteResult;

            Assert.That(result != null);
            Assert.That(result.RouteValues["Action"], Is.EqualTo(nameof(ManageController.ManageAddresses)));
        }
        public async void EditAddress_SaveChangesAsyncThrowing_RedisplaysViewWithSameViewModel()
        {
            MemberAddress addressToEdit = new MemberAddress();
            AddressViewModel viewModel = new AddressViewModel();

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit);

            Mock<DbSet<Country>> countryDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<Country>().AsQueryable());
            countryDbSetStub.SetupForInclude();

            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);
            dbStub.
                Setup(db => db.Countries).
                Returns(countryDbSetStub.Object);

            dbStub.
                Setup(db => db.SaveChangesAsync()).
                ThrowsAsync(new DbUpdateException());

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            var result = await controller.EditAddress(addressId, viewModel) as ViewResult;

            Assert.That(result != null);
            Assert.That(result.Model, Is.EqualTo(viewModel));
        }
        public void EditAddress_SaveChangesAsyncThrowing_HandlesException()
        {
            MemberAddress addressToEdit = new MemberAddress();
            AddressViewModel viewModel = new AddressViewModel();

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit);

            Mock<DbSet<Country>> countryDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<Country>().AsQueryable());
            countryDbSetStub.SetupForInclude();

            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);
            dbStub.
                Setup(db => db.Countries).
                Returns(countryDbSetStub.Object);
            dbStub.
                Setup(db => db.SaveChangesAsync()).
                ThrowsAsync(new DbUpdateException());

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            Assert.That(async () => await controller.EditAddress(addressId, viewModel), Throws.Nothing);
        }
        public void EditAddress_SaveChangesAsyncThrowingProvinceForeignKeyViolationException_HandlesException()
        {
            MemberAddress addressToEdit = new MemberAddress();
            AddressViewModel viewModel = new AddressViewModel();

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit);

            Mock<DbSet<Country>> countryDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<Country>().AsQueryable());
            countryDbSetStub.SetupForInclude();

            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);
            dbStub.
                Setup(db => db.Countries).
                Returns(countryDbSetStub.Object);

            DbUpdateException provinceConstraintException = new DbUpdateException("See inner",
                SqlExceptionCreator.Create( // This message was copied verbatim from the actual exception being thrown
                    "The INSERT statement conflicted with the FOREIGN KEY constraint " +
                    "\"FK_dbo.MemberAddress_dbo.Province_ProvinceCode_CountryCode\". " +
                    "The conflict occurred in database \"prog3050\", table " +
                    "\"dbo.Province\".\r\nThe statement has been terminated.",
                    (int)SqlErrorNumbers.ConstraintViolation));

            dbStub.
                Setup(db => db.SaveChangesAsync()).
                ThrowsAsync(provinceConstraintException);

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            Assert.That(async () => await controller.EditAddress(addressId, viewModel), Throws.Nothing);
        }
        public async void EditAddress_ValidModel_ReformatsPostalCodeToMatchStoredPostalCodeRegex(string postalCode, string countryCode)
        {
            MemberAddress addressToEdit = new MemberAddress { Address = new Address() };
            AddressViewModel viewModel = new AddressViewModel
            {
                CountryCode = countryCode,
                PostalCode = postalCode,
            };

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<MemberAddress>> addressDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<MemberAddress>().AsQueryable());
            addressDbSetStub.
                Setup(adb => adb.FindAsync(It.IsAny<Guid>())).
                ReturnsAsync(addressToEdit);
            dbStub.
                Setup(db => db.MemberAddresses).
                Returns(addressDbSetStub.Object);

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object);

            await controller.EditAddress(addressId, viewModel);

            Assert.That(addressToEdit.Address.PostalCode, Is.StringMatching(ValidationRegex.STORED_POSTAL_CODE));
        }
        public async void ConfirmOrder_AddressIsId_GetsAddressFromDb()
        {
            WebOrderCheckoutDetails details = new WebOrderCheckoutDetails
            {
                MemberAddressId = addressId,
                MemberCreditCardId = creditCardId
            };

            MemberAddress address = new MemberAddress
            {
                Address = new Address
                {
                    City = "Waterloo",
                    PostalCode = "N2L 6R2",
                    StreetAddress = "445 Wes Graham Way"
                },
                CountryCode = "CA",
                Country = new Country { CountryCode = "CA", CountryName = "Canada", FederalTaxRate = 0.05m },
                ProvinceCode = "ON",
                Province = new Province { CountryCode = "CA", ProvinceCode = "ON", ProvincialTaxRate = 0.08m },
                MemberId = memberId,
                Id = addressId
            };

            List<MemberAddress> addresses = new List<MemberAddress> { address };

            Mock<IVeilDataAccess> dbMock = TestHelpers.GetVeilDataAccessFake();
            SetupVeilDataAccessWithCarts(dbMock, GetCartsListContainingCartWithNewAndUsed());
            SetupVeilDataAccessWithMember(dbMock, member);
            SetupVeilDataAccessWithUser(dbMock, memberUser);
            Mock<DbSet<MemberAddress>> addressDbMock = TestHelpers.GetFakeAsyncDbSet(addresses.AsQueryable());
            addressDbMock.SetupForInclude();

            dbMock.
                Setup(db => db.MemberAddresses).
                Returns(addressDbMock.Object).
                Verifiable();

            Mock<ControllerContext> contextStub = GetControllerContextWithSessionSetupToReturn(details);
            Mock<IShippingCostService> shippingServiceStub = new Mock<IShippingCostService>();

            CheckoutController controller = CreateCheckoutController(dbMock.Object, context: contextStub.Object, shippingCostService: shippingServiceStub.Object);

            var result = await controller.ConfirmOrder() as ViewResult;

            Assert.That(
                () => 
                    dbMock.Verify(db => db.MemberAddresses,
                    Times.Once),
                Throws.Nothing);

            Assert.That(result != null);
            Assert.That(result.Model, Is.InstanceOf<ConfirmOrderViewModel>());

            var model = (ConfirmOrderViewModel) result.Model;

            Assert.That(model.Address, Is.SameAs(address.Address));
            Assert.That(model.CountryName, Is.SameAs(address.Country.CountryName));
            Assert.That(model.ProvinceName, Is.SameAs(address.Province.Name));
        }
        public async void ConfirmOrder_ValidState_CalculatesTaxAmountProperly()
        {
            MemberAddress address = new MemberAddress
            {
                Address = new Address
                {
                    City = "Waterloo",
                    PostalCode = "N2L 6R2",
                    StreetAddress = "445 Wes Graham Way"
                },
                CountryCode = "CA",
                Country = new Country { CountryCode = "CA", CountryName = "Canada", FederalTaxRate = 0.05m },
                ProvinceCode = "ON",
                Province = new Province { CountryCode = "CA", ProvinceCode = "ON", ProvincialTaxRate = 0.08m },
                MemberId = memberId,
                Id = addressId
            };

            List<MemberAddress> addresses = new List<MemberAddress> { address };

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            SetupVeilDataAccessWithCarts(dbStub, GetCartsListContainingCartWithNewAndUsed());
            SetupVeilDataAccessWithUser(dbStub, memberUser);
            SetupVeilDataAccessWithAddresses(dbStub, addresses);
            SetupVeilDataAccessWithMember(dbStub, member);

            Mock<ControllerContext> contextStub = GetControllerContextWithSessionSetupToReturn(validSavedShippingBillingDetails);
            Mock<IShippingCostService> shippingServiceStub = new Mock<IShippingCostService>();

            CheckoutController controller = CreateCheckoutController(dbStub.Object, context: contextStub.Object, shippingCostService: shippingServiceStub.Object);

            var result = await controller.ConfirmOrder() as ViewResult;

            Assert.That(result != null);
            Assert.That(result.Model, Is.InstanceOf<ConfirmOrderViewModel>());

            var model = (ConfirmOrderViewModel)result.Model;

            Assert.That(model.TaxAmount, Is.EqualTo(model.ItemSubTotal * 0.13m));
        }
        public async Task<ActionResult> CreateAddress(AddressViewModel model)
        {
            model.UpdatePostalCodeModelError(ModelState);

            if (!ModelState.IsValid)
            {
                this.AddAlert(AlertType.Error, "Some address information was invalid.");

                await model.SetupAddressesAndCountries(db, GetUserId());

                return View("ManageAddresses", model);
            }

            model.FormatPostalCode();

            MemberAddress newAddress = new MemberAddress
            {
                MemberId = GetUserId(),
                Address = model.MapToNewAddress(),
                ProvinceCode = model.ProvinceCode,
                CountryCode = model.CountryCode
            };

            db.MemberAddresses.Add(newAddress);

            try
            {
                await db.SaveChangesAsync();
            }
            catch (DbUpdateException ex)
            {
                // Get the exception which states if a foreign key constraint was violated
                SqlException innermostException = ex.GetBaseException() as SqlException;

                bool errorWasProvinceForeignKeyConstraint = false;

                if (innermostException != null)
                {
                    string exMessage = innermostException.Message;

                    errorWasProvinceForeignKeyConstraint =
                        innermostException.Number == (int) SqlErrorNumbers.ConstraintViolation &&
                            exMessage.Contains(nameof(Province.ProvinceCode)) &&
                            exMessage.Contains(nameof(Province.CountryCode));
                }

                this.AddAlert(
                    AlertType.Error,
                    errorWasProvinceForeignKeyConstraint
                        ? "The Province/State you selected isn't in the Country you selected."
                        : "An unknown error occured while adding the address.");

                await model.SetupAddressesAndCountries(db, GetUserId());

                return View("ManageAddresses", model);
            }

            this.AddAlert(AlertType.Success, "Successfully add a new address.");
            return RedirectToAction("ManageAddresses");
        }