From 6cc9758a5b60f7d68ea4d8cfd93c2175a6947c13 Mon Sep 17 00:00:00 2001 From: "nikitkagorkov@gmail.com" <gerosp> Date: Wed, 18 Oct 2023 00:04:29 +0300 Subject: [PATCH 1/3] Added subscription detection algorithm Renamed enity to entity --- .../data/api/TransactionNetworkDataSource.kt | 11 +-- .../subscriptio/data/local/MainDatabase.kt | 2 +- .../data/local/dao/SubscriptionDao.kt | 3 +- .../data/local/dbmodel/TransactionDbModel.kt | 4 +- .../repository/SubscriptionRepository.kt | 3 +- .../subscriptio/data/mapper/TokenMapper.kt | 2 +- .../data/mapper/TransactionMapper.kt | 22 ++--- .../repository/TransactionRepositoryImpl.kt | 7 +- .../subscriptio/domain/actions/DefinerAlg.kt | 64 +++++++++++++ .../subscriptio/domain/actions/Period.kt | 90 +++++++++++++++++++ .../domain/actions/mergeTransaction.kt | 8 +- .../domain/actions/networkUpdate.kt | 58 ++++++++++++ .../subscriptio/domain/enity/ResultType.kt | 5 -- .../domain/{enity => entity}/Result.kt | 2 +- .../subscriptio/domain/entity/ResultType.kt | 5 ++ .../{enity => entity}/SubscriptionEntity.kt | 9 +- .../domain/{enity => entity}/Token.kt | 2 +- .../{enity => entity}/TransactionEntity.kt | 2 +- .../repository/TransactionRepository.kt | 4 +- .../domain/usecase/GetTransactionUseCase.kt | 4 +- .../presentation/AddSubscriptionActivity.kt | 5 +- .../EditSubscriptionDetailActivity.kt | 7 +- .../EditSubscriptionDetailViewModel.kt | 2 +- .../subscriptio/presentation/MainActivity.kt | 23 +++-- .../SubscriptionDashBoardActivity.kt | 14 ++- .../SubscriptionDetailActivity.kt | 3 +- .../presentation/VtbLoginActivity.kt | 26 ++---- app/src/main/res/values/strings.xml | 1 + 28 files changed, 298 insertions(+), 90 deletions(-) create mode 100644 app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/DefinerAlg.kt create mode 100644 app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/Period.kt create mode 100644 app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt delete mode 100644 app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/ResultType.kt rename app/src/main/java/com/threehundredbugs/subscriptio/domain/{enity => entity}/Result.kt (87%) create mode 100644 app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/ResultType.kt rename app/src/main/java/com/threehundredbugs/subscriptio/domain/{enity => entity}/SubscriptionEntity.kt (78%) rename app/src/main/java/com/threehundredbugs/subscriptio/domain/{enity => entity}/Token.kt (83%) rename app/src/main/java/com/threehundredbugs/subscriptio/domain/{enity => entity}/TransactionEntity.kt (96%) diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/data/api/TransactionNetworkDataSource.kt b/app/src/main/java/com/threehundredbugs/subscriptio/data/api/TransactionNetworkDataSource.kt index f2aa244..917ca26 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/data/api/TransactionNetworkDataSource.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/data/api/TransactionNetworkDataSource.kt @@ -1,18 +1,13 @@ package com.threehundredbugs.subscriptio.data.api -import android.util.Log import com.threehundredbugs.subscriptio.data.api.exceptions.IncorrectTokenException import com.threehundredbugs.subscriptio.data.api.exceptions.handleNetworkExceptions -import com.threehundredbugs.subscriptio.data.api.model.DataField -import com.threehundredbugs.subscriptio.data.api.model.LinksField -import com.threehundredbugs.subscriptio.data.api.model.MetaField -import com.threehundredbugs.subscriptio.data.api.model.RiskField import com.threehundredbugs.subscriptio.data.api.model.TransactionApi -import com.threehundredbugs.subscriptio.domain.enity.Token +import com.threehundredbugs.subscriptio.domain.entity.Token import com.threehundredbugs.subscriptio.data.api.retrofit.BankApi import com.threehundredbugs.subscriptio.data.mapper.mapTokenApiToToken -import com.threehundredbugs.subscriptio.domain.enity.Result -import com.threehundredbugs.subscriptio.domain.enity.ResultType +import com.threehundredbugs.subscriptio.domain.entity.Result +import com.threehundredbugs.subscriptio.domain.entity.ResultType class TransactionNetworkDataSource { // val token = diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/data/local/MainDatabase.kt b/app/src/main/java/com/threehundredbugs/subscriptio/data/local/MainDatabase.kt index 74a5f2a..bc5e9d0 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/data/local/MainDatabase.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/data/local/MainDatabase.kt @@ -9,7 +9,7 @@ import com.threehundredbugs.subscriptio.data.local.dao.SubscriptionDao import com.threehundredbugs.subscriptio.data.local.dao.TransactionDao import com.threehundredbugs.subscriptio.data.local.dbmodel.SubscriptionDbModel import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel -import com.threehundredbugs.subscriptio.domain.enity.SubscriptionEntity +import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity @Database( entities = [SubscriptionDbModel::class, SubscriptionEntity::class, TransactionDbModel::class], diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/data/local/dao/SubscriptionDao.kt b/app/src/main/java/com/threehundredbugs/subscriptio/data/local/dao/SubscriptionDao.kt index 62d0299..08f4fb3 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/data/local/dao/SubscriptionDao.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/data/local/dao/SubscriptionDao.kt @@ -6,8 +6,7 @@ import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import androidx.room.Update -import com.threehundredbugs.subscriptio.domain.enity.SubscriptionEntity -import kotlinx.coroutines.flow.Flow +import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity @Dao interface SubscriptionDao { diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/data/local/dbmodel/TransactionDbModel.kt b/app/src/main/java/com/threehundredbugs/subscriptio/data/local/dbmodel/TransactionDbModel.kt index 6db7c0d..7215d72 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/data/local/dbmodel/TransactionDbModel.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/data/local/dbmodel/TransactionDbModel.kt @@ -5,8 +5,8 @@ import androidx.room.PrimaryKey import java.time.LocalDateTime @Entity(tableName = "Transactions") -data class TransactionDbModel ( - @PrimaryKey() +data class TransactionDbModel( + @PrimaryKey(autoGenerate = true) val id: Int = 0, val accountId: String, val amount: Double, diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/data/local/repository/SubscriptionRepository.kt b/app/src/main/java/com/threehundredbugs/subscriptio/data/local/repository/SubscriptionRepository.kt index b7e1458..a7f5b0c 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/data/local/repository/SubscriptionRepository.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/data/local/repository/SubscriptionRepository.kt @@ -1,8 +1,7 @@ package com.threehundredbugs.subscriptio.data.local.repository import com.threehundredbugs.subscriptio.data.local.dao.SubscriptionDao -import com.threehundredbugs.subscriptio.domain.enity.SubscriptionEntity -import kotlinx.coroutines.flow.Flow +import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity class SubscriptionRepository(private val subscriptionDao: SubscriptionDao) { fun getAllSubscriptions(): List<SubscriptionEntity> = subscriptionDao.getAllSubscriptions() diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/data/mapper/TokenMapper.kt b/app/src/main/java/com/threehundredbugs/subscriptio/data/mapper/TokenMapper.kt index 50c59e3..76287bc 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/data/mapper/TokenMapper.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/data/mapper/TokenMapper.kt @@ -1,7 +1,7 @@ package com.threehundredbugs.subscriptio.data.mapper import com.threehundredbugs.subscriptio.data.api.model.TokenApi -import com.threehundredbugs.subscriptio.domain.enity.Token +import com.threehundredbugs.subscriptio.domain.entity.Token fun mapTokenApiToToken(tokenApi: TokenApi) =// mapTokenApiToTokenEntity ?? Token(tokenApi.token, tokenApi.expiresIn+System.currentTimeMillis()) // TODO: If the function is not called immediately, expiration time is incorrect diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/data/mapper/TransactionMapper.kt b/app/src/main/java/com/threehundredbugs/subscriptio/data/mapper/TransactionMapper.kt index d80dccd..c823b3d 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/data/mapper/TransactionMapper.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/data/mapper/TransactionMapper.kt @@ -1,20 +1,16 @@ package com.threehundredbugs.subscriptio.data.mapper -import android.os.Build -import androidx.annotation.RequiresApi import com.threehundredbugs.subscriptio.data.api.model.TransactionApi import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel -import com.threehundredbugs.subscriptio.domain.enity.AmountEntityField -import com.threehundredbugs.subscriptio.domain.enity.BalanceEntityField -import com.threehundredbugs.subscriptio.domain.enity.BankTransactionCodeEntityField -import com.threehundredbugs.subscriptio.domain.enity.DataEntityField -import com.threehundredbugs.subscriptio.domain.enity.ProprietaryBankTransactionCodeEntityField -import com.threehundredbugs.subscriptio.domain.enity.TransactionEntity -import com.threehundredbugs.subscriptio.domain.enity.TransactionEntityField -import java.sql.Date +import com.threehundredbugs.subscriptio.domain.entity.AmountEntityField +import com.threehundredbugs.subscriptio.domain.entity.BalanceEntityField +import com.threehundredbugs.subscriptio.domain.entity.BankTransactionCodeEntityField +import com.threehundredbugs.subscriptio.domain.entity.DataEntityField +import com.threehundredbugs.subscriptio.domain.entity.ProprietaryBankTransactionCodeEntityField +import com.threehundredbugs.subscriptio.domain.entity.TransactionEntity +import com.threehundredbugs.subscriptio.domain.entity.TransactionEntityField import java.text.SimpleDateFormat -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter + fun mapTransactionalApiToEntity(transactionApi: TransactionApi) = TransactionEntity( data = DataEntityField( transaction = transactionApi.data.transaction.map { @@ -55,7 +51,7 @@ fun mapTransactionalApiToEntity(transactionApi: TransactionApi) = TransactionEnt ) }, merchantDetails = it.merchantDetails?.let { merchantDetails -> - com.threehundredbugs.subscriptio.domain.enity.MerchantDetailsEntityField( + com.threehundredbugs.subscriptio.domain.entity.MerchantDetailsEntityField( merchantName = merchantDetails.merchantName, merchantCategoryCode = merchantDetails.merchantCategoryCode ) diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/data/repository/TransactionRepositoryImpl.kt b/app/src/main/java/com/threehundredbugs/subscriptio/data/repository/TransactionRepositoryImpl.kt index 2632ca9..bd7dd84 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/data/repository/TransactionRepositoryImpl.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/data/repository/TransactionRepositoryImpl.kt @@ -1,11 +1,10 @@ package com.threehundredbugs.subscriptio.data.repository import com.threehundredbugs.subscriptio.data.api.TransactionNetworkDataSource -import com.threehundredbugs.subscriptio.data.local.MainDatabase import com.threehundredbugs.subscriptio.data.mapper.mapTransactionalApiToEntity -import com.threehundredbugs.subscriptio.domain.enity.Result -import com.threehundredbugs.subscriptio.domain.enity.ResultType -import com.threehundredbugs.subscriptio.domain.enity.TransactionEntity +import com.threehundredbugs.subscriptio.domain.entity.Result +import com.threehundredbugs.subscriptio.domain.entity.ResultType +import com.threehundredbugs.subscriptio.domain.entity.TransactionEntity import com.threehundredbugs.subscriptio.domain.repository.TransactionRepository class TransactionRepositoryImpl: TransactionRepository { diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/DefinerAlg.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/DefinerAlg.kt new file mode 100644 index 0000000..2113f5c --- /dev/null +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/DefinerAlg.kt @@ -0,0 +1,64 @@ +package com.threehundredbugs.subscriptio.domain.actions + +import android.icu.text.SimpleDateFormat +import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel +import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity + +val SIMILAR_TRANSACTIONS_THRESHOLD = 2 +fun getSubscriptions( + transactions: MutableList<TransactionDbModel> + +): MutableList<SubscriptionEntity> { + + val sortedByTimeTransactions = transactions.sortedBy { it.bookingDateTime }.toMutableList() + val subBuilder: MutableList<SubscriptionEntity> = mutableListOf() + while (sortedByTimeTransactions.isNotEmpty()) { + val latestTransaction = sortedByTimeTransactions[0] + sortedByTimeTransactions.removeAt(0) + for (transaction in sortedByTimeTransactions) { + for (prd in Period.values()) { + if (nodeOfChainSubs(latestTransaction, transaction, prd)) { + if (prd.lst.isEmpty()) prd.lst.add(latestTransaction) + prd.lst.add(transaction) + } + } + } + for (prd in Period.values()) { + if (prd.lst.size >= SIMILAR_TRANSACTIONS_THRESHOLD) { + subBuilder.add( + SubscriptionEntity( + active = prd.isActive(latestTransaction.bookingDateTime), + name = latestTransaction.merchantName + ?: "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñка", // TODO: strings.xml : unknown_subscription_label + lastOrNextTransactionDate = SimpleDateFormat("yyyy.MM.dd HH:mm").format( + latestTransaction.bookingDateTime + ), + sum = latestTransaction.amount.toString(), + transactionDate = prd.lst.toMutableList(), + bankCard = latestTransaction.accountId, + subscriptionLink = "", + period = prd.ordinal + ) + ) + sortedByTimeTransactions.removeAll(prd.lst) + } + prd.lst.clear() + } + + } + return subBuilder +} + + +fun nodeOfChainSubs( + first: TransactionDbModel, + second: TransactionDbModel, + period: Period +): Boolean { + return first.currency == second.currency + && + first.amount == second.amount && + first.merchantName == second.merchantName && + period.differ(first.bookingDateTime, second.bookingDateTime) +} + diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/Period.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/Period.kt new file mode 100644 index 0000000..4781ed3 --- /dev/null +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/Period.kt @@ -0,0 +1,90 @@ +package com.threehundredbugs.subscriptio.domain.actions + +import android.icu.util.Calendar +import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel +import kotlin.math.abs + +enum class Period { + WEEK { + override fun differ(firstDate: Long, secondDate: Long) = + kotlin.math.abs( + kotlin.math.abs( + getDateInDays(firstDate / 1000) - getDateInDays( + secondDate / 1000 + ) + ) - 7L + ) <= 2 + + override fun isActive(last: Long): Boolean = + abs(Calendar.getInstance().timeInMillis - last) <= 7 + + override val lst: MutableList<TransactionDbModel> = mutableListOf() + + }, + TWO_WEEKS { + override fun differ(firstDate: Long, secondDate: Long) = + kotlin.math.abs( + kotlin.math.abs( + getDateInDays(firstDate / 1000) - getDateInDays( + secondDate / 1000 + ) + ) - 14L + ) <= 4 + + override fun isActive(last: Long): Boolean = + abs(Calendar.getInstance().timeInMillis - last) <= 14 + + override val lst: MutableList<TransactionDbModel> = mutableListOf() + }, + MONTH { + override fun differ(firstDate: Long, secondDate: Long) = + kotlin.math.abs( + kotlin.math.abs( + getDateInDays(firstDate / 1000) - getDateInDays( + secondDate / 1000 + ) + ) - 31L + ) <= 5 + + override fun isActive(last: Long): Boolean = + abs(Calendar.getInstance().timeInMillis - last) <= 31 + + override val lst: MutableList<TransactionDbModel> = mutableListOf() + }, + SIX_MONTHS { + override fun differ(firstDate: Long, secondDate: Long) = + kotlin.math.abs( + kotlin.math.abs( + getDateInDays(firstDate / 1000) - getDateInDays( + secondDate / 1000 + ) + ) - 186L + ) <= 10 + + override fun isActive(last: Long): Boolean = + abs(Calendar.getInstance().timeInMillis - last) <= 186 + + override val lst: MutableList<TransactionDbModel> = mutableListOf() + }, + YEAR { + override fun differ(firstDate: Long, secondDate: Long) = + kotlin.math.abs( + kotlin.math.abs( + getDateInDays(firstDate / 1000) - getDateInDays( + secondDate / 1000 + ) + ) - 365L + ) <= 20 + + override fun isActive(last: Long): Boolean = + abs(Calendar.getInstance().timeInMillis - last) <= 365 + + override val lst: MutableList<TransactionDbModel> = mutableListOf() + }; + + abstract fun differ(firstDate: Long, secondDate: Long): Boolean + abstract fun isActive(last: Long): Boolean + abstract val lst: MutableList<TransactionDbModel> +} + +fun getDateInDays(transactionDate: Long) = transactionDate / 86400 \ No newline at end of file diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/mergeTransaction.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/mergeTransaction.kt index 4e89c4d..d906713 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/mergeTransaction.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/mergeTransaction.kt @@ -1,8 +1,8 @@ package com.threehundredbugs.subscriptio.domain.actions -import com.threehundredbugs.subscriptio.domain.enity.Result -import com.threehundredbugs.subscriptio.domain.enity.ResultType -import com.threehundredbugs.subscriptio.domain.enity.TransactionEntity +import com.threehundredbugs.subscriptio.domain.entity.Result +import com.threehundredbugs.subscriptio.domain.entity.ResultType +import com.threehundredbugs.subscriptio.domain.entity.TransactionEntity import com.threehundredbugs.subscriptio.data.local.repository.TransactionRepository import com.threehundredbugs.subscriptio.data.mapper.mapTransactionEntityToDbModel @@ -16,7 +16,7 @@ suspend fun mergeTransactions(dbInstance: TransactionRepository, networkResult: val transactionModel = mapTransactionEntityToDbModel(transaction) val similarTransactions = dbInstance.getAllByDate(transactionModel.bookingDateTime, transactionModel.bookingDateTime) for (similarTransaction in similarTransactions) { - if (similarTransaction.equalWithoutId(transactionModel)) { + if (similarTransaction.equalWithoutId(transactionModel)) { // TODO: Add transactionId field to the entity so we can compare it if it is present return } } diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt new file mode 100644 index 0000000..c9dd307 --- /dev/null +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt @@ -0,0 +1,58 @@ +package com.threehundredbugs.subscriptio.domain.actions + +import android.util.Log +import com.threehundredbugs.subscriptio.data.local.repository.SubscriptionRepository +import com.threehundredbugs.subscriptio.data.local.repository.TransactionRepository +import com.threehundredbugs.subscriptio.data.repository.TransactionRepositoryImpl +import com.threehundredbugs.subscriptio.domain.entity.ResultType +import com.threehundredbugs.subscriptio.domain.usecase.GetTransactionUseCase + + +suspend fun networkUpdate( + transactionRepository: TransactionRepository, + subscriptionRepository: SubscriptionRepository +) { + val transactionUseCase = GetTransactionUseCase(TransactionRepositoryImpl()) + + // Get updated transactions from the API + val networkResult = transactionUseCase.execute() + //TODO добавить реализацию Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… из мокапа + if (networkResult.resultType == ResultType.ERROR) { + //TODO обработать ошибки + Log.e("NETWORK_ERROR", networkResult.error?.stackTraceToString() ?: "") + } else { + mergeTransactions(transactionRepository, networkResult) // Merge with the database + } + + // Detect all available subscriptions + val subscriptions = getSubscriptions( + transactionRepository.getAll().toMutableList() + ) + // Update existing subscriptions and add new ones + for (subscription in subscriptions) { + if (subscription.transactionDate.isEmpty()) continue + val subscriptionId = + subscriptionRepository.getAllSubscriptions().find { + it.sum == subscription.sum && it.lastOrNextTransactionDate == subscription.lastOrNextTransactionDate + && it.bankCard == subscription.bankCard && it.period == subscription.period + }?.id + if (subscriptionId != null) { // if similar subscription was fund + + for (transaction in subscription.transactionDate) // update it`s transactions + transactionRepository.update(transaction.copy(associatedSubscriptionId = subscriptionId)) + + } else { // if this is a new subscription + subscriptionRepository.insertSubscription(subscription) + } + } +// Testing data +// val transactions = transactionRepository.getAll() + TransactionDbModel( +// id = 0, +// accountId = "87659", +// amount = 1000.0, +// currency = "RUB", +// bookingDateTime = 1548142387000, +// bankTransactionCode = "ReceivedCreditTransfer", +// bankTransactionSubCode = "DomesticCreditTransfer" +// ) +} \ No newline at end of file diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/ResultType.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/ResultType.kt deleted file mode 100644 index 3c1f9a2..0000000 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/ResultType.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.threehundredbugs.subscriptio.domain.enity - -enum class ResultType { - ERROR, SUCCESS -} \ No newline at end of file diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/Result.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/Result.kt similarity index 87% rename from app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/Result.kt rename to app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/Result.kt index a903b88..57ec970 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/Result.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/Result.kt @@ -1,4 +1,4 @@ -package com.threehundredbugs.subscriptio.domain.enity +package com.threehundredbugs.subscriptio.domain.entity data class Result<out T>( var resultType: ResultType, diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/ResultType.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/ResultType.kt new file mode 100644 index 0000000..039580c --- /dev/null +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/ResultType.kt @@ -0,0 +1,5 @@ +package com.threehundredbugs.subscriptio.domain.entity + +enum class ResultType { + ERROR, SUCCESS +} \ No newline at end of file diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/SubscriptionEntity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SubscriptionEntity.kt similarity index 78% rename from app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/SubscriptionEntity.kt rename to app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SubscriptionEntity.kt index 50aff17..72302d6 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/SubscriptionEntity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SubscriptionEntity.kt @@ -1,8 +1,9 @@ -package com.threehundredbugs.subscriptio.domain.enity +package com.threehundredbugs.subscriptio.domain.entity import androidx.room.Entity import androidx.room.Ignore import androidx.room.PrimaryKey +import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel import java.io.Serializable @Entity(tableName = "Subscriptions") @@ -13,7 +14,7 @@ data class SubscriptionEntity( val lastOrNextTransactionDate: String, val sum: String, @Ignore - val transactionDate: List<String>, + val transactionDate: List<TransactionDbModel>, val bankCard: String, val subscriptionLink: String, @PrimaryKey(autoGenerate = true) @@ -44,4 +45,8 @@ data class SubscriptionEntity( period, notify ) + + override fun toString(): String { + return "Subscription $name for $sum" + } } diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/Token.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/Token.kt similarity index 83% rename from app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/Token.kt rename to app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/Token.kt index 1a13b0e..bbf747d 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/Token.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/Token.kt @@ -1,4 +1,4 @@ -package com.threehundredbugs.subscriptio.domain.enity +package com.threehundredbugs.subscriptio.domain.entity class Token(val token: String, val expiration: Long) { diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/TransactionEntity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/TransactionEntity.kt similarity index 96% rename from app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/TransactionEntity.kt rename to app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/TransactionEntity.kt index e72f815..2270422 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/enity/TransactionEntity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/TransactionEntity.kt @@ -1,4 +1,4 @@ -package com.threehundredbugs.subscriptio.domain.enity +package com.threehundredbugs.subscriptio.domain.entity data class TransactionEntity( val data: DataEntityField diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/repository/TransactionRepository.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/repository/TransactionRepository.kt index 3cdfe36..a0953d8 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/repository/TransactionRepository.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/repository/TransactionRepository.kt @@ -1,7 +1,7 @@ package com.threehundredbugs.subscriptio.domain.repository -import com.threehundredbugs.subscriptio.domain.enity.Result -import com.threehundredbugs.subscriptio.domain.enity.TransactionEntity +import com.threehundredbugs.subscriptio.domain.entity.Result +import com.threehundredbugs.subscriptio.domain.entity.TransactionEntity interface TransactionRepository { diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/usecase/GetTransactionUseCase.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/usecase/GetTransactionUseCase.kt index 3a9c66d..97851bf 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/usecase/GetTransactionUseCase.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/usecase/GetTransactionUseCase.kt @@ -1,6 +1,6 @@ package com.threehundredbugs.subscriptio.domain.usecase -import com.threehundredbugs.subscriptio.domain.enity.Result -import com.threehundredbugs.subscriptio.domain.enity.TransactionEntity +import com.threehundredbugs.subscriptio.domain.entity.Result +import com.threehundredbugs.subscriptio.domain.entity.TransactionEntity import com.threehundredbugs.subscriptio.domain.repository.TransactionRepository class GetTransactionUseCase(private val transactionRepository: TransactionRepository) { diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/AddSubscriptionActivity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/AddSubscriptionActivity.kt index 42c3043..bd7d2ea 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/AddSubscriptionActivity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/AddSubscriptionActivity.kt @@ -3,7 +3,6 @@ package com.threehundredbugs.subscriptio.presentation import android.content.Context import android.content.Intent import android.os.Bundle -import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.background @@ -41,8 +40,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.threehundredbugs.subscriptio.R import com.threehundredbugs.subscriptio.data.repository.TransactionRepositoryImpl -import com.threehundredbugs.subscriptio.domain.enity.TransactionEntity -import com.threehundredbugs.subscriptio.domain.enity.TransactionEntityField +import com.threehundredbugs.subscriptio.domain.entity.TransactionEntity +import com.threehundredbugs.subscriptio.domain.entity.TransactionEntityField import com.threehundredbugs.subscriptio.domain.usecase.GetTransactionUseCase import com.threehundredbugs.subscriptio.presentation.ui.theme.SubScriptioTheme import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/EditSubscriptionDetailActivity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/EditSubscriptionDetailActivity.kt index c7862b7..6021b7c 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/EditSubscriptionDetailActivity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/EditSubscriptionDetailActivity.kt @@ -5,7 +5,6 @@ import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.activity.viewModels import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -48,7 +47,7 @@ import androidx.lifecycle.lifecycleScope import com.threehundredbugs.subscriptio.R import com.threehundredbugs.subscriptio.data.local.MainDatabase import com.threehundredbugs.subscriptio.data.local.repository.SubscriptionRepository -import com.threehundredbugs.subscriptio.domain.enity.SubscriptionEntity +import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity import com.threehundredbugs.subscriptio.presentation.ui.theme.SubScriptioTheme import kotlinx.coroutines.launch @@ -310,7 +309,7 @@ fun EditTransactionInterval( fun EditSubscriptionCost(subscription: SubscriptionEntity, onValueChange: (String) -> Unit) { var cost by remember { mutableStateOf( - subscription.sum.toIntOrNull() ?: 0 + subscription.sum.toDoubleOrNull() ?: 0.0 ) } var isError by remember { mutableStateOf(false) } @@ -327,7 +326,7 @@ fun EditSubscriptionCost(subscription: SubscriptionEntity, onValueChange: (Strin isError = isError, onValueChange = { try { - cost = it.toInt() + cost = it.toDouble() isError = false onValueChange(it) } catch (e: Exception) { diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/EditSubscriptionDetailViewModel.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/EditSubscriptionDetailViewModel.kt index 9171817..65cad16 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/EditSubscriptionDetailViewModel.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/EditSubscriptionDetailViewModel.kt @@ -1,7 +1,7 @@ package com.threehundredbugs.subscriptio.presentation import androidx.lifecycle.ViewModel -import com.threehundredbugs.subscriptio.domain.enity.SubscriptionEntity +import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity class EditSubscriptionDetailViewModel( private val subscriptionEntity: SubscriptionEntity diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/MainActivity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/MainActivity.kt index 007085b..1c0a763 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/MainActivity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/MainActivity.kt @@ -1,11 +1,9 @@ package com.threehundredbugs.subscriptio.presentation -import android.os.Build import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -26,8 +24,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.lifecycleScope import com.threehundredbugs.subscriptio.R -import com.threehundredbugs.subscriptio.data.api.TransactionNetworkDataSource -import com.threehundredbugs.subscriptio.data.api.retrofit.BankApi import com.threehundredbugs.subscriptio.data.cache.CacheUtils import com.threehundredbugs.subscriptio.data.cache.CacheUtils.IS_USER_LOGIN import com.threehundredbugs.subscriptio.data.local.MainDatabase @@ -35,10 +31,8 @@ import com.threehundredbugs.subscriptio.data.local.repository.SubscriptionReposi import com.threehundredbugs.subscriptio.data.local.repository.TransactionRepository import com.threehundredbugs.subscriptio.data.repository.TransactionRepositoryImpl -import com.threehundredbugs.subscriptio.domain.enity.SubscriptionEntity - import com.threehundredbugs.subscriptio.domain.actions.mergeTransactions -import com.threehundredbugs.subscriptio.domain.enity.ResultType +import com.threehundredbugs.subscriptio.domain.entity.ResultType import com.threehundredbugs.subscriptio.domain.usecase.GetTransactionUseCase import com.threehundredbugs.subscriptio.presentation.theme.SubScriptioTheme @@ -65,6 +59,21 @@ class MainActivity : ComponentActivity() { TransactionRepository(MainDatabase.getInstance(application).transactionDao()) } + +// lifecycleScope.launch { +// Log.d("UPDATE","Network update started") +// +// networkUpdate(transactionRepository, subscriptionRepository) +// Log.d("UPDATE","Network update finished") +// } +// runBlocking{ +// Log.d("UPDATE","Network update started") +// +// networkUpdate(transactionRepository, subscriptionRepository) +// Log.d("UPDATE","Network update finished") +// } + + //Log.d("ROOM_LOG", transactionRepository.getAll().toString()) diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDashBoardActivity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDashBoardActivity.kt index 26c3d1a..dd33dd9 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDashBoardActivity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDashBoardActivity.kt @@ -55,11 +55,11 @@ import androidx.lifecycle.lifecycleScope import com.threehundredbugs.subscriptio.R import com.threehundredbugs.subscriptio.data.local.MainDatabase import com.threehundredbugs.subscriptio.data.local.repository.SubscriptionRepository -import com.threehundredbugs.subscriptio.domain.enity.SubscriptionEntity +import com.threehundredbugs.subscriptio.data.local.repository.TransactionRepository +import com.threehundredbugs.subscriptio.domain.actions.networkUpdate +import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity import com.threehundredbugs.subscriptio.presentation.ui.theme.SubScriptioTheme -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking class SubscriptionDashBoardActivity : ComponentActivity() { @@ -67,10 +67,18 @@ class SubscriptionDashBoardActivity : ComponentActivity() { SubscriptionRepository(MainDatabase.getInstance(application).subscriptionDao()) } + private val transactionRepository by lazy { + TransactionRepository(MainDatabase.getInstance(application).transactionDao()) + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + lifecycleScope.launch { + Log.d("UPDATE", "Network update started") + networkUpdate(transactionRepository, subscriptionRepository) + Log.d("UPDATE", "Network update finished") + } setContent { var subscription by remember { diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDetailActivity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDetailActivity.kt index 18198d2..c43da97 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDetailActivity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDetailActivity.kt @@ -26,14 +26,13 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.threehundredbugs.subscriptio.R -import com.threehundredbugs.subscriptio.domain.enity.SubscriptionEntity +import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity import com.threehundredbugs.subscriptio.presentation.ui.theme.SubScriptioTheme class SubscriptionDetailActivity : ComponentActivity() { diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/VtbLoginActivity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/VtbLoginActivity.kt index d7e319b..512b2fb 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/VtbLoginActivity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/VtbLoginActivity.kt @@ -3,7 +3,6 @@ package com.threehundredbugs.subscriptio.presentation import android.content.Context import android.content.Intent import android.os.Bundle -import android.util.Log import android.view.ViewGroup import android.webkit.WebView import android.webkit.WebViewClient @@ -20,22 +19,16 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView -import androidx.lifecycle.lifecycleScope import com.threehundredbugs.subscriptio.R import com.threehundredbugs.subscriptio.data.cache.CacheUtils import com.threehundredbugs.subscriptio.data.cache.CacheUtils.IS_USER_LOGIN import com.threehundredbugs.subscriptio.data.local.MainDatabase import com.threehundredbugs.subscriptio.data.local.repository.TransactionRepository import com.threehundredbugs.subscriptio.data.repository.TransactionRepositoryImpl -import com.threehundredbugs.subscriptio.domain.actions.mergeTransactions -import com.threehundredbugs.subscriptio.domain.enity.ResultType import com.threehundredbugs.subscriptio.domain.usecase.GetTransactionUseCase import com.threehundredbugs.subscriptio.presentation.ui.theme.SubScriptioTheme -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch class VtbLoginActivity : ComponentActivity() { private val transactionUseCase = GetTransactionUseCase(TransactionRepositoryImpl()) @@ -57,18 +50,11 @@ class VtbLoginActivity : ComponentActivity() { modifier = Modifier .fillMaxHeight(0.05f) .clickable { - CacheUtils.setBoolean(IS_USER_LOGIN, true, this@VtbLoginActivity) - lifecycleScope.launch(Dispatchers.IO) { - val networkResult = transactionUseCase.execute() - //TODO добавить реализацию Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… из мокапа - if (networkResult.resultType == ResultType.ERROR) { - //TODO обработать ошибки - Log.e("NETWORK_ERROR", networkResult.error?.stackTraceToString() ?: "") - } - else { - mergeTransactions(transactionRepository, networkResult) - } - } + CacheUtils.setBoolean( + IS_USER_LOGIN, + true, + this@VtbLoginActivity + ) startActivity(SubscriptionDashBoardActivity.newInstance(this@VtbLoginActivity)) finish() }, @@ -82,10 +68,12 @@ class VtbLoginActivity : ComponentActivity() { } } } + companion object { fun newInstance(context: Context) = Intent(context, VtbLoginActivity::class.java) } } + @Composable fun VtbLogin() { val url = "https://www.vtb.ru/" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d4df77..58db9cb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,4 +27,5 @@ <string name="login_by_vtb">Войти Ñ Ð’Ð¢Ð‘ ID</string> <string name="next_step">Перейти на Ñледующий Ñтап</string> <string name="database_error">Ðе удалоÑÑŒ прочитать базу данных. Попробуйте очиÑтить данные приложениÑ</string> + <string name="unknown_subscription_label">ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñка</string> </resources> \ No newline at end of file -- GitLab From 67adb656b28638ca67a8c45cac7e5d7548039f2b Mon Sep 17 00:00:00 2001 From: "nikitkagorkov@gmail.com" <gerosp> Date: Wed, 18 Oct 2023 02:20:42 +0300 Subject: [PATCH 2/3] Added random tests --- .../subscriptio/domain/actions/DefinerAlg.kt | 15 +++- .../subscriptio/domain/actions/Period.kt | 8 +- .../domain/actions/networkUpdate.kt | 10 ++- .../domain/entity/SubscriptionEntity.kt | 4 +- .../presentation/AddSubscriptionActivity.kt | 19 +++- .../SubscriptionDashBoardActivity.kt | 24 +++-- .../subscriptio/SampleGenerator.kt | 87 +++++++++++++------ 7 files changed, 119 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/DefinerAlg.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/DefinerAlg.kt index 2113f5c..4b815d8 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/DefinerAlg.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/DefinerAlg.kt @@ -1,6 +1,7 @@ package com.threehundredbugs.subscriptio.domain.actions import android.icu.text.SimpleDateFormat +import android.util.Log import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity @@ -13,18 +14,20 @@ fun getSubscriptions( val sortedByTimeTransactions = transactions.sortedBy { it.bookingDateTime }.toMutableList() val subBuilder: MutableList<SubscriptionEntity> = mutableListOf() while (sortedByTimeTransactions.isNotEmpty()) { - val latestTransaction = sortedByTimeTransactions[0] + var latestTransaction = sortedByTimeTransactions[0] sortedByTimeTransactions.removeAt(0) for (transaction in sortedByTimeTransactions) { for (prd in Period.values()) { if (nodeOfChainSubs(latestTransaction, transaction, prd)) { if (prd.lst.isEmpty()) prd.lst.add(latestTransaction) + latestTransaction = transaction prd.lst.add(transaction) } } } for (prd in Period.values()) { if (prd.lst.size >= SIMILAR_TRANSACTIONS_THRESHOLD) { +// latestTransaction = prd.lst[0] subBuilder.add( SubscriptionEntity( active = prd.isActive(latestTransaction.bookingDateTime), @@ -41,6 +44,10 @@ fun getSubscriptions( ) ) sortedByTimeTransactions.removeAll(prd.lst) + for (period in Period.values()) { + period.lst.clear() + } + break } prd.lst.clear() } @@ -55,10 +62,12 @@ fun nodeOfChainSubs( second: TransactionDbModel, period: Period ): Boolean { + return first.currency == second.currency && first.amount == second.amount && - first.merchantName == second.merchantName && - period.differ(first.bookingDateTime, second.bookingDateTime) + first.merchantName == second.merchantName + && ( + period.differ(first.bookingDateTime, second.bookingDateTime)) } diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/Period.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/Period.kt index 4781ed3..76a933b 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/Period.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/Period.kt @@ -13,7 +13,7 @@ enum class Period { secondDate / 1000 ) ) - 7L - ) <= 2 + ) <= 3 override fun isActive(last: Long): Boolean = abs(Calendar.getInstance().timeInMillis - last) <= 7 @@ -29,7 +29,7 @@ enum class Period { secondDate / 1000 ) ) - 14L - ) <= 4 + ) <= 5 override fun isActive(last: Long): Boolean = abs(Calendar.getInstance().timeInMillis - last) <= 14 @@ -44,7 +44,7 @@ enum class Period { secondDate / 1000 ) ) - 31L - ) <= 5 + ) <= 10 override fun isActive(last: Long): Boolean = abs(Calendar.getInstance().timeInMillis - last) <= 31 @@ -59,7 +59,7 @@ enum class Period { secondDate / 1000 ) ) - 186L - ) <= 10 + ) <= 15 override fun isActive(last: Long): Boolean = abs(Calendar.getInstance().timeInMillis - last) <= 186 diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt index c9dd307..e43d065 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt @@ -1,6 +1,7 @@ package com.threehundredbugs.subscriptio.domain.actions import android.util.Log +import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel import com.threehundredbugs.subscriptio.data.local.repository.SubscriptionRepository import com.threehundredbugs.subscriptio.data.local.repository.TransactionRepository import com.threehundredbugs.subscriptio.data.repository.TransactionRepositoryImpl @@ -10,8 +11,9 @@ import com.threehundredbugs.subscriptio.domain.usecase.GetTransactionUseCase suspend fun networkUpdate( transactionRepository: TransactionRepository, - subscriptionRepository: SubscriptionRepository + subscriptionRepository: SubscriptionRepository, ) { + val transactionUseCase = GetTransactionUseCase(TransactionRepositoryImpl()) // Get updated transactions from the API @@ -30,7 +32,7 @@ suspend fun networkUpdate( ) // Update existing subscriptions and add new ones for (subscription in subscriptions) { - if (subscription.transactionDate.isEmpty()) continue + if (subscription.transactionDate?.isEmpty() == true || subscription.transactionDate == null) continue val subscriptionId = subscriptionRepository.getAllSubscriptions().find { it.sum == subscription.sum && it.lastOrNextTransactionDate == subscription.lastOrNextTransactionDate @@ -38,13 +40,15 @@ suspend fun networkUpdate( }?.id if (subscriptionId != null) { // if similar subscription was fund - for (transaction in subscription.transactionDate) // update it`s transactions + for (transaction in subscription.transactionDate!!) // update it`s transactions transactionRepository.update(transaction.copy(associatedSubscriptionId = subscriptionId)) } else { // if this is a new subscription subscriptionRepository.insertSubscription(subscription) } } + + // Testing data // val transactions = transactionRepository.getAll() + TransactionDbModel( // id = 0, diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SubscriptionEntity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SubscriptionEntity.kt index 72302d6..54e272e 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SubscriptionEntity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SubscriptionEntity.kt @@ -5,7 +5,6 @@ import androidx.room.Ignore import androidx.room.PrimaryKey import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel import java.io.Serializable - @Entity(tableName = "Subscriptions") data class SubscriptionEntity( @@ -14,7 +13,8 @@ data class SubscriptionEntity( val lastOrNextTransactionDate: String, val sum: String, @Ignore - val transactionDate: List<TransactionDbModel>, + @Transient + val transactionDate: List<TransactionDbModel>?, val bankCard: String, val subscriptionLink: String, @PrimaryKey(autoGenerate = true) diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/AddSubscriptionActivity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/AddSubscriptionActivity.kt index bd7d2ea..19376b1 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/AddSubscriptionActivity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/AddSubscriptionActivity.kt @@ -40,6 +40,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.threehundredbugs.subscriptio.R import com.threehundredbugs.subscriptio.data.repository.TransactionRepositoryImpl +import com.threehundredbugs.subscriptio.domain.entity.DataEntityField +import com.threehundredbugs.subscriptio.domain.entity.SampleGenerator import com.threehundredbugs.subscriptio.domain.entity.TransactionEntity import com.threehundredbugs.subscriptio.domain.entity.TransactionEntityField import com.threehundredbugs.subscriptio.domain.usecase.GetTransactionUseCase @@ -55,6 +57,9 @@ class AddSubscriptionActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + +// val data = SampleGenerator().generateSampleTransactionEntity(2) // TODO: Remove, debug + setContent { SubScriptioTheme { var selectedTransaction by remember { @@ -84,6 +89,14 @@ class AddSubscriptionActivity : ComponentActivity() { loading = false } } + + //debug + +// transactions = data // TODO: Remove debug code +// +// loading=false + + // End debug InfinityCircularIndicator(loading) AllTransactions(transactions, { selectedTransaction = selectedTransaction.toMutableList().apply { @@ -173,7 +186,7 @@ fun AllTransactions( Transaction(it, onAdd, onRemove) } } - Spacer(modifier = Modifier.padding( bottom = 6.dp)) + Spacer(modifier = Modifier.padding(bottom = 6.dp)) } } @@ -231,7 +244,9 @@ fun Transaction( ) } Text( - modifier = Modifier.padding(end = 6.dp, top = 5.dp).background(Color.Cyan), + modifier = Modifier + .padding(end = 6.dp, top = 5.dp) + .background(Color.Cyan), text = transaction.amount.amount + " " + transaction.amount.currency, fontWeight = FontWeight.SemiBold, fontSize = 16.sp diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDashBoardActivity.kt b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDashBoardActivity.kt index 835a203..eb9689e 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDashBoardActivity.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/presentation/SubscriptionDashBoardActivity.kt @@ -56,7 +56,9 @@ import com.threehundredbugs.subscriptio.R import com.threehundredbugs.subscriptio.data.local.MainDatabase import com.threehundredbugs.subscriptio.data.local.repository.SubscriptionRepository import com.threehundredbugs.subscriptio.data.local.repository.TransactionRepository +import com.threehundredbugs.subscriptio.domain.actions.getSubscriptions import com.threehundredbugs.subscriptio.domain.actions.networkUpdate +import com.threehundredbugs.subscriptio.domain.entity.SampleGenerator import com.threehundredbugs.subscriptio.domain.entity.SubscriptionEntity import com.threehundredbugs.subscriptio.presentation.ui.theme.SubScriptioTheme import kotlinx.coroutines.launch @@ -74,14 +76,24 @@ class SubscriptionDashBoardActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { - Log.d("UPDATE", "Network update started") - networkUpdate(transactionRepository, subscriptionRepository) - Log.d("UPDATE", "Network update finished") } + + + + val debug = false + + + val sampleTransactions = SampleGenerator().generateSampleTransactions() + val debugSubs = getSubscriptions(sampleTransactions.toMutableList()) + Log.d("DEBUG", sampleTransactions.toString()) + Log.d("DEBUG", debugSubs.toString()) + + setContent { var subscription by remember { + try { mutableStateOf(subscriptionRepository.getAllSubscriptions()) } catch (ex: Exception) { @@ -90,8 +102,8 @@ class SubscriptionDashBoardActivity : ComponentActivity() { mutableStateOf(listOf()) } } - - + if(debug) + subscription = debugSubs HomeScreen(subscription = subscription) { subscription = subscriptionRepository.getAllSubscriptions() @@ -410,7 +422,7 @@ fun SubscriptionCard(subscriptionEntity: SubscriptionEntity) { Text( text = stringResource( id = if (subscriptionEntity.active) R.string.next_transaction - else R.string.last_transaction + else R.string.last_transaction ), color = MaterialTheme.colorScheme.outline, fontWeight = FontWeight.SemiBold, diff --git a/app/src/test/java/com/threehundredbugs/subscriptio/SampleGenerator.kt b/app/src/test/java/com/threehundredbugs/subscriptio/SampleGenerator.kt index 2fbee76..e23b072 100644 --- a/app/src/test/java/com/threehundredbugs/subscriptio/SampleGenerator.kt +++ b/app/src/test/java/com/threehundredbugs/subscriptio/SampleGenerator.kt @@ -1,6 +1,8 @@ package com.threehundredbugs.subscriptio import com.threehundredbugs.subscriptio.data.api.model.* +import com.threehundredbugs.subscriptio.data.mapper.mapTransactionEntityToDbModel +import com.threehundredbugs.subscriptio.data.mapper.mapTransactionalApiToEntity import org.junit.Test import java.io.File import kotlin.math.max @@ -11,7 +13,8 @@ import kotlin.random.nextInt class SampleGenerator { val OPERATION_CODES = listOf("ReceivedCreditTransfer", "IssuedCreditTransfer") - val SUBCODES = listOf("InternalBookTransfer", "StandingOrder", "CrossBorderStandingOrder", + val SUBCODES = listOf( + "InternalBookTransfer", "StandingOrder", "CrossBorderStandingOrder", "SEPACreditTransfer", "DomesticCreditTransfer", "CrossBorderCreditTransfer", "CreditTransferWithAgreedCommercialInformation", "FinancialInstitutionCreditTransfer", "PriorityCreditTransfer", "PayrollSalaryPayment", "CrossBorderPayrollSalaryPayment", @@ -19,11 +22,12 @@ class SampleGenerator { "ReversalDueToPaymentReturnReimbursementOfACreditTransfer", "CrossBorderReversalDueToPaymentReturn", "AutomaticTransfer", "ACHTransaction", "ACHCorporateTrade", "ACHPreAuthorised", "ACHSettlement", "ACHReturn", "ACHReversal", - "ACHCredit", "ACHDebit", "TreasuryTaxAndLoanService", "NordicPaymentCouncilCreditTransfer") + "ACHCredit", "ACHDebit", "TreasuryTaxAndLoanService", "NordicPaymentCouncilCreditTransfer" + ) @Test fun generate_tests() { - for(j in 1..10){ + for (j in 1..10) { val transactionApi = generateTransactionApi() File("samples${j}.out").bufferedWriter().use { out -> out.write(transactionApi.toString()) @@ -31,6 +35,14 @@ class SampleGenerator { } } + fun generateSampleTransactions() { + for (j in 1..10) { + val transactionApi = generateTransactionApi() + val transactionData = mapTransactionalApiToEntity(transactionApi).data.transaction + mapTransactionEntityToDbModel(transactionData.first()) + } + } + fun getRandomString(length: Int): String { val allowedChars = ('a'..'z') + ('0'..'9') return (1..length).map { allowedChars.random() }.joinToString("") @@ -51,8 +63,12 @@ class SampleGenerator { } fun generateAmount(): AmountField { - val amount = Random.nextLong(0, 10.0.pow(Random.nextInt(1, 14).toDouble()).toLong()).toString() + '.' + - max(0, 2 * Random.nextInt(0, 10.0.pow(Random.nextInt(0, 6).toDouble()).toInt()) - 100).toString() + val amount = Random.nextLong(0, 10.0.pow(Random.nextInt(1, 14).toDouble()).toLong()) + .toString() + '.' + + max( + 0, + 2 * Random.nextInt(0, 10.0.pow(Random.nextInt(0, 6).toDouble()).toInt()) - 100 + ).toString() val currency = listOf("RUB", "USD", "EUR", "GBP").shuffled().first() return AmountField(amount, currency) } @@ -124,11 +140,17 @@ class SampleGenerator { val merchantCategoryCode = String.format("%04d", Random.nextInt(0, 10000)) //create last transaction transactions.add( - TransactionField(accountId = accountId, + TransactionField( + accountId = accountId, creditDebitIndicator = "Debit", status = "Booked", amount = amount, - bookingDateTime = String.format("%04d-%02d-%02dT00:00:00+00:00", year, month, day), + bookingDateTime = String.format( + "%04d-%02d-%02dT00:00:00+00:00", + year, + month, + day + ), bankTransactionCode = BankTransactionCodeField( code = "IssuedCreditTransfer", subCode = "AutomaticTransfer" @@ -140,7 +162,7 @@ class SampleGenerator { ) ) //generate other transactions - for (j in 1 .. Random.nextInt(1, 15)) { + for (j in 1..Random.nextInt(1, 15)) { val creditDebitIndicator = "Debit" if (period == "WEEKLY") { day -= 7 @@ -152,37 +174,43 @@ class SampleGenerator { year -= 1 } } - } - else if (period == "MONTHLY") { + } else if (period == "MONTHLY") { month -= 1 if (month < 1) { month += 12 year -= 1 } - } - else if (period == "3 MONTH") { + } else if (period == "3 MONTH") { month -= 3 if (month < 1) { month += 12 year -= 1 } - } - else { + } else { year -= 1 } - transactions.add(TransactionField(accountId = accountId, - creditDebitIndicator = creditDebitIndicator, - status = "Booked", - amount = amount, - bookingDateTime = String.format("%04d-%02d-%02dT00:00:00+00:00", year, month, day), - bankTransactionCode = BankTransactionCodeField( - code = "IssuedCreditTransfer", - subCode = "AutomaticTransfer" - ), - merchantDetails = MerchantDetailsField( - merchantName = merchantName, - merchantCategoryCode = merchantCategoryCode - ))) + transactions.add( + TransactionField( + accountId = accountId, + creditDebitIndicator = creditDebitIndicator, + status = "Booked", + amount = amount, + bookingDateTime = String.format( + "%04d-%02d-%02dT00:00:00+00:00", + year, + month, + day + ), + bankTransactionCode = BankTransactionCodeField( + code = "IssuedCreditTransfer", + subCode = "AutomaticTransfer" + ), + merchantDetails = MerchantDetailsField( + merchantName = merchantName, + merchantCategoryCode = merchantCategoryCode + ) + ) + ) } } for (i in 1..Random.nextInt(1, 10000)) { @@ -192,7 +220,10 @@ class SampleGenerator { val df = DataField(transactions) val rf = RiskField() val lf = LinksField("https://bank.ru/open-banking/v3.1/aisp/accounts/87659/transactions/") - val mf = MetaField("1", transactions.minOf { it.bookingDateTime }, transactions.maxOf { it.bookingDateTime }) + val mf = MetaField( + "1", + transactions.minOf { it.bookingDateTime }, + transactions.maxOf { it.bookingDateTime }) return TransactionApi(df, rf, lf, mf) } -- GitLab From 88de3102edace84076592f8b29896126e5e9b30d Mon Sep 17 00:00:00 2001 From: "nikitkagorkov@gmail.com" <gerosp> Date: Wed, 18 Oct 2023 09:00:10 +0300 Subject: [PATCH 3/3] Added random tests --- .../domain/actions/networkUpdate.kt | 2 +- .../domain/entity/SampleGenerator.kt | 240 ++++++++++++++++++ 2 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SampleGenerator.kt diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt index e43d065..1c20334 100644 --- a/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/actions/networkUpdate.kt @@ -49,7 +49,7 @@ suspend fun networkUpdate( } -// Testing data +// Testing data DO NOT DELETE // val transactions = transactionRepository.getAll() + TransactionDbModel( // id = 0, // accountId = "87659", diff --git a/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SampleGenerator.kt b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SampleGenerator.kt new file mode 100644 index 0000000..b566980 --- /dev/null +++ b/app/src/main/java/com/threehundredbugs/subscriptio/domain/entity/SampleGenerator.kt @@ -0,0 +1,240 @@ +package com.threehundredbugs.subscriptio.domain.entity + +import com.threehundredbugs.subscriptio.data.api.model.* +import com.threehundredbugs.subscriptio.data.local.dbmodel.TransactionDbModel +import com.threehundredbugs.subscriptio.data.mapper.mapTransactionEntityToDbModel +import com.threehundredbugs.subscriptio.data.mapper.mapTransactionalApiToEntity + +import java.io.File +import kotlin.math.max +import kotlin.math.pow +import kotlin.random.Random +import kotlin.random.nextInt + +class SampleGenerator { + + val OPERATION_CODES = listOf("ReceivedCreditTransfer", "IssuedCreditTransfer") + val SUBCODES = listOf( + "InternalBookTransfer", "StandingOrder", "CrossBorderStandingOrder", + "SEPACreditTransfer", "DomesticCreditTransfer", "CrossBorderCreditTransfer", + "CreditTransferWithAgreedCommercialInformation", "FinancialInstitutionCreditTransfer", + "PriorityCreditTransfer", "PayrollSalaryPayment", "CrossBorderPayrollSalaryPayment", + "SameDayValueCreditTransfer", "ReversalDueToPaymentCancellationRequest", + "ReversalDueToPaymentReturnReimbursementOfACreditTransfer", + "CrossBorderReversalDueToPaymentReturn", "AutomaticTransfer", "ACHTransaction", + "ACHCorporateTrade", "ACHPreAuthorised", "ACHSettlement", "ACHReturn", "ACHReversal", + "ACHCredit", "ACHDebit", "TreasuryTaxAndLoanService", "NordicPaymentCouncilCreditTransfer" + ) + + + fun generate_tests() { + for (j in 1..10) { + val transactionApi = generateTransactionApi() + File("samples${j}.out").bufferedWriter().use { out -> + out.write(transactionApi.toString()) + } + } + } + + fun generateSampleTransactions(subscriptionsNumber: Int = 1): List<TransactionDbModel> { + val transactions = mutableListOf<TransactionDbModel>() + for (j in 1..1) { + val transactionApi = generateTransactionApi() + val transactionData = mapTransactionalApiToEntity(transactionApi).data.transaction + for (data in transactionData) { + + transactions.add(mapTransactionEntityToDbModel(data)) + } + + } + return transactions + } + + fun generateSampleTransactionEntity(iterations: Int = 100): TransactionEntity { + val transactionApi = generateTransactionApi(iterations) + return mapTransactionalApiToEntity(transactionApi) + } + + fun getRandomString(length: Int): String { + val allowedChars = ('a'..'z') + ('0'..'9') + return (1..length).map { allowedChars.random() }.joinToString("") + } + + fun getRandomIsoDateTime(): String { + val randomYear = Random.nextInt(2000, 2024) + val randomMonth = Random.nextInt(1, 13) + val randomDay = Random.nextInt(1, 29) + val randomHour = Random.nextInt(0, 24) + val randomMinute = Random.nextInt(0, 60) + val randomSecond = Random.nextInt(0, 60) + return String.format( + "%04d-%02d-%02dT%02d:%02d:%02d+00:00", + randomYear, randomMonth, randomDay, + randomHour, randomMinute, randomSecond + ) + } + + fun generateAmount(): AmountField { + val amount = Random.nextLong(0, 10.0.pow(Random.nextInt(1, 14).toDouble()).toLong()) + .toString() + '.' + + max( + 0, + 2 * Random.nextInt(0, 10.0.pow(Random.nextInt(0, 6).toDouble()).toInt()) - 100 + ).toString() + val currency = listOf("RUB", "USD", "EUR", "GBP").shuffled().first() + return AmountField(amount, currency) + } + + fun generateTransaction(): TransactionField { + val accountId = getRandomString(Random.nextInt(1, 41)) + val creditDebitIndicator = "Debit" + val status = listOf("Booked", "Pending").shuffled().first() + val amount = generateAmount() + val bookingDateTime = getRandomIsoDateTime() + if (Random.nextInt(0, 2) == 0) { + val bankTransactionCode = BankTransactionCodeField( + code = OPERATION_CODES.shuffled().first(), + subCode = SUBCODES.shuffled().first() + ) + return TransactionField( + accountId = accountId, creditDebitIndicator = creditDebitIndicator, + status = status, amount = amount, bookingDateTime = bookingDateTime, + bankTransactionCode = bankTransactionCode + ) + } + if (Random.nextInt(0, 2) == 0) { + val merchantName = getRandomString(Random.nextInt(1, 351)) + val merchantCategoryCode = String.format("%04d", Random.nextInt(0, 10000)) + return TransactionField( + accountId = accountId, creditDebitIndicator = creditDebitIndicator, + status = status, amount = amount, bookingDateTime = bookingDateTime, + merchantDetails = MerchantDetailsField( + merchantName = merchantName, + merchantCategoryCode = merchantCategoryCode + ) + ) + } + if (Random.nextInt(0, 4) == 0) { + val bankTransactionCode = BankTransactionCodeField( + code = OPERATION_CODES.shuffled().first(), + subCode = SUBCODES.shuffled().first() + ) + val merchantName = getRandomString(Random.nextInt(1, 351)) + val merchantCategoryCode = String.format("%04d", Random.nextInt(0, 10000)) + return TransactionField( + accountId = accountId, creditDebitIndicator = creditDebitIndicator, + status = status, amount = amount, bookingDateTime = bookingDateTime, + bankTransactionCode = bankTransactionCode, + merchantDetails = MerchantDetailsField( + merchantName = merchantName, + merchantCategoryCode = merchantCategoryCode + ) + ) + } + return TransactionField( + accountId = accountId, creditDebitIndicator = creditDebitIndicator, + status = status, amount = amount, bookingDateTime = bookingDateTime + ) + } + + fun generateTransactionApi(iterations: Int = 100): TransactionApi { + val transactions = mutableListOf<TransactionField>() + for (i in 1..Random.nextInt(1, 3)) { + // choose a random subscription period + val period = listOf("WEEKLY").shuffled().first() + // choose a random subscription amount + val amount = generateAmount() + val accountId = getRandomString(Random.nextInt(1, 41)) + var day = Random.nextInt(1, 29) + var month = Random.nextInt(1, 12) + var year = Random.nextInt(2000, 2023) + val merchantName = "Subscription $i" + val merchantCategoryCode = String.format("%04d", Random.nextInt(0, 10000)) + //create last transaction + transactions.add( + TransactionField( + accountId = accountId, + creditDebitIndicator = "Debit", + status = "Booked", + amount = amount, + bookingDateTime = String.format( + "%04d-%02d-%02dT00:00:00+00:00", + year, + month, + day + ), + bankTransactionCode = BankTransactionCodeField( + code = "IssuedCreditTransfer", + subCode = "AutomaticTransfer" + ), + merchantDetails = MerchantDetailsField( + merchantName = merchantName, + merchantCategoryCode = merchantCategoryCode + ) + ) + ) + //generate other transactions + for (j in 1..4) { + val creditDebitIndicator = "Debit" + if (period == "WEEKLY") { + day -= 7 + if (day < 1) { + day += 30 + month -= 1 + if (month < 1) { + month += 12 + year -= 1 + } + } + } else if (period == "MONTHLY") { + month -= 1 + if (month < 1) { + month += 12 + year -= 1 + } + } else if (period == "3 MONTH") { + month -= 3 + if (month < 1) { + month += 12 + year -= 1 + } + } else { + year -= 1 + } + transactions.add( + TransactionField( + accountId = accountId, + creditDebitIndicator = creditDebitIndicator, + status = "Booked", + amount = amount, + bookingDateTime = String.format( + "%04d-%02d-%02dT00:00:00+00:00", + year, + month, + day + ), + bankTransactionCode = BankTransactionCodeField( + code = "IssuedCreditTransfer", + subCode = "AutomaticTransfer" + ), + merchantDetails = MerchantDetailsField( + merchantName = merchantName, + merchantCategoryCode = merchantCategoryCode + ) + ) + ) + } + } + + transactions.sortBy { it.bookingDateTime } + val df = DataField(transactions) + val rf = RiskField() + val lf = LinksField("https://bank.ru/open-banking/v3.1/aisp/accounts/87659/transactions/") + val mf = MetaField( + "1", + transactions.minOf { it.bookingDateTime }, + transactions.maxOf { it.bookingDateTime }) + return TransactionApi(df, rf, lf, mf) + } + +} -- GitLab