public ActionResult ThreeDSecure()
        {
            //Braintree has its own 3dSecure form
            if (AppLogic.ActivePaymentGatewayCleaned() == Gateway.ro_GWBRAINTREE)
            {
                var customer = HttpContext.GetCustomer();
                var context  = PersistedCheckoutContextProvider.LoadCheckoutContext(customer);
                var cart     = new ShoppingCart(customer.SkinID, customer, CartTypeEnum.ShoppingCart, 0, false);

                var braintreeModel = new BraintreeThreeDSecureViewModel(
                    nonce: context.Braintree.Nonce,
                    scriptUrl: AppConfigProvider.GetAppConfigValue("Braintree.ScriptUrl"),
                    token: context.Braintree.Token,
                    total: cart.Total(true).ToString());

                return(View(ViewNames.BraintreeThreeDSecureForm, braintreeModel));
            }
            //Sage Pay PI has its own 3dSecure form
            if (AppLogic.ActivePaymentGatewayCleaned() == Gateway.ro_GWSAGEPAYPI)
            {
                var customer = HttpContext.GetCustomer();
                var sagePayPiThreeDSecureViewModel = new SagePayPiThreeDSecureViewModel(
                    paReq: customer.ThisCustomerSession[AppLogic.SagePayPiPaReq],
                    termUrl: customer.ThisCustomerSession[AppLogic.SagePayPiTermUrl],
                    md: customer.ThisCustomerSession[AppLogic.SagePayPiMd],
                    acsUrl: customer.ThisCustomerSession[AppLogic.SagePayPiAcsUrl]
                    );

                return(View(ViewNames.SagePayPiThreeDSecureForm, sagePayPiThreeDSecureViewModel));
            }

            var threeDSecureModel = new ThreeDSecureFrameViewModel
            {
                FrameUrl = Url.Action(ActionNames.ThreeDSecureForm, ControllerNames.ThreeDSecure, null, this.Request.Url.Scheme)
            };

            return(View(threeDSecureModel));
        }
        public override string ProcessCard(int orderNumber, int customerID, Decimal orderTotal, bool useLiveTransactions, TransactionModeEnum transactionMode, Address useBillingAddress, string cardExtraCode, Address useShippingAddress, string cavv, string eci, string xid, out string avsResult, out string authorizationResult, out string authorizationCode, out string authorizationTransID, out string transactionCommandOut, out string transactionResponse)
        {
            var result   = AppLogic.ro_OK;
            var session  = new CustomerSession(customerID);
            var customer = new Customer(customerID);
            var shippingTwoLetterCountryCode = AppLogic.GetCountryTwoLetterISOCode(customer.PrimaryShippingAddress.Country);
            var billingTwoLetterCountryCode  = AppLogic.GetCountryTwoLetterISOCode(customer.PrimaryBillingAddress.Country);

            authorizationCode     = string.Empty;
            authorizationResult   = string.Empty;
            authorizationTransID  = string.Empty;
            avsResult             = string.Empty;
            transactionCommandOut = string.Empty;
            transactionResponse   = string.Empty;
            var threeDSecureEnabled = AppConfigProvider.GetAppConfigValue <bool>("SagePayPi.3dSecureEnabled");
            var isRecurringOrder    = TransactionType != null && TransactionType.EqualsIgnoreCase("repeat");

            if (isRecurringOrder)
            {
                //process recurring order charge and set the result
                if (TransactionId != null)
                {
                    var repeatJsonObject = new JObject(
                        new JProperty("transactionType", "Repeat"),
                        new JProperty("referenceTransactionId", TransactionId),
                        new JProperty("vendorTxCode", orderNumber.ToString()),
                        new JProperty("amount", GetSmallestCurrencyUnit(orderTotal, Localization.StoreCurrency())),
                        new JProperty("currency", Localization.StoreCurrency()),
                        new JProperty("description", $"{HttpContext.Current.Server.UrlEncode(AppConfigProvider.GetAppConfigValue("StoreName"))} Order {orderNumber}"),
                        new JProperty("shippingDetails",
                                      new JObject(
                                          new JProperty("recipientFirstName", customer.PrimaryShippingAddress.FirstName),
                                          new JProperty("recipientLastName", customer.PrimaryShippingAddress.LastName),
                                          new JProperty("shippingAddress1", customer.PrimaryShippingAddress.Address1),
                                          new JProperty("shippingAddress2", customer.PrimaryShippingAddress.Address2),
                                          new JProperty("shippingCity", customer.PrimaryShippingAddress.City),
                                          new JProperty("shippingPostalCode", shippingTwoLetterCountryCode.EqualsIgnoreCase("IE")
                                                                        ? string.Empty
                                                                        : customer.PrimaryShippingAddress.Zip),
                                          new JProperty("shippingCountry", AppLogic.GetCountryTwoLetterISOCode(customer.PrimaryShippingAddress.Country)),
                                          new JProperty("shippingState", shippingTwoLetterCountryCode.EqualsIgnoreCase("US")
                                                                        ? GetStateAbbreviationById(customer.PrimaryShippingAddress.StateID)
                                                                        : string.Empty)
                                          )
                                      )
                        );
                    var url = (useLiveTransactions
                                                ? $"{AppConfigProvider.GetAppConfigValue("SagePayPi.LiveUrl")}transactions"
                                                : $"{AppConfigProvider.GetAppConfigValue("SagePayPi.TestUrl")}transactions");

                    var apiResponse       = SagePayPiApiCall(repeatJsonObject.ToString(), url, "POST");
                    var formattedResponse = JObject.Parse(apiResponse);
                    var responseHasError  = ResponseHasError(formattedResponse, "status", "ok");

                    transactionCommandOut = $"URL: {url}, Request: {repeatJsonObject}";
                    transactionResponse   = formattedResponse.ToString();

                    if (responseHasError)
                    {
                        result = GetResponseError(formattedResponse, "statusDetail", customerID);

                        if (result.EqualsIgnoreCase(StringResourceProvider.GetString("sagepaypi.error.unknownresponseerror")))
                        {
                            result = GetResponseError(formattedResponse, "description", customerID);
                        }

                        if (result.EqualsIgnoreCase(StringResourceProvider.GetString("sagepaypi.error.unknownresponseerror")))
                        {
                            result = GetResponseError(formattedResponse, "errors", customerID);
                        }

                        return($"{StringResourceProvider.GetString("admin.sagepaypi.transaction.repeaterror")} {result}");
                    }
                    else
                    {
                        //Get the checkout context so we can use the shipping method the customer chose
                        authorizationTransID = formattedResponse["transactionId"].ToString() ?? string.Empty;
                        authorizationCode    = formattedResponse["bankAuthorisationCode"].ToString() ?? string.Empty;
                        authorizationResult  = formattedResponse["statusDetail"].ToString() ?? string.Empty;
                        avsResult            = string.Empty;

                        useBillingAddress.CardType   = formattedResponse["paymentMethod"]["card"]["cardType"].ToString();
                        useBillingAddress.CardNumber = formattedResponse["paymentMethod"]["card"]["lastFourDigits"].ToString();
                        useBillingAddress.UpdateDB();

                        //Update the transaction id on the original order. This needs freshened up because the Sage Pay gateway archives all
                        //transactions that are older than 2 years old.
                        if (RecurringOrderNumberOriginal > 0 && !string.IsNullOrEmpty(authorizationTransID))
                        {
                            UpdateOriginalTransactionID(RecurringOrderNumberOriginal, authorizationTransID);
                        }
                    }
                }
                else
                {
                    result = $"{StringResourceProvider.GetString("admin.sagepaypi.transaction.repeaterror")} {StringResourceProvider.GetString("admin.sagepaypi.transaction.repeatnotransactionid")}";
                }
            }
            else
            {
                //Make a transaction, if 3d secure is required it will be returned here
                if ((threeDSecureEnabled &&
                     session[AppLogic.SagePayPi3dSecureKey].EqualsIgnoreCase("false") &&
                     session[AppLogic.SagePayPiPaymentMethod].EqualsIgnoreCase("creditcard")) ||
                    (!threeDSecureEnabled))
                {
                    var jsonObject = new JObject(
                        new JProperty("transactionType", AppLogic.TransactionModeIsAuthOnly()
                                                                                                                        ? "Deferred"
                                                                                                                        : "Payment"),
                        new JProperty("paymentMethod",
                                      new JObject(
                                          new JProperty("card",
                                                        new JObject(
                                                            new JProperty("merchantSessionKey", session[AppLogic.SagePayPiMerchantSessionKey]),
                                                            new JProperty("cardIdentifier", session[AppLogic.SagePayPiCardIdentifier]),
                                                            new JProperty("save", true)
                                                            )
                                                        )
                                          )
                                      ),
                        new JProperty("vendorTxCode", orderNumber.ToString()),
                        new JProperty("amount", GetSmallestCurrencyUnit(orderTotal, Localization.StoreCurrency())),
                        new JProperty("currency", Localization.StoreCurrency()),
                        new JProperty("description", $"{HttpContext.Current.Server.UrlEncode(AppConfigProvider.GetAppConfigValue("StoreName"))} Order {orderNumber}"),
                        new JProperty("apply3DSecure", "UseMSPSetting"),
                        new JProperty("applyAvsCvcCheck", "UseMSPSetting"),
                        new JProperty("customerFirstName", customer.PrimaryBillingAddress.FirstName),
                        new JProperty("customerLastName", customer.PrimaryBillingAddress.LastName),
                        new JProperty("customerEmail", customer.EMail),
                        new JProperty("customerPhone", customer.Phone),
                        new JProperty("billingAddress",
                                      new JObject(
                                          new JProperty("address1", customer.PrimaryBillingAddress.Address1),
                                          new JProperty("address2", customer.PrimaryBillingAddress.Address2),
                                          new JProperty("city", customer.PrimaryBillingAddress.City),
                                          new JProperty("postalCode", billingTwoLetterCountryCode.EqualsIgnoreCase("IE")
                                                                ? string.Empty
                                                                : customer.PrimaryBillingAddress.Zip),
                                          new JProperty("country", AppLogic.GetCountryTwoLetterISOCode(customer.PrimaryBillingAddress.Country)),
                                          new JProperty("state", billingTwoLetterCountryCode.EqualsIgnoreCase("US")
                                                                ? GetStateAbbreviationById(customer.PrimaryBillingAddress.StateID)
                                                                : string.Empty)
                                          )
                                      ),
                        new JProperty("shippingDetails",
                                      new JObject(
                                          new JProperty("recipientFirstName", customer.PrimaryShippingAddress.FirstName),
                                          new JProperty("recipientLastName", customer.PrimaryShippingAddress.LastName),
                                          new JProperty("shippingAddress1", customer.PrimaryShippingAddress.Address1),
                                          new JProperty("shippingAddress2", customer.PrimaryShippingAddress.Address2),
                                          new JProperty("shippingCity", customer.PrimaryShippingAddress.City),
                                          new JProperty("shippingPostalCode", shippingTwoLetterCountryCode.EqualsIgnoreCase("IE")
                                                                ? string.Empty
                                                                : customer.PrimaryShippingAddress.Zip),
                                          new JProperty("shippingCountry", AppLogic.GetCountryTwoLetterISOCode(customer.PrimaryShippingAddress.Country)),
                                          new JProperty("shippingState", shippingTwoLetterCountryCode.EqualsIgnoreCase("US")
                                                                ? GetStateAbbreviationById(customer.PrimaryShippingAddress.StateID)
                                                                : string.Empty)
                                          )
                                      ),
                        new JProperty("entryMethod", "Ecommerce")
                        );

                    var url = (useLiveTransactions
                                                ? $"{AppConfigProvider.GetAppConfigValue("SagePayPi.LiveUrl")}transactions"
                                                : $"{AppConfigProvider.GetAppConfigValue("SagePayPi.TestUrl")}transactions");

                    var apiResponse       = SagePayPiApiCall(jsonObject.ToString(), url, "POST");
                    var formattedResponse = JObject.Parse(apiResponse);
                    var responseHasError  = ResponseHasError(formattedResponse, "status", "ok");

                    if (responseHasError)
                    {
                        transactionCommandOut = $"URL: {url}, Request: {jsonObject}";
                        transactionResponse   = formattedResponse.ToString();

                        if (AppConfigProvider.GetAppConfigValue <bool>("SagePayPI.CustomerFriendlyErrors"))
                        {
                            ClearPaymentMethod(customerID);
                            return($"{StringResourceProvider.GetString("sagepaypi.transaction.didnotprocess")} {StringResourceProvider.GetString("sagepaypi.error.reentercarddetails")}");
                        }

                        result = GetResponseError(formattedResponse, "statusDetail", customerID);

                        if (result.EqualsIgnoreCase(StringResourceProvider.GetString("sagepaypi.error.unknownresponseerror")))
                        {
                            result = GetResponseError(formattedResponse, "description", customerID);
                        }

                        if (result.EqualsIgnoreCase(StringResourceProvider.GetString("sagepaypi.error.unknownresponseerror")))
                        {
                            result = GetResponseError(formattedResponse, "errors", customerID);
                        }

                        ClearPaymentMethod(customerID);
                        return($"{StringResourceProvider.GetString("sagepaypi.transaction.paymenterror")} {result.TrimEnd('.')}. {StringResourceProvider.GetString("sagepaypi.error.reentercarddetails")}");
                    }
                    else
                    {
                        session[AppLogic.SagePayPiMd] = formattedResponse["transactionId"].ToString();

                        //Implement 3-d secure logic if it is required per the transaction response
                        if (threeDSecureEnabled &&
                            session[AppLogic.SagePayPi3dSecureKey].EqualsIgnoreCase("false") &&
                            session[AppLogic.SagePayPiPaymentMethod].EqualsIgnoreCase("creditcard") &&
                            formattedResponse["status"].ToString().EqualsIgnoreCase("3dauth"))                        //Do a 3DSecure redirect
                        {
                            session[AppLogic.SagePayPiPaReq]   = formattedResponse["paReq"].ToString();
                            session[AppLogic.SagePayPiTermUrl] = string.Format("{0}{1}",
                                                                               HttpContext
                                                                               .Current
                                                                               .Request
                                                                               .Url
                                                                               .AbsoluteUri
                                                                               .Replace(
                                                                                   HttpContext
                                                                                   .Current
                                                                                   .Request
                                                                                   .Url
                                                                                   .LocalPath,
                                                                                   string.Empty),
                                                                               AppConfigProvider.GetAppConfigValue("SagePayPi.3DSecureTermUrl"));
                            session[AppLogic.SagePayPiAcsUrl] = formattedResponse["acsUrl"].ToString();
                            var sagePayPiThreeDSecureViewModel = new SagePayPiThreeDSecureViewModel(
                                paReq: formattedResponse["paReq"].ToString(),
                                termUrl: string.Format("{0}{1}",
                                                       HttpContext
                                                       .Current
                                                       .Request
                                                       .Url
                                                       .AbsoluteUri
                                                       .Replace(
                                                           HttpContext
                                                           .Current
                                                           .Request
                                                           .Url
                                                           .LocalPath,
                                                           string.Empty),
                                                       AppConfigProvider.GetAppConfigValue("SagePayPi.3DSecureTermUrl")),
                                md: formattedResponse["transactionId"].ToString(),
                                acsUrl: formattedResponse["acsUrl"].ToString()
                                );
                            session["3DSecure.OrderNumber"] = orderNumber.ToString();
                            result = AppLogic.ro_3DSecure;
                            return(result);
                        }
                    }
                }

                //Do a final retrieval of the completed transaction and record some of the results
                var emptyObject    = new JObject();
                var transactionUrl = (useLiveTransactions
                                        ? $"{AppConfigProvider.GetAppConfigValue("SagePayPi.LiveUrl")}transactions/{session[AppLogic.SagePayPiMd]}"
                                        : $"{AppConfigProvider.GetAppConfigValue("SagePayPi.TestUrl")}transactions/{session[AppLogic.SagePayPiMd]}");

                var apiTransactionResponse       = SagePayPiApiCall(emptyObject.ToString(), transactionUrl, "GET");
                var formattedTransactionResponse = JObject.Parse(apiTransactionResponse);
                var transactionResponseError     = ResponseHasError(formattedTransactionResponse, "status", "ok");

                transactionCommandOut = $"GET Method - URL: {transactionUrl}";
                transactionResponse   = formattedTransactionResponse.ToString();

                if (transactionResponseError)
                {
                    if (AppConfigProvider.GetAppConfigValue <bool>("SagePayPI.CustomerFriendlyErrors"))
                    {
                        result = $"{StringResourceProvider.GetString("sagepaypi.transaction.didnotprocess")} {StringResourceProvider.GetString("sagepaypi.error.reentercarddetails")}";
                    }
                    else
                    {
                        result = string.Format(
                            "{0} 3-D Secure status: {1}.",
                            GetResponseError(formattedTransactionResponse, "statusDetail", customerID),
                            GetThreeDSecureStatus(formattedTransactionResponse["3DSecure"]["status"].ToString()));
                    }
                }
                else
                {
                    var threeDSecureStatus = formattedTransactionResponse["3DSecure"]["status"].ToString();

                    if (formattedTransactionResponse["status"].ToString().EqualsIgnoreCase("ok"))
                    {
                        authorizationTransID = formattedTransactionResponse["transactionId"].ToString() ?? string.Empty;
                        authorizationCode    = formattedTransactionResponse["bankAuthorisationCode"].ToString() ?? string.Empty;
                        authorizationResult  = formattedTransactionResponse["statusDetail"].ToString() ?? string.Empty;
                        avsResult            = string.Empty;

                        useBillingAddress.CardType   = formattedTransactionResponse["paymentMethod"]["card"]["cardType"].ToString();
                        useBillingAddress.CardNumber = formattedTransactionResponse["paymentMethod"]["card"]["lastFourDigits"].ToString();
                        useBillingAddress.UpdateDB();
                    }
                    else
                    {
                        //if the transaction did not retrieve properly, put an error from sage pay into result
                        result = formattedTransactionResponse["statusDetail"].ToString();
                    }

                    if (threeDSecureEnabled && threeDSecureStatus.ToString().EqualsIgnoreCase("Error"))
                    {
                        //We need to stop processing the order if 3d secure is required but had an error
                        result = $"{StringResourceProvider.GetString("sagepaypi.threedsecure.error")} {StringResourceProvider.GetString("sagepaypi.error.reentercarddetails")}";

                        ClearPaymentMethod(customerID);
                    }
                }
            }
            return(result);
        }