public ActionResult BillingInformation(BillingInformationViewModel model)
        {
            CheckoutViewModel checkoutModel;

            if (CacheHelpers.GetCheckoutInstanceFromCache(model.CheckoutInstance, this.ControllerContext, out checkoutModel) != CacheHelpers.CheckoutCacheStatus.Success)
            {
                return(RedirectToAction("Index", "ShoppingCart"));
            }

            if (NextButtonWasClicked())
            {
                if (ModelState.IsValid)
                {
                    Address billingAddress;

                    if (model.BillingSameAsShipping)
                    {
                        billingAddress = checkoutModel.ShippingAddress;
                    }
                    else
                    {
                        billingAddress = new Address()
                        {
                            AddressLine1 = model.AddressLine1, AddressLine2 = model.AddressLine2, City = model.City, State = model.State, PostalCode = model.PostalCode
                        }
                    };

                    checkoutModel.BillingAddress = billingAddress;

                    checkoutModel.CreditCardPayment = model.CreditCardPayment;

                    //checkoutModel.GiftCardPayments = model.GiftCardPayments;

                    var nextModel = checkoutModel.GetReviewViewModel();

                    return(View("Review", nextModel));
                }
                else
                {
                    //Resupply unbound information the model needs to redisplay
                    model = checkoutModel.GetBillingViewModel();

                    //UNDONE
                    //Clear any modelstate entries for credit card to avoid posting them back
                    //ModelState.ToList().ForEach(kvp =>
                    //    {
                    //        if (kvp.Key.Contains("CreditCard"))
                    //        {
                    //            var emptyVal = new ValueProviderResult(String.Empty, String.Empty, CultureInfo.CurrentCulture);
                    //            ModelState.SetModelValue(kvp.Key, emptyVal);
                    //        }
                    //    });

                    return(View(model));
                }
            }
            else if (PreviousButtonWasClicked())
            {
                var previousModel = checkoutModel.GetShippingViewModel(_userService
                                                                       .GetUserWithAddresses(IdentityHelpers.GetUserId(User.Identity)).Addresses);

                this.ModelState.Clear();

                return(View("ShippingInformation", previousModel));
            }

            throw new HttpException(500, "Invalid destination.");
        }
        public ActionResult Review(ReviewViewModel model)
        {
            CheckoutViewModel checkoutModel;

            if (CacheHelpers.GetCheckoutInstanceFromCache(model.CheckoutInstance, this.ControllerContext, out checkoutModel) != CacheHelpers.CheckoutCacheStatus.Success)
            {
                return(RedirectToAction("Index", "ShoppingCart"));
            }

            //Check to see where the user was trying to go
            if (ConfirmButtonWasClicked())
            {
                //Clear the checkoutmodel from cache to prevent reprocessing
                CacheHelpers.RemoveCheckoutInstanceFromCache(this.ControllerContext);

                Order toCreate = checkoutModel.GetOrder(IdentityHelpers.GetUserId(this.User.Identity));

                Boolean orderCreated = false;
                Int32   attempts     = 3;

                Order newOrder = null;

                using (TransactionScope orderProcessingScope = new TransactionScope())
                {
                    do
                    {
                        try
                        {
                            using (TransactionScope createOrderScope = new TransactionScope())
                            {
                                _shoppingCartService.EmptyCart(ShoppingCartHelpers.GetShoppingCartID(this.ControllerContext));

                                if (!_productService.DecrementInventory(toCreate.OrderDetails))
                                {
                                    return(RedirectToAction("StockUnavailable", "Checkout"));
                                }

                                newOrder = _orderService.CreateOrder(toCreate);

                                _uow.Save();

                                orderCreated = true;

                                createOrderScope.Complete();
                            }
                        }
                        catch (DbUpdateConcurrencyException ex)
                        {
                            //Reload any entry that changed with new values before we retry
                            foreach (var item in ex.Entries)
                            {
                                item.Reload();
                            }

                            attempts--;
                        }
                    } while (!orderCreated && attempts > 0);

                    if (orderCreated)
                    {
                        using (TransactionScope scope = new TransactionScope())
                        {
                            var payment = new CreditCardPayment()
                            {
                                Amount           = newOrder.SubTotal + newOrder.Tax + newOrder.ShippingCost,
                                CreditCardNumber = checkoutModel.CreditCardPayment.CreditCardNumber,
                                CVV        = checkoutModel.CreditCardPayment.CVV,
                                Expiration = new DateTime(checkoutModel.CreditCardPayment.ExpirationYear, checkoutModel.CreditCardPayment.ExpirationMonth, DateTime.DaysInMonth(checkoutModel.CreditCardPayment.ExpirationYear, checkoutModel.CreditCardPayment.ExpirationMonth), 0, 0, 0)
                            };

                            //Authorize the payment
                            var paymentAuthResult = _creditCardService
                                                    .Authorize(payment, "Payment for order " + newOrder.OrderID, newOrder.BillingAddress);

                            //If successful authorization
                            if (paymentAuthResult.Success)
                            {
                                _transactionService.Create(paymentAuthResult.Transaction);

                                newOrder.OrderStatus = OrderStatus.Processing;

                                _orderService.Update(newOrder);

                                _uow.Save();

                                _emailService.SendMessage(EmailHelpers.GetOrderReceivedEmail(this, newOrder.Email, newOrder.OrderID));

                                scope.Complete();

                                orderProcessingScope.Complete();

                                TempData.Add("OrderID", newOrder.OrderID);

                                return(RedirectToAction("Confirmation"));
                            }
                            else
                            {
                                paymentAuthResult.Errors.ForEach(e => ModelState.AddModelError("", e));
                            }
                        }
                    }
                    else
                    {
                        ModelState.AddModelError("", "We're sorry, there was a problem creating your order. " +
                                                 "Please try again and if the problem persists, please try again later.");
                    }
                }

                CacheHelpers.InsertCheckoutInstanceIntoCache(checkoutModel, this.ControllerContext);

                var reModel = checkoutModel.GetReviewViewModel();

                return(View("Review", reModel));
            }
            else if (PreviousButtonWasClicked())
            {
                var previousModel = checkoutModel.GetBillingViewModel();

                ModelState.Clear();

                return(View("BillingInformation", previousModel));
            }

            throw new HttpException(500, "Invalid destination.");
        }
        public ActionResult ShippingInformation(ShippingInformationViewModel model)
        {
            CheckoutViewModel checkoutModel;

            if (CacheHelpers.GetCheckoutInstanceFromCache(model.CheckoutInstance, this.ControllerContext, out checkoutModel) != CacheHelpers.CheckoutCacheStatus.Success)
            {
                return(RedirectToAction("Index", "ShoppingCart"));
            }

            if (ModelState.IsValid)
            {
                Address shippingAddress;

                //If the user selected an address
                if (model.SelectedShippingAddressId > 0)
                {
                    var address = _addressService.Get(model.SelectedShippingAddressId);

                    //Verify it exists
                    if (address != null)
                    {
                        //Verify it belongs to this user
                        if (address.UserID == IdentityHelpers.GetUserId(this.User.Identity))
                        {
                            shippingAddress = address;
                        }
                        else
                        {
                            throw new InvalidOperationException("Address does not belong to this user.");
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("Expected address, but not found.");
                    }
                }
                else
                {
                    shippingAddress = new Address {
                        AddressLine1 = model.AddressLine1, AddressLine2 = model.AddressLine2, City = model.City, PostalCode = model.PostalCode, State = model.State
                    }
                };

                checkoutModel.Email = model.Email;

                checkoutModel.PhoneNumber = model.PhoneNumber;

                checkoutModel.ShippingAddress = shippingAddress;

                checkoutModel.ShippingCost = _orderService.CalculateShipping(checkoutModel.CartItems);

                checkoutModel.Tax = _orderService.CalculateTax(checkoutModel.CartItems);

                var nextModel = checkoutModel.GetBillingViewModel();

                #region Test Information
#if DEBUG
                nextModel.CreditCardPayment = new CreditCardPaymentViewModel()
                {
                    //Authorize.Net Test Visa
                    CreditCardNumber = "4007000000027",
                    CVV             = "123",
                    ExpirationMonth = 1,
                    ExpirationYear  = 2018
                };

                nextModel.BillingSameAsShipping = true;
#endif
                #endregion

                ModelState.Clear();

                return(View("BillingInformation", nextModel));
            }
            else
            {
                //Resupply unbound information the model needs to redisplay
                checkoutModel.GetShippingViewModel(_userService
                                                   .GetUserWithAddresses(IdentityHelpers.GetUserId(User.Identity)).Addresses);

                return(View(model));
            }
        }