Implemented changing TAN medium (HKTAU)
This commit is contained in:
parent
11f115936b
commit
cb557812c4
|
@ -12,7 +12,9 @@ import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
|
|||
import net.dankito.banking.fints4java.android.ui.dialogs.AddAccountDialog
|
||||
import net.dankito.banking.fints4java.android.ui.dialogs.EnterTanDialog
|
||||
import net.dankito.fints.FinTsClientCallback
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.fints.model.CustomerData
|
||||
import net.dankito.fints.model.EnterTanGeneratorAtcResult
|
||||
import net.dankito.fints.model.TanChallenge
|
||||
import net.dankito.fints.model.TanProcedure
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
@ -34,6 +36,10 @@ class MainActivity : AppCompatActivity() {
|
|||
return getTanFromUserOffUiThread(customer, tanChallenge)
|
||||
}
|
||||
|
||||
override fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult? {
|
||||
return null
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ 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.signatur.Sicherheitsfunktion
|
||||
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.model.*
|
||||
|
@ -345,6 +346,61 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
open fun changeTanMediumAsync(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData,
|
||||
callback: (FinTsClientResponse) -> Unit) {
|
||||
|
||||
threadPool.runAsync {
|
||||
callback(changeTanMedium(newActiveTanMedium, bank, customer))
|
||||
}
|
||||
}
|
||||
|
||||
open fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData): FinTsClientResponse {
|
||||
|
||||
val lastCreatedMessage = messageBuilder.lastCreatedMessage
|
||||
|
||||
// lastCreatedMessage?.let { closeDialog(bank, customer, ) } // TODO: close previous dialog
|
||||
|
||||
|
||||
var enteredAtc: EnterTanGeneratorAtcResult? = null
|
||||
|
||||
if (bank.changeTanMediumParameters?.enteringAtcAndTanRequired == true) {
|
||||
enteredAtc = callback.enterTanGeneratorAtc(customer, newActiveTanMedium)
|
||||
|
||||
if (enteredAtc == null) {
|
||||
return FinTsClientResponse(Response(false, exception =
|
||||
Exception("Bank requires to enter ATC and TAN in order to change TAN medium."))) // TODO: translate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val dialogData = DialogData()
|
||||
|
||||
val initDialogResponse = initDialog(bank, customer, dialogData)
|
||||
|
||||
if (initDialogResponse.successful == false) {
|
||||
return FinTsClientResponse(initDialogResponse)
|
||||
}
|
||||
|
||||
|
||||
dialogData.increaseMessageNumber()
|
||||
|
||||
val message = messageBuilder.createChangeTanMediumMessage(newActiveTanMedium, bank, customer, dialogData,
|
||||
enteredAtc?.tan, enteredAtc?.atc)
|
||||
|
||||
val response = getAndHandleResponseForMessage(message, bank)
|
||||
|
||||
closeDialog(bank, customer, dialogData)
|
||||
|
||||
|
||||
lastCreatedMessage?.let {
|
||||
resendMessageInNewDialogAsync(lastCreatedMessage, bank, customer)
|
||||
}
|
||||
|
||||
|
||||
return FinTsClientResponse(response)
|
||||
}
|
||||
|
||||
|
||||
open fun doBankTransferAsync(bankTransferData: BankTransferData, bank: BankData,
|
||||
customer: CustomerData, callback: (FinTsClientResponse) -> Unit) {
|
||||
|
||||
|
@ -377,6 +433,37 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
protected open fun resendMessageInNewDialogAsync(message: MessageBuilderResult, bank: BankData,
|
||||
customer: CustomerData) {
|
||||
|
||||
threadPool.runAsync {
|
||||
resendMessageInNewDialog(message, bank, customer)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun resendMessageInNewDialog(message: MessageBuilderResult, bank: BankData,
|
||||
customer: CustomerData): FinTsClientResponse {
|
||||
|
||||
log.info("Resending message ${message.messageBodySegments.map { it.dataElementsAndGroups.firstOrNull()?.format() }} in a new dialog") // TODO: remove again
|
||||
|
||||
val dialogData = DialogData()
|
||||
|
||||
val initDialogResponse = initDialog(bank, customer, dialogData)
|
||||
if (initDialogResponse.successful == false) {
|
||||
return FinTsClientResponse(initDialogResponse)
|
||||
}
|
||||
|
||||
|
||||
val newMessage = messageBuilder.rebuildMessage(message, bank, customer, dialogData)
|
||||
|
||||
val response = getAndHandleResponseForMessageThatMayRequiresTan(newMessage, bank, customer, dialogData)
|
||||
|
||||
closeDialog(bank, customer, dialogData)
|
||||
|
||||
return FinTsClientResponse(response)
|
||||
}
|
||||
|
||||
|
||||
protected open fun initDialog(bank: BankData, customer: CustomerData, dialogData: DialogData): Response {
|
||||
|
||||
// we first need to retrieve supported tan procedures and jobs before we can do anything
|
||||
|
@ -596,6 +683,13 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: check if response contains '3931 TAN-Generator gesperrt, Synchronisierung erforderlich' or
|
||||
// '3933 TAN-Generator gesperrt, Synchronisierung erforderlich Kartennummer ##########' message,
|
||||
// call callback.enterAtc() and implement and call HKTSY job (p. 77)
|
||||
|
||||
// TODO: also check '9931 Sperrung des Kontos nach %1 Fehlversuchen' -> if %1 == 3 synchronize TAN generator
|
||||
// as it's quite unrealistic that user entered TAN wrong three times, in most cases TAN generator is not synchronized
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
|
@ -639,6 +733,10 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
response.getFirstSegmentById<ChangeTanMediaParameters>(InstituteSegmentId.ChangeTanMediaParameters)?.let { parameters ->
|
||||
bank.changeTanMediumParameters = parameters
|
||||
}
|
||||
|
||||
if (response.supportedJobs.isNotEmpty()) {
|
||||
bank.supportedJobs = response.supportedJobs
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package net.dankito.fints
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.fints.model.CustomerData
|
||||
import net.dankito.fints.model.EnterTanGeneratorAtcResult
|
||||
import net.dankito.fints.model.TanChallenge
|
||||
import net.dankito.fints.model.TanProcedure
|
||||
|
||||
|
@ -11,4 +13,9 @@ interface FinTsClientCallback {
|
|||
|
||||
fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): String?
|
||||
|
||||
/**
|
||||
* This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator.
|
||||
*/
|
||||
fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult?
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package net.dankito.fints
|
||||
|
||||
import net.dankito.fints.messages.MessageBuilder
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.fints.model.*
|
||||
import net.dankito.fints.response.ResponseParser
|
||||
import net.dankito.fints.response.client.AddAccountResponse
|
||||
|
@ -40,4 +41,8 @@ open class FinTsClientForCustomer(
|
|||
client.doBankTransferAsync(bankTransferData, bank, customer, callback)
|
||||
}
|
||||
|
||||
open fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, callback: (FinTsClientResponse) -> Unit) {
|
||||
client.changeTanMediumAsync(newActiveTanMedium, bank, customer, callback)
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@ package net.dankito.fints.messages
|
|||
import net.dankito.fints.extensions.containsAny
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Aufsetzpunkt
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Synchronisierungsmodus
|
||||
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.datenelemente.implementierte.tan.TanProcess
|
||||
|
@ -14,6 +15,7 @@ import net.dankito.fints.messages.segmente.id.CustomerSegmentId
|
|||
import net.dankito.fints.messages.segmente.implementierte.*
|
||||
import net.dankito.fints.messages.segmente.implementierte.sepa.SepaEinzelueberweisung
|
||||
import net.dankito.fints.messages.segmente.implementierte.tan.TanGeneratorListeAnzeigen
|
||||
import net.dankito.fints.messages.segmente.implementierte.tan.TanGeneratorTanMediumAnOderUmmelden
|
||||
import net.dankito.fints.messages.segmente.implementierte.umsaetze.KontoumsaetzeZeitraumMt940Version5
|
||||
import net.dankito.fints.messages.segmente.implementierte.umsaetze.KontoumsaetzeZeitraumMt940Version6
|
||||
import net.dankito.fints.messages.segmente.implementierte.umsaetze.KontoumsaetzeZeitraumMt940Version7
|
||||
|
@ -40,6 +42,10 @@ 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
|
||||
* angebotenen Geschäftsvorfälle fremder Kreditinstitute (von denen sie keine BPD besitzen)
|
||||
|
@ -157,6 +163,23 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
return result
|
||||
}
|
||||
|
||||
open fun createChangeTanMediumMessage(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData,
|
||||
dialogData: DialogData, tan: String? = null, atc: Int? = null): MessageBuilderResult {
|
||||
|
||||
val result = getSupportedVersionsOfJob(CustomerSegmentId.ChangeTanMedium, customer, listOf(1, 2, 3))
|
||||
|
||||
if (result.isJobVersionSupported) {
|
||||
val segments = listOf(
|
||||
TanGeneratorTanMediumAnOderUmmelden(result.getHighestAllowedVersion!!, generator.resetSegmentNumber(2),
|
||||
bank, customer, newActiveTanMedium, tan, atc)
|
||||
)
|
||||
|
||||
return createMessageBuilderResult(bank, customer, dialogData, segments)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
open fun createSendEnteredTanMessage(enteredTan: String, tanResponse: TanResponse, bank: BankData, customer: CustomerData, dialogData: DialogData): String {
|
||||
|
||||
val tanProcess = if (tanResponse.tanProcess == TanProcess.TanProcess1) TanProcess.TanProcess1 else TanProcess.TanProcess2
|
||||
|
@ -203,13 +226,23 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
|
||||
aufsetzpunkte.forEach { it.resetContinuationId(continuationId) }
|
||||
|
||||
return rebuildMessage(message, bank, customer, dialogData)
|
||||
}
|
||||
|
||||
open fun rebuildMessage(message: MessageBuilderResult, bank: BankData, customer: CustomerData,
|
||||
dialogData: DialogData): MessageBuilderResult {
|
||||
|
||||
dialogData.increaseMessageNumber()
|
||||
|
||||
return createMessageBuilderResult(bank, customer, dialogData, message.messageBodySegments)
|
||||
}
|
||||
|
||||
protected open fun createMessageBuilderResult(bank: BankData, customer: CustomerData, dialogData: DialogData, segments: List<Segment>): MessageBuilderResult {
|
||||
return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, segments), segments)
|
||||
val message = MessageBuilderResult(createSignedMessage(bank, customer, dialogData, segments), segments)
|
||||
|
||||
lastCreatedMessage = message
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,14 +2,20 @@ package net.dankito.fints.messages.datenelemente.abgeleiteteformate
|
|||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
|
||||
|
||||
/**
|
||||
* Es sind nur die jeweils aufgeführten Werte zulässig.
|
||||
*/
|
||||
abstract class Code(code: String?, val allowedValues: List<String>, existenzstatus: Existenzstatus)
|
||||
open class Code(code: String?, val allowedValues: List<String>, existenzstatus: Existenzstatus)
|
||||
: AlphanumerischesDatenelement(code, existenzstatus) {
|
||||
|
||||
|
||||
constructor(code: ICodeEnum?, allowedValues: List<String>, existenzstatus: Existenzstatus)
|
||||
: this(code?.code, allowedValues, existenzstatus)
|
||||
|
||||
|
||||
override fun validate() {
|
||||
super.validate()
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import net.dankito.fints.messages.Existenzstatus
|
|||
/**
|
||||
* Es gilt der FinTS-Basiszeichensatz ohne die Zeichen CR und LF.
|
||||
*/
|
||||
abstract class AlphanumerischesDatenelement @JvmOverloads constructor(
|
||||
open class AlphanumerischesDatenelement @JvmOverloads constructor(
|
||||
alphanumericValue: String?, existenzstatus: Existenzstatus, val maxLength: Int? = null
|
||||
) : TextDatenelement(alphanumericValue, existenzstatus) {
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import net.dankito.fints.messages.Existenzstatus
|
|||
/**
|
||||
* Zulässig sind lediglich die Ziffern ‘0’ bis ‘9’. Führende Nullen sind nicht zugelassen.
|
||||
*/
|
||||
abstract class NumerischesDatenelement(val number: Int?, val numberOfDigits: Int, existenzstatus: Existenzstatus)
|
||||
open class NumerischesDatenelement(val number: Int?, val numberOfDigits: Int, existenzstatus: Existenzstatus)
|
||||
: TextDatenelement(number?.toString(), existenzstatus) {
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.TextDatenelement
|
||||
|
||||
|
||||
/**
|
||||
* A dummy data element for conditional data elements building to tell formatter not to print this data element
|
||||
*/
|
||||
open class DoNotPrintDatenelement : TextDatenelement("", Existenzstatus.NotAllowed)
|
|
@ -8,7 +8,7 @@ class TanGeneratorTanMedium(
|
|||
status: TanMediumStatus,
|
||||
val cardNumber: String,
|
||||
val followUpCardNumber: String?,
|
||||
val cardType: String?,
|
||||
val cardType: Int?,
|
||||
val validFrom: Date?,
|
||||
val validTo: Date?,
|
||||
val mediaName: String?
|
||||
|
|
|
@ -5,6 +5,9 @@ import net.dankito.fints.messages.datenelemente.implementierte.account.KontoDepo
|
|||
import net.dankito.fints.messages.datenelemente.implementierte.account.Unterkontomerkmal
|
||||
import net.dankito.fints.messages.datenelementgruppen.Datenelementgruppe
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.Kreditinstitutskennung
|
||||
import net.dankito.fints.model.AccountData
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
|
||||
|
||||
/**
|
||||
|
@ -26,4 +29,12 @@ open class Kontoverbindung(
|
|||
KontoDepotnummer(accountNumber, Existenzstatus.Mandatory),
|
||||
Unterkontomerkmal(subAccountAttribute ?: "", Existenzstatus.Optional),
|
||||
Kreditinstitutskennung(bankCountryCode, bankCode)
|
||||
), Existenzstatus.Mandatory)
|
||||
), 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)
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import net.dankito.fints.messages.datenelemente.implementierte.account.KontoDepo
|
|||
import net.dankito.fints.messages.datenelemente.implementierte.account.Unterkontomerkmal
|
||||
import net.dankito.fints.messages.datenelementgruppen.Datenelementgruppe
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.Kreditinstitutskennung
|
||||
import net.dankito.fints.model.AccountData
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
|
||||
|
@ -32,6 +33,9 @@ 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(bank: BankData, customer: CustomerData, subAccountAttribute: String?)
|
||||
: this(customer.iban, bank.bic, bank.countryCode, bank.bankCode, customer.customerId, subAccountAttribute)
|
||||
}
|
|
@ -3,6 +3,7 @@ package net.dankito.fints.messages.segmente
|
|||
import net.dankito.fints.messages.Nachrichtenteil
|
||||
import net.dankito.fints.messages.Separators
|
||||
import net.dankito.fints.messages.datenelemente.DatenelementBase
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.DoNotPrintDatenelement
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
|
@ -15,7 +16,7 @@ abstract class Segment(val dataElementsAndGroups: List<DatenelementBase>) : Nach
|
|||
|
||||
|
||||
override fun format(): String {
|
||||
val formattedSegment = dataElementsAndGroups.joinToString(Separators.DataElementGroupsSeparator) { it.format() }
|
||||
val formattedSegment = dataElementsAndGroups.filter { it is DoNotPrintDatenelement == false }.joinToString(Separators.DataElementGroupsSeparator) { it.format() }
|
||||
|
||||
return cutEmptyDataElementGroupsAtEndOfSegment(formattedSegment)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ enum class CustomerSegmentId(override val id: String) : ISegmentId {
|
|||
|
||||
TanMediaList("HKTAB"),
|
||||
|
||||
ChangeTanMedium("HKTAU"),
|
||||
|
||||
Balance("HKSAL"),
|
||||
|
||||
AccountTransactionsMt940("HKKAZ"),
|
||||
|
|
|
@ -27,7 +27,7 @@ open class TanGeneratorListeAnzeigen(
|
|||
|
||||
if (supportedMediaClasses.contains(tanMediumClass) == false) {
|
||||
throw UnsupportedOperationException("Value $tanMediumClass for TAN medium class is not valid for HKTAB version $segmentVersion. " +
|
||||
"Supported values are: " + TanMediumKlasse.values().filter { it.supportedHkTabVersions.contains(segmentVersion) }.map { it.code })
|
||||
"Supported values are: " + supportedMediaClasses)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package net.dankito.fints.messages.segmente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Datum
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.DoNotPrintDatenelement
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.NotAllowedDatenelement
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.allCodes
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.account.Kontoverbindung
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.account.KontoverbindungInternational
|
||||
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.response.segments.ChangeTanMediaParameters
|
||||
|
||||
|
||||
/**
|
||||
* The actual job is called "TAN-Medium an- bzw. ummelden", but as TAN lists aren't supported anymore I've implemented
|
||||
* it only for TAN Generators.
|
||||
*
|
||||
* Mit Hilfe dieses Geschäftsvorfalls kann der Kunde seinem Institut mitteilen, welches Medium (Chipkarte,
|
||||
* TAN-Generator oder bilateral vereinbart) er für die Autorisierung der Aufträge per TAN verwenden wird.
|
||||
*
|
||||
* Welches Medium gerade aktiv ist, kann mit Hilfe des Geschäftsvorfalls „TAN-Medium anzeigen Bestand (HKTAB)“ bzw.
|
||||
* für Detailinformationen zur Karte auch „Kartenanzeige anfordern (HKAZK)“ durch den Kunden erfragt werden.
|
||||
*
|
||||
* Der Kunde entscheidet selbst, welches seiner verfügbaren TAN-Medien er verwenden möchte.
|
||||
*
|
||||
* chipTAN-Verfahren:
|
||||
* Steht beim chipTAN-Verfahren ein Kartenwechsel an, so kann der Kunde mit diesem Geschäftsvorfall seine Karte bzw.
|
||||
* Folgekarte aktivieren. Kann der Kunde mehrere Karten verwenden, dann kann mit diesem GV die Ummeldung auf eine
|
||||
* andere Karte erfolgen. Das Kreditinstitut entscheidet selbst, ob dieser GV TAN-pflichtig istoder nicht.
|
||||
*/
|
||||
open class TanGeneratorTanMediumAnOderUmmelden(
|
||||
segmentVersion: Int,
|
||||
segmentNumber: Int,
|
||||
bank: BankData,
|
||||
customer: CustomerData,
|
||||
newActiveTanMedium: TanGeneratorTanMedium,
|
||||
/**
|
||||
* Has to be set if „Eingabe von ATC und TAN erforderlich“ (BPD)=“J“
|
||||
*/
|
||||
tan: String? = null,
|
||||
/**
|
||||
* Has to be set if „Eingabe von ATC und TAN erforderlich“ (BPD)=“J“
|
||||
*/
|
||||
atc: Int? = null,
|
||||
/**
|
||||
* An optional field and only used in version 3
|
||||
*/
|
||||
iccsn: String? = null,
|
||||
|
||||
parameters: ChangeTanMediaParameters = bank.changeTanMediumParameters!!
|
||||
)
|
||||
: Segment(listOf(
|
||||
Segmentkopf(CustomerSegmentId.ChangeTanMedium, segmentVersion, segmentNumber),
|
||||
Code(TanMediumKlasse.TanGenerator, allCodes<TanMediumKlasse>(), Existenzstatus.Mandatory),
|
||||
AlphanumerischesDatenelement(newActiveTanMedium.cardNumber, Existenzstatus.Mandatory),
|
||||
AlphanumerischesDatenelement(newActiveTanMedium.followUpCardNumber, if (parameters.enteringFollowUpCardNumberRequired) 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) 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(),
|
||||
NotAllowedDatenelement(), // TAN-Listennummer not supported anymore
|
||||
NumerischesDatenelement(atc, 5, if (parameters.enteringAtcAndTanRequired) Existenzstatus.Mandatory else Existenzstatus.NotAllowed),
|
||||
AlphanumerischesDatenelement(tan, if (parameters.enteringAtcAndTanRequired) Existenzstatus.Mandatory else Existenzstatus.NotAllowed, 99)
|
||||
)) {
|
||||
|
||||
init {
|
||||
if (parameters.enteringAtcAndTanRequired) {
|
||||
if (atc == null || tan == null) {
|
||||
throw UnsupportedOperationException("As „Eingabe von ATC und TAN erforderlich“ is set to \"J\" " +
|
||||
"(ChangeTanMediaParameters.enteringAtcAndTanRequired is set to true) parameters atc and tan have to be set.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@ package net.dankito.fints.model
|
|||
import net.dankito.fints.messages.datenelemente.implementierte.BPDVersion
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.HbciVersion
|
||||
import net.dankito.fints.response.segments.ChangeTanMediaParameters
|
||||
import net.dankito.fints.response.segments.JobParameters
|
||||
|
||||
|
||||
|
@ -22,6 +23,7 @@ open class BankData(
|
|||
|
||||
var supportedHbciVersions: List<HbciVersion> = listOf(),
|
||||
var supportedTanProcedures: List<TanProcedure> = listOf(),
|
||||
var changeTanMediumParameters: ChangeTanMediaParameters? = null,
|
||||
var supportedLanguages: List<Dialogsprache> = listOf(),
|
||||
var supportedJobs: List<JobParameters> = listOf()
|
||||
) {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
|
||||
open class EnterTanGeneratorAtcResult(
|
||||
val tan: String,
|
||||
val atc: Int
|
||||
) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "TAN: $tan, ATC: $atc"
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,8 @@ enum class InstituteSegmentId(override val id: String) : ISegmentId {
|
|||
|
||||
TanMediaList("HITAB"),
|
||||
|
||||
ChangeTanMediaParameters("HITAUS"), // there's no response data segment for HKTAU -> HITAU does not exist
|
||||
|
||||
Balance("HISAL"),
|
||||
|
||||
AccountTransactionsMt940("HIKAZ")
|
||||
|
|
|
@ -8,7 +8,7 @@ import net.dankito.fints.messages.segmente.id.MessageSegmentId
|
|||
import net.dankito.fints.response.segments.*
|
||||
|
||||
|
||||
open class Response constructor(
|
||||
open class Response(
|
||||
val didReceiveResponse: Boolean,
|
||||
val receivedResponse: String? = null,
|
||||
val receivedSegments: List<ReceivedSegment> = listOf(),
|
||||
|
|
|
@ -94,6 +94,7 @@ open class ResponseParser @JvmOverloads constructor(
|
|||
InstituteSegmentId.TanInfo.id -> parseTanInfo(segment, segmentId, dataElementGroups)
|
||||
InstituteSegmentId.Tan.id -> parseTanResponse(segment, dataElementGroups)
|
||||
InstituteSegmentId.TanMediaList.id -> parseTanMediaList(segment, dataElementGroups)
|
||||
InstituteSegmentId.ChangeTanMediaParameters.id -> parseChangeTanMediaParameters(segment, segmentId, dataElementGroups)
|
||||
|
||||
InstituteSegmentId.Balance.id -> parseBalanceSegment(segment, dataElementGroups)
|
||||
InstituteSegmentId.AccountTransactionsMt940.id -> parseMt940AccountTransactions(segment, dataElementGroups)
|
||||
|
@ -432,7 +433,7 @@ open class ResponseParser @JvmOverloads constructor(
|
|||
protected open fun parseTanGeneratorTanMedium(mediumClass: TanMediumKlasse, status: TanMediumStatus,
|
||||
hitabVersion: Int, dataElements: List<String>): TanGeneratorTanMedium {
|
||||
|
||||
val cardType = if (hitabVersion < 2) null else parseStringToNullIfEmpty(dataElements[2]) // TODO: may parse to number
|
||||
val cardType = if (hitabVersion < 2) null else parseNullableInt(dataElements[2])
|
||||
// TODO: may also parse account info
|
||||
val validFrom = if (hitabVersion < 2) null else parseNullableDate(dataElements[8])
|
||||
val validTo = if (hitabVersion < 2) null else parseNullableDate(dataElements[9])
|
||||
|
@ -443,6 +444,28 @@ open class ResponseParser @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
protected open fun parseChangeTanMediaParameters(segment: String, segmentId: String, dataElementGroups: List<String>): ChangeTanMediaParameters {
|
||||
val jobParameters = parseJobParameters(segment, segmentId, dataElementGroups)
|
||||
|
||||
val hiTausSegmentVersion = parseInt(getDataElements(dataElementGroups[0])[2])
|
||||
val changeTanGeneratorParameters = getDataElements(dataElementGroups[4])
|
||||
|
||||
val enteringCardTypeRequired = if (hiTausSegmentVersion < 2) false else parseBoolean(changeTanGeneratorParameters[3])
|
||||
val accountInfoRequired = if (hiTausSegmentVersion < 3) false else parseBoolean(changeTanGeneratorParameters[4])
|
||||
|
||||
val remainingParameters = when (hiTausSegmentVersion) {
|
||||
1 -> listOf()
|
||||
2 -> changeTanGeneratorParameters.subList(4, changeTanGeneratorParameters.size)
|
||||
else -> changeTanGeneratorParameters.subList(5, changeTanGeneratorParameters.size)
|
||||
}
|
||||
val allowedCardTypes = remainingParameters.map { parseInt(it) }
|
||||
|
||||
return ChangeTanMediaParameters(jobParameters, parseBoolean(changeTanGeneratorParameters[0]),
|
||||
parseBoolean(changeTanGeneratorParameters[1]), parseBoolean(changeTanGeneratorParameters[2]),
|
||||
enteringCardTypeRequired, accountInfoRequired, allowedCardTypes)
|
||||
}
|
||||
|
||||
|
||||
protected open fun parseBalanceSegment(segment: String, dataElementGroups: List<String>): BalanceSegment {
|
||||
// dataElementGroups[1] is account details
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package net.dankito.fints.response.segments
|
||||
|
||||
|
||||
open class ChangeTanMediaParameters(
|
||||
parameters: JobParameters,
|
||||
val enteringTanListNumberRequired: Boolean,
|
||||
val enteringFollowUpCardNumberRequired: Boolean,
|
||||
val enteringAtcAndTanRequired: Boolean,
|
||||
val enteringCardTypeAllowed: Boolean,
|
||||
val accountInfoRequired: Boolean,
|
||||
val allowedCardTypes: List<Int>
|
||||
)
|
||||
: JobParameters(parameters)
|
|
@ -4,6 +4,7 @@ import net.dankito.fints.FinTsClient;
|
|||
import net.dankito.fints.FinTsClientCallback;
|
||||
import net.dankito.fints.banks.BankFinder;
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion;
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium;
|
||||
import net.dankito.fints.model.*;
|
||||
import net.dankito.fints.model.mapper.BankDataMapper;
|
||||
import net.dankito.fints.response.client.GetTransactionsResponse;
|
||||
|
@ -45,6 +46,11 @@ public class JavaShowcase {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EnterTanGeneratorAtcResult enterTanGeneratorAtc(@NotNull CustomerData customer, @NotNull TanGeneratorTanMedium tanMedium) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
FinTsClient finTsClient = new FinTsClient(callback, new Java8Base64Service());
|
||||
|
|
|
@ -6,6 +6,7 @@ import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
|||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatus
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanEinsatzOption
|
||||
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.model.*
|
||||
|
@ -13,6 +14,7 @@ import net.dankito.fints.model.mapper.BankDataMapper
|
|||
import net.dankito.fints.response.client.FinTsClientResponse
|
||||
import net.dankito.fints.util.Java8Base64Service
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Assert
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
@ -41,6 +43,12 @@ class FinTsClientTest {
|
|||
return null
|
||||
}
|
||||
|
||||
override fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult? {
|
||||
Assert.fail("Bank asks you to synchronize your TAN generator for card ${tanMedium.cardNumber} " +
|
||||
"(follow-up number ${tanMedium.followUpCardNumber}). Please do this via your online banking portal or Banking UI.")
|
||||
return null // should actually never be called
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Laenderkennze
|
|||
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.ChangeTanMediaParameters
|
||||
import net.dankito.fints.response.segments.JobParameters
|
||||
import java.math.BigDecimal
|
||||
import java.util.*
|
||||
|
||||
|
@ -45,6 +47,11 @@ abstract class FinTsTestBase {
|
|||
const val Date = 19880327
|
||||
|
||||
const val Time = 182752
|
||||
|
||||
|
||||
init {
|
||||
Bank.changeTanMediumParameters = ChangeTanMediaParameters(JobParameters("", 1, 1, 1, ":0:0"), false, false, false, false, false, listOf())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,4 +75,9 @@ abstract class FinTsTestBase {
|
|||
return message.replace(0.toChar(), ' ')
|
||||
}
|
||||
|
||||
|
||||
protected open fun createEmptyJobParameters(): JobParameters {
|
||||
return JobParameters("", 1, 1, 1, ":0:0")
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
package net.dankito.fints.messages.segmente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.FinTsTestBase
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus
|
||||
import net.dankito.fints.response.segments.ChangeTanMediaParameters
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAN = "123456"
|
||||
|
||||
private const val ATC = 12345
|
||||
|
||||
private const val CardNumber = "9876543210"
|
||||
|
||||
private const val FollowUpCardNumber = "02"
|
||||
|
||||
private const val CardType = 11
|
||||
|
||||
private const val SegmentNumber = 3
|
||||
|
||||
private val NewActiveTanMedium = TanGeneratorTanMedium(TanMediumKlasse.TanGenerator, TanMediumStatus.Verfuegbar, CardNumber, FollowUpCardNumber, CardType, null, null, "EC-Card")
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun format_Version1_AtcNotRequired_FollowUpCardNumberNotRequired() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, false, false, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:1+G+$CardNumber")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun format_Version1_AtcRequired_FollowUpCardNumberNotRequired() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, true, false, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:1+G+$CardNumber+++$ATC+$TAN")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun format_Version1_AtcNotRequired_FollowUpCardNumberRequired() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, true, false, false, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:1+G+$CardNumber+$FollowUpCardNumber")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun format_Version1_AtcRequired_FollowUpCardNumberRequired() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, true, true, false, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:1+G+$CardNumber+$FollowUpCardNumber++$ATC+$TAN")
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun format_Version2_AtcNotRequired_FollowUpCardNumberNotRequired_CardTypeNotAllowed() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, false, false, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:2+G+$CardNumber+++$CustomerId::$BankCountryCode:$BankCode")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun format_Version2_AtcRequired_FollowUpCardNumberNotRequired_CardTypeNotAllowed() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, true, false, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:2+G+$CardNumber+++$CustomerId::$BankCountryCode:$BankCode++++$ATC+$TAN")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun format_Version2_AtcNotRequired_FollowUpCardNumberRequired_CardTypeNotAllowed() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, true, false, false, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:2+G+$CardNumber+$FollowUpCardNumber++$CustomerId::$BankCountryCode:$BankCode")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun format_Version2_AtcNotRequired_FollowUpCardNumberNotRequired_CardTypeAllowed() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, false, true, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:2+G+$CardNumber++$CardType+$CustomerId::$BankCountryCode:$BankCode")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun format_Version2_AtcRequired_FollowUpCardNumberRequired_CardTypeAllowed() {
|
||||
|
||||
// given
|
||||
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, true, true, true, false, listOf())
|
||||
|
||||
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, Customer, NewActiveTanMedium, TAN, ATC, null, parameters)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKTAU:$SegmentNumber:2+G+$CardNumber+$FollowUpCardNumber+$CardType+$CustomerId::$BankCountryCode:$BankCode++++$ATC+$TAN")
|
||||
}
|
||||
|
||||
// TODO: may also test 'gueltig ab' and 'gueltig bis'
|
||||
|
||||
|
||||
// TODO: also test Version3
|
||||
|
||||
}
|
|
@ -710,6 +710,80 @@ class ResponseParserTest : FinTsTestBase() {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
fun parseChangeTanMediaParametersVersion1() {
|
||||
|
||||
// when
|
||||
val result = underTest.parse("HITAUS:64:1:3+1+1+1+J:N:J:'")
|
||||
|
||||
// then
|
||||
assertSuccessfullyParsedSegment(result, InstituteSegmentId.ChangeTanMediaParameters, 64, 1, 3)
|
||||
|
||||
result.getFirstSegmentById<ChangeTanMediaParameters>(InstituteSegmentId.ChangeTanMediaParameters)?.let { segment ->
|
||||
assertThat(segment.maxCountJobs).isEqualTo(1)
|
||||
assertThat(segment.minimumCountSignatures).isEqualTo(1)
|
||||
assertThat(segment.securityClass).isEqualTo(1)
|
||||
|
||||
assertThat(segment.enteringTanListNumberRequired).isTrue()
|
||||
assertThat(segment.enteringFollowUpCardNumberRequired).isFalse()
|
||||
assertThat(segment.enteringAtcAndTanRequired).isTrue()
|
||||
assertThat(segment.enteringCardTypeAllowed).isFalse()
|
||||
assertThat(segment.accountInfoRequired).isFalse()
|
||||
assertThat(segment.allowedCardTypes).isEmpty()
|
||||
}
|
||||
?: run { Assert.fail("No segment of type ChangeTanMediaParameters found in ${result.receivedSegments}") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseChangeTanMediaParametersVersion2() {
|
||||
|
||||
// when
|
||||
val result = underTest.parse("HITAUS:64:2:3+1+1+1+N:J:N:J:11:13:15:17'")
|
||||
|
||||
// then
|
||||
assertSuccessfullyParsedSegment(result, InstituteSegmentId.ChangeTanMediaParameters, 64, 2, 3)
|
||||
|
||||
result.getFirstSegmentById<ChangeTanMediaParameters>(InstituteSegmentId.ChangeTanMediaParameters)?.let { segment ->
|
||||
assertThat(segment.maxCountJobs).isEqualTo(1)
|
||||
assertThat(segment.minimumCountSignatures).isEqualTo(1)
|
||||
assertThat(segment.securityClass).isEqualTo(1)
|
||||
|
||||
assertThat(segment.enteringTanListNumberRequired).isFalse()
|
||||
assertThat(segment.enteringFollowUpCardNumberRequired).isTrue()
|
||||
assertThat(segment.enteringAtcAndTanRequired).isFalse()
|
||||
assertThat(segment.enteringCardTypeAllowed).isTrue()
|
||||
assertThat(segment.accountInfoRequired).isFalse()
|
||||
assertThat(segment.allowedCardTypes).containsExactlyInAnyOrder(11, 13, 15, 17)
|
||||
}
|
||||
?: run { Assert.fail("No segment of type ChangeTanMediaParameters found in ${result.receivedSegments}") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseChangeTanMediaParametersVersion3() {
|
||||
|
||||
// when
|
||||
val result = underTest.parse("HITAUS:64:3:3+1+1+1+N:J:N:J:J:11:13:15:17'")
|
||||
|
||||
// then
|
||||
assertSuccessfullyParsedSegment(result, InstituteSegmentId.ChangeTanMediaParameters, 64, 3, 3)
|
||||
|
||||
result.getFirstSegmentById<ChangeTanMediaParameters>(InstituteSegmentId.ChangeTanMediaParameters)?.let { segment ->
|
||||
assertThat(segment.maxCountJobs).isEqualTo(1)
|
||||
assertThat(segment.minimumCountSignatures).isEqualTo(1)
|
||||
assertThat(segment.securityClass).isEqualTo(1)
|
||||
|
||||
assertThat(segment.enteringTanListNumberRequired).isFalse()
|
||||
assertThat(segment.enteringFollowUpCardNumberRequired).isTrue()
|
||||
assertThat(segment.enteringAtcAndTanRequired).isFalse()
|
||||
assertThat(segment.enteringCardTypeAllowed).isTrue()
|
||||
assertThat(segment.accountInfoRequired).isTrue()
|
||||
assertThat(segment.allowedCardTypes).containsExactlyInAnyOrder(11, 13, 15, 17)
|
||||
}
|
||||
?: run { Assert.fail("No segment of type ChangeTanMediaParameters found in ${result.receivedSegments}") }
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun parseBalance() {
|
||||
|
||||
|
|
Loading…
Reference in New Issue