How toGeneral

General

Create a Custom External Payment Module for a PSP

Besides internal payment modules there is also means in the framework to easy implement any payment service provider. By default the Sana Commerce framework supports a few PSP's already. These payment modules are distributed as separate modules. If a payment service provider module does not exist yet it can also be added as a custom library. This can be done the following way:
  • First study the documentation of the PSP to see what has to be customized in the default external payment module (for example, custom steps);
  • Create a new assembly/project that will contain the custom payment method, while it is possible to add it to any existing assembly, this will make it easier to distribute the payment method;
  • Create a new payment class that will inherit from the 'ExternalPaymentModule' Class, this will be the base class for implementing the custom PSP provider.
Functions Found in the External Payment Module Base Class 
The 'ExternalPaymentModule' is an important part in creating a PSP implementation. It contains a basic 'framework' for implementation. It contains the following function that can be overridden:
 
 Pay 
 Signature   public virtual bool Pay(IOrder order, NameValueCollection externalConfiguration)
 Description  The 'Pay' function is called whenever a payment is started. This function will call the pre-process pipeline to prepare the redirection to the payment service provider
 When to overwrite  Customization of this function is uncommon. Configuration independent from the configuration of the payment module can be added with the 'externalConfiguration' parameter. These values will be directly added to the configuration
 
 Confirm 
 Signature  public virtual void Confirm(IOrder order, HttpRequest request, NameValueCollection externalParameters)
 Description  The 'Confirm' function will execute the confirm pipeline and is called by the confirm page
 When to overwrite  It functions the same way as the 'Pay' function and it is also unlikely it will need to be overwritten
 
 Finish 
 Signature   public virtual void Finish(IOrder order, HttpRequest request, NameValueCollection externalParameters)
 Description  This function is the same as the 'Pay' and 'Confirm' functions only that the post-process pipeline is executed
 When to overwrite    -
 
 Aborted
 Signature  public virtual void Aborted(IOrder order, HttpRequest request, NameValueCollection externalParameters)            
 Description  Again the same as 'Pay', 'Confirm' and 'Finish' but this time the Cancel pipeline is called
 When to overwrite  -
 
 CreateResponse
 Signature  public virtual NameValueCollection CreateResponse(IOrder order, NameValueCollection externalParameters)
 Description 
 This function is called to redirect the user to the PSP payment page. This can be done in three ways:
 
  •  A simple redirect
  • A form POST
  • A form POST as XML
 
The method chosen will depend on the configuration of the payment module.  When post is selected all configuration values marked as 'isRequestParameter' will be added to the post
 When to overwrite     While the system is flexible in some cases another means of redirection might be needed. In that case this function can be overwritten
 
 Initialize
 Signature  protected virtual PaymentContext Initialize(IOrder order, NameValueCollection externalParameters)
 Description This function will load all configuration and pipelines and put them into the 'PaymentContext' object. The 'Payment Context' will be passed to each pipeline.
The 'SetPaymentConfiguration' and 'BuildPipelines' functions are called by this function
 When to overwrite      When trying to overwrite pipeline behaviour it is advised to overwrite the 'BuildPipeline' functions instead. When trying to change the way configuration is loaded (for example from another location) the 'ConfigurationPaymentModuleCreator' should be overwritten. In all other cases this method can be customized
 
 SetPaymentConfiguration
 Signature   protected virtual void SetPaymentConfiguration(IOrder order, List<PaymentConfigurationSetting> configuration)
 Description   This function is called each time the configuration is initialized
 When to overwrite  When making runtime changes to configuration values (for example replacing values) this function can be overwritten. By default this function does not contain any code. Again when making changes to the way configuration is fetched overwrite the 'ConfigurationPaymentModuleCreator' instead. Note that the configuration is loaded only once for each request but this function is called every request
 
 GetPaymentStatus
 Signature  public virtual string GetPaymentStatus(PaymentContext context)
 Description   Maps the payment service provider status to a matching Sana commerce status. By default the 'PaymentStatusLookup' table is used for this and status mapping can be changed here
 When to overwrite  If the way the status is mapped needs to be changed it can be changed by overwriting this function. This function will generate a table of status 'translations' and pass it to the 'ResolvePaymentStatus' method
 
 ResolvePaymentStatus
 Signature   protected virtual string ResolvePaymentStatus(string status, string method, IEnumerable<IPaymentStatusLookup> statusLookup)
 Description   Will set the correct Sana commerce status based on the 'translations' table generated by the 'GetPaymentStatus' function
 When to overwrite  This function can be changed if there are exceptions in how certain statuses should be handled that cannot be handled by just changing the translations table
 
 GetPSPPaymentStatus
 Signature   protected virtual string GetPSPPaymentStatus(PaymentContext context)
 Description  Function to get the PSP status from an order, by default it will take the 'status' field from the order. The status of an order should be placed in this field
 When to overwrite  When this logic needs to be changed
 
 GetPSPPaymentMethod
 Signature   protected virtual string GetPSPPaymentMethod(PaymentContext context)
 Description  Like the 'GetPSPPaymentStatus' function this is used to get the payment method as defined by the PSP from the order the same way. Only this time it is stored in the 'method' field
 When to overwrite  When this logic needs to be changed
 
 GetPSPPaymentInformation
 Signature  protected virtual string GetPaymentInformation(IOrder order, string key)
 Description  Internal function to get information from the field values of an order in a safe way
 When to overwrite  In most cases this function will remain the same
 
 BuildPipelines
 Signature   protected virtual void BuildPipelines()
 Description  Base function that will construct all pipelines used by this payment module. It will make calls to the 'BuildCustomPipelines', 'BuildPreProcessPipeline', 'BuildConfirmPipeline', 'BuildPostProcessPipeline' and 'BuildCancelPipeline' functions
 When to overwrite  It is advised to only change these sub-function instead of the 'BuildPipelines' function in order to keep the existing steps in unmodified pipelines. The only exception is when every pipeline is changed and new pipelines are also added
 
 BuildPreProcessPipelines
 Signature   protected virtual IPaymentPipeline BuildPreProcessPipeline()
 Description   Sets up the sets that are done by the 'Pre-Process' pipeline
 When to overwrite  If any steps need to be changed, removed or added this method should be overwritten to return the new pipeline
 
 BuildConfirmPipelines
 Signature   protected virtual IPaymentPipeline BuildConfirmPipeline()
 Description  Sets up the sets that are done by the 'Confirm' pipeline
 When to overwrite  If any steps need to be changed, removed or added this method should be overwritten to return the new pipeline
 
 BuildPostProcessPipelines
 Signature  protected virtual IPaymentPipeline BuildPostProcessPipeline()
 Description  Sets up the sets that are done by the 'Post-Process' pipeline
 When to overwrite  If any steps need to be changed, removed or added this method should be overwritten to return the new pipeline
 
 BuildCancelPipelines
 Signature  protected virtual IPaymentPipeline BuildCancelPipeline()
 Description  Sets up the sets that are done by the 'Cancel' pipeline
 When to overwrite  If any steps need to be changed, removed or added this method should be overwritten to return the new pipeline
 
 BuildCustomPipelines
 Signature  protected virtual List<IPaymentPipeline> BuildCustomPipelines()
 Description  This function will create all child pipelines. These pipelines can be used in steps in the four main pipelines. In the default implementation they are used as pipelines that are executing depending on the status of the order in the confirm pipeline
 When to overwrite  If any of these steps need to be changed or if another child pipeline has to be created, this method needs to be overwritten
 
Note when overwriting the 'BuildCustomPipelines' method be sure to construct all needed pipelines, this also means all pipelines that are now constructed by default. The following code can be copied when customizing:
 
List<IPaymentPipeline> pipeline = new List<IPaymentPipeline>();
 
 //Pipeline executed if paymentstatus is ok
 var okSteps = new IPaymentStep[]
 {     
  //Add steps here
  new PayOrderStep(),     //Set order status to paid
  new DeductStockStep(),  //Deduct the stock from the ordered products
  new SendOrderMailStep(),    //Send an order mail to the user
  new DeleteBasketStep()     //Delete the basket of the user
 };
 pipeline.Add(new PaymentPipeline("StatusOkPipeline", okSteps, false));
 
 var cancelSteps = new IPaymentStep[]
 {     
  //Add steps here
   new CancelOrderStep()
 };
 pipeline.Add(new PaymentPipeline("StatusCancelPipeline", cancelSteps, 
 false));
 
 var pendingSteps = new IPaymentStep[]
 {     
   //Add steps here          
   new PendingOrderStep(),
   new SendOrderMailStep()   
 };
 pipeline.Add(new PaymentPipeline("StatusPendingPipeline",
 pendingSteps, false));
 
 return pipeline;
 
 GetXmlResponseParameter
 Signature  protected virtual NameValueCollection GetXmlReponseParameter(IOrder order)
 Description  This function will be called when the 'PostUsesXML' setting is set to 'true'. It will generate the XML that will be posted to the PSP
 When to overwrite  To change the format of the XML this method should be overwritten. It should return a 'NameValueCollection' with a single value containing the xml field
 
 GetResponseParameter
 Signature  protected virtual NameValueCollection GetReponseParameters(IOrder order)
 Description  Creates a 'NameValueCollection' of all values that have the 'isRequestParameter' set to true
 When to overwrite  Normally this function does not have to be customized
 
 GetRedirectUrl
 Signature  Protected virtual string GenerateRedirectUrl(IOrder order, bool getParameters)
 Description  This function generates the URL that the user will be directed to at the PSP site
 When to overwrite  This can normally be changed by changing the 'PaymentPage Configuration' value and should not have to be customized
 
Custom Configuration Values 
To add custom configuration values to the PSP the 'isRequestParameter' property can be used. Besides the name and value field, each configuration value also has this property. If set to true, the value will be directly sent to the PSP in the request (in hidden form our URL). This way it is easy to add new parameters to the PSP without changing the payment module code. But be sure to only set this parameter to true, if it really needs to be passed to the PSP to prevent cluttering of data.
 
If set to false the configuration value must explicitly be used in the code of the payment module or in one of the steps executed in the module. In this case you will need to write custom code to handle the configuration value. This is easily done the following way:
 
The value of the configuration will be automatically loaded (once the application starts) in the Configuration property of the payment module (as defined in 'IPaymentModule').
 
For example, we add a new configuration setting to a custom module:
 
<add name="CustomValue" value="1" isRequestParameter="false" /> 
 
In the code of the custom module we can then get the value of this configuration setting with the following line:
 
Configuration.Where(value => value.Name = "CustomValue").First().Value;

In external payment pipelines the configuration will be passed into the context object and can then be retrieved in the same way. After that the effect of the new configuration setting can then be defined by the implemented custom code.  
 
How toGeneral