Years of experience in processing payments have taught us an important lesson. When you interface with our API it is well worth the effort to create a very simple standard logging utility. Since we are dealing with payments and other peoples money, it is highly recommended that you leave a trail of breadcrumbs just in case issues arise which are outside of your control. These occasional issues can frustrate the normal payment process and can make it difficult to research ways to fix them.
You should make a call to the logging function after each interaction with Easy Pay and send important Easy Pay values.
This is an example of calling our logging function after authentication:
private void Authenticate ( string AcctCode , string Token) { CardProc.api_AuthResponse AuthResp; CardProc.CardProcessClient CardClient = new CardProc.CardProcessClient(); try { AuthResp = CardClient.Authenticate( AcctCode , Token); } catch(Exception ee) { Cursor.Current = Cursors.Default; MessageBox.Show("Problem communicating with EasyPay service:" + ee.Message); // log the result EasyPayLogging.WriteEasyPayResponse("Authenticate", false, false, "Network Error " + ee.Message,900900, "Exception Encountered on Authentication Call"); return; } if (AuthResp == null) { Cursor.Current = Cursors.Default; MessageBox.Show("Critical Error , Null response From EasyPay"); // log the result EasyPayLogging.WriteEasyPayResponse("Authenticate", false, false, "Null Response", 911911, "Null Response on Authentication Call"); return; } // log the result and continue processing EasyPayLogging.WriteEasyPayResponse("Authenticate", "AuthResp.FunctionOK", AuthResp.AuthSuccess, AuthResp.RespMsg, AuthResp.ErrCode, AuthResp.ErrMsg); if (!AuthResp.FunctionOk) { // determine errors and abort string ErrMsg = AuthResp.ErrMsg; return; } if (!AuthResp.AuthSuccess) { // determine reason for failed Authentication string Reason = AuthResp.RespMsg; return; } /// success !! string SessionKey = AuthResp.SessKey; }
This is an example of calling our logging function after processing a card-on-file:
private void ProcessCardOnFile ( string SessKey , int ConsentID , decimal Amt) { CardProc.api_CCSaleResponse SaleResp; CardProc.CardProcessClient CardClient = new CardProc.CardProcessClient(); try { SaleResp = CardClient.ConsentAnnual_ProcPayment(SessKey, ConsentID, Amt); } catch(Exception ee) { Cursor.Current = Cursors.Default; MessageBox.Show("Error:" + ee.Message); // log the result EasyPayLogging.WriteEasyPayResponse("ConsentAnnual_ProcPayment", false, false, "Network Error " + ee.Message,900900, "Exception Encountered on ConsentAnnual_ProcPayment"); return; } Cursor.Current = Cursors.Default; if (SaleResp == null) { MessageBox.Show("Critical Error"); // log the result EasyPayLogging.WriteEasyPayResponse("ConsentAnnual_ProcPayment", false, false, "Null Response", 911911, "Null Response on ConsentAnnual_ProcPayment"); return; } // log the result and continue processing EasyPayLogging.WriteEasyPayResponse("ConsentAnnual_ProcPayment", "SaleResp.FunctionOk, SaleResp.TxApproved, SaleResp.RespMsg, SaleResp.ErrCode, SaleResp.ErrMsg); if (!SaleResp.FunctionOk) { // determine errors and abort string ErrMsg = SaleResp.ErrMsg;; return; } if (!SaleResp.TxApproved) { // determine reason for failed Authentication string Reason = SaleResp.RespMsg; string DeclineCode = SaleResp.TxnCode return; } /// success !! /// int TXID = SaleResp.TxID; string ApprovalCode = SaleResp.TxnCode; }
This is a example of A Logging Class:
using System; using System.IO; namespace WinFormAPItest
{ public static class EasyPayLogging { private static readonly object locker = new object(); public static bool WriteEasyPayResponse( string APIcallName , bool FunctionOK , bool IsSuccess, string RespMsg , int ErrorCode , string ErrMsg) { try { if (string.IsNullOrEmpty(RespMsg)) { RespMsg = "NA"; } if (string.IsNullOrEmpty(ErrMsg)) { ErrMsg = "NA"; } string Mypath = "C:\\Logs\\EasyPay\\"; string MyMonthlyFileName = DateTime.Now.Year.ToString("D4") + "_" + DateTime.Now.Month.ToString("D2") + "_EasyPayLogFile.txt"; string timeStamp = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.ff"); string message = timeStamp + "," + APIcallName + "," + FunctionOK.ToString() + "," + IsSuccess.ToString() + "," + RespMsg + "," + ErrorCode.ToString() + "," + ErrMsg; bool fileExists = File.Exists(Mypath + MyMonthlyFileName); lock (locker) { StreamWriter SW; /// place a header in each monthly log file at the beginning of the month if (!File.Exists(Mypath + MyMonthlyFileName)) { SW = File.AppendText(Mypath + MyMonthlyFileName); SW.WriteLine("Timestamp,APIcallName,FunctionOK,IsSuccess,RespMsg,ErrorCode,ErrMsg"); SW.WriteLine(message); } else { SW = File.AppendText(Mypath + MyMonthlyFileName); SW.WriteLine(message); } SW.Close(); } return true; } catch (Exception ee) { return false; } } }
}
This is what the logging output might look like for the logging file named: 2020_10_EasyPayLogFile.txt
Timestamp,APIcallName,FunctionOK,IsSuccess,RespMsg,ErrorCode,ErrMsg
2020/10/30 10:48:21.23,Authenticate,True,False,Invalid API Token,0,NA
2020/10/30 10:48:28.53,Authenticate,True,True,SessKey Expires|10/31/2020 10:48:28 AM,0,NA
2020/10/30 10:49:28.00,CreditCardSale_Manual,True,True,APPROVED TAS251,0,NA
2020/10/30 10:49:33.62,CreditCardSale_Manual,True,False,DECLINED N7 : CVV2 MISMATCH,0,NA
2020/10/30 10:49:38.63,CreditCardSale_Manual,False,False,NA,6660,ERROR:6660:HIGH:Current Account settings require a valid accountholder Last Name
2020/10/30 10:49:49.55,CreditCardSale_Manual,True,True,APPROVED TAS263,0,NA