How to

Sana Commerce 8.2
Your provider

Create a Custom Internal Payment Module

The creation of an internal payment method is very easy. First you will need to create a new class that is the entry-point of the payment method. This class should inherit from the 'PaymentModuleBase' abstract class ('Sana.Commerce.Payment' namespace).
 
All you will have to do is override the OnPay method. That is all that is needed to create a payment method. The pay method will be called whenever the user starts a payment using this payment method. The payment method can be used by configuring it in the 'web.config'. See this chapter for more information. 
 
Adding Pipelines 
While we have created a custom payment module it does not do very much at this point as no code is defined in it. In a real life scenario this will not be very useful. There are a few actions that will be present in (almost) all payment modules. These are:
  • Setting the status of the order;
  • Saving of the order;
  • Deleting the current users basket;
  • Sending an order confirmation mail;
  • Deducting stock;
  • Sending the user to the order success page.
We could create custom code to accomplish these steps but since the code for these actions already exists this will be inefficient. These steps already exist as pipeline steps, we just have to add a pipeline to our payment module to easily re-use these steps and even add custom steps at any place in the pipeline.
 
It is easy to extend or add a pipeline. Follow these steps:
 
Step 1: Create a list of steps to execute as a IPaymentStep[ ] or collection of steps, for example:

var steps = new IPaymentStep[ ]
{      
  new PayOrderStep(),                    //Set the order to paid
  new SaveOrderStep(),                  //Saves order   
  new DeductStockStep(),               //Deduct the stock for this order 
  new DeleteBasketStep(),             //Delete the basket  
  new SendOrderMailStep(),           //Send to order confirmation mail  
  new RedirectToSuccessPageStep()   //Redirect the user
};
 

Step 2: Create a new pipeline; specify the name of the pipeline, the steps that need to be executed. This can be done in the following way:

PaymentPipeline pipeline = new PaymentPipeline("Pipeline",steps);

Step 3: Setup the payment context; we always need to pass this context to the pipeline. (we assume order contains the current order and 'Configuration' - the current configuration). Objects in this context are used by all the steps in the pipeline.

IOrderContext context = ObjectManager. GetInstance<IOrderContext>();
context.Order = order;
context.ShippingAddressId = shippingAddressId;
context.Payment.Configuration = Configuration;
 
For an overview of the objects that can/should be set in the context refer to the context help section.

Step 4: Finally the pipeline needs to be executed:

pipeline.Execute(context, null);
 
As you could see earlier we needed to supply the context we just created. The second parameter is a list of custom objects that can be passed into the pipeline. This is only needed if custom objects need to be processed by the pipeline, for example we just supply null as we do not have any of these custom objects.
 
Those are all the steps needed to add a pipeline to the payment module. A module is not limited to a single pipeline; multiple pipelines can be added if needed. Below you can find a complete working example of an internal payment method:
     /// <summary>
    /// Payment method for placing orders on account. This means no verification of is needed and no
    /// user action is required, the order will be set to paid right away.
    /// This payment method is usefull in a B2B scenario where an ERP system is used.
    /// </summary>
    public class OnAccountModule : PaymentModuleBase
    {
        /// <summary>
        /// Pay this Order using the <see cref="OnAccountModule"/>. This module will set the order to paid
        /// right away.
        /// </summary>
        /// <param name="context">Context object to pass between the steps</param>
        /// <param name="paymentMethodId">The payment method id.</param>
        /// <param name="externalConfiguration">A list of configuration values that are not configured by the payment
        /// module itself but rather by an external source. For example the payment method selected.</param>
        /// <returns>
        /// true if the payment was handled right away, false if it is still in progress.
        /// </returns>
        protected override bool OnPay(IOrderContext context, Guid paymentMethodId, NameValueCollection externalConfiguration)
        {
            IPaymentPipeline pipeline = CreatePipeline();
            //Create configuration
            SetExternalConfigurationSettings(externalConfiguration);
            context.Payment.Configuration = Configuration;
            //Execute the pipeline
            pipeline.Execute(context, null);
            PaymentLog.Current.Add(context.Order, "Order was paid using the OnAccountModule.", false);
            return true; //let the checkout process handle deleing of basket, ect.
        }
        /// <summary>
        /// Creates a pipeline instance.
        /// </summary>
        /// <returns>A fully initialized pipeline instance.</returns>
        protected virtual IPaymentPipeline CreatePipeline()
        {
            var okSteps = new IPaymentStep[]
            {    
                new PayOrderStep(),                 //Set the order to paid
                new SaveOrderStep(),               //Saves order
                new DeductStockStep(),              //Deduct the stock for this order
                new DeleteBasketStep(),             //Delete the basket linked to this order
                new SendOrderMailStep(),            //Send to order confirmation mail
                new RedirectToSuccessPageStep()     //Redirect the user to the success page.
            };
            return new PaymentPipeline("StatusOkPipeline", okSteps);
        }
    }
The steps executed by this payment method can easily be changed. Out-of-the box the Sana Commerce framework contains the following steps.