ready for prod

This commit is contained in:
Md Asif 2024-09-19 00:53:02 +05:30
parent dfa85ede7e
commit 66dde20601
14 changed files with 152 additions and 107 deletions

View File

@ -6,7 +6,7 @@ import io.ktor.server.netty.*
import net.ipksindia.plugins.* import net.ipksindia.plugins.*
fun main() { fun main() {
embeddedServer(Netty, port = 8088, host = "0.0.0.0", module = Application::module) embeddedServer(Netty, port = 8082, host = "0.0.0.0", module = Application::module)
.start(wait = true) .start(wait = true)
} }

View File

@ -1,20 +1,22 @@
package net.ipksindia package net.ipksindia
import TransactionExecutor
import TransactionFactory
import dao.TellerDao import dao.TellerDao
import net.ipksindia.dao.TransactionDao import net.ipksindia.dao.TransactionDao
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import redis.clients.jedis.JedisPooled import response.TransactionFailureResponse
import response.TransactionSuccessResponse import response.TransactionSuccessResponse
class NeftRequestProcessor { class NeftRequestProcessor {
companion object { companion object {
private val logger: Logger = LoggerFactory.getLogger(NeftRequestProcessor::class.java) private val logger: Logger = LoggerFactory.getLogger(NeftRequestProcessor::class.java)
private const val PROCESSED_TRANSACTION_LIST = "ipks:processed_outward_transactions" private val migratedDCCBCodes = listOf("0003","0015", "0016")
private val migratedDCCBCodes = listOf("0012") val bankDccbToSftpMap = mutableMapOf<String, String>(
"0015" to "0005", //Tamluk
"0003" to "0021", //Balageria
"0016" to "0001", //WBSCB
)
fun process(transactionNumber: String): Pair<String, String>? { fun process(transactionNumber: String): Pair<String, String>? {
@ -23,18 +25,16 @@ class NeftRequestProcessor {
return null return null
} }
logger.info("TXN: #{} FOUND", transactionNumber) logger.info("TXN: #{} FOUND", transactionNumber)
val jedis = JedisPooled("localhost", 6379)
val processedTransactionList = jedis.smembers(PROCESSED_TRANSACTION_LIST)
val dccbCode = outwardTransaction.dccbCode.padStart(4, '0') val dccbCode = outwardTransaction.dccbCode.padStart(4, '0')
val branchCode = outwardTransaction.branchCode.padStart(5, '0')
if(dccbCode !in migratedDCCBCodes) { if(dccbCode !in migratedDCCBCodes) {
logger.error("TXN: #{} FAILED REASON: DCCB Code not migrated", transactionNumber) logger.error("TXN: #{} FAILED REASON: DCCB Code not migrated", transactionNumber)
return null return null
} }
val branchCode = outwardTransaction.branchCode.padStart(3, '0')
if (transactionNumber in processedTransactionList) {
logger.error("TXN: #{} FAILED REASON: Transaction already processed", transactionNumber)
return null
}
val makerTeller = TellerDao.getTeller(dccbCode, branchCode) ?: run { val makerTeller = TellerDao.getTeller(dccbCode, branchCode) ?: run {
logger.error("TXN: #{} FAILED REASON: Teller not found", transactionNumber) logger.error("TXN: #{} FAILED REASON: Teller not found", transactionNumber)
return null return null
@ -54,11 +54,9 @@ class NeftRequestProcessor {
neftResponse.status neftResponse.status
) )
jedis.sadd(PROCESSED_TRANSACTION_LIST, outwardTransaction.transactionNumber)
if (transferResponse.status == "SUCCESS" && neftResponse.status == "SUCCESS") { if (transferResponse.status == "SUCCESS" && neftResponse.status == "SUCCESS") {
val transferQueueNumber = (transferResponse as TransactionSuccessResponse).response.queueId val transferQueueNumber = (transferResponse as TransactionSuccessResponse).queueNumber
val neftQueueNumber = (neftResponse as TransactionSuccessResponse).response.queueId val neftQueueNumber = (neftResponse as TransactionSuccessResponse).queueNumber
try { try {
TransactionDao().updateSuccessTransaction(outwardTransaction, transferQueueNumber, neftQueueNumber) TransactionDao().updateSuccessTransaction(outwardTransaction, transferQueueNumber, neftQueueNumber)
logger.info("TXN: #{} UPDATED RESULTS SUCCESSFULLY", transactionNumber) logger.info("TXN: #{} UPDATED RESULTS SUCCESSFULLY", transactionNumber)
@ -69,12 +67,22 @@ class NeftRequestProcessor {
e.message e.message
) )
} }
return Pair(transferQueueNumber, neftQueueNumber) return Pair(transferQueueNumber, neftQueueNumber)
} else { } else {
logger.error("TXN: #{} QUEUE INITIATED BUT FAILED TO UPDATE RESULT", transactionNumber) val transferErrorMsg = (transferResponse as TransactionFailureResponse).errorMsg
return null val neftErrorMsg = (neftResponse as TransactionFailureResponse).errorMsg
logger.error(
"TXN: #{} TRANSFER TXN FAILED DUE TO: {}",
transactionNumber,
transferErrorMsg
)
logger.error(
"TXN: #{} NEFT TXN FAILED DUE TO: {}",
transactionNumber,
neftErrorMsg
)
} }
return null
} }
} }
} }

View File

@ -1,24 +1,27 @@
package net.ipksindia
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import model.NeftTransaction import net.ipksindia.model.NeftTransaction
import model.TransferTransaction import net.ipksindia.model.TransferTransaction
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONException
import org.json.JSONObject
import response.TransactionFailureResponse import response.TransactionFailureResponse
import response.TransactionResponse import response.TransactionResponse
import response.TransactionSuccessResponse import response.TransactionSuccessResponse
import java.io.IOException import java.io.IOException
import javax.net.ssl.HostnameVerifier
class TransactionExecutor() { class TransactionExecutor() {
private val protocol = "http" private val protocol = "https"
private val host = "localhost" private val host = "180.179.119.227"
private val port = "8080" private val port = "443"
private val rootRoute = "WESTBANGAL/api" private val rootRoute = "IPKS_Queue_Generation"
private val remoteUrl = "$protocol://$host:$port/$rootRoute" private val remoteUrl = "$protocol://$host:$port/$rootRoute"
fun executePair(transactionPair: Pair<TransferTransaction, NeftTransaction>): Pair<TransactionResponse, TransactionResponse> { fun executePair(transactionPair: Pair<TransferTransaction, NeftTransaction>): Pair<TransactionResponse, TransactionResponse> {
@ -31,13 +34,18 @@ class TransactionExecutor() {
} }
private fun execute(postBody: String): TransactionResponse { private fun execute(postBody: String): TransactionResponse {
val transferRoute = "IPKSNeftRtgsApiTransfer"
val transferRoute = "Ipks"
val transferURL = "$remoteUrl/$transferRoute" val transferURL = "$remoteUrl/$transferRoute"
val jsonMediaType = "application/json; charset=utf-8".toMediaType() val jsonMediaType = "application/json; charset=utf-8".toMediaType()
val httpClient = OkHttpClient() val httpClient = OkHttpClient
.Builder()
.hostnameVerifier(HostnameVerifier { _, _ -> true })
.build()
val request = Request.Builder() val request = Request
.Builder()
.url(transferURL) .url(transferURL)
.post(postBody.toRequestBody(jsonMediaType)) .post(postBody.toRequestBody(jsonMediaType))
.build() .build()
@ -49,10 +57,17 @@ class TransactionExecutor() {
response.body!!.string() response.body!!.string()
} }
val responseObj = JSONObject(responseBody)
val status = try {responseObj.getString("status") } catch(_: JSONException) { "" }
val message = try { responseObj.getString("message") }catch(_: JSONException) { "" }
val error = try { responseObj.getInt("error") } catch(_: JSONException) { 1 }
val response = if(responseBody.contains("SUCCESS")) { val response = if(responseBody.contains("SUCCESS")) {
Json.decodeFromString<TransactionSuccessResponse>(responseBody) val queueNo = try { responseObj.getJSONObject("response").getString("QueueId") } catch(_: JSONException) { "" }
return TransactionSuccessResponse(status, message, queueNo, error)
} else { } else {
Json.decodeFromString<TransactionFailureResponse>(responseBody) val errorMsg = try { responseObj.getJSONObject("response").getString("errorMsg") } catch(_: JSONException) { "no error message provided" }
return TransactionFailureResponse(status, message, errorMsg, error)
} }
return response return response
} }

View File

@ -1,9 +1,11 @@
package net.ipksindia
import enums.TransactionType import enums.TransactionType
import model.NeftTransaction import net.ipksindia.model.NeftTransaction
import model.Teller import model.Teller
import model.TransactionRequest import model.TransactionRequest
import model.TransferTransaction import net.ipksindia.model.TransferTransaction
import net.ipksindia.NeftRequestProcessor.Companion.bankDccbToSftpMap
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
class TransactionFactory(private val transactionRequest: TransactionRequest, private val teller: Teller) { class TransactionFactory(private val transactionRequest: TransactionRequest, private val teller: Teller) {
@ -13,10 +15,10 @@ class TransactionFactory(private val transactionRequest: TransactionRequest, pri
private fun createTransferTransaction(): TransferTransaction { private fun createTransferTransaction(): TransferTransaction {
return TransferTransaction( return TransferTransaction(
bankCode = transactionRequest.dccbCode.padStart(4, '0'), bankCode = bankDccbToSftpMap[transactionRequest.dccbCode.padStart(4, '0')]!!,
branchCode = transactionRequest.branchCode.padStart(3,'0'), branchCode = transactionRequest.branchCode.padStart(3,'0'),
cbsTellerId = teller.tellerId, cbsTellerId = teller.tellerId,
cbsTellerUserIdType = teller.userType, cbsTellerUserType = teller.userType,
queIdType = "5", queIdType = "5",
description = "${TransactionType.TRANSFER.code}For Checking", description = "${TransactionType.TRANSFER.code}For Checking",
priority = "1", priority = "1",
@ -25,12 +27,14 @@ class TransactionFactory(private val transactionRequest: TransactionRequest, pri
txnAmt = transactionRequest.amount, txnAmt = transactionRequest.amount,
txnDate = date, txnDate = date,
sourceAcctNo = transactionRequest.pacsCurrentAccountNumber, sourceAcctNo = transactionRequest.pacsCurrentAccountNumber,
cbsSbAcctNo = "",
destinationAcctNo = transactionRequest.linkedCBSAccountNumber, destinationAcctNo = transactionRequest.linkedCBSAccountNumber,
narration = "TRF to member A/C for NEFT RTGS", narration = "TRF to member A/C for NEFT RTGS",
sourceTxnNo = "1045", sourceTxnNo = TransactionType.TRANSFER.code,
sourceStat = "A/P", sourceStat = "A/P",
apiType = "OUTWARD_QUEUE_POSTING", apiType = "OUTWARD_QUEUE_POSTING",
remitterName = transactionRequest.remitterName, remitterName = transactionRequest.remitterName,
ifscCode = "ABCD0000000",
rrn = rrn + "1" rrn = rrn + "1"
) )
@ -38,10 +42,10 @@ class TransactionFactory(private val transactionRequest: TransactionRequest, pri
private fun createNEFTTransaction(): NeftTransaction { private fun createNEFTTransaction(): NeftTransaction {
return NeftTransaction( return NeftTransaction(
bankCode = transactionRequest.dccbCode, bankCode = bankDccbToSftpMap[transactionRequest.dccbCode.padStart(4, '0')]!!,
branchCode = transactionRequest.branchCode.padStart(3,'0'), branchCode = transactionRequest.branchCode.padStart(3,'0'),
cbsTellerId = teller.tellerId, cbsTellerId = teller.tellerId,
cbsTellerUserIdType = teller.userType, cbsTellerUserType = teller.userType,
queIdType = "5", queIdType = "5",
description = "${TransactionType.NEFT.code}For Checking", description = "${TransactionType.NEFT.code}For Checking",
priority = "1", priority = "1",
@ -50,6 +54,7 @@ class TransactionFactory(private val transactionRequest: TransactionRequest, pri
txnAmt = transactionRequest.amount, txnAmt = transactionRequest.amount,
txnDate = date, txnDate = date,
sourceAcctNo = transactionRequest.linkedCBSAccountNumber, sourceAcctNo = transactionRequest.linkedCBSAccountNumber,
cbsSbAcctNo = "",
destinationAcctNo = transactionRequest.neftBeneficiaryAccountNumber, destinationAcctNo = transactionRequest.neftBeneficiaryAccountNumber,
narration = "TRF to member A/C for NEFT RTGS", narration = "TRF to member A/C for NEFT RTGS",
sourceTxnNo = TransactionType.NEFT.code, sourceTxnNo = TransactionType.NEFT.code,

View File

@ -4,37 +4,42 @@ import model.Teller
class TellerDao { class TellerDao {
companion object { companion object {
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"
)
private val tellerMap = mapOf(
"0003" to mapOf(
"00008" to "8",
"00022" to "22",
"00012" to "12",
"00014" to "14",
"00003" to "1003",
"00015" to "15",
"00013" to "13",
"00018" to "18",
"00001" to "1001",
"00004" to "4",
"00017" to "1234",
"00005" to "5",
"00011" to "11",
"00020" to "1234",
"00021" to "1234",
"00016" to "016",
"00009" to "9",
"00010" to "10",
"00007" to "7",
"00006" to "6",
),
"0015" to mapOf(
"00008" to "118",
"00002" to "249",
),
"0016" to mapOf(
"00001" to "249",
"00002" to "249"
)
) )
fun getTeller(dccbCode: String, branchCode: String): Teller? { fun getTeller(dccbCode: String, branchCode: String): Teller? {
val branchList = tellerMap[dccbCode] ?: return null val branchList = tellerMap[dccbCode] ?: return null
val tellerId = branchList[branchCode] ?: return null val tellerId = branchList[branchCode] ?: "249"
val teller = Teller( val teller = Teller(
tellerId, tellerId,
dccbCode, dccbCode,

View File

@ -1,7 +1,6 @@
package model package net.ipksindia.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import org.ipks.model.Transaction import org.ipks.model.Transaction
@Serializable @Serializable
@ -9,7 +8,7 @@ class NeftTransaction(
override val bankCode: String, override val bankCode: String,
override val branchCode: String, override val branchCode: String,
override val cbsTellerId: String, override val cbsTellerId: String,
override val cbsTellerUserIdType: String, override val cbsTellerUserType: String,
override val queIdType: String, override val queIdType: String,
override val description: String, override val description: String,
override val priority: String, override val priority: String,
@ -18,13 +17,13 @@ class NeftTransaction(
override val txnAmt: String, override val txnAmt: String,
override val txnDate: String, override val txnDate: String,
override val sourceAcctNo: String, override val sourceAcctNo: String,
override val cbsSbAcctNo: String,
override val destinationAcctNo: String, override val destinationAcctNo: String,
override val narration: String, override val narration: String,
override val sourceTxnNo: String, override val sourceTxnNo: String,
override val sourceStat: String, override val sourceStat: String,
override val apiType: String, override val apiType: String,
override val remitterName: String, override val remitterName: String,
val ifscCode: String, override val ifscCode: String,
override val rrn: String, override val rrn: String,
@Transient override var queueNo: String = ""
) : Transaction ) : Transaction

View File

@ -4,7 +4,7 @@ interface Transaction {
val bankCode: String val bankCode: String
val branchCode: String val branchCode: String
val cbsTellerId: String val cbsTellerId: String
val cbsTellerUserIdType: String val cbsTellerUserType: String
val queIdType: String val queIdType: String
val description: String val description: String
val priority: String val priority: String
@ -13,12 +13,13 @@ interface Transaction {
val txnAmt: String val txnAmt: String
val txnDate: String val txnDate: String
val sourceAcctNo: String val sourceAcctNo: String
val cbsSbAcctNo: String
val destinationAcctNo: String val destinationAcctNo: String
val narration: String val narration: String
val sourceTxnNo: String val sourceTxnNo: String
val sourceStat: String val sourceStat: String
val apiType: String val apiType: String
val remitterName: String val remitterName: String
val ifscCode: String
val rrn: String val rrn: String
val queueNo: String?
} }

View File

@ -1,7 +1,6 @@
package model package net.ipksindia.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import org.ipks.model.Transaction import org.ipks.model.Transaction
@Serializable @Serializable
@ -9,7 +8,7 @@ class TransferTransaction(
override val bankCode: String, override val bankCode: String,
override val branchCode: String, override val branchCode: String,
override val cbsTellerId: String, override val cbsTellerId: String,
override val cbsTellerUserIdType: String, override val cbsTellerUserType: String,
override val queIdType: String, override val queIdType: String,
override val description: String, override val description: String,
override val priority: String, override val priority: String,
@ -18,12 +17,13 @@ class TransferTransaction(
override val txnAmt: String, override val txnAmt: String,
override val txnDate: String, override val txnDate: String,
override val sourceAcctNo: String, override val sourceAcctNo: String,
override val cbsSbAcctNo: String,
override val destinationAcctNo: String, override val destinationAcctNo: String,
override val narration: String, override val narration: String,
override val sourceTxnNo: String, override val sourceTxnNo: String,
override val sourceStat: String, override val sourceStat: String,
override val apiType: String, override val apiType: String,
override val remitterName: String, override val remitterName: String,
override val ifscCode: String,
override val rrn: String, override val rrn: String,
@Transient override var queueNo: String = "" ) : Transaction
) : Transaction

View File

@ -9,11 +9,14 @@ import net.ipksindia.model.OutwardNeftRequest
fun Application.configureRouting() { fun Application.configureRouting() {
routing { routing {
post("/neftOutward") { route("/neftOutward") {
val neftRequest = call.receive<OutwardNeftRequest>() post {
val transactionNumber = neftRequest.transactionNumber val neftRequest = call.receive<OutwardNeftRequest>()
val response = NeftRequestProcessor.process(transactionNumber) ?: Pair("500", "Error doing outward neft" ) val transactionNumber = neftRequest.transactionNumber
call.respond("${response.first}\n${response.second}") val response = NeftRequestProcessor.process(transactionNumber) ?: Pair("500", "Error doing outward neft" )
call.respond("${response.first}\n${response.second}")
}
} }
} }
} }

View File

@ -1,16 +0,0 @@
package response
import kotlinx.serialization.Serializable
@Serializable
data class ResponseData (
val transactionDate: Int,
val sourceStat: String,
val journalId: Int,
val queueId: String,
val error: Int,
val apiType: String,
val errorMsg: String,
val txnScreenNo: Int
)

View File

@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable
data class TransactionFailureResponse( data class TransactionFailureResponse(
override val status: String, override val status: String,
override val message: String, override val message: String,
val response: String, val errorMsg: String,
override val error: Int override val error: Int
): TransactionResponse ): TransactionResponse

View File

@ -6,6 +6,6 @@ import kotlinx.serialization.Serializable
data class TransactionSuccessResponse( data class TransactionSuccessResponse(
override val status: String, override val status: String,
override val message: String, override val message: String,
val response: ResponseData, val queueNumber: String,
override val error: Int override val error: Int
): TransactionResponse ): TransactionResponse

View File

@ -1,5 +1,6 @@
DB_NAME=IPKSDB DB_NAME=IPKSDB
DB_HOST=localhost DB_HOST=testipksdb.c7q7defafeea.ap-south-1.rds.amazonaws.com
#DB_HOST=localhost
DB_PORT=1521 DB_PORT=1521
DB_USER=pacs_db DB_USER=pacs_db
DB_PASSWORD=pacs_db DB_PASSWORD=pacs_db

View File

@ -1,12 +1,36 @@
<configuration> <configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <property name="LOG_PATH" value="./logs" />
<property name="LOG_ARCHIVE" value="${LOG_PATH}/archive" />
<!-- file appender -->
<appender name="FILE-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender" >
<file>${LOG_PATH}/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_ARCHIVE}/application.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder> <encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>
<root level="trace">
<!-- console appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- <logger name="org.eclipse.jetty" level="WARN"/>-->
<!-- <logger name="io.netty" level="WARN"/>-->
<logger name="net.ipksindia" level="DEBUG" additivity="false">
<appender-ref ref="FILE-ROLLING"/>
<appender-ref ref="STDOUT" />
</logger>
<root level="INFO">
<appender-ref ref="STDOUT"/> <appender-ref ref="STDOUT"/>
</root> </root>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="io.netty" level="INFO"/>
</configuration> </configuration>