You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
534 lines
23 KiB
534 lines
23 KiB
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>(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>(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<DetailDataRequest>);
|
|
|
|
string signature = SignData(request);
|
|
|
|
_log.Info($"{url}|REQUEST : {request}");
|
|
var result = client.Execute<MasterDataResponse>(BuildRequest<string>(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<DongaV2Error>(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<MasterDataResponse>(BuildRequest<MasterDataRequest>(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<DongaV2Error>(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<DetailDataRequest> _dongaSendTxnRequestData = new List<DetailDataRequest>();
|
|
|
|
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<AccountVerifyResponse>(BuildRequest<AccountVerifyRequest>(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<DongaV2Error>(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<TrackingStatusResponse>(BuildRequest<TrackingStatusRequest>(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<DongaV2Error>(result.Content).Errors);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_response.ResponseCode = "999";
|
|
_response.Msg = ex.Message;
|
|
}
|
|
return _response;
|
|
}
|
|
|
|
private RestRequest BuildRequest<T>(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<string, string> ResponseCodes = new Dictionary<string, string>()
|
|
{
|
|
{ "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<string, string> StatusCodes = new Dictionary<string, string>()
|
|
{
|
|
{ "001", "WAITING"},
|
|
{ "002", "IN PROCESS "},
|
|
{ "003", "PAID"},
|
|
{ "004", "CANCELLED"},
|
|
{ "005", "NO DATA FOUND"}
|
|
};
|
|
}
|
|
}
|