EFTTransactionExtraInfo

Introduction

When implementing EFT integrations it is often required to store additional information on the transaction level. This is different from EFTExtraInfo in the sense that EFTTransactionExtraInfo is intended for information that is not directly tied to a single payment line. This functionality is very similar to the Partner object but is specifically intended to be used for EFT functionality. This way it's possible to have a separation from the data- or functionality that is stored on the partner object.

 

There can only be a single instance of EFTTransactionExtraInfo at any given time and this instance supplied by the active EFTService. he LS One POS will then persist this information in the following way:

  • Serialize- and deserialize as XML so that no information is lost in case the application stops unexpectedly.
  • Saves the information stored on your IEFTTransactionExtraInfo object to the database at the same time that the transaction is saved by the LS One POS.
  • Rebuilds the information from the database when a transaction is rebuilt (e.g. when returning a transaction or reprinting a receipt).

The following diagram shows the flow when a user runs the Authorize card operation to finalize a transaction. This assumes that a customized EFTService has been implemented to communicate with a PSP:

IEFTTransactionExtraInfo interface

Defines an object that is stored on a IRetailTransaction and adds transaction-level information for an EFT integration.

Name Description
XElement ToXml(IErrorLog errorLogger = null) Serializes the contents of this instance to XML and returns it as a XElement
void ToClass(XElement xmlExtraInfo, IErrorLog errorLogger = null) Deserializes xmlExtraInfo and populates this instance with the information
void Insert(IConnectionManager entry, IRetailTransaction retailTransaction) Saves any relevant information to the database. This is called when the transaction is saved into RBOTRANSACTIONTABLE
void Rebuild(IConnectionManager entry, IRetailTransaction retailTransaction)

Called when the transaction has been rebuilt from data from the database. E.g. when returning a transaction or when it's being viewed from the journal. This will rebuild this instance from data from the posted transaction and any other data required from the transaction tables.

 

Implementing IEFTTransactionExtraInfo

Fully implementing and utilizing this functionality requires not only implementing the interface itself but also touching on the following :

  • Returning your instance from your EFTService implementation
  • Adding database table/tables to the database to store the information that you are adding
  • Adding your instance of IEFTTransactionExtraInfo onto the transaction

Below are code samples from the integration made to LS Pay. This is to show how this functionality is implemented in a real-life scenario. Note that this implementation does not utilize the Insert() and Rebuild() methods but you can refer to EFTExtraInfo for how this functionality can be implemented. Both IEFTExtraInfo and the PartnerObject are inserted- and rebuilt in the same manner.

In the case of the LS Pay integration the EFTService is managing information about pre-authorizations on the transaction level. Since pre-authorizations are not tied to a payment line until they are finalized we needed a way of managing this information.

1: Implementing the IEFTTransactionExtraInfo interface

Below is the full implementation from the LS Pay integration to store information about pre-authorizations. The class has a list of PreAuthInfo objects which it can serialize and deserialize so that they persist on the transaction.

public class EFTTransactionExtraInfo : IEFTTransactionExtraInfo
{        

    public List<PreAuthInfo> PreAuthInfoLines { get; set; }

    public EFTTransactionExtraInfo()
    {
        PreAuthInfoLines = new List<PreAuthInfo>();
    }

    public void Insert(IConnectionManager entry, IRetailTransaction retailTransaction)
    {
            
    }

    public void Rebuild(IConnectionManager entry, IRetailTransaction retailTransaction)
    {

    }

    public void ToClass(XElement xmlExtraInfo, IErrorLog errorLogger = null)
    {
        try
        {
            if (xmlExtraInfo.HasElements)
            {
                IEnumerable<XElement> classVariables = xmlExtraInfo.Elements();

                foreach (XElement xVariable in classVariables)
                {
                    if (!xVariable.IsEmpty)
                    {
                        try
                        {
                            PreAuthInfo preAuthInfo = new PreAuthInfo();
                            preAuthInfo.ToClass(xVariable, errorLogger);
                            PreAuthInfoLines.Add(preAuthInfo);
                        }
                        catch (Exception ex)
                        {
                            if (errorLogger != null)
                            {
                                errorLogger.LogMessage(LogMessageType.Error, "LSPay.EFTTransactionExtraInfo:" + xVariable.Name, ex);
                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            if (errorLogger != null)
            {
                errorLogger.LogMessage(LogMessageType.Error, "EFTTransactionExtraInfo.ToClass", ex);
            }

            throw;
        }
    }

    public XElement ToXml(IErrorLog errorLogger = null)
    {
        try
        {
            XElement extraInfoElement = new XElement("EFTTransactionExtraInfo");

            foreach(PreAuthInfo preAuthInfo in PreAuthInfoLines)
            {
                extraInfoElement.Add(preAuthInfo.ToXml(errorLogger));
            }

            return extraInfoElement;
        }
        catch (Exception ex)
        {
            if (errorLogger != null)
            {
                errorLogger.LogMessage(LogMessageType.Error, "EFTTransactionExtraInfo.ToXML", ex);
            }
            throw;
        }
    }        
}

Both Insert and Rebuild are left empty since the information stored does not need to be saved to the database. In both ToXml and ToClass we serialize and deserialize a list of PreAuthInfo objects. For reference the implementation of the PreAuthInfo class is shown below:

/// <summary>
/// Stores information about a live pre-auth request
/// </summary>
public class PreAuthInfo
{
        
    public PreAuthInfo()
    {
        PreAuthTransactionID = "";
        PreAuthEFTTransactionID = "";
        PreAuthAdditionalID = "";
        PreAuthAmount = 0;
        CardNumber = "";
        TransactionDateTime = "";
        CardName = "";
    }

    /// <summary>
    /// The transaction ID assigned to the pre-auth request
    /// </summary>
    public string PreAuthTransactionID { get; set; }

    /// <summary>
    /// The EFT transaction ID returned from LS Pay that was assigned to this pre-auth request
    /// </summary>
    public string PreAuthEFTTransactionID { get; set; }

    /// <summary>
    /// The EFT additional ID returned from LS Pay that was assigned to this pre-auth request
    /// </summary>
    public string PreAuthAdditionalID { get; set; }

    /// <summary>
    /// The card number returned from the LS Pay service. Used for lookup when updating, canceling and finalizing
    /// </summary>
    public string CardNumber { get; set; }

    /// <summary>
    /// The amount that authorized
    /// </summary>
    public decimal PreAuthAmount { get; set; }

    /// <summary>
    /// The transaction date-time returned from the LS Pay service. Used for lookup when updating, canceling and finalizing
    /// </summary>
    public string TransactionDateTime { get; set; }

    /// <summary>
    /// The name of the card issuer returned from the LS Pay service. Used for lookup when updating, canceling and finalizing
    /// </summary>
    public string CardName { get; set; }

    public void ToClass(XElement xmlExtraInfo, IErrorLog errorLogger = null)
    {
        try
        {
            if (xmlExtraInfo.HasElements)
            {
                IEnumerable<XElement> classVariables = xmlExtraInfo.Elements();

                foreach (XElement xVariable in classVariables)
                {
                    if (!xVariable.IsEmpty)
                    {
                        try
                        {
                            switch (xVariable.Name.ToString())
                            {
                                case "PreAuthTransactionID":
                                    PreAuthTransactionID = xVariable.Value;
                                    break;

                                case "PreAuthEFTTransactionID":
                                    PreAuthEFTTransactionID = xVariable.Value;
                                    break;
                                case "PreAuthAdditionalID":
                                    PreAuthAdditionalID = xVariable.Value;
                                    break;

                                case "PreAuthAmount":
                                    PreAuthAmount = Conversion.XmlStringToDecimal(xVariable.Value);
                                    break;

                                case "CardNumber":
                                    CardNumber = xVariable.Value;
                                    break;

                                case "TransactionDateTime":
                                    TransactionDateTime = xVariable.Value;
                                    break;

                                case "CardName":
                                    TransactionDateTime = xVariable.Value;
                                    break;
                            }
                        }
                        catch (Exception ex)
                        {
                            if (errorLogger != null)
                            {
                                errorLogger.LogMessage(LogMessageType.Error, "LSPay.PreAuthInfo:" + xVariable.Name, ex);
                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            if (errorLogger != null)
            {
                errorLogger.LogMessage(LogMessageType.Error, "PreAuthInfo.ToClass", ex);
            }

            throw;
        }
    }

    public XElement ToXml(IErrorLog errorLogger = null)
    {
        try
        {
            return new XElement("PreAuthInfo",
                new XElement("PreAuthTransactionID", PreAuthTransactionID),
                new XElement("PreAuthEFTTransactionID", PreAuthEFTTransactionID),
                new XElement("PreAuthAdditionalID", PreAuthAdditionalID),
                new XElement("PreAuthAmount", Conversion.ToXmlString(PreAuthAmount)),
                new XElement("CardNumber", CardNumber),
                new XElement("TransactionDateTime", TransactionDateTime),
                new XElement("CardName", CardName)
            );
        }
        catch (Exception ex)
        {
            if (errorLogger != null)
            {
                errorLogger.LogMessage(LogMessageType.Error, "PreAuthInfo.ToXML", ex);
            }
            throw;
        }
    }
}

This instance is then created and managed from any appropriate method in the EFTService, BlankOperationsService or from a How to implement a POS Plugin. In the case of the LS Pay integration there is a POS Plugin that calls code in the EFTService to manage the pre-authorization logic. In this sample code below a pre-authorization is being added to the transaction and a new instance of EFTTransactionExtraInfo is created if it does not exist already:

EFTTransactionExtraInfo transactionExtraInfo = retailTransaction.EFTTransactionExtraInfo == null ? new EFTTransactionExtraInfo() : (EFTTransactionExtraInfo)retailTransaction.EFTTransactionExtraInfo;

PreAuthInfo preAuthInfo = new PreAuthInfo();

preAuthInfo.PreAuthTransactionID = response.Ids.TransactionId;
preAuthInfo.PreAuthEFTTransactionID = response.Ids.EFTTransactionId;
preAuthInfo.PreAuthAdditionalID = response.Ids.AdditionalId;
preAuthInfo.PreAuthAmount = response.AmountBreakdown.TotalAmount;
preAuthInfo.CardNumber = response.CardDetails.CardNumber;
preAuthInfo.CardName = response.CardDetails.CardIssuer;
preAuthInfo.TransactionDateTime = response.Ids.TransactionDateTime;

transactionExtraInfo.PreAuthInfoLines.Add(preAuthInfo);

retailTransaction.EFTTransactionExtraInfo = transactionExtraInfo;

POSFormsManager.ShowPOSStatusPanelText(Properties.Resources.PreAuthAdded);

3: Returning EFTExtraInfo from EFTService

In order for the LS One POS to activate this functionality the EFTService implementation has to return the default instance of the implementation instead of a null value. To do this it is enough to just return a new instance:

public IEFTTransactionExtraInfo EFTTransactionExtraInfo => new EFTTransactionExtraInfo();