03 Dec

Ogone subscriptions implementation .Net – Client

ogone_logo

 

We’ll be creating a Ogone client application which will make you able to create, update and delete a subscription via Ogone.

 
 

To do this we’ll be needing 4 classes:

  • Ogone Client: to control all actions done by the client
  • Remote Post: this class is made to post to Ogone and catch Ogone’s responses
  • Ogone Request: this class will create all the requests and call RemotePost
  • Ogone Status Request: an enum of possible statuses returned by Ogone.

Remote Post

All the calls send to Ogone are done by posting to a specific url. To do this we’ve created Remote Post, which simulates a simple HTML form.


Code looks like this:
/// <summary>
/// Class which simulates an HTML form and sends data to a certain URL.
/// </summary>
public class RemotePost
{
    public readonly Dictionary<string , string> Values;

    public string Url { get; set; }
    public string Method { get; set; }
    public string FormName { get; set; }

    /// <summary>
    /// Default constructor
    /// </summary>
    public RemotePost()
    {
        Method = "POST";
        FormName = "form1";
        Values = new Dictionary<string , string>();
    }

    /// <summary>
    /// Adds variables to a collection which will be sent to Ogone.
    /// </summary>
    /// <param name="key">Key of the variable</param>
    /// <param name="value">Value of the variable</param>
    public void Add(string key, string value)
    {
        Values.Add(key, value);
    }

    /// <summary>
    /// Posts all data to specific url.
    /// </summary>
    /// <returns>Dictionary with Ogone Response.</returns>
    public Dictionary<string , string> Post()
    {
        var client = new HttpClient();
        var content = new FormUrlEncodedContent(Values);
        //Here we'll post the data to Ogone.
        var result = client.PostAsync(Url, content).Result;
        var output = new Dictionary<string , string>();

        if (result.IsSuccessStatusCode)
        {
            //Reading the response from Ogone.
            var data = result.Content.ReadAsStringAsync();
            var doc = new XmlDocument();
            doc.LoadXml(data.Result);

            //Getting the needed elements from the response
            var elemList = doc.GetElementsByTagName("ncresponse");
            for (var i = 0; i < elemList.Count; i++)
            {
                var attrs = elemList[i].Attributes;
                if (attrs == null) continue;
                foreach (XmlNode attr in attrs)
                {
                    output.Add(attr.Name.ToLower(), attr.Value.ToLower());
                }
            }
        }
        return output;
    }
}

Ogone Status Request

We’ve also created a small enum which will contain all statuses returned by Ogone.

 

/// <summary>
/// Enum which contains all the error that could be sent back by Ogone.
/// </summary>
public enum OgoneRequestStatus
{
    /// <summary>
    /// The creation was successful.
    /// </summary>
    [Description("Success")]
    Success = 1,
    /// <summary>
    /// An unexpected system error occurred while processing this request.
    /// </summary>
    [Description("Failed")]
    Failed = 0,
    /// <summary>
    /// The credit card expires before the subscription start date.
    /// </summary>
    [Description("The credit card is expired")]
    CreditCardIsExpired = 2,
    /// <summary>
    /// Invalid Credit card was given.
    /// </summary>
    [Description("The card number is invalid")]
    InValidCreditCard = 3,
    /// <summary>
    /// Gets popped when a user uses a credit card not supported.
    /// </summary>
    [Description("The credit card is not supported")]
    NotSupported = 4,
    /// <summary>
    /// Cvc entered is not correct.
    /// </summary>
    [Description("The security code is incorrect")]
    CvcIncorrect = 5,
    /// <summary>
    /// When users enters a different expiry date then stated on the card.
    /// </summary>
    [Description("The card number or expiry date is incorrect")]
    ExpiryDateIncorrect = 6,
    /// <summary>
    /// When user enters wrong address data.
    /// </summary>
    [Description("The address is incorrect")]
    InvalidAddress = 7
}


Ogone Client

The Ogone client contains functions and methods which are used as helpers to communicate with Ogone.
In this post we’ll only focus on the client itself. How the request are sent to Ogone will be covered in our next Ogone post.

 

Data you’ll be needing:

  • SHA_IN-string, the one you created on the Ogone website: [SHAIN]
  • SHA_OUT-string, the one you created on the Ogone website: [SHAOUT]

 

The code:
/// <summary>
/// Client which controls all Ogone actions.
/// </summary>
public class OgoneClient
{
    /// <summary>
    /// Generates the SHA-1 string to use with Ogone.
    /// </summary>
    /// <param name="input">All the values merged into one string.</param>
    /// <returns>Generated SHA-1 string</returns>
    private static string GenerateHash(string input)
    {
        var bytes = Encoding.UTF8.GetBytes(input);
        var sha = new SHA1CryptoServiceProvider();
        var hash = sha.ComputeHash(bytes);
        var result = new StringBuilder();
        for (var i = 0; i < 20; i++)
        {
            var temp = hash[i].ToString("X2");
            if (temp.Length == 1)
            {
                temp = "0" + temp;
            }
            result.Append(temp);
        }
        return result.ToString();
    }

    /// <summary>
    /// Function that will convert a Dictionary of values to a complete string for SHA-1.
    /// <param name="values">Values in Alphabetical order meant for Ogone.</param>
    /// <param name="shaIn">Says if SHA-In is needed or not.</param>
    /// <returns>Complete string used to create the SHA-1 string.</returns>
    public static string GenerateStaticHash(Dictionary<string , string> values, bool shaIn)
    {
        var sign = shaIn ? [SHAIN] : [SHAOUT];
        // Create the string with all the values which are not empty.
        var input = values.Where(item => !string.IsNullOrEmpty(item.Value))
                            .Aggregate("", (current, item) => current + (item.Key + "=" + item.Value + sign));
        return GenerateHash(input);
    }
    
    /// <summary>
    /// Function that will handle the returned results from Ogone.
    /// </summary>
    /// <param name="dic">The values returned by Ogone.</param>
    /// <returns>Returns the result from the Ogone request.</returns>
    public string HandleSubscription(IReadOnlyDictionary<string , string> dic)
    {
        string subscriptionId, creationstatus, errorcode;

        dic.TryGetValue("subscription_id", out subscriptionId);
        dic.TryGetValue("orderid", out orderId);
        // Check if the subscription is created successfully
        if (dic.TryGetValue("creation_status", out creationstatus) && creationstatus.ToLower().Equals("ok"))
        {
            // If subscription is made successfully, but credit card validation gave an error. Subscription has to be canceled again.
            if (dic.TryGetValue("ncerror", out errorcode) && !errorcode.Equals("0"))
            {
                CancelSubscription(subscriptionId);
                return HandleError(errorcode);
            }
            else
            {
                return OgoneRequestStatus.Success.GetDescription<ogonerequeststatus>();
            }
        }
        else
        {
            // Subscription has failed. If error show the error otherwise its unknown and failed.
            return dic.TryGetValue("ncerror", out errorcode)
                                        ? HandleError(errorcode)
                                        : OgoneRequestStatus.Failed.GetDescription<ogonerequeststatus>();
        }
    }

    /// <summary>
    /// Will create a subscription in Ogone.
    /// </summary>
    /// <returns>Returns the result from the Ogone request.</returns>
    public string CreateSubcription()
    {
        return HandleSubscription(OgoneRequest.CreateSubscription());
    }

    /// <summary>
    /// Will delete and create new a subscription in Ogone.
    /// </summary>
    /// <returns>Returns the result from the Ogone request.</returns>
    public string UpdateSubcription()
    {
        var status= HandleSubscription(
            OgoneRequest.CreateSubscription();
        // If not success keep the old successful subscription.
        if (status.ToLower().Equals("success"))
        {
            OgoneRequest.DeleteSubscription();
        }
        return status;
    }
    
    /// <summary>
    /// Will delete a subscription in Ogone.
    /// </summary>
    public void CancelSubscription()
    {
        OgoneRequest.DeleteSubscription();
    }

    /// <summary>
    /// Handles errors codes coming from Ogone.
    /// </summary>
    /// <returns>Description of the error code.</returns>
    public string HandleError(string error)
    {
        switch (error)
        {
            //Wrong CVC
            case "30051001":
                return OgoneRequestStatus.CvcIncorrect.GetDescription<ogonerequeststatus>();
            //Expired
            case "50001005":
                return OgoneRequestStatus.CreditCardIsExpired.GetDescription<ogonerequeststatus>();
            //Dummy credit card
            case "50001045":
                return OgoneRequestStatus.InValidCreditCard.GetDescription<ogonerequeststatus>();
            //Correct credit card, wrong expiry date
            case "30141001":
                return OgoneRequestStatus.ExpiryDateIncorrect.GetDescription<ogonerequeststatus>();
            //Not supported card
            case "50001123":
                return OgoneRequestStatus.NotSupported.GetDescription<ogonerequeststatus>();
            //Send Masked credit card
            case "50001111":
                return OgoneRequestStatus.InValidCreditCard.GetDescription<ogonerequeststatus>();
            //Wrong address
            case "30001096":
                return OgoneRequestStatus.InvalidAddress.GetDescription<ogonerequeststatus>();
            //Incorrect/Dummy credit card number
            case "30031001":
                return OgoneRequestStatus.InValidCreditCard.GetDescription<ogonerequeststatus>();
            default:
                return OgoneRequestStatus.Failed.GetDescription<ogonerequeststatus>();
        }
    }
}


This concludes our second post about Ogone subscriptions in .net. In our next post we’ll show you how to create a subscription.

 

 

Sources

 

Leave a Reply

Your email address will not be published. Required fields are marked *