Made IWebClient and FinTsClient async so that on iOS everything but the web request can run on the main thread -> we don't need to freeze objects to pass them between threads
This commit is contained in:
parent
27dd8c98cc
commit
8e221f17ce
|
@ -74,7 +74,7 @@ open class FinTsClient(
|
||||||
open fun getAnonymousBankInfoAsync(bank: BankData, callback: (FinTsClientResponse) -> Unit) {
|
open fun getAnonymousBankInfoAsync(bank: BankData, callback: (FinTsClientResponse) -> Unit) {
|
||||||
|
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
callback(getAnonymousBankInfo(bank))
|
getAnonymousBankInfo(bank, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,20 +84,20 @@ open class FinTsClient(
|
||||||
*
|
*
|
||||||
* 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, callback: (FinTsClientResponse) -> Unit) {
|
||||||
val dialogContext = DialogContext(bank, CustomerData.Anonymous, product)
|
val dialogContext = DialogContext(bank, CustomerData.Anonymous, product)
|
||||||
|
|
||||||
val message = messageBuilder.createAnonymousDialogInitMessage(dialogContext)
|
val message = messageBuilder.createAnonymousDialogInitMessage(dialogContext)
|
||||||
|
|
||||||
val response = getAndHandleResponseForMessage(message, dialogContext)
|
getAndHandleResponseForMessage(message, dialogContext) { response ->
|
||||||
|
|
||||||
if (response.successful) {
|
if (response.successful) {
|
||||||
updateBankData(bank, response)
|
updateBankData(bank, response)
|
||||||
|
|
||||||
closeAnonymousDialog(dialogContext, response)
|
closeAnonymousDialog(dialogContext, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
return FinTsClientResponse(response)
|
callback(FinTsClientResponse(response))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun closeAnonymousDialog(dialogContext: DialogContext, response: Response) {
|
protected open fun closeAnonymousDialog(dialogContext: DialogContext, response: Response) {
|
||||||
|
@ -113,7 +113,7 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun getBankAndCustomerInfoForNewUser(bank: BankData, customer: CustomerData): AddAccountResponse {
|
open fun getBankAndCustomerInfoForNewUser(bank: BankData, customer: CustomerData, callback: (AddAccountResponse) -> Unit) {
|
||||||
// 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()
|
||||||
|
@ -128,16 +128,17 @@ open class FinTsClient(
|
||||||
|
|
||||||
val dialogContext = DialogContext(bank, customer, product)
|
val dialogContext = DialogContext(bank, customer, product)
|
||||||
|
|
||||||
val initDialogResponse = initDialogAfterSuccessfulChecks(dialogContext)
|
initDialogAfterSuccessfulChecks(dialogContext) { initDialogResponse ->
|
||||||
|
|
||||||
closeDialog(dialogContext)
|
closeDialog(dialogContext)
|
||||||
|
|
||||||
// even though it is required by specification some banks don't support retrieving user's TAN procedure by setting TAN procedure to '999'
|
// even though it is required by specification some banks don't support retrieving user's TAN procedure by setting TAN procedure to '999'
|
||||||
if (bankDoesNotSupportRetrievingUsersTanProcedures(initDialogResponse)) {
|
if (bankDoesNotSupportRetrievingUsersTanProcedures(initDialogResponse)) {
|
||||||
return getBankAndCustomerInfoForNewUserViaAnonymousDialog(bank, customer)
|
getBankAndCustomerInfoForNewUserViaAnonymousDialog(bank, customer, callback)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(AddAccountResponse(initDialogResponse, bank, customer))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return AddAccountResponse(initDialogResponse, bank, customer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun bankDoesNotSupportRetrievingUsersTanProcedures(response: Response): Boolean {
|
protected open fun bankDoesNotSupportRetrievingUsersTanProcedures(response: Response): Boolean {
|
||||||
|
@ -147,27 +148,28 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is only a quick fix. Find a better and general solution
|
// TODO: this is only a quick fix. Find a better and general solution
|
||||||
protected open fun getBankAndCustomerInfoForNewUserViaAnonymousDialog(bank: BankData, customer: CustomerData): AddAccountResponse {
|
protected open fun getBankAndCustomerInfoForNewUserViaAnonymousDialog(bank: BankData, customer: CustomerData, callback: (AddAccountResponse) -> Unit) {
|
||||||
val anonymousBankInfoResponse = getAnonymousBankInfo(bank)
|
getAnonymousBankInfo(bank) { anonymousBankInfoResponse ->
|
||||||
|
|
||||||
if (anonymousBankInfoResponse.isSuccessful == false) {
|
if (anonymousBankInfoResponse.isSuccessful == false) {
|
||||||
return AddAccountResponse(anonymousBankInfoResponse.toResponse(), bank, customer)
|
callback(AddAccountResponse(anonymousBankInfoResponse.toResponse(), bank, customer))
|
||||||
}
|
}
|
||||||
else if (bank.supportedTanProcedures.isEmpty()) { // should only be a theoretical error
|
else if (bank.supportedTanProcedures.isEmpty()) { // should only be a theoretical error
|
||||||
return AddAccountResponse(Response(true,
|
callback(AddAccountResponse(Response(true,
|
||||||
exception = Exception("Die TAN Verfahren der Bank konnten nicht ermittelt werden")), bank, customer) // TODO: translate
|
exception = Exception("Die TAN Verfahren der Bank konnten nicht ermittelt werden")), bank, customer)) // TODO: translate
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
customer.supportedTanProcedures = bank.supportedTanProcedures
|
customer.supportedTanProcedures = bank.supportedTanProcedures
|
||||||
getUsersTanProcedure(customer)
|
getUsersTanProcedure(customer)
|
||||||
|
|
||||||
val dialogContext = DialogContext(bank, customer, product)
|
val dialogContext = DialogContext(bank, customer, product)
|
||||||
|
|
||||||
val initDialogResponse = initDialogAfterSuccessfulChecks(dialogContext)
|
initDialogAfterSuccessfulChecks(dialogContext) { initDialogResponse ->
|
||||||
|
|
||||||
closeDialog(dialogContext)
|
closeDialog(dialogContext)
|
||||||
|
|
||||||
return AddAccountResponse(initDialogResponse, bank, customer)
|
callback(AddAccountResponse(initDialogResponse, bank, customer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,13 +184,12 @@ open class FinTsClient(
|
||||||
*
|
*
|
||||||
* If you change customer system id during a dialog your messages get rejected by bank institute.
|
* If you change customer system id during a dialog your messages get rejected by bank institute.
|
||||||
*/
|
*/
|
||||||
protected open fun synchronizeCustomerSystemId(bank: BankData, customer: CustomerData): FinTsClientResponse {
|
protected open fun synchronizeCustomerSystemId(bank: BankData, customer: CustomerData, callback: (FinTsClientResponse) -> Unit) {
|
||||||
|
|
||||||
val dialogContext = DialogContext(bank, customer, product)
|
val dialogContext = DialogContext(bank, customer, product)
|
||||||
val message = messageBuilder.createSynchronizeCustomerSystemIdMessage(dialogContext)
|
val message = messageBuilder.createSynchronizeCustomerSystemIdMessage(dialogContext)
|
||||||
|
|
||||||
val response = getAndHandleResponseForMessage(message, dialogContext)
|
getAndHandleResponseForMessage(message, dialogContext) { response ->
|
||||||
|
|
||||||
if (response.successful) {
|
if (response.successful) {
|
||||||
updateBankData(bank, response)
|
updateBankData(bank, response)
|
||||||
updateCustomerData(customer, bank, response)
|
updateCustomerData(customer, bank, response)
|
||||||
|
@ -196,7 +197,8 @@ open class FinTsClient(
|
||||||
closeDialog(dialogContext)
|
closeDialog(dialogContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
return FinTsClientResponse(response)
|
callback(FinTsClientResponse(response))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,21 +206,21 @@ open class FinTsClient(
|
||||||
callback: (AddAccountResponse) -> Unit) {
|
callback: (AddAccountResponse) -> Unit) {
|
||||||
|
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
callback(addAccount(bank, customer))
|
addAccount(bank, customer, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun addAccount(bank: BankData, customer: CustomerData): AddAccountResponse {
|
open fun addAccount(bank: BankData, customer: CustomerData, callback: (AddAccountResponse) -> Unit) {
|
||||||
|
|
||||||
val originalAreWeThatGentleToCloseDialogs = areWeThatGentleToCloseDialogs
|
val originalAreWeThatGentleToCloseDialogs = areWeThatGentleToCloseDialogs
|
||||||
areWeThatGentleToCloseDialogs = false
|
areWeThatGentleToCloseDialogs = false
|
||||||
|
|
||||||
/* First dialog: Get user's basic data like her TAN procedures */
|
/* First dialog: Get user's basic data like her TAN procedures */
|
||||||
|
|
||||||
val newUserInfoResponse = getBankAndCustomerInfoForNewUser(bank, customer)
|
getBankAndCustomerInfoForNewUser(bank, customer) { newUserInfoResponse ->
|
||||||
|
|
||||||
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
|
||||||
return newUserInfoResponse
|
callback(newUserInfoResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -241,7 +243,7 @@ open class FinTsClient(
|
||||||
|
|
||||||
/* Third dialog: Get customer TAN media list - last step that can and must be done without strong customer authorization */
|
/* Third dialog: Get customer TAN media list - last step that can and must be done without strong customer authorization */
|
||||||
|
|
||||||
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 */
|
/* Fourth dialog: Try to retrieve account transactions of last 90 days without TAN */
|
||||||
|
@ -249,14 +251,31 @@ open class FinTsClient(
|
||||||
// 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, Money>()
|
val balances = mutableMapOf<AccountData, Money>()
|
||||||
|
val countAccountSupportingRetrievingTransactions = customer.accounts.filter { it.supportsFeature(AccountFeature.RetrieveAccountTransactions) }.size
|
||||||
|
var countRetrievedAccounts = 0
|
||||||
|
|
||||||
customer.accounts.forEach { account ->
|
customer.accounts.forEach { account ->
|
||||||
if (account.supportsFeature(AccountFeature.RetrieveAccountTransactions)) {
|
if (account.supportsFeature(AccountFeature.RetrieveAccountTransactions)) {
|
||||||
val response = tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false)
|
tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false) { response ->
|
||||||
transactionsOfLast90DaysResponses.add(response)
|
transactionsOfLast90DaysResponses.add(response)
|
||||||
response.balance?.let { balances.put(account, it) }
|
response.balance?.let { balances.put(account, it) }
|
||||||
|
|
||||||
|
countRetrievedAccounts++
|
||||||
|
if (countRetrievedAccounts == countAccountSupportingRetrievingTransactions) {
|
||||||
|
addAccountAfterRetrievingTransactions(bank, customer, newUserInfoResponse, didOverwriteUserUnselectedTanProcedure, originalAreWeThatGentleToCloseDialogs,
|
||||||
|
transactionsOfLast90DaysResponses, balances, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun addAccountAfterRetrievingTransactions(bank: BankData, customer: CustomerData, newUserInfoResponse: AddAccountResponse,
|
||||||
|
didOverwriteUserUnselectedTanProcedure: Boolean, originalAreWeThatGentleToCloseDialogs: Boolean,
|
||||||
|
transactionsOfLast90DaysResponses: MutableList<GetTransactionsResponse>,
|
||||||
|
balances: MutableMap<AccountData, Money>, callback: (AddAccountResponse) -> Unit) {
|
||||||
if (didOverwriteUserUnselectedTanProcedure) {
|
if (didOverwriteUserUnselectedTanProcedure) {
|
||||||
customer.resetSelectedTanProcedure()
|
customer.resetSelectedTanProcedure()
|
||||||
}
|
}
|
||||||
|
@ -267,8 +286,8 @@ open class FinTsClient(
|
||||||
val unbookedTransactions = transactionsOfLast90DaysResponses.flatMap { it.unbookedTransactions }
|
val unbookedTransactions = transactionsOfLast90DaysResponses.flatMap { it.unbookedTransactions }
|
||||||
val bookedTransactions = transactionsOfLast90DaysResponses.flatMap { it.bookedTransactions }
|
val bookedTransactions = transactionsOfLast90DaysResponses.flatMap { it.bookedTransactions }
|
||||||
|
|
||||||
return AddAccountResponse(newUserInfoResponse.toResponse(), bank, customer,
|
callback(AddAccountResponse(newUserInfoResponse.toResponse(), bank, customer,
|
||||||
supportsRetrievingTransactionsOfLast90DaysWithoutTan, bookedTransactions, unbookedTransactions, balances)
|
supportsRetrievingTransactionsOfLast90DaysWithoutTan, bookedTransactions, unbookedTransactions, balances))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -278,19 +297,17 @@ open class FinTsClient(
|
||||||
*
|
*
|
||||||
* Check if bank supports this.
|
* Check if bank supports this.
|
||||||
*/
|
*/
|
||||||
open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData): GetTransactionsResponse {
|
open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
return tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false)
|
tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData,
|
protected open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData,
|
||||||
hasRetrievedTransactionsWithTanJustBefore: Boolean): GetTransactionsResponse {
|
hasRetrievedTransactionsWithTanJustBefore: Boolean, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
|
|
||||||
val now = Date()
|
val now = Date()
|
||||||
val ninetyDaysAgo = Date(now.millisSinceEpoch - NinetyDaysMillis)
|
val ninetyDaysAgo = Date(now.millisSinceEpoch - NinetyDaysMillis)
|
||||||
|
|
||||||
val response = getTransactions(GetTransactionsParameter(account.supportsFeature(AccountFeature.RetrieveBalance), ninetyDaysAgo, abortIfTanIsRequired = true), bank, customer, account)
|
getTransactions(GetTransactionsParameter(account.supportsFeature(AccountFeature.RetrieveBalance), ninetyDaysAgo, abortIfTanIsRequired = true), bank, customer, account) { response ->
|
||||||
|
|
||||||
|
|
||||||
account.triedToRetrieveTransactionsOfLast90DaysWithoutTan = true
|
account.triedToRetrieveTransactionsOfLast90DaysWithoutTan = true
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
|
@ -300,44 +317,47 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
callback(response)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getTransactionsAsync(parameter: GetTransactionsParameter, bank: BankData,
|
open fun getTransactionsAsync(parameter: GetTransactionsParameter, bank: BankData,
|
||||||
customer: CustomerData, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
|
customer: CustomerData, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
|
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
callback(getTransactions(parameter, bank, customer, account))
|
getTransactions(parameter, bank, customer, account, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getTransactions(parameter: GetTransactionsParameter, bank: BankData,
|
open fun getTransactions(parameter: GetTransactionsParameter, bank: BankData,
|
||||||
customer: CustomerData, account: AccountData): GetTransactionsResponse {
|
customer: CustomerData, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
|
|
||||||
val dialogContext = DialogContext(bank, customer, product)
|
val dialogContext = DialogContext(bank, customer, product)
|
||||||
|
|
||||||
val initDialogResponse = initDialog(dialogContext)
|
initDialog(dialogContext) { initDialogResponse ->
|
||||||
|
|
||||||
if (initDialogResponse.successful == false) {
|
if (initDialogResponse.successful == false) {
|
||||||
return GetTransactionsResponse(initDialogResponse)
|
callback(GetTransactionsResponse(initDialogResponse))
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
mayGetBalance(parameter, account, dialogContext) { balanceResponse ->
|
||||||
var balance: Money? = null
|
|
||||||
|
|
||||||
if (parameter.alsoRetrieveBalance && account.supportsFeature(AccountFeature.RetrieveBalance)) {
|
|
||||||
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(dialogContext)
|
closeDialog(dialogContext)
|
||||||
return GetTransactionsResponse(balanceResponse)
|
callback(GetTransactionsResponse(balanceResponse))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
getTransactionsAfterInitAndGetBalance(parameter, account, dialogContext, balanceResponse, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
balanceResponse.getFirstSegmentById<BalanceSegment>(InstituteSegmentId.Balance)?.let {
|
|
||||||
balance = Money(it.balance, it.currency)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun getTransactionsAfterInitAndGetBalance(parameter: GetTransactionsParameter, account: AccountData, dialogContext: DialogContext,
|
||||||
|
balanceResponse: Response, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
|
val balance: Money? = balanceResponse.getFirstSegmentById<BalanceSegment>(InstituteSegmentId.Balance)?.let {
|
||||||
|
Money(it.balance, it.currency)
|
||||||
|
}
|
||||||
|
|
||||||
val message = messageBuilder.createGetTransactionsMessage(parameter, account, dialogContext)
|
val message = messageBuilder.createGetTransactionsMessage(parameter, account, dialogContext)
|
||||||
|
|
||||||
|
@ -357,28 +377,34 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val response = getAndHandleResponseForMessage(message, dialogContext)
|
getAndHandleResponseForMessage(message, dialogContext) { response ->
|
||||||
|
|
||||||
closeDialog(dialogContext)
|
closeDialog(dialogContext)
|
||||||
|
|
||||||
|
|
||||||
// just retrieved all transactions -> check if retrieving that ones of last 90 days is possible without entering TAN
|
// just retrieved all transactions -> check if retrieving that ones of last 90 days is possible without entering TAN
|
||||||
if (account.supportsRetrievingTransactionsOfLast90DaysWithoutTan == null &&
|
if (account.supportsRetrievingTransactionsOfLast90DaysWithoutTan == null &&
|
||||||
response.successful && bookedTransactions.isNotEmpty() && parameter.fromDate == null) {
|
response.successful && bookedTransactions.isNotEmpty() && parameter.fromDate == null) {
|
||||||
tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, true)
|
tryGetTransactionsOfLast90DaysWithoutTan(dialogContext.bank, dialogContext.customer, account, true) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetTransactionsResponse(response,
|
callback(GetTransactionsResponse(
|
||||||
|
response,
|
||||||
bookedTransactions,
|
bookedTransactions,
|
||||||
listOf(), // TODO: implement parsing MT942
|
listOf(), // TODO: implement parsing MT942
|
||||||
balance)
|
balance
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getBalanceAfterDialogInit(account: AccountData, dialogContext: DialogContext): Response {
|
protected open fun mayGetBalance(parameter: GetTransactionsParameter, account: AccountData, dialogContext: DialogContext, callback: (Response) -> Unit) {
|
||||||
|
if (parameter.alsoRetrieveBalance && account.supportsFeature(AccountFeature.RetrieveBalance)) {
|
||||||
val message = messageBuilder.createGetBalanceMessage(account, dialogContext)
|
val message = messageBuilder.createGetBalanceMessage(account, dialogContext)
|
||||||
|
|
||||||
return getAndHandleResponseForMessage(message, dialogContext)
|
getAndHandleResponseForMessage(message, dialogContext) { response ->
|
||||||
|
callback(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -388,17 +414,16 @@ open class FinTsClient(
|
||||||
callback: (GetTanMediaListResponse) -> Unit) {
|
callback: (GetTanMediaListResponse) -> Unit) {
|
||||||
|
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
callback(getTanMediaList(bank, customer))
|
getTanMediaList(bank, customer, tanMediaKind, tanMediumClass, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, callback: (GetTanMediaListResponse) -> Unit) {
|
||||||
|
|
||||||
val response = sendMessageAndHandleResponse(bank, customer) { dialogContext ->
|
sendMessageAndHandleResponse(bank, customer, true, { dialogContext ->
|
||||||
messageBuilder.createGetTanMediaListMessage(dialogContext, tanMediaKind, tanMediumClass)
|
messageBuilder.createGetTanMediaListMessage(dialogContext, tanMediaKind, tanMediumClass)
|
||||||
}
|
}) { response ->
|
||||||
|
|
||||||
// TAN media list (= TAN generator list) is only returned for users with chipTAN TAN procedures
|
// TAN media list (= TAN generator list) is only returned for users with chipTAN TAN procedures
|
||||||
val tanMediaList = if (response.successful == false ) null
|
val tanMediaList = if (response.successful == false ) null
|
||||||
else response.getFirstSegmentById<TanMediaList>(InstituteSegmentId.TanMediaList)
|
else response.getFirstSegmentById<TanMediaList>(InstituteSegmentId.TanMediaList)
|
||||||
|
@ -407,31 +432,32 @@ open class FinTsClient(
|
||||||
customer.tanMedia = it.tanMedia
|
customer.tanMedia = it.tanMedia
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetTanMediaListResponse(response, tanMediaList)
|
callback(GetTanMediaListResponse(response, tanMediaList))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData): FinTsClientResponse {
|
open fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData, callback: (FinTsClientResponse) -> Unit) {
|
||||||
|
|
||||||
var enteredAtc: EnterTanGeneratorAtcResult? = null
|
var enteredAtc: EnterTanGeneratorAtcResult? = null
|
||||||
|
|
||||||
if (bank.changeTanMediumParameters?.enteringAtcAndTanRequired == true) {
|
if (bank.changeTanMediumParameters?.enteringAtcAndTanRequired == true) {
|
||||||
enteredAtc = callback.enterTanGeneratorAtc(customer, newActiveTanMedium)
|
enteredAtc = this.callback.enterTanGeneratorAtc(customer, newActiveTanMedium)
|
||||||
|
|
||||||
if (enteredAtc.hasAtcBeenEntered == false) {
|
if (enteredAtc.hasAtcBeenEntered == false) {
|
||||||
val message = "Bank requires to enter ATC and TAN in order to change TAN medium." // TODO: translate
|
val message = "Bank requires to enter ATC and TAN in order to change TAN medium." // TODO: translate
|
||||||
return FinTsClientResponse(Response(false, exception = Exception(message)))
|
callback(FinTsClientResponse(Response(false, exception = Exception(message))))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val response = sendMessageAndHandleResponse(bank, customer, false) { dialogContext ->
|
sendMessageAndHandleResponse(bank, customer, false, { dialogContext ->
|
||||||
messageBuilder.createChangeTanMediumMessage(newActiveTanMedium, dialogContext,
|
messageBuilder.createChangeTanMediumMessage(newActiveTanMedium, dialogContext,
|
||||||
enteredAtc?.tan, enteredAtc?.atc)
|
enteredAtc?.tan, enteredAtc?.atc)
|
||||||
|
}) { response ->
|
||||||
|
callback(FinTsClientResponse(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return FinTsClientResponse(response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -439,66 +465,69 @@ open class FinTsClient(
|
||||||
customer: CustomerData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
|
customer: CustomerData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
|
||||||
|
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
callback(doBankTransfer(bankTransferData, bank, customer, account))
|
doBankTransfer(bankTransferData, bank, customer, account, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun doBankTransfer(bankTransferData: BankTransferData, bank: BankData,
|
open fun doBankTransfer(bankTransferData: BankTransferData, bank: BankData,
|
||||||
customer: CustomerData, account: AccountData): FinTsClientResponse {
|
customer: CustomerData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
|
||||||
|
|
||||||
val response = sendMessageAndHandleResponse(bank, customer) { dialogContext ->
|
sendMessageAndHandleResponse(bank, customer, true, { dialogContext ->
|
||||||
messageBuilder.createBankTransferMessage(bankTransferData, account, dialogContext)
|
messageBuilder.createBankTransferMessage(bankTransferData, account, dialogContext)
|
||||||
|
}) { response ->
|
||||||
|
callback(FinTsClientResponse(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
return FinTsClientResponse(response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun sendMessageAndHandleResponse(bank: BankData, customer: CustomerData, messageMayRequiresTan: Boolean = true,
|
protected open fun sendMessageAndHandleResponse(bank: BankData, customer: CustomerData, messageMayRequiresTan: Boolean = true,
|
||||||
createMessage: (DialogContext) -> MessageBuilderResult): Response {
|
createMessage: (DialogContext) -> MessageBuilderResult, callback: (Response) -> Unit) {
|
||||||
|
|
||||||
val dialogContext = DialogContext(bank, customer, product)
|
val dialogContext = DialogContext(bank, customer, product)
|
||||||
|
|
||||||
val initDialogResponse = initDialog(dialogContext)
|
initDialog(dialogContext) { initDialogResponse ->
|
||||||
|
|
||||||
if (initDialogResponse.successful == false) {
|
if (initDialogResponse.successful == false) {
|
||||||
return initDialogResponse
|
callback(initDialogResponse)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
val message = createMessage(dialogContext)
|
val message = createMessage(dialogContext)
|
||||||
|
|
||||||
val response = getAndHandleResponseForMessage(message, dialogContext)
|
getAndHandleResponseForMessage(message, dialogContext) { response ->
|
||||||
|
|
||||||
closeDialog(dialogContext)
|
closeDialog(dialogContext)
|
||||||
|
|
||||||
|
callback(response)
|
||||||
return response
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun initDialog(dialogContext: DialogContext): Response {
|
protected open fun initDialog(dialogContext: DialogContext, callback: (Response) -> Unit) {
|
||||||
|
|
||||||
// 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(dialogContext.bank, dialogContext.customer)
|
ensureBasicBankDataRetrieved(dialogContext.bank, dialogContext.customer) { retrieveBasicBankDataResponse ->
|
||||||
if (retrieveBasicBankDataResponse.successful == false) {
|
if (retrieveBasicBankDataResponse.successful == false) {
|
||||||
return retrieveBasicBankDataResponse
|
callback(retrieveBasicBankDataResponse)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
// 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(dialogContext.bank, dialogContext.customer)
|
ensureTanProcedureIsSelected(dialogContext.bank, dialogContext.customer) { tanProcedureSelectedResponse ->
|
||||||
if (tanProcedureSelectedResponse.successful == false) {
|
if (tanProcedureSelectedResponse.successful == false) {
|
||||||
return tanProcedureSelectedResponse
|
callback(tanProcedureSelectedResponse)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
initDialogAfterSuccessfulChecks(dialogContext, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return initDialogAfterSuccessfulChecks(dialogContext)
|
protected open fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext, callback: (Response) -> Unit) {
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun initDialogAfterSuccessfulChecks(dialogContext: DialogContext): Response {
|
|
||||||
|
|
||||||
val message = messageBuilder.createInitDialogMessage(dialogContext)
|
val message = messageBuilder.createInitDialogMessage(dialogContext)
|
||||||
|
|
||||||
val response = GetUserTanProceduresResponse(getAndHandleResponseForMessage(message, dialogContext))
|
getAndHandleResponseForMessage(message, dialogContext) { unmappedResponse ->
|
||||||
|
val response = GetUserTanProceduresResponse(unmappedResponse)
|
||||||
dialogContext.response = response
|
dialogContext.response = response
|
||||||
|
|
||||||
if (response.successful) {
|
if (response.successful) {
|
||||||
|
@ -506,7 +535,8 @@ open class FinTsClient(
|
||||||
updateCustomerData(dialogContext.customer, dialogContext.bank, response)
|
updateCustomerData(dialogContext.customer, dialogContext.bank, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
callback(response)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun closeDialog(dialogContext: DialogContext) {
|
protected open fun closeDialog(dialogContext: DialogContext) {
|
||||||
|
@ -522,35 +552,45 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun ensureBasicBankDataRetrieved(bank: BankData, customer: CustomerData): Response {
|
protected open fun ensureBasicBankDataRetrieved(bank: BankData, customer: CustomerData, callback: (Response) -> Unit) {
|
||||||
if (bank.supportedTanProcedures.isEmpty() || bank.supportedJobs.isEmpty()) {
|
if (bank.supportedTanProcedures.isEmpty() || bank.supportedJobs.isEmpty()) {
|
||||||
val getBankInfoResponse = getBankAndCustomerInfoForNewUser(bank, customer)
|
getBankAndCustomerInfoForNewUser(bank, customer) { getBankInfoResponse ->
|
||||||
|
|
||||||
if (getBankInfoResponse.isSuccessful == false || bank.supportedTanProcedures.isEmpty()
|
if (getBankInfoResponse.isSuccessful == false || bank.supportedTanProcedures.isEmpty()
|
||||||
|| bank.supportedJobs.isEmpty()) {
|
|| bank.supportedJobs.isEmpty()) {
|
||||||
|
|
||||||
return Response(false, exception =
|
callback(Response(false, exception =
|
||||||
Exception("Could not retrieve basic bank data like supported tan procedures or supported jobs")) // TODO: translate // TODO: add as messageToShowToUser
|
Exception("Could not retrieve basic bank data like supported tan procedures or supported jobs"))) // TODO: translate // TODO: add as messageToShowToUser
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(Response(true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(Response(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response(true)
|
protected open fun ensureTanProcedureIsSelected(bank: BankData, customer: CustomerData, callback: (Response) -> Unit) {
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun ensureTanProcedureIsSelected(bank: BankData, customer: CustomerData): Response {
|
|
||||||
if (customer.isTanProcedureSelected == false) {
|
if (customer.isTanProcedureSelected == false) {
|
||||||
if (customer.supportedTanProcedures.isEmpty()) {
|
if (customer.supportedTanProcedures.isEmpty()) {
|
||||||
getBankAndCustomerInfoForNewUser(bank, customer)
|
getBankAndCustomerInfoForNewUser(bank, customer) {
|
||||||
}
|
|
||||||
|
|
||||||
if (customer.supportedTanProcedures.isEmpty()) { // could not retrieve supported tan procedures for user
|
if (customer.supportedTanProcedures.isEmpty()) { // could not retrieve supported tan procedures for user
|
||||||
return Response(false, noTanProcedureSelected = true)
|
callback(Response(false, noTanProcedureSelected = true))
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
getUsersTanProcedure(customer)
|
getUsersTanProcedure(customer)
|
||||||
|
callback(Response(customer.isTanProcedureSelected, noTanProcedureSelected = !!!customer.isTanProcedureSelected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(Response(customer.isTanProcedureSelected, noTanProcedureSelected = !!!customer.isTanProcedureSelected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(Response(customer.isTanProcedureSelected, noTanProcedureSelected = !!!customer.isTanProcedureSelected))
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response(customer.isTanProcedureSelected, noTanProcedureSelected = !!!customer.isTanProcedureSelected)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getUsersTanProcedure(customer: CustomerData) {
|
protected open fun getUsersTanProcedure(customer: CustomerData) {
|
||||||
|
@ -573,12 +613,13 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun getAndHandleResponseForMessage(message: MessageBuilderResult, dialogContext: DialogContext): Response {
|
protected open fun getAndHandleResponseForMessage(message: MessageBuilderResult, dialogContext: DialogContext, callback: (Response) -> Unit) {
|
||||||
val response = if (message.createdMessage == null) Response(false, messageCreationError = message)
|
if (message.createdMessage == null) {
|
||||||
else getAndHandleResponseForMessage(message.createdMessage, dialogContext)
|
callback(Response(false, messageCreationError = message))
|
||||||
|
}
|
||||||
val handledResponse = handleMayRequiresTan(response, dialogContext)
|
else {
|
||||||
|
getAndHandleResponseForMessage(message.createdMessage, dialogContext) { response ->
|
||||||
|
handleMayRequiresTan(response, dialogContext) { handledResponse ->
|
||||||
// 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
|
||||||
|
@ -586,21 +627,28 @@ open class FinTsClient(
|
||||||
dialogContext.chunkedResponseHandler?.invoke(handledResponse)
|
dialogContext.chunkedResponseHandler?.invoke(handledResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
handledResponse.followUpResponse = getFollowUpMessageForContinuationId(handledResponse, continuationId, message, dialogContext)
|
getFollowUpMessageForContinuationId(handledResponse, continuationId, message, dialogContext) { followUpResponse ->
|
||||||
|
handledResponse.followUpResponse = followUpResponse
|
||||||
handledResponse.hasFollowUpMessageButCouldNotReceiveIt = handledResponse.followUpResponse == null
|
handledResponse.hasFollowUpMessageButCouldNotReceiveIt = handledResponse.followUpResponse == null
|
||||||
}
|
|
||||||
}
|
|
||||||
?: run { dialogContext.chunkedResponseHandler?.invoke(handledResponse) }
|
|
||||||
|
|
||||||
return handledResponse
|
callback(handledResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?: run {
|
||||||
|
dialogContext.chunkedResponseHandler?.invoke(handledResponse)
|
||||||
|
|
||||||
|
callback(handledResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getAndHandleResponseForMessage(requestBody: String, dialogContext: DialogContext): Response {
|
protected open fun getAndHandleResponseForMessage(requestBody: String, dialogContext: DialogContext, callback: (Response) -> Unit) {
|
||||||
addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext)
|
addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext)
|
||||||
|
|
||||||
val webResponse = getResponseForMessage(requestBody, dialogContext.bank.finTs3ServerAddress)
|
getResponseForMessage(requestBody, dialogContext.bank.finTs3ServerAddress) { webResponse ->
|
||||||
|
|
||||||
val response = handleResponse(webResponse, dialogContext)
|
val response = handleResponse(webResponse, dialogContext)
|
||||||
|
|
||||||
dialogContext.response = response
|
dialogContext.response = response
|
||||||
|
@ -608,20 +656,21 @@ open class FinTsClient(
|
||||||
response.messageHeader?.let { header -> dialogContext.dialogId = header.dialogId }
|
response.messageHeader?.let { header -> dialogContext.dialogId = header.dialogId }
|
||||||
dialogContext.didBankCloseDialog = response.didBankCloseDialog
|
dialogContext.didBankCloseDialog = response.didBankCloseDialog
|
||||||
|
|
||||||
return response
|
callback(response)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getResponseForMessage(requestBody: String, finTs3ServerAddress: String): WebClientResponse {
|
protected open fun getResponseForMessage(requestBody: String, finTs3ServerAddress: String, callback: (WebClientResponse) -> Unit) {
|
||||||
val encodedRequestBody = base64Service.encode(requestBody)
|
val encodedRequestBody = base64Service.encode(requestBody)
|
||||||
|
|
||||||
return webClient.post(finTs3ServerAddress, encodedRequestBody, "application/octet-stream")
|
webClient.post(finTs3ServerAddress, encodedRequestBody, "application/octet-stream", IWebClient.DefaultUserAgent, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun fireAndForgetMessage(message: MessageBuilderResult, dialogContext: DialogContext) {
|
protected open fun fireAndForgetMessage(message: MessageBuilderResult, dialogContext: DialogContext) {
|
||||||
message.createdMessage?.let { requestBody ->
|
message.createdMessage?.let { requestBody ->
|
||||||
addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext)
|
addMessageLog(requestBody, MessageLogEntryType.Sent, dialogContext)
|
||||||
|
|
||||||
getResponseForMessage(requestBody, dialogContext.bank.finTs3ServerAddress)
|
getResponseForMessage(requestBody, dialogContext.bank.finTs3ServerAddress) { }
|
||||||
|
|
||||||
// if really needed add received response to message log here
|
// if really needed add received response to message log here
|
||||||
}
|
}
|
||||||
|
@ -658,13 +707,12 @@ open class FinTsClient(
|
||||||
|
|
||||||
|
|
||||||
protected open fun getFollowUpMessageForContinuationId(response: Response, continuationId: String, message: MessageBuilderResult,
|
protected open fun getFollowUpMessageForContinuationId(response: Response, continuationId: String, message: MessageBuilderResult,
|
||||||
dialogContext: DialogContext): Response? {
|
dialogContext: DialogContext, callback: (Response?) -> Unit) {
|
||||||
|
|
||||||
messageBuilder.rebuildMessageWithContinuationId(message, continuationId, dialogContext)?.let { followUpMessage ->
|
messageBuilder.rebuildMessageWithContinuationId(message, continuationId, dialogContext)?.let { followUpMessage ->
|
||||||
return getAndHandleResponseForMessage(followUpMessage, dialogContext)
|
getAndHandleResponseForMessage(followUpMessage, dialogContext, callback)
|
||||||
}
|
}
|
||||||
|
?: run { callback(null) }
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -717,26 +765,29 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun handleMayRequiresTan(response: Response, dialogContext: DialogContext): Response { // TODO: use response from DialogContext
|
protected open fun handleMayRequiresTan(response: Response, dialogContext: DialogContext, callback: (Response) -> Unit) { // TODO: use response from DialogContext
|
||||||
|
|
||||||
if (response.isStrongAuthenticationRequired) {
|
if (response.isStrongAuthenticationRequired) {
|
||||||
if (dialogContext.abortIfTanIsRequired) {
|
if (dialogContext.abortIfTanIsRequired) {
|
||||||
response.tanRequiredButWeWereToldToAbortIfSo = true
|
response.tanRequiredButWeWereToldToAbortIfSo = true
|
||||||
|
|
||||||
return response
|
callback(response)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.tanResponse?.let { tanResponse ->
|
response.tanResponse?.let { tanResponse ->
|
||||||
val customer = dialogContext.customer
|
val customer = dialogContext.customer
|
||||||
val enteredTanResult = callback.enterTan(customer, createTanChallenge(tanResponse, customer))
|
val enteredTanResult = this.callback.enterTan(customer, createTanChallenge(tanResponse, customer))
|
||||||
|
|
||||||
if (enteredTanResult.changeTanProcedureTo != null) {
|
if (enteredTanResult.changeTanProcedureTo != null) {
|
||||||
return handleUserAsksToChangeTanProcedureAndResendLastMessage(enteredTanResult.changeTanProcedureTo,
|
handleUserAsksToChangeTanProcedureAndResendLastMessage(enteredTanResult.changeTanProcedureTo,
|
||||||
dialogContext)
|
dialogContext, callback)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
else if (enteredTanResult.changeTanMediumTo is TanGeneratorTanMedium) {
|
else if (enteredTanResult.changeTanMediumTo is TanGeneratorTanMedium) {
|
||||||
return handleUserAsksToChangeTanMediumAndResendLastMessage(enteredTanResult.changeTanMediumTo,
|
handleUserAsksToChangeTanMediumAndResendLastMessage(enteredTanResult.changeTanMediumTo,
|
||||||
dialogContext, enteredTanResult.changeTanMediumResultCallback)
|
dialogContext, enteredTanResult.changeTanMediumResultCallback, callback)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
@ -744,7 +795,8 @@ open class FinTsClient(
|
||||||
response.tanRequiredButUserDidNotEnterOne = true
|
response.tanRequiredButUserDidNotEnterOne = true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return sendTanToBank(enteredTanResult.enteredTan, tanResponse, dialogContext)
|
sendTanToBank(enteredTanResult.enteredTan, tanResponse, dialogContext, callback)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -756,7 +808,7 @@ open class FinTsClient(
|
||||||
// TODO: also check '9931 Sperrung des Kontos nach %1 Fehlversuchen' -> if %1 == 3 synchronize TAN generator
|
// 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
|
// as it's quite unrealistic that user entered TAN wrong three times, in most cases TAN generator is not synchronized
|
||||||
|
|
||||||
return response
|
callback(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createTanChallenge(tanResponse: TanResponse, customer: CustomerData): TanChallenge {
|
protected open fun createTanChallenge(tanResponse: TanResponse, customer: CustomerData): TanChallenge {
|
||||||
|
@ -778,14 +830,14 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun sendTanToBank(enteredTan: String, tanResponse: TanResponse, dialogContext: DialogContext): Response {
|
protected open fun sendTanToBank(enteredTan: String, tanResponse: TanResponse, dialogContext: DialogContext, callback: (Response) -> Unit) {
|
||||||
|
|
||||||
val message = messageBuilder.createSendEnteredTanMessage(enteredTan, tanResponse, dialogContext)
|
val message = messageBuilder.createSendEnteredTanMessage(enteredTan, tanResponse, dialogContext)
|
||||||
|
|
||||||
return getAndHandleResponseForMessage(message, dialogContext)
|
getAndHandleResponseForMessage(message, dialogContext, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, dialogContext: DialogContext): Response {
|
protected open fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, dialogContext: DialogContext, callback: (Response) -> Unit) {
|
||||||
|
|
||||||
dialogContext.customer.selectedTanProcedure = changeTanProcedureTo
|
dialogContext.customer.selectedTanProcedure = changeTanProcedureTo
|
||||||
|
|
||||||
|
@ -794,53 +846,55 @@ open class FinTsClient(
|
||||||
|
|
||||||
lastCreatedMessage?.let { closeDialog(dialogContext) }
|
lastCreatedMessage?.let { closeDialog(dialogContext) }
|
||||||
|
|
||||||
return resendMessageInNewDialog(lastCreatedMessage, dialogContext)
|
resendMessageInNewDialog(lastCreatedMessage, dialogContext, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium,
|
protected open fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium,
|
||||||
dialogContext: DialogContext,
|
dialogContext: DialogContext,
|
||||||
changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): Response {
|
changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?,
|
||||||
|
callback: (Response) -> Unit) {
|
||||||
|
|
||||||
val lastCreatedMessage = dialogContext.currentMessage
|
val lastCreatedMessage = dialogContext.currentMessage
|
||||||
|
|
||||||
lastCreatedMessage?.let { closeDialog(dialogContext) }
|
lastCreatedMessage?.let { closeDialog(dialogContext) }
|
||||||
|
|
||||||
|
|
||||||
val changeTanMediumResponse = changeTanMedium(changeTanMediumTo, dialogContext.bank, dialogContext.customer)
|
changeTanMedium(changeTanMediumTo, dialogContext.bank, dialogContext.customer) { changeTanMediumResponse ->
|
||||||
|
|
||||||
changeTanMediumResultCallback?.invoke(changeTanMediumResponse)
|
changeTanMediumResultCallback?.invoke(changeTanMediumResponse)
|
||||||
|
|
||||||
if (changeTanMediumResponse.isSuccessful == false || lastCreatedMessage == null) {
|
if (changeTanMediumResponse.isSuccessful == false || lastCreatedMessage == null) {
|
||||||
return changeTanMediumResponse.toResponse()
|
callback(changeTanMediumResponse.toResponse())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resendMessageInNewDialog(lastCreatedMessage, dialogContext, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return resendMessageInNewDialog(lastCreatedMessage, dialogContext)
|
protected open fun resendMessageInNewDialog(lastCreatedMessage: MessageBuilderResult?, previousDialogContext: DialogContext, callback: (Response) -> Unit) {
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected open fun resendMessageInNewDialog(lastCreatedMessage: MessageBuilderResult?, previousDialogContext: DialogContext): Response {
|
|
||||||
|
|
||||||
lastCreatedMessage?.let { // do not use previousDialogContext.currentMessage as this may is previous dialog's dialog close message
|
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, chunkedResponseHandler = previousDialogContext.chunkedResponseHandler)
|
val newDialogContext = DialogContext(previousDialogContext.bank, previousDialogContext.customer, previousDialogContext.product, chunkedResponseHandler = previousDialogContext.chunkedResponseHandler)
|
||||||
|
|
||||||
val initDialogResponse = initDialog(newDialogContext)
|
initDialog(newDialogContext) { initDialogResponse ->
|
||||||
if (initDialogResponse.successful == false) {
|
if (initDialogResponse.successful == false) {
|
||||||
return initDialogResponse
|
callback(initDialogResponse)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
val newMessage = messageBuilder.rebuildMessage(lastCreatedMessage, newDialogContext)
|
val newMessage = messageBuilder.rebuildMessage(lastCreatedMessage, newDialogContext)
|
||||||
|
|
||||||
val response = getAndHandleResponseForMessage(newMessage, newDialogContext)
|
getAndHandleResponseForMessage(newMessage, newDialogContext) { response ->
|
||||||
|
|
||||||
closeDialog(newDialogContext)
|
closeDialog(newDialogContext)
|
||||||
|
|
||||||
return response
|
callback(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
|
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
|
callback(Response(false, exception = Exception(errorMessage))) // should never come to this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,8 @@ open class FinTsClientForCustomer(
|
||||||
client.addAccountAsync(bank, customer, callback)
|
client.addAccountAsync(bank, customer, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun addAccount(): AddAccountResponse {
|
open fun addAccount(callback: (AddAccountResponse) -> Unit) {
|
||||||
return client.addAccount(bank, customer)
|
client.addAccount(bank, customer, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ open class FinTsClientForCustomer(
|
||||||
client.getTransactionsAsync(parameter, bank, customer, account, callback)
|
client.getTransactionsAsync(parameter, bank, customer, account, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getTransactions(parameter: GetTransactionsParameter, account: AccountData): GetTransactionsResponse {
|
open fun getTransactions(parameter: GetTransactionsParameter, account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
return client.getTransactions(parameter, bank, customer, account)
|
client.getTransactions(parameter, bank, customer, account, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,8 +56,8 @@ open class FinTsClientForCustomer(
|
||||||
client.doBankTransferAsync(bankTransferData, bank, customer, account, callback)
|
client.doBankTransferAsync(bankTransferData, bank, customer, account, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun doBankTransfer(bankTransferData: BankTransferData, account: AccountData): FinTsClientResponse {
|
open fun doBankTransfer(bankTransferData: BankTransferData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
|
||||||
return client.doBankTransfer(bankTransferData, bank, customer, account)
|
client.doBankTransfer(bankTransferData, bank, customer, account, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -20,6 +20,6 @@ interface IWebClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun post(url: String, body: String, contentType: String = "application/octet-stream", userAgent: String = DefaultUserAgent) : WebClientResponse
|
fun post(url: String, body: String, contentType: String = "application/octet-stream", userAgent: String = DefaultUserAgent, callback: (WebClientResponse) -> Unit)
|
||||||
|
|
||||||
}
|
}
|
|
@ -34,9 +34,8 @@ open class KtorWebClient : IWebClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun post(url: String, body: String, contentType: String, userAgent: String): WebClientResponse {
|
override fun post(url: String, body: String, contentType: String, userAgent: String, callback: (WebClientResponse) -> Unit) {
|
||||||
try {
|
GlobalScope.async {
|
||||||
val job = GlobalScope.async {
|
|
||||||
try {
|
try {
|
||||||
val clientResponse = client.post<HttpResponse>(url) {
|
val clientResponse = client.post<HttpResponse>(url) {
|
||||||
this.body = TextContent(body, contentType = ContentType.Application.OctetStream)
|
this.body = TextContent(body, contentType = ContentType.Application.OctetStream)
|
||||||
|
@ -44,20 +43,13 @@ open class KtorWebClient : IWebClient {
|
||||||
|
|
||||||
val responseBody = clientResponse.readText()
|
val responseBody = clientResponse.readText()
|
||||||
|
|
||||||
WebClientResponse(clientResponse.status.value == 200, clientResponse.status.value, body = responseBody)
|
callback(WebClientResponse(clientResponse.status.value == 200, clientResponse.status.value, body = responseBody))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error(e) { "Could not send request to url '$url'" }
|
log.error(e) { "Could not send request to url '$url'" }
|
||||||
|
|
||||||
WebClientResponse(false, error = e)
|
callback(WebClientResponse(false, error = e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (job.isCompleted == false) { } // let's warm the CPU to get suspend function synchronous (runBlocking is not available in common projects)
|
|
||||||
|
|
||||||
return job.getCompleted()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
return WebClientResponse(false, error = e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -87,7 +87,7 @@ open class FinTsClientTestBase {
|
||||||
fun getAnonymousBankInfo() {
|
fun getAnonymousBankInfo() {
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val result = underTest.getAnonymousBankInfo(BankDataAnonymous)
|
underTest.getAnonymousBankInfo(BankDataAnonymous) { result ->
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.isSuccessful).isTrue()
|
expect(result.isSuccessful).isTrue()
|
||||||
|
@ -97,6 +97,7 @@ open class FinTsClientTestBase {
|
||||||
expect(BankDataAnonymous.supportedLanguages).isNotEmpty()
|
expect(BankDataAnonymous.supportedLanguages).isNotEmpty()
|
||||||
expect(BankDataAnonymous.name).isNotEmpty()
|
expect(BankDataAnonymous.name).isNotEmpty()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -166,7 +167,7 @@ open class FinTsClientTestBase {
|
||||||
|
|
||||||
// this test is only senseful for accounts using chipTAN / TAN generator as TAN procedure
|
// this test is only senseful for accounts using chipTAN / TAN generator as TAN procedure
|
||||||
|
|
||||||
underTest.getAnonymousBankInfo(Bank)
|
underTest.getAnonymousBankInfo(Bank) { }
|
||||||
|
|
||||||
val supportsRetrievingTanMedia = Bank.supportedJobs.firstOrNull { it.jobName == "HKTAB" } != null
|
val supportsRetrievingTanMedia = Bank.supportedJobs.firstOrNull { it.jobName == "HKTAB" } != null
|
||||||
|
|
||||||
|
@ -178,8 +179,7 @@ open class FinTsClientTestBase {
|
||||||
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val result = underTest.getTanMediaList(Bank, Customer, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien)
|
underTest.getTanMediaList(Bank, Customer, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien) { result ->
|
||||||
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.isSuccessful).isTrue()
|
expect(result.isSuccessful).isTrue()
|
||||||
|
@ -190,6 +190,7 @@ open class FinTsClientTestBase {
|
||||||
|
|
||||||
expect(Customer.tanMedia).isNotEmpty()
|
expect(Customer.tanMedia).isNotEmpty()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Ignore // only works with banks that don't support HKTAB version 5
|
@Ignore // only works with banks that don't support HKTAB version 5
|
||||||
@Test
|
@Test
|
||||||
|
@ -197,7 +198,7 @@ open class FinTsClientTestBase {
|
||||||
|
|
||||||
// when
|
// when
|
||||||
expect {
|
expect {
|
||||||
underTest.getTanMediaList(Bank, Customer, TanMedienArtVersion.Alle, TanMediumKlasse.BilateralVereinbart)
|
underTest.getTanMediaList(Bank, Customer, TanMedienArtVersion.Alle, TanMediumKlasse.BilateralVereinbart) { }
|
||||||
}.toThrow<UnsupportedOperationException>()
|
}.toThrow<UnsupportedOperationException>()
|
||||||
|
|
||||||
|
|
||||||
|
@ -226,10 +227,11 @@ open class FinTsClientTestBase {
|
||||||
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val result = underTest.doBankTransfer(BankTransferData, Bank, Customer, account)
|
underTest.doBankTransfer(BankTransferData, Bank, Customer, account) { result ->
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.isSuccessful).isTrue()
|
expect(result.isSuccessful).isTrue()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue