From 553b55e09016c49836aa2d03deee2791e7222d4d Mon Sep 17 00:00:00 2001 From: dankl Date: Sun, 29 Dec 2019 15:07:05 +0100 Subject: [PATCH] Implemented reading user's tan media list --- .../kotlin/net/dankito/fints/FinTsClient.kt | 39 ++++++++++++++ .../dankito/fints/messages/MessageBuilder.kt | 21 ++++++++ .../fints/messages/MessageBuilderResult.kt | 3 ++ .../implementierte/tan/TanEinsatzOption.kt | 18 +++++++ .../tan/TanGeneratorTanMedium.kt | 51 +++++++++++++++++++ .../implementierte/tan/TanMedienArtVersion.kt | 19 +++++++ .../implementierte/tan/TanMedium.kt | 40 +++++++++++++++ .../tan/TanMediumKlasseVersion.kt | 24 +++++++++ .../implementierte/tan/TanMediumStatus.kt | 33 ++++++++++++ .../messages/segmente/id/CustomerSegmentId.kt | 2 + .../tan/TanGeneratorListeAnzeigen.kt | 34 +++++++++++++ .../fints/response/InstituteSegmentId.kt | 2 + .../dankito/fints/response/ResponseParser.kt | 47 +++++++++++++++++ .../client/GetTanMediaListResponse.kt | 11 ++++ .../fints/response/segments/TanMediaList.kt | 12 +++++ .../net/dankito/fints/FinTsClientTest.kt | 31 +++++++++++ .../fints/response/ResponseParserTest.kt | 29 ++++++++++- 17 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanEinsatzOption.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanGeneratorTanMedium.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMedienArtVersion.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMedium.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMediumKlasseVersion.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMediumStatus.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/implementierte/tan/TanGeneratorListeAnzeigen.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/response/client/GetTanMediaListResponse.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/TanMediaList.kt diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt index e92a8f98..7a8ae1c4 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt @@ -6,12 +6,15 @@ 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.TanMedienArtVersion +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasseVersion import net.dankito.fints.model.* import net.dankito.fints.response.InstituteSegmentId import net.dankito.fints.response.Response import net.dankito.fints.response.ResponseParser import net.dankito.fints.response.client.AddAccountResponse import net.dankito.fints.response.client.FinTsClientResponse +import net.dankito.fints.response.client.GetTanMediaListResponse import net.dankito.fints.response.client.GetTransactionsResponse import net.dankito.fints.response.segments.* import net.dankito.fints.util.IBase64Service @@ -300,6 +303,42 @@ open class FinTsClient @JvmOverloads constructor( } + open fun getTanMediaListAsync(bank: BankData, customer: CustomerData, + tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, + tanMediumClass: TanMediumKlasseVersion = TanMediumKlasseVersion.AlleMedien, + callback: (GetTanMediaListResponse) -> Unit) { + + threadPool.runAsync { + callback(getTanMediaList(bank, customer)) + } + } + + open fun getTanMediaList(bank: BankData, customer: CustomerData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, + tanMediumClass: TanMediumKlasseVersion = TanMediumKlasseVersion.AlleMedien): GetTanMediaListResponse { + + val dialogData = DialogData() + + val initDialogResponse = initDialog(bank, customer, dialogData) + + if (initDialogResponse.successful == false) { + return GetTanMediaListResponse(initDialogResponse, null) + } + + + dialogData.increaseMessageNumber() + + val message = messageBuilder.createGetTanMediaListMessage(bank, customer, dialogData, tanMediaKind, tanMediumClass) + + val response = getAndHandleResponseForMessageThatMayRequiresTan(message, bank, customer, dialogData) + + closeDialog(bank, customer, dialogData) + + val tanMediaList = response.getFirstSegmentById(InstituteSegmentId.TanMediaList) + + return GetTanMediaListResponse(response, tanMediaList) + } + + open fun doBankTransferAsync(bankTransferData: BankTransferData, bank: BankData, customer: CustomerData, callback: (FinTsClientResponse) -> Unit) { diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilder.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilder.kt index 8160701a..1b045ac6 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilder.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilder.kt @@ -3,6 +3,8 @@ 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.TanMedienArtVersion +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasseVersion import net.dankito.fints.messages.datenelemente.implementierte.tan.TanProcess import net.dankito.fints.messages.segmente.ISegmentNumberGenerator import net.dankito.fints.messages.segmente.Segment @@ -11,6 +13,7 @@ import net.dankito.fints.messages.segmente.Synchronisierung 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.umsaetze.KontoumsaetzeZeitraumMt940Version5 import net.dankito.fints.messages.segmente.implementierte.umsaetze.KontoumsaetzeZeitraumMt940Version6 import net.dankito.fints.messages.segmente.implementierte.umsaetze.KontoumsaetzeZeitraumMt940Version7 @@ -136,6 +139,24 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg } + open fun createGetTanMediaListMessage(bank: BankData, customer: CustomerData, dialogData: DialogData, + tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, + tanMediumClass: TanMediumKlasseVersion = TanMediumKlasseVersion.AlleMedien): MessageBuilderResult { + + val result = getSupportedVersionsOfJob(CustomerSegmentId.TanMediaList, customer, listOf(2, 3, 4, 5)) + + if (result.isJobVersionSupported) { + val segments = listOf( + TanGeneratorListeAnzeigen(result.getHighestAllowedVersion!!, + generator.resetSegmentNumber(2), tanMediaKind, tanMediumClass) + ) + + 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 diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilderResult.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilderResult.kt index edd05955..677fc6e7 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilderResult.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilderResult.kt @@ -22,4 +22,7 @@ open class MessageBuilderResult( return allowedVersions.contains(version) } + open val getHighestAllowedVersion: Int? + get() = allowedVersions.max() + } \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanEinsatzOption.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanEinsatzOption.kt new file mode 100644 index 00000000..671018e2 --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanEinsatzOption.kt @@ -0,0 +1,18 @@ +package net.dankito.fints.messages.datenelemente.implementierte.tan + +import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum + + +/** + * Es werden die Möglichkeiten festgelegt, die ein Kunde hat, wenn er für + * PIN/TAN parallel mehrere TAN-Medien zur Verfügung hat. + */ +enum class TanEinsatzOption(override val code: String) : ICodeEnum { + + KundeKannAlleAktivenMedienParallelNutzen("0"), + + KundeKannGenauEinMediumZuEinerZeitNutzen("1"), + + KundeKannEinMobiltelefonUndEinenTanGeneratorParallelNutzen("2") + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanGeneratorTanMedium.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanGeneratorTanMedium.kt new file mode 100644 index 00000000..f3d96067 --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanGeneratorTanMedium.kt @@ -0,0 +1,51 @@ +package net.dankito.fints.messages.datenelemente.implementierte.tan + +import java.util.* + + +class TanGeneratorTanMedium( + mediumClass: TanMediumKlasseVersion, + status: TanMediumStatus, + val cardNumber: String, + val followUpCardNumber: String?, + val cardType: String?, + val validFrom: Date?, + val validTo: Date?, + val mediaName: String? +) : TanMedium(mediumClass, status) { + + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + if (!super.equals(other)) return false + + other as TanGeneratorTanMedium + + if (cardNumber != other.cardNumber) return false + if (followUpCardNumber != other.followUpCardNumber) return false + if (cardType != other.cardType) return false + if (validFrom != other.validFrom) return false + if (validTo != other.validTo) return false + if (mediaName != other.mediaName) return false + + return true + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + cardNumber.hashCode() + result = 31 * result + followUpCardNumber.hashCode() + result = 31 * result + (cardType?.hashCode() ?: 0) + result = 31 * result + (validFrom?.hashCode() ?: 0) + result = 31 * result + (validTo?.hashCode() ?: 0) + result = 31 * result + (mediaName?.hashCode() ?: 0) + return result + } + + + override fun toString(): String { + return super.toString() + " $mediaName $cardNumber (follow up: ${followUpCardNumber ?: "-"})" + } + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMedienArtVersion.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMedienArtVersion.kt new file mode 100644 index 00000000..e99edfd1 --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMedienArtVersion.kt @@ -0,0 +1,19 @@ +package net.dankito.fints.messages.datenelemente.implementierte.tan + +import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum + + +/** + * dient der Klassifizierung der gesamten dem Kunden zugeordneten TAN-Medien. Bei + * Geschäftsvorfällen zum Management des TAN-Generators kann aus diesen nach folgender + * Codierung selektiert werden. + */ +enum class TanMedienArtVersion(override val code: String) : ICodeEnum { + + Alle("0"), + + Aktiv("1"), + + Verfuegbar("2") + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMedium.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMedium.kt new file mode 100644 index 00000000..cbe3fdf2 --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMedium.kt @@ -0,0 +1,40 @@ +package net.dankito.fints.messages.datenelemente.implementierte.tan + + +/** + * Informationen zu Art und Parametrisierung von TAN-Medien. Als TAN-Medien werden sowohl + * TAN-Listen als auch DK-TAN-Generatoren / Karten oder Mobiltelefone sowie bilateral + * vereinbarte Medien bezeichnet. + * + * Wird das Datenelement „TAN-Medium-Klasse“ mit „B“ (bilateral vereinbart) belegt, so muss im Element „Sicherheitsfunktion, kodiert“ die entsprechende Sicherheitsfunktion in der DEG „Verfahrensparameter Zwei-Schritt-Verfahren“ referenziert werden. + */ +open class TanMedium( + val mediumClass: TanMediumKlasseVersion, + val status: TanMediumStatus +) { + + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as TanMedium + + if (mediumClass != other.mediumClass) return false + if (status != other.status) return false + + return true + } + + override fun hashCode(): Int { + var result = mediumClass.hashCode() + result = 31 * result + status.hashCode() + return result + } + + + override fun toString(): String { + return "$mediumClass $status" + } + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMediumKlasseVersion.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMediumKlasseVersion.kt new file mode 100644 index 00000000..c47038a5 --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMediumKlasseVersion.kt @@ -0,0 +1,24 @@ +package net.dankito.fints.messages.datenelemente.implementierte.tan + +import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum + + +/** + * dient der Klassifizierung der möglichen TAN-Medien. Bei Geschäftsvorfällen zum + * Management der TAN-Medien kann aus diesen nach folgender Codierung selektiert werden. + */ +enum class TanMediumKlasseVersion(override val code: String, val supportedHkTabVersions: List) : ICodeEnum { + + AlleMedien("A", listOf(4, 5)), + + Liste("L", listOf(1, 2, 3, 4, 5)), + + TanGenerator("G", listOf(1, 2, 3, 4, 5)), + + MobiltelefonMitMobileTan("M", listOf(2, 3, 4, 5)), + + Secoder("S", listOf(3, 4, 5)), + + BilateralVereinbart("B", listOf(5)) + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMediumStatus.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMediumStatus.kt new file mode 100644 index 00000000..cdb89b89 --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanMediumStatus.kt @@ -0,0 +1,33 @@ +package net.dankito.fints.messages.datenelemente.implementierte.tan + +import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum + + +/** + * Gibt an, in welchem Status sich ein TAN-Medium befindet. + * + */ +enum class TanMediumStatus(override val code: String) : ICodeEnum { + + /** + * Die Bank zeigt an, dass es eine TAN-Verifikation gegen dieses Medium vornimmt. + */ + Aktiv("1"), + + /** + * Das Medium kann genutzt werden, muss aber zuvor mit „TAN-Generator an- bzw. ummelden (HKTAU)“ aktiv gemeldet werden. + */ + Verfuegbar("2"), + + /** + * Mit der ersten Nutzung der Folgekarte wird die zur Zeit aktive Karte gesperrt. + */ + AktivFolgekarte("3"), + + /** + * Das Medium kann mit dem Geschäftsvorfall „TAN-Medium an- bzw. ummelden (HKTAU)“ aktiv gemeldet werden. + * Die aktuelle Karte kann dann nicht mehr genutzt werden. + */ + VerfuegbarFolgekarte("4") + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/id/CustomerSegmentId.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/id/CustomerSegmentId.kt index 8eee646c..90c4e819 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/id/CustomerSegmentId.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/id/CustomerSegmentId.kt @@ -13,6 +13,8 @@ enum class CustomerSegmentId(override val id: String) : ISegmentId { Tan("HKTAN"), + TanMediaList("HKTAB"), + Balance("HKSAL"), AccountTransactionsMt940("HKKAZ"), diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/implementierte/tan/TanGeneratorListeAnzeigen.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/implementierte/tan/TanGeneratorListeAnzeigen.kt new file mode 100644 index 00000000..4cb94fff --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/implementierte/tan/TanGeneratorListeAnzeigen.kt @@ -0,0 +1,34 @@ +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.implementierte.allCodes +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedienArtVersion +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasseVersion +import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf +import net.dankito.fints.messages.segmente.Segment +import net.dankito.fints.messages.segmente.id.CustomerSegmentId + + +open class TanGeneratorListeAnzeigen( + segmentVersion: Int, + segmentNumber: Int, + tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, + tanMediumClass: TanMediumKlasseVersion = TanMediumKlasseVersion.AlleMedien +) + : Segment(listOf( + Segmentkopf(CustomerSegmentId.TanMediaList, segmentVersion, segmentNumber), + Code(tanMediaKind, allCodes(), Existenzstatus.Mandatory), + Code(tanMediumClass, allCodes(), Existenzstatus.Mandatory) +)) { + + init { + val supportedMediaClasses = TanMediumKlasseVersion.values().filter { it.supportedHkTabVersions.contains(segmentVersion) } + + if (supportedMediaClasses.contains(tanMediumClass) == false) { + throw UnsupportedOperationException("Value $tanMediumClass for TAN medium class is not valid for HKTAB version $segmentVersion. " + + "Supported values are: " + TanMediumKlasseVersion.values().filter { it.supportedHkTabVersions.contains(segmentVersion) }.map { it.code }) + } + } + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/InstituteSegmentId.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/InstituteSegmentId.kt index e4344008..7cb66b27 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/InstituteSegmentId.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/InstituteSegmentId.kt @@ -29,6 +29,8 @@ enum class InstituteSegmentId(override val id: String) : ISegmentId { Tan("HITAN"), + TanMediaList("HITAB"), + Balance("HISAL"), AccountTransactionsMt940("HIKAZ") diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt index e0fd0c09..5630eedf 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt @@ -93,6 +93,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.Balance.id -> parseBalanceSegment(segment, dataElementGroups) InstituteSegmentId.AccountTransactionsMt940.id -> parseMt940AccountTransactions(segment, dataElementGroups) @@ -395,6 +396,52 @@ open class ResponseParser @JvmOverloads constructor( ) } + protected open fun parseTanMediaList(segment: String, dataElementGroups: List): TanMediaList { + val usageOption = parseCodeEnum(dataElementGroups[1], TanEinsatzOption.values()) + val segmentVersion = parseInt(getDataElements(dataElementGroups[0])[2]) + + return TanMediaList(usageOption, + parseTanMedia(segmentVersion, dataElementGroups.subList(2, dataElementGroups.size)), + segment) + } + + protected open fun parseTanMedia(hitabVersion: Int, dataElementGroups: List): List { + return dataElementGroups.map { getDataElements(it) }.map { parseTanMedium(hitabVersion, it) } + } + + protected open fun parseTanMedium(hitabVersion: Int, dataElements: List): TanMedium { + val mediumClassCode = dataElements[0] + val mediumClass = parseCodeEnum(mediumClassCode, TanMediumKlasseVersion.values()) + if (mediumClass.supportedHkTabVersions.contains(hitabVersion) == false) { + throw UnsupportedOperationException("$mediumClassCode is not a valid medium class for HITAB version $hitabVersion. " + + "Supported values are: " + TanMediumKlasseVersion.values().filter { it.supportedHkTabVersions.contains(hitabVersion) }.map { it.code }) + } + + val status = parseCodeEnum(dataElements[1], TanMediumStatus.values()) + + // TODO: may also parse 'Letzte Benutzung' (second last element) and 'Freigeschaltet am' (last element) + + val remainingDataElements = dataElements.subList(2, dataElements.size - 2) + + return when (mediumClass) { + TanMediumKlasseVersion.TanGenerator -> parseTanGeneratorTanMedium(mediumClass, status, hitabVersion, remainingDataElements) + else -> TanMedium(mediumClass, status) + } + } + + protected open fun parseTanGeneratorTanMedium(mediumClass: TanMediumKlasseVersion, status: TanMediumStatus, + hitabVersion: Int, dataElements: List): TanGeneratorTanMedium { + + val cardType = if (hitabVersion < 2) null else parseStringToNullIfEmpty(dataElements[2]) // TODO: may parse to number + // 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]) + val mediaName = if (hitabVersion < 2) null else parseStringToNullIfEmpty(dataElements[10]) + + return TanGeneratorTanMedium(mediumClass, status, parseString(dataElements[0]), parseStringToNullIfEmpty(dataElements[1]), + cardType, validFrom, validTo, mediaName) + } + protected open fun parseBalanceSegment(segment: String, dataElementGroups: List): BalanceSegment { // dataElementGroups[1] is account details diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/client/GetTanMediaListResponse.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/client/GetTanMediaListResponse.kt new file mode 100644 index 00000000..a9b237bf --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/client/GetTanMediaListResponse.kt @@ -0,0 +1,11 @@ +package net.dankito.fints.response.client + +import net.dankito.fints.response.Response +import net.dankito.fints.response.segments.TanMediaList + + +open class GetTanMediaListResponse( + response: Response, + val tanMediaList: TanMediaList? +) + : FinTsClientResponse(response) \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/TanMediaList.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/TanMediaList.kt new file mode 100644 index 00000000..a681b2df --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/TanMediaList.kt @@ -0,0 +1,12 @@ +package net.dankito.fints.response.segments + +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanEinsatzOption +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium + + +open class TanMediaList( + val usageOption: TanEinsatzOption, + val tanMedia: List, + segmentString: String +) + : ReceivedSegment(segmentString) \ No newline at end of file diff --git a/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt b/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt index 4b0d19ee..525b9884 100644 --- a/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt +++ b/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt @@ -5,6 +5,9 @@ import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Laenderkennze 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.TanMedienArtVersion +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasseVersion import net.dankito.fints.model.* import net.dankito.fints.model.mapper.BankDataMapper import net.dankito.fints.response.client.FinTsClientResponse @@ -132,6 +135,34 @@ class FinTsClientTest { } + @Test + fun getTanMediaList() { + + // when + val result = underTest.getTanMediaList(Bank, Customer, TanMedienArtVersion.Alle, TanMediumKlasseVersion.AlleMedien) + + + // then + assertThat(result.isSuccessful).isTrue() + + assertThat(result.tanMediaList).isNotNull() + assertThat(result.tanMediaList!!.usageOption).isEqualByComparingTo(TanEinsatzOption.KundeKannGenauEinMediumZuEinerZeitNutzen) // TODO: may adjust to your value + assertThat(result.tanMediaList!!.tanMedia).isNotEmpty() + } + + @Ignore // only works with banks that don't support HKTAB version 5 + @Test(expected = UnsupportedOperationException::class) + fun getTanMediaList_UnsupportedTanMediumClass() { + + // when + underTest.getTanMediaList(Bank, Customer, TanMedienArtVersion.Alle, TanMediumKlasseVersion.BilateralVereinbart) + + + // then + // exception gets thrown + } + + @Test fun testBankTransfer() { diff --git a/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt b/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt index 70932802..d00cfdd0 100644 --- a/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt +++ b/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt @@ -6,7 +6,7 @@ import net.dankito.fints.messages.datenelemente.implementierte.HbciVersion import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsverfahren import net.dankito.fints.messages.datenelemente.implementierte.signatur.VersionDesSicherheitsverfahrens -import net.dankito.fints.messages.datenelemente.implementierte.tan.TanProcess +import net.dankito.fints.messages.datenelemente.implementierte.tan.* import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil import net.dankito.fints.messages.segmente.id.ISegmentId import net.dankito.fints.messages.segmente.id.MessageSegmentId @@ -683,6 +683,33 @@ class ResponseParserTest : FinTsTestBase() { } + @Test + fun parseTanMediaListResponse() { + + // given + val oldCardNumber = "5109972878" + val followUpCardNumber = "5200310149" + val mediaName = "EC-Card (Debitkarte)" + + // when + val result = underTest.parse("HITAB:5:4:3+1+G:3:$oldCardNumber:$followUpCardNumber:::::::::$mediaName::::::::+G:2:$followUpCardNumber::::::::::$mediaName::::::::'") + + // then + assertSuccessfullyParsedSegment(result, InstituteSegmentId.TanMediaList, 5, 4, 3) + + assertThat(result.isStrongAuthenticationRequired).isFalse() + + result.getFirstSegmentById(InstituteSegmentId.TanMediaList)?.let { segment -> + assertThat(segment.usageOption).isEqualTo(TanEinsatzOption.KundeKannGenauEinMediumZuEinerZeitNutzen) + assertThat(segment.tanMedia).containsOnly( + TanGeneratorTanMedium(TanMediumKlasseVersion.TanGenerator, TanMediumStatus.AktivFolgekarte, oldCardNumber, followUpCardNumber, null, null, null, mediaName), + TanGeneratorTanMedium(TanMediumKlasseVersion.TanGenerator, TanMediumStatus.Verfuegbar, followUpCardNumber, null, null, null, null, mediaName) + ) + } + ?: run { Assert.fail("No segment of type TanMediaList found in ${result.receivedSegments}") } + } + + @Test fun parseBalance() {