Implemented persisting data with Room
This commit is contained in:
parent
29dbe70983
commit
12e84109f3
|
@ -58,6 +58,8 @@ ext {
|
||||||
|
|
||||||
multiDexVersion = "2.0.1"
|
multiDexVersion = "2.0.1"
|
||||||
|
|
||||||
|
androidXCoreVersion = "1.3.1"
|
||||||
|
|
||||||
appCompatVersion = "1.1.0"
|
appCompatVersion = "1.1.0"
|
||||||
|
|
||||||
constraintLayoutVersion = "1.1.3"
|
constraintLayoutVersion = "1.1.3"
|
||||||
|
@ -66,6 +68,8 @@ ext {
|
||||||
|
|
||||||
daggerVersion = "2.27"
|
daggerVersion = "2.27"
|
||||||
|
|
||||||
|
roomVersion = "2.2.5"
|
||||||
|
|
||||||
|
|
||||||
/* JavaFX */
|
/* JavaFX */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion androidCompileSdkVersion
|
||||||
|
buildToolsVersion androidBuildToolsVersion
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
|
||||||
|
minSdkVersion androidMinSdkVersion
|
||||||
|
targetSdkVersion androidTargetSdkVersion
|
||||||
|
|
||||||
|
versionName version
|
||||||
|
versionCode appVersionCode
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':BankingUiCommon')
|
||||||
|
|
||||||
|
implementation "androidx.room:room-runtime:$roomVersion"
|
||||||
|
kapt "androidx.room:room-compiler:$roomVersion"
|
||||||
|
implementation "androidx.room:room-ktx:$roomVersion"
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,5 @@
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="net.dankito.banking.persistence">
|
||||||
|
|
||||||
|
/
|
||||||
|
</manifest>
|
|
@ -0,0 +1,25 @@
|
||||||
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import androidx.room.TypeConverters
|
||||||
|
import net.dankito.banking.persistence.dao.*
|
||||||
|
import net.dankito.banking.persistence.model.*
|
||||||
|
|
||||||
|
|
||||||
|
@Database(entities = [ Bank::class, BankAccount::class, AccountTransaction::class, TanProcedure::class, TanMedium::class ],
|
||||||
|
version = 1, exportSchema = false)
|
||||||
|
@TypeConverters(net.dankito.banking.persistence.TypeConverters::class)
|
||||||
|
abstract class BankingDatabase : RoomDatabase() {
|
||||||
|
|
||||||
|
abstract fun bankDao(): BankDao
|
||||||
|
|
||||||
|
abstract fun bankAccountDao(): BankAccountDao
|
||||||
|
|
||||||
|
abstract fun accountTransactionDao(): AccountTransactionDao
|
||||||
|
|
||||||
|
abstract fun tanProcedureDao(): TanProcedureDao
|
||||||
|
|
||||||
|
abstract fun tanMediumDao(): TanMediumDao
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Room
|
||||||
|
import net.dankito.banking.persistence.dao.saveOrUpdate
|
||||||
|
import net.dankito.banking.persistence.model.*
|
||||||
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
|
import net.dankito.banking.ui.model.tan.MobilePhoneTanMedium
|
||||||
|
import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
||||||
|
import net.dankito.banking.util.persistence.doSaveUrlToFile
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
|
|
||||||
|
|
||||||
|
open class RoomBankingPersistence(applicationContext: Context) : IBankingPersistence {
|
||||||
|
|
||||||
|
protected val db = Room.databaseBuilder(
|
||||||
|
applicationContext,
|
||||||
|
BankingDatabase::class.java, "banking-database"
|
||||||
|
).build()
|
||||||
|
|
||||||
|
|
||||||
|
override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||||
|
(customer as? Bank)?.let { bank ->
|
||||||
|
bank.selectedTanProcedureId = bank.selectedTanProcedure?.technicalId
|
||||||
|
|
||||||
|
db.bankDao().saveOrUpdate(bank)
|
||||||
|
|
||||||
|
// TODO: in this way removed accounts won't be deleted from DB and therefore still be visible to user
|
||||||
|
val accounts = bank.accounts.filterIsInstance<BankAccount>()
|
||||||
|
accounts.forEach { it.bankId = bank.id }
|
||||||
|
db.bankAccountDao().saveOrUpdate(accounts)
|
||||||
|
|
||||||
|
// TODO: in this way removed TAN procedures won't be deleted from DB and therefore still be visible to user
|
||||||
|
val tanProcedures = bank.supportedTanProcedures.filterIsInstance<TanProcedure>()
|
||||||
|
tanProcedures.forEach { it.bankId = bank.id }
|
||||||
|
db.tanProcedureDao().saveOrUpdate(tanProcedures)
|
||||||
|
|
||||||
|
// TODO: in this way removed TAN procedures won't be deleted from DB and therefore still be visible to user
|
||||||
|
val tanMedia = bank.tanMedia.map { map(bank, it) }
|
||||||
|
db.tanMediumDao().saveOrUpdate(tanMedia)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||||
|
(customer as? Bank)?.let { bank ->
|
||||||
|
db.accountTransactionDao().delete(bank.accounts.flatMap { it.bookedTransactions }.filterIsInstance<AccountTransaction>())
|
||||||
|
|
||||||
|
db.bankAccountDao().delete(bank.accounts.filterIsInstance<BankAccount>())
|
||||||
|
|
||||||
|
db.tanProcedureDao().delete(bank.supportedTanProcedures.filterIsInstance<TanProcedure>())
|
||||||
|
db.tanMediumDao().delete(bank.tanMedia.filterIsInstance<TanMedium>())
|
||||||
|
|
||||||
|
db.bankDao().delete(bank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun readPersistedAccounts(): List<TypedCustomer> {
|
||||||
|
val banks = db.bankDao().getAll()
|
||||||
|
|
||||||
|
val accounts = db.bankAccountDao().getAll()
|
||||||
|
|
||||||
|
val transactions = db.accountTransactionDao().getAll()
|
||||||
|
|
||||||
|
val tanProcedures = db.tanProcedureDao().getAll()
|
||||||
|
|
||||||
|
val tanMedia = db.tanMediumDao().getAll()
|
||||||
|
|
||||||
|
banks.forEach { bank ->
|
||||||
|
bank.accounts = accounts.filter { it.bankId == bank.id }
|
||||||
|
|
||||||
|
bank.accounts.filterIsInstance<BankAccount>().forEach { account ->
|
||||||
|
account.customer = bank
|
||||||
|
|
||||||
|
account.bookedTransactions = transactions.filter { it.bankAccountId == account.id }
|
||||||
|
|
||||||
|
account.bookedTransactions.filterIsInstance<AccountTransaction>().forEach { transaction ->
|
||||||
|
transaction.bankAccount = account
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bank.supportedTanProcedures = tanProcedures.filter { it.bankId == bank.id }
|
||||||
|
bank.selectedTanProcedure = bank.supportedTanProcedures.firstOrNull { it.technicalId == bank.selectedTanProcedureId }
|
||||||
|
|
||||||
|
bank.tanMedia = tanMedia.filter { it.bankId == bank.id }.map { map(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return banks
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||||
|
val accountId = (bankAccount as? BankAccount)?.id ?: bankAccount.technicalId.toLong()
|
||||||
|
|
||||||
|
val mappedTransactions = transactions.filterIsInstance<AccountTransaction>()
|
||||||
|
|
||||||
|
mappedTransactions.forEach { it.bankAccountId = accountId }
|
||||||
|
|
||||||
|
db.accountTransactionDao().saveOrUpdate(mappedTransactions)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected open fun map(bank: Bank, tanMedium: net.dankito.banking.ui.model.tan.TanMedium): TanMedium {
|
||||||
|
val type = when (tanMedium) {
|
||||||
|
is TanGeneratorTanMedium -> TanMediumType.TanGeneratorTanMedium
|
||||||
|
is MobilePhoneTanMedium -> TanMediumType.MobilePhoneTanMedium
|
||||||
|
else -> TanMediumType.OtherTanMedium
|
||||||
|
}
|
||||||
|
|
||||||
|
return TanMedium(tanMedium.technicalId, bank.id, type, tanMedium.displayName, tanMedium.status,
|
||||||
|
(tanMedium as? TanGeneratorTanMedium)?.cardNumber, (tanMedium as? MobilePhoneTanMedium)?.phoneNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun map(tanMedium: TanMedium): net.dankito.banking.ui.model.tan.TanMedium {
|
||||||
|
val displayName = tanMedium.displayName
|
||||||
|
val status = tanMedium.status
|
||||||
|
|
||||||
|
val mapped = when (tanMedium.type) {
|
||||||
|
TanMediumType.TanGeneratorTanMedium -> TanGeneratorTanMedium(displayName, status, tanMedium.cardNumber ?: "")
|
||||||
|
TanMediumType.MobilePhoneTanMedium -> MobilePhoneTanMedium(displayName, status, tanMedium.phoneNumber)
|
||||||
|
else -> net.dankito.banking.ui.model.tan.TanMedium(displayName, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped.technicalId = tanMedium.id
|
||||||
|
|
||||||
|
return mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun saveUrlToFile(url: String, file: File) {
|
||||||
|
doSaveUrlToFile(url, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
|
import androidx.room.TypeConverter
|
||||||
|
import net.dankito.banking.persistence.model.TanMediumType
|
||||||
|
import net.dankito.banking.ui.model.BankAccountType
|
||||||
|
import net.dankito.banking.ui.model.tan.AllowedTanFormat
|
||||||
|
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
||||||
|
import net.dankito.banking.ui.model.tan.TanProcedureType
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
|
||||||
|
|
||||||
|
open class TypeConverters {
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromMultiplatformBigDecimal(value: BigDecimal?): String? {
|
||||||
|
return value?.toPlainString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toMultiplatformBigDecimal(value: String?): BigDecimal? {
|
||||||
|
return value?.let { BigDecimal(value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromMultiplatformDate(value: Date?): Long? {
|
||||||
|
return value?.millisSinceEpoch
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toMultiplatformDate(value: Long?): Date? {
|
||||||
|
return value?.let { Date(value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromBankAccountType(value: BankAccountType): Int {
|
||||||
|
return value.ordinal
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toBankAccountType(value: Int): BankAccountType {
|
||||||
|
return BankAccountType.values().first { it.ordinal == value }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromTanProcedureType(value: TanProcedureType): Int {
|
||||||
|
return value.ordinal
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toTanProcedureType(value: Int): TanProcedureType {
|
||||||
|
return TanProcedureType.values().first { it.ordinal == value }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromAllowedTanFormat(value: AllowedTanFormat): Int {
|
||||||
|
return value.ordinal
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toAllowedTanFormat(value: Int): AllowedTanFormat {
|
||||||
|
return AllowedTanFormat.values().first { it.ordinal == value }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromTanMediumStatus(value: TanMediumStatus): Int {
|
||||||
|
return value.ordinal
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toTanMediumStatus(value: Int): TanMediumStatus {
|
||||||
|
return TanMediumStatus.values().first { it.ordinal == value }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromTanMediumTypes(value: TanMediumType): Int {
|
||||||
|
return value.ordinal
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toTanMediumType(value: Int): TanMediumType {
|
||||||
|
return TanMediumType.values().first { it.ordinal == value }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package net.dankito.banking.persistence.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import net.dankito.banking.persistence.model.AccountTransaction
|
||||||
|
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface AccountTransactionDao : BaseDao<AccountTransaction> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM AccountTransaction")
|
||||||
|
fun getAll(): List<AccountTransaction>
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package net.dankito.banking.persistence.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import net.dankito.banking.persistence.model.BankAccount
|
||||||
|
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface BankAccountDao : BaseDao<BankAccount> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM BankAccount")
|
||||||
|
fun getAll(): List<BankAccount>
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package net.dankito.banking.persistence.dao
|
||||||
|
|
||||||
|
import androidx.room.*
|
||||||
|
import net.dankito.banking.persistence.model.Bank
|
||||||
|
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface BankDao : BaseDao<Bank> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Bank")
|
||||||
|
fun getAll(): List<Bank>
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package net.dankito.banking.persistence.dao
|
||||||
|
|
||||||
|
import androidx.room.*
|
||||||
|
|
||||||
|
|
||||||
|
interface BaseDao<T> {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ObjectNotInsertedId = -1L
|
||||||
|
|
||||||
|
const val IdNotSet = 0L
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
fun insert(obj: T): Long
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
fun insert(obj: List<T>): List<Long>
|
||||||
|
|
||||||
|
|
||||||
|
@Update(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
fun update(obj: T)
|
||||||
|
|
||||||
|
@Update(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
fun update(obj: List<T>)
|
||||||
|
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun delete(obj: T)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun delete(obj: List<T>)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package net.dankito.banking.persistence.dao
|
||||||
|
|
||||||
|
import androidx.room.Transaction
|
||||||
|
import net.dankito.banking.persistence.model.*
|
||||||
|
|
||||||
|
|
||||||
|
/* Room didn't allow me to add these methods to BaseDao directly (Kapt error), so i defined them as extension methods */
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
fun <T> BaseDao<T>.saveOrUpdate(obj: T) {
|
||||||
|
val id = insert(obj)
|
||||||
|
|
||||||
|
if (wasNotInserted(id)) {
|
||||||
|
update(obj)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setId(obj, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
fun <T> BaseDao<T>.saveOrUpdate(objList: List<T>) {
|
||||||
|
val ids = insert(objList)
|
||||||
|
|
||||||
|
// i was not allowed to use mapIndexedNotNull()
|
||||||
|
val notInsertedObjects = mutableListOf<T>()
|
||||||
|
ids.forEachIndexed { index, id ->
|
||||||
|
val obj = objList[index]
|
||||||
|
|
||||||
|
if (wasNotInserted(id)) {
|
||||||
|
notInsertedObjects.add(obj)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setId(obj, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(notInsertedObjects)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun wasNotInserted(id: Long): Boolean {
|
||||||
|
return id == BaseDao.ObjectNotInsertedId
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> setId(obj: T, id: Long) {
|
||||||
|
if (obj is Bank) {
|
||||||
|
obj.id = id // why doesn't Room set this on itself?
|
||||||
|
obj.technicalId = obj.id.toString()
|
||||||
|
}
|
||||||
|
else if (obj is BankAccount) {
|
||||||
|
obj.id = id // why doesn't Room set this on itself?
|
||||||
|
obj.technicalId = obj.id.toString()
|
||||||
|
}
|
||||||
|
else if (obj is AccountTransaction) {
|
||||||
|
obj.id = id // why doesn't Room set this on itself?
|
||||||
|
obj.technicalId = obj.id.toString()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package net.dankito.banking.persistence.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import net.dankito.banking.persistence.model.TanMedium
|
||||||
|
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface TanMediumDao : BaseDao<TanMedium> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM TanMedium")
|
||||||
|
fun getAll(): List<TanMedium>
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package net.dankito.banking.persistence.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import net.dankito.banking.persistence.model.TanProcedure
|
||||||
|
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface TanProcedureDao : BaseDao<TanProcedure> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM TanProcedure")
|
||||||
|
fun getAll(): List<TanProcedure>
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Ignore
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import net.dankito.banking.persistence.dao.BaseDao
|
||||||
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
|
import net.dankito.utils.multiplatform.*
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
open class AccountTransaction(
|
||||||
|
@Ignore
|
||||||
|
override var bankAccount: BankAccount,
|
||||||
|
|
||||||
|
override var amount: BigDecimal,
|
||||||
|
override var currency: String,
|
||||||
|
override var unparsedUsage: String,
|
||||||
|
override var bookingDate: Date,
|
||||||
|
override var otherPartyName: String?,
|
||||||
|
override var otherPartyBankCode: String?,
|
||||||
|
override var otherPartyAccountId: String?,
|
||||||
|
override var bookingText: String?,
|
||||||
|
override var valueDate: Date,
|
||||||
|
override var statementNumber: Int,
|
||||||
|
override var sequenceNumber: Int?,
|
||||||
|
override var openingBalance: BigDecimal?,
|
||||||
|
override var closingBalance: BigDecimal?,
|
||||||
|
|
||||||
|
override var endToEndReference: String?,
|
||||||
|
override var customerReference: String?,
|
||||||
|
override var mandateReference: String?,
|
||||||
|
override var creditorIdentifier: String?,
|
||||||
|
override var originatorsIdentificationCode: String?,
|
||||||
|
override var compensationAmount: String?,
|
||||||
|
override var originalAmount: String?,
|
||||||
|
override var sepaUsage: String?,
|
||||||
|
override var deviantOriginator: String?,
|
||||||
|
override var deviantRecipient: String?,
|
||||||
|
override var usageWithNoSpecialType: String?,
|
||||||
|
override var primaNotaNumber: String?,
|
||||||
|
override var textKeySupplement: String?,
|
||||||
|
|
||||||
|
override var currencyType: String?,
|
||||||
|
override var bookingKey: String,
|
||||||
|
override var referenceForTheAccountOwner: String,
|
||||||
|
override var referenceOfTheAccountServicingInstitution: String?,
|
||||||
|
override var supplementaryDetails: String?,
|
||||||
|
|
||||||
|
override var transactionReferenceNumber: String,
|
||||||
|
override var relatedReferenceNumber: String?
|
||||||
|
) : IAccountTransaction {
|
||||||
|
|
||||||
|
// for object deserializers
|
||||||
|
internal constructor() : this(BankAccount(), null, "", BigDecimal.Zero, Date(), null)
|
||||||
|
|
||||||
|
/* convenience constructors for languages not supporting default values */
|
||||||
|
|
||||||
|
constructor(bankAccount: BankAccount, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
|
||||||
|
: this(bankAccount, amount, "EUR", unparsedUsage, valueDate,
|
||||||
|
otherPartyName, null, null, bookingText, valueDate)
|
||||||
|
|
||||||
|
|
||||||
|
constructor(bankAccount: BankAccount, amount: BigDecimal, currency: String, unparsedUsage: String, bookingDate: Date,
|
||||||
|
otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?,
|
||||||
|
bookingText: String?, valueDate: Date)
|
||||||
|
: this(bankAccount, amount, currency, unparsedUsage, bookingDate,
|
||||||
|
otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate,
|
||||||
|
0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
|
||||||
|
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
open var id: Long = BaseDao.IdNotSet
|
||||||
|
|
||||||
|
override var technicalId: String = buildTransactionIdentifier()
|
||||||
|
|
||||||
|
// Room doesn't allow me to add getters and setters -> have to map it manually
|
||||||
|
open var bankAccountId: Long = BaseDao.ObjectNotInsertedId
|
||||||
|
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return doesEqual(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return calculateHashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return stringRepresentation
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Ignore
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import net.dankito.banking.persistence.dao.BaseDao
|
||||||
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
|
import net.dankito.banking.ui.model.tan.TanMedium
|
||||||
|
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
open class Bank(
|
||||||
|
override var bankCode: String,
|
||||||
|
override var customerId: String,
|
||||||
|
override var password: String,
|
||||||
|
override var finTsServerAddress: String,
|
||||||
|
override var bankName: String,
|
||||||
|
override var bic: String,
|
||||||
|
override var customerName: String,
|
||||||
|
|
||||||
|
override var userId: String = customerId,
|
||||||
|
override var iconUrl: String? = null,
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
override var accounts: List<TypedBankAccount> = listOf(),
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
override var supportedTanProcedures: List<TanProcedure> = listOf(),
|
||||||
|
@Ignore
|
||||||
|
override var selectedTanProcedure: TanProcedure? = null,
|
||||||
|
@Ignore
|
||||||
|
override var tanMedia: List<TanMedium> = listOf(),
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
open var id: Long = BaseDao.IdNotSet,
|
||||||
|
|
||||||
|
override var technicalId: String = id.toString(),
|
||||||
|
|
||||||
|
override var userSetDisplayName: String? = null,
|
||||||
|
override var displayIndex: Int = 0
|
||||||
|
) : TypedCustomer {
|
||||||
|
|
||||||
|
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
|
open var selectedTanProcedureId: String? = null
|
||||||
|
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return stringRepresentation
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Ignore
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import net.dankito.banking.persistence.dao.BaseDao
|
||||||
|
import net.dankito.banking.ui.model.*
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
import net.dankito.utils.multiplatform.UUID
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
open class BankAccount(
|
||||||
|
@Ignore
|
||||||
|
override var customer: TypedCustomer,
|
||||||
|
override var identifier: String,
|
||||||
|
override var accountHolderName: String,
|
||||||
|
override var iban: String?,
|
||||||
|
override var subAccountNumber: String?,
|
||||||
|
override var customerId: String,
|
||||||
|
override var balance: BigDecimal = BigDecimal.Zero,
|
||||||
|
override var currency: String = "EUR",
|
||||||
|
override var type: BankAccountType = BankAccountType.Girokonto,
|
||||||
|
override var productName: String? = null,
|
||||||
|
override var accountLimit: String? = null,
|
||||||
|
override var lastRetrievedTransactionsTimestamp: Date? = null,
|
||||||
|
|
||||||
|
override var supportsRetrievingAccountTransactions: Boolean = false,
|
||||||
|
override var supportsRetrievingBalance: Boolean = false,
|
||||||
|
override var supportsTransferringMoney: Boolean = false,
|
||||||
|
override var supportsInstantPaymentMoneyTransfer: Boolean = false,
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
override var bookedTransactions: List<IAccountTransaction> = listOf(),
|
||||||
|
@Ignore
|
||||||
|
override var unbookedTransactions: List<Any> = listOf()
|
||||||
|
) : TypedBankAccount {
|
||||||
|
|
||||||
|
internal constructor() : this(Bank(), null, "") // for object deserializers
|
||||||
|
|
||||||
|
/* convenience constructors for languages not supporting default values */
|
||||||
|
|
||||||
|
constructor(customer: TypedCustomer, productName: String?, identifier: String) : this(customer, productName, identifier, BankAccountType.Girokonto)
|
||||||
|
|
||||||
|
constructor(customer: TypedCustomer, productName: String?, identifier: String, type: BankAccountType = BankAccountType.Girokonto, balance: BigDecimal = BigDecimal.Zero)
|
||||||
|
: this(customer, identifier, "", null, null, "", balance, "EUR", type, productName)
|
||||||
|
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
open var id: Long = BaseDao.IdNotSet
|
||||||
|
|
||||||
|
override var technicalId: String = UUID.random()
|
||||||
|
|
||||||
|
// Room doesn't allow me to add getters and setters -> have to map it manually
|
||||||
|
open var bankId: Long = BaseDao.ObjectNotInsertedId
|
||||||
|
|
||||||
|
|
||||||
|
override var haveAllTransactionsBeenFetched: Boolean = false
|
||||||
|
|
||||||
|
|
||||||
|
override var userSetDisplayName: String? = null
|
||||||
|
|
||||||
|
override var displayIndex: Int = 0
|
||||||
|
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return stringRepresentation
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.IAccountTransaction
|
||||||
|
import net.dankito.banking.ui.model.TypedBankAccount
|
||||||
|
import net.dankito.banking.ui.model.TypedCustomer
|
||||||
|
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||||
|
import net.dankito.banking.ui.model.tan.AllowedTanFormat
|
||||||
|
import net.dankito.banking.ui.model.tan.TanProcedureType
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
|
||||||
|
|
||||||
|
open class RoomModelCreator : IModelCreator {
|
||||||
|
|
||||||
|
override fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String,
|
||||||
|
bic: String, customerName: String, userId: String, iconUrl: String?): TypedCustomer {
|
||||||
|
|
||||||
|
return Bank(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String): TypedBankAccount {
|
||||||
|
return BankAccount(customer, productName, identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createTransaction(
|
||||||
|
bankAccount: TypedBankAccount,
|
||||||
|
amount: BigDecimal,
|
||||||
|
currency: String,
|
||||||
|
unparsedUsage: String,
|
||||||
|
bookingDate: Date,
|
||||||
|
otherPartyName: String?,
|
||||||
|
otherPartyBankCode: String?,
|
||||||
|
otherPartyAccountId: String?,
|
||||||
|
bookingText: String?,
|
||||||
|
valueDate: Date,
|
||||||
|
statementNumber: Int,
|
||||||
|
sequenceNumber: Int?,
|
||||||
|
openingBalance: BigDecimal?,
|
||||||
|
closingBalance: BigDecimal?,
|
||||||
|
endToEndReference: String?,
|
||||||
|
customerReference: String?,
|
||||||
|
mandateReference: String?,
|
||||||
|
creditorIdentifier: String?,
|
||||||
|
originatorsIdentificationCode: String?,
|
||||||
|
compensationAmount: String?,
|
||||||
|
originalAmount: String?,
|
||||||
|
sepaUsage: String?,
|
||||||
|
deviantOriginator: String?,
|
||||||
|
deviantRecipient: String?,
|
||||||
|
usageWithNoSpecialType: String?,
|
||||||
|
primaNotaNumber: String?,
|
||||||
|
textKeySupplement: String?,
|
||||||
|
currencyType: String?,
|
||||||
|
bookingKey: String,
|
||||||
|
referenceForTheAccountOwner: String,
|
||||||
|
referenceOfTheAccountServicingInstitution: String?,
|
||||||
|
supplementaryDetails: String?,
|
||||||
|
transactionReferenceNumber: String,
|
||||||
|
relatedReferenceNumber: String?
|
||||||
|
): IAccountTransaction {
|
||||||
|
return AccountTransaction(bankAccount as BankAccount, amount, currency, unparsedUsage, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId,
|
||||||
|
bookingText, valueDate, statementNumber, sequenceNumber, openingBalance, closingBalance, endToEndReference, customerReference, mandateReference,
|
||||||
|
creditorIdentifier, originatorsIdentificationCode, compensationAmount, originalAmount, sepaUsage, deviantOriginator, deviantRecipient,
|
||||||
|
usageWithNoSpecialType, primaNotaNumber, textKeySupplement, currencyType, bookingKey, referenceForTheAccountOwner,
|
||||||
|
referenceOfTheAccountServicingInstitution, supplementaryDetails, transactionReferenceNumber, relatedReferenceNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun createTanProcedure(displayName: String, type: TanProcedureType, bankInternalProcedureCode: String, maxTanInputLength: Int?, allowedTanFormat: AllowedTanFormat): net.dankito.banking.ui.model.tan.TanProcedure {
|
||||||
|
return TanProcedure(displayName, type, bankInternalProcedureCode, maxTanInputLength, allowedTanFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import net.dankito.banking.persistence.dao.BaseDao
|
||||||
|
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
open class TanMedium(
|
||||||
|
@PrimaryKey
|
||||||
|
open var id: String,
|
||||||
|
open var bankId: Long,
|
||||||
|
|
||||||
|
open var type: TanMediumType,
|
||||||
|
open var displayName: String,
|
||||||
|
open var status: TanMediumStatus,
|
||||||
|
open var cardNumber: String? = null,
|
||||||
|
open var phoneNumber: String? = null
|
||||||
|
) {
|
||||||
|
|
||||||
|
internal constructor() : this("", BaseDao.ObjectNotInsertedId, TanMediumType.OtherTanMedium, "", TanMediumStatus.Available) // for object deserializers
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
|
|
||||||
|
enum class TanMediumType {
|
||||||
|
|
||||||
|
TanGeneratorTanMedium,
|
||||||
|
|
||||||
|
MobilePhoneTanMedium,
|
||||||
|
|
||||||
|
OtherTanMedium
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package net.dankito.banking.persistence.model
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import net.dankito.banking.persistence.dao.BaseDao
|
||||||
|
import net.dankito.banking.ui.model.tan.AllowedTanFormat
|
||||||
|
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||||
|
import net.dankito.banking.ui.model.tan.TanProcedureType
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
open class TanProcedure(
|
||||||
|
displayName: String,
|
||||||
|
type: TanProcedureType,
|
||||||
|
bankInternalProcedureCode: String,
|
||||||
|
maxTanInputLength: Int? = null,
|
||||||
|
allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
|
||||||
|
) : TanProcedure(displayName, type, bankInternalProcedureCode, maxTanInputLength, allowedTanFormat) {
|
||||||
|
|
||||||
|
internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
|
@PrimaryKey
|
||||||
|
open var id: String = technicalId
|
||||||
|
|
||||||
|
// Room doesn't allow me to add getters and setters -> have to map it manually
|
||||||
|
open var bankId: Long = BaseDao.ObjectNotInsertedId
|
||||||
|
|
||||||
|
}
|
|
@ -4,8 +4,7 @@ import net.dankito.banking.persistence.model.CustomerEntity
|
||||||
import net.dankito.banking.ui.model.*
|
import net.dankito.banking.ui.model.*
|
||||||
import net.dankito.utils.multiplatform.File
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.util.ISerializer
|
import net.dankito.banking.util.ISerializer
|
||||||
import java.io.FileOutputStream
|
import net.dankito.banking.util.persistence.doSaveUrlToFile
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
|
|
||||||
open class BankingPersistenceJson(
|
open class BankingPersistenceJson(
|
||||||
|
@ -43,11 +42,7 @@ open class BankingPersistenceJson(
|
||||||
|
|
||||||
|
|
||||||
override fun saveUrlToFile(url: String, file: File) {
|
override fun saveUrlToFile(url: String, file: File) {
|
||||||
URL(url).openConnection().getInputStream().buffered().use { iconInputStream ->
|
doSaveUrlToFile(url, file)
|
||||||
FileOutputStream(file).use { fileOutputStream ->
|
|
||||||
iconInputStream.copyTo(fileOutputStream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -70,4 +70,8 @@ open class AccountTransactionEntity(
|
||||||
return calculateHashCode()
|
return calculateHashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return stringRepresentation
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -38,4 +38,9 @@ open class BankAccountEntity(
|
||||||
|
|
||||||
internal constructor() : this(CustomerEntity(), "", "", null, null, "") // for object deserializers
|
internal constructor() : this(CustomerEntity(), "", "", null, null, "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return stringRepresentation
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -30,4 +30,9 @@ open class CustomerEntity(
|
||||||
|
|
||||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return stringRepresentation
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,6 +18,7 @@ include ':hbci4jBankingClient'
|
||||||
|
|
||||||
include ':BankingPersistenceJson'
|
include ':BankingPersistenceJson'
|
||||||
include ':LuceneBankingPersistence'
|
include ':LuceneBankingPersistence'
|
||||||
|
include ':RoomBankingPersistence'
|
||||||
|
|
||||||
include ':BankingAndroidApp'
|
include ':BankingAndroidApp'
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ project(':BankingUiNativeIntegration').projectDir = "$rootDir/ui/BankingUiNative
|
||||||
|
|
||||||
project(':BankingPersistenceJson').projectDir = "$rootDir/persistence/json/BankingPersistenceJson/" as File
|
project(':BankingPersistenceJson').projectDir = "$rootDir/persistence/json/BankingPersistenceJson/" as File
|
||||||
project(':LuceneBankingPersistence').projectDir = "$rootDir/persistence/LuceneBankingPersistence/" as File
|
project(':LuceneBankingPersistence').projectDir = "$rootDir/persistence/LuceneBankingPersistence/" as File
|
||||||
|
project(':RoomBankingPersistence').projectDir = "$rootDir/persistence/database/RoomBankingPersistence/" as File
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,7 @@ dependencies {
|
||||||
|
|
||||||
implementation project(':BankingPersistenceJson')
|
implementation project(':BankingPersistenceJson')
|
||||||
implementation project(':LuceneBankingPersistence')
|
implementation project(':LuceneBankingPersistence')
|
||||||
|
implementation project(':RoomBankingPersistence')
|
||||||
|
|
||||||
|
|
||||||
implementation "net.dankito.text.extraction:itext2-text-extractor:$textExtractorVersion"
|
implementation "net.dankito.text.extraction:itext2-text-extractor:$textExtractorVersion"
|
||||||
|
|
|
@ -9,7 +9,6 @@ import net.dankito.banking.ui.android.RouterAndroid
|
||||||
import net.dankito.banking.ui.android.util.CurrentActivityTracker
|
import net.dankito.banking.ui.android.util.CurrentActivityTracker
|
||||||
import net.dankito.banking.fints4kBankingClientCreator
|
import net.dankito.banking.fints4kBankingClientCreator
|
||||||
import net.dankito.banking.persistence.IBankingPersistence
|
import net.dankito.banking.persistence.IBankingPersistence
|
||||||
import net.dankito.banking.persistence.LuceneBankingPersistence
|
|
||||||
import net.dankito.banking.search.IRemitteeSearcher
|
import net.dankito.banking.search.IRemitteeSearcher
|
||||||
import net.dankito.banking.search.LuceneRemitteeSearcher
|
import net.dankito.banking.search.LuceneRemitteeSearcher
|
||||||
import net.dankito.banking.ui.IBankingClientCreator
|
import net.dankito.banking.ui.IBankingClientCreator
|
||||||
|
@ -17,7 +16,8 @@ import net.dankito.banking.ui.IRouter
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.banking.bankfinder.IBankFinder
|
import net.dankito.banking.bankfinder.IBankFinder
|
||||||
import net.dankito.banking.bankfinder.LuceneBankFinder
|
import net.dankito.banking.bankfinder.LuceneBankFinder
|
||||||
import net.dankito.banking.persistence.mapper.EntitiesModelCreator
|
import net.dankito.banking.persistence.RoomBankingPersistence
|
||||||
|
import net.dankito.banking.persistence.model.RoomModelCreator
|
||||||
import net.dankito.banking.ui.model.mapper.IModelCreator
|
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||||
import net.dankito.utils.multiplatform.toFile
|
import net.dankito.utils.multiplatform.toFile
|
||||||
import net.dankito.banking.util.*
|
import net.dankito.banking.util.*
|
||||||
|
@ -115,8 +115,8 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideBankingPersistence(@Named(IndexFolderKey) indexFolder: File, @Named(DatabaseFolderKey) databaseFolder: File, serializer: ISerializer) : IBankingPersistence {
|
fun provideBankingPersistence() : IBankingPersistence {
|
||||||
return LuceneBankingPersistence(indexFolder, databaseFolder, serializer)
|
return RoomBankingPersistence(applicationContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -169,7 +169,7 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideModelCreator() : IModelCreator {
|
fun provideModelCreator() : IModelCreator {
|
||||||
return EntitiesModelCreator()
|
return RoomModelCreator()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
@ -77,7 +77,7 @@ open class AccountTransaction(
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "${DateFormatter(DateFormatStyle.Medium).format(valueDate)} $amount $otherPartyName: $usage"
|
return stringRepresentation
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -49,7 +49,7 @@ open class BankAccount @JvmOverloads constructor(
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$accountHolderName ($identifier)"
|
return stringRepresentation
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -43,7 +43,7 @@ open class Customer(
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$bankName $customerId"
|
return stringRepresentation
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ package net.dankito.banking.ui.model
|
||||||
|
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.utils.multiplatform.Date
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
import net.dankito.utils.multiplatform.DateFormatStyle
|
||||||
import net.dankito.utils.multiplatform.DateFormatter
|
import net.dankito.utils.multiplatform.DateFormatter
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,4 +108,7 @@ interface IAccountTransaction {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val stringRepresentation: String
|
||||||
|
get() = "${DateFormatter(DateFormatStyle.Medium).format(valueDate)} $amount $otherPartyName: $usage"
|
||||||
|
|
||||||
}
|
}
|
|
@ -53,4 +53,8 @@ interface IBankAccount<TTransaction: IAccountTransaction> : OrderedDisplayable {
|
||||||
this.unbookedTransactions = uniqueUnbookedTransactions.toList()
|
this.unbookedTransactions = uniqueUnbookedTransactions.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val stringRepresentation: String
|
||||||
|
get() = "$accountHolderName ($identifier)"
|
||||||
|
|
||||||
}
|
}
|
|
@ -53,4 +53,8 @@ interface ICustomer<TAccount: IBankAccount<TAccountTransaction>, TAccountTransac
|
||||||
val tanMediaSorted: List<TanMedium>
|
val tanMediaSorted: List<TanMedium>
|
||||||
get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }
|
get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }
|
||||||
|
|
||||||
|
|
||||||
|
val stringRepresentation: String
|
||||||
|
get() = "$bankName $customerId"
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package net.dankito.banking.ui.model.mapper
|
package net.dankito.banking.ui.model.mapper
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.*
|
import net.dankito.banking.ui.model.*
|
||||||
|
import net.dankito.banking.ui.model.tan.*
|
||||||
import net.dankito.utils.multiplatform.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.utils.multiplatform.Date
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
|
||||||
|
@ -54,4 +55,22 @@ interface IModelCreator {
|
||||||
relatedReferenceNumber: String?
|
relatedReferenceNumber: String?
|
||||||
) : IAccountTransaction
|
) : IAccountTransaction
|
||||||
|
|
||||||
|
|
||||||
|
fun createTanProcedure(displayName: String, type: TanProcedureType, bankInternalProcedureCode: String,
|
||||||
|
maxTanInputLength: Int? = null, allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric): TanProcedure {
|
||||||
|
return TanProcedure(displayName, type, bankInternalProcedureCode, maxTanInputLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createTanMedium(displayName: String, status: TanMediumStatus): TanMedium {
|
||||||
|
return TanMedium(displayName, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createTanGeneratorTanMedium(displayName: String, status: TanMediumStatus, cardNumber: String): TanGeneratorTanMedium {
|
||||||
|
return TanGeneratorTanMedium(displayName, status, cardNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createMobilePhoneTanMedium(displayName: String, status: TanMediumStatus, phoneNumber: String?): MobilePhoneTanMedium {
|
||||||
|
return MobilePhoneTanMedium(displayName, status, phoneNumber)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ import net.dankito.utils.multiplatform.UUID
|
||||||
|
|
||||||
open class TanMedium(
|
open class TanMedium(
|
||||||
override val displayName: String,
|
override val displayName: String,
|
||||||
val status: TanMediumStatus
|
open val status: TanMediumStatus
|
||||||
) : Displayable {
|
) : Displayable {
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,23 @@ package net.dankito.banking.ui.model.tan
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.Displayable
|
import net.dankito.banking.ui.model.Displayable
|
||||||
import net.dankito.utils.multiplatform.UUID
|
import net.dankito.utils.multiplatform.UUID
|
||||||
|
import kotlin.jvm.Transient
|
||||||
|
|
||||||
|
|
||||||
open class TanProcedure(
|
open class TanProcedure(
|
||||||
override val displayName: String,
|
override val displayName: String,
|
||||||
val type: TanProcedureType,
|
open val type: TanProcedureType,
|
||||||
val bankInternalProcedureCode: String,
|
open val bankInternalProcedureCode: String,
|
||||||
val maxTanInputLength: Int? = null,
|
open val maxTanInputLength: Int? = null,
|
||||||
val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
|
open val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
|
||||||
) : Displayable {
|
) : Displayable {
|
||||||
|
|
||||||
|
|
||||||
internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers
|
internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
val isNumericTan: Boolean = allowedTanFormat == AllowedTanFormat.Numeric
|
@Transient
|
||||||
|
open val isNumericTan: Boolean = allowedTanFormat == AllowedTanFormat.Numeric
|
||||||
|
|
||||||
|
|
||||||
open var technicalId: String = UUID.random()
|
open var technicalId: String = UUID.random()
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package net.dankito.banking.util.persistence
|
||||||
|
|
||||||
|
import net.dankito.banking.persistence.IBankingPersistence
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
|
||||||
|
fun IBankingPersistence.doSaveUrlToFile(url: String, file: File) {
|
||||||
|
URL(url).openConnection().getInputStream().buffered().use { iconInputStream ->
|
||||||
|
FileOutputStream(file).use { fileOutputStream ->
|
||||||
|
iconInputStream.copyTo(fileOutputStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -253,7 +253,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
account.selectedTanProcedure = null
|
account.selectedTanProcedure = null
|
||||||
}
|
}
|
||||||
|
|
||||||
account.tanMedia = mapTanMediums(bank.tanMedia)
|
account.tanMedia = mapTanMedia(bank.tanMedia)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapTanProcedure(tanProcedure: net.dankito.banking.fints.model.TanProcedure): TanProcedure {
|
open fun mapTanProcedure(tanProcedure: net.dankito.banking.fints.model.TanProcedure): TanProcedure {
|
||||||
return TanProcedure(
|
return modelCreator.createTanProcedure(
|
||||||
tanProcedure.displayName,
|
tanProcedure.displayName,
|
||||||
mapTanProcedureType(tanProcedure.type),
|
mapTanProcedureType(tanProcedure.type),
|
||||||
tanProcedure.securityFunction.code,
|
tanProcedure.securityFunction.code,
|
||||||
|
@ -306,40 +306,34 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun mapTanMediums(tanMediums: List<net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium>): List<TanMedium> {
|
open fun mapTanMedia(tanMediums: List<net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium>): List<TanMedium> {
|
||||||
return tanMediums.map { mapTanMedium(it) }
|
return tanMediums.map { mapTanMedium(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium {
|
open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium {
|
||||||
|
val displayName = getDisplayNameForTanMedium(tanMedium)
|
||||||
|
val status = mapTanMediumStatus(tanMedium)
|
||||||
|
|
||||||
// TODO: irgendwas ging hier schief
|
// TODO: irgendwas ging hier schief
|
||||||
if (tanMedium is net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium) {
|
if (tanMedium is net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium) {
|
||||||
return mapTanMedium(tanMedium)
|
return mapTanMedium(tanMedium, displayName, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tanMedium is net.dankito.banking.fints.messages.datenelemente.implementierte.tan.MobilePhoneTanMedium) {
|
if (tanMedium is net.dankito.banking.fints.messages.datenelemente.implementierte.tan.MobilePhoneTanMedium) {
|
||||||
return mapTanMedium(tanMedium)
|
return modelCreator.createMobilePhoneTanMedium(displayName, status, tanMedium.phoneNumber ?: tanMedium.concealedPhoneNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
return TanMedium(
|
return modelCreator.createTanMedium(displayName, status)
|
||||||
getDisplayNameForTanMedium(tanMedium),
|
|
||||||
mapTanMediumStatus(tanMedium)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium): TanGeneratorTanMedium {
|
open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium): TanGeneratorTanMedium {
|
||||||
return TanGeneratorTanMedium(
|
return mapTanMedium(tanMedium, getDisplayNameForTanMedium(tanMedium), mapTanMediumStatus(tanMedium))
|
||||||
getDisplayNameForTanMedium(tanMedium),
|
|
||||||
mapTanMediumStatus(tanMedium),
|
|
||||||
tanMedium.cardNumber
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.MobilePhoneTanMedium): MobilePhoneTanMedium {
|
protected open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium,
|
||||||
return MobilePhoneTanMedium(
|
displayName: String, status: TanMediumStatus): TanGeneratorTanMedium {
|
||||||
getDisplayNameForTanMedium(tanMedium),
|
|
||||||
mapTanMediumStatus(tanMedium),
|
return modelCreator.createTanGeneratorTanMedium(displayName, status, tanMedium.cardNumber)
|
||||||
tanMedium.phoneNumber ?: tanMedium.concealedPhoneNumber
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getDisplayNameForTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): String {
|
protected open fun getDisplayNameForTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): String {
|
||||||
|
|
|
@ -106,15 +106,15 @@ open class hbci4jModelMapper(
|
||||||
// TODO: implement all TAN procedures
|
// TODO: implement all TAN procedures
|
||||||
displayNameLowerCase.contains("chiptan") -> {
|
displayNameLowerCase.contains("chiptan") -> {
|
||||||
if (displayNameLowerCase.contains("qr")) {
|
if (displayNameLowerCase.contains("qr")) {
|
||||||
net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.ChipTanQrCode, code)
|
modelCreator.createTanProcedure(displayName, TanProcedureType.ChipTanQrCode, code)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.ChipTanFlickercode, code)
|
modelCreator.createTanProcedure(displayName, TanProcedureType.ChipTanFlickercode, code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
displayNameLowerCase.contains("sms") -> net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.SmsTan, code)
|
displayNameLowerCase.contains("sms") -> modelCreator.createTanProcedure(displayName, TanProcedureType.SmsTan, code)
|
||||||
displayNameLowerCase.contains("push") -> net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.AppTan, code)
|
displayNameLowerCase.contains("push") -> modelCreator.createTanProcedure(displayName, TanProcedureType.AppTan, code)
|
||||||
|
|
||||||
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
|
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
|
||||||
else -> null
|
else -> null
|
||||||
|
|
Loading…
Reference in New Issue