Skip to content

Commit

Permalink
changed transaction history to return details of sender/receiver in o…
Browse files Browse the repository at this point in the history
…ne record (#418)

* #395: add wallet type to history

* #412: change exchange transfer to have two transactions in each the system involved

* #412: a bit refactoring and make tests green again!

* #412: enabled IT tests with maven build

* #412: used kafka testcontainer to provide dynamic kafka port

* #412: add missed class!

* #396: changed transaction history to return details of sender/receiver in one record

* #396: optimize imports

---------

Co-authored-by: Peyman <marchosiax@gmail.com>
Co-authored-by: Benyamin <23664159+Benyamin001@users.noreply.github.com>
Co-authored-by: Peyman <peyman.sepehrad@gmail.com>
  • Loading branch information
4 people authored Jan 27, 2024
1 parent 81a79d3 commit 33d8988
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package co.nilin.opex.wallet.app.controller

import co.nilin.opex.wallet.app.dto.TransactionRequest
import co.nilin.opex.wallet.core.model.TransactionHistory
import co.nilin.opex.wallet.core.model.TransactionWithDetailHistory
import co.nilin.opex.wallet.core.spi.TransactionManager
import org.springframework.web.bind.annotation.*
import java.time.Instant
Expand Down Expand Up @@ -31,7 +32,7 @@ class TransactionController(private val manager: TransactionManager) {
suspend fun getTransactionsForUser(
@PathVariable("uuid") uuid: String,
@RequestBody request: TransactionRequest
): List<TransactionHistory> {
): List<TransactionWithDetailHistory> {
return manager.findTransactions(
uuid,
request.coin,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package co.nilin.opex.wallet.app.controller

import co.nilin.opex.wallet.app.KafkaEnabledTest
import co.nilin.opex.wallet.app.dto.TransactionRequest
import co.nilin.opex.wallet.core.model.TransactionHistory
import co.nilin.opex.wallet.core.model.TransactionWithDetailHistory
import co.nilin.opex.wallet.core.spi.TransactionManager
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -30,8 +30,8 @@ class TransactionControllerIT : KafkaEnabledTest() {
fun whenGetTransactionsForUser_thenReturnsHistory() {
val uuid = "uuid"
val t = System.currentTimeMillis()
val history = TransactionHistory(
1L, "c", "w", BigDecimal.ONE, "desc", "ref", System.currentTimeMillis(), "cat", mapOf(Pair("key1", "val1")), true
val history = TransactionWithDetailHistory(
1L, "sw", "dw", "su", "du", "c", BigDecimal.ONE, "desc", "ref", System.currentTimeMillis(), "cat", mapOf(Pair("key1", "val1"))
)
runBlocking {
Mockito.`when`(
Expand All @@ -43,7 +43,7 @@ class TransactionControllerIT : KafkaEnabledTest() {
.bodyValue(TransactionRequest("c", null, t, t, 1, 1, true))
.exchange()
.expectStatus().isOk
.expectBodyList(TransactionHistory::class.java)
.expectBodyList(TransactionWithDetailHistory::class.java)
.contains(history)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import co.nilin.opex.wallet.app.KafkaEnabledTest
import co.nilin.opex.wallet.app.dto.TransactionRequest
import co.nilin.opex.wallet.core.inout.TransferResult
import co.nilin.opex.wallet.core.model.Amount
import co.nilin.opex.wallet.core.model.TransactionHistory
import co.nilin.opex.wallet.core.model.TransactionWithDetailHistory
import co.nilin.opex.wallet.core.spi.CurrencyService
import co.nilin.opex.wallet.core.spi.WalletManager
import co.nilin.opex.wallet.core.spi.WalletOwnerManager
Expand Down Expand Up @@ -49,11 +49,11 @@ class TransferControllerIT : KafkaEnabledTest() {
runBlocking {
val t = System.currentTimeMillis()
val sender = walletOwnerManager.createWalletOwner(UUID.randomUUID().toString(), "sender", "")
val receiver = UUID.randomUUID().toString()
val receiver = sender.uuid
val srcCurrency = currencyService.getCurrency("ETH")!!
walletManager.createWallet(sender, Amount(srcCurrency, BigDecimal.valueOf(100)), srcCurrency, "main")

val transfer = webClient.post().uri("/v2/transfer/1_ETH/from/${sender.uuid}_main/to/${receiver}_main").accept(MediaType.APPLICATION_JSON)
val transfer = webClient.post().uri("/v2/transfer/1_ETH/from/${sender.uuid}_main/to/${receiver}_exchange").accept(MediaType.APPLICATION_JSON)
.bodyValue(TransferController.TransferBody("desc", "ref", "NORMAL", mapOf(Pair("key", "value"))))
.exchange()
.expectStatus().isOk
Expand All @@ -62,20 +62,24 @@ class TransferControllerIT : KafkaEnabledTest() {
Assertions.assertEquals(BigDecimal.ONE, transfer.amount.amount)
Assertions.assertEquals("ETH", transfer.amount.currency.symbol)
val receiverWallet = walletManager.findWalletByOwnerAndCurrencyAndType(
walletOwnerManager.findWalletOwner(receiver)!!, "main", srcCurrency
walletOwnerManager.findWalletOwner(receiver)!!, "exchange", srcCurrency
)
Assertions.assertEquals(BigDecimal.ONE, receiverWallet!!.balance.amount)
val txList = webClient.post().uri("/transaction/$receiver").accept(MediaType.APPLICATION_JSON)
.bodyValue(TransactionRequest("ETH", null, t, System.currentTimeMillis(), 1, 0, true))
.exchange()
.expectStatus().isOk
.expectBodyList(TransactionHistory::class.java)
.expectBodyList(TransactionWithDetailHistory::class.java)
.returnResult().responseBody
Assertions.assertEquals(1, txList!!.size)
with(txList[0]) {
Assertions.assertEquals("NORMAL", this.category)
Assertions.assertEquals(mapOf(Pair("key", "value")), this.additionalData)
Assertions.assertEquals("ETH", this.currency)
Assertions.assertEquals("main", this.srcWallet)
Assertions.assertEquals("exchange", this.destWallet)
Assertions.assertEquals(sender.uuid, this.senderUuid)
Assertions.assertEquals(receiverUuid, this.receiverUuid)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,17 @@ class TransactionManagerImplIT : KafkaEnabledTest() {

assertEquals(2, thSender.size)
assertTrue(thSender.first().date.compareTo(thSender.last().date) < 0)
assertTrue(thSender.all { th -> th.withdraw })
assertTrue(thSender.all { th -> th.wallet == senderWalletType })
assertTrue(thSender.all { th -> th.senderUuid == sender.uuid })
assertTrue(thSender.all { th -> th.srcWallet == senderWalletType })

val thReceiver = transactionManager.findTransactions(
receiver.uuid, currency.symbol, "NORMAL", LocalDateTime.now().minusHours(1), LocalDateTime.now(), false, 3, 1
)

assertEquals(3, thReceiver.size)
assertTrue(thReceiver.first().date.compareTo(thReceiver.last().date) > 0)
assertTrue(thReceiver.none { th -> th.withdraw })
assertTrue(thReceiver.all { th -> th.wallet == receiverWalletType })
assertTrue(thReceiver.all { th -> th.receiverUuid == receiver.uuid })
assertTrue(thReceiver.all { th -> th.destWallet == receiverWalletType })

val thReceiverAll = transactionManager.findTransactions(
receiver.uuid, null, null, LocalDateTime.now().minusHours(1), LocalDateTime.now(), true, 100, 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import co.nilin.opex.wallet.core.spi.*
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
Expand Down Expand Up @@ -263,27 +264,25 @@ class TransferManagerImplIT : KafkaEnabledTest() {

val thwMatch = thw.find { th -> th.id.toString().equals(result.tx) }
assertNotNull(thwMatch)
assertTrue(thwMatch!!.withdraw)
assertEquals("NORMAL", thwMatch.category)
assertEquals("NORMAL", thwMatch!!.category)

val thdMatch = thd.find { th -> th.id.toString().equals(result.tx) }
assertNotNull(thdMatch)
assertFalse(thdMatch!!.withdraw)
assertEquals("NORMAL", thdMatch.category)
assertEquals("NORMAL", thdMatch!!.category)

val thSender = transactionManager.findTransactions(
sender.uuid, currency.symbol, "NORMAL", LocalDateTime.now().minusHours(1), LocalDateTime.now(), true, 100, 0
)
val thSenderMatch = thSender.find { i -> i.id.toString().equals(result.tx) }
assertTrue(thSenderMatch!!.withdraw)
assertEquals(sender.uuid, thSenderMatch!!.senderUuid)
assertEquals("NORMAL", thSenderMatch.category)


val thReceiver = transactionManager.findTransactions(
receiver.uuid, currency.symbol, "NORMAL", LocalDateTime.now().minusHours(1), LocalDateTime.now(), true, 100, 0
)
val thReceiverMatch = thReceiver.find { i -> i.id.toString().equals(result.tx) }
assertFalse(thReceiverMatch!!.withdraw)
assertEquals(receiver.uuid, thReceiverMatch!!.receiverUuid)
assertEquals("NORMAL", thReceiverMatch.category)

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@ data class TransactionHistory(
val ref: String?,
val date: Long,
val category: String?,
val additionalData: Map<String, Any>?,
val withdraw: Boolean
val additionalData: Map<String, Any>?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package co.nilin.opex.wallet.core.model

import java.math.BigDecimal

data class TransactionWithDetailHistory(
val id: Long,
val srcWallet: String,
val destWallet: String,
val senderUuid: String,
val receiverUuid: String,
val currency: String,
val amount: BigDecimal,
val description: String?,
val ref: String?,
val date: Long,
val category: String,
val additionalData: Map<String, Any>?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package co.nilin.opex.wallet.core.spi

import co.nilin.opex.wallet.core.model.Transaction
import co.nilin.opex.wallet.core.model.TransactionHistory
import co.nilin.opex.wallet.core.model.TransactionWithDetailHistory
import java.time.LocalDateTime

interface TransactionManager {
Expand All @@ -26,5 +27,5 @@ interface TransactionManager {
offset: Int
): List<TransactionHistory>

suspend fun findTransactions(uuid: String, coin: String?, category: String?, startTime: LocalDateTime, endTime: LocalDateTime, asc: Boolean, limit: Int, offset: Int): List<TransactionHistory>
suspend fun findTransactions(uuid: String, coin: String?, category: String?, startTime: LocalDateTime, endTime: LocalDateTime, asc: Boolean, limit: Int, offset: Int): List<TransactionWithDetailHistory>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package co.nilin.opex.wallet.ports.postgres.dao

import co.nilin.opex.wallet.ports.postgres.dto.DepositWithdrawTransaction
import co.nilin.opex.wallet.ports.postgres.dto.TransactionStat
import co.nilin.opex.wallet.ports.postgres.dto.TransactionWithDetail
import co.nilin.opex.wallet.ports.postgres.model.TransactionModel
import org.springframework.data.r2dbc.repository.Query
import org.springframework.data.repository.query.Param
Expand Down Expand Up @@ -84,7 +85,7 @@ interface TransactionRepository : ReactiveCrudRepository<TransactionModel, Long>
@Query(
"""
select distinct t.id, w.currency, w.wallet_type as wallet, t.dest_amount as amount, t.description, t.transfer_ref as ref, t.transaction_date as date
, t.transfer_category as category, t.transfer_detail_json as detail, t.source_wallet as sender, t.dest_wallet as receiver, w.id as owner
, t.transfer_category as category, t.transfer_detail_json as detail
from wallet as w
inner join wallet_owner as wo on (w.owner = wo.id)
inner join transaction as t on (w.id = t.dest_wallet)
Expand All @@ -105,7 +106,7 @@ interface TransactionRepository : ReactiveCrudRepository<TransactionModel, Long>
@Query(
"""
select distinct t.id, w.currency, w.wallet_type as wallet, t.dest_amount as amount, t.description, t.transfer_ref as ref, t.transaction_date as date
, t.transfer_category as category, t.transfer_detail_json as detail, t.source_wallet as sender, t.dest_wallet as receiver, w.id as owner
, t.transfer_category as category, t.transfer_detail_json as detail
from wallet as w
inner join wallet_owner as wo on (w.owner = wo.id)
inner join transaction as t on (w.id = t.source_wallet)
Expand All @@ -125,7 +126,7 @@ interface TransactionRepository : ReactiveCrudRepository<TransactionModel, Long>
@Query(
"""
select distinct t.id, w.currency, w.wallet_type as wallet, t.dest_amount as amount, t.description, t.transfer_ref as ref, t.transaction_date as date
, t.transfer_category as category, t.transfer_detail_json as detail, t.source_wallet as sender, t.dest_wallet as receiver, w.id as owner
, t.transfer_category as category, t.transfer_detail_json as detail
from wallet as w
inner join wallet_owner as wo on (w.owner = wo.id)
inner join transaction as t on (w.id = t.dest_wallet)
Expand All @@ -148,7 +149,7 @@ interface TransactionRepository : ReactiveCrudRepository<TransactionModel, Long>
@Query(
"""
select distinct t.id, w.currency, w.wallet_type as wallet, t.dest_amount as amount, t.description, t.transfer_ref as ref, t.transaction_date as date
, t.transfer_category as category, t.transfer_detail_json as detail, t.source_wallet as sender, t.dest_wallet as receiver, w.id as owner
, t.transfer_category as category, t.transfer_detail_json as detail
from wallet as w
inner join wallet_owner as wo on (w.owner = wo.id)
inner join transaction as t on (w.id = t.source_wallet)
Expand All @@ -169,16 +170,18 @@ interface TransactionRepository : ReactiveCrudRepository<TransactionModel, Long>

@Query(
"""
select distinct t.id, w.currency, w.wallet_type as wallet, t.dest_amount as amount, t.description, t.transfer_ref as ref, t.transaction_date as date
, t.transfer_category as category, t.transfer_detail_json as detail, t.source_wallet as sender, t.dest_wallet as receiver, w.id as owner
from wallet as w
inner join wallet_owner as wo on (w.owner = wo.id)
inner join transaction as t on w.id in (t.source_wallet, t.dest_wallet)
where wo.uuid = :uuid
select distinct t.id, sw.wallet_type as src_wallet, dw.wallet_type as dest_wallet, swo.uuid as sender_uuid, dwo.uuid as receiver_uuid, sw.currency, t.dest_amount as amount, t.description, t.transfer_ref as ref, t.transaction_date as date
, t.transfer_category as category, t.transfer_detail_json as detail
from transaction as t
inner join wallet as sw on sw.id = t.source_wallet
inner join wallet_owner as swo on (sw.owner = swo.id)
inner join wallet as dw on dw.id = t.dest_wallet
inner join wallet_owner as dwo on (dw.owner = dwo.id)
where :uuid in (swo.uuid, dwo.uuid)
and t.transaction_date > :startTime
and t.transaction_date <= :endTime
and (:category is null or t.transfer_category = :category)
and (:currency is null or w.currency = :currency)
and (:currency is null or sw.currency = :currency)
order by date asc
limit :limit
offset :offset
Expand All @@ -192,20 +195,22 @@ interface TransactionRepository : ReactiveCrudRepository<TransactionModel, Long>
@Param("endTime") endTime: LocalDateTime,
@Param("limit") limit: Int,
@Param("offset") offset: Int,
): Flux<DepositWithdrawTransaction>
): Flux<TransactionWithDetail>

@Query(
"""
select distinct t.id, w.currency, w.wallet_type as wallet, t.dest_amount as amount, t.description, t.transfer_ref as ref, t.transaction_date as date
, t.transfer_category as category, t.transfer_detail_json as detail, t.source_wallet as sender, t.dest_wallet as receiver, w.id as owner
from wallet as w
inner join wallet_owner as wo on (w.owner = wo.id)
inner join transaction as t on w.id in (t.source_wallet, t.dest_wallet)
where wo.uuid = :uuid
select distinct t.id, sw.wallet_type as src_wallet, dw.wallet_type as dest_wallet, swo.uuid as sender_uuid, dwo.uuid as receiver_uuid, sw.currency, t.dest_amount as amount, t.description, t.transfer_ref as ref, t.transaction_date as date
, t.transfer_category as category, t.transfer_detail_json as detail
from transaction as t
inner join wallet as sw on sw.id = t.source_wallet
inner join wallet_owner as swo on (sw.owner = swo.id)
inner join wallet as dw on dw.id = t.dest_wallet
inner join wallet_owner as dwo on (dw.owner = dwo.id)
where :uuid in (swo.uuid, dwo.uuid)
and t.transaction_date > :startTime
and t.transaction_date <= :endTime
and (:category is null or t.transfer_category = :category)
and (:currency is null or w.currency = :currency)
and (:currency is null or sw.currency = :currency)
order by date desc
limit :limit
offset :offset
Expand All @@ -219,6 +224,6 @@ interface TransactionRepository : ReactiveCrudRepository<TransactionModel, Long>
@Param("endTime") endTime: LocalDateTime,
@Param("limit") limit: Int,
@Param("offset") offset: Int,
): Flux<DepositWithdrawTransaction>
): Flux<TransactionWithDetail>

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,5 @@ data class DepositWithdrawTransaction(
val ref: String?,
val date: LocalDateTime,
val category: String,
val detail: String?,
val sender: Long?,
val receiver: Long?,
val owner: Long?
val detail: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package co.nilin.opex.wallet.ports.postgres.dto

import java.math.BigDecimal
import java.time.LocalDateTime

data class TransactionWithDetail(
val id: Long,
val srcWallet: String,
val destWallet: String,
val senderUuid: String,
val receiverUuid: String,
val currency: String,
val amount: BigDecimal,
val description: String?,
val ref: String?,
val date: LocalDateTime,
val category: String,
val detail: String?,
)
Loading

0 comments on commit 33d8988

Please sign in to comment.