Implemented evaluating count days for which bank stores transactions -> don't show fetch all transactions overlay if bank server doesn't store additional transactions
This commit is contained in:
parent
1f9fd48e80
commit
094d669148
|
@ -8,6 +8,15 @@ val Char.isUpperCase: Boolean
|
|||
get() = isLowerCase == false
|
||||
|
||||
|
||||
fun Date.isBefore(other: Date): Boolean {
|
||||
return compareTo(other) < 0
|
||||
}
|
||||
|
||||
fun Date.isBeforeOrEquals(other: Date): Boolean {
|
||||
return compareTo(other) <= 0
|
||||
}
|
||||
|
||||
|
||||
fun Throwable.getInnerExceptionMessage(maxDepth: Int = 3): String {
|
||||
return this.getInnerException(maxDepth).message ?: ""
|
||||
}
|
||||
|
|
|
@ -12,6 +12,13 @@ fun Date.format(pattern: String): String {
|
|||
|
||||
expect class Date(millisSinceEpoch: Long) {
|
||||
|
||||
companion object {
|
||||
|
||||
val today: Date
|
||||
|
||||
}
|
||||
|
||||
|
||||
constructor()
|
||||
|
||||
constructor(year: Int, month: Int, day: Int)
|
||||
|
@ -29,4 +36,7 @@ expect class Date(millisSinceEpoch: Long) {
|
|||
|
||||
fun day(): Int
|
||||
|
||||
|
||||
fun compareTo(other: Date): Int
|
||||
|
||||
}
|
|
@ -44,12 +44,7 @@ actual class BigDecimal(val decimal: NSDecimalNumber) : Comparable<BigDecimal> {
|
|||
|
||||
|
||||
override fun compareTo(other: BigDecimal): Int {
|
||||
return when (decimal.compare(other.decimal)) {
|
||||
NSOrderedSame -> 0
|
||||
NSOrderedAscending -> -1
|
||||
NSOrderedDescending -> 1
|
||||
else -> 0
|
||||
}
|
||||
return decimal.compare(other.decimal).toCompareToResult()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
|
|
@ -18,7 +18,7 @@ fun NSDate.toDate(): Date {
|
|||
|
||||
actual class Date(val date: NSDate) { // cannot subclass NSDate as it's a class cluster
|
||||
|
||||
companion object {
|
||||
actual companion object {
|
||||
|
||||
val DiffBetweenEpochTimeAndReferenceDate = (NSDate.timeIntervalSinceReferenceDate - NSTimeIntervalSince1970).toMillis()
|
||||
|
||||
|
@ -32,6 +32,14 @@ actual class Date(val date: NSDate) { // cannot subclass NSDate as it's a class
|
|||
return NSCalendar.currentCalendar.dateFromComponents(dateComponents) !!
|
||||
}
|
||||
|
||||
|
||||
actual val today: Date
|
||||
get() {
|
||||
val now = Date()
|
||||
|
||||
return Date(from(now.year(), now.monthInt(), now.day()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,6 +76,12 @@ actual class Date(val date: NSDate) { // cannot subclass NSDate as it's a class
|
|||
}
|
||||
|
||||
|
||||
|
||||
actual fun compareTo(other: Date): Int {
|
||||
return date.compare(other.date).toCompareToResult()
|
||||
}
|
||||
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Date) return false
|
||||
|
|
|
@ -28,6 +28,16 @@ fun NSDictionary.getStringOrEmpty(key: String): String {
|
|||
}
|
||||
|
||||
|
||||
fun NSComparisonResult.toCompareToResult(): Int {
|
||||
return when (this) {
|
||||
NSOrderedSame -> 0
|
||||
NSOrderedAscending -> -1
|
||||
NSOrderedDescending -> 1
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun String.toNSData(): NSData {
|
||||
return this.encodeToByteArray().toNSData()
|
||||
}
|
||||
|
|
|
@ -3,11 +3,30 @@ package net.dankito.utils.multiplatform
|
|||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import net.dankito.utils.multiplatform.serialization.DateDeserializer
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
|
||||
@JsonDeserialize(using = DateDeserializer::class)
|
||||
actual class Date actual constructor(millisSinceEpoch: Long) : java.util.Date(millisSinceEpoch) {
|
||||
|
||||
actual companion object {
|
||||
|
||||
actual val today: net.dankito.utils.multiplatform.Date
|
||||
get() {
|
||||
val today = Calendar.getInstance()
|
||||
|
||||
today.set(Calendar.HOUR_OF_DAY, 0)
|
||||
today.set(Calendar.MINUTE, 0)
|
||||
today.set(Calendar.SECOND, 0)
|
||||
today.set(Calendar.MILLISECOND, 0)
|
||||
|
||||
return net.dankito.utils.multiplatform.Date(today.time.time)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
actual constructor() : this(System.currentTimeMillis())
|
||||
|
||||
actual constructor(year: Int, month: Int, day: Int) : this(java.util.Date(year - 1900, month - 1, day).time)
|
||||
|
@ -41,4 +60,9 @@ actual class Date actual constructor(millisSinceEpoch: Long) : java.util.Date(mi
|
|||
return dateStringString.toInt()
|
||||
}
|
||||
|
||||
|
||||
actual fun compareTo(other: net.dankito.utils.multiplatform.Date): Int {
|
||||
return super.compareTo(other)
|
||||
}
|
||||
|
||||
}
|
|
@ -997,6 +997,16 @@ open class FinTsClient(
|
|||
}
|
||||
}
|
||||
|
||||
response.receivedSegments.filterIsInstance<RetrieveAccountTransactionsInMt940Parameters>().firstOrNull()?.let { retrieveTransactionsParameters ->
|
||||
bank.countDaysForWhichTransactionsAreKept = retrieveTransactionsParameters.countDaysForWhichTransactionsAreKept
|
||||
}
|
||||
|
||||
response.getFirstSegmentById<SepaAccountInfo>(InstituteSegmentId.SepaAccountInfo)?.let { sepaAccountInfo ->
|
||||
sepaAccountInfo.account.bic?.let {
|
||||
bank.bic = it // TODO: really set BIC on bank then?
|
||||
}
|
||||
}
|
||||
|
||||
response.getFirstSegmentById<ChangeTanMediaParameters>(InstituteSegmentId.ChangeTanMediaParameters)?.let { parameters ->
|
||||
bank.changeTanMediumParameters = parameters
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ open class BankData(
|
|||
*/
|
||||
open var countMaxJobsPerMessage: Int = 0,
|
||||
|
||||
open var countDaysForWhichTransactionsAreKept: Int? = null,
|
||||
|
||||
open var supportedHbciVersions: List<HbciVersion> = listOf(),
|
||||
open var supportedJobs: List<JobParameters> = listOf()
|
||||
) {
|
||||
|
|
|
@ -33,6 +33,10 @@ open class Bank(
|
|||
@Ignore
|
||||
override var tanMedia: List<TanMedium> = listOf(),
|
||||
|
||||
|
||||
override var countDaysForWhichTransactionsAreKept: Int? = null,
|
||||
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
open var id: Long = BaseDao.IdNotSet,
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ open class CustomerEntity(
|
|||
override var supportedTanProcedures: List<TanProcedure> = listOf(),
|
||||
override var selectedTanProcedure: TanProcedure? = null,
|
||||
override var tanMedia: List<TanMedium> = listOf(),
|
||||
override var countDaysForWhichTransactionsAreKept: Int? = null,
|
||||
override var technicalId: String = UUID.randomUUID().toString(),
|
||||
override var userSetDisplayName: String? = null,
|
||||
override var displayIndex: Int = 0
|
||||
|
|
|
@ -37,6 +37,9 @@ open class Customer(
|
|||
override var tanMedia: List<TanMedium> = listOf()
|
||||
|
||||
|
||||
override var countDaysForWhichTransactionsAreKept: Int? = null
|
||||
|
||||
|
||||
override var userSetDisplayName: String? = null
|
||||
|
||||
override var displayIndex: Int = 0
|
||||
|
|
|
@ -54,6 +54,9 @@ interface ICustomer<TAccount: IBankAccount<TAccountTransaction>, TAccountTransac
|
|||
get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }
|
||||
|
||||
|
||||
var countDaysForWhichTransactionsAreKept: Int?
|
||||
|
||||
|
||||
val stringRepresentation: String
|
||||
get() = "$bankName $customerId"
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ open class BankingPresenter(
|
|||
val ChipTanTanProcedures = listOf(TanProcedureType.ChipTanManuell, TanProcedureType.ChipTanFlickercode, TanProcedureType.ChipTanUsb,
|
||||
TanProcedureType.ChipTanQrCode, TanProcedureType.ChipTanPhotoTanMatrixCode)
|
||||
|
||||
protected const val OneDayMillis = 24 * 60 * 60 * 1000
|
||||
protected const val OneDayMillis = 24 * 60 * 60 * 1000L
|
||||
|
||||
protected val MessageLogEntryDateFormatter = DateFormatter("yyyy.MM.dd HH:mm:ss.SSS")
|
||||
|
||||
|
@ -335,10 +335,11 @@ open class BankingPresenter(
|
|||
protected open fun retrievedAccountTransactions(response: GetTransactionsResponse, startDate: Date, didFetchAllTransactions: Boolean) {
|
||||
if (response.successful) {
|
||||
response.retrievedData.forEach { retrievedData ->
|
||||
retrievedData.account.lastRetrievedTransactionsTimestamp = startDate
|
||||
val account = retrievedData.account
|
||||
account.lastRetrievedTransactionsTimestamp = startDate
|
||||
|
||||
if (didFetchAllTransactions) {
|
||||
retrievedData.account.haveAllTransactionsBeenFetched = true
|
||||
if (didFetchAllTransactions || didFetchAllTransactionsStoredOnBankServer(account, retrievedData.bookedTransactions)) {
|
||||
account.haveAllTransactionsBeenFetched = true
|
||||
}
|
||||
|
||||
updateAccountTransactionsAndBalances(retrievedData)
|
||||
|
@ -348,6 +349,20 @@ open class BankingPresenter(
|
|||
callRetrievedAccountTransactionsResponseListener(response)
|
||||
}
|
||||
|
||||
protected open fun didFetchAllTransactionsStoredOnBankServer(account: IBankAccount<IAccountTransaction>, fetchedTransactions: Collection<IAccountTransaction>): Boolean {
|
||||
account.customer.countDaysForWhichTransactionsAreKept?.let { countDaysForWhichTransactionsAreKept ->
|
||||
val firstAccountTransactions = if (account.bookedTransactions.isNotEmpty()) account.bookedTransactions else fetchedTransactions
|
||||
|
||||
firstAccountTransactions.map { it.valueDate }.minBy { it.millisSinceEpoch }?.let { dateOfFirstRetrievedTransaction ->
|
||||
val dayOfFirstTransactionStoredOnBankServer = Date(Date.today.millisSinceEpoch - countDaysForWhichTransactionsAreKept * OneDayMillis)
|
||||
|
||||
return dateOfFirstRetrievedTransaction.isBeforeOrEquals(dayOfFirstTransactionStoredOnBankServer)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
protected open fun receivedAccountsTransactionChunk(bankAccount: TypedBankAccount, accountTransactionsChunk: List<IAccountTransaction>) {
|
||||
if (accountTransactionsChunk.isNotEmpty()) {
|
||||
asyncRunner.runAsync { // don't block retrieving next chunk by blocked saving to db / json
|
||||
|
@ -366,17 +381,17 @@ open class BankingPresenter(
|
|||
}
|
||||
}
|
||||
|
||||
protected open fun updateAccountTransactions(bankAccount: TypedBankAccount, bookedTransactions: Collection<IAccountTransaction>, unbookedTransactions: List<Any>? = null) {
|
||||
val knownAccountTransactions = bankAccount.bookedTransactions.map { it.transactionIdentifier }
|
||||
protected open fun updateAccountTransactions(account: TypedBankAccount, bookedTransactions: Collection<IAccountTransaction>, unbookedTransactions: List<Any>? = null) {
|
||||
val knownAccountTransactions = account.bookedTransactions.map { it.transactionIdentifier }
|
||||
|
||||
val newBookedTransactions = bookedTransactions.filterNot { knownAccountTransactions.contains(it.transactionIdentifier) }
|
||||
bankAccount.addBookedTransactions(newBookedTransactions)
|
||||
account.addBookedTransactions(newBookedTransactions)
|
||||
|
||||
unbookedTransactions?.let {
|
||||
bankAccount.addUnbookedTransactions(unbookedTransactions)
|
||||
account.addUnbookedTransactions(unbookedTransactions)
|
||||
}
|
||||
|
||||
persistAccountTransactionsOffUiThread(bankAccount, newBookedTransactions)
|
||||
persistAccountTransactionsOffUiThread(account, newBookedTransactions)
|
||||
}
|
||||
|
||||
protected open fun updateBalance(bankAccount: TypedBankAccount, balance: BigDecimal) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19E287" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17192" systemVersion="19G2021" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="PersistedAccountTransaction" representedClassName="PersistedAccountTransaction" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="amount" attributeType="Decimal" defaultValueString="0.0"/>
|
||||
<attribute name="bookingDate" attributeType="Date" usesScalarValueType="NO"/>
|
||||
|
@ -62,6 +62,7 @@
|
|||
<attribute name="bankCode" attributeType="String"/>
|
||||
<attribute name="bankName" attributeType="String"/>
|
||||
<attribute name="bic" attributeType="String"/>
|
||||
<attribute name="countDaysForWhichTransactionsAreKept" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO"/>
|
||||
<attribute name="customerId" attributeType="String"/>
|
||||
<attribute name="customerName" attributeType="String"/>
|
||||
<attribute name="displayIndex" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
|
@ -90,7 +91,7 @@
|
|||
<element name="PersistedAccountTransaction" positionX="-36" positionY="45" width="128" height="553"/>
|
||||
<element name="PersistedBankAccount" positionX="-54" positionY="63" width="128" height="343"/>
|
||||
<element name="PersistedCustomer" positionX="-63" positionY="-18" width="128" height="28"/>
|
||||
<element name="PersistedTanProcedure" positionX="-54" positionY="135" width="128" height="118"/>
|
||||
<element name="PersistedTanMedium" positionX="-45" positionY="144" width="128" height="28"/>
|
||||
<element name="PersistedTanProcedure" positionX="-54" positionY="135" width="128" height="118"/>
|
||||
</elements>
|
||||
</model>
|
|
@ -8,6 +8,8 @@ class Mapper {
|
|||
func map(_ customer: PersistedCustomer) -> ICustomer {
|
||||
let mapped = Customer(bankCode: map(customer.bankCode), customerId: map(customer.customerId), password: map(customer.password), finTsServerAddress: map(customer.finTsServerAddress), bankName: map(customer.bankName), bic: map(customer.bic), customerName: map(customer.customerName), userId: map(customer.userId), iconUrl: customer.iconUrl, accounts: [])
|
||||
|
||||
mapped.countDaysForWhichTransactionsAreKept = mapToInt(customer.countDaysForWhichTransactionsAreKept)
|
||||
|
||||
mapped.userSetDisplayName = customer.userSetDisplayName
|
||||
mapped.displayIndex = customer.displayIndex
|
||||
|
||||
|
@ -35,6 +37,7 @@ class Mapper {
|
|||
mapped.customerName = customer.customerName
|
||||
mapped.userId = customer.userId
|
||||
mapped.iconUrl = customer.iconUrl
|
||||
mapped.countDaysForWhichTransactionsAreKept = mapFromInt(customer.countDaysForWhichTransactionsAreKept)
|
||||
|
||||
mapped.userSetDisplayName = customer.userSetDisplayName
|
||||
mapped.displayIndex = customer.displayIndex
|
||||
|
@ -357,6 +360,22 @@ class Mapper {
|
|||
return nil
|
||||
}
|
||||
|
||||
func mapToInt(_ int: NSNumber?) -> KotlinInt? {
|
||||
if let int = int {
|
||||
return KotlinInt(int: int.int32Value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mapFromInt(_ int: KotlinInt?) -> NSNumber? {
|
||||
if let int = map(int) {
|
||||
return NSNumber(value: int)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func map(_ string: String?) -> String {
|
||||
return string ?? ""
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
customer.bankName = bank.bankName
|
||||
customer.bic = bank.bic
|
||||
customer.customerName = bank.customerName
|
||||
customer.countDaysForWhichTransactionsAreKept = bank.countDaysForWhichTransactionsAreKept
|
||||
customer.userId = bank.userId
|
||||
|
||||
customer.accounts = mapBankAccounts(customer, bank.accounts)
|
||||
|
|
Loading…
Reference in New Issue