Compare commits

..

No commits in common. "9252b2fee531dd32e402d5312223bace11aae82d" and "8046dd0e623c675ed5e626a55e05ab7cf0e63de1" have entirely different histories.

22 changed files with 335 additions and 448 deletions

View File

@ -1,22 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ApplicationKt" type="KtorApplicationConfigurationType" factoryName="Ktor" nameIsGenerated="true">
<envs>
<env name="KTOR_ENV" value="dev" />
<env name="DB_PASSWORD" value="pacs_db" />
</envs>
<option name="MAIN_CLASS_NAME" value="net.ipksindia.ApplicationKt" />
<module name="neft-server.main" />
<option name="alternativeJrePath" />
<option name="alternativeJrePathEnabled" value="false" />
<option name="includeProvidedScope" value="false" />
<option name="mainClass" value="net.ipksindia.ApplicationKt" />
<option name="passParentEnvs" value="true" />
<option name="programParameters" value="" />
<option name="shortenCommandLine" />
<option name="vmParameters" />
<option name="workingDirectory" value="D:\work\neft-server" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -1,3 +1,4 @@
val kotlin_version: String by project
val logback_version: String by project
plugins {
@ -31,5 +32,6 @@ dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
implementation("org.slf4j:slf4j-api:2.0.16")
implementation("com.zaxxer:HikariCP:6.0.0")
testImplementation("io.ktor:ktor-server-test-host-jvm")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
}

View File

@ -1,15 +1,16 @@
package net.ipksindia
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import net.ipksindia.config.configureApplication
import net.ipksindia.plugins.configureRouting
import net.ipksindia.plugins.configureSerialization
import net.ipksindia.plugins.*
fun main(args: Array<String>):Unit = EngineMain.main(args)
fun main() {
embeddedServer(Netty, port = 8083, host = "0.0.0.0", module = Application::module)
.start(wait = true)
}
fun Application.module() {
configureApplication()
configureSerialization()
configureRouting()
}

View File

@ -1,3 +0,0 @@
package net.ipksindia
class ItemNotFoundException(type: String, name: String) : Exception("Not Found $type: $name")

View File

@ -1,114 +1,90 @@
package net.ipksindia
import model.TransactionRequest
import net.ipksindia.config.AppConfig
import net.ipksindia.dao.TellerDao
import dao.TellerDao
import net.ipksindia.dao.TransactionDao
import net.ipksindia.model.NeftTransaction
import net.ipksindia.model.OutwardNeftResponse
import net.ipksindia.model.TransferTransaction
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import response.TransactionFailureResponse
import response.TransactionResponse
import response.TransactionSuccessResponse
class NeftRequestProcessor {
companion object {
private val logger: Logger = LoggerFactory.getLogger(NeftRequestProcessor::class.java)
private val migratedDCCBCodes = AppConfig.bankCodes
private val migratedDCCBCodes = listOf("0003","0015")
val bankDccbToSftpMap = mutableMapOf<String, String>(
"0015" to "0005", //Tamluk
"0003" to "0021", //Balageria
// "0016" to "0001", //WBSCB
)
/**
* Process the transaction request based on the transaction number.
* @param transactionNumber The transaction number to be processed.
* @return A pair of transferQueueNumber and neftQueueNumber if successful, null otherwise.
*/
fun process(transactionNumber: String): OutwardNeftResponse {
return try {
val transactionRequest = fetchTransactionRequest(transactionNumber)
val dccbCode = transactionRequest.dccbCode.padStart(4, '0')
val branchCode = transactionRequest.branchCode.padStart(5, '0')
fun process(transactionNumber: String): Pair<String, String>? {
if (!isDCCBCodeMigrated(dccbCode)) {
logDCCBCodeNotMigrated(transactionNumber)
return OutwardNeftResponse(0, "DCCB NOT MIGRATED", null, null)
val outwardTransaction = TransactionDao().getTransactionRequest(transactionNumber) ?: run {
logger.error("TXN: #{} FAILED REASON: Transaction not found", transactionNumber)
return null
}
val teller = TellerDao().getTeller(dccbCode, branchCode)
val transactionPair = TransactionFactory(transactionRequest, teller)
.createTransactionPair()
executeAndProcessTransaction(transactionNumber, transactionRequest, transactionPair)
} catch (e: Exception) {
logger.error("TXN: #{} FAILED REASON: {}", transactionNumber, e.toString())
OutwardNeftResponse(0, "ERROR OCCURRED DURING PROCESSING", null, null)
}
}
/**
* Fetch the transaction request using the transaction number.
*/
private fun fetchTransactionRequest(transactionNumber: String): TransactionRequest {
val transactionRequest = TransactionDao().getTransactionRequest(transactionNumber)
logger.info("TXN: #{} FOUND", transactionNumber)
return transactionRequest
}
/**
* Check if the DCCB code is not migrated.
*/
private fun isDCCBCodeMigrated(dccbCode: String)= dccbCode in migratedDCCBCodes
val dccbCode = outwardTransaction.dccbCode.padStart(4, '0')
val branchCode = outwardTransaction.branchCode.padStart(5, '0')
/**
* Log an error if the DCCB code is not migrated.
*/
private fun logDCCBCodeNotMigrated(transactionNumber: String) {
if(dccbCode !in migratedDCCBCodes) {
logger.error("TXN: #{} FAILED REASON: DCCB Code not migrated", transactionNumber)
return null
}
/**
* Execute the transaction pair and process the results.
*/
private fun executeAndProcessTransaction(
transactionNumber: String,
transactionRequest: TransactionRequest,
transactionPair: Pair<TransferTransaction, NeftTransaction>
): OutwardNeftResponse {
val (transferResponse, neftResponse) = TransactionExecutor().executePair(transactionPair)
val makerTeller = TellerDao.getTeller(dccbCode, branchCode) ?: run {
logger.error("TXN: #{} FAILED REASON: Teller not found", transactionNumber)
return null
}
return if (isSuccess(transferResponse, neftResponse)) {
val transactionPair = TransactionFactory(outwardTransaction, makerTeller).createTransactionPair()
logger.info("TXN: #{} TRANSFER RRN: {} NEFT RRN: {}", transactionNumber, transactionPair.first.rrn, transactionPair.second.rrn)
val (transferResponse, neftResponse) = try {
TransactionExecutor().executePair(transactionPair)
} catch (e: Exception) {
logger.error("TXN: #{} FAILED REASON: {}", transactionNumber, e.message)
return null
}
logger.info(
"TXN: #{} TRF_TXN: {} NEFT_TXN: {}",
transactionNumber,
transferResponse.status,
neftResponse.status
)
if (transferResponse.status == "SUCCESS" && neftResponse.status == "SUCCESS") {
val transferQueueNumber = (transferResponse as TransactionSuccessResponse).queueNumber
val neftQueueNumber = (neftResponse as TransactionSuccessResponse).queueNumber
TransactionDao().updateSuccessTransaction(transactionRequest, transferQueueNumber, neftQueueNumber)
try {
TransactionDao().updateSuccessTransaction(outwardTransaction, transferQueueNumber, neftQueueNumber)
logger.info("TXN: #{} UPDATED RESULTS SUCCESSFULLY", transactionNumber)
OutwardNeftResponse(1, "transaction successful", transferQueueNumber, neftQueueNumber)
} catch (e: Exception) {
logger.error(
"TXN: #{} QUEUE INITIATED BUT FAILED TO UPDATE RESULT: {}",
transactionNumber,
e.message
)
}
return Pair(transferQueueNumber, neftQueueNumber)
} else {
logTransactionFailure(transactionNumber, transferResponse, neftResponse)
OutwardNeftResponse(0, "TRANSACTION FAILED", null, null)
val transferErrorMsg = (transferResponse as TransactionFailureResponse).errorMsg
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
)
}
}
/**
* Check if both transfer and NEFT responses are successful.
*/
private fun isSuccess(transferResponse: TransactionResponse, neftResponse: TransactionResponse) = transferResponse is TransactionSuccessResponse && neftResponse is TransactionSuccessResponse
/**
* Log errors if the transaction fails.
*/
private fun logTransactionFailure(
transactionNumber: String,
transferResponse: Any,
neftResponse: Any
) {
val transferErrorMsg = (transferResponse as? TransactionFailureResponse)?.errorMsg ?: "Unknown Error"
val neftErrorMsg = (neftResponse as? TransactionFailureResponse)?.errorMsg ?: "Unknown Error"
logger.error("TXN: #{} TRANSFER TXN FAILED DUE TO: {}", transactionNumber, transferErrorMsg)
logger.error("TXN: #{} NEFT TXN FAILED DUE TO: {}", transactionNumber, neftErrorMsg)
return null
}
}
}

View File

@ -0,0 +1 @@
class TellerNotFoundException(s: String) : Exception(s)

View File

@ -1,76 +1,76 @@
package net.ipksindia
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import net.ipksindia.config.AppConfig
import net.ipksindia.model.NeftTransaction
import net.ipksindia.model.TransferTransaction
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONException
import org.json.JSONObject
import org.slf4j.LoggerFactory
import response.TransactionFailureResponse
import response.TransactionResponse
import response.TransactionSuccessResponse
import java.io.IOException
import javax.net.ssl.HostnameVerifier
class TransactionExecutor() {
private val logger = LoggerFactory.getLogger(TransactionExecutor::class.java)
private val transactionUrl = AppConfig.remoteServerConfig.transactionUrl
private val protocol = "https"
private val host = "180.179.110.185"
private val port = "443"
private val rootRoute = "IPKS_Queue_Generation"
private val remoteUrl = "$protocol://$host:$port/$rootRoute"
fun executePair(transactionPair: Pair<TransferTransaction, NeftTransaction>): Pair<TransactionResponse, TransactionResponse> {
val transferTransaction = transactionPair.first
val neftTransaction = transactionPair.second
val transferResponseString = execute(Json.encodeToString(transferTransaction))
logger.debug("TRANSFER-RRN: {} - CBS Response: {}", transferTransaction.rrn, transferResponseString)
val transferResponse = processResponse(transferResponseString)
val neftResponseString = execute(Json.encodeToString(neftTransaction))
logger.debug("NEFT-RRN: {}, CBS Response: {}", neftTransaction.rrn, neftResponseString)
val neftResponse = processResponse(neftResponseString)
val transferResponse = execute(Json.encodeToString(transferTransaction))
val neftResponse = execute(Json.encodeToString(neftTransaction))
return Pair(transferResponse, neftResponse)
}
private fun execute(postBody: String): String {
private fun execute(postBody: String): TransactionResponse {
// println(postBody)
val transferRoute = "IpksApi"
val transferURL = "$remoteUrl/$transferRoute"
val jsonMediaType = "application/json; charset=utf-8".toMediaType()
val httpClient = OkHttpClient
.Builder()
.hostnameVerifier { _, _ -> true }
.hostnameVerifier(HostnameVerifier { _, _ -> true })
.build()
val request = Request
.Builder()
.url(transactionUrl)
.url(transferURL)
.post(postBody.toRequestBody(jsonMediaType))
.build()
return httpClient.newCall(request).execute().use { response ->
val responseBody = httpClient.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException("Unexpected response: ${response.body}")
}
response.body?.string() ?: throw IOException("no response body")
}
}
private fun processResponse(responseBody: String): TransactionResponse {
val responseObj = JSONObject(responseBody)
val status = responseObj.getString("status")
val message = responseObj.getString("message")
val error = responseObj.getInt("error")
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 }
if(responseBody.contains("SUCCESS")) {
val queueNo = responseObj.getJSONObject("response").getString("QueueId")
val response = if(responseBody.contains("SUCCESS")) {
val queueNo = try { responseObj.getJSONObject("response").getString("QueueId") } catch(_: JSONException) { "" }
return TransactionSuccessResponse(status, message, queueNo, error)
} else {
val errorMsg = responseObj.getJSONObject("response").getString("errorMsg")
val errorMsg = try { responseObj.getJSONObject("response").getString("errorMsg") } catch(_: JSONException) { responseBody }
return TransactionFailureResponse(status, message, errorMsg, error)
}
return response
}
}

View File

@ -5,18 +5,19 @@ import net.ipksindia.model.NeftTransaction
import model.Teller
import model.TransactionRequest
import net.ipksindia.model.TransferTransaction
import net.ipksindia.NeftRequestProcessor.Companion.bankDccbToSftpMap
import java.time.format.DateTimeFormatter
class TransactionFactory(private val transactionRequest: TransactionRequest, private val teller: Teller) {
private val bankDccbToSftpMap = mutableMapOf("0015" to "0005", "0003" to "0021")
private val date = transactionRequest.date.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))
private val rrn = transactionRequest.date.format(DateTimeFormatter.ofPattern("ddMM")) + transactionRequest.transactionNumber.takeLast(4)
private fun createTransferTransaction(): TransferTransaction {
val bankCode = bankDccbToSftpMap[transactionRequest.dccbCode.padStart(4, '0')] ?: throw ItemNotFoundException("SFTP code for", transactionRequest.dccbCode)
return TransferTransaction(
bankCode = bankCode,
bankCode = bankDccbToSftpMap[transactionRequest.dccbCode.padStart(4, '0')]!!,
branchCode = transactionRequest.branchCode.padStart(3,'0'),
// branchCode = "99999", for UAT
cbsTellerId = teller.tellerId,
cbsTellerUserType = teller.userType,
queIdType = "5",
@ -41,10 +42,10 @@ class TransactionFactory(private val transactionRequest: TransactionRequest, pri
}
private fun createNEFTTransaction(): NeftTransaction {
val bankCode = bankDccbToSftpMap[transactionRequest.dccbCode.padStart(4, '0')] ?: throw ItemNotFoundException("SFTP code for", transactionRequest.dccbCode)
return NeftTransaction(
bankCode = bankCode,
bankCode = bankDccbToSftpMap[transactionRequest.dccbCode.padStart(4, '0')]!!,
branchCode = transactionRequest.branchCode.padStart(3,'0'),
// branchCode = "99999", for UAT
cbsTellerId = teller.tellerId,
cbsTellerUserType = teller.userType,
queIdType = "5",

View File

@ -1,92 +0,0 @@
package net.ipksindia.config
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import net.ipksindia.config.AppConfig.config
import org.slf4j.LoggerFactory
import kotlin.system.exitProcess
object AppConfig {
private val environment = ConfigFactory.load().getString("ktor.environment")
val config: Config = when (environment) {
"prod" -> ConfigFactory.load("application-prod.conf")
else -> ConfigFactory.load("application-dev.conf")
}
val databaseConfig by lazy { DatabaseConfig(
config.getString("database.host"),
config.getInt("database.port"),
config.getString("database.name"),
config.getString("database.user"),
config.getString("database.password")
)}
val remoteServerConfig by lazy {
RemoteServerConfig(
config.getString("bank.server.protocol"),
config.getString("bank.server.host"),
config.getInt("bank.server.port"),
config.getString("bank.server.rootRoute"),
config.getString("bank.server.transactionRoute")
)
}
val bankCodes: MutableList<String> by lazy { config.getStringList("bank.codes")}
}
data class RemoteServerConfig(
val protocol: String,
val host: String,
val port: Int,
val rootRoute: String,
val transactionRoute: String
) {
val transactionUrl = "$protocol://$host:$port/$rootRoute/$transactionRoute"
}
data class DatabaseConfig(
val host: String,
val port: Int,
val name: String,
val user: String,
val password: String
) {
val url = "jdbc:oracle:thin:@$host:$port:$name"
}
fun validateAppConfigs() {
val logger = LoggerFactory.getLogger(AppConfig::class.java)
val requiredKeys = listOf(
"database.host",
"database.port",
"database.name",
"database.user",
"database.password",
"bank.server.protocol",
"bank.server.host",
"bank.server.port",
"bank.server.rootRoute",
"bank.server.transactionRoute",
"bank.codes"
)
val missingKeys = requiredKeys.filterNot { config.hasPath(it) }
if (missingKeys.isNotEmpty()) {
logger.error("Missing configuration keys: {}", missingKeys.toString())
exitProcess(1)
}
val dbPort = config.getInt("database.port")
val remoteServerPort = config.getInt("bank.server.port")
if (dbPort !in 1..65535) {
logger.error("Invalid database port: {}", dbPort)
exitProcess(1)
}
if (remoteServerPort !in 1..65535) {
logger.error("Invalid remote server port: {}", remoteServerPort)
exitProcess(1)
}
}

View File

@ -1,13 +0,0 @@
package net.ipksindia.config
import io.ktor.server.application.*
import org.slf4j.LoggerFactory
fun Application.configureApplication() {
val logger = LoggerFactory.getLogger(AppConfig::class.java)
environment.config.propertyOrNull("ktor.environment")?.getString()?.let {
logger.info("Application running on environment: $it")
}
validateAppConfigs()
}

View File

@ -1,25 +0,0 @@
package net.ipksindia.dao
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import net.ipksindia.config.AppConfig
import java.sql.Connection
class DatabaseFactory private constructor() {
private val dataSource: HikariDataSource
init {
val config = HikariConfig()
config.jdbcUrl = AppConfig.databaseConfig.url
config.username = AppConfig.databaseConfig.user
config.password = AppConfig.databaseConfig.password
config.maximumPoolSize = 5
dataSource = HikariDataSource(config)
}
fun getConnection(): Connection = dataSource.connection
companion object {
val instance = DatabaseFactory()
}
}

View File

@ -1,9 +1,9 @@
package net.ipksindia.dao
package dao
import model.Teller
import net.ipksindia.ItemNotFoundException
class TellerDao {
companion object {
private val tellerMap = mapOf(
"0003" to mapOf(
@ -46,13 +46,15 @@ class TellerDao {
),
)
fun getTeller(dccbCode: String, branchCode: String): Teller {
val branchList = tellerMap[dccbCode] ?: throw ItemNotFoundException("Branch Code", branchCode)
val tellerId = branchList[branchCode] ?: throw ItemNotFoundException("DCCB Code", branchCode)
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
tellerId,
dccbCode,
branchCode
)
return teller
}
}
}

View File

@ -1,12 +1,44 @@
package net.ipksindia.dao
import model.TransactionRequest
import net.ipksindia.ItemNotFoundException
import java.sql.Date
import java.sql.DriverManager
import java.sql.ResultSet
import java.sql.SQLException
import java.util.*
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,
comm_txn_no,
comm_txn_amt,
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()
private val singleTransactionRequestQuery = """
SELECT
@ -65,8 +97,10 @@ class TransactionDao {
""".trimIndent()
fun updateSuccessTransaction(request: TransactionRequest, transferQueueNumber: String, neftQueueNumber: String) {
try {
DatabaseFactory.instance.getConnection().use { connection ->
val dbUrl = getDatabaseUrl()
val (dbUser, dbPassword) = getUserCredentials()
DriverManager.getConnection(dbUrl, dbUser, dbPassword).use { connection ->
connection.prepareStatement(transactionUpdateQuery).also {
it.setString(1, request.transactionNumber)
it.setString(2, request.pacsCurrentAccountNumber)
@ -87,31 +121,73 @@ class TransactionDao {
it.setString(17, transferQueueNumber)
it.setString(18, request.pacsAccountNumber)
it.setString(19, neftQueueNumber)
}.use { it.executeUpdate() }
}.use {
it.executeUpdate()
}
}catch (e: ExceptionInInitializerError) {
throw SQLException("Failed to connect to the database")
}
}
fun getTransactionRequests(): List<TransactionRequest> {
val transactionList: List<TransactionRequest>
val dbUrl = getDatabaseUrl()
val (dbUser, dbPassword) = getUserCredentials()
DriverManager.getConnection(dbUrl, dbUser, dbPassword).use { connection ->
connection.prepareStatement(transactionRequestQuery).executeQuery().use {
transactionList = mapToObject(it)
}
}
fun getTransactionRequest(transactionNumber: String): TransactionRequest {
return try {
DatabaseFactory.instance.getConnection().use { connection ->
connection.prepareStatement(singleTransactionRequestQuery).apply { setString(1, transactionNumber) }
.executeQuery()
.use { mapToObject(it) ?: throw ItemNotFoundException("Transaction Number", transactionNumber) }
return transactionList
}
} catch (e: ExceptionInInitializerError) {
throw SQLException("Failed to connect to the database")
fun getTransactionRequest(transactionNumber: String): TransactionRequest? {
val dbUrl = getDatabaseUrl()
val (dbUser, dbPassword) = getUserCredentials()
return DriverManager.getConnection(dbUrl, dbUser, dbPassword).use { connection ->
connection.prepareStatement(singleTransactionRequestQuery).apply {
setString(1, transactionNumber)
}.executeQuery().use {
mapToObject(it).firstOrNull()
}
}
}
}
private fun getDatabaseUrl(): String {
val prop = loadProp()
val dbHost = getProp(prop, "DB_HOST")
val dbPort = getProp(prop, "DB_PORT")
val dbName = getProp(prop, "DB_NAME")
private fun mapToObject(rs: ResultSet): TransactionRequest? {
return "jdbc:oracle:thin:@$dbHost:$dbPort:$dbName"
}
if (rs.next()) {
return TransactionRequest(
private fun getUserCredentials(): Pair<String, String> {
val prop = loadProp()
val dbUser = getProp(prop, "DB_USER")
val dbPassword = getProp(prop, "DB_PASSWORD")
return Pair(dbUser, dbPassword)
}
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<TransactionRequest> {
val list = mutableListOf<TransactionRequest>()
while (rs.next()) {
val transactionRequest = TransactionRequest(
transactionNumber = rs.getString("txn_no"),
pacsCurrentAccountNumber = rs.getString("src_ac_no"),
neftBeneficiaryAccountNumber = rs.getString("dest_ac_no"),
@ -131,7 +207,10 @@ private fun mapToObject(rs: ResultSet): TransactionRequest? {
pacsAccountNumber = rs.getString("pacs_acc_no"),
linkedCBSAccountNumber = rs.getString("cbs_sb_acc_no"),
)
list.add(transactionRequest)
}
return list
}
return null
}
}

View File

@ -1,11 +0,0 @@
package net.ipksindia.model
import kotlinx.serialization.Serializable
@Serializable
data class OutwardNeftResponse(
val status: Int,
val message: String,
val transferQueueNumber: String?,
val neftQueueNumber: String?
)

View File

@ -13,8 +13,8 @@ fun Application.configureRouting() {
post {
val neftRequest = call.receive<OutwardNeftRequest>()
val transactionNumber = neftRequest.transactionNumber
val response = NeftRequestProcessor.process(transactionNumber)
call.respond(response)
val response = NeftRequestProcessor.process(transactionNumber) ?: Pair("500", "Error doing outward neft" )
call.respond("${response.first}\n${response.second}")
}
}

View File

@ -3,9 +3,16 @@ package net.ipksindia.plugins
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun Application.configureSerialization() {
install(ContentNegotiation) {
json()
}
routing {
get("/json/kotlinx-serialization") {
call.respond(mapOf("hello" to "world"))
}
}
}

View File

@ -1,18 +0,0 @@
database {
host = "localhost"
port = 1521
name = "IPKSDB"
user = "pacs_db"
password = "pacs_db"
}
bank {
server {
protocol = "http"
host = "localhost"
port = 8080
rootRoute = "IPKS_Queue_Generation"
transactionRoute = "IpksApi"
}
codes = ["0003", "0015"]
}

View File

@ -1,17 +0,0 @@
database {
host = "ipksprod3.c7q7defafeea.ap-south-1.rds.amazonaws.com"
port = 1521
name = "IPKS"
user = ${DB_USER}
password = ${DB_PASSWORD}
}
bank {
server {
protocol = "https"
host = "180.179.110.185"
port = 443
rootRoute = "IPKS_Queue_Generation"
transactionRoute = "IpksApi"
}
}

View File

@ -1,10 +0,0 @@
ktor {
environment = ${KTOR_ENV}
deployment {
port = 8083
watch = [ classes ]
}
application {
modules = [ net.ipksindia.ApplicationKt.module ]
}
}

View File

@ -0,0 +1,7 @@
DB_NAME=IPKS
#DB_HOST=testipksdb.c7q7defafeea.ap-south-1.rds.amazonaws.com
#DB_HOST=localhost
DB_HOST=ipksprod3.c7q7defafeea.ap-south-1.rds.amazonaws.com
DB_PORT=1521
DB_USER=pacs_db
DB_PASSWORD=pacs_db

View File

@ -23,7 +23,8 @@
</encoder>
</appender>
<logger name="io.netty" level="WARN"/>
<!-- <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" />

View File

@ -0,0 +1,21 @@
package net.ipksindia
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.server.testing.*
import kotlin.test.*
import net.ipksindia.plugins.*
class ApplicationTest {
@Test
fun testRoot() = testApplication {
application {
configureRouting()
}
client.get("/").apply {
assertEquals(HttpStatusCode.OK, status)
assertEquals("Hello World!", bodyAsText())
}
}
}