using Common.Models.Bank_Account; using Common.Models.Donga; using Common.Models.RequestResponse; using Common.Models.Status; using Common.Models.TxnModel; using Common.TPService; using Common.Utility; using log4net; using Newtonsoft.Json; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Security; using RestSharp; using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Web.Hosting; namespace Donga.DongaAPIService { public class DongApiV2 : ITPApiServices { private readonly ILog _log = LogManager.GetLogger(typeof(DongApiV2)); protected string baseUrl { get; set; } protected string partnerId { get; set; } protected string secretKey { get; set; } protected string privatekey { get; set; } private const string ACCOUNT_VERIFY = "/restapi/account/verify"; private const string TRANSFER_SENDMASTER = "/restapi/transfer/sendmaster"; private const string TRANSFER_SENDDETAIL = "/restapi/transfer/senddetail"; private const string TRANSFER_ONLINE = "/restapi/transfer/online"; private const string TRANSFER_STATUS = "/restapi/transfer/tracking"; public DongApiV2() { baseUrl = GetStatic.ReadWebConfig("dongav2_base_url", ""); partnerId = GetStatic.ReadWebConfig("dongav2_partnerId", ""); secretKey = GetStatic.ReadWebConfig("dongav2_secretKey", ""); privatekey = GetStatic.ReadWebConfig("dongav2_privateKey", ""); } public TPResponse GetTPResponse(T model, string MethodName) where T : class { switch (MethodName) { case "send": return SendTransaction(model as SendTransaction); case "verify": return AccountVerifyDongav2(model as AccountValidate); case "status": return GetStatusDongaV2(model as GetStatus); default: throw new NotImplementedException(); } } private TPResponse SendTransaction(SendTransaction model) { TPResponse _response = new TPResponse(); string sendTxnURL = ""; if (model.IsAccValSupported && model.Transaction.PaymentType.ToLower() == "bank deposit") { sendTxnURL = TRANSFER_ONLINE; AccountValidate _validateRequest = new AccountValidate { AccountNumber = model.Receiver.RAccountNo, BankCode = model.Agent.PBankId, ReceiverName = model.Receiver.RFullName, ControlNo = model.Transaction.JMEControlNo }; _response = AccountVerifyDongav2(_validateRequest); if (_response.ResponseCode == "0") { var _request = MapDongaRequestData(model, _response.Extra, "online"); _response = SendTransactionDonga(_request, "online", sendTxnURL); } } else { sendTxnURL = TRANSFER_SENDDETAIL; _response = SendMasterData(model); if (_response.ResponseCode == "0") { var _request = MapDongaRequestData(model, _response.Extra, "other"); _response = SendTransactionDonga(_request, "other", sendTxnURL); } } return _response; } private TPResponse SendTransactionDonga(T model, string sendType, string url) { TPResponse _response = new TPResponse(); try { var client = new RestClient(baseUrl); string request = ""; if (sendType == "online") request = SimpleJson.SerializeObject(model as OnlineTransferRequest); else request = SimpleJson.SerializeObject(model as List); string signature = SignData(request); _log.Info($"{url}|REQUEST : {request}"); var result = client.Execute(BuildRequest(url, request, signature)); _log.Info($"{url}|RESPONSE : {result.Content}"); if (result.StatusCode == System.Net.HttpStatusCode.OK) { var res = result.Data; _response.Data = result.Data; if (!string.IsNullOrEmpty(res.ResponseCode) && res.ResponseCode.Equals("0000")) { _response.ResponseCode = "0"; _response.Msg = "Success"; } else { _response.ResponseCode = "1"; _response.Extra = res.ResponseCode; _response.Msg = $"ErrorCode: {res.ResponseCode }. { (ResponseCodes.ContainsKey(res.ResponseCode) ? ResponseCodes[res.ResponseCode] : "")}"; } } else { _response.ResponseCode = "1"; _response.Msg = string.IsNullOrEmpty(result.Content) ? result.ErrorMessage : string.Join(",", SimpleJson.DeserializeObject(result.Content).Errors); } } catch (Exception ex) { _response.ResponseCode = "999"; _response.Msg = ex.Message; } return _response; } private TPResponse SendMasterData(SendTransaction model) { TPResponse _response = new TPResponse(); try { var client = new RestClient(baseUrl); MasterDataRequest masterDataRequest = new MasterDataRequest() { SumTransaction = 1, PartnerId = partnerId, SumAUD = (model.Transaction.PCurr.ToLower().Equals("aud")) ? Convert.ToDecimal(model.Transaction.PAmt) : 0, SumCAD = (model.Transaction.PCurr.ToLower().Equals("cad")) ? Convert.ToDecimal(model.Transaction.PAmt) : 0, SumEUR = (model.Transaction.PCurr.ToLower().Equals("eur")) ? Convert.ToDecimal(model.Transaction.PAmt) : 0, SumGBP = (model.Transaction.PCurr.ToLower().Equals("gbp")) ? Convert.ToDecimal(model.Transaction.PAmt) : 0, SumJPY = (model.Transaction.PCurr.ToLower().Equals("jpy")) ? Convert.ToDecimal(model.Transaction.PAmt) : 0, SumUSD = (model.Transaction.PCurr.ToLower().Equals("usd")) ? Convert.ToDecimal(model.Transaction.PAmt) : 0, SumVND = (model.Transaction.PCurr.ToLower().Equals("vnd")) ? Convert.ToDecimal(model.Transaction.PAmt) : 0 }; string requestString = SimpleJson.SerializeObject(masterDataRequest); string signature = SignData(requestString); _log.Info($"{TRANSFER_SENDMASTER}|REQUEST : {requestString}"); var result = client.Execute(BuildRequest(TRANSFER_SENDMASTER, masterDataRequest, signature)); _log.Info($"{TRANSFER_SENDMASTER}|RESPONSE : {result.Content}"); if (result.StatusCode == System.Net.HttpStatusCode.OK) { var res = result.Data; _response.Data = result.Data; if (!string.IsNullOrEmpty(res.ResponseCode) && res.ResponseCode.Equals("0000")) { _response.ResponseCode = "0"; _response.Msg = "Success"; _response.Extra = result.Data.ApiKey; } else { _response.ResponseCode = "1"; _response.Msg = $"ErrorCode: {res.ResponseCode }. { (ResponseCodes.ContainsKey(res.ResponseCode) ? ResponseCodes[res.ResponseCode] : "")}"; } } else { _response.ResponseCode = "1"; _response.Msg = string.IsNullOrEmpty(result.Content) ? result.ErrorMessage : string.Join(",", SimpleJson.DeserializeObject(result.Content).Errors); } } catch (Exception ex) { _response.ResponseCode = "999"; _response.Msg = ex.Message; } return _response; } private object MapDongaRequestData(SendTransaction model, string apiKey, string type) { if (type == "online") { return new OnlineTransferRequest { PartnerID = partnerId, ApiKey = apiKey, TransactionId = model.Transaction.JMEControlNo, SenderName = model.Sender.SFullName, BenName = model.Receiver.RFullName, BenAddress = model.Receiver.RAdd1.Trim(), CityCode = "002", //Default DistrictCode = model.Receiver.RCityCode, Amount = model.Transaction.PAmt, SCurrency = model.Transaction.PCurr, PCurrency = model.Transaction.PCurr, PaymentMode = GetPayoutMode(model.Transaction.PaymentType), TransferType = "OT", BenPhone = model.Receiver.RMobile, BenAccount = model.Receiver.RAccountNo, AccountType = "ACC", BankCode = model.Agent.PBankId, BenRelationship = model.Receiver.RelWithSenderName, MoneyPurpose = model.Transaction.PurposeOfRemittanceName }; } else { List _dongaSendTxnRequestData = new List(); var pm = GetPayoutMode(model.Transaction.PaymentType); _dongaSendTxnRequestData.Add(new DetailDataRequest { ApiKey = apiKey, TransactionId = model.Transaction.JMEControlNo, SenderName = model.Sender.SFullName, BenName = model.Receiver.RFullName, BenAddress = model.Receiver.RAdd1.Trim(), CityCode = pm.Equals("TA") ? "002" : model.Receiver.RStateId, DistrictCode = model.Receiver.RCityCode, Amount = model.Transaction.PAmt, SCurrency = model.Transaction.PCurr, PCurrency = model.Transaction.PCurr, PaymentMode = pm, BenPhone = model.Receiver.RMobile, BenAccount = pm.Equals("TA") ? model.Receiver.RAccountNo : null, BankCode = pm.Equals("TA") ? model.Agent.PBankId : null, Message = model.Transaction.PayoutMsg, BenRelationship = model.Receiver.RelWithSenderName, MoneyPurpose = model.Transaction.PurposeOfRemittanceName, // IsBankTransfer = pm.Equals("TA") ? true : false }); return _dongaSendTxnRequestData; } } private string GetPayoutMode(string paymentType) { if (paymentType.ToLower().Equals("cash payment")) return "CP"; else if (paymentType.ToLower().Equals("home delivery")) return "HD"; else if (paymentType.ToLower().Equals("bank deposit")) return "TA"; return ""; } private TPResponse AccountVerifyDongav2(AccountValidate model) { TPResponse _response = new TPResponse(); try { var client = new RestClient(baseUrl); AccountVerifyRequest accountVerifyRequest = new AccountVerifyRequest() { AccountType = "ACC", BankCode = model.BankCode, BenAccount = model.AccountNumber, PartnerId = partnerId }; var requestJson = JsonConvert.SerializeObject(accountVerifyRequest, Formatting.None); _log.Info($"{ACCOUNT_VERIFY}|REQUEST : {requestJson}"); var result = client.Execute(BuildRequest(ACCOUNT_VERIFY, accountVerifyRequest, SignData(requestJson))); _log.Info($"{ACCOUNT_VERIFY}|RESPONSE : {result.Content}"); if (result.StatusCode == System.Net.HttpStatusCode.OK) { var res = result.Data; _response.Data = result.Data; if (!string.IsNullOrEmpty(res.ResponseCode) && res.ResponseCode.Equals("0000")) { _response.ResponseCode = "0"; _response.Msg = "Success"; _response.Extra = res.ApiKey; _response.Extra2 = res.BenName; } else { _response.ResponseCode = "1"; if (res.ResponseCode.Equals("0001")) { _response.Msg = $"ErrorCode: {res.ResponseCode }. Account validation failed!. Please check Bank/Account number"; } else _response.Msg = $"ErrorCode: {res.ResponseCode }. { (ResponseCodes.ContainsKey(res.ResponseCode) ? ResponseCodes[res.ResponseCode] : "")}"; } } else { _response.ResponseCode = "1"; _response.Msg = string.IsNullOrEmpty(result.Content) ? result.ErrorMessage : string.Join(",", SimpleJson.DeserializeObject(result.Content).Errors); } } catch (Exception ex) { _response.ResponseCode = "999"; _response.Msg = ex.Message; } return _response; } private TPResponse GetStatusDongaV2(GetStatus model) { TPResponse _response = new TPResponse(); try { var client = new RestClient(baseUrl); TrackingStatusRequest statusRequest = new TrackingStatusRequest() { TransactionID = model.ControlNo, PartnerID = partnerId }; var requestJson = JsonConvert.SerializeObject(statusRequest, Formatting.None); _log.Info($"{TRANSFER_STATUS}|REQUEST : {requestJson}"); var result = client.Execute(BuildRequest(TRANSFER_STATUS, statusRequest, SignData(requestJson))); _log.Info($"{TRANSFER_STATUS}|RESPONSE : {result.Content}"); if (result.StatusCode == System.Net.HttpStatusCode.OK) { var res = result.Data; _response.Data = result.Data; if (!string.IsNullOrEmpty(res.ResponseCode) && res.ResponseCode.Equals("0000")) { _response.ResponseCode = "0"; _response.Extra2 = StatusCodes.ContainsKey(res.Status) ? StatusCodes[res.Status] : "Unpaid"; _response.Msg = $"{res.Status }: { (StatusCodes.ContainsKey(res.Status) ? StatusCodes[res.Status] : "")}"; if (!string.IsNullOrEmpty(res.PaidDate)) _response.Msg += $"Paid Date : {res.PaidDate} | "; if (!string.IsNullOrEmpty(res.UnpaidReason)) _response.Msg += $"Unpaid Reason: { res.UnpaidReason}"; } else { _response.ResponseCode = "1"; _response.Msg = !string.IsNullOrEmpty(res.Status) ? $"Code: {res.Status}| Reason: {(StatusCodes.ContainsKey(res.Status) ? StatusCodes[res.Status] : result.Content)}" : result.Content; } } else { _response.ResponseCode = "1"; _response.Msg = string.IsNullOrEmpty(result.Content) ? result.ErrorMessage : string.Join(",", SimpleJson.DeserializeObject(result.Content).Errors); } } catch (Exception ex) { _response.ResponseCode = "999"; _response.Msg = ex.Message; } return _response; } private RestRequest BuildRequest(string action, T o, string signature = "", Method method = Method.POST) where T : class { var authorizeHeader = "Basic " + Base64Encode($"{ partnerId}:{secretKey}"); var request = new RestRequest(action, method); request.AddHeader("Content-Type", "application/json"); if (!string.IsNullOrEmpty(authorizeHeader)) request.AddHeader("Authorization", authorizeHeader); if (!string.IsNullOrEmpty(signature)) request.AddHeader("Signature", signature); request.RequestFormat = DataFormat.Json; if (o != null) request.AddJsonBody(o); return request; } #region Helpers private static string Base64Encode(string plainText) { var plainTextBytes = Encoding.UTF8.GetBytes(plainText); return Convert.ToBase64String(plainTextBytes); } public string SignData(string plainText) { var privateKey = File.ReadAllText(HostingEnvironment.MapPath($"~/{privatekey}")); var ms = new MemoryStream(Encoding.Default.GetBytes(privateKey)); var sr = new StreamReader(ms); var pemReader = new PemReader(sr); var key = (RsaPrivateCrtKeyParameters)pemReader.ReadObject(); var signer = SignerUtilities.GetSigner("SHA256withRSA"); signer.Init(true, key); var bytes = Encoding.UTF8.GetBytes(plainText); signer.BlockUpdate(bytes, 0, bytes.Length); byte[] signature = signer.GenerateSignature(); return Convert.ToBase64String(signature); } #endregion public static Dictionary ResponseCodes = new Dictionary() { { "0000", "SUCCESS"}, { "0001", "Unexpected error."}, { "0002", "Records missedmatch"}, { "0003", "Account is incorrect"}, { "0004", "Invalid data."}, { "0005", "Invalid API KEY"}, { "0006", "Duplicate records."}, { "0007", "Total of amount missed match"}, { "0008", "TIME OUT"}, { "0009", "NO DATA FOUND"}, { "0010", "Invalid Data"}, { "0012", "Invalid transaction."}, { "0013", "Invalid amount."}, { "0014", "Invalid card or Account number (no such number)"}, { "0015", "Not sufficient funds"}, { "0016", "Http method is not Allow"}, { "0017", "Invalid capture date"}, { "0019", "Please check with issuing bank."}, { "0021", "Card not initialized"}, { "0030", "Message Format Error"}, { "0034", "Suspected Fraud"}, { "0039", "No Credit account"}, { "0041", "Pick up card (Lost card)"}, { "0042", "No universal account"}, { "0043", "Stolen card, pick-up"}, { "0051", "System is busy. Try again later"}, { "0054", "Expire Card"}, { "0057", "Transaction not permitted to cardholder"}, { "0059", "Suspected Fraud"}, { "0062", "Restricted Card"}, { "0064", "Original Amount Incorrect"}, { "0066", "Exceeds Acquirer Limit"}, { "0068", "Response received too late (time-out)"}, { "0075", "Allowable number of PIN tries exceeded"}, { "0076", "Invalid Account."}, { "0090", "Cut-off is in progress"}, { "0091", "Issuer or switch is in operation"}, { "0092", "Financial institution or intermediate network facility cannot be found for routing"}, { "0093", "Invalid Acquirer"}, { "0094", "Duplicate Transaction"}, { "0096", "System denied transaction, please try again later."}, //{ "0099", "Please check with issuing bank."}, { "0103", "Transaction does not exist"}, { "0105", "Invalid Transfer Account Type"}, { "0106", "CITAD only support working time & business date"}, { "1111", "Internal Error"}, { "1002", "IBT Transfer to Our bank card"}, { "1003", "There are no app payments information registered"}, { "1004", "The transaction has been canceled due to an error of authentication number three time or more"}, { "1005", "Transaction error, please make transaction again."}, { "1006", "Please check with issuing bank."}, { "1007", "This request is not able to process Please apply for a new one"}, { "1010", "Currency not allowed"}, { "1011", "Operation account number is mandatory."}, { "1021", "In-Active Card"}, { "0025", "Unable to locate record on file"}, { "1030", "Transaction information is invalid."}, { "1040", "Requested function not supported"}, { "1053", "Deposit limit account"}, { "0061", "The transfer amount is over allowed limit."}, { "0065", "Allowable number of Transactions Count exceeded"}, //{ "1075", "Please check with issuing bank."}, { "3001", "Communication"}, { "3002", "Identify"}, { "3003", "Message parsing"}, { "3004", "Connect Error"}, { "3005", "No Channel"}, { "3006", "Time over"}, { "3007", "Closed"}, { "3008", "No Adapter"}, { "9997", "Create signature error"}, { "9998", "Validation signature error"}, { "9999", "Authorization error"} }; public static Dictionary StatusCodes = new Dictionary() { { "001", "WAITING"}, { "002", "IN PROCESS "}, { "003", "PAID"}, { "004", "CANCELLED"}, { "005", "NO DATA FOUND"} }; } }