diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/Response.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/Response.kt index ec17e146..d720cfdb 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/Response.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/Response.kt @@ -2,6 +2,7 @@ package net.dankito.fints.response import net.dankito.fints.messages.MessageBuilderResult import net.dankito.fints.messages.Separators +import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion import net.dankito.fints.messages.segmente.id.ISegmentId import net.dankito.fints.messages.segmente.id.MessageSegmentId import net.dankito.fints.response.segments.* @@ -72,6 +73,11 @@ open class Response constructor( open val supportedJobs: List get() = receivedSegments.mapNotNull { it as? SupportedJob } + open val supportedTanProceduresForUser: List + get() = segmentFeedbacks.flatMap { it.feedbacks } + .filterIsInstance() + .flatMap { it.supportedTanProcedures } + open fun getFirstSegmentById(id: ISegmentId): T? { return getFirstSegmentById(id.id) 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 548938fc..6a4bbb05 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt @@ -34,6 +34,10 @@ open class ResponseParser @JvmOverloads constructor( val AllowedJobSegmentPattern = Pattern.compile("HI[A-Z]{3}S") + val FeedbackParametersSeparator = "; " + + val SupportedTanProceduresForUserResponseCode = 3920 + private val log = LoggerFactory.getLogger(ResponseParser::class.java) } @@ -124,12 +128,18 @@ open class ResponseParser @JvmOverloads constructor( protected open fun parseFeedback(dataElementGroup: String): Feedback { val dataElements = getDataElements(dataElementGroup) - return Feedback( - parseInt(dataElements[0]), - parseString(dataElements[2]), - parseStringToNullIfEmpty(dataElements[1]), - if (dataElements.size > 3) parseStringToNullIfEmpty(dataElements[3]) else null - ) + val responseCode = parseInt(dataElements[0]) + val referencedDataElement = parseStringToNullIfEmpty(dataElements[1]) + val message = parseString(dataElements[2]) + + if (responseCode == SupportedTanProceduresForUserResponseCode) { + val supportedProcedures = parseCodeEnum(dataElements.subList(3, dataElements.size), Sicherheitsfunktion.values()) + return SupportedTanProceduresForUserFeedback(supportedProcedures, message) + } + + val parameter = if (dataElements.size > 3) dataElements.subList(3, dataElements.size).joinToString(FeedbackParametersSeparator) else null + + return Feedback(responseCode, message, referencedDataElement, parameter) } protected open fun parseSynchronization(segment: String, dataElementGroups: List): ReceivedSynchronization { diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/Feedback.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/Feedback.kt index e21a089c..9c3bffb1 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/Feedback.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/Feedback.kt @@ -33,9 +33,9 @@ open class Feedback( * Segmentkopf+DE+GD:GD:GD:|GD|+DE+GD:GD’ : 3,4 * Segmentkopf+DE+GD:GD:GD:GD+DE+GD:|GD|’ : 5,2 */ - val referencedDataElement: String?, + val referencedDataElement: String? = null, - val parameter: String? + val parameter: String? = null ) { diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/SupportedTanProceduresForUserFeedback.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/SupportedTanProceduresForUserFeedback.kt new file mode 100644 index 00000000..c1c4197c --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/SupportedTanProceduresForUserFeedback.kt @@ -0,0 +1,10 @@ +package net.dankito.fints.response.segments + +import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion +import net.dankito.fints.response.ResponseParser + +open class SupportedTanProceduresForUserFeedback( + val supportedTanProcedures: List, + message: String +) + : Feedback(ResponseParser.SupportedTanProceduresForUserResponseCode, message) \ No newline at end of file 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 dace47a2..872b2b1b 100644 --- a/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt +++ b/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt @@ -3,6 +3,7 @@ package net.dankito.fints.response import net.dankito.fints.FinTsTestBase import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache 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 @@ -207,6 +208,55 @@ class ResponseParserTest : FinTsTestBase() { } + @Test + fun parseSegmentFeedback_AllowedUserTanProcedures() { + + // when + val result = underTest.parse("HIRMS:4:2:4+3050::BPD nicht mehr aktuell, aktuelle Version enthalten.+3920::Zugelassene Zwei-Schritt-Verfahren für den Benutzer.:910:911:912:913+0020::Der Auftrag wurde ausgeführt.") + + + // then + assertCouldParseSegment(result, InstituteSegmentId.SegmentFeedback, 4, 2, 4) + + assertThat(result.segmentFeedbacks).hasSize(1) + + assertThat(result.supportedTanProceduresForUser).containsExactlyInAnyOrder(Sicherheitsfunktion.PIN_TAN_910, + Sicherheitsfunktion.PIN_TAN_911, Sicherheitsfunktion.PIN_TAN_912, Sicherheitsfunktion.PIN_TAN_913) + + val segmentFeedback = result.segmentFeedbacks.first() + + assertThat(segmentFeedback.feedbacks).hasSize(3) + + val firstFeedback = segmentFeedback.feedbacks[0] + assertThat(firstFeedback.responseCode).isEqualTo(3050) + assertThat(firstFeedback.isSuccess).isFalse() + assertThat(firstFeedback.isWarning).isTrue() + assertThat(firstFeedback.isError).isFalse() + assertThat(firstFeedback.message).isEqualTo("BPD nicht mehr aktuell, aktuelle Version enthalten.") + assertThat(firstFeedback.parameter).isNull() + + val secondFeedback = segmentFeedback.feedbacks[1] + assertThat(secondFeedback is SupportedTanProceduresForUserFeedback).isTrue() + assertThat((secondFeedback as SupportedTanProceduresForUserFeedback).supportedTanProcedures) + .containsExactlyInAnyOrder(Sicherheitsfunktion.PIN_TAN_910,Sicherheitsfunktion.PIN_TAN_911, + Sicherheitsfunktion.PIN_TAN_912, Sicherheitsfunktion.PIN_TAN_913) + assertThat(secondFeedback.responseCode).isEqualTo(3920) + assertThat(secondFeedback.isSuccess).isFalse() + assertThat(secondFeedback.isWarning).isTrue() + assertThat(secondFeedback.isError).isFalse() + assertThat(secondFeedback.message).isEqualTo("Zugelassene Zwei-Schritt-Verfahren für den Benutzer.") + assertThat(secondFeedback.parameter).isNull() + + val thirdFeedback = segmentFeedback.feedbacks[2] + assertThat(thirdFeedback.responseCode).isEqualTo(20) + assertThat(thirdFeedback.isSuccess).isTrue() + assertThat(thirdFeedback.isWarning).isFalse() + assertThat(thirdFeedback.isError).isFalse() + assertThat(thirdFeedback.message).isEqualTo("Der Auftrag wurde ausgeführt.") + assertThat(thirdFeedback.parameter).isNull() + } + + @Test fun parseSynchronization() {