public static Iso8583Message ProcessIncommingMessage(int sourceId, Iso8583Message originalMessage) { SourceNode sourceNode = new SourceNodeRepository().Get(sourceId); //Configure Original Data Element DateTime transmissionDate = DateTime.UtcNow; //Configuring the original data element (intended for transaction matching (e.g. to identify a transaction for correction or reversal) //consists of 5 data elements: MTI (1-4), STAN (5-10), Date&Time (11-20), AcquirerInsttutionCode (21-31), ForwardingInstCode(32-42) string transactionDate = string.Format("{0}{1}", string.Format("{0:00}{1:00}", transmissionDate.Month, transmissionDate.Day), string.Format("{0:00}{1:00}{2:00}", transmissionDate.Hour, transmissionDate.Minute, transmissionDate.Second)); //string originalDataElement = $"{originalMessage.MessageTypeIdentifier}{originalMessage.Fields[11]}{transactionDate}"; string originalDataElement = originalMessage.MessageTypeIdentifier.ToString() + originalMessage.Fields[11] + transactionDate; //if the originalDataElement is empty (for non-reversal), add it if (!(originalMessage.Fields.Contains(MessageField.ORIGINAL_DATA_ELEMENT_FIELD))) { originalMessage.Fields.Add(MessageField.ORIGINAL_DATA_ELEMENT_FIELD, originalDataElement); } MessageLogger.LogMessage("Validating message..."); //check if it's a reversal message if (originalMessage.MessageTypeIdentifier == MTI.REVERSAL_ADVICE || originalMessage.MessageTypeIdentifier == MTI.REPEAT_REVERSAL_ADVICE) { MessageLogger.LogMessage("\nReversal message!"); //confirm that this transaction actually needs to be reversed bool isReversal; Iso8583Message reversalMessage = GetReversalMessage(originalMessage, out isReversal); if (!isReversal) { MessageLogger.LogMessage("Invalid Reversal transaction"); return(reversalMessage); } //continue if it's a reversal message originalMessage = reversalMessage; } string cardPan = originalMessage.Fields[MessageField.CARD_PAN_FIELD].ToString(); decimal amount = Convert.ToDecimal(originalMessage[MessageField.AMOUNT_FIELD].Value); //The amount is in kobo string channelCode = originalMessage.Fields[MessageField.CHANNEL_ID_FIELD].Value.ToString().Substring(0, 2); string tTypeCode = originalMessage.Fields[MessageField.TRANSACTION_TYPE_FIELD].Value.ToString().Substring(0, 2); //first two positions for the transaction type string expiryDate = originalMessage.Fields[MessageField.EXPIRY_DATE_FIELD].Value.ToString(); DateTime expiryDateOfCard = ConvertToDateTime(expiryDate); Iso8583Message responseMessage; //rsponse message to return after performing some checks if (expiryDateOfCard <= DateTime.Now) //card expired { responseMessage = SetReponseMessage(originalMessage, ResponseCode.EXPIRED_CARD.ToString()); MessageLogger.LogMessage("Expired card"); return(responseMessage); } //check the amount, only for balance enq should the amount be zero if (amount <= 0 && tTypeCode != TransactionTypeCode.BALANCE_ENQUIRY.ToString()) { responseMessage = SetReponseMessage(originalMessage, ResponseCode.INVALID_AMOUNT.ToString()); //Invalid amount MessageLogger.LogMessage("Invalid Amount"); return(responseMessage); } Combo theCombo = null; Scheme theScheme = null; var sourceNodeSchemes = sourceNode.Schemes; string pan = originalMessage.Fields[MessageField.CARD_PAN_FIELD].Value.ToString(); var route = new RouteRepository().GetByCardPAN(pan.Substring(0, 6)); if (route == null) { MessageLogger.LogMessage("Route is null."); responseMessage = SetReponseMessage(originalMessage, ResponseCode.ROUTING_ERROR.ToString()); return(responseMessage); } //get the sourcenode by the route theScheme = sourceNodeSchemes.Where(s => s.RouteId == route.FirstOrDefault().Id).FirstOrDefault(); if (theScheme == null) { MessageLogger.LogMessage("No such secheme"); responseMessage = SetReponseMessage(originalMessage, ResponseCode.TRANSACTION_NOT_PERMITTED_ON_TERMINAL.ToString()); return(responseMessage); } theCombo = theScheme.Combos.Where(c => c.TransactionType.Code.Equals(tTypeCode) && c.Channel.Code.Equals(channelCode)).FirstOrDefault(); if (theCombo == null) //of course, scheme also = null { MessageLogger.LogMessage("Invalid transaction type-channel-fee combo"); responseMessage = SetReponseMessage(originalMessage, ResponseCode.TRANSACTION_NOT_PERMITTED_ON_TERMINAL.ToString()); // Transaction not allowed on terminal return(responseMessage); } var sinkNnode = route.FirstOrDefault().SinkNode; if (sinkNnode == null) { MessageLogger.LogMessage("Sink node is null."); responseMessage = SetReponseMessage(originalMessage, ResponseCode.ISSUER_OR_SWITCH_INOPERATIVE.ToString()); return(responseMessage); } //At this point, everything is assumed to be okay Fee fee = theCombo.Fee; if (fee == null) { MessageLogger.LogMessage("Unacceptable transaction fee"); responseMessage = SetReponseMessage(originalMessage, ResponseCode.UNACCEPTABLE_TRANSACTION_FEE.ToString()); // Transaction type not allowed in this scheme return(responseMessage); } //calculate the transaction fee and embed in the message originalMessage = SetTransactionFee(originalMessage, ComputeFee(fee, amount)); var clientPeer = Program.ClientPeers.Where(p => p.Name.Equals(theScheme.Route.SinkNode.Id.ToString())).FirstOrDefault(); if (clientPeer == null) { MessageLogger.LogMessage("Clientpeer is null"); originalMessage = SetReponseMessage(originalMessage, ResponseCode.ISSUER_OR_SWITCH_INOPERATIVE.ToString()); return(originalMessage); } //////// Iso8583Message replyFromFEP = SendMessageToFEP(clientPeer, originalMessage); //sends message to the client return(replyFromFEP); }