Implemented that for retrieving account transactions and for bank transfer the concrete AccountData is required (as for CustomerData with multiple accounts using CustomerData will not work)

This commit is contained in:
dankito 2020-01-21 00:54:06 +01:00 committed by dankito
parent 0c92a25d92
commit 57aba0971d
21 changed files with 154 additions and 126 deletions

View File

@ -18,6 +18,6 @@ interface IBankingClient {
callback: (GetTransactionsResponse) -> Unit
)
fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit)
fun transferMoneyAsync(data: TransferMoneyData, bankAccount: BankAccount, callback: (BankingClientResponse) -> Unit)
}

View File

@ -220,7 +220,7 @@ open class MainWindowPresenter(
open fun transferMoneyAsync(bankAccount: BankAccount, data: TransferMoneyData, callback: (BankingClientResponse) -> Unit) {
getClientForAccount(bankAccount.account)?.let { client ->
client.transferMoneyAsync(data, callback)
client.transferMoneyAsync(data, bankAccount, callback)
}
}

View File

@ -79,20 +79,34 @@ open class fints4javaBankingClient(
}
override fun getTransactionsAsync(bankAccount: BankAccount, parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) {
client.getTransactionsAsync(net.dankito.fints.model.GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate, parameter.toDate)) { response ->
val account = mapper.findAccountForBankAccount(customer, bankAccount)
if (account == null) {
callback(GetTransactionsResponse(false, "Cannot find account for ${bankAccount.identifier}")) // TODO: translate
}
else {
client.getTransactionsAsync(net.dankito.fints.model.GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate, parameter.toDate), account) { response ->
val mappedResponse = mapper.mapResponse(bankAccount, response)
callback(mappedResponse)
}
}
}
override fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit) {
override fun transferMoneyAsync(data: TransferMoneyData, bankAccount: BankAccount, callback: (BankingClientResponse) -> Unit) {
val account = mapper.findAccountForBankAccount(customer, bankAccount)
if (account == null) {
callback(BankingClientResponse(false, "Cannot find account for ${bankAccount.identifier}")) // TODO: translate
}
else {
val mappedData = BankTransferData(data.creditorName, data.creditorIban, data.creditorBic, data.amount, data.usage)
client.doBankTransferAsync(mappedData) { response ->
client.doBankTransferAsync(mappedData, account) { response ->
callback(mapper.mapResponse(response))
}
}
}
}

View File

@ -91,6 +91,11 @@ open class fints4javaModelMapper {
}
}
open fun findAccountForBankAccount(customer: CustomerData, bankAccount: BankAccount): AccountData? {
return customer.accounts.firstOrNull { bankAccount.identifier == it.accountIdentifier }
}
open fun mapTransactions(bankAccount: BankAccount, transactions: List<net.dankito.fints.model.AccountTransaction>): List<AccountTransaction> {
return transactions.map { mapTransaction(bankAccount, it) }
}

View File

@ -9,6 +9,7 @@ import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherhe
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedienArtVersion
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
import net.dankito.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.fints.model.*
import net.dankito.fints.response.InstituteSegmentId
import net.dankito.fints.response.Response
@ -152,7 +153,8 @@ open class FinTsClient @JvmOverloads constructor(
getTanMediaList(bank, customer, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien)
// also check if retrieving account transactions of last 90 days without tan is supported (and thereby may retrieve first account transactions)
val transactionsOfLast90DaysResponse = tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, false)
val account = getBestAccountForRetrievingTransactions(customer)
val transactionsOfLast90DaysResponse = if (account != null) tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false) else GetTransactionsResponse(Response(false))
if (didOverwriteUserUnselectedTanProcedure) {
customer.resetSelectedTanProcedure()
@ -172,12 +174,12 @@ open class FinTsClient @JvmOverloads constructor(
*
* Check if bank supports this.
*/
open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData,
open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData,
hasRetrievedTransactionsWithTanJustBefore: Boolean): GetTransactionsResponse {
val ninetyDaysAgo = Date(Date().time - NinetyDaysAgoMilliseconds)
val response = getTransactions(GetTransactionsParameter(true, ninetyDaysAgo), bank, customer)
val response = getTransactions(GetTransactionsParameter(true, ninetyDaysAgo), bank, customer, account)
customer.triedToRetrieveTransactionsOfLast90DaysWithoutTan = true
@ -192,15 +194,15 @@ open class FinTsClient @JvmOverloads constructor(
}
open fun getTransactionsAsync(parameter: GetTransactionsParameter, bank: BankData,
customer: CustomerData, callback: (GetTransactionsResponse) -> Unit) {
customer: CustomerData, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
threadPool.runAsync {
callback(getTransactions(parameter, bank, customer))
callback(getTransactions(parameter, bank, customer, account))
}
}
open fun getTransactions(parameter: GetTransactionsParameter, bank: BankData,
customer: CustomerData): GetTransactionsResponse {
customer: CustomerData, account: AccountData): GetTransactionsResponse {
val dialogData = DialogData()
@ -214,7 +216,7 @@ open class FinTsClient @JvmOverloads constructor(
var balance: BigDecimal? = null
if (parameter.alsoRetrieveBalance) {
val balanceResponse = getBalanceAfterDialogInit(bank, customer, dialogData)
val balanceResponse = getBalanceAfterDialogInit(bank, customer, account, dialogData)
if (balanceResponse.successful == false && balanceResponse.couldCreateMessage == true) { // don't break here if required HKSAL message is not implemented
closeDialog(bank, customer, dialogData)
@ -231,7 +233,7 @@ open class FinTsClient @JvmOverloads constructor(
}
val message = messageBuilder.createGetTransactionsMessage(parameter, bank, customer, product, dialogData)
val message = messageBuilder.createGetTransactionsMessage(parameter, bank, customer, account, product, dialogData)
val response = getAndHandleResponseForMessageThatMayRequiresTan(message, bank, customer, dialogData)
@ -242,7 +244,7 @@ open class FinTsClient @JvmOverloads constructor(
// just retrieved all transactions -> check if retrieving that ones of last 90 days is possible without entering TAN
if (customer.supportsRetrievingTransactionsOfLast90DaysWithoutTan == null &&
response.successful && transactions.bookedTransactionsString.isNotEmpty() && parameter.fromDate == null) {
tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, true)
tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, true)
}
val bookedAndUnbookedTransactions = getTransactionsFromResponse(response, transactions)
@ -284,12 +286,12 @@ open class FinTsClient @JvmOverloads constructor(
}
}
protected open fun getBalanceAfterDialogInit(bank: BankData, customer: CustomerData,
protected open fun getBalanceAfterDialogInit(bank: BankData, customer: CustomerData, account: AccountData,
dialogData: DialogData): Response {
dialogData.increaseMessageNumber()
val balanceRequest = messageBuilder.createGetBalanceMessage(bank, customer, product, dialogData)
val balanceRequest = messageBuilder.createGetBalanceMessage(bank, customer, account, product, dialogData)
return getAndHandleResponseForMessage(balanceRequest, bank)
}
@ -373,15 +375,15 @@ open class FinTsClient @JvmOverloads constructor(
open fun doBankTransferAsync(bankTransferData: BankTransferData, bank: BankData,
customer: CustomerData, callback: (FinTsClientResponse) -> Unit) {
customer: CustomerData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
threadPool.runAsync {
callback(doBankTransfer(bankTransferData, bank, customer))
callback(doBankTransfer(bankTransferData, bank, customer, account))
}
}
open fun doBankTransfer(bankTransferData: BankTransferData, bank: BankData,
customer: CustomerData): FinTsClientResponse {
customer: CustomerData, account: AccountData): FinTsClientResponse {
val dialogData = DialogData()
@ -394,7 +396,7 @@ open class FinTsClient @JvmOverloads constructor(
dialogData.increaseMessageNumber()
val message = messageBuilder.createBankTransferMessage(bankTransferData, bank, customer, dialogData)
val message = messageBuilder.createBankTransferMessage(bankTransferData, bank, customer, account, dialogData)
val response = getAndHandleResponseForMessageThatMayRequiresTan(message, bank, customer, dialogData)
@ -791,10 +793,6 @@ open class FinTsClient @JvmOverloads constructor(
}
response.getSegmentsById<AccountInfo>(InstituteSegmentId.AccountInfo).forEach { accountInfo ->
if (customer.iban == null && accountInfo.iban != null) {
customer.iban = accountInfo.iban // TODO: remove and use that one from AccountData
}
var accountHolderName = accountInfo.accountHolderName1
accountInfo.accountHolderName2?.let {
accountHolderName += it // TODO: add a whitespace in between?
@ -817,9 +815,9 @@ open class FinTsClient @JvmOverloads constructor(
}
response.getFirstSegmentById<SepaAccountInfo>(InstituteSegmentId.SepaAccountInfo)?.let { sepaAccountInfo ->
// TODO: may also make use of other info
// TODO: make use of information
sepaAccountInfo.account.iban?.let {
customer.iban = it
}
}
@ -837,7 +835,7 @@ open class FinTsClient @JvmOverloads constructor(
response.getFirstSegmentById<CommunicationInfo>(InstituteSegmentId.CommunicationInfo)?.let { communicationInfo ->
if (customer.selectedLanguage != communicationInfo.defaultLanguage) {
customer.selectedLanguage == communicationInfo.defaultLanguage
customer.selectedLanguage = communicationInfo.defaultLanguage
}
}
@ -940,4 +938,9 @@ open class FinTsClient @JvmOverloads constructor(
return null
}
internal fun getBestAccountForRetrievingTransactions(customer: CustomerData): AccountData? {
return customer.accounts.firstOrNull { it.allowedJobNames.contains(CustomerSegmentId.AccountTransactionsMt940.id) }
}
}

View File

@ -35,12 +35,12 @@ open class FinTsClientForCustomer(
client.addAccountAsync(bank, customer, callback)
}
open fun getTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) {
client.getTransactionsAsync(parameter, bank, customer, callback)
open fun getTransactionsAsync(parameter: GetTransactionsParameter, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
client.getTransactionsAsync(parameter, bank, customer, account, callback)
}
open fun doBankTransferAsync(bankTransferData: BankTransferData, callback: (FinTsClientResponse) -> Unit) {
client.doBankTransferAsync(bankTransferData, bank, customer, callback)
open fun doBankTransferAsync(bankTransferData: BankTransferData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
client.doBankTransferAsync(bankTransferData, bank, customer, account, callback)
}
}

View File

@ -108,14 +108,14 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
open fun createGetTransactionsMessage(parameter: GetTransactionsParameter, bank: BankData, customer: CustomerData,
product: ProductData, dialogData: DialogData): MessageBuilderResult {
account: AccountData, product: ProductData, dialogData: DialogData): MessageBuilderResult {
val result = getSupportedVersionsOfJob(CustomerSegmentId.AccountTransactionsMt940, customer, listOf(5, 6, 7))
val result = getSupportedVersionsOfJob(CustomerSegmentId.AccountTransactionsMt940, account, listOf(5, 6, 7))
if (result.isJobVersionSupported) {
val transactionsJob = if (result.isAllowed(7)) KontoumsaetzeZeitraumMt940Version7(generator.resetSegmentNumber(2), parameter, bank, customer)
else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(generator.resetSegmentNumber(2), parameter, bank, customer)
else KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter, bank, customer)
val transactionsJob = if (result.isAllowed(7)) KontoumsaetzeZeitraumMt940Version7(generator.resetSegmentNumber(2), parameter, bank, account)
else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(generator.resetSegmentNumber(2), parameter, account)
else KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter, account)
val segments = listOf(
transactionsJob,
@ -128,13 +128,13 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
return result
}
open fun createGetBalanceMessage(bank: BankData, customer: CustomerData, product: ProductData, dialogData: DialogData): MessageBuilderResult {
open fun createGetBalanceMessage(bank: BankData, customer: CustomerData, account: AccountData, product: ProductData, dialogData: DialogData): MessageBuilderResult {
val result = getSupportedVersionsOfJob(CustomerSegmentId.Balance, customer, listOf(5))
val result = getSupportedVersionsOfJob(CustomerSegmentId.Balance, account, listOf(5))
if (result.isJobVersionSupported) {
val segments = listOf(
Saldenabfrage(generator.resetSegmentNumber(2), bank, customer),
Saldenabfrage(generator.resetSegmentNumber(2), account),
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Balance)
)
@ -191,15 +191,15 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
}
open fun createBankTransferMessage(bankTransferData: BankTransferData, bank: BankData, customer: CustomerData, dialogData: DialogData): MessageBuilderResult {
open fun createBankTransferMessage(bankTransferData: BankTransferData, bank: BankData, customer: CustomerData, account: AccountData, dialogData: DialogData): MessageBuilderResult {
val result = getSupportedVersionsOfJob(CustomerSegmentId.SepaBankTransfer, customer, listOf(1))
val result = getSupportedVersionsOfJob(CustomerSegmentId.SepaBankTransfer, account, listOf(1))
if (result.isJobVersionSupported) {
getSepaUrnFor(CustomerSegmentId.SepaAccountInfoParameters, customer, "pain.001.001.03")?.let { urn ->
getSepaUrnFor(CustomerSegmentId.SepaAccountInfoParameters, account, "pain.001.001.03")?.let { urn ->
val segments = listOf(
SepaEinzelueberweisung(generator.resetSegmentNumber(2), urn, customer, bank.bic, bankTransferData),
SepaEinzelueberweisung(generator.resetSegmentNumber(2), urn, customer, account, bank.bic, bankTransferData),
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.SepaBankTransfer)
)
@ -326,39 +326,58 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
}
protected open fun getSupportedVersionsOfJob(segmentId: CustomerSegmentId, account: AccountData,
supportedVersions: List<Int>): MessageBuilderResult {
val allowedJobs = getAllowedJobs(segmentId, account)
return getSupportedVersionsOfJob(supportedVersions, allowedJobs)
}
// TODO: try to get rid of
protected open fun getSupportedVersionsOfJob(segmentId: CustomerSegmentId, customer: CustomerData,
supportedVersions: List<Int>): MessageBuilderResult {
val allowedJobs = getAllowedJobs(segmentId, customer)
return getSupportedVersionsOfJob(supportedVersions, allowedJobs)
}
protected open fun getSupportedVersionsOfJob(supportedVersions: List<Int>, allowedJobs: List<JobParameters>): MessageBuilderResult {
if (allowedJobs.isNotEmpty()) {
val allowedVersions = allowedJobs
.map { it.segmentVersion }
.sortedDescending()
return MessageBuilderResult(allowedVersions.isNotEmpty(), allowedVersions.containsAny(supportedVersions),
allowedVersions, supportedVersions, null)
return MessageBuilderResult(
allowedVersions.isNotEmpty(), allowedVersions.containsAny(supportedVersions),
allowedVersions, supportedVersions, null
)
}
return MessageBuilderResult(false)
}
protected open fun getSepaUrnFor(segmentId: CustomerSegmentId, customer: CustomerData, sepaDataFormat: String): String? {
protected open fun getSepaUrnFor(segmentId: CustomerSegmentId, account: AccountData, sepaDataFormat: String): String? {
return getAllowedJobs(segmentId, customer)
return getAllowedJobs(segmentId, account)
.filterIsInstance<SepaAccountInfoParameters>()
.sortedByDescending { it.segmentVersion }
.flatMap { it.supportedSepaFormats }
.firstOrNull { it.contains(sepaDataFormat) }
}
protected open fun getAllowedJobs(segmentId: CustomerSegmentId, customer: CustomerData): List<JobParameters> {
protected open fun getAllowedJobs(segmentId: CustomerSegmentId, account: AccountData): List<JobParameters> {
customer.accounts.firstOrNull()?.let { account -> // TODO: find a better solution / make more generic
return account.allowedJobs.filter { it.jobName == segmentId.id }
}
return listOf()
// TODO: this implementation is in most cases wrong, try to get rid of
protected open fun getAllowedJobs(segmentId: CustomerSegmentId, customer: CustomerData): List<JobParameters> {
return customer.accounts.flatMap { account ->
return account.allowedJobs.filter { it.jobName == segmentId.id }
}
}
}

View File

@ -31,10 +31,7 @@ open class Kontoverbindung(
Kreditinstitutskennung(bankCountryCode, bankCode)
), Existenzstatus.Mandatory) {
constructor(bank: BankData, customer: CustomerData, account: AccountData?)
: this(bank, customer, account?.subAccountAttribute)
constructor(bank: BankData, customer: CustomerData, subAccountAttribute: String?)
: this(bank.countryCode, bank.bankCode, customer.customerId, subAccountAttribute)
constructor(account: AccountData)
: this(account.bankCountryCode, account.bankCode, account.accountIdentifier, account.subAccountAttribute)
}

View File

@ -33,9 +33,8 @@ open class KontoverbindungInternational(
Kreditinstitutskennung(bankCountryCode ?: 0, bankCode ?: "", if (bankCountryCode != null && bankCode != null) Existenzstatus.Optional else Existenzstatus.NotAllowed)
), Existenzstatus.Mandatory) {
constructor(bank: BankData, customer: CustomerData, account: AccountData?)
: this(bank, customer, account?.subAccountAttribute)
constructor(account: AccountData, bank: BankData) : this(account, bank.bic)
constructor(bank: BankData, customer: CustomerData, subAccountAttribute: String?)
: this(customer.iban, bank.bic, bank.countryCode, bank.bankCode, customer.customerId, subAccountAttribute)
constructor(account: AccountData, bic: String)
: this(account.iban, bic, account.bankCountryCode, account.bankCode, account.accountIdentifier, account.subAccountAttribute)
}

View File

@ -1,6 +1,7 @@
package net.dankito.fints.messages.segmente.implementierte.sepa
import net.dankito.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.fints.model.AccountData
import net.dankito.fints.model.BankTransferData
import net.dankito.fints.model.CustomerData
@ -9,6 +10,7 @@ open class SepaEinzelueberweisung(
segmentNumber: Int,
sepaDescriptorUrn: String,
debitor: CustomerData,
account: AccountData,
debitorBic: String,
data: BankTransferData,
messageCreator: ISepaMessageCreator = SepaMessageCreator()
@ -19,12 +21,12 @@ open class SepaEinzelueberweisung(
1,
sepaDescriptorUrn,
"pain.001.001.03.xml",
debitor.iban ?: "", // TODO: what to do if iban is not set?
account.iban ?: "", // TODO: what to do if iban is not set?
debitorBic,
mapOf(
SepaMessageCreator.NumberOfTransactionsKey to "1", // TODO: may someday support more then one transaction per file
"DebitorName" to messageCreator.convertToAllowedCharacters(debitor.name),
"DebitorIban" to debitor.iban!!,
"DebitorIban" to account.iban!!,
"DebitorBic" to debitorBic,
"CreditorName" to messageCreator.convertToAllowedCharacters(data.creditorName),
"CreditorIban" to data.creditorIban,

View File

@ -64,8 +64,8 @@ open class TanGeneratorTanMediumAnOderUmmelden(
AlphanumerischesDatenelement(newActiveTanMedium.cardNumber, Existenzstatus.Mandatory),
AlphanumerischesDatenelement(newActiveTanMedium.cardSequenceNumber, if (parameters.enteringCardSequenceNumberRequired) Existenzstatus.Mandatory else Existenzstatus.NotAllowed),
if (segmentVersion > 1) NumerischesDatenelement(newActiveTanMedium.cardType, 2, if (parameters.enteringCardTypeAllowed) Existenzstatus.Optional else Existenzstatus.NotAllowed) else DoNotPrintDatenelement(),
if (segmentVersion == 2) Kontoverbindung(bank, customer, customer.accounts.firstOrNull()) else DoNotPrintDatenelement(),
if (segmentVersion >= 3 && parameters.accountInfoRequired) KontoverbindungInternational(bank, customer, customer.accounts.firstOrNull()) else DoNotPrintDatenelement(),
if (segmentVersion == 2) Kontoverbindung(customer.accounts.first()) else DoNotPrintDatenelement(),
if (segmentVersion >= 3 && parameters.accountInfoRequired) KontoverbindungInternational(customer.accounts.first(), bank) else DoNotPrintDatenelement(),
if (segmentVersion >= 2) Datum(newActiveTanMedium.validFrom, Existenzstatus.Optional) else DoNotPrintDatenelement(),
if (segmentVersion >= 2) Datum(newActiveTanMedium.validTo, Existenzstatus.Optional) else DoNotPrintDatenelement(),
if (segmentVersion >= 3) AlphanumerischesDatenelement(iccsn, Existenzstatus.Optional, 19) else DoNotPrintDatenelement(),

View File

@ -1,8 +1,7 @@
package net.dankito.fints.messages.segmente.implementierte.umsaetze
import net.dankito.fints.messages.datenelementgruppen.implementierte.account.Kontoverbindung
import net.dankito.fints.model.BankData
import net.dankito.fints.model.CustomerData
import net.dankito.fints.model.AccountData
import net.dankito.fints.model.GetTransactionsParameter
@ -19,14 +18,6 @@ import net.dankito.fints.model.GetTransactionsParameter
open class KontoumsaetzeZeitraumMt940Version5(
segmentNumber: Int,
parameter: GetTransactionsParameter,
bank: BankData,
customer: CustomerData,
subAccountAttribute: String? = null
)
: KontoumsaetzeZeitraumMt940Base(
5,
segmentNumber,
Kontoverbindung(bank.countryCode, bank.bankCode, customer.customerId, subAccountAttribute),
parameter
account: AccountData
)
: KontoumsaetzeZeitraumMt940Base(5, segmentNumber, Kontoverbindung(account), parameter)

View File

@ -1,8 +1,7 @@
package net.dankito.fints.messages.segmente.implementierte.umsaetze
import net.dankito.fints.messages.datenelementgruppen.implementierte.account.Kontoverbindung
import net.dankito.fints.model.BankData
import net.dankito.fints.model.CustomerData
import net.dankito.fints.model.AccountData
import net.dankito.fints.model.GetTransactionsParameter
@ -19,14 +18,7 @@ import net.dankito.fints.model.GetTransactionsParameter
open class KontoumsaetzeZeitraumMt940Version6(
segmentNumber: Int,
parameter: GetTransactionsParameter,
bank: BankData,
customer: CustomerData,
subAccountAttribute: String? = null
account: AccountData
)
: KontoumsaetzeZeitraumMt940Base(
6,
segmentNumber,
Kontoverbindung(bank.countryCode, bank.bankCode, customer.customerId, subAccountAttribute),
parameter
)
: KontoumsaetzeZeitraumMt940Base(6, segmentNumber, Kontoverbindung(account), parameter)

View File

@ -1,8 +1,8 @@
package net.dankito.fints.messages.segmente.implementierte.umsaetze
import net.dankito.fints.messages.datenelementgruppen.implementierte.account.KontoverbindungInternational
import net.dankito.fints.model.AccountData
import net.dankito.fints.model.BankData
import net.dankito.fints.model.CustomerData
import net.dankito.fints.model.GetTransactionsParameter
@ -20,12 +20,6 @@ open class KontoumsaetzeZeitraumMt940Version7(
segmentNumber: Int,
parameter: GetTransactionsParameter,
bank: BankData,
customer: CustomerData,
subAccountAttribute: String? = null // TODO: move to CustomerData.accounts
)
: KontoumsaetzeZeitraumMt940Base(
7,
segmentNumber,
KontoverbindungInternational(bank, customer, subAccountAttribute),
parameter
account: AccountData
)
: KontoumsaetzeZeitraumMt940Base(7, segmentNumber, KontoverbindungInternational(account, bank), parameter)

View File

@ -8,21 +8,19 @@ import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
import net.dankito.fints.messages.datenelementgruppen.implementierte.account.Kontoverbindung
import net.dankito.fints.messages.segmente.Segment
import net.dankito.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.fints.model.BankData
import net.dankito.fints.model.CustomerData
import net.dankito.fints.model.AccountData
open class Saldenabfrage(
segmentNumber: Int,
bank: BankData,
customer: CustomerData, // TODO: pass AccountData instead
account: AccountData,
allAccounts: Boolean = false,
maxAmountEntries: Int? = null,
continuationId: String? = null
)
: Segment(listOf(
Segmentkopf(CustomerSegmentId.Balance, 5, segmentNumber),
Kontoverbindung(bank.countryCode, bank.bankCode, customer.customerId),
Kontoverbindung(account),
AlleKonten(allAccounts, Existenzstatus.Mandatory),
MaximaleAnzahlEintraege(maxAmountEntries, Existenzstatus.Optional),
Aufsetzpunkt(continuationId, Existenzstatus.Optional)

View File

@ -10,7 +10,6 @@ open class CustomerData(
var pin: String,
val userId: String = customerId,
var name: String = "",
var iban: String? = null,
val accounts: List<AccountData> = mutableListOf(),
var updVersion: Int = UPDVersion.VersionNotReceivedYet,
var supportedTanProcedures: List<TanProcedure> = listOf(),

View File

@ -9,6 +9,7 @@ import net.dankito.fints.messages.datenelemente.implementierte.tan.TanEinsatzOpt
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedienArtVersion
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
import net.dankito.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.fints.model.*
import net.dankito.fints.model.mapper.BankDataMapper
import net.dankito.fints.response.client.FinTsClientResponse
@ -101,7 +102,6 @@ class FinTsClientTest {
assertThat(Bank.supportedLanguages).isNotEmpty() // supported languages are now known
assertThat(Customer.name).isNotEmpty()
assertThat(Customer.iban).isNotNull()
assertThat(Customer.supportedTanProcedures).isNotEmpty()
assertThat(Customer.selectedLanguage).isNotEqualTo(Dialogsprache.Default) // language is set now
assertThat(Customer.customerSystemId).isNotEqualTo(KundensystemStatus.SynchronizingCustomerSystemId) // customer system id is now set
@ -128,10 +128,15 @@ class FinTsClientTest {
@Test
fun getTransactions() {
// given
underTest.addAccount(Bank, Customer) // retrieve basic data, e.g. accounts
val account = underTest.getBestAccountForRetrievingTransactions(Customer)
assertThat(account).describedAs("We need at least one account that supports retrieving account transactions (${CustomerSegmentId.AccountTransactionsMt940.id})").isNotNull()
// when
// some banks support retrieving account transactions of last 90 days without TAN
val result = underTest.tryGetTransactionsOfLast90DaysWithoutTan(Bank, Customer, false)
val result = underTest.tryGetTransactionsOfLast90DaysWithoutTan(Bank, Customer, account!!, false)
// then
@ -177,17 +182,21 @@ class FinTsClientTest {
fun testBankTransfer() {
// given
underTest.addAccount(Bank, Customer)
underTest.addAccount(Bank, Customer) // retrieve basic data, e.g. accounts
// now IBAN should be set
assertThat(Customer.iban).describedAs("Customer's IBAN should now be set").isNotNull()
// we need at least one account that supports cash transfer
val account = Customer.accounts.firstOrNull { it.allowedJobNames.contains(CustomerSegmentId.SepaBankTransfer.id) }
assertThat(account).describedAs("We need at least one account that supports cash transfer (${CustomerSegmentId.SepaBankTransfer.id})").isNotNull()
// IBAN should be set
assertThat(account?.iban).describedAs("Account IBAN must be set").isNotNull()
// transfer 1 cent to yourself. Transferring money to oneself also doesn't require to enter a TAN according to PSD2
val BankTransferData = BankTransferData(Customer.name, Customer.iban!!, Bank.bic, 0.01.toBigDecimal(), "Give it to me baby")
val BankTransferData = BankTransferData(Customer.name, account?.iban!!, Bank.bic, 0.01.toBigDecimal(), "Give it to me baby")
// when
val result = underTest.doBankTransfer(BankTransferData, Bank, Customer)
val result = underTest.doBankTransfer(BankTransferData, Bank, Customer, account)
// then
assertThat(result.isSuccessful).isTrue()

View File

@ -3,8 +3,8 @@ package net.dankito.fints
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Datum
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
import net.dankito.fints.model.*
import net.dankito.fints.response.segments.AccountType
import net.dankito.fints.response.segments.ChangeTanMediaParameters
import net.dankito.fints.response.segments.JobParameters
import java.math.BigDecimal
@ -38,6 +38,12 @@ abstract class FinTsTestBase {
val Customer = CustomerData(CustomerId, Pin, selectedTanProcedure = TanProcedure("chipTAN-optisch", SecurityFunction, TanProcedureType.ChipTanOptisch), selectedLanguage = Language)
val Currency = "EUR"
val AccountHolderName = "Martina Musterfrau"
val Account = AccountData(CustomerId, null, BankCountryCode, BankCode, Iban, CustomerId, AccountType.Girokonto, Currency, AccountHolderName, null, null, listOf(), listOf())
const val ProductName = "FinTS-TestClient25Stellen"
const val ProductVersion = "1"

View File

@ -38,7 +38,6 @@ class MessageBuilderTest : FinTsTestBase() {
@After
fun tearDown() {
Bank.supportedJobs = listOf()
Customer.accounts = listOf()
}
@ -122,7 +121,7 @@ class MessageBuilderTest : FinTsTestBase() {
fun createGetTransactionsMessage_JobIsNotAllowed() {
// when
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Bank, Customer, Product, DialogData.DialogInitDialogData)
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Bank, Customer, Account, Product, DialogData.DialogInitDialogData)
// then
assertThat(result.isJobAllowed).isFalse()
@ -136,10 +135,10 @@ class MessageBuilderTest : FinTsTestBase() {
val getTransactionsJobWithPreviousVersion = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:72:4")
Bank.supportedJobs = listOf(getTransactionsJob)
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJobWithPreviousVersion))
Customer.accounts = listOf(account)
Customer.addAccount(account)
// when
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Bank, Customer, Product, DialogData.DialogInitDialogData)
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Bank, Customer, account, Product, DialogData.DialogInitDialogData)
// then
assertThat(result.isJobAllowed).isTrue()
@ -153,14 +152,14 @@ class MessageBuilderTest : FinTsTestBase() {
val getTransactionsJob = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:73:5")
Bank.supportedJobs = listOf(getTransactionsJob)
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob))
Customer.accounts = listOf(account)
Customer.addAccount(account)
val fromDate = LocalDate.of(2019, Month.AUGUST, 6).asUtilDate()
val toDate = LocalDate.of(2019, Month.OCTOBER, 21).asUtilDate()
val maxCountEntries = 99
// when
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries), Bank, Customer, Product, DialogData.DialogInitDialogData)
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries), Bank, Customer, account, Product, DialogData.DialogInitDialogData)
// then
assertThat(result.createdMessage).isNotNull()
@ -183,7 +182,7 @@ class MessageBuilderTest : FinTsTestBase() {
val getTransactionsJob = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:73:5")
Bank.supportedJobs = listOf(getTransactionsJob)
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob))
Customer.accounts = listOf(account)
Customer.addAccount(account)
val fromDate = LocalDate.of(2019, Month.AUGUST, 6).asUtilDate()
val toDate = LocalDate.of(2019, Month.OCTOBER, 21).asUtilDate()
@ -191,7 +190,7 @@ class MessageBuilderTest : FinTsTestBase() {
val continuationId = "9345-10-26-11.52.15.693455"
// when
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries, false, continuationId), Bank, Customer, Product, DialogData.DialogInitDialogData)
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries, false, continuationId), Bank, Customer, account, Product, DialogData.DialogInitDialogData)
// then
assertThat(result.createdMessage).isNotNull()

View File

@ -1,10 +1,12 @@
package net.dankito.fints.messages.segmente.implementierte.sepa
import net.dankito.fints.model.AccountData
import net.dankito.fints.model.BankTransferData
import net.dankito.fints.model.CustomerData
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
class SepaEinzelueberweisungTest {
@Test
@ -23,7 +25,8 @@ class SepaEinzelueberweisungTest {
val underTest = SepaEinzelueberweisung(segmentNumber,
"urn:iso:std:iso:20022:tech:xsd:pain.001.001.03",
CustomerData("", "", "", debitorName, debitorIban),
CustomerData("", "", "", debitorName),
AccountData("", null, 0, "", debitorIban, "", null, null, "", null, null, listOf()),
debitorBic,
BankTransferData(creditorName, creditorIban, creditorBic, amount, usage)
)

View File

@ -10,8 +10,7 @@ class SaldenabfrageTest : FinTsTestBase() {
fun format_NotAllAccounts() {
// given
val underTest =
Saldenabfrage(3, Bank, Customer, false)
val underTest = Saldenabfrage(3, Account, false)
// when
val result = underTest.format()
@ -24,8 +23,7 @@ class SaldenabfrageTest : FinTsTestBase() {
fun format_AllAccounts() {
// given
val underTest =
Saldenabfrage(3, Bank, Customer, true)
val underTest = Saldenabfrage(3, Account, true)
// when
val result = underTest.format()