VPSSignature Not Matching

5 лет назад
Hi,

I have an issues with Sage Pay they have upgraded there payment gateway from 2.x to 3.x and I am in the middle of moding the sage pay plugin for later version of the VPS Protocal but i am getting an issue with the MD5 checksum, the MD5 generated by Sagepay dose not Match the MD5 that the code generates.

Here is the code I have moded but not sure why I am getting the MD5 mismatch.  

//Updated:
//02 - XX / 05/2014
//Moded so that sage pay would behave more like the PayPal plug-in, and take payment at the end of the order process.
//As there was a problem with customers not processing complete.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Web.Mvc;
using Microsoft.VisualBasic;
using Nop.Core;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Payments;
using Nop.Plugin.Payments.SagePayServer.Domain;
using Nop.Plugin.Payments.SagePayServer.Models;
using Nop.Plugin.Payments.SagePayServer.Services;
using Nop.Services.Configuration;
using Nop.Services.Directory;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Web.Framework;
using Nop.Web.Framework.Controllers;
using Nop.Core.Domain.Orders;
using Nop.Services.Common;
using System.Web;

namespace Nop.Plugin.Payments.SagePayServer.Controllers
{
    public class PaymentSagePayServerController : BaseNopPaymentController
    {
        private readonly IPaymentService _paymentService;
        private readonly ISettingService _settingService;
        private readonly SagePayServerPaymentSettings _sagePayServerPaymentSettings;
        private readonly IOrderService _orderService;
        private readonly IOrderProcessingService _orderProcessingService;
        private readonly ILogger _logger;
        private readonly PaymentSettings _paymentSettings;
        private readonly ILocalizationService _localizationService;

        private readonly IWorkContext _workContext;
        private readonly ISagePayServerTransactionService _sagePayServerTransactionService;
        private readonly IOrderTotalCalculationService _orderTotalCalculationService;
        private readonly ICurrencyService _currencyService;
        private readonly CurrencySettings _currencySettings;

        private readonly IMobileDeviceHelper _mobileDeviceHelper;
        private readonly OrderSettings _orderSettings;

        private readonly HttpContextBase _httpContext;

        public PaymentSagePayServerController(ISettingService settingService,
            IPaymentService paymentService, IOrderService orderService,
            IOrderProcessingService orderProcessingService,
            ILogger logger, SagePayServerPaymentSettings sagePayServerPaymentSettings,
            PaymentSettings paymentSettings, ILocalizationService localizationService,
            IWorkContext workContext, ISagePayServerTransactionService sagePayServerTransactionService,
            IOrderTotalCalculationService orderTotalCalculationService, ICurrencyService currencyService, CurrencySettings currencySettings,
            IMobileDeviceHelper mobileDeviceHelper, OrderSettings orderSettings, HttpContextBase httpContext)
        {
            this._settingService = settingService;
            this._paymentService = paymentService;
            this._orderService = orderService;
            this._orderProcessingService = orderProcessingService;
            this._localizationService = localizationService;
            this._sagePayServerTransactionService = sagePayServerTransactionService;
            this._orderTotalCalculationService = orderTotalCalculationService;
            this._currencyService = currencyService;

            this._sagePayServerPaymentSettings = sagePayServerPaymentSettings;
            this._paymentSettings = paymentSettings;
            this._currencySettings = currencySettings;
            this._orderSettings = orderSettings;

            this._logger = logger;

            this._workContext = workContext;

            this._httpContext = httpContext;

            this._mobileDeviceHelper = mobileDeviceHelper;
          
        }

        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure()
        {
            var model = new ConfigurationModel();
            model.AdditionalFee = _sagePayServerPaymentSettings.AdditionalFee;
            model.ConnectTo = _sagePayServerPaymentSettings.ConnectTo;

            model.PartnerID = _sagePayServerPaymentSettings.PartnerID;
            model.TransactType = _sagePayServerPaymentSettings.TransactType;

            model.VendorName = _sagePayServerPaymentSettings.VendorName;
            model.NotificationFullyQualifiedDomainName = _sagePayServerPaymentSettings.NotificationFullyQualifiedDomainName;
            model.ReturnFullyQualifiedDomainName = _sagePayServerPaymentSettings.ReturnFullyQualifiedDomainName;
            model.Profile = _sagePayServerPaymentSettings.Profile;

            //model.ConnectToList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ConnectToValues.SIMULATOR });
            model.ConnectToList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ConnectToValues.TEST });
            model.ConnectToList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ConnectToValues.LIVE });
            model.TransactTypeList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.TransactTypeValues.PAYMENT });
            model.TransactTypeList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.TransactTypeValues.DEFERRED });
            model.TransactTypeList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.TransactTypeValues.AUTHENTICATE });
            model.ProfileList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ProfileValues.NORMAL });
            //model.ProfileList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ProfileValues.LOW });

            return View("Nop.Plugin.Payments.SagePayServer.Views.PaymentSagePayServer.Configure", model);
        }

        [HttpPost]
        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure(ConfigurationModel model)
        {
            if (!ModelState.IsValid)
                return Configure();

            //save settings
            _sagePayServerPaymentSettings.AdditionalFee = model.AdditionalFee;
            _sagePayServerPaymentSettings.ConnectTo = model.ConnectTo;
            _sagePayServerPaymentSettings.PartnerID = model.PartnerID;
            _sagePayServerPaymentSettings.TransactType = model.TransactType;
            _sagePayServerPaymentSettings.VendorName = model.VendorName;
            _sagePayServerPaymentSettings.NotificationFullyQualifiedDomainName = model.NotificationFullyQualifiedDomainName;
            _sagePayServerPaymentSettings.ReturnFullyQualifiedDomainName = model.ReturnFullyQualifiedDomainName;
            _sagePayServerPaymentSettings.Profile = model.Profile;
            _settingService.SaveSetting(_sagePayServerPaymentSettings);


            //model.ConnectToList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ConnectToValues.SIMULATOR });
            model.ConnectToList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ConnectToValues.TEST });
            model.ConnectToList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ConnectToValues.LIVE });
            model.TransactTypeList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.TransactTypeValues.PAYMENT });
            model.TransactTypeList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.TransactTypeValues.DEFERRED });
            model.TransactTypeList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.TransactTypeValues.AUTHENTICATE });
            model.ProfileList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ProfileValues.NORMAL });
            //model.ProfileList.Add(new SelectListItem() { Text = SagePayServerPaymentSettings.ProfileValues.LOW });

            return View("Nop.Plugin.Payments.SagePayServer.Views.PaymentSagePayServer.Configure", model);
        }


        [ChildActionOnly]
        public ActionResult PaymentInfo()
        {
            return Content("<b>You will be redirected to SagePay site to complete the order.</b>");
        }


        public ActionResult PaymentInfoPostPayment()
        {
            var model = new PaymentSagePayServerModel();

            var losrder = _workContext.CurrentCustomer.Orders.Last();

            //First validate if this is the response of failed transaction (Status INVALID)
            var StatusDetail = Request.QueryString["StatusDetail"];

            if (StatusDetail != null)
            {
                model.Warnings.Add(StatusDetail);
                return View("Nop.Plugin.Payments.SagePayServer.Views.PaymentSagePayServer.PaymentInfo", model);
            }

            var webClient = new WebClient();

            var data = new NVPCodec();

            data.Add("VPSProtocol", SagePayHelper.GetProtocol());
            data.Add("TxType", _sagePayServerPaymentSettings.TransactType);
            data.Add("Vendor", _sagePayServerPaymentSettings.VendorName.ToLower());


            //return Content(_sagePayServerPaymentSettings.TransactType);


            //var orderGuid = Guid.NewGuid(losrder.OrderGuid);

            var orderGuid = Guid.Empty;

            //Guid orderNumberGuid = Guid.Empty;
            string orderNumber = losrder.OrderGuid.ToString();
            orderGuid = new Guid(orderNumber);


            data.Add("VendorTxCode", orderGuid.ToString());

            //data.Add("VendorTxCode", "00001123-5a57-4cde-9dd3-693edd6df697");

            if (!String.IsNullOrWhiteSpace(_sagePayServerPaymentSettings.PartnerID))
                data.Add("ReferrerID", _sagePayServerPaymentSettings.PartnerID);

            var cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();

            //decimal? shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart);
            //var OrderTotal = shoppingCartTotalBase.GetValueOrDefault();

            decimal  OrderTotal = 0;
            decimal shipprice = 0;
            
          
            OrderTotal = Convert.ToDecimal(losrder.OrderSubtotalInclTax);
            shipprice = Convert.ToDecimal(losrder.OrderShippingInclTax);

            OrderTotal += shipprice;

            data.Add("Amount", OrderTotal.ToString("F2", CultureInfo.InvariantCulture));

            if (_workContext.WorkingCurrency != null)
                data.Add("Currency", _workContext.WorkingCurrency.CurrencyCode);
            else if (_workContext.CurrentCustomer.CurrencyId.HasValue && _workContext.CurrentCustomer.Currency != null)
                data.Add("Currency", _workContext.CurrentCustomer.Currency.CurrencyCode);
            else
                data.Add("Currency", _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode);


            data.Add("Description", "eCommerce Order from " + _sagePayServerPaymentSettings.VendorName);

            // The Notification URL is the page to which Server calls back when a transaction completes

            var notificationUrl = _sagePayServerPaymentSettings.NotificationFullyQualifiedDomainName;

            data.Add("NotificationURL", notificationUrl + "Plugins/PaymentSagePayServer/NotificationPage");

            // Billing Details
            data.Add("BillingSurname", _workContext.CurrentCustomer.BillingAddress.LastName);
            data.Add("BillingFirstnames", _workContext.CurrentCustomer.BillingAddress.FirstName);
            data.Add("BillingAddress1", _workContext.CurrentCustomer.BillingAddress.Address1);

            if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.BillingAddress.Address2))
                data.Add("BillingAddress2", _workContext.CurrentCustomer.BillingAddress.Address2);

            data.Add("BillingCity", _workContext.CurrentCustomer.BillingAddress.City);
            data.Add("BillingPostCode", _workContext.CurrentCustomer.BillingAddress.ZipPostalCode);
            data.Add("BillingCountry", _workContext.CurrentCustomer.BillingAddress.Country.TwoLetterIsoCode); //TODO: Verify if it is ISO 3166-1 country code

            if (_workContext.CurrentCustomer.BillingAddress.StateProvince != null)
                data.Add("BillingState", _workContext.CurrentCustomer.BillingAddress.StateProvince.Abbreviation);

            if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.BillingAddress.PhoneNumber))
                data.Add("BillingPhone", _workContext.CurrentCustomer.BillingAddress.PhoneNumber);


            // Delivery Details
            if (_workContext.CurrentCustomer.ShippingAddress != null)
            {
                data.Add("DeliverySurname", _workContext.CurrentCustomer.ShippingAddress.LastName);
                data.Add("DeliveryFirstnames", _workContext.CurrentCustomer.ShippingAddress.FirstName);
                data.Add("DeliveryAddress1", _workContext.CurrentCustomer.ShippingAddress.Address1);

                if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.ShippingAddress.Address2))
                    data.Add("DeliveryAddress2", _workContext.CurrentCustomer.ShippingAddress.Address2);

                data.Add("DeliveryCity", _workContext.CurrentCustomer.ShippingAddress.City);
                data.Add("DeliveryPostCode", _workContext.CurrentCustomer.ShippingAddress.ZipPostalCode);

                if (_workContext.CurrentCustomer.ShippingAddress.Country != null)
                {
                    data.Add("DeliveryCountry", _workContext.CurrentCustomer.ShippingAddress.Country.TwoLetterIsoCode);
                }

                if (_workContext.CurrentCustomer.ShippingAddress.StateProvince != null)
                    data.Add("DeliveryState", _workContext.CurrentCustomer.ShippingAddress.StateProvince.Abbreviation);

                if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.ShippingAddress.PhoneNumber))
                    data.Add("DeliveryPhone", _workContext.CurrentCustomer.ShippingAddress.PhoneNumber);

            }
            else
            {
                //Thanks to 'nomisit' for pointing this out. https://www.nopcommerce.com/p/258/sagepay-server-integration-iframe-and-redirect-methods.aspx
                data.Add("DeliverySurname", "");
                data.Add("DeliveryFirstnames", "");
                data.Add("DeliveryAddress1", "");
                data.Add("DeliveryAddress2", "");
                data.Add("DeliveryCity", "");
                data.Add("DeliveryPostCode", "");
                data.Add("DeliveryCountry", "");
                data.Add("DeliveryState", "");
                data.Add("DeliveryPhone", "");
            }

            data.Add("CustomerEMail", _workContext.CurrentCustomer.Email);

            //var strBasket = String.Empty;
            //strBasket = cart.Count + ":";

            //for (int i = 0; i < cart.Count; i++)
            //{
            //    ShoppingCartItem item = cart[i];
            //    strBasket += item.ProductVariant.FullProductName) + ":" +
            //                    item.Quantity + ":" + item.ProductVariant.Price + ":" +
            //                    item.ProductVariant.TaxCategoryId;
            //};

            //data.Add("Basket", strBasket);

            data.Add("AllowGiftAid", "0");

            // Allow fine control over AVS/CV2 checks and rules by changing this value. 0 is Default
            if (_sagePayServerPaymentSettings.TransactType != "AUTHENTICATE") data.Add("ApplyAVSCV2", "0");


            // Allow fine control over 3D-Secure checks and rules by changing this value. 0 is Default
            data.Add("Apply3DSecure", "0");

            //if (String.Compare(_sagePayServerPaymentSettings.Profile, "LOW", true) == 0)
            //{
            //    data.Add("Profile", "LOW"); //simpler payment page version.
            //}

            var postURL = SagePayHelper.GetSageSystemUrl(_sagePayServerPaymentSettings.ConnectTo, "purchase");

            string strResponse = string.Empty;

            try
            {

                Byte[] responseData = webClient.UploadValues(postURL, data);

                strResponse = Encoding.ASCII.GetString(responseData);
                

            }
            catch (WebException ex)
            {

                return Content(String.Format(
                    @"Your server was unable to register this transaction with Sage Pay.
                    Check that you do not have a firewall restricting the POST and
                    that your server can correctly resolve the address {0}. <br/>
                    The Status Number is: {1}<br/>
                    The Description given is: {2}", postURL, ex.Status, ex.Message));

            }

            if (string.IsNullOrWhiteSpace(strResponse))
                return Content(String.Format(
                    @"Your server was unable to register this transaction with Sage Pay.
                    Check that you do not have a firewall restricting the POST and
                    that your server can correctly resolve the address {0}.", postURL));

            var strStatus = SagePayHelper.FindField("Status", strResponse);
            var strStatusDetail = SagePayHelper.FindField("StatusDetail", strResponse);

            //string strToken= string.Empty;

            switch (strStatus)
            {
                case "OK":

                    var strVPSTxId = SagePayHelper.FindField("VPSTxId", strResponse);
                    var strSecurityKey = SagePayHelper.FindField("SecurityKey", strResponse);
                    var strNextURL = SagePayHelper.FindField("NextURL", strResponse);

                    //var tokenfound = SagePayHelper.FindField("Token", strToken);
                    //if (tokenfound.Length == 0)
                    //{
                    //    return Content(strResponse);
                    //}
                    


                    var transx = new SagePayServerTransaction()
                    {
                        CreatedOnUtc = DateTime.UtcNow,
                        VPSTxId = strVPSTxId,
                        SecurityKey = strSecurityKey,
                        NotificationResponse = strResponse,
                        VendorTxCode = orderGuid.ToString()
                    };

                    //Store this record in DB
                    _sagePayServerTransactionService.InsertSagePayServerTransaction(transx);


                    //ViewBag.UseOnePageCheckout = UseOnePageCheckout();

                    //if (_sagePayServerPaymentSettings.Profile == SagePayServerPaymentSettings.ProfileValues.LOW || ViewBag.UseOnePageCheckout)
                    //{//Iframe
                    //    model.FrameURL = strNextURL;

                    //    return View("Nop.Plugin.Payments.SagePayServer.Views.PaymentSagePayServer.PaymentInfo", model);
                    //}
                    //else
                    //{
                        HttpContext.Response.Redirect(strNextURL);
                        HttpContext.Response.End();

                        return null;
                    //}


                case "MALFORMED":
                    return Content(string.Format("Error ({0}: {1}) <br/> {2}", strStatus, strStatusDetail, data.Encode()));

                case "INVALID":
                    return Content(string.Format("Error ({0}: {1}) <br/> {2}", strStatus, strStatusDetail, data.Encode()));

                default:
                    return Content(string.Format("Error ({0}: {1})", strStatus, strStatusDetail));

            }

        }


        
//        [ChildActionOnly]
//        public ActionResult PaymentInfo()
//        {
//            var model = new PaymentSagePayServerModel();

//            //First validate if this is the response of failed transaction (Status INVALID)
//            var StatusDetail = Request.QueryString["StatusDetail"];

//            if (StatusDetail != null)
//            {
//                model.Warnings.Add(StatusDetail);
//                return View("Nop.Plugin.Payments.SagePayServer.Views.PaymentSagePayServer.PaymentInfo", model);
//            }

//            var webClient = new WebClient();

//            var data = new NVPCodec();

//            data.Add("VPSProtocol", SagePayHelper.GetProtocol());
//            data.Add("TxType", _sagePayServerPaymentSettings.TransactType);
//            data.Add("Vendor", _sagePayServerPaymentSettings.VendorName.ToLower());

//            var orderGuid = Guid.NewGuid();

//            data.Add("VendorTxCode", orderGuid.ToString());

//            //data.Add("VendorTxCode", "00001123-5a57-4cde-9dd3-693edd6df697");

//            if (!String.IsNullOrWhiteSpace(_sagePayServerPaymentSettings.PartnerID))
//                data.Add("ReferrerID", _sagePayServerPaymentSettings.PartnerID);

//            var cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();
            
//            decimal? shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart);

//            var OrderTotal = shoppingCartTotalBase.GetValueOrDefault();

//            data.Add("Amount", OrderTotal.ToString("F2", CultureInfo.InvariantCulture));

//            if (_workContext.WorkingCurrency != null)
//                data.Add("Currency", _workContext.WorkingCurrency.CurrencyCode);
//            else if (_workContext.CurrentCustomer.CurrencyId.HasValue && _workContext.CurrentCustomer.Currency != null)
//                data.Add("Currency", _workContext.CurrentCustomer.Currency.CurrencyCode);
//            else
//                data.Add("Currency", _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode);
            

//            data.Add("Description", "eCommerce Order from " + _sagePayServerPaymentSettings.VendorName);

//            // The Notification URL is the page to which Server calls back when a transaction completes

//            var notificationUrl = _sagePayServerPaymentSettings.NotificationFullyQualifiedDomainName;

//            data.Add("NotificationURL", notificationUrl + "Plugins/PaymentSagePayServer/NotificationPage");

//            // Billing Details
//            data.Add("BillingSurname", _workContext.CurrentCustomer.BillingAddress.LastName);
//            data.Add("BillingFirstnames", _workContext.CurrentCustomer.BillingAddress.FirstName);
//            data.Add("BillingAddress1", _workContext.CurrentCustomer.BillingAddress.Address1);

//            if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.BillingAddress.Address2))
//                data.Add("BillingAddress2", _workContext.CurrentCustomer.BillingAddress.Address2);

//            data.Add("BillingCity", _workContext.CurrentCustomer.BillingAddress.City);
//            data.Add("BillingPostCode", _workContext.CurrentCustomer.BillingAddress.ZipPostalCode);
//            data.Add("BillingCountry", _workContext.CurrentCustomer.BillingAddress.Country.TwoLetterIsoCode); //TODO: Verify if it is ISO 3166-1 country code

//            if (_workContext.CurrentCustomer.BillingAddress.StateProvince != null)
//                data.Add("BillingState", _workContext.CurrentCustomer.BillingAddress.StateProvince.Abbreviation);

//            if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.BillingAddress.PhoneNumber))
//                data.Add("BillingPhone", _workContext.CurrentCustomer.BillingAddress.PhoneNumber);


//            // Delivery Details
//            if (_workContext.CurrentCustomer.ShippingAddress != null)
//            {
//                data.Add("DeliverySurname", _workContext.CurrentCustomer.ShippingAddress.LastName);
//                data.Add("DeliveryFirstnames", _workContext.CurrentCustomer.ShippingAddress.FirstName);
//                data.Add("DeliveryAddress1", _workContext.CurrentCustomer.ShippingAddress.Address1);

//                if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.ShippingAddress.Address2))
//                    data.Add("DeliveryAddress2", _workContext.CurrentCustomer.ShippingAddress.Address2);

/
5 лет назад
Sorted the problem it turned out to be a type on my part and after talking to sage a couple of missing fields:

strMessage = strVPSTxId + strVendorTxCode + strStatus + strTxAuthNo + strVendorName +   strAVSCV2 +  transx.SecurityKey +
              strAddressResult + strPostCodeResult + strCV2Result + strGiftAid + str3DSecureStatus +
              strCardType + strLast4Digits + DeclineCode + ExpiryDate +  BankAuthCode;

If any one is interested the above code is correct string that is needed.
5 лет назад
Hi,

How far have you got with this and what version of SagePay are you currently using... iFrame or Direct?

p.s. I'm currently trying to update a 3.20 version to 3.50 and having a mare!!!

Thanks,
Craig
5 лет назад
The mod was done for 2.5, but at the moment I am in the middle of updating our site to 3.5 and need to update the plugin I found to work the way we want it or need it to work. , we use direct as we found Iframe to be a little unreliable.

As long as the Boss says it ok when I have done the 3.5 mod to sage pay I post the code here.

it be in the next couple of weeks as I am in the process of moding the discount system to work the way we do our discounts as the current way Nop works out discounts brakes our discounts.

If that makes any sence.
5 лет назад
Ah ok... I've managed to port it over to 3.50, but having a pain in the ass to get the configure view working!!

I did some work on the orginal iFrame plugin, but looks like I may have to move to direct (easier to work with mobile too) and see if I can port it to SagePay 3.
5 лет назад
We have a plugin that supports Direct and Server (with Iframe support), if that helps.