/// <summary> /// The Payment Method executes the payment Authorisation /// for the received transaction payment amount from the kiosk /// Sends socket inputs to smartpay /// Sends the Authorisation response value out /// if Authorisation is successful waits for an order number /// if Order number is valid from a transaction thats goes through /// run the settlement process or if transaction result not valid /// void the transaction. /// sends out the transaction reciepts to the payment service /// </summary> /// <param name="amount"></param> /// <param name="transactionRef"></param> /// <param name="transactionReceipts"></param> /// <returns></returns> public DiagnosticErrMsg Pay(int amount, string transactionRef, out TransactionReceipts transactionReceipts) { XDocument paymentXml = null; XDocument procTranXML = null; XDocument customerSuccessXML = null; XDocument processTransRespSuccessXML = null; XDocument finaliseXml = null; XDocument voidXml = null; XDocument finaliseSettleXml = null; XDocument paymentSettlementXml = null; XDocument procSettleTranXML = null; int intAmount; isSuccessful = DiagnosticErrMsg.OK; transactionReceipts = new TransactionReceipts(); //check for a success or failure string from smartpay string submitPaymentResult = string.Empty; string finaliseResult = string.Empty; string finaliseSettleResult = string.Empty; string submitSettlePaymentResult = string.Empty; string description = transactionRef; // increment transaction number number++; transNum = number.ToString().PadLeft(6, '0'); //check for transNum max value if (transNum == transactionLimit) { //reset back to beginning number = 1; transNum = number.ToString().PadLeft(6, '0'); } //check amount is valid intAmount = Utils.GetNumericAmountValue(amount); if (intAmount == 0) { throw new Exception("Error in Amount value..."); } Log.Info($"Valid payment amount: {intAmount}"); Log.Info("Transaction Number : " + transNum); Log.Info("Transaction Ref (Description) : " + transactionRef); /*********************** AUTHORISATION SECTION *************************** * * Submittal – Submitting data to Smartpay Connect ready for processing. * SUBMIT PAYMENT Process * *************************************************************************/ //process Payment XML paymentXml = smartpayOps.Payment(amount, transNum, description, sourceId, currency, country); Socket paymentSocket = CreateSocket(); Log.Info("paymentSocket Open: " + SocketConnected(paymentSocket)); //send submitpayment to smartpay - check response string paymentResponseStr = sendToSmartPay(paymentSocket, paymentXml, "SUBMITPAYMENT"); //check response from Smartpay is not Null or Empty if (CheckIsNullOrEmpty(paymentResponseStr, "Submit Authorisation Payment")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { //check response outcome submitPaymentResult = CheckResult(paymentResponseStr); if (submitPaymentResult.ToLower() == "success") { Log.Info("Successful payment submitted"); } else { Log.Error("Payment failed"); isSuccessful = DiagnosticErrMsg.NOTOK; } } //checkSocket closed Log.Info("paymentSocket Open: " + SocketConnected(paymentSocket)); /************************************************************************************ * * * Transactional – Processing of a transaction submitted during the submittal phase. * * PROCESSTRANSACTION process - gets the Merchant receipt * * * *************************************************************************************/ //create processtransaction socket Socket processSocket = CreateSocket(); Log.Info("ProcessTransaction Socket Open: " + SocketConnected(processSocket)); //Process Transaction XML procTranXML = smartpayOps.ProcessTransaction(transNum); //send processTransaction - check response string processTranReturnStr = sendToSmartPay(processSocket, procTranXML, "PROCESSTRANSACTION"); //check response from Smartpay is not NULL or Empty if (CheckIsNullOrEmpty(processTranReturnStr, "Process Transaction")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { //check that the response contains a Receipt or is not NULL this is the Merchant receipt transactionReceipts.MerchantReturnedReceipt = ExtractXMLReceiptDetails(processTranReturnStr); //Check the merchant receipt is populated if (CheckIsNullOrEmpty(transactionReceipts.MerchantReturnedReceipt, "Merchant Receipt populated")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { //check if reciept has a successful transaction if (transactionReceipts.MerchantReturnedReceipt.Contains("DECLINED")) { Log.Error("Merchant Receipt has Declined Transaction."); isSuccessful = DiagnosticErrMsg.NOTOK; } } } //check socket closed Log.Info("ProcessTransaction Socket Open: " + SocketConnected(processSocket)); /****************************************************************************** * * * Interaction – Specific functionality for controlling POS and PED behaviour. * * gets the Customer receipt * * * *******************************************************************************/ //create customer socket Socket customerSuccessSocket = CreateSocket(); Log.Info("customerSuccess Socket Open: " + SocketConnected(customerSuccessSocket)); //process customerSuccess XML customerSuccessXML = smartpayOps.PrintReciptResponse(transNum); string customerResultStr = sendToSmartPay(customerSuccessSocket, customerSuccessXML, "CUSTOMERECEIPT"); //Check response from Smartpay is not Null or Empty if (CheckIsNullOrEmpty(customerResultStr, "Customer Receipt process")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { transactionReceipts.CustomerReturnedReceipt = ExtractXMLReceiptDetails(customerResultStr); //check returned receipt is not Null or Empty if (CheckIsNullOrEmpty(transactionReceipts.CustomerReturnedReceipt, "Customer Receipt returned")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { //check if reciept has a successful transaction if (transactionReceipts.CustomerReturnedReceipt.Contains("DECLINED")) { Log.Error("Customer Receipt has Declined Transaction."); isSuccessful = DiagnosticErrMsg.NOTOK; } } } Log.Info("customerSuccess Socket Open: " + SocketConnected(customerSuccessSocket)); /*********************************************************************************************************** * Interaction – Specific functionality for controlling PoS and PED behaviour. ( ProcessTransactionResponse) * PROCESSTRANSACTIONRESPONSE *************************************************************************************************************/ Socket processTransactionRespSocket = CreateSocket(); Log.Info("processTransactionRespSocket Socket Open: " + SocketConnected(processTransactionRespSocket)); processTransRespSuccessXML = smartpayOps.PrintReciptResponse(transNum); string processTransRespStr = sendToSmartPay(processTransactionRespSocket, processTransRespSuccessXML, "PROCESSTRANSACTIONRESPONSE"); //check response from Smartpay is not Null or Empty if (CheckIsNullOrEmpty(processTransRespStr, "Process Transaction Response")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { //get the reference value from the process Transaction Response // this is needed for the settlement process // reference = GetReferenceValue(processTransRespStr); Log.Info($"REFERENCE Number = {reference}"); if (processTransRespStr.Contains("declined")) { Log.Error("***** Auth Process Transaction Response has Declined Transaction. *****"); isSuccessful = DiagnosticErrMsg.NOTOK; } } Log.Info("processTransRespSuccessXML Socket Open: " + SocketConnected(processTransactionRespSocket)); /***************************************************************************************************************** * * finalise Response message so that the transaction can be finalised and removed from Smartpay Connect's memory * * FINALISE ******************************************************************************************************************/ Socket finaliseSocket = CreateSocket(); Log.Info("Finalise Socket Open: " + SocketConnected(finaliseSocket)); finaliseXml = smartpayOps.Finalise(transNum); string finaliseStr = sendToSmartPay(finaliseSocket, finaliseXml, "FINALISE"); //check response from Smartpay is not Null or Empty if (CheckIsNullOrEmpty(finaliseStr, "Finalise Authorisation")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { finaliseResult = CheckResult(finaliseStr); if (finaliseResult == "success") { Log.Info("****** Authorisation Transaction Finalised Successfully******"); } else { Log.Info("***** Authorisation Transaction not Finalised *****"); isSuccessful = DiagnosticErrMsg.NOTOK; } } Log.Info("Finalise Socket Open: " + SocketConnected(finaliseSocket)); /***************************************************************************************************************** * * check if the Authorisation has been successful * ******************************************************************************************************************/ if (isSuccessful == DiagnosticErrMsg.OK) { authorisationFlag = true; } else { authorisationFlag = false; isSuccessful = DiagnosticErrMsg.NOTOK; } /* ********************************************************************** * * if Authorisation check successful carry on else * end Authorisation and close database connection * ******************************************************************/ if (authorisationFlag == false) { //authoriation has failed return to paymentService //end payment process and print out failure receipt. Log.Error("\n***** Authorisation Check has failed. *****\n"); return(DiagnosticErrMsg.NOTOK); } else { Log.Info("\n\n***** Payment Authorisation Check has passed. Get Order Number. *****\n"); } /************************************************************************************************* * AUTHORISATION check has passed run the APIS and get back the OrderNumber from the Flyt system * * Need to run the APIs MarkAsPaid and SendToPOS * **************************************************************************************************/ using (SqlConnection con = new SqlConnection()) { con.ConnectionString = connectionString; con.Open(); CallStoredProcs storedProcs = new CallStoredProcs(); Log.Info("RefInt = " + transactionRef); /********************************************** * Get BasketID and OrderId using RefInt * *********************************************/ Log.Info("tableName = " + tableName); SqlCommand comm = new SqlCommand($"SELECT ID, APIOrderID from { tableName } where KioskRefInt = {Convert.ToInt32(transactionRef)}", con); using (SqlDataReader reader = comm.ExecuteReader()) { while (reader.Read()) { basketId = reader.GetInt32(0); orderId = reader.GetString(1); } } Log.Info($"BasketId = {basketId}"); Log.Info($"OrderId = {orderId}"); //1) call stored procedure OrderBasket_API_MarkAsPaid to get Payload for API Call payLoad = storedProcs.ExecuteOrderBasket_API_MarkAsPaid(con, basketId); //2) call MarkAsPaid API with the generated PayLoad //IRestResponse markAsPaidResp = storedProcs.MarkAsPaidAPI(orderId, payLoad); string url = orderURL + "/" + orderId + markAsPaidURL; IRestResponse markAsPaidResp = storedProcs.ApiPost(url, keyType2, aPIKey2, contentType, payLoad); if (markAsPaidResp.IsSuccessful) { //3) call stored procedure OrderBasket_APIResponse_MarkAsPaid to check response of API Call storedProcs.ExecuteOrderBasket_APIResponse_MarkAsPaid(con, basketId, markAsPaidResp.Content); Log.Info($"MarkAsPaid return = {markAsPaidResp.Content}"); //4) Call stored procedure OrderBasket_API_SendToPos to get PayLoad to use in API call payLoad = string.Empty; payLoad = storedProcs.ExecuteOrderBasket_API_SendToPos(con, basketId); //5) Call SendToPos API with the generated PayLoad //IRestResponse sendToPOSResp = storedProcs.SendToPOSAPI(payLoad); //IRestResponse sendToPOSResp = storedProcs.SendToPOSAPI(orderId); IRestResponse sendToPOSResp = storedProcs.ApiPost(sendToPOSURL, keyType1, aPIKey1, contentType, payLoad); if (sendToPOSResp.IsSuccessful) { //6) call stored procedure OrderBasket_APIResponse_SendToPos to check response from API storedProcs.ExecuteOrderBasket_APIResponse_SendToPos(con, basketId, sendToPOSResp.Content); //get PosOrderNumber //dynamic sendToPOS = JsonConvert.DeserializeObject<dynamic>(sendToPOSResp.Content); //posOrderId = sendToPOS.Data.PosOrderID; //Log.Info($"Order Number returned: {posOrderId}"); // Create and configure a command object to get the PosOrderID SqlCommand com = con.CreateCommand(); com.CommandType = CommandType.StoredProcedure; com.CommandText = "OrderBasket_APIPosOrderID_ByID"; com.Parameters.Add("@OrderBasketID", SqlDbType.VarChar).Value = basketId; var result = com.ExecuteScalar(); posOrderId = result.ToString(); } else { posOrderId = null; isSuccessful = DiagnosticErrMsg.NOTOK; Log.Error($"SendToPOS API Failed = {markAsPaidResp.Content}"); } } else { Log.Error("MarkAsPaid API Failed"); isSuccessful = DiagnosticErrMsg.NOTOK; } } /******************************************************************************** * * Submittal using settlement Reference * * ******************************************************************************/ if (string.IsNullOrEmpty(posOrderId)) { Log.Error("\n*** No order number returned the Transaction will be voided **************\n"); } /************************************************************************************ * * Check the transaction returns an order number and settle the transaction * if not void the transaction * * **********************************************************************************/ if ((isSuccessful == DiagnosticErrMsg.OK) && (authorisationFlag == true) && (!(string.IsNullOrEmpty(posOrderId)))) { /**************************************************************************** * Submittal using settlement Reference, amount , transNum * description which is the transaction reference * * Submit Settlement Payment ****************************************************************************/ Log.Info("\n******Performing Settlement Payment ******\n"); paymentSettlementXml = smartpayOps.PaymentSettle(amount, transNum, reference, description, currency, country); // open paymentXml socket connection Socket paymenSettlementSocket = CreateSocket(); //check socket open Log.Info("Paymentsocket Open: " + SocketConnected(paymenSettlementSocket)); //send submitpayment to smartpay - check response string paymentSettleResponseStr = sendToSmartPay(paymenSettlementSocket, paymentSettlementXml, "SUBMITPAYMENT"); //check response from Smartpay is not Null or Empty if (CheckIsNullOrEmpty(paymentSettleResponseStr, "Settlement Payment")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { submitSettlePaymentResult = CheckResult(paymentSettleResponseStr); if (submitSettlePaymentResult == "success") { Log.Info("******Successful Settlement Payment submitted******\n"); } else { Log.Error("****** Settlement Payment failed******\n"); isSuccessful = DiagnosticErrMsg.NOTOK; } } Log.Info("paymenSettlementSocket Open: " + SocketConnected(paymenSettlementSocket)); /**************************************************************************** * Process the settlement transaction * * * *****************************************************************************/ Socket processSettleSocket = CreateSocket(); Log.Info("processSettleSocket Socket Open: " + SocketConnected(processSettleSocket)); procSettleTranXML = smartpayOps.ProcessTransaction(transNum); //send processTransaction - check response string processSettleTranResponseStr = sendToSmartPay(processSettleSocket, procSettleTranXML, "PROCESSSETTLETRANSACTION"); //check response from Smartpay is not Null or Empty if (CheckIsNullOrEmpty(processSettleTranResponseStr, "Process Settlement Transaction")) { isSuccessful = DiagnosticErrMsg.NOTOK; } //No response needed Log.Info("processSettleSocket Socket Open: " + SocketConnected(processSettleSocket)); /**************************************************************************** * Procees the Settlement finalise transaction * * * *****************************************************************************/ Socket finaliseSettSocket = CreateSocket(); Log.Info("Finalise Socket Open: " + SocketConnected(finaliseSettSocket)); finaliseSettleXml = smartpayOps.Finalise(transNum); //check response string finaliseSettleStr = sendToSmartPay(finaliseSettSocket, finaliseSettleXml, "FINALISE"); if (CheckIsNullOrEmpty(finaliseSettleStr, "Settlement Finalise")) { isSuccessful = DiagnosticErrMsg.NOTOK; } else { finaliseSettleResult = CheckResult(finaliseSettleStr); if (finaliseSettleResult == "success") { Log.Info("******Transaction Settle Finalised successfully******\n"); } else { Log.Error("****** Transaction Settle not Finalised ******\n"); isSuccessful = DiagnosticErrMsg.NOTOK; } } Log.Info("Finalise Socket Open: " + SocketConnected(finaliseSettSocket)); /***************************************************************************** * Update the OrderBasket Table with the PosOrderID number * * * *****************************************************************************/ if (isSuccessful == DiagnosticErrMsg.OK) { //add the order number and the VAT to the reciepts //using (SqlConnection con = new SqlConnection()) //{ // con.ConnectionString = connectionString; // con.Open(); // // Create and configure a command object // SqlCommand com = con.CreateCommand(); // com.CommandType = CommandType.StoredProcedure; // com.CommandText = "OrderBasket_APIPosOrderID_ByID"; // com.Parameters.Add("@OrderBasketID", SqlDbType.VarChar).Value // = basketId; // var result = com.ExecuteScalar(); // Int32 OrderBasketId = Int32.Parse(result.ToString()); // posOrderId = Convert.ToString(OrderBasketId); //} int position = transactionReceipts.CustomerReturnedReceipt.IndexOf("Please"); if (position >= 0) { //Add TAX Values and order number // transactionReceipts.CustomerReturnedReceipt = transactionReceipts.CustomerReturnedReceipt.Insert(position, taxValues); transactionReceipts.CustomerReturnedReceipt = transactionReceipts.CustomerReturnedReceipt.Insert(0, "Order Number: " + posOrderId + "\n"); } } } else { //////////////////////// // void the transaction //////////////////////// Socket voidSocket = CreateSocket(); Log.Info("void Socket Open: " + SocketConnected(voidSocket)); voidXml = smartpayOps.VoidTransaction(transNum, sourceId, transactionRef); string voidResponseStr = sendToSmartPay(voidSocket, voidXml, "VOID"); //success is not OK isSuccessful = DiagnosticErrMsg.NOTOK; Log.Info("void Socket Open: " + SocketConnected(voidSocket)); } return(isSuccessful); }