Implemented DialogContext to keep track of dialog's current state and to not have to pass BankData, CustomerData and ProductData to almost all methods

This commit is contained in:
dankito 2020-05-12 16:05:23 +02:00
parent 584adf9375
commit 333747a5e4
17 changed files with 312 additions and 289 deletions

View File

@ -4,7 +4,6 @@ import net.dankito.fints.callback.FinTsClientCallback
import net.dankito.fints.messages.MessageBuilder import net.dankito.fints.messages.MessageBuilder
import net.dankito.fints.messages.MessageBuilderResult import net.dankito.fints.messages.MessageBuilderResult
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemID
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
@ -76,35 +75,33 @@ open class FinTsClient @JvmOverloads constructor(
* On success [bank] parameter is updated afterwards. * On success [bank] parameter is updated afterwards.
*/ */
open fun getAnonymousBankInfo(bank: BankData): FinTsClientResponse { open fun getAnonymousBankInfo(bank: BankData): FinTsClientResponse {
val dialogData = DialogData() val dialogContext = DialogContext(bank, CustomerData.Anonymous, product)
val requestBody = messageBuilder.createAnonymousDialogInitMessage(bank, product, dialogData) val message = messageBuilder.createAnonymousDialogInitMessage(dialogContext)
val response = getAndHandleResponseForMessage(requestBody, bank) val response = getAndHandleResponseForMessage(message, dialogContext)
if (response.successful) { if (response.successful) {
updateBankData(bank, response) updateBankData(bank, response)
closeAnonymousDialog(dialogData, response, bank) closeAnonymousDialog(dialogContext, response)
} }
return FinTsClientResponse(response) return FinTsClientResponse(response)
} }
protected open fun closeAnonymousDialog(dialogData: DialogData, response: Response, bank: BankData) { protected open fun closeAnonymousDialog(dialogContext: DialogContext, response: Response) {
dialogData.increaseMessageNumber() dialogContext.increaseMessageNumber() // TODO: move to MessageBuilder
response.messageHeader?.let { header -> dialogData.dialogId = header.dialogId } response.messageHeader?.let { header -> dialogContext.dialogId = header.dialogId } // TODO: senseful here? // TODO: move to MessageBuilder
val dialogEndRequestBody = messageBuilder.createAnonymousDialogEndMessage(bank, dialogData) val dialogEndRequestBody = messageBuilder.createAnonymousDialogEndMessage(dialogContext)
getAndHandleResponseForMessage(dialogEndRequestBody, bank) getAndHandleResponseForMessage(dialogEndRequestBody, dialogContext)
} }
open fun getBankAndCustomerInfoForNewUser(bank: BankData, customer: CustomerData): AddAccountResponse { open fun getBankAndCustomerInfoForNewUser(bank: BankData, customer: CustomerData): AddAccountResponse {
val dialogData = DialogData()
// just to ensure settings are in its initial state and that bank sends use bank parameter (BPD), // just to ensure settings are in its initial state and that bank sends use bank parameter (BPD),
// user parameter (UPD) and allowed tan procedures for user (therefore the resetSelectedTanProcedure()) // user parameter (UPD) and allowed tan procedures for user (therefore the resetSelectedTanProcedure())
bank.resetBpdVersion() bank.resetBpdVersion()
@ -117,24 +114,15 @@ open class FinTsClient @JvmOverloads constructor(
*/ */
customer.resetSelectedTanProcedure() customer.resetSelectedTanProcedure()
val initDialogResponse = initDialogWithoutChecks(bank, customer, dialogData, false) val dialogContext = DialogContext(bank, customer, product)
closeDialog(bank, customer, dialogData) val initDialogResponse = initDialogAfterSuccessfulChecks(dialogContext, false)
closeDialog(dialogContext) // TODO: only close dialog if a) bank didn't close it already and b) if a global flag is set to close dialog as actually it's not necessary
return AddAccountResponse(initDialogResponse, bank, customer) return AddAccountResponse(initDialogResponse, bank, customer)
} }
protected open fun synchronizeCustomerSystemIdIfNotDoneYet(bank: BankData,
customer: CustomerData): FinTsClientResponse {
if (customer.customerSystemId == KundensystemID.Anonymous) { // customer system id not synchronized yet
return synchronizeCustomerSystemId(bank, customer)
}
return FinTsClientResponse(true, true, false)
}
/** /**
* According to specification synchronizing customer system id is required: * According to specification synchronizing customer system id is required:
* "Die Kundensystem-ID ist beim HBCI RAH- / RDH- sowie dem PIN/TAN-Verfahren erforderlich." * "Die Kundensystem-ID ist beim HBCI RAH- / RDH- sowie dem PIN/TAN-Verfahren erforderlich."
@ -148,18 +136,18 @@ open class FinTsClient @JvmOverloads constructor(
*/ */
protected open fun synchronizeCustomerSystemId(bank: BankData, customer: CustomerData): FinTsClientResponse { protected open fun synchronizeCustomerSystemId(bank: BankData, customer: CustomerData): FinTsClientResponse {
val dialogData = DialogData() val dialogContext = DialogContext(bank, customer, product)
val requestBody = messageBuilder.createSynchronizeCustomerSystemIdMessage(bank, customer, product, dialogData) val message = messageBuilder.createSynchronizeCustomerSystemIdMessage(dialogContext)
val response = getAndHandleResponseForMessage(requestBody, bank) val response = getAndHandleResponseForMessage(message, dialogContext) // TODO: HKSYN also contains HKTAN -> get..ThatMayRequiresTan()
if (response.successful) { if (response.successful) {
updateBankData(bank, response) updateBankData(bank, response)
updateCustomerData(customer, bank, response) updateCustomerData(customer, bank, response)
response.messageHeader?.let { header -> dialogData.dialogId = header.dialogId } response.messageHeader?.let { header -> dialogContext.dialogId = header.dialogId }
closeDialog(bank, customer, dialogData) closeDialog(dialogContext)
} }
return FinTsClientResponse(response) return FinTsClientResponse(response)
@ -176,6 +164,8 @@ open class FinTsClient @JvmOverloads constructor(
open fun addAccount(bank: BankData, customer: CustomerData): AddAccountResponse { open fun addAccount(bank: BankData, customer: CustomerData): AddAccountResponse {
/* First dialog: Get user's basic data like her TAN procedures */
val newUserInfoResponse = getBankAndCustomerInfoForNewUser(bank, customer) val newUserInfoResponse = getBankAndCustomerInfoForNewUser(bank, customer)
if (newUserInfoResponse.isSuccessful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong if (newUserInfoResponse.isSuccessful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong
@ -188,14 +178,22 @@ open class FinTsClient @JvmOverloads constructor(
if (customer.isTanProcedureSelected == false && customer.supportedTanProcedures.isNotEmpty()) { if (customer.isTanProcedureSelected == false && customer.supportedTanProcedures.isNotEmpty()) {
didOverwriteUserUnselectedTanProcedure = true didOverwriteUserUnselectedTanProcedure = true
customer.selectedTanProcedure = customer.supportedTanProcedures.first() customer.selectedTanProcedure = customer.supportedTanProcedures.first() // TODO: check if user has only one TAN procedure -> set it and we're done
} }
/* Second dialog: Get customer system ID */ // TODO: needed?
val synchronizeCustomerResponse = synchronizeCustomerSystemId(bank, customer) val synchronizeCustomerResponse = synchronizeCustomerSystemId(bank, customer)
/* Third dialog: Get customer TAN media list */
getTanMediaList(bank, customer, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien) getTanMediaList(bank, customer, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien)
/* Fourth dialog: Try to retrieve account transactions of last 90 days without TAN */
// also check if retrieving account transactions of last 90 days without tan is supported (and thereby may retrieve first account transactions) // also check if retrieving account transactions of last 90 days without tan is supported (and thereby may retrieve first account transactions)
val transactionsOfLast90DaysResponses = mutableListOf<GetTransactionsResponse>() val transactionsOfLast90DaysResponses = mutableListOf<GetTransactionsResponse>()
val balances = mutableMapOf<AccountData, BigDecimal>() val balances = mutableMapOf<AccountData, BigDecimal>()
@ -257,9 +255,9 @@ open class FinTsClient @JvmOverloads constructor(
open fun getTransactions(parameter: GetTransactionsParameter, bank: BankData, open fun getTransactions(parameter: GetTransactionsParameter, bank: BankData,
customer: CustomerData, account: AccountData): GetTransactionsResponse { customer: CustomerData, account: AccountData): GetTransactionsResponse {
val dialogData = DialogData() val dialogContext = DialogContext(bank, customer, product)
val initDialogResponse = initDialog(bank, customer, dialogData) val initDialogResponse = initDialog(dialogContext)
if (initDialogResponse.successful == false) { if (initDialogResponse.successful == false) {
return GetTransactionsResponse(initDialogResponse) return GetTransactionsResponse(initDialogResponse)
@ -269,10 +267,10 @@ open class FinTsClient @JvmOverloads constructor(
var balance: BigDecimal? = null var balance: BigDecimal? = null
if (parameter.alsoRetrieveBalance && account.supportsRetrievingBalance) { if (parameter.alsoRetrieveBalance && account.supportsRetrievingBalance) {
val balanceResponse = getBalanceAfterDialogInit(bank, customer, account, dialogData) val balanceResponse = getBalanceAfterDialogInit(account, dialogContext)
if (balanceResponse.successful == false && balanceResponse.couldCreateMessage == true) { // don't break here if required HKSAL message is not implemented if (balanceResponse.successful == false && balanceResponse.couldCreateMessage == true) { // don't break here if required HKSAL message is not implemented
closeDialog(bank, customer, dialogData) closeDialog(dialogContext)
return GetTransactionsResponse(balanceResponse) return GetTransactionsResponse(balanceResponse)
} }
@ -281,16 +279,16 @@ open class FinTsClient @JvmOverloads constructor(
} }
if (balanceResponse.didReceiveResponse) { if (balanceResponse.didReceiveResponse) {
dialogData.increaseMessageNumber() dialogContext.increaseMessageNumber() // TODO: move to MessageBuilder
} }
} }
val message = messageBuilder.createGetTransactionsMessage(parameter, bank, customer, account, product, dialogData) val message = messageBuilder.createGetTransactionsMessage(parameter, account, dialogContext)
val response = getAndHandleResponseForMessageThatMayRequiresTan(message, bank, customer, dialogData) val response = getAndHandleResponseForMessageThatMayRequiresTan(message, dialogContext)
closeDialog(bank, customer, dialogData) closeDialog(dialogContext)
response.getFirstSegmentById<ReceivedAccountTransactions>(InstituteSegmentId.AccountTransactionsMt940)?.let { transactions -> response.getFirstSegmentById<ReceivedAccountTransactions>(InstituteSegmentId.AccountTransactionsMt940)?.let { transactions ->
@ -339,14 +337,13 @@ open class FinTsClient @JvmOverloads constructor(
} }
} }
protected open fun getBalanceAfterDialogInit(bank: BankData, customer: CustomerData, account: AccountData, protected open fun getBalanceAfterDialogInit(account: AccountData, dialogContext: DialogContext): Response {
dialogData: DialogData): Response {
dialogData.increaseMessageNumber() dialogContext.increaseMessageNumber() // TODO: move to MessageBuilder
val balanceRequest = messageBuilder.createGetBalanceMessage(bank, customer, account, product, dialogData) val message = messageBuilder.createGetBalanceMessage(account, dialogContext)
return getAndHandleResponseForMessage(balanceRequest, bank) return getAndHandleResponseForMessage(message, dialogContext)
} }
@ -363,8 +360,8 @@ open class FinTsClient @JvmOverloads constructor(
open fun getTanMediaList(bank: BankData, customer: CustomerData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, open fun getTanMediaList(bank: BankData, customer: CustomerData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle,
tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien): GetTanMediaListResponse { tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien): GetTanMediaListResponse {
val response = sendMessageAndHandleResponse(bank, customer) { dialogData -> val response = sendMessageAndHandleResponse(bank, customer) { dialogContext ->
messageBuilder.createGetTanMediaListMessage(bank, customer, dialogData, tanMediaKind, tanMediumClass) messageBuilder.createGetTanMediaListMessage(dialogContext, tanMediaKind, tanMediumClass)
} }
val tanMediaList = if (response.successful == false ) null val tanMediaList = if (response.successful == false ) null
@ -392,8 +389,8 @@ open class FinTsClient @JvmOverloads constructor(
} }
val response = sendMessageAndHandleResponse(bank, customer, false) { dialogData -> val response = sendMessageAndHandleResponse(bank, customer, false) { dialogContext ->
messageBuilder.createChangeTanMediumMessage(newActiveTanMedium, bank, customer, dialogData, messageBuilder.createChangeTanMediumMessage(newActiveTanMedium, dialogContext,
enteredAtc?.tan, enteredAtc?.atc) enteredAtc?.tan, enteredAtc?.atc)
} }
@ -413,8 +410,8 @@ open class FinTsClient @JvmOverloads constructor(
open fun doBankTransfer(bankTransferData: BankTransferData, bank: BankData, open fun doBankTransfer(bankTransferData: BankTransferData, bank: BankData,
customer: CustomerData, account: AccountData): FinTsClientResponse { customer: CustomerData, account: AccountData): FinTsClientResponse {
val response = sendMessageAndHandleResponse(bank, customer) { dialogData -> val response = sendMessageAndHandleResponse(bank, customer) { dialogContext ->
messageBuilder.createBankTransferMessage(bankTransferData, bank, customer, account, dialogData) messageBuilder.createBankTransferMessage(bankTransferData, account, dialogContext)
} }
return FinTsClientResponse(response) return FinTsClientResponse(response)
@ -422,70 +419,72 @@ open class FinTsClient @JvmOverloads constructor(
protected open fun sendMessageAndHandleResponse(bank: BankData, customer: CustomerData, messageMayRequiresTan: Boolean = true, protected open fun sendMessageAndHandleResponse(bank: BankData, customer: CustomerData, messageMayRequiresTan: Boolean = true,
createMessage: (DialogData) -> MessageBuilderResult): Response { createMessage: (DialogContext) -> MessageBuilderResult): Response {
val dialogData = DialogData()
val initDialogResponse = initDialog(bank, customer, dialogData) val dialogContext = DialogContext(bank, customer, product)
val initDialogResponse = initDialog(dialogContext)
if (initDialogResponse.successful == false) { if (initDialogResponse.successful == false) {
return initDialogResponse return initDialogResponse
} }
dialogData.increaseMessageNumber() dialogContext.increaseMessageNumber() // TODO: move to MessageBuilder
val message = createMessage(dialogData) val message = createMessage(dialogContext)
val response = if (messageMayRequiresTan) getAndHandleResponseForMessageThatMayRequiresTan(message, bank, customer, dialogData) val response = if (messageMayRequiresTan) getAndHandleResponseForMessageThatMayRequiresTan(message, dialogContext)
else getAndHandleResponseForMessage(message, bank) else getAndHandleResponseForMessage(message, dialogContext)
closeDialog(bank, customer, dialogData) closeDialog(dialogContext)
return response return response
} }
protected open fun initDialog(bank: BankData, customer: CustomerData, dialogData: DialogData): Response { protected open fun initDialog(dialogContext: DialogContext): Response {
// we first need to retrieve supported tan procedures and jobs before we can do anything // we first need to retrieve supported tan procedures and jobs before we can do anything
val retrieveBasicBankDataResponse = ensureBasicBankDataRetrieved(bank, customer) val retrieveBasicBankDataResponse = ensureBasicBankDataRetrieved(dialogContext.bank, dialogContext.customer)
if (retrieveBasicBankDataResponse.successful == false) { if (retrieveBasicBankDataResponse.successful == false) {
return retrieveBasicBankDataResponse return retrieveBasicBankDataResponse
} }
// as in the next step we have to supply user's tan procedure, ensure user selected his or her // as in the next step we have to supply user's tan procedure, ensure user selected his or her
val tanProcedureSelectedResponse = ensureTanProcedureIsSelected(bank, customer) val tanProcedureSelectedResponse = ensureTanProcedureIsSelected(dialogContext.bank, dialogContext.customer)
if (tanProcedureSelectedResponse.successful == false) { if (tanProcedureSelectedResponse.successful == false) {
return tanProcedureSelectedResponse return tanProcedureSelectedResponse
} }
return initDialogWithoutChecks(bank, customer, dialogData, true) return initDialogAfterSuccessfulChecks(dialogContext, true)
} }
protected open fun initDialogWithoutChecks(bank: BankData, customer: CustomerData, dialogData: DialogData, protected open fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext,
useStrongAuthentication: Boolean = true): Response { useStrongAuthentication: Boolean = true): Response {
val requestBody = messageBuilder.createInitDialogMessage(bank, customer, product, dialogData, useStrongAuthentication) val message = messageBuilder.createInitDialogMessage(dialogContext, useStrongAuthentication)
val response = GetUserTanProceduresResponse(getAndHandleResponseForMessage(requestBody, bank)) val response = GetUserTanProceduresResponse(getAndHandleResponseForMessageThatMayRequiresTan(message, dialogContext))
dialogContext.response = response
response.messageHeader?.let { header -> dialogContext.dialogId = header.dialogId }
if (response.successful) { if (response.successful) {
updateBankData(bank, response) updateBankData(dialogContext.bank, response)
updateCustomerData(customer, bank, response) updateCustomerData(dialogContext.customer, dialogContext.bank, response)
response.messageHeader?.let { header -> dialogData.dialogId = header.dialogId }
} }
return response return response
} }
protected open fun closeDialog(bank: BankData, customer: CustomerData, dialogData: DialogData) { protected open fun closeDialog(dialogContext: DialogContext) {
dialogData.increaseMessageNumber() dialogContext.increaseMessageNumber() // TODO: move to MessageBuilder
val dialogEndRequestBody = messageBuilder.createDialogEndMessage(bank, customer, dialogData) val dialogEndRequestBody = messageBuilder.createDialogEndMessage(dialogContext)
getAndHandleResponseForMessage(dialogEndRequestBody, bank) getAndHandleResponseForMessage(dialogEndRequestBody, dialogContext)
} }
@ -529,16 +528,15 @@ open class FinTsClient @JvmOverloads constructor(
} }
protected open fun getAndHandleResponseForMessageThatMayRequiresTan(message: MessageBuilderResult, bank: BankData, protected open fun getAndHandleResponseForMessageThatMayRequiresTan(message: MessageBuilderResult, dialogContext: DialogContext): Response {
customer: CustomerData, dialogData: DialogData): Response { val response = getAndHandleResponseForMessage(message, dialogContext)
val response = getAndHandleResponseForMessage(message, bank)
val handledResponse = handleMayRequiredTan(response, bank, customer, dialogData) val handledResponse = handleMayRequiredTan(response, dialogContext)
// if there's a Aufsetzpunkt (continuationId) set, then response is not complete yet, there's more information to fetch by sending this Aufsetzpunkt // if there's a Aufsetzpunkt (continuationId) set, then response is not complete yet, there's more information to fetch by sending this Aufsetzpunkt
handledResponse.aufsetzpunkt?.let { continuationId -> handledResponse.aufsetzpunkt?.let { continuationId ->
if (handledResponse.followUpResponse == null) { // for re-sent messages followUpResponse is already set and dialog already closed -> would be overwritten with an error response that dialog is closed if (handledResponse.followUpResponse == null) { // for re-sent messages followUpResponse is already set and dialog already closed -> would be overwritten with an error response that dialog is closed
handledResponse.followUpResponse = getFollowUpMessageForContinuationId(handledResponse, continuationId, message, bank, customer, dialogData) handledResponse.followUpResponse = getFollowUpMessageForContinuationId(handledResponse, continuationId, message, dialogContext)
handledResponse.hasFollowUpMessageButCouldNotReceiveIt = handledResponse.followUpResponse == null handledResponse.hasFollowUpMessageButCouldNotReceiveIt = handledResponse.followUpResponse == null
} }
@ -548,47 +546,50 @@ open class FinTsClient @JvmOverloads constructor(
} }
protected open fun getFollowUpMessageForContinuationId(response: Response, continuationId: String, message: MessageBuilderResult, protected open fun getFollowUpMessageForContinuationId(response: Response, continuationId: String, message: MessageBuilderResult,
bank: BankData, customer: CustomerData, dialogData: DialogData): Response? { dialogContext: DialogContext): Response? {
messageBuilder.rebuildMessageWithContinuationId(message, continuationId, bank, customer, dialogData)?.let { followUpMessage -> messageBuilder.rebuildMessageWithContinuationId(message, continuationId, dialogContext)?.let { followUpMessage ->
return getAndHandleResponseForMessageThatMayRequiresTan(followUpMessage, bank, customer, dialogData) return getAndHandleResponseForMessageThatMayRequiresTan(followUpMessage, dialogContext)
} }
return null return null
} }
protected open fun getAndHandleResponseForMessageThatMayRequiresTan(message: String, bank: BankData, protected open fun getAndHandleResponseForMessageThatMayRequiresTan(message: String, dialogContext: DialogContext): Response {
customer: CustomerData, dialogData: DialogData): Response { val response = getAndHandleResponseForMessage(message, dialogContext)
val response = getAndHandleResponseForMessage(message, bank)
return handleMayRequiredTan(response, bank, customer, dialogData) return handleMayRequiredTan(response, dialogContext)
} }
protected open fun getAndHandleResponseForMessage(message: MessageBuilderResult, bank: BankData): Response { protected open fun getAndHandleResponseForMessage(message: MessageBuilderResult, dialogContext: DialogContext): Response {
message.createdMessage?.let { requestBody -> message.createdMessage?.let { requestBody ->
return getAndHandleResponseForMessage(requestBody, bank) return getAndHandleResponseForMessage(requestBody, dialogContext)
} }
return Response(false, messageCreationError = message) return Response(false, messageCreationError = message)
} }
protected open fun getAndHandleResponseForMessage(requestBody: String, bank: BankData): Response { protected open fun getAndHandleResponseForMessage(requestBody: String, dialogContext: DialogContext): Response {
val webResponse = getResponseForMessage(requestBody, bank) val webResponse = getResponseForMessage(requestBody, dialogContext.bank.finTs3ServerAddress)
return handleResponse(webResponse, bank) val response = handleResponse(webResponse, dialogContext)
dialogContext.response = response
return response
} }
protected open fun getResponseForMessage(requestBody: String, bank: BankData): WebClientResponse { protected open fun getResponseForMessage(requestBody: String, finTs3ServerAddress: String): WebClientResponse {
log.debug("Sending message:\n${prettyPrintHbciMessage(requestBody)}") log.debug("Sending message:\n${prettyPrintHbciMessage(requestBody)}")
val encodedRequestBody = base64Service.encode(requestBody) val encodedRequestBody = base64Service.encode(requestBody)
return webClient.post( return webClient.post(
RequestParameters(bank.finTs3ServerAddress, encodedRequestBody, "application/octet-stream") RequestParameters(finTs3ServerAddress, encodedRequestBody, "application/octet-stream")
) )
} }
protected open fun handleResponse(webResponse: WebClientResponse, bank: BankData): Response { protected open fun handleResponse(webResponse: WebClientResponse, dialogContext: DialogContext): Response {
val responseBody = webResponse.body val responseBody = webResponse.body
if (webResponse.isSuccessful && responseBody != null) { if (webResponse.isSuccessful && responseBody != null) {
@ -606,6 +607,7 @@ open class FinTsClient @JvmOverloads constructor(
} }
} }
else { else {
val bank = dialogContext.bank
log.error("Request to $bank (${bank.finTs3ServerAddress}) failed", webResponse.error) log.error("Request to $bank (${bank.finTs3ServerAddress}) failed", webResponse.error)
} }
@ -620,18 +622,20 @@ open class FinTsClient @JvmOverloads constructor(
return message.replace("'", "'\r\n") return message.replace("'", "'\r\n")
} }
protected open fun handleMayRequiredTan(response: Response, bank: BankData, customer: CustomerData, dialogData: DialogData): Response { protected open fun handleMayRequiredTan(response: Response, dialogContext: DialogContext): Response { // TODO: use response from DialogContext
if (response.isStrongAuthenticationRequired) { if (response.isStrongAuthenticationRequired) {
response.tanResponse?.let { tanResponse -> response.tanResponse?.let { tanResponse ->
val customer = dialogContext.customer
val enteredTanResult = callback.enterTan(customer, createTanChallenge(tanResponse, customer)) val enteredTanResult = callback.enterTan(customer, createTanChallenge(tanResponse, customer))
if (enteredTanResult.changeTanProcedureTo != null) { if (enteredTanResult.changeTanProcedureTo != null) {
return handleUserAsksToChangeTanProcedureAndResendLastMessage(enteredTanResult.changeTanProcedureTo, return handleUserAsksToChangeTanProcedureAndResendLastMessage(enteredTanResult.changeTanProcedureTo,
bank, customer, dialogData) dialogContext)
} }
else if (enteredTanResult.changeTanMediumTo is TanGeneratorTanMedium) { else if (enteredTanResult.changeTanMediumTo is TanGeneratorTanMedium) {
return handleUserAsksToChangeTanMediumAndResendLastMessage(enteredTanResult.changeTanMediumTo, return handleUserAsksToChangeTanMediumAndResendLastMessage(enteredTanResult.changeTanMediumTo,
bank, customer, dialogData, enteredTanResult.changeTanMediumResultCallback) dialogContext, enteredTanResult.changeTanMediumResultCallback)
} }
else if (enteredTanResult.enteredTan == null) { else if (enteredTanResult.enteredTan == null) {
// i tried to send a HKTAN with cancelJob = true but then i saw there are no tan procedures that support cancellation (at least not at my bank) // i tried to send a HKTAN with cancelJob = true but then i saw there are no tan procedures that support cancellation (at least not at my bank)
@ -639,7 +643,7 @@ open class FinTsClient @JvmOverloads constructor(
response.tanRequiredButUserDidNotEnterOne = true response.tanRequiredButUserDidNotEnterOne = true
} }
else { else {
return sendTanToBank(enteredTanResult.enteredTan, tanResponse, bank, customer, dialogData) return sendTanToBank(enteredTanResult.enteredTan, tanResponse, dialogContext)
} }
} }
} }
@ -672,44 +676,39 @@ open class FinTsClient @JvmOverloads constructor(
} }
} }
protected open fun sendTanToBank(enteredTan: String, tanResponse: TanResponse, bank: BankData, protected open fun sendTanToBank(enteredTan: String, tanResponse: TanResponse, dialogContext: DialogContext): Response {
customer: CustomerData, dialogData: DialogData): Response {
dialogData.increaseMessageNumber()
val message = messageBuilder.createSendEnteredTanMessage(enteredTan, tanResponse, bank, customer, dialogData) dialogContext.increaseMessageNumber() // TODO: move to MessageBuilder
return getAndHandleResponseForMessageThatMayRequiresTan(message, bank, customer, dialogData) val message = messageBuilder.createSendEnteredTanMessage(enteredTan, tanResponse, dialogContext)
// TODO: shouldn't we use MessageBuilderResult here as well?
return getAndHandleResponseForMessageThatMayRequiresTan(message, dialogContext)
} }
protected open fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, bank: BankData, protected open fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, dialogContext: DialogContext): Response {
customer: CustomerData, dialogData: DialogData): Response {
val lastCreatedMessage = messageBuilder.lastCreatedMessage dialogContext.customer.selectedTanProcedure = changeTanProcedureTo
customer.selectedTanProcedure = changeTanProcedureTo
lastCreatedMessage?.let { val lastCreatedMessage = dialogContext.currentMessage
closeDialog(bank, customer, dialogData)
return resendMessageInNewDialog(lastCreatedMessage, bank, customer) lastCreatedMessage?.let { closeDialog(dialogContext) }
return resendMessageInNewDialog(lastCreatedMessage, dialogContext)
} }
val errorMessage = "There's no last action (like retrieve account transactions, transfer money, ...) to re-send with new TAN procedure. Probably an internal programming error." // TODO: translate protected open fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium,
return Response(false, exception = Exception(errorMessage)) // should never come to this dialogContext: DialogContext,
}
protected open fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium, bank: BankData,
customer: CustomerData, dialogData: DialogData,
changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): Response { changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): Response {
val lastCreatedMessage = messageBuilder.lastCreatedMessage val lastCreatedMessage = dialogContext.currentMessage
lastCreatedMessage?.let { closeDialog(bank, customer, dialogData) } lastCreatedMessage?.let { closeDialog(dialogContext) }
val changeTanMediumResponse = changeTanMedium(changeTanMediumTo, bank, customer) val changeTanMediumResponse = changeTanMedium(changeTanMediumTo, dialogContext.bank, dialogContext.customer)
changeTanMediumResultCallback?.invoke(changeTanMediumResponse) changeTanMediumResultCallback?.invoke(changeTanMediumResponse)
@ -718,30 +717,34 @@ open class FinTsClient @JvmOverloads constructor(
} }
return resendMessageInNewDialog(lastCreatedMessage, bank, customer) return resendMessageInNewDialog(lastCreatedMessage, dialogContext)
} }
protected open fun resendMessageInNewDialog(message: MessageBuilderResult, bank: BankData, protected open fun resendMessageInNewDialog(lastCreatedMessage: MessageBuilderResult?, previousDialogContext: DialogContext): Response {
customer: CustomerData): Response {
val dialogData = DialogData() lastCreatedMessage?.let { // do not use previousDialogContext.currentMessage as this may is previous dialog's dialog close message
val newDialogContext = DialogContext(previousDialogContext.bank, previousDialogContext.customer, previousDialogContext.product)
val initDialogResponse = initDialog(bank, customer, dialogData) val initDialogResponse = initDialog(newDialogContext)
if (initDialogResponse.successful == false) { if (initDialogResponse.successful == false) {
return initDialogResponse return initDialogResponse
} }
val newMessage = messageBuilder.rebuildMessage(message, bank, customer, dialogData) val newMessage = messageBuilder.rebuildMessage(lastCreatedMessage, newDialogContext)
val response = getAndHandleResponseForMessageThatMayRequiresTan(newMessage, bank, customer, dialogData) val response = getAndHandleResponseForMessageThatMayRequiresTan(newMessage, newDialogContext)
closeDialog(bank, customer, dialogData) closeDialog(newDialogContext)
return response return response
} }
val errorMessage = "There's no last action (like retrieve account transactions, transfer money, ...) to re-send with new TAN procedure. Probably an internal programming error." // TODO: translate
return Response(false, exception = Exception(errorMessage)) // should never come to this
}
protected open fun updateBankData(bank: BankData, response: Response) { protected open fun updateBankData(bank: BankData, response: Response) {
response.getFirstSegmentById<BankParameters>(InstituteSegmentId.BankParameters)?.let { bankParameters -> response.getFirstSegmentById<BankParameters>(InstituteSegmentId.BankParameters)?.let { bankParameters ->

View File

@ -39,10 +39,6 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
} }
var lastCreatedMessage: MessageBuilderResult? = null
protected set
/** /**
* Um Kunden die Möglichkeit zu geben, sich anonym anzumelden, um sich bspw. über die * Um Kunden die Möglichkeit zu geben, sich anonym anzumelden, um sich bspw. über die
* angebotenen Geschäftsvorfälle fremder Kreditinstitute (von denen sie keine BPD besitzen) * angebotenen Geschäftsvorfälle fremder Kreditinstitute (von denen sie keine BPD besitzen)
@ -51,66 +47,61 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
* *
* Bei anonymen Dialogen werden Nachrichten weder signiert, noch können sie verschlüsselt und komprimiert werden. * Bei anonymen Dialogen werden Nachrichten weder signiert, noch können sie verschlüsselt und komprimiert werden.
*/ */
open fun createAnonymousDialogInitMessage(bank: BankData, product: ProductData, dialogData: DialogData): String { open fun createAnonymousDialogInitMessage(dialogContext: DialogContext): MessageBuilderResult {
val customer = CustomerData.Anonymous return createUnsignedMessageBuilderResult(dialogContext, listOf(
IdentifikationsSegment(generator.resetSegmentNumber(1), dialogContext),
return createMessage(bank, customer, dialogData, listOf( Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), dialogContext)
IdentifikationsSegment(generator.resetSegmentNumber(1), bank, customer),
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), bank, customer, product)
)) ))
} }
open fun createAnonymousDialogEndMessage(bank: BankData, dialogData: DialogData): String { open fun createAnonymousDialogEndMessage(dialogContext: DialogContext): String {
val customer = CustomerData.Anonymous return createMessage(dialogContext, listOf(
Dialogende(generator.resetSegmentNumber(1), dialogContext)
return createMessage(bank, customer, dialogData, listOf(
Dialogende(generator.resetSegmentNumber(1), dialogData)
)) ))
} }
open fun createInitDialogMessage(bank: BankData, customer: CustomerData, product: ProductData, open fun createInitDialogMessage(dialogContext: DialogContext, useStrongAuthentication: Boolean = true): MessageBuilderResult {
dialogData: DialogData, useStrongAuthentication: Boolean = true): String {
val segments = mutableListOf( val segments = mutableListOf(
IdentifikationsSegment(generator.resetSegmentNumber(2), bank, customer), IdentifikationsSegment(generator.resetSegmentNumber(2), dialogContext),
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), bank, customer, product) Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), dialogContext)
) )
if (useStrongAuthentication) { if (useStrongAuthentication) {
segments.add(ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Identification)) segments.add(ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Identification))
} }
return createSignedMessage(bank, customer, dialogData, segments) return createMessageBuilderResult(dialogContext, segments)
} }
open fun createSynchronizeCustomerSystemIdMessage(bank: BankData, customer: CustomerData, product: ProductData, dialogData: DialogData): String { open fun createSynchronizeCustomerSystemIdMessage(dialogContext: DialogContext): MessageBuilderResult {
return createSignedMessage(bank, customer, dialogData, listOf( return createMessageBuilderResult(dialogContext, listOf(
IdentifikationsSegment(generator.resetSegmentNumber(2), bank, customer), IdentifikationsSegment(generator.resetSegmentNumber(2), dialogContext),
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), bank, customer, product), Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), dialogContext),
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Identification), ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Identification),
Synchronisierung(generator.getNextSegmentNumber(), Synchronisierungsmodus.NeueKundensystemIdZurueckmelden) Synchronisierung(generator.getNextSegmentNumber(), Synchronisierungsmodus.NeueKundensystemIdZurueckmelden)
)) ))
} }
open fun createDialogEndMessage(bank: BankData, customer: CustomerData, dialogData: DialogData): String { open fun createDialogEndMessage(dialogContext: DialogContext): String {
return createSignedMessage(bank, customer, dialogData, listOf( return createSignedMessage(dialogContext, listOf(
Dialogende(generator.resetSegmentNumber(2), dialogData) Dialogende(generator.resetSegmentNumber(2), dialogContext)
)) ))
} }
open fun createGetTransactionsMessage(parameter: GetTransactionsParameter, bank: BankData, customer: CustomerData, open fun createGetTransactionsMessage(parameter: GetTransactionsParameter, account: AccountData,
account: AccountData, product: ProductData, dialogData: DialogData): MessageBuilderResult { dialogContext: DialogContext): MessageBuilderResult {
val result = supportsGetTransactionsMt940(account) val result = supportsGetTransactionsMt940(account)
if (result.isJobVersionSupported) { if (result.isJobVersionSupported) {
val transactionsJob = if (result.isAllowed(7)) KontoumsaetzeZeitraumMt940Version7(generator.resetSegmentNumber(2), parameter, bank, account) val transactionsJob = if (result.isAllowed(7)) KontoumsaetzeZeitraumMt940Version7(generator.resetSegmentNumber(2), parameter, dialogContext.bank, account)
else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(generator.resetSegmentNumber(2), parameter, account) else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(generator.resetSegmentNumber(2), parameter, account)
else KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter, account) else KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter, account)
@ -119,7 +110,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.AccountTransactionsMt940) ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.AccountTransactionsMt940)
) )
return createMessageBuilderResult(bank, customer, dialogData, segments) return createMessageBuilderResult(dialogContext, segments)
} }
return result return result
@ -134,20 +125,20 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
} }
open fun createGetBalanceMessage(bank: BankData, customer: CustomerData, account: AccountData, product: ProductData, dialogData: DialogData): MessageBuilderResult { open fun createGetBalanceMessage(account: AccountData, dialogContext: DialogContext): MessageBuilderResult {
val result = supportsGetBalanceMessage(account) val result = supportsGetBalanceMessage(account)
if (result.isJobVersionSupported) { if (result.isJobVersionSupported) {
val balanceJob = if (result.isAllowed(5)) SaldenabfrageVersion5(generator.resetSegmentNumber(2), account) val balanceJob = if (result.isAllowed(5)) SaldenabfrageVersion5(generator.resetSegmentNumber(2), account)
else SaldenabfrageVersion7(generator.resetSegmentNumber(2), account, bank) else SaldenabfrageVersion7(generator.resetSegmentNumber(2), account, dialogContext.bank)
val segments = listOf( val segments = listOf(
balanceJob, balanceJob,
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Balance) ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Balance)
) )
return createMessageBuilderResult(bank, customer, dialogData, segments) return createMessageBuilderResult(dialogContext, segments)
} }
return result return result
@ -162,11 +153,11 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
} }
open fun createGetTanMediaListMessage(bank: BankData, customer: CustomerData, dialogData: DialogData, open fun createGetTanMediaListMessage(dialogContext: DialogContext,
tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle,
tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien): MessageBuilderResult { tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien): MessageBuilderResult {
val result = getSupportedVersionsOfJob(CustomerSegmentId.TanMediaList, customer, listOf(2, 3, 4, 5)) val result = getSupportedVersionsOfJob(CustomerSegmentId.TanMediaList, dialogContext.customer, listOf(2, 3, 4, 5))
if (result.isJobVersionSupported) { if (result.isJobVersionSupported) {
val segments = listOf( val segments = listOf(
@ -174,41 +165,41 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
generator.resetSegmentNumber(2), tanMediaKind, tanMediumClass) generator.resetSegmentNumber(2), tanMediaKind, tanMediumClass)
) )
return createMessageBuilderResult(bank, customer, dialogData, segments) return createMessageBuilderResult(dialogContext, segments)
} }
return result return result
} }
open fun createChangeTanMediumMessage(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData, open fun createChangeTanMediumMessage(newActiveTanMedium: TanGeneratorTanMedium, dialogContext: DialogContext,
dialogData: DialogData, tan: String? = null, atc: Int? = null): MessageBuilderResult { tan: String? = null, atc: Int? = null): MessageBuilderResult {
val result = getSupportedVersionsOfJob(CustomerSegmentId.ChangeTanMedium, customer, listOf(1, 2, 3)) val result = getSupportedVersionsOfJob(CustomerSegmentId.ChangeTanMedium, dialogContext.customer, listOf(1, 2, 3))
if (result.isJobVersionSupported) { if (result.isJobVersionSupported) {
val segments = listOf( val segments = listOf(
TanGeneratorTanMediumAnOderUmmelden(result.getHighestAllowedVersion!!, generator.resetSegmentNumber(2), TanGeneratorTanMediumAnOderUmmelden(result.getHighestAllowedVersion!!, generator.resetSegmentNumber(2),
bank, customer, newActiveTanMedium, tan, atc) dialogContext.bank, dialogContext.customer, newActiveTanMedium, tan, atc)
) )
return createMessageBuilderResult(bank, customer, dialogData, segments) return createMessageBuilderResult(dialogContext, segments)
} }
return result return result
} }
open fun createSendEnteredTanMessage(enteredTan: String, tanResponse: TanResponse, bank: BankData, customer: CustomerData, dialogData: DialogData): String { open fun createSendEnteredTanMessage(enteredTan: String, tanResponse: TanResponse, dialogContext: DialogContext): String {
val tanProcess = if (tanResponse.tanProcess == TanProcess.TanProcess1) TanProcess.TanProcess1 else TanProcess.TanProcess2 val tanProcess = if (tanResponse.tanProcess == TanProcess.TanProcess1) TanProcess.TanProcess1 else TanProcess.TanProcess2
return createSignedMessage(bank, customer, dialogData, enteredTan, listOf( return createSignedMessage(dialogContext, enteredTan, listOf(
ZweiSchrittTanEinreichung(generator.resetSegmentNumber(2), tanProcess, null, ZweiSchrittTanEinreichung(generator.resetSegmentNumber(2), tanProcess, null,
tanResponse.jobHashValue, tanResponse.jobReference, false, null, tanResponse.tanMediaIdentifier) tanResponse.jobHashValue, tanResponse.jobReference, false, null, tanResponse.tanMediaIdentifier)
)) ))
} }
open fun createBankTransferMessage(bankTransferData: BankTransferData, bank: BankData, customer: CustomerData, account: AccountData, dialogData: DialogData): MessageBuilderResult { open fun createBankTransferMessage(bankTransferData: BankTransferData, account: AccountData, dialogContext: DialogContext): MessageBuilderResult {
val messageBuilderResultAndNullableUrn = supportsBankTransferAndSepaVersion(account) val messageBuilderResultAndNullableUrn = supportsBankTransferAndSepaVersion(account)
val result = messageBuilderResultAndNullableUrn.first val result = messageBuilderResultAndNullableUrn.first
@ -216,11 +207,11 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
if (result.isJobVersionSupported && urn != null) { if (result.isJobVersionSupported && urn != null) {
val segments = listOf( val segments = listOf(
SepaEinzelueberweisung(generator.resetSegmentNumber(2), urn, customer, account, bank.bic, bankTransferData), SepaEinzelueberweisung(generator.resetSegmentNumber(2), urn, dialogContext.customer, account, dialogContext.bank.bic, bankTransferData),
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.SepaBankTransfer) ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.SepaBankTransfer)
) )
return createMessageBuilderResult(bank, customer, dialogData, segments) return createMessageBuilderResult(dialogContext, segments)
} }
return result return result
@ -250,8 +241,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
} }
open fun rebuildMessageWithContinuationId(message: MessageBuilderResult, continuationId: String, bank: BankData, open fun rebuildMessageWithContinuationId(message: MessageBuilderResult, continuationId: String, dialogContext: DialogContext): MessageBuilderResult? {
customer: CustomerData, dialogData: DialogData): MessageBuilderResult? {
// val copiedSegments = message.messageBodySegments.map { } // val copiedSegments = message.messageBodySegments.map { }
val aufsetzpunkte = message.messageBodySegments.flatMap { it.dataElementsAndGroups }.filterIsInstance<Aufsetzpunkt>() val aufsetzpunkte = message.messageBodySegments.flatMap { it.dataElementsAndGroups }.filterIsInstance<Aufsetzpunkt>()
@ -263,70 +253,78 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
aufsetzpunkte.forEach { it.resetContinuationId(continuationId) } aufsetzpunkte.forEach { it.resetContinuationId(continuationId) }
return rebuildMessage(message, bank, customer, dialogData) return rebuildMessage(message, dialogContext)
} }
open fun rebuildMessage(message: MessageBuilderResult, bank: BankData, customer: CustomerData, open fun rebuildMessage(message: MessageBuilderResult, dialogContext: DialogContext): MessageBuilderResult {
dialogData: DialogData): MessageBuilderResult {
dialogData.increaseMessageNumber() dialogContext.increaseMessageNumber()
return createMessageBuilderResult(bank, customer, dialogData, message.messageBodySegments) return createMessageBuilderResult(dialogContext, message.messageBodySegments)
} }
protected open fun createMessageBuilderResult(bank: BankData, customer: CustomerData, dialogData: DialogData, segments: List<Segment>): MessageBuilderResult { protected open fun createMessageBuilderResult(dialogContext: DialogContext, segments: List<Segment>): MessageBuilderResult {
val message = MessageBuilderResult(createSignedMessage(bank, customer, dialogData, segments), segments) val message = MessageBuilderResult(createSignedMessage(dialogContext, segments), segments)
lastCreatedMessage = message dialogContext.previousMessageInDialog = dialogContext.currentMessage
dialogContext.currentMessage = message
return message
}
protected open fun createUnsignedMessageBuilderResult(dialogContext: DialogContext, segments: List<Segment>): MessageBuilderResult {
val message = MessageBuilderResult(createMessage(dialogContext, segments), segments)
dialogContext.previousMessageInDialog = dialogContext.currentMessage
dialogContext.currentMessage = message
return message return message
} }
open fun createSignedMessage(bank: BankData, customer: CustomerData, dialogData: DialogData, open fun createSignedMessage(dialogContext: DialogContext, payloadSegments: List<Segment>): String {
payloadSegments: List<Segment>): String {
return createSignedMessage(bank, customer, dialogData, null, payloadSegments) return createSignedMessage(dialogContext, null, payloadSegments)
} }
open fun createSignedMessage(bank: BankData, customer: CustomerData, dialogData: DialogData, open fun createSignedMessage(dialogContext: DialogContext, tan: String? = null,
tan: String? = null, payloadSegments: List<Segment>): String { payloadSegments: List<Segment>): String {
val date = utils.formatDateTodayAsInt() val date = utils.formatDateTodayAsInt()
val time = utils.formatTimeNowAsInt() val time = utils.formatTimeNowAsInt()
val signedPayload = signPayload(2, bank, customer, date, time, tan, payloadSegments) val signedPayload = signPayload(2, dialogContext, date, time, tan, payloadSegments)
val encryptedPayload = encryptPayload(bank, customer, date, time, signedPayload) val encryptedPayload = encryptPayload(dialogContext, date, time, signedPayload)
return createMessage(bank, customer, dialogData, encryptedPayload) return createMessage(dialogContext, encryptedPayload)
} }
open fun createMessage(bank: BankData, customer: CustomerData, dialogData: DialogData, open fun createMessage(dialogContext: DialogContext, payloadSegments: List<Segment>): String {
payloadSegments: List<Segment>): String {
val formattedPayload = formatPayload(payloadSegments) val formattedPayload = formatPayload(payloadSegments)
val messageSize = formattedPayload.length + MessageHeaderLength + MessageEndingLength + AddedSeparatorsLength val messageSize = formattedPayload.length + MessageHeaderLength + MessageEndingLength + AddedSeparatorsLength
val header = Nachrichtenkopf(ISegmentNumberGenerator.FirstSegmentNumber, messageSize, dialogData) val header = Nachrichtenkopf(ISegmentNumberGenerator.FirstSegmentNumber, messageSize, dialogContext)
val ending = Nachrichtenabschluss(generator.getNextSegmentNumber(), dialogData) val ending = Nachrichtenabschluss(generator.getNextSegmentNumber(), dialogContext)
return listOf(header.format(), formattedPayload, ending.format()) return listOf(header.format(), formattedPayload, ending.format())
.joinToString(Separators.SegmentSeparator, postfix = Separators.SegmentSeparator) .joinToString(Separators.SegmentSeparator, postfix = Separators.SegmentSeparator)
} }
protected open fun signPayload(headerSegmentNumber: Int, bank: BankData, customer: CustomerData, date: Int, time: Int, protected open fun signPayload(headerSegmentNumber: Int, dialogContext: DialogContext, date: Int, time: Int,
tan: String? = null, payloadSegments: List<Segment>): List<Segment> { tan: String? = null, payloadSegments: List<Segment>): List<Segment> {
val controlReference = createControlReference() val controlReference = createControlReference()
val signatureHeader = PinTanSignaturkopf( val signatureHeader = PinTanSignaturkopf(
headerSegmentNumber, headerSegmentNumber,
bank, dialogContext,
customer,
controlReference, controlReference,
date, date,
time time
@ -335,7 +333,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
val signatureEnding = Signaturabschluss( val signatureEnding = Signaturabschluss(
generator.getNextSegmentNumber(), generator.getNextSegmentNumber(),
controlReference, controlReference,
customer.pin, dialogContext.customer.pin,
tan tan
) )
@ -347,10 +345,10 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
} }
private fun encryptPayload(bank: BankData, customer: CustomerData, date: Int, time: Int, private fun encryptPayload(dialogContext: DialogContext, date: Int, time: Int,
payload: List<Segment>): List<Segment> { payload: List<Segment>): List<Segment> {
val encryptionHeader = PinTanVerschluesselungskopf(bank, customer, date, time) val encryptionHeader = PinTanVerschluesselungskopf(dialogContext, date, time)
val encryptedData = VerschluesselteDaten(formatPayload(payload) + Separators.SegmentSeparator) val encryptedData = VerschluesselteDaten(formatPayload(payload) + Separators.SegmentSeparator)

View File

@ -4,14 +4,14 @@ import net.dankito.fints.messages.datenelemente.implementierte.DialogId
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
import net.dankito.fints.messages.segmente.Segment import net.dankito.fints.messages.segmente.Segment
import net.dankito.fints.messages.segmente.id.CustomerSegmentId import net.dankito.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.fints.model.DialogData import net.dankito.fints.model.DialogContext
class Dialogende( class Dialogende(
segmentNumber: Int, segmentNumber: Int,
dialogData: DialogData dialogContext: DialogContext
) : Segment(listOf( ) : Segment(listOf(
Segmentkopf(CustomerSegmentId.DialogEnd, 1, segmentNumber), Segmentkopf(CustomerSegmentId.DialogEnd, 1, segmentNumber),
DialogId(dialogData.dialogId) DialogId(dialogContext.dialogId)
)) ))

View File

@ -8,19 +8,17 @@ import net.dankito.fints.messages.datenelementgruppen.implementierte.Kreditinsti
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
import net.dankito.fints.messages.segmente.Segment import net.dankito.fints.messages.segmente.Segment
import net.dankito.fints.messages.segmente.id.CustomerSegmentId import net.dankito.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.fints.model.BankData import net.dankito.fints.model.MessageBaseData
import net.dankito.fints.model.CustomerData
open class IdentifikationsSegment( open class IdentifikationsSegment(
segmentNumber: Int, segmentNumber: Int,
bank: BankData, baseData: MessageBaseData
customer: CustomerData
) : Segment(listOf( ) : Segment(listOf(
Segmentkopf(CustomerSegmentId.Identification, 2, segmentNumber), Segmentkopf(CustomerSegmentId.Identification, 2, segmentNumber),
Kreditinstitutskennung(bank.countryCode, bank.bankCode), Kreditinstitutskennung(baseData.bank.countryCode, baseData.bank.bankCode),
KundenID(customer.customerId), KundenID(baseData.customer.customerId),
KundensystemID(customer.customerSystemId), KundensystemID(baseData.customer.customerSystemId),
KundensystemStatus(customer.customerSystemStatus, Existenzstatus.Mandatory) KundensystemStatus(baseData.customer.customerSystemStatus, Existenzstatus.Mandatory)
)) ))

View File

@ -4,7 +4,7 @@ import net.dankito.fints.messages.datenelemente.implementierte.Nachrichtennummer
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
import net.dankito.fints.messages.segmente.Segment import net.dankito.fints.messages.segmente.Segment
import net.dankito.fints.messages.segmente.id.MessageSegmentId import net.dankito.fints.messages.segmente.id.MessageSegmentId
import net.dankito.fints.model.DialogData import net.dankito.fints.model.DialogContext
/** /**
@ -12,9 +12,9 @@ import net.dankito.fints.model.DialogData
*/ */
open class Nachrichtenabschluss( open class Nachrichtenabschluss(
segmentNumber: Int, segmentNumber: Int,
dialogData: DialogData dialogContext: DialogContext
) : Segment(listOf( ) : Segment(listOf(
Segmentkopf(MessageSegmentId.MessageEnding, 1, segmentNumber), Segmentkopf(MessageSegmentId.MessageEnding, 1, segmentNumber),
Nachrichtennummer(dialogData.messageNumber) Nachrichtennummer(dialogContext.messageNumber)
)) ))

View File

@ -4,18 +4,18 @@ import net.dankito.fints.messages.datenelemente.implementierte.*
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
import net.dankito.fints.messages.segmente.Segment import net.dankito.fints.messages.segmente.Segment
import net.dankito.fints.messages.segmente.id.MessageSegmentId import net.dankito.fints.messages.segmente.id.MessageSegmentId
import net.dankito.fints.model.DialogData import net.dankito.fints.model.DialogContext
open class Nachrichtenkopf( open class Nachrichtenkopf(
segmentNumber: Int, segmentNumber: Int,
messageSize: Int, messageSize: Int,
dialogData: DialogData dialogContext: DialogContext
) : Segment(listOf( ) : Segment(listOf(
Segmentkopf(MessageSegmentId.MessageHeader, 3, segmentNumber), Segmentkopf(MessageSegmentId.MessageHeader, 3, segmentNumber),
Nachrichtengroesse(messageSize), Nachrichtengroesse(messageSize),
HbciVersionDatenelement(HbciVersion.FinTs_3_0_0), HbciVersionDatenelement(HbciVersion.FinTs_3_0_0),
DialogId(dialogData.dialogId), DialogId(dialogContext.dialogId),
Nachrichtennummer(dialogData.messageNumber) Nachrichtennummer(dialogContext.messageNumber)
)) ))

View File

@ -4,22 +4,20 @@ import net.dankito.fints.messages.datenelemente.implementierte.signatur.Operatio
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselnummer import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselnummer
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselversion import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselversion
import net.dankito.fints.messages.datenelemente.implementierte.signatur.SignaturalgorithmusKodiert import net.dankito.fints.messages.datenelemente.implementierte.signatur.SignaturalgorithmusKodiert
import net.dankito.fints.model.BankData import net.dankito.fints.model.MessageBaseData
import net.dankito.fints.model.CustomerData
open class PinTanSignaturkopf( open class PinTanSignaturkopf(
segmentNumber: Int, segmentNumber: Int,
bank: BankData, baseData: MessageBaseData,
customer: CustomerData,
securityControlReference: String, securityControlReference: String,
date: Int, date: Int,
time: Int time: Int
) : Signaturkopf( ) : Signaturkopf(
segmentNumber, segmentNumber,
bank, baseData.bank,
customer, baseData.customer,
securityControlReference, securityControlReference,
date, date,
time, time,

View File

@ -5,19 +5,17 @@ import net.dankito.fints.messages.datenelemente.implementierte.signatur.Operatio
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselart import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselart
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselnummer import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselnummer
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselversion import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselversion
import net.dankito.fints.model.BankData import net.dankito.fints.model.MessageBaseData
import net.dankito.fints.model.CustomerData
open class PinTanVerschluesselungskopf( open class PinTanVerschluesselungskopf(
bank: BankData, baseData: MessageBaseData,
customer: CustomerData,
date: Int, date: Int,
time: Int time: Int
) : Verschluesselungskopf( ) : Verschluesselungskopf(
bank, baseData.bank,
customer, baseData.customer,
date, date,
time, time,
OperationsmodusKodiert.FinTsMockValue, OperationsmodusKodiert.FinTsMockValue,

View File

@ -5,21 +5,17 @@ import net.dankito.fints.messages.datenelemente.implementierte.*
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
import net.dankito.fints.messages.segmente.Segment import net.dankito.fints.messages.segmente.Segment
import net.dankito.fints.messages.segmente.id.CustomerSegmentId import net.dankito.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.fints.model.BankData import net.dankito.fints.model.MessageBaseData
import net.dankito.fints.model.CustomerData
import net.dankito.fints.model.ProductData
open class Verarbeitungsvorbereitung( open class Verarbeitungsvorbereitung(
segmentNumber: Int, segmentNumber: Int,
bank: BankData, baseData: MessageBaseData
customer: CustomerData,
product: ProductData
) : Segment(listOf( ) : Segment(listOf(
Segmentkopf(CustomerSegmentId.ProcessingPreparation, 3, segmentNumber), Segmentkopf(CustomerSegmentId.ProcessingPreparation, 3, segmentNumber),
BPDVersion(bank.bpdVersion, Existenzstatus.Mandatory), BPDVersion(baseData.bank.bpdVersion, Existenzstatus.Mandatory),
UPDVersion(customer.updVersion, Existenzstatus.Mandatory), UPDVersion(baseData.customer.updVersion, Existenzstatus.Mandatory),
DialogspracheDatenelement(customer.selectedLanguage, Existenzstatus.Mandatory), DialogspracheDatenelement(baseData.customer.selectedLanguage, Existenzstatus.Mandatory),
Produktbezeichnung(product.name, Existenzstatus.Mandatory), Produktbezeichnung(baseData.product.name, Existenzstatus.Mandatory),
Produktversion(product.version, Existenzstatus.Mandatory) Produktversion(baseData.product.version, Existenzstatus.Mandatory)
)) ))

View File

@ -0,0 +1,29 @@
package net.dankito.fints.model
import net.dankito.fints.messages.MessageBuilderResult
import net.dankito.fints.response.Response
open class DialogContext(
bank: BankData,
customer: CustomerData,
product: ProductData,
var currentMessage: MessageBuilderResult? = null,
var dialogId: String = InitialDialogId,
var messageNumber: Int = InitialMessageNumber,
var response: Response? = null,
var previousMessageInDialog: MessageBuilderResult? = null
) : MessageBaseData(bank, customer, product) {
companion object {
const val InitialDialogId = "0"
const val InitialMessageNumber = 1
}
fun increaseMessageNumber() {
messageNumber++
}
}

View File

@ -1,18 +0,0 @@
package net.dankito.fints.model
open class DialogData(
var dialogId: String = "0",
var messageNumber: Int = 1
) {
companion object {
val DialogInitDialogData = DialogData("0", 1)
}
fun increaseMessageNumber() {
messageNumber++
}
}

View File

@ -0,0 +1,8 @@
package net.dankito.fints.model
open class MessageBaseData(
val bank: BankData,
val customer: CustomerData,
val product: ProductData
)

View File

@ -44,8 +44,8 @@ class BanksFinTsDetailsRetriever {
private val finTsClient = object : FinTsClient(NoOpFinTsClientCallback(), Java8Base64Service()) { private val finTsClient = object : FinTsClient(NoOpFinTsClientCallback(), Java8Base64Service()) {
fun getAndHandleResponseForMessagePublic(requestBody: String, bank: BankData): Response { fun getAndHandleResponseForMessagePublic(requestBody: String, dialogContext: DialogContext): Response {
return getAndHandleResponseForMessage(requestBody, bank) return getAndHandleResponseForMessage(requestBody, dialogContext)
} }
fun updateBankDataPublic(bank: BankData, response: Response) { fun updateBankDataPublic(bank: BankData, response: Response) {
@ -109,11 +109,11 @@ class BanksFinTsDetailsRetriever {
private fun getAnonymousBankInfo(bank: BankData): Response { private fun getAnonymousBankInfo(bank: BankData): Response {
val dialogData = DialogData() val dialogContext = DialogContext(bank, CustomerData.Anonymous, product)
val requestBody = messageBuilder.createAnonymousDialogInitMessage(bank, product, dialogData) val requestBody = messageBuilder.createAnonymousDialogInitMessage(dialogContext).createdMessage ?: ""
val anonymousBankInfoResponse = val anonymousBankInfoResponse =
finTsClient.getAndHandleResponseForMessagePublic(requestBody, bank) finTsClient.getAndHandleResponseForMessagePublic(requestBody, dialogContext)
finTsClient.updateBankDataPublic(bank, anonymousBankInfoResponse) finTsClient.updateBankDataPublic(bank, anonymousBankInfoResponse)
return anonymousBankInfoResponse return anonymousBankInfoResponse

View File

@ -1,9 +1,7 @@
package net.dankito.fints.messages package net.dankito.fints.messages
import net.dankito.fints.FinTsTestBase import net.dankito.fints.FinTsTestBase
import net.dankito.fints.model.AccountData import net.dankito.fints.model.*
import net.dankito.fints.model.DialogData
import net.dankito.fints.model.GetTransactionsParameter
import net.dankito.fints.response.segments.AccountType import net.dankito.fints.response.segments.AccountType
import net.dankito.fints.response.segments.JobParameters import net.dankito.fints.response.segments.JobParameters
import net.dankito.fints.util.FinTsUtils import net.dankito.fints.util.FinTsUtils
@ -44,8 +42,11 @@ class MessageBuilderTest : FinTsTestBase() {
@Test @Test
fun createAnonymousDialogInitMessage() { fun createAnonymousDialogInitMessage() {
// given
val dialogContext = DialogContext(Bank, CustomerData.Anonymous, Product)
// when // when
val result = underTest.createAnonymousDialogInitMessage(Bank, Product, DialogData.DialogInitDialogData) val result = underTest.createAnonymousDialogInitMessage(dialogContext).createdMessage
// then // then
assertThat(result).isEqualTo( assertThat(result).isEqualTo(
@ -61,10 +62,10 @@ class MessageBuilderTest : FinTsTestBase() {
// given // given
val dialogId = createDialogId() val dialogId = createDialogId()
val dialogData = DialogData(dialogId) val dialogContext = DialogContext(Bank, Customer, Product, null, dialogId)
// when // when
val result = underTest.createAnonymousDialogEndMessage(Bank, dialogData) val result = underTest.createAnonymousDialogEndMessage(dialogContext)
// then // then
assertThat(normalizeBinaryData(result)).isEqualTo(normalizeBinaryData( assertThat(normalizeBinaryData(result)).isEqualTo(normalizeBinaryData(
@ -78,8 +79,11 @@ class MessageBuilderTest : FinTsTestBase() {
@Test @Test
fun createDialogInitMessage() { fun createDialogInitMessage() {
// given
val dialogContext = DialogContext(Bank, Customer, Product)
// when // when
val result = underTest.createSynchronizeCustomerSystemIdMessage(Bank, Customer, Product, DialogData.DialogInitDialogData) val result = underTest.createSynchronizeCustomerSystemIdMessage(dialogContext).createdMessage ?: ""
// then // then
assertThat(normalizeBinaryData(result)).isEqualTo(normalizeBinaryData( assertThat(normalizeBinaryData(result)).isEqualTo(normalizeBinaryData(
@ -100,10 +104,10 @@ class MessageBuilderTest : FinTsTestBase() {
// given // given
val dialogId = createDialogId() val dialogId = createDialogId()
val dialogData = DialogData(dialogId) val dialogContext = DialogContext(Bank, Customer, Product, null, dialogId)
// when // when
val result = underTest.createDialogEndMessage(Bank, Customer, dialogData) val result = underTest.createDialogEndMessage(dialogContext)
// then // then
assertThat(normalizeBinaryData(result)).isEqualTo(normalizeBinaryData( assertThat(normalizeBinaryData(result)).isEqualTo(normalizeBinaryData(
@ -120,8 +124,11 @@ class MessageBuilderTest : FinTsTestBase() {
@Test @Test
fun createGetTransactionsMessage_JobIsNotAllowed() { fun createGetTransactionsMessage_JobIsNotAllowed() {
// given
val dialogContext = DialogContext(Bank, Customer, Product)
// when // when
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Bank, Customer, Account, Product, DialogData.DialogInitDialogData) val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Account, dialogContext)
// then // then
assertThat(result.isJobAllowed).isFalse() assertThat(result.isJobAllowed).isFalse()
@ -136,9 +143,10 @@ class MessageBuilderTest : FinTsTestBase() {
Bank.supportedJobs = listOf(getTransactionsJob) Bank.supportedJobs = listOf(getTransactionsJob)
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJobWithPreviousVersion)) val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJobWithPreviousVersion))
Customer.addAccount(account) Customer.addAccount(account)
val dialogContext = DialogContext(Bank, Customer, Product)
// when // when
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Bank, Customer, account, Product, DialogData.DialogInitDialogData) val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), account, dialogContext)
// then // then
assertThat(result.isJobAllowed).isTrue() assertThat(result.isJobAllowed).isTrue()
@ -153,13 +161,14 @@ class MessageBuilderTest : FinTsTestBase() {
Bank.supportedJobs = listOf(getTransactionsJob) Bank.supportedJobs = listOf(getTransactionsJob)
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob)) val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob))
Customer.addAccount(account) Customer.addAccount(account)
val dialogContext = DialogContext(Bank, Customer, Product)
val fromDate = LocalDate.of(2019, Month.AUGUST, 6).asUtilDate() val fromDate = LocalDate.of(2019, Month.AUGUST, 6).asUtilDate()
val toDate = LocalDate.of(2019, Month.OCTOBER, 21).asUtilDate() val toDate = LocalDate.of(2019, Month.OCTOBER, 21).asUtilDate()
val maxCountEntries = 99 val maxCountEntries = 99
// when // when
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries), Bank, Customer, account, Product, DialogData.DialogInitDialogData) val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries), account, dialogContext)
// then // then
assertThat(result.createdMessage).isNotNull() assertThat(result.createdMessage).isNotNull()
@ -183,6 +192,7 @@ class MessageBuilderTest : FinTsTestBase() {
Bank.supportedJobs = listOf(getTransactionsJob) Bank.supportedJobs = listOf(getTransactionsJob)
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob)) val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob))
Customer.addAccount(account) Customer.addAccount(account)
val dialogContext = DialogContext(Bank, Customer, Product)
val fromDate = LocalDate.of(2019, Month.AUGUST, 6).asUtilDate() val fromDate = LocalDate.of(2019, Month.AUGUST, 6).asUtilDate()
val toDate = LocalDate.of(2019, Month.OCTOBER, 21).asUtilDate() val toDate = LocalDate.of(2019, Month.OCTOBER, 21).asUtilDate()
@ -190,7 +200,7 @@ class MessageBuilderTest : FinTsTestBase() {
val continuationId = "9345-10-26-11.52.15.693455" val continuationId = "9345-10-26-11.52.15.693455"
// when // when
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries, false, continuationId), Bank, Customer, account, Product, DialogData.DialogInitDialogData) val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries, false, continuationId), account, dialogContext)
// then // then
assertThat(result.createdMessage).isNotNull() assertThat(result.createdMessage).isNotNull()

View File

@ -1,6 +1,7 @@
package net.dankito.fints.messages.segmente.implementierte package net.dankito.fints.messages.segmente.implementierte
import net.dankito.fints.FinTsTestBase import net.dankito.fints.FinTsTestBase
import net.dankito.fints.model.MessageBaseData
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Test import org.junit.Test
@ -11,7 +12,7 @@ class IdentifikationsSegmentTest : FinTsTestBase() {
fun format() { fun format() {
// given // given
val underTest = IdentifikationsSegment(2, Bank, Customer) val underTest = IdentifikationsSegment(2, MessageBaseData(Bank, Customer, Product))
// when // when
val result = underTest.format() val result = underTest.format()

View File

@ -1,6 +1,7 @@
package net.dankito.fints.messages.segmente.implementierte package net.dankito.fints.messages.segmente.implementierte
import net.dankito.fints.FinTsTestBase import net.dankito.fints.FinTsTestBase
import net.dankito.fints.model.MessageBaseData
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Test import org.junit.Test
@ -13,7 +14,7 @@ class SignaturkopfTest : FinTsTestBase() {
// given // given
val controlReference = "1902675680" val controlReference = "1902675680"
val underTest = PinTanSignaturkopf(2, Bank, Customer, val underTest = PinTanSignaturkopf(2, MessageBaseData(Bank, Customer, Product),
controlReference, Date, Time) controlReference, Date, Time)
// when // when

View File

@ -1,6 +1,7 @@
package net.dankito.fints.messages.segmente.implementierte package net.dankito.fints.messages.segmente.implementierte
import net.dankito.fints.FinTsTestBase import net.dankito.fints.FinTsTestBase
import net.dankito.fints.model.MessageBaseData
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Test import org.junit.Test
@ -12,7 +13,7 @@ class VerschluesselungskopfTest : FinTsTestBase() {
// given // given
val underTest = PinTanVerschluesselungskopf(Bank, Customer, Date, Time) val underTest = PinTanVerschluesselungskopf(MessageBaseData(Bank, Customer, Product), Date, Time)
// when // when
val result = underTest.format() val result = underTest.format()