codeflood logo

SEFE On-Site Payment Provider

I’ve recently had the opportunity to get to know the Sitecore eCommerce Fundamental Edition or SEFE for short. One of our clients wanted to port their existing online shop to Sitecore which we’d used to rebuild their site.

The main reason I chose SEFE was due to the fact that SEFE IS Sitecore and is built completely in Sitecore. All other eCommerce platforms I assessed were external applications and would have required a great deal of integration effort to make them work as seamlessly as SEFE felt. I should mention that SEEE (Sitecore eCommerce Enterprise Edition) had not been released at the time, so that was never a contender.

Before I get into the goodness of this post about the payment providers, a quick warning to any about to use SEFE. The example site is just that. An example. I would never again attempt to use the example site as part of my production site. The example site has it’s own way of doing things and it’s own markup. Perhaps my experience was marred by the fact I had to bash the example controls to work with the existing CSS. So based on my experience, my advice to you is to refer to the example site as a reference, but build your own site components.

So, onto payment providers. The site I was porting over to SEFE hosted a credit card payment form itself. It uses an on-site payment method where the user never leaves the site; there is no redirect to the payment providers payment page and then a redirect back to the site. I needed to replicate this in SEFE.

Flicking through the SEFE payment method reference guide, which can be found on SDN, it seemed it didn’t quite tell me what I needed to do to host my own payment form. That document focused heavily on using a redirect to the payment providers hosted form. There were snippets about an on-site option, but not nearly enough information on this.

Eventually I found in the document the IIntegrationalPaymentProvider interface that sounded like what I needed to be able to write my own on-site payment provider…but it has not been implemented yet.

As it turns out, it’s not that hard to handle payments on-site but still fit within how SEFE wants to work. The trick is to create a normal IOnlinePaymentProvider (for an off-site payment provider) but host the payment forms yourself and have your payment provider interact with your own forms.

So let’s create a sample on-site payment provider using this approach. I’m going to write my sample payment provider and deploy it to the SEFE sample site. For this sample I’ll need to work against an existing Sitecore site with the latest version of SEFE installed.

We need to create a new class for our payment provider which extends the Sitecore.Ecommerce.Payments.OnlinePaymentProvider class which can be found in the Sitecore.Ecommerce.Kernel assembly. There are 2 methods we need to override to make our payment provider work; Invoke and ProcessCallback. Invoke is called when SEFE uses your payment provider to make a payment and ProcessCallback is called when the normally external payment provider site redirects the user back to your site.

For our sample on-site provider, in the Invoke method we simply need to redirect the user to the payment form on our site. We don't need to send any data like we would an off-site payment provider cause we can simply retrieve that data from the payment form. The OOTB payment provider configuration in SEFE allows entering a primary and secondary URL for the provider. For our provider we’ll use the primary URL to point to our on-site payment form, and the secondary URL to point to the payment gateway service we’ll be using. The URLs are configured inside Sitecore on the payment provider item we’ll configure a but later on. SEFE passes the configured URLs into the payment provider through the paymentSystem parameter.

public override void Invoke(
  Sitecore.Ecommerce.DomainModel.Payments.PaymentSystem paymentSystem, 
    PaymentArgs paymentArgs) 
{ 
  base.Invoke(paymentSystem, paymentArgs);

  // Store return page URL in transaction for use on credit card form 
  var transaction = Sitecore.Ecommerce.Context.Entity.Resolve<TransactionData>(); 

  transaction.SavePersistentValue(paymentArgs.ShoppingCart.OrderNumber, 
    "returnurl", paymentArgs.PaymentUrls.ReturnPageUrl);

  HttpContext.Current.Response.Redirect(paymentSystem.PaymentUrl); 
}

Note above how I’m storing the return page URL? That URL is what we must redirect the user to after a successful payment so SEFE will process the order. I can't retrieve that URL from the payment form by other means so I'll store that URL in the transaction so I can retrieve it later.

The page we redirect the user to will handle collection of credit card information from the user, communication with the payment gateway and setting the success or failure of the payment. For this we’ll create a new sublayout containing the following markup:

<%@ Control Language="C#" AutoEventWireup="true" 
  CodeBehind="CreditCardForm.ascx.cs" 
  Inherits="SampleOnsitePaymentProvider.layouts.CreditCardForm" %> 
  <div>
    <strong>Amount Due: </strong><asp:Literal runat="server" 
      ID="litAmount" /> 
  </div> 
  <div> 
    Card Number: <asp:TextBox runat="server" ID="txtCardNumber" /> 
  </div> 
  <div> 
    Name on Card: <asp:TextBox runat="server" ID="txtName" /> 
  </div> 
  <div> 
    Expiry: Month: <asp:TextBox runat="server" ID="txtMonth" /> 
    Year: <asp:TextBox runat="server" ID="txtYear" /> 
  </div> 
  <div> 
    <asp:Literal runat="server" ID="litMessage" /> 
  </div> 
  <div> 
    <asp:Button runat="server" ID="btnSubmit" Text="Submit" 
      OnClick="SubmitClicked" /> 
  </div>

Not particularly complex. The code behind of this sublayout is pretty straight forward, set the total of the order when the page loads and then process the credit card details when the form is submitted.

using System; 
using Sitecore.Ecommerce; 
using Sitecore.Ecommerce.DomainModel.Carts; 
using Sitecore.Ecommerce.Payments;

namespace SampleOnsitePaymentProvider.layouts 
{
  public partial class CreditCardForm : System.Web.UI.UserControl 
  { 
    protected void Page_Load(object sender, EventArgs e) 
    { 
      var shoppingCart = 
        Sitecore.Ecommerce.Context.Entity.GetInstance<ShoppingCart>(); 
      if (shoppingCart != null) 
        litAmount.Text = shoppingCart.Totals.TotalPriceIncVat.ToString(); 
      else 
      { 
        litMessage.Text = "Failed to find the shopping cart"; 
        btnSubmit.Enabled = false; 
      } 
    }

    protected void SubmitClicked(object sender, EventArgs args) 
    { 
      // TODO: validation
      var shoppingCart = 
        Sitecore.Ecommerce.Context.Entity.GetInstance<ShoppingCart>(); 
      if (shoppingCart != null) 
      { 
        // Configure payment gateway client 
        var client = new PaymentGateway(); 
        client.Url = shoppingCart.PaymentSystem.PaymentSecondaryUrl; 
        client.Username = shoppingCart.PaymentSystem.Username; 
        client.Password = shoppingCart.PaymentSystem.Password; 

        client.CardNumber = txtCardNumber.Text; 
        client.CardName = txtName.Text; 
        client.ExpireMonth = txtMonth.Text; 
        client.ExpireYear = txtYear.Text;

        if (client.Process()) 
        { 
          // Store the transaction number to indicate success 
          var transaction = 
            Sitecore.Ecommerce.Context.Entity.Resolve<TransactionData>(); 
          transaction.SavePersistentValue(shoppingCart.OrderNumber, 
            TransactionConstants.TransactionNumber, client.TransactionNumber);

          // Get return page URL from transaction 
          var url = transaction.GetPersistentValue(shoppingCart.OrderNumber, 
            "returnurl") as string;
          Response.Redirect(url); 
        } 
        else 
        { 
          litMessage.Text = "Payment failed. Please try again."; 
        } 
      } 
      else 
      { 
        litMessage.Text = "Failed to find the shopping cart"; 
        btnSubmit.Enabled = false; 
      } 
    } 
  } 
}

You would of course need to alter the above code to call out to your payment gateway appropriately. Note how I store the transaction number from the payment gateway into my SEFE transaction? I’m going to use this piece of data in my payment provider to determine that the payment was successful. The TransactionConstants class is provided by SEFE to provide keys for common pieces of data you might require.

I’m also using that return page URL I stored when my payment provider was invoked.

Now all that’s left is to process the callback in my payment provider as a result of redirecting to the return page. This method is called by SEFE.

public override void ProcessCallback(
  Sitecore.Ecommerce.DomainModel.Payments.PaymentSystem paymentSystem, 
    PaymentArgs paymentArgs) 
{ 
  var transaction = Sitecore.Ecommerce.Context.Entity.Resolve<TransactionData>(); 
  if (!string.IsNullOrEmpty(transaction.GetPersistentValue(
    paymentArgs.ShoppingCart.OrderNumber, 
    TransactionConstants.TransactionNumber) as string)) 
    PaymentStatus = PaymentStatus.Succeeded; 
  else 
    PaymentStatus = PaymentStatus.Failure; 
}

In this method I’m checking that the transaction number has been populated before setting the outcome of the payment in the PaymentStatus property as succcessful.

Now to register everything with SEFE and get this sample working in the SEFE example site.

SEFE stores the payment providers available for a site under the site’s business catalogue under the payment options item. The payment options item contains settings for all payment providers such as the payment return page and other URLs. Individual payment providers are defined as children of the payment options item and are based on the ecommerce/business catalog/payment data template.

One of the settings of our sample payment provider will be the URL to the credit card form, so we’d better create that first. I’m going to create this page as one of the function pages in the sample checkout.

credit card checkout page

Make sure you add the credit card form sublayout we created above to the page.

Now we’ll register our payment provider. Create a new payment provider item in the business catalogue and populate the fields appropriately. The important fields are:

Field Purpose Value
Code maps this provider to a provider through the Unity configuration credit
Name Appears on the UI Credit Card
Payment Provider URL The URL SEFE will redirect the user to Link to the credit card form
Username The username of the account to access the payment gateway Your payment gateway username
Password The password of the account to access the payment gateway Your payment gateway password
Payment Provider Secondary URL For our payment provider, this is the URL of the payment gateway service Your payment gateway URL

SEFE uses Unity to configure many parts of the module, including mapping payment providers. Open up the App_Include/Unit.config file and find an existing payment provider by searching for the code PayByCheck. This is the registration of the code and the mapping to the implementation type. Copy this element and update to use the code we defined in the payment provider item’s code field above, and update the mapTo attribute(which we’ll need to register next). Also, the <property name="PaymentSystem" /> element isn’t required. The resulting updated element may look like the following:

<register type="PaymentProvider" mapTo="CreditCardPaymentProvider" name="Credit Card"/>

Now search for the alias implementing the PayByCheck payment provider, OfflinePaymentProvider. This isn’t a .net type, but a Unity alias, we’re looking for the alias to real type mapping element. Copy the existing OfflinePaymentProvider alias and update to map the CreditCardPaymentProvider alias above to the payment provider we created in our project above. The resulting updated element may look like the following:

<alias alias="CreditCardPaymentProvider" 
  type="SampleOnsitePaymentProvider.OnsitePaymentProvider, SampleOnsitePaymentProvider" />

If everything worked properly then you’ll be able to test your payment provider on the sample site. Just go through the normal checkout process and select credit card as the payment option on the payment page.

credit card payment page

And there you have it! The payment provider we’ve created in this post isn’t tied to any particular payment gateway, only the credit card page (that you configure) is. So you can use this technique to host your own payment form in SEFE without redirecting users off-site.

Comments

Good post. There are not that many posts on SEFE so it's nice to see that other people are integrating SEFE too. I can confirm that the examples are very limited once you implement a real world scenario but at least you can use it as a reference. Keep up the good work!

Nigel

Hi, I find your post very useful. I would like to ask you a bit about how the Sitecore E-commerce module handle an order.
Could you explain to me the process of how orders are placed by customers? There are no documentation regarding this topic.
Our logic flow is as following:
1. Proceed checkout. 2. Checkout confirmation 3. Payment screen 4, Checkout completion
My question is when user click on the checkout confirmation they will be redirected to our payment screen how the payment provider would be triggered? Should we initiaite it and call Invoke or ProcessCallBack?
When payment is proceed it, according to my result from reflection of Sitecore code I saw that the order would be placed by itself? So we do not need to do anything? In case I am wrong please explain to me how we should do with the order (how to create it and how to save it to database as well as creating Sitecore items for them in the Content editor).
Thanks and really appreciate your helps, this will save us a lot !

Alistair Deneys

Hi Nigel, I last used SEFE quite a long time ago, and my memory's a little hazy. But from memory (and from the version I used) SEFE only really supported offsite payment providers where the payment provider required you to redirect to their site where the transaction takes place, then the payment provider will redirect the user back to your site where your callback will be processed. In this blog post I showed how to do all this but simply redirect to a page you host so you can handle the payment yourself using a payment provider gateway, service or some other kind of payment process. The ProcessCallback method gets invoked by SEFE after the payment and this is where you set the status of the transaction. If the transaction was successful then from memory SEFE takes care of creating the order which in turn creates the order items in the content tree.
As I said, this is all from memory and on an older version of SEFE. The module may have changed by now. I hope this helps.

Leave a comment

All fields are required.