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.
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.
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.
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!