Introduction
EMV (Europay, MasterCard, and Visa) is a set of standards for the use of payment chip cards (those with an embedded microprocessor). The microprocessor within a payment chip card provides strong security features and other capabilities not possible with traditional magnetic stripe cards.
Prior to October of 2015, most counterfeit card fraud that occurred at business’ in-store locations, liability was with the card issuers. Since October 2015 that liability has shifted to the merchants in certain cases unless they have replaced or upgraded their card acceptance and processing systems to use chip-enabled devices and applications to process payment transactions.
Background
Chip-enabled credit (and debit) cards have been issued by almost every card issuer in the United States and they have become very common. It used to be a card with a magnetic stripe that you could swipe to process. Chip-Enabled cards require special hardware for card reading and transaction verification.
I developed multiple point of sale systems for both retail and restaurant and was among the first developers to fully integrate PAX S300 pin pads into .NET applications.
I will show methods that allow you to process a credit card, adjust the transaction amount, void a transaction and finally close a batch.
Using POSLink
In order to use this code, you will not have PAX POSLink API. Visit the PAX website and apply for an account and you will receive a copy of POSLink class.
I walk you through the following steps:
- Communication settings
- Log management
- Payment request and payment response
- Batch request and response
1- Set Communication Parameters
POSLink class communicates with the Pin pad (or credit card terminal) via:
- Ethernet
- RS232
- Bluetooth
Let’s start by CommSetting class and its constructor:
Communication settings are stored in commsetting.ini.
commsetting.ini has the following structure:
[COMMUNICATE]PORT=10009
IP=10.1.10.4
SERIALPORT=COM1
TIMEOUT=30000
CommType=TCP
public void SaveSettings()
{
POSLink.PosLink cg = new POSLink.PosLink();
CommSetting commSetting = new CommSetting();
try
{
commSetting.CommType = "TCP";
commSetting.TimeOut = "60000";
commSetting.SerialPort = "COM1";
commSetting.DestIP = "10.1.10.4";
commSetting.DestPort = "10009";
commSetting.saveFile();
//save the setting into file, therefore other classes will use the setting communication
cg.CommSetting = commSetting;
}
catch (Exception e)
{
MessageBox.Show("{0} Exception caught.", e.ToString());
}
}
2- Set Log Management Parameters
The log management parameters are stored in LogSetting.ini . We manage LogSetting.ini with LogManagement class:
[LOGSETTING]LOGSWITCH=1 (1: ON 0: OFF)
LOGFILEPATH= (Log file location)
LOGFILENAME= (Log file name)
LOGDAYS=30
LOGLEVEL=1 (1: Debug 0: Error)
POSLink.PosLink paxProcess = new PosLink();
POSLink.PaymentRequest paxRequest = new PaymentRequest();
//Initialize PaymentRequest
paxRequest.TenderType = 1;
paxRequest.TransType = 2;
paxRequest.ECRRefNum= txtInv.Text;
payAmount = Math.Round(Decimal.Parse(txtPayment.Text) * 100, 0);
paxRequest.Amount = payAmount.ToString();
paxRequest.InvNum = txtInv.Text;
paxProcess.PaymentRequest = paxRequest;
3 – PaymentRequest and PaymentResponse
PaymentRequest () Initializes a PaymentRequest object. This constructor has several properties but we need to values for the followings:
- TenderType
ALL = 0
CREDIT = 1
DEBIT = 2
- TransType
AUTH =1 Verify/Authorize a transaction. Do not put add it to the batch.
SALE = 2 To make a purchase with a card or e-check/ACH with a check. Adds the transaction to the current open batch.
RETURN = 3 Returns transaction amount to the card.
VOID = 4 Void/Reverse a transaction while still in an unsettled batch.
- ECRRefNum
This is a unique code on the ECR side. for instance, you can use an invoice number.
POSLink.PosLink paxProcess = new PosLink();
POSLink.PaymentRequest paxRequest = new PaymentRequest();
//Initialize PaymentRequest
paxRequest.TenderType = 1;
paxRequest.TransType = 2;
paxRequest.ECRRefNum= txtInv.Text;
payAmount = Math.Round(Decimal.Parse(txtPayment.Text) * 100, 0);
paxRequest.Amount = payAmount.ToString();
paxRequest.InvNum = txtInv.Text;
paxProcess.PaymentRequest = paxRequest;
4- PaymentResponse Class
This class with its paymentresponse() constructor provides us with returned values from the PAX terminal after a transaction has been commenced by paymentrequest() constructor:
ResultCode : This is the transaction’s result code.
Now we can build our method to use all of the above and process a SALE transaction:
private void ProcessCredit()
{
POSLink.PosLink paxProcess = new PosLink();
POSLink.PaymentRequest paxRequest = new PaymentRequest();
CommSetting paxSettings = new CommSetting();
POSLink.LogManagement paxLog = new LogManagement();
IniParser.FileIniDataParser paxParser = new FileIniDataParser();
var parser = new FileIniDataParser();
IniData data = parser.ReadFile("commsetting.ini");
decimal payAmount;
string cardLast4;
string cardName;
string payRef;
string payAuth;
//Initialize Settings
paxSettings.DestIP = data["COMMUNICATE"]["IP"];
paxSettings.CommType = data["COMMUNICATE"]["CommType"];
paxSettings.DestPort = data["COMMUNICATE"]["PORT"];
paxSettings.TimeOut = data["COMMUNICATE"]["TIMEOUT"];
paxProcess.CommSetting = paxSettings;
//Initialize PaymentRequest
paxRequest.TenderType = 1;
paxRequest.TransType = 2;
paxRequest.ECRRefNum= txtInv.Text;
payAmount = Math.Round(Decimal.Parse(txtPayment.Text) * 100, 0);
paxRequest.Amount = payAmount.ToString();
paxRequest.InvNum = txtInv.Text;
paxProcess.PaymentRequest = paxRequest;
//Initialize log management
paxLog.LogSwitchMode = true;
paxLog.LogLevel = 1;
paxLog.LogFilePath = Application.LocalUserAppDataPath;
paxProcess.LogManageMent = paxLog;
//Launch it
ProcessTransResult result = paxProcess.ProcessTrans();
if (result.Code == POSLink.ProcessTransResultCode.OK)
{
POSLink.PaymentResponse paymentResponse = paxProcess.PaymentResponse;
if (paymentResponse != null && paymentResponse.ResultCode != null)
{
lblMsg.Text = paymentResponse.ResultTxt;
cardLast4 = paymentResponse.BogusAccountNum;
payAuth = paymentResponse.AuthCode;
payRef = paymentResponse.RefNum;
}
else
{
MessageBox.Show("Unknown error: paxProcess.PaymentResponse is null.");
}
RegisterCard();
}
else if (result.Code == POSLink.ProcessTransResultCode.TimeOut)
{
lblMsg.Text = "Action Timeout.";
}
else
{
lblMsg.Text = result.Msg;
}
this.Focus();
}
5- BatchRequest Class
BatchRequest() constructor initializes a BatchRequest object.
The only required property is the TransType:
BATCHCLOSE = 1 – Closes the currently open batch.
FORCEBATCHCLOSE = 2 – Force closes the currently open batch, if supported by the host.
BATCHCLEAR = 3 – Clears the local database on the PAX device.
POSLink.PosLink paxProcess = new PosLink();
POSLink.BatchRequest paxBatch = new BatchRequest();
//Initialize Batch
paxBatch.TransType = 1; ‘ Close the current batch
paxBatch.EDCType = 0; ‘Close all transaction types (Credit, debit,..)
paxProcess.BatchRequest = paxBatch;
//Launch it
ProcessTransResult result = paxProcess.ProcessTrans();
if (result.Code == POSLink.ProcessTransResultCode.OK)
{
BatchResponse r = paxProcess.BatchResponse;
lblMsg.Text = r.ResultTxt;
}
else if (result.Code == POSLink.ProcessTransResultCode.TimeOut)
{
lblMsg.Text = "Action Timeout.";
}
else
{
lblMsg.Text = result.Msg;
}
Integration into PAX payment terminals is relatively simple and you can activate more options, such contactless payments, which enables ApplePay and other payment types.
I believe life is too short to ignore learning a programming language!