Implemented parsing PinInfo and setting HKTAN only if required according to PinInfo
This commit is contained in:
parent
de91056094
commit
1859fb2575
|
@ -746,6 +746,10 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
// bank.bic = bankParameters. // TODO: where's the BIC?
|
||||
}
|
||||
|
||||
response.getFirstSegmentById<PinInfo>(InstituteSegmentId.PinInfo)?.let { pinInfo ->
|
||||
bank.pinInfo = pinInfo
|
||||
}
|
||||
|
||||
response.getFirstSegmentById<TanInfo>(InstituteSegmentId.TanInfo)?.let { tanInfo ->
|
||||
bank.supportedTanProcedures = mapToTanProcedures(tanInfo)
|
||||
}
|
||||
|
|
|
@ -105,10 +105,9 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(generator.resetSegmentNumber(2), parameter, account)
|
||||
else KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter, account)
|
||||
|
||||
val segments = listOf(
|
||||
transactionsJob,
|
||||
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.AccountTransactionsMt940)
|
||||
)
|
||||
val segments = mutableListOf<Segment>(transactionsJob)
|
||||
|
||||
addTanSegmentIfRequired(CustomerSegmentId.AccountTransactionsMt940, dialogContext, segments)
|
||||
|
||||
return createMessageBuilderResult(dialogContext, segments)
|
||||
}
|
||||
|
@ -133,10 +132,9 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
val balanceJob = if (result.isAllowed(5)) SaldenabfrageVersion5(generator.resetSegmentNumber(2), account)
|
||||
else SaldenabfrageVersion7(generator.resetSegmentNumber(2), account, dialogContext.bank)
|
||||
|
||||
val segments = listOf(
|
||||
balanceJob,
|
||||
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Balance)
|
||||
)
|
||||
val segments = mutableListOf<Segment>(balanceJob)
|
||||
|
||||
addTanSegmentIfRequired(CustomerSegmentId.Balance, dialogContext, segments)
|
||||
|
||||
return createMessageBuilderResult(dialogContext, segments)
|
||||
}
|
||||
|
@ -208,10 +206,10 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
val urn = messageBuilderResultAndNullableUrn.second
|
||||
|
||||
if (result.isJobVersionSupported && urn != null) {
|
||||
val segments = listOf(
|
||||
SepaBankTransferBase(segmentId, generator.resetSegmentNumber(2), urn, dialogContext.customer, account, dialogContext.bank.bic, data),
|
||||
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, segmentId)
|
||||
)
|
||||
val segments = mutableListOf<Segment>(SepaBankTransferBase(segmentId, generator.resetSegmentNumber(2),
|
||||
urn, dialogContext.customer, account, dialogContext.bank.bic, data))
|
||||
|
||||
addTanSegmentIfRequired(segmentId, dialogContext, segments)
|
||||
|
||||
return createMessageBuilderResult(dialogContext, segments)
|
||||
}
|
||||
|
@ -401,6 +399,18 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
return MessageBuilderResult(false)
|
||||
}
|
||||
|
||||
protected open fun addTanSegmentIfRequired(segmentId: CustomerSegmentId, dialogContext: DialogContext, segments: MutableList<Segment>) {
|
||||
if (isTanRequiredForJob(segmentId, dialogContext)) {
|
||||
segments.add(ZweiSchrittTanEinreichung(
|
||||
generator.getNextSegmentNumber(), TanProcess.TanProcess4, segmentId))
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun isTanRequiredForJob(segmentId: CustomerSegmentId, dialogContext: DialogContext): Boolean {
|
||||
return dialogContext.bank.pinInfo?.jobTanConfiguration?.first { it.segmentId == segmentId.id }?.tanRequired
|
||||
?: false // TODO: actually in this case it's not allowed to execute job via PIN/TAN at all
|
||||
}
|
||||
|
||||
protected open fun getSepaUrnFor(segmentId: CustomerSegmentId, account: AccountData, sepaDataFormat: String): String? {
|
||||
|
||||
return getAllowedJobs(segmentId, account)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
|
||||
open class JobTanConfiguration(
|
||||
val segmentId: String,
|
||||
val tanRequired: Boolean
|
||||
) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$segmentId requires TAN? $tanRequired"
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ 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
|
||||
import net.dankito.fints.response.segments.PinInfo
|
||||
|
||||
|
||||
open class BankData(
|
||||
|
@ -24,6 +25,7 @@ open class BankData(
|
|||
var supportedHbciVersions: List<HbciVersion> = listOf(),
|
||||
var supportedTanProcedures: List<TanProcedure> = listOf(),
|
||||
var changeTanMediumParameters: ChangeTanMediaParameters? = null,
|
||||
var pinInfo: PinInfo? = null,
|
||||
var supportedLanguages: List<Dialogsprache> = listOf(),
|
||||
var supportedJobs: List<JobParameters> = listOf()
|
||||
) {
|
||||
|
|
|
@ -25,6 +25,8 @@ enum class InstituteSegmentId(override val id: String) : ISegmentId {
|
|||
|
||||
SepaAccountInfoParameters("HISPAS"),
|
||||
|
||||
PinInfo("HIPINS"),
|
||||
|
||||
TanInfo("HITANS"),
|
||||
|
||||
Tan("HITAN"),
|
||||
|
|
|
@ -89,6 +89,7 @@ open class ResponseParser @JvmOverloads constructor(
|
|||
InstituteSegmentId.SepaAccountInfo.id -> parseSepaAccountInfo(segment, dataElementGroups)
|
||||
InstituteSegmentId.SepaAccountInfoParameters.id -> parseSepaAccountInfoParameters(segment, segmentId, dataElementGroups)
|
||||
|
||||
InstituteSegmentId.PinInfo.id -> parsePinInfo(segment, segmentId, dataElementGroups)
|
||||
InstituteSegmentId.TanInfo.id -> parseTanInfo(segment, segmentId, dataElementGroups)
|
||||
InstituteSegmentId.Tan.id -> parseTanResponse(segment, dataElementGroups)
|
||||
InstituteSegmentId.TanMediaList.id -> parseTanMediaList(segment, dataElementGroups)
|
||||
|
@ -304,6 +305,31 @@ open class ResponseParser @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
protected open fun parsePinInfo(segment: String, segmentId: String, dataElementGroups: List<String>): PinInfo {
|
||||
val jobParameters = parseJobParameters(segment, segmentId, dataElementGroups)
|
||||
|
||||
val dataElements = getDataElements(dataElementGroups[4])
|
||||
|
||||
val minPinLength = parseIntToNullIfEmpty(dataElements[0])
|
||||
val maxPinLength = parseIntToNullIfEmpty(dataElements[1])
|
||||
val minTanLength = parseIntToNullIfEmpty(dataElements[2])
|
||||
val userIdHint = parseStringToNullIfEmpty(dataElements[3])
|
||||
val customerIdHint = parseStringToNullIfEmpty(dataElements[4])
|
||||
|
||||
return PinInfo(jobParameters, minPinLength, maxPinLength, minTanLength, userIdHint, customerIdHint,
|
||||
parseJobTanConfigurations(dataElements.subList(5, dataElements.size)))
|
||||
}
|
||||
|
||||
protected open fun parseJobTanConfigurations(dataElementGroups: List<String>): List<JobTanConfiguration> {
|
||||
return dataElementGroups.chunked(2).map {
|
||||
JobTanConfiguration(
|
||||
parseString(it[0]),
|
||||
parseBoolean(it[1])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected open fun parseTanInfo(segment: String, segmentId: String, dataElementGroups: List<String>): TanInfo? {
|
||||
val jobParameters = parseJobParameters(segment, segmentId, dataElementGroups)
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package net.dankito.fints.response.segments
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.JobTanConfiguration
|
||||
|
||||
|
||||
open class PinInfo(
|
||||
parameters: JobParameters,
|
||||
val minPinLength: Int?,
|
||||
val maxPinLength: Int?,
|
||||
val minTanLength: Int?,
|
||||
val userIdHint: String?,
|
||||
val customerIdHint: String?,
|
||||
val jobTanConfiguration: List<JobTanConfiguration>
|
||||
)
|
||||
: JobParameters(parameters)
|
|
@ -660,6 +660,30 @@ class ResponseParserTest : FinTsTestBase() {
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun parsePinInfo() {
|
||||
|
||||
// when
|
||||
val result = underTest.parse("HIPINS:49:1:4+1+1+0+5:20:6:VR-NetKey oder Alias::HKTAN:N:HKKAZ:J:HKSAL:N:HKEKA:N:HKPAE:J:HKPSP:N:HKQTG:N:HKCSA:J:HKCSB:N:HKCSL:J:HKCSE:J:HKCCS:J:HKSPA:N:HKCCM:J:HKCDB:N:HKCDL:J:HKPPD:J:HKCDN:J:HKDSB:N:HKCUB:N:HKCUM:J:HKCDE:J:HKDSW:J:HKCME:J:HKCMB:N:HKCML:J:HKWPD:N:HKWDU:N:HKKAU:N:HKKIF:N:HKCAZ:J:HKKAA:N:HKPOF:N:HKIPS:N:HKIPZ:J:GKVPU:N:GKVPD:N'")
|
||||
|
||||
// then
|
||||
assertSuccessfullyParsedSegment(result, InstituteSegmentId.PinInfo, 49, 1, 4)
|
||||
|
||||
result.getFirstSegmentById<PinInfo>(InstituteSegmentId.PinInfo)?.let { segment ->
|
||||
assertThat(segment.minPinLength).isEqualTo(5)
|
||||
assertThat(segment.maxPinLength).isEqualTo(20)
|
||||
assertThat(segment.minTanLength).isEqualTo(6)
|
||||
assertThat(segment.userIdHint).isEqualTo("VR-NetKey oder Alias")
|
||||
assertThat(segment.customerIdHint).isNull()
|
||||
|
||||
assertThat(segment.jobTanConfiguration).hasSize(37)
|
||||
assertThat(segment.jobTanConfiguration.first { it.segmentId == "HKKAZ" }.tanRequired).isTrue()
|
||||
assertThat(segment.jobTanConfiguration.first { it.segmentId == "HKSAL" }.tanRequired).isFalse()
|
||||
}
|
||||
?: run { Assert.fail("No segment of type PinInfo found in ${result.receivedSegments}") }
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun parseTanInfo() {
|
||||
|
||||
|
@ -936,7 +960,7 @@ class ResponseParserTest : FinTsTestBase() {
|
|||
assertThat(segment.accountProductName).isEqualTo(accountProductName)
|
||||
assertThat(segment.balanceOfPreBookedTransactions).isNull()
|
||||
}
|
||||
?: run { Assert.fail("No segment of type Balance found in ${result.receivedSegments}") }
|
||||
?: run { Assert.fail("No segment of type BalanceSegment found in ${result.receivedSegments}") }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -963,7 +987,7 @@ class ResponseParserTest : FinTsTestBase() {
|
|||
assertThat(segment.accountProductName).isEqualTo(accountProductName)
|
||||
assertThat(segment.balanceOfPreBookedTransactions).isNull()
|
||||
}
|
||||
?: run { Assert.fail("No segment of type Balance found in ${result.receivedSegments}") }
|
||||
?: run { Assert.fail("No segment of type BalanceSegment found in ${result.receivedSegments}") }
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue