From dff61dc29435dca5b2d573f7010d7e89f5f96a07 Mon Sep 17 00:00:00 2001 From: Md Asif Date: Tue, 17 Sep 2024 21:43:56 +0530 Subject: [PATCH] Implemented logic to send transaction to C-EDGE servers --- .idea/dataSources.xml | 19 ++++ .idea/kotlinc.xml | 6 ++ src/main/kotlin/Main.kt | 1 + src/main/kotlin/ResponseData.kt | 14 +++ src/main/kotlin/TellerNotFoundException.kt | 1 + src/main/kotlin/TransactionExecutor.kt | 55 ++++++++++ src/main/kotlin/TransactionFactory.kt | 63 ++++++++++++ src/main/kotlin/TransactionResponse.kt | 11 ++ src/main/kotlin/dao/TellerDao.kt | 46 +++++++++ src/main/kotlin/dao/TransactionDao.kt | 101 +++++++++++++++++++ src/main/kotlin/enums/TransactionType.kt | 7 ++ src/main/kotlin/model/NeftTransaction.kt | 29 ++++++ src/main/kotlin/model/Teller.kt | 10 ++ src/main/kotlin/model/Transaction.kt | 23 +++++ src/main/kotlin/model/TransactionRequest.kt | 27 +++++ src/main/kotlin/model/TransferTransaction.kt | 27 +++++ 16 files changed, 440 insertions(+) create mode 100644 .idea/dataSources.xml create mode 100644 .idea/kotlinc.xml create mode 100644 src/main/kotlin/ResponseData.kt create mode 100644 src/main/kotlin/TellerNotFoundException.kt create mode 100644 src/main/kotlin/TransactionExecutor.kt create mode 100644 src/main/kotlin/TransactionFactory.kt create mode 100644 src/main/kotlin/TransactionResponse.kt create mode 100644 src/main/kotlin/dao/TellerDao.kt create mode 100644 src/main/kotlin/dao/TransactionDao.kt create mode 100644 src/main/kotlin/enums/TransactionType.kt create mode 100644 src/main/kotlin/model/NeftTransaction.kt create mode 100644 src/main/kotlin/model/Teller.kt create mode 100644 src/main/kotlin/model/Transaction.kt create mode 100644 src/main/kotlin/model/TransactionRequest.kt create mode 100644 src/main/kotlin/model/TransferTransaction.kt diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..aa13dbe --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,19 @@ + + + + + oracle.19 + true + false + oracle.jdbc.OracleDriver + jdbc:oracle:thin:@ipksprod3.c7q7defafeea.ap-south-1.rds.amazonaws.com:1521:IPKS + + + + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..d4b7acc --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index ff5fe3e..f7427e8 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -17,6 +17,7 @@ fun main() { val neftTransaction = transactionFactory.createNEFTTransaction() val transactionPair = Pair(transferTransaction, neftTransaction) val success = TransactionExecutor().execute(transactionPair) + print(success) } } diff --git a/src/main/kotlin/ResponseData.kt b/src/main/kotlin/ResponseData.kt new file mode 100644 index 0000000..4485f46 --- /dev/null +++ b/src/main/kotlin/ResponseData.kt @@ -0,0 +1,14 @@ +import kotlinx.serialization.Serializable + + +@Serializable +data class ResponseData ( + val transactionDate: Int, + val sourceStat: String, + val journalId: String, + val queueId: String, + val error: String, + val apiType: String, + val errorMsg: String, + val txnScreenNo: String +) \ No newline at end of file diff --git a/src/main/kotlin/TellerNotFoundException.kt b/src/main/kotlin/TellerNotFoundException.kt new file mode 100644 index 0000000..bbad8c0 --- /dev/null +++ b/src/main/kotlin/TellerNotFoundException.kt @@ -0,0 +1 @@ +class TellerNotFoundException(s: String) : Exception(s) \ No newline at end of file diff --git a/src/main/kotlin/TransactionExecutor.kt b/src/main/kotlin/TransactionExecutor.kt new file mode 100644 index 0000000..b9ce58a --- /dev/null +++ b/src/main/kotlin/TransactionExecutor.kt @@ -0,0 +1,55 @@ + +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import model.NeftTransaction +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import model.TransferTransaction + + +class TransactionExecutor() { + + private val protocol = "http" + private val host = "localhost" + private val port = "3000" + private val rootRoute = "WESTBANGAL/api" + private val remoteUrl = "$protocol://$host:$port/$rootRoute" + + fun execute(transactionPair: Pair): Boolean { + + val transferTransaction = transactionPair.first + val neftTransaction = transactionPair.second + val transferSuccess = execute(Json.encodeToString(transferTransaction)) + if(!transferSuccess) { + return false + } + val neftSuccess = execute(Json.encodeToString(neftTransaction)) + return neftSuccess + } + + fun execute(postBody: String): Boolean { + val transferRoute = "IPKSNeftRtgsApiTransfer" + val transferURL = "$remoteUrl/$transferRoute" + val jsonMediaType = "application/json; charset=utf-8".toMediaType() + + val httpClient = OkHttpClient() + + val request = Request.Builder() + .url(transferURL) + .post(postBody.toRequestBody(jsonMediaType)) + .build() + + httpClient.newCall(request).execute().use { response -> + if (!response.isSuccessful) { + return false + } + response.body!!.string() + } + + println("success") + return true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/TransactionFactory.kt b/src/main/kotlin/TransactionFactory.kt new file mode 100644 index 0000000..d7d8270 --- /dev/null +++ b/src/main/kotlin/TransactionFactory.kt @@ -0,0 +1,63 @@ + +import model.NeftTransaction +import model.Teller +import model.TransactionRequest +import model.TransferTransaction +import enums.TransactionType +import java.time.format.DateTimeFormatter + +class TransactionFactory(private val transactionRequest: TransactionRequest, private val teller: Teller) { + + private val date = transactionRequest.date.format(DateTimeFormatter.ofPattern("dd-MM-yyyy")) + private val rrn = transactionRequest.date.format(DateTimeFormatter.ofPattern("ddMM")) + transactionRequest.transactionNumber.takeLast(4) + + fun createTransferTransaction(): TransferTransaction { + return TransferTransaction( + bankCode = transactionRequest.dccbCode, + branchCode = transactionRequest.branchCode.padStart(3,'0'), + cbsTellerId = teller.tellerId, + cbsTellerUserIdType = teller.userType, + queIdType = "5", + description = "${TransactionType.TRANSFER.code}For Checking", + priority = "1", + cbsTellerCapability = teller.capability, + txnScreenNo = TransactionType.TRANSFER.code.padStart(6, '0'), + txnAmt = transactionRequest.amount.toString(), + txnDate = date, + sourceAcctNo = transactionRequest.pacsCurrentAccountNumber, + destinationAcctNo = transactionRequest.linkedCBSAccountNumber, + narration = "TRF to member A/C for NEFT RTGS", + sourceTxnNo = "1045", + sourceStat = "A/P", + apiType = "OUTWARD_QUEUE_POSTING", + remitterName = transactionRequest.remitterName, + rrn = rrn + "1" + ) + + } + + fun createNEFTTransaction(): NeftTransaction { + return NeftTransaction( + bankCode = transactionRequest.dccbCode, + branchCode = transactionRequest.branchCode.padStart(3,'0'), + cbsTellerId = teller.tellerId, + cbsTellerUserIdType = teller.userType, + queIdType = "5", + description = "${TransactionType.NEFT.code}For Checking", + priority = "1", + cbsTellerCapability = teller.capability, + txnScreenNo = TransactionType.NEFT.code.padStart(6, '0'), + txnAmt = transactionRequest.amount.toString(), + txnDate = date, + sourceAcctNo = transactionRequest.linkedCBSAccountNumber, + destinationAcctNo = transactionRequest.neftBeneficiaryAccountNumber, + narration = "TRF to member A/C for NEFT RTGS", + sourceTxnNo = TransactionType.NEFT.code, + sourceStat = "A/P", + apiType = "OUTWARD_QUEUE_POSTING", + remitterName = transactionRequest.remitterName, + ifscCode = transactionRequest.ifscCode, + rrn = rrn + "2" + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/TransactionResponse.kt b/src/main/kotlin/TransactionResponse.kt new file mode 100644 index 0000000..bb17692 --- /dev/null +++ b/src/main/kotlin/TransactionResponse.kt @@ -0,0 +1,11 @@ + +import kotlinx.serialization.Serializable + + +@Serializable +data class TransactionResponse( + val status: String, + val message: String, + val response: ResponseData, + val error: String +) diff --git a/src/main/kotlin/dao/TellerDao.kt b/src/main/kotlin/dao/TellerDao.kt new file mode 100644 index 0000000..03afb18 --- /dev/null +++ b/src/main/kotlin/dao/TellerDao.kt @@ -0,0 +1,46 @@ +package dao + +import model.Teller + +class TellerDao { + + private val tellerMap = mapOf( + "0016" to mapOf( + "008" to "118" + ), + "0012" to mapOf( + "008" to "8", + "022" to "22", + "012" to "12", + "014" to "14", + "003" to "1003", + "015" to "15", + "013" to "13", + "018" to "18", + "001" to "1001", + "004" to "4", + "017" to "1234", + "005" to "5", + "011" to "11", + "020" to "1234", + "021" to "1234", + "016" to "016", + "009" to "9", + "010" to "10", + "007" to "7", + "006" to "6" + ) + + ) + + fun getTeller(dccbCode: String, branchCode: String): Teller? { + val branchList = tellerMap[dccbCode] ?: return null + val tellerId = branchList[branchCode] ?: return null + val teller = Teller( + tellerId, + dccbCode, + branchCode + ) + return teller + } +} \ No newline at end of file diff --git a/src/main/kotlin/dao/TransactionDao.kt b/src/main/kotlin/dao/TransactionDao.kt new file mode 100644 index 0000000..7d2b7af --- /dev/null +++ b/src/main/kotlin/dao/TransactionDao.kt @@ -0,0 +1,101 @@ +package dao + +import model.TransactionRequest +import java.sql.DriverManager +import java.sql.ResultSet +import java.util.Properties + +class TransactionDao { + private val transactionRequestQuery = """ + select txn_no, + trim(src_ac_no) AS src_ac_no, + trim(dest_ac_no) AS dest_ac_no, + ifsc_code, + txn_amt, + txn_date, + t.teller_id, + (case + when t.ifsc_code like 'WBSC%' then + 'FAILED' + else + 'RECEIVED' + end) AS status, + substr(regexp_replace(regexp_replace(upper(beneficiary_name),'[^A-Z0-9 ]',''),' {2,}',' '),1,35) AS beneficiary_name, + beneficiary_add, + t.pacs_id, + dccb_code, + TO_NUMBER(cbs_br_code) AS br_code, + substr(regexp_replace(regexp_replace(upper(remm_name),'[^A-Z0-9 ]',''),' {2,}',' '),1,35) AS remitter_name, + ipks_accno AS pacs_acc_no, + da.link_accno AS cbs_sb_acc_no, + 'pacs_db' AS db_name + from neft_rtgs_txn t + join dep_account da ON t.ipks_accno = da.key_1 + where + t.txn_date = (select system_date from system_date) + and t.STATUS = 'A' + and t.bank_channel = 'SCB' + and da.link_accno IS NOT NULL + """.trimIndent() + + fun getTransactionRequests(): List { + val prop = loadProp() + + val dbHost = getProp(prop, "DB_HOST") + val dbPort = getProp(prop, "DB_PORT") + val dbName = getProp(prop, "DB_NAME") + + val dbUrl = "jdbc:oracle:thin:@$dbHost:$dbPort:$dbName" + + val dbUser = getProp(prop, "DB_USER") + val dbPassword = getProp(prop, "DB_PASSWORD") + + val transactionList: List + + DriverManager.getConnection(dbUrl, dbUser, dbPassword).use { connection -> + connection.prepareStatement(transactionRequestQuery).executeQuery().use { + transactionList = mapToObject(it) + } + } + + return transactionList + } + + private fun loadProp(): Properties { + + val props = javaClass.classLoader.getResourceAsStream("application.properties").use { + Properties().apply { load(it) } + } + return props + } + + private fun getProp(prop: Properties, key: String): String { + return prop.getProperty(key) ?: throw RuntimeException("property $prop not found") + } + + private fun mapToObject(rs: ResultSet): List { + val list = mutableListOf() + while (rs.next()) { + val transactionRequest = TransactionRequest( + transactionNumber = rs.getString("txn_no"), + pacsCurrentAccountNumber = rs.getString("src_ac_no"), + neftBeneficiaryAccountNumber = rs.getString("dest_ac_no"), + ifscCode = rs.getString("ifsc_code"), + amount = rs.getString("txn_amt").toFloat(), + date = rs.getDate("txn_date").toLocalDate(), + tellerId = rs.getString("teller_id"), + status = rs.getString("status"), + beneficiaryName = rs.getString("beneficiary_name"), + beneficiaryAddress = rs.getString("beneficiary_add"), + pacsId = rs.getString("pacs_id"), + dccbCode = rs.getString("dccb_code").padStart(4, '0'), + branchCode = rs.getString("br_Code").padStart(3, '0'), + remitterName = rs.getString("remitter_name"), + pacsAccountNumber = rs.getString("pacs_acc_no"), + linkedCBSAccountNumber = rs.getString("cbs_sb_acc_no"), + ) + list.add(transactionRequest) + } + return list + } +} \ No newline at end of file diff --git a/src/main/kotlin/enums/TransactionType.kt b/src/main/kotlin/enums/TransactionType.kt new file mode 100644 index 0000000..98adec3 --- /dev/null +++ b/src/main/kotlin/enums/TransactionType.kt @@ -0,0 +1,7 @@ +package enums + +enum class TransactionType(val code: String) { + TRANSFER("01045"), + NEFT("20066"), + RTGS("20035") +} diff --git a/src/main/kotlin/model/NeftTransaction.kt b/src/main/kotlin/model/NeftTransaction.kt new file mode 100644 index 0000000..3da9e60 --- /dev/null +++ b/src/main/kotlin/model/NeftTransaction.kt @@ -0,0 +1,29 @@ +package model + +import kotlinx.serialization.Serializable +import org.ipks.enums.TransactionType +import org.ipks.model.Transaction + +@Serializable +class NeftTransaction( + override val bankCode: String, + override val branchCode: String, + override val cbsTellerId: String, + override val cbsTellerUserIdType: String, + override val queIdType: String, + override val description: String, + override val priority: String, + override val cbsTellerCapability: String, + override val txnScreenNo: String, + override val txnAmt: String, + override val txnDate: String, + override val sourceAcctNo: String, + override val destinationAcctNo: String, + override val narration: String, + override val sourceTxnNo: String, + override val sourceStat: String, + override val apiType: String, + override val remitterName: String, + val ifscCode: String, + override val rrn: String +) : Transaction \ No newline at end of file diff --git a/src/main/kotlin/model/Teller.kt b/src/main/kotlin/model/Teller.kt new file mode 100644 index 0000000..22fe5d3 --- /dev/null +++ b/src/main/kotlin/model/Teller.kt @@ -0,0 +1,10 @@ +package model + +data class Teller( + val tellerId: String, + val password: String, + val branch: String, + val dccbCode: String = "", + val userType: String = "50", + val capability: String = "9" +) \ No newline at end of file diff --git a/src/main/kotlin/model/Transaction.kt b/src/main/kotlin/model/Transaction.kt new file mode 100644 index 0000000..0459efe --- /dev/null +++ b/src/main/kotlin/model/Transaction.kt @@ -0,0 +1,23 @@ +package org.ipks.model + +interface Transaction { + val bankCode: String + val branchCode: String + val cbsTellerId: String + val cbsTellerUserIdType: String + val queIdType: String + val description: String + val priority: String + val cbsTellerCapability: String + val txnScreenNo: String + val txnAmt: String + val txnDate: String + val sourceAcctNo: String + val destinationAcctNo: String + val narration: String + val sourceTxnNo: String + val sourceStat: String + val apiType: String + val remitterName: String + val rrn: String +} diff --git a/src/main/kotlin/model/TransactionRequest.kt b/src/main/kotlin/model/TransactionRequest.kt new file mode 100644 index 0000000..0b3bf43 --- /dev/null +++ b/src/main/kotlin/model/TransactionRequest.kt @@ -0,0 +1,27 @@ +package model + +import kotlinx.serialization.Serializable +import org.ipks.enums.TransactionType +import org.ipks.model.Transaction +import java.time.LocalDate + + +data class TransactionRequest( + val transactionNumber: String, + val pacsCurrentAccountNumber: String, + val neftBeneficiaryAccountNumber: String, + val ifscCode: String, + val amount: Float, + val date: LocalDate, + val tellerId: String, + val status: String, + val beneficiaryName: String, + val beneficiaryAddress: String?, + val pacsId: String, + val dccbCode: String, + val branchCode: String, + val remitterName: String, + val pacsAccountNumber: String, + val linkedCBSAccountNumber: String +) + diff --git a/src/main/kotlin/model/TransferTransaction.kt b/src/main/kotlin/model/TransferTransaction.kt new file mode 100644 index 0000000..a20e645 --- /dev/null +++ b/src/main/kotlin/model/TransferTransaction.kt @@ -0,0 +1,27 @@ +package model + +import kotlinx.serialization.Serializable +import org.ipks.model.Transaction + +@Serializable +class TransferTransaction( + override val bankCode: String, + override val branchCode: String, + override val cbsTellerId: String, + override val cbsTellerUserIdType: String, + override val queIdType: String, + override val description: String, + override val priority: String, + override val cbsTellerCapability: String, + override val txnScreenNo: String, + override val txnAmt: String, + override val txnDate: String, + override val sourceAcctNo: String, + override val destinationAcctNo: String, + override val narration: String, + override val sourceTxnNo: String, + override val sourceStat: String, + override val apiType: String, + override val remitterName: String, + override val rrn: String +) : Transaction \ No newline at end of file