Compare commits

...

10 Commits

22 changed files with 455 additions and 342 deletions

View File

@ -0,0 +1,22 @@
<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,4 +1,3 @@
val kotlin_version: String by project
val logback_version: String by project
plugins {
@ -32,6 +31,5 @@ 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")
testImplementation("io.ktor:ktor-server-test-host-jvm")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
implementation("com.zaxxer:HikariCP:6.0.0")
}

View File

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

View File

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

View File

@ -1,90 +1,114 @@
package net.ipksindia
import dao.TellerDao
import model.TransactionRequest
import net.ipksindia.config.AppConfig
import net.ipksindia.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 = listOf("0003","0015")
val bankDccbToSftpMap = mutableMapOf<String, String>(
"0015" to "0005", //Tamluk
"0003" to "0021", //Balageria
// "0016" to "0001", //WBSCB
)
private val migratedDCCBCodes = AppConfig.bankCodes
fun process(transactionNumber: String): Pair<String, String>? {
/**
* 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')
val outwardTransaction = TransactionDao().getTransactionRequest(transactionNumber) ?: run {
logger.error("TXN: #{} FAILED REASON: Transaction not found", transactionNumber)
return null
}
logger.info("TXN: #{} FOUND", transactionNumber)
val dccbCode = outwardTransaction.dccbCode.padStart(4, '0')
val branchCode = outwardTransaction.branchCode.padStart(5, '0')
if(dccbCode !in migratedDCCBCodes) {
logger.error("TXN: #{} FAILED REASON: DCCB Code not migrated", transactionNumber)
return null
if (!isDCCBCodeMigrated(dccbCode)) {
logDCCBCodeNotMigrated(transactionNumber)
return OutwardNeftResponse(0, "DCCB NOT MIGRATED", null, null)
}
val teller = TellerDao().getTeller(dccbCode, branchCode)
val transactionPair = TransactionFactory(transactionRequest, teller)
.createTransactionPair()
val makerTeller = TellerDao.getTeller(dccbCode, branchCode) ?: run {
logger.error("TXN: #{} FAILED REASON: Teller not found", transactionNumber)
return null
}
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)
executeAndProcessTransaction(transactionNumber, transactionRequest, transactionPair)
} catch (e: Exception) {
logger.error("TXN: #{} FAILED REASON: {}", transactionNumber, e.message)
return null
logger.error("TXN: #{} FAILED REASON: {}", transactionNumber, e.toString())
OutwardNeftResponse(0, "ERROR OCCURRED DURING PROCESSING", null, null)
}
}
logger.info(
"TXN: #{} TRF_TXN: {} NEFT_TXN: {}",
transactionNumber,
transferResponse.status,
neftResponse.status
)
/**
* 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
}
if (transferResponse.status == "SUCCESS" && neftResponse.status == "SUCCESS") {
/**
* Check if the DCCB code is not migrated.
*/
private fun isDCCBCodeMigrated(dccbCode: String)= dccbCode in migratedDCCBCodes
/**
* Log an error if the DCCB code is not migrated.
*/
private fun logDCCBCodeNotMigrated(transactionNumber: String) {
logger.error("TXN: #{} FAILED REASON: DCCB Code not migrated", transactionNumber)
}
/**
* 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)
return if (isSuccess(transferResponse, neftResponse)) {
val transferQueueNumber = (transferResponse as TransactionSuccessResponse).queueNumber
val neftQueueNumber = (neftResponse as TransactionSuccessResponse).queueNumber
try {
TransactionDao().updateSuccessTransaction(outwardTransaction, transferQueueNumber, neftQueueNumber)
TransactionDao().updateSuccessTransaction(transactionRequest, transferQueueNumber, neftQueueNumber)
logger.info("TXN: #{} UPDATED RESULTS SUCCESSFULLY", transactionNumber)
} catch (e: Exception) {
logger.error(
"TXN: #{} QUEUE INITIATED BUT FAILED TO UPDATE RESULT: {}",
transactionNumber,
e.message
)
}
return Pair(transferQueueNumber, neftQueueNumber)
OutwardNeftResponse(1, "transaction successful", transferQueueNumber, neftQueueNumber)
} else {
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
)
logTransactionFailure(transactionNumber, transferResponse, neftResponse)
OutwardNeftResponse(0, "TRANSACTION FAILED", null, null)
}
return null
}
/**
* 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)
}
}
}

View File

@ -1 +0,0 @@
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 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"
private val logger = LoggerFactory.getLogger(TransactionExecutor::class.java)
private val transactionUrl = AppConfig.remoteServerConfig.transactionUrl
fun executePair(transactionPair: Pair<TransferTransaction, NeftTransaction>): Pair<TransactionResponse, TransactionResponse> {
val transferTransaction = transactionPair.first
val neftTransaction = transactionPair.second
val transferResponse = execute(Json.encodeToString(transferTransaction))
val neftResponse = execute(Json.encodeToString(neftTransaction))
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)
return Pair(transferResponse, neftResponse)
}
private fun execute(postBody: String): TransactionResponse {
// println(postBody)
val transferRoute = "IpksApi"
val transferURL = "$remoteUrl/$transferRoute"
private fun execute(postBody: String): String {
val jsonMediaType = "application/json; charset=utf-8".toMediaType()
val httpClient = OkHttpClient
.Builder()
.hostnameVerifier(HostnameVerifier { _, _ -> true })
.hostnameVerifier { _, _ -> true }
.build()
val request = Request
.Builder()
.url(transferURL)
.url(transactionUrl)
.post(postBody.toRequestBody(jsonMediaType))
.build()
val responseBody = httpClient.newCall(request).execute().use { response ->
return httpClient.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException("Unexpected response: ${response.body}")
}
response.body?.string() ?: throw IOException("no response body")
}
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 queueNo = try { responseObj.getJSONObject("response").getString("QueueId") } catch(_: JSONException) { "" }
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")
if(responseBody.contains("SUCCESS")) {
val queueNo = responseObj.getJSONObject("response").getString("QueueId")
return TransactionSuccessResponse(status, message, queueNo, error)
} else {
val errorMsg = try { responseObj.getJSONObject("response").getString("errorMsg") } catch(_: JSONException) { responseBody }
val errorMsg = responseObj.getJSONObject("response").getString("errorMsg")
return TransactionFailureResponse(status, message, errorMsg, error)
}
return response
}
}

View File

@ -5,19 +5,18 @@ 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 = bankDccbToSftpMap[transactionRequest.dccbCode.padStart(4, '0')]!!,
bankCode = bankCode,
branchCode = transactionRequest.branchCode.padStart(3,'0'),
// branchCode = "99999", for UAT
cbsTellerId = teller.tellerId,
cbsTellerUserType = teller.userType,
queIdType = "5",
@ -42,10 +41,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 = bankDccbToSftpMap[transactionRequest.dccbCode.padStart(4, '0')]!!,
bankCode = bankCode,
branchCode = transactionRequest.branchCode.padStart(3,'0'),
// branchCode = "99999", for UAT
cbsTellerId = teller.tellerId,
cbsTellerUserType = teller.userType,
queIdType = "5",

View File

@ -0,0 +1,92 @@
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

@ -0,0 +1,13 @@
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

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

View File

@ -1,44 +1,12 @@
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.util.*
import java.sql.SQLException
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
@ -97,10 +65,8 @@ class TransactionDao {
""".trimIndent()
fun updateSuccessTransaction(request: TransactionRequest, transferQueueNumber: String, neftQueueNumber: String) {
val dbUrl = getDatabaseUrl()
val (dbUser, dbPassword) = getUserCredentials()
DriverManager.getConnection(dbUrl, dbUser, dbPassword).use { connection ->
try {
DatabaseFactory.instance.getConnection().use { connection ->
connection.prepareStatement(transactionUpdateQuery).also {
it.setString(1, request.transactionNumber)
it.setString(2, request.pacsCurrentAccountNumber)
@ -121,73 +87,31 @@ class TransactionDao {
it.setString(17, transferQueueNumber)
it.setString(18, request.pacsAccountNumber)
it.setString(19, neftQueueNumber)
}.use {
it.executeUpdate()
}.use { it.executeUpdate() }
}
}
}
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)
}catch (e: ExceptionInInitializerError) {
throw SQLException("Failed to connect to the database")
}
}
return transactionList
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) }
}
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()
} catch (e: ExceptionInInitializerError) {
throw SQLException("Failed to connect to the database")
}
}
}
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")
return "jdbc:oracle:thin:@$dbHost:$dbPort:$dbName"
}
private fun mapToObject(rs: ResultSet): 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(
if (rs.next()) {
return TransactionRequest(
transactionNumber = rs.getString("txn_no"),
pacsCurrentAccountNumber = rs.getString("src_ac_no"),
neftBeneficiaryAccountNumber = rs.getString("dest_ac_no"),
@ -207,10 +131,7 @@ class TransactionDao {
pacsAccountNumber = rs.getString("pacs_acc_no"),
linkedCBSAccountNumber = rs.getString("cbs_sb_acc_no"),
)
list.add(transactionRequest)
}
return list
}
return null
}

View File

@ -0,0 +1,11 @@
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) ?: Pair("500", "Error doing outward neft" )
call.respond("${response.first}\n${response.second}")
val response = NeftRequestProcessor.process(transactionNumber)
call.respond(response)
}
}

View File

@ -3,16 +3,9 @@ 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

@ -0,0 +1,18 @@
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

@ -0,0 +1,17 @@
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

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

View File

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

@ -1,21 +0,0 @@
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())
}
}
}