private BillingInformationViewModel prepareBillingInformationViewModel(CheckoutViewModel model)
        {
            if (model == null)
            {
                throw new ArgumentNullException("model");
            }

            BillingInformationViewModel result = new BillingInformationViewModel();

            //If the billing address already exists this call is the result of a previous navigation request.
            if (model.BillingAddress != null)
            {
                //result.CreditCard = model.CreditCard;
                result.CreditCard = new CreditCardViewModel();

                result.BillingSameAsShipping = model.ShippingAddress == model.BillingAddress;

                if (!result.BillingSameAsShipping)
                {
                    result.BillingAddress = model.BillingAddress;
                }
            }

#if DEBUG
            if (model.BillingAddress == null)
            {
                result.BillingAddress = new AddressViewModel()
                {
                    AddressLine1 = "123 Address st.",
                    AddressLine2 = "apt 2",
                    City         = "SomeCity",
                    State        = StateCode.NY,
                    PostalCode   = "12345"
                };

                result.CreditCard = new CreditCardViewModel()
                {
                    CardNumber         = "0000000000000000",
                    ExpirationMonth    = (Month)DateTime.Now.Month,
                    ExpirationYear     = DateTime.Now.AddYears(0),
                    VerificationNumber = "123"
                };
            }
#endif

            result.InstanceKey = model.InstanceKey;

            result.OrderLines = model.OrderLines;

            result.SalesTax = model.SalesTax;

            result.ShippingAddress = model.ShippingAddress;

            result.ShippingCost = model.ShippingCost;

            return(result);
        }
        public BillingInformationViewModel GetBillingViewModel()
        {
            if (this.ShippingAddress == null)
            {
                throw new InvalidOperationException("Shipping address must exist to create billing view model.");
            }

            var result = new BillingInformationViewModel();

            //If the billing address exists, we are going forward from a previous or coming back from a next.
            if (this.BillingAddress != null)
            {
                if (BillingAddress.AddressID > 0)
                {
                    result.BillingSameAsShipping = this.ShippingAddress.AddressID == this.BillingAddress.AddressID;
                }
                else
                {
                    Boolean addressesAreSame = this.ShippingAddress.AddressLine1 == this.BillingAddress.AddressLine1 &&
                                               this.ShippingAddress.AddressLine2 == this.BillingAddress.AddressLine2 &&
                                               this.ShippingAddress.City == this.BillingAddress.City &&
                                               this.ShippingAddress.State == this.BillingAddress.State &&
                                               this.ShippingAddress.PostalCode == this.BillingAddress.PostalCode;

                    if (!addressesAreSame)
                    {
                        result.AddressLine1 = this.BillingAddress.AddressLine1;
                        result.AddressLine2 = this.BillingAddress.AddressLine2;
                        result.City         = this.BillingAddress.City;
                        result.State        = this.BillingAddress.State;
                        result.PostalCode   = this.BillingAddress.PostalCode;
                    }

                    result.BillingSameAsShipping = addressesAreSame;
                }
            }

            result.CartItems = this.CartItems;

            result.CheckoutInstance = this.CheckoutInstance;

            //UNDONE
            //result.CreditCardPayment = this.CreditCardPayment;

            //UNDONE
            //result.GiftCardPayments = this.GiftCardPayments;

            result.ShippingAddress = this.ShippingAddress;

            result.ShippingCost = this.ShippingCost;

            result.Tax = this.Tax;

            return(result);
        }
        public ActionResult BillingInformation(BillingInformationViewModel model)
        {
            CacheItem cachedCheckoutInstance =
                MemoryCache.Default.GetCacheItem(model.InstanceKey);

            if (cachedCheckoutInstance != null)
            {
                CheckoutViewModel checkoutInstance = cachedCheckoutInstance.Value as CheckoutViewModel;

                if (checkoutInstance.InstanceKey != model.InstanceKey)
                {
                    throw new InvalidOperationException("Checkout key mismatch.");
                }

                if (nextButtonWasClicked())
                {
                    if (ModelState.IsValid)
                    {
                        applyBillinginformationToCheckoutInstance(checkoutInstance, model);

                        ReviewViewModel nextModel = prepareReviewViewModel(checkoutInstance);

                        return(View("Review", nextModel));
                    }


                    //Something failed

                    //Repopulate non-bound items
                    model.OrderLines      = checkoutInstance.OrderLines;
                    model.SalesTax        = checkoutInstance.SalesTax;
                    model.ShippingAddress = checkoutInstance.ShippingAddress;
                    model.ShippingCost    = checkoutInstance.ShippingCost;

                    return(View(model));
                }
                else if (previousButtonWasClicked())
                {
                    ModelState.Clear();

                    ShippingInformationViewModel previousModel = prepareShippingInformationViewModel(checkoutInstance);

                    return(View("ShippingInformation", previousModel));
                }
                else
                {
                    throw new InvalidOperationException("Unexpected navigation.");
                }
            }

            return(Content("CheckoutExpired"));
        }
        public ActionResult ShippingInformation(ShippingInformationViewModel model)
        {
            CacheItem cachedCheckoutInstance =
                MemoryCache.Default.GetCacheItem(model.InstanceKey);

            if (cachedCheckoutInstance != null)
            {
                CheckoutViewModel checkoutInstance = cachedCheckoutInstance.Value as CheckoutViewModel;

                if (checkoutInstance.InstanceKey != model.InstanceKey)
                {
                    throw new InvalidOperationException("Checkout key mismatch.");
                }

                if (nextButtonWasClicked())
                {
                    if (ModelState.IsValid)
                    {
                        applyShippingInformationToCheckoutInstance(checkoutInstance, model);

                        BillingInformationViewModel nextModel = prepareBillingInformationViewModel(checkoutInstance);

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

                    //Something failed

                    //Repopulate non bound items
                    model.OrderLines = checkoutInstance.OrderLines;
                    model.SalesTax   = checkoutInstance.SalesTax;

                    return(View(model));
                }

                throw new InvalidOperationException("Unexpected navigation.");
            }

            return(Content("CheckoutExpired"));
        }
        private void applyBillinginformationToCheckoutInstance(CheckoutViewModel checkoutInstance, BillingInformationViewModel model)
        {
            if (checkoutInstance == null)
            {
                throw new ArgumentNullException("checkoutInstance");
            }

            if (model == null)
            {
                throw new ArgumentNullException("model");
            }

            if (checkoutInstance.InstanceKey != model.InstanceKey)
            {
                throw new InvalidOperationException("Checkout key mismatch.");
            }

            if (model.BillingSameAsShipping)
            {
                checkoutInstance.BillingAddress = checkoutInstance.ShippingAddress;
            }
            else
            {
                if (checkoutInstance.BillingAddress == null)
                {
                    checkoutInstance.BillingAddress = new AddressViewModel();
                }

                checkoutInstance.BillingAddress.AddressLine1 = model.BillingAddress.AddressLine1.Trim();
                checkoutInstance.BillingAddress.AddressLine2 = model.BillingAddress.AddressLine2.Trim();
                checkoutInstance.BillingAddress.City         = model.BillingAddress.City.Trim();
                checkoutInstance.BillingAddress.State        = model.BillingAddress.State;
                checkoutInstance.BillingAddress.PostalCode   = model.BillingAddress.PostalCode.Trim();
            }

            if (checkoutInstance.CreditCard == null)
            {
                checkoutInstance.CreditCard = new CreditCardViewModel();
            }

            checkoutInstance.CreditCard.CardNumber         = model.CreditCard.CardNumber.Trim();
            checkoutInstance.CreditCard.ExpirationMonth    = model.CreditCard.ExpirationMonth;
            checkoutInstance.CreditCard.ExpirationYear     = model.CreditCard.ExpirationYear;
            checkoutInstance.CreditCard.VerificationNumber = model.CreditCard.VerificationNumber.Trim();
        }
        public async Task <ActionResult> Review(ReviewViewModel model)
        {
            CacheItem cachedCheckoutInstance =
                MemoryCache.Default.GetCacheItem(model.InstanceKey);

            if (cachedCheckoutInstance != null)
            {
                CheckoutViewModel checkoutInstance = cachedCheckoutInstance.Value as CheckoutViewModel;

                if (checkoutInstance.InstanceKey != model.InstanceKey)
                {
                    throw new InvalidOperationException("Checkout key mismatch.");
                }

                if (confirmButtonWasClicked())
                {
                    if (ModelState.IsValid)
                    {
                        //To prevent double processing of this order remove it from the cache
                        MemoryCache.Default.Remove(checkoutInstance.InstanceKey);


                        //TODO Cleanup + transaction processing with authorize.net

                        //_apiLoginID = "5hVHQz84B";
                        //_transactionKey = "653Dh9rH3W88juYU";

                        using (TransactionScope scope = new TransactionScope())
                        {
                            ServiceOperationResult <Order> result = await createOrderAsync(checkoutInstance);

                            if (result.Succeeded)
                            {
                                User currentUser = await _userService.GetAsync(Utility.Helpers.IdentityHelpers.GetUserId(this.User.Identity));

                                await _userService.SendEmailAsync(currentUser, EmailHelpers.UserEmails.OrderReceived(result.Data.OrderId));

                                try
                                {
                                    _uow.Commit();

                                    scope.Complete();

                                    return(RedirectToAction("OrderSuccess"));
                                }
                                catch (Exception ex)
                                {
                                    ModelState.AddModelError("", "There was a problem processing your order, if the problem persists, please try again later.");

                                    //TODO Logger elmah/notifications
                                }
                            }
                        }
                    }

                    //If we got this far something failed, reprepare the viewmodel and cache the checkout instance
                    CacheItem item = new CacheItem(checkoutInstance.InstanceKey, checkoutInstance);

                    MemoryCache.Default.Add(item, CheckoutSettings.CheckoutInstanceCachePolicy);

                    ReviewViewModel repreparedModel = prepareReviewViewModel(checkoutInstance);

                    return(View(repreparedModel));
                }
                else if (previousButtonWasClicked())
                {
                    ModelState.Clear();

                    BillingInformationViewModel previousModel = prepareBillingInformationViewModel(checkoutInstance);

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

            return(Content("CheckoutExpired"));
        }
        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.");
        }