public async Task <IActionResult> ThreeDSecure(string source, bool livemode, string client_secret)
        {
            var order = _context.Orders.Where(x => x.StripeSource == source).Include(x => x.DeliveryType).SingleOrDefault();

            var userId    = _userManager.GetUserId(User);
            var viewModel = new CheckoutViewModel()
            {
                Basket        = OrderHelper.GetOrder(order.Id, _context),
                DeliveryTypes = _context.DeliveryTypes.
                                Where(x => x.Id > 0).
                                Include(x => x.DeliveryCompany).
                                ToList(),
                Contacts = _context.CustomerContacts.
                           Where(x => x.UserId == userId).
                           ToList()
            };

            var result = StripeHelper.ChargeSource(source, livemode, client_secret, order.Id, "OrderId");

            order.SellerMessage = result.SellerMessage;
            order.PaymentId     = result.Id;
            order.PaymentStatus = result.NetworkStatus;

            try
            {
                _context.Update(order);
                _context.SaveChanges();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

            if (result.NetworkStatus == MasterStrings.StripeDeclined)
            {
                var messages = new DeclineMessageViewModel();
                messages = StripeHelper.DeclineMessage(result.Reason);

                var statusMessage = messages.StatusMessage;
                order.PaymentMessage = messages.PaymentMessage;

                return(ControllerHelper.RedirectToLocal(this, "/Checkout/Index?id=" + order.Id + "&&failureMessage=" + statusMessage));
            }

            if (result.NetworkStatus == MasterStrings.StripeApproved ||
                result.NetworkStatus == MasterStrings.StripeNotSent && result.Type == MasterStrings.StripeResultPending)
            {
                await PlaceOrder(order.Id);

                return(ControllerHelper.RedirectToLocal(this, "/Checkout/OrderPlaced?id=" + order.Id));
            }

            if (result.NetworkStatus == MasterStrings.StripeReversed ||
                (result.NetworkStatus == MasterStrings.StripeNotSent && result.Type != MasterStrings.StripeResultPending))
            {
                var statusMessage = "The payment has been declined.<br/>Please contact your card issuer for more information.";
                order.PaymentMessage = "Status reason: " + result.Reason;

                return(ControllerHelper.RedirectToLocal(this, "/Checkout/Index?id=" + order.Id + "&&failureMessage" + statusMessage));
            }

            return(View());
        }
        public async Task <IActionResult> Index(CheckoutViewModel model)
        {
            bool isValid = true;
            var  user    = await _userManager.GetUserAsync(User);

            // stripe token?
            if (string.IsNullOrWhiteSpace(model.StripeToken) &&
                string.IsNullOrWhiteSpace(model.PayPal))
            {
                isValid              = false;
                model.StatusMessage += "Payment details required.";
            }

            // DeliveryType?
            if (model.Basket.DeliveryType == null)
            {
                isValid              = false;
                model.StatusMessage += "Delivery method required.";
            }

            // address
            if (string.IsNullOrWhiteSpace(model.Basket.CustomerContact.AddressLine1) ||
                string.IsNullOrWhiteSpace(model.Basket.CustomerContact.PostTown) ||
                string.IsNullOrWhiteSpace(model.Basket.CustomerContact.Postcode))
            {
                isValid              = false;
                model.StatusMessage += "Delivery address required. Please ensure Address Line 1, Post Town and Post Code are completed.";
            }

            if (isValid)
            {
                // update contact address and delivery type
                var inDb = OrderHelper.GetOrder(model.Basket.Id, _context);

                var deliveryType = _context.DeliveryTypes.
                                   Where(x => x.Id == model.Basket.DeliveryType.Id).
                                   SingleOrDefault();

                inDb.DeliveryType = deliveryType;

                var country = model.Basket.CustomerContact.Country;

                if (country == "Please Select")
                {
                    country = "";
                }

                var contact = new CustomerContact()
                {
                    BuildingNumber = model.Basket.CustomerContact.BuildingNumber,
                    AddressLine1   = model.Basket.CustomerContact.AddressLine1,
                    AddressLine2   = model.Basket.CustomerContact.AddressLine2,
                    PostTown       = model.Basket.CustomerContact.PostTown,
                    County         = model.Basket.CustomerContact.County,
                    Postcode       = model.Basket.CustomerContact.Postcode,
                    Country        = country,
                    MobilePhone    = model.Basket.CustomerContact.MobilePhone,
                    WorkPhone      = model.Basket.CustomerContact.WorkPhone,
                    OtherPhone     = model.Basket.CustomerContact.OtherPhone,
                    UserId         = user.Id
                };

                decimal orderTotalPrice = 0;

                foreach (var item in inDb.OrderItems)
                {
                    var product = _context.Products.
                                  Where(x => x.Id == item.ProductId).
                                  SingleOrDefault();

                    orderTotalPrice += product.Price;
                }

                inDb.CustomerContact        = contact;
                inDb.OrderTotalPostagePrice = inDb.DeliveryType.Price;
                inDb.OrderSubTotalPrice     = orderTotalPrice;
                inDb.OrderTotalPrice        = inDb.OrderSubTotalPrice + inDb.DeliveryType.Price;

                // create charge
                if (!string.IsNullOrWhiteSpace(model.StripeToken))
                {
                    // create charge
                    int amount = Convert.ToInt32(inDb.OrderTotalPrice * 100);

                    if (model.ThreeDSecure == MasterStrings.ThreeDSecureRequired || model.ThreeDSecure == MasterStrings.ThreeDSecureRecommended)
                    {
                        var source = StripeHelper.CreateSource(model.StripeToken, amount, "http://localhost:5000/Checkout/ThreeDSecure");

                        inDb.StripeSource = source.Id;

                        _context.Update(inDb);
                        _context.SaveChanges();

                        return(Redirect(source.Redirect.Url));
                    }

                    var result = StripeHelper.CreateCharge(model.StripeToken, model.Basket.Id, "OrderId", amount);

                    inDb.SellerMessage = result.SellerMessage;
                    inDb.PaymentId     = result.Id;
                    inDb.PaymentStatus = result.NetworkStatus;
                    inDb.StripeSource  = model.StripeToken;

                    _context.Update(inDb);
                    _context.SaveChanges();


                    if (result.NetworkStatus == MasterStrings.StripeDeclined)
                    {
                        var messages = new DeclineMessageViewModel();
                        messages = StripeHelper.DeclineMessage(result.Reason);

                        model.FailureMessage       += messages.StatusMessage;
                        model.Basket.PaymentMessage = messages.PaymentMessage;

                        return(ControllerHelper.RedirectToLocal(this, "/Checkout?id=" + model.Basket.Id + "&&failureMessage=" + model.FailureMessage));
                    }

                    if (result.NetworkStatus == MasterStrings.StripeApproved)
                    {
                        await PlaceOrder(model.Basket.Id);

                        return(ControllerHelper.RedirectToLocal(this, "/Checkout/OrderPlaced?id=" + model.Basket.Id));
                    }

                    return(ControllerHelper.RedirectToLocal(this, "/Checkout?id=" + model.Basket.Id + "&&failureMessage=Something went wrong with your payment, please try again."));
                }
                if (!string.IsNullOrWhiteSpace(model.PayPal))
                {
                    // process paypal

                    // create charge
                    var createdPayment = PayPalHelper.CreatePayment(model.Basket.Id, inDb.OrderItems, inDb.OrderTotalPostagePrice, _context);
                    var redirect       = "";

                    inDb.PayPalPaymentId = createdPayment.id;
                    inDb.PaymentId       = createdPayment.transactions[0].invoice_number;

                    _context.Update(inDb);
                    _context.SaveChanges();

                    var links = createdPayment.links.GetEnumerator();
                    while (links.MoveNext())
                    {
                        var link = links.Current;
                        if (link.rel.ToLower().Trim().Equals("approval_url"))
                        {
                            // Redirect the customer to link.href
                            redirect = link.href;
                        }
                    }

                    if (!string.IsNullOrWhiteSpace(redirect))
                    {
                        return(Redirect(redirect));
                    }
                }
            }

            return(ControllerHelper.RedirectToLocal(this, string.Format("/Checkout?id={0}&&failureMessage={1}", model.Basket.Id, model.StatusMessage)));
        }