Implemented restoring fints4java BankingClient's data
This commit is contained in:
parent
19fcbf2823
commit
08f603a9a0
|
@ -16,7 +16,9 @@ import java.io.File
|
||||||
|
|
||||||
class MainWindow : View(messages["application.title"]) {
|
class MainWindow : View(messages["application.title"]) {
|
||||||
|
|
||||||
private val presenter = MainWindowPresenter(fints4javaBankingClientCreator(), BankingPersistenceJson(File("data/accounts.json")), Base64ServiceJava8(), RouterJavaFx())
|
private val dataFolder = File("data")
|
||||||
|
|
||||||
|
private val presenter = MainWindowPresenter(fints4javaBankingClientCreator(), dataFolder, BankingPersistenceJson(File(dataFolder, "accounts.json")), Base64ServiceJava8(), RouterJavaFx())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,4 +20,6 @@ interface IBankingClient {
|
||||||
|
|
||||||
fun transferMoneyAsync(data: TransferMoneyData, bankAccount: BankAccount, callback: (BankingClientResponse) -> Unit)
|
fun transferMoneyAsync(data: TransferMoneyData, bankAccount: BankAccount, callback: (BankingClientResponse) -> Unit)
|
||||||
|
|
||||||
|
fun restoreData()
|
||||||
|
|
||||||
}
|
}
|
|
@ -25,6 +25,7 @@ import net.dankito.utils.extensions.ofMaxLength
|
||||||
import net.dankito.utils.web.client.IWebClient
|
import net.dankito.utils.web.client.IWebClient
|
||||||
import net.dankito.utils.web.client.OkHttpWebClient
|
import net.dankito.utils.web.client.OkHttpWebClient
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.io.File
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
@ -32,6 +33,7 @@ import kotlin.collections.ArrayList
|
||||||
|
|
||||||
open class MainWindowPresenter(
|
open class MainWindowPresenter(
|
||||||
protected val bankingClientCreator: IBankingClientCreator,
|
protected val bankingClientCreator: IBankingClientCreator,
|
||||||
|
protected val dataFolder: File,
|
||||||
protected val persister: IBankingPersistence,
|
protected val persister: IBankingPersistence,
|
||||||
protected val base64Service: IBase64Service,
|
protected val base64Service: IBase64Service,
|
||||||
protected val router: IRouter,
|
protected val router: IRouter,
|
||||||
|
@ -102,7 +104,15 @@ open class MainWindowPresenter(
|
||||||
val bank = account.bank
|
val bank = account.bank
|
||||||
val bankInfo = BankInfo(bank.name, bank.bankCode, bank.bic, "", "", "", bank.finTsServerAddress, "FinTS V3.0", null)
|
val bankInfo = BankInfo(bank.name, bank.bankCode, bank.bic, "", "", "", bank.finTsServerAddress, "FinTS V3.0", null)
|
||||||
|
|
||||||
val newClient = bankingClientCreator.createClient(bankInfo, account.customerId, account.password, webClient, base64Service, threadPool, callback)
|
val newClient = bankingClientCreator.createClient(bankInfo, account.customerId, account.password,
|
||||||
|
dataFolder, webClient, base64Service, threadPool, callback)
|
||||||
|
|
||||||
|
try {
|
||||||
|
newClient.restoreData()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.error("Could not deserialize account data of $account", e)
|
||||||
|
// TODO: show error message to user
|
||||||
|
}
|
||||||
|
|
||||||
addClientForAccount(account, newClient)
|
addClientForAccount(account, newClient)
|
||||||
}
|
}
|
||||||
|
@ -123,7 +133,7 @@ open class MainWindowPresenter(
|
||||||
// TODO: move BankInfo out of fints4javaLib
|
// TODO: move BankInfo out of fints4javaLib
|
||||||
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String, callback: (AddAccountResponse) -> Unit) {
|
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String, callback: (AddAccountResponse) -> Unit) {
|
||||||
|
|
||||||
val newClient = bankingClientCreator.createClient(bankInfo, customerId, pin, webClient, base64Service, threadPool, this.callback)
|
val newClient = bankingClientCreator.createClient(bankInfo, customerId, pin, dataFolder, webClient, base64Service, threadPool, this.callback)
|
||||||
|
|
||||||
newClient.addAccountAsync { response ->
|
newClient.addAccountAsync { response ->
|
||||||
val account = response.account
|
val account = response.account
|
||||||
|
@ -299,16 +309,7 @@ open class MainWindowPresenter(
|
||||||
|
|
||||||
|
|
||||||
protected open fun getClientForAccount(account: Account): IBankingClient? {
|
protected open fun getClientForAccount(account: Account): IBankingClient? {
|
||||||
clientsForAccounts.get(account)?.let { client ->
|
return clientsForAccounts.get(account)
|
||||||
// TODO: is this code still needed after updating data model is implemented?
|
|
||||||
// account.selectedTanProcedure?.let { selectedTanProcedure ->
|
|
||||||
// client.customer.selectedTanProcedure = fints4javaModelMapper.mapTanProcedureBack(selectedTanProcedure)
|
|
||||||
// }
|
|
||||||
|
|
||||||
return client
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
presenter = MainWindowPresenter(fints4javaBankingClientCreator(), BankingPersistenceJson(File(this.filesDir, "data/accounts.json")), Base64ServiceAndroid(), RouterAndroid(this))
|
val dataFolder = File(this.filesDir, "data")
|
||||||
|
|
||||||
|
presenter = MainWindowPresenter(fints4javaBankingClientCreator(), dataFolder,
|
||||||
|
BankingPersistenceJson(File(dataFolder, "accounts.json")), Base64ServiceAndroid(), RouterAndroid(this))
|
||||||
|
|
||||||
initUi()
|
initUi()
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,18 @@ import net.dankito.fints.model.mapper.BankDataMapper
|
||||||
import net.dankito.fints.util.IBase64Service
|
import net.dankito.fints.util.IBase64Service
|
||||||
import net.dankito.utils.IThreadPool
|
import net.dankito.utils.IThreadPool
|
||||||
import net.dankito.utils.ThreadPool
|
import net.dankito.utils.ThreadPool
|
||||||
|
import net.dankito.utils.serialization.JacksonJsonSerializer
|
||||||
import net.dankito.utils.web.client.IWebClient
|
import net.dankito.utils.web.client.IWebClient
|
||||||
import net.dankito.utils.web.client.OkHttpWebClient
|
import net.dankito.utils.web.client.OkHttpWebClient
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
open class fints4javaBankingClient(
|
open class fints4javaBankingClient(
|
||||||
bankInfo: BankInfo,
|
bankInfo: BankInfo,
|
||||||
customerId: String,
|
customerId: String,
|
||||||
pin: String,
|
pin: String,
|
||||||
|
protected val dataFolder: File,
|
||||||
webClient: IWebClient = OkHttpWebClient(),
|
webClient: IWebClient = OkHttpWebClient(),
|
||||||
base64Service: IBase64Service,
|
base64Service: IBase64Service,
|
||||||
threadPool: IThreadPool = ThreadPool(),
|
threadPool: IThreadPool = ThreadPool(),
|
||||||
|
@ -32,10 +36,20 @@ open class fints4javaBankingClient(
|
||||||
|
|
||||||
) : IBankingClient {
|
) : IBankingClient {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val fints4javaClientDataFilename = "fints4javaClientData.json"
|
||||||
|
|
||||||
|
private val log = LoggerFactory.getLogger(fints4javaBankingClient::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected val mapper = net.dankito.banking.mapper.fints4javaModelMapper()
|
protected val mapper = net.dankito.banking.mapper.fints4javaModelMapper()
|
||||||
|
|
||||||
protected val bankDataMapper = BankDataMapper()
|
protected val bankDataMapper = BankDataMapper()
|
||||||
|
|
||||||
|
protected val serializer = JacksonJsonSerializer()
|
||||||
|
|
||||||
|
|
||||||
protected val bank = bankDataMapper.mapFromBankInfo(bankInfo)
|
protected val bank = bankDataMapper.mapFromBankInfo(bankInfo)
|
||||||
|
|
||||||
protected val customer = CustomerData(customerId, pin)
|
protected val customer = CustomerData(customerId, pin)
|
||||||
|
@ -74,6 +88,8 @@ open class fints4javaBankingClient(
|
||||||
this.account = mapper.mapAccount(customer, bank)
|
this.account = mapper.mapAccount(customer, bank)
|
||||||
val mappedResponse = mapper.mapResponse(account, response)
|
val mappedResponse = mapper.mapResponse(account, response)
|
||||||
|
|
||||||
|
saveData()
|
||||||
|
|
||||||
callback(mappedResponse)
|
callback(mappedResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,6 +105,8 @@ open class fints4javaBankingClient(
|
||||||
|
|
||||||
val mappedResponse = mapper.mapResponse(bankAccount, response)
|
val mappedResponse = mapper.mapResponse(bankAccount, response)
|
||||||
|
|
||||||
|
saveData()
|
||||||
|
|
||||||
callback(mappedResponse)
|
callback(mappedResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,9 +122,32 @@ open class fints4javaBankingClient(
|
||||||
val mappedData = BankTransferData(data.creditorName, data.creditorIban, data.creditorBic, data.amount, data.usage)
|
val mappedData = BankTransferData(data.creditorName, data.creditorIban, data.creditorBic, data.amount, data.usage)
|
||||||
|
|
||||||
client.doBankTransferAsync(mappedData, account) { response ->
|
client.doBankTransferAsync(mappedData, account) { response ->
|
||||||
|
saveData()
|
||||||
|
|
||||||
callback(mapper.mapResponse(response))
|
callback(mapper.mapResponse(response))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun restoreData() {
|
||||||
|
val deserializedCustomer = serializer.deserializeObject(getFints4javaClientDataFile(), CustomerData::class.java)
|
||||||
|
|
||||||
|
deserializedCustomer?.let {
|
||||||
|
mapper.updateCustomer(customer, deserializedCustomer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun saveData() {
|
||||||
|
try {
|
||||||
|
serializer.serializeObject(customer, getFints4javaClientDataFile())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.error("Could not save customer data for $customer", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun getFints4javaClientDataFile(): File {
|
||||||
|
return File(dataFolder, "${bank.bankCode}_${customer.customerId}_$fints4javaClientDataFilename")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -9,14 +9,23 @@ import net.dankito.fints.model.BankInfo
|
||||||
import net.dankito.utils.IThreadPool
|
import net.dankito.utils.IThreadPool
|
||||||
import net.dankito.utils.web.client.IWebClient
|
import net.dankito.utils.web.client.IWebClient
|
||||||
import net.dankito.utils.web.client.OkHttpWebClient
|
import net.dankito.utils.web.client.OkHttpWebClient
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
open class fints4javaBankingClientCreator : IBankingClientCreator {
|
open class fints4javaBankingClientCreator : IBankingClientCreator {
|
||||||
|
|
||||||
override fun createClient(bankInfo: BankInfo, customerId: String, pin: String, webClient: IWebClient,
|
override fun createClient(
|
||||||
base64Service: IBase64Service, threadPool: IThreadPool, callback: BankingClientCallback): IBankingClient {
|
bankInfo: BankInfo,
|
||||||
|
customerId: String,
|
||||||
|
pin: String,
|
||||||
|
dataFolder: File,
|
||||||
|
webClient: IWebClient,
|
||||||
|
base64Service: IBase64Service,
|
||||||
|
threadPool: IThreadPool,
|
||||||
|
callback: BankingClientCallback
|
||||||
|
): IBankingClient {
|
||||||
|
|
||||||
return fints4javaBankingClient(bankInfo, customerId, pin, OkHttpWebClient(), UiCommonBase64ServiceWrapper(base64Service), threadPool, callback)
|
return fints4javaBankingClient(bankInfo, customerId, pin, dataFolder, OkHttpWebClient(), UiCommonBase64ServiceWrapper(base64Service), threadPool, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -61,6 +61,10 @@ open class fints4javaModelMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open fun mapBank(bank: BankData): Bank {
|
||||||
|
return Bank(bank.name, bank.bankCode, bank.bic, bank.finTs3ServerAddress)
|
||||||
|
}
|
||||||
|
|
||||||
open fun mapAccount(customer: CustomerData, bank: BankData): Account {
|
open fun mapAccount(customer: CustomerData, bank: BankData): Account {
|
||||||
val mappedBank = mapBank(bank)
|
val mappedBank = mapBank(bank)
|
||||||
|
|
||||||
|
@ -73,10 +77,24 @@ open class fints4javaModelMapper {
|
||||||
return account
|
return account
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapBank(bank: BankData): Bank {
|
// TODO: move to a fints4java internal mapper
|
||||||
return Bank(bank.name, bank.bankCode, bank.bic, bank.finTs3ServerAddress)
|
open fun updateCustomer(customer: CustomerData, updatedCustomer: CustomerData) {
|
||||||
|
customer.pin = updatedCustomer.pin
|
||||||
|
customer.name = updatedCustomer.name
|
||||||
|
|
||||||
|
customer.supportedTanProcedures = updatedCustomer.supportedTanProcedures
|
||||||
|
customer.selectedTanProcedure = updatedCustomer.selectedTanProcedure
|
||||||
|
customer.tanMedia = updatedCustomer.tanMedia
|
||||||
|
|
||||||
|
customer.updVersion = updatedCustomer.updVersion
|
||||||
|
customer.selectedLanguage = updatedCustomer.selectedLanguage
|
||||||
|
customer.customerSystemId = updatedCustomer.customerSystemId
|
||||||
|
customer.customerSystemStatus = updatedCustomer.customerSystemStatus
|
||||||
|
|
||||||
|
updateBankAccounts(customer, updatedCustomer.accounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun mapBankAccounts(account: Account, accountData: List<AccountData>): List<BankAccount> {
|
open fun mapBankAccounts(account: Account, accountData: List<AccountData>): List<BankAccount> {
|
||||||
return accountData.map { mapBankAccount(account, it) }
|
return accountData.map { mapBankAccount(account, it) }
|
||||||
}
|
}
|
||||||
|
@ -103,6 +121,38 @@ open class fints4javaModelMapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move to a fints4java internal mapper
|
||||||
|
open fun updateBankAccounts(customer: CustomerData, updatedAccounts: List<AccountData>) {
|
||||||
|
val accounts = customer.accounts
|
||||||
|
|
||||||
|
updatedAccounts.forEach { updatedAccount ->
|
||||||
|
val matchingExistingAccount = findMatchingBankAccount(accounts, updatedAccount)
|
||||||
|
|
||||||
|
if (matchingExistingAccount == null) {
|
||||||
|
customer.addAccount(updatedAccount)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
updateBankAccount(matchingExistingAccount, updatedAccount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customer.accounts.forEach { account ->
|
||||||
|
val updatedAccount = findMatchingBankAccount(updatedAccounts, account)
|
||||||
|
|
||||||
|
if (updatedAccount == null) {
|
||||||
|
customer.removeAccount(account)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun updateBankAccount(account: AccountData, updatedAccount: AccountData) {
|
||||||
|
account.allowedJobs = updatedAccount.allowedJobs
|
||||||
|
|
||||||
|
account.supportsRetrievingAccountTransactions = updatedAccount.supportsRetrievingAccountTransactions
|
||||||
|
account.supportsRetrievingBalance = updatedAccount.supportsRetrievingBalance
|
||||||
|
account.supportsTransferringMoney = updatedAccount.supportsTransferringMoney
|
||||||
|
}
|
||||||
|
|
||||||
open fun findAccountForBankAccount(customer: CustomerData, bankAccount: BankAccount): AccountData? {
|
open fun findAccountForBankAccount(customer: CustomerData, bankAccount: BankAccount): AccountData? {
|
||||||
return customer.accounts.firstOrNull { bankAccount.identifier == it.accountIdentifier }
|
return customer.accounts.firstOrNull { bankAccount.identifier == it.accountIdentifier }
|
||||||
}
|
}
|
||||||
|
@ -111,6 +161,10 @@ open class fints4javaModelMapper {
|
||||||
return account.bankAccounts.firstOrNull { it.identifier == accountData.accountIdentifier }
|
return account.bankAccounts.firstOrNull { it.identifier == accountData.accountIdentifier }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun findMatchingBankAccount(accounts: List<AccountData>, accountData: AccountData): AccountData? {
|
||||||
|
return accounts.firstOrNull { it.accountIdentifier == accountData.accountIdentifier }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun mapTransactions(bankAccount: BankAccount, transactions: List<net.dankito.fints.model.AccountTransaction>): List<AccountTransaction> {
|
open fun mapTransactions(bankAccount: BankAccount, transactions: List<net.dankito.fints.model.AccountTransaction>): List<AccountTransaction> {
|
||||||
return transactions.map { mapTransaction(bankAccount, it) }
|
return transactions.map { mapTransaction(bankAccount, it) }
|
||||||
|
|
|
@ -14,6 +14,9 @@ open class TanMedium(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
internal constructor() : this(TanMediumKlasse.AlleMedien, TanMediumStatus.Verfuegbar)
|
||||||
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (javaClass != other?.javaClass) return false
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
|
@ -26,7 +26,7 @@ open class AccountData(
|
||||||
var triedToRetrieveTransactionsOfLast90DaysWithoutTan: Boolean = false
|
var triedToRetrieveTransactionsOfLast90DaysWithoutTan: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|
||||||
internal constructor() : this("", null, Laenderkennzeichen.Germany, "", null, "", null, null, "", null, null, listOf())
|
internal constructor() : this("", null, Laenderkennzeichen.Germany, "", null, "", null, null, "", null, null, listOf()) // for object deserializers
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$productName $accountIdentifier $accountHolderName"
|
return "$productName $accountIdentifier $accountHolderName"
|
||||||
|
|
|
@ -29,6 +29,9 @@ open class BankData(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
internal constructor() : this("", 0, "", "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
open fun resetBpdVersion() {
|
open fun resetBpdVersion() {
|
||||||
bpdVersion = BPDVersion.VersionNotReceivedYet
|
bpdVersion = BPDVersion.VersionNotReceivedYet
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ open class CustomerData(
|
||||||
// for Java
|
// for Java
|
||||||
constructor(customerId: String, pin: String) : this(customerId, pin, customerId)
|
constructor(customerId: String, pin: String) : this(customerId, pin, customerId)
|
||||||
|
|
||||||
|
internal constructor() : this("", "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
val isTanProcedureSelected: Boolean
|
val isTanProcedureSelected: Boolean
|
||||||
get() = selectedTanProcedure != TanProcedureNotSelected
|
get() = selectedTanProcedure != TanProcedureNotSelected
|
||||||
|
@ -50,6 +52,10 @@ open class CustomerData(
|
||||||
(accounts as? MutableList)?.add(account)
|
(accounts as? MutableList)?.add(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun removeAccount(account: AccountData) {
|
||||||
|
(accounts as? MutableList)?.remove(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return customerId
|
return customerId
|
||||||
|
|
|
@ -9,6 +9,10 @@ open class TanProcedure(
|
||||||
val type: TanProcedureType
|
val type: TanProcedureType
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
internal constructor() : this("", Sicherheitsfunktion.Einschritt_Verfahren, TanProcedureType.EnterTan) // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$displayName ($type, ${securityFunction.code})"
|
return "$displayName ($type, ${securityFunction.code})"
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,14 @@ open class JobParameters(
|
||||||
val maxCountJobs: Int,
|
val maxCountJobs: Int,
|
||||||
val minimumCountSignatures: Int,
|
val minimumCountSignatures: Int,
|
||||||
val securityClass: Int?,
|
val securityClass: Int?,
|
||||||
segmentString: String
|
segmentString: String // TODO: when serializing / deserializing we don't care for segment string -> remove it
|
||||||
)
|
)
|
||||||
: ReceivedSegment(segmentString) {
|
: ReceivedSegment(segmentString) {
|
||||||
|
|
||||||
|
|
||||||
|
internal constructor() : this("", 0, 0, null, "0:0:0") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
constructor(parameters: JobParameters)
|
constructor(parameters: JobParameters)
|
||||||
: this(parameters.jobName, parameters.maxCountJobs, parameters.minimumCountSignatures,
|
: this(parameters.jobName, parameters.maxCountJobs, parameters.minimumCountSignatures,
|
||||||
parameters.securityClass, parameters.segmentString)
|
parameters.securityClass, parameters.segmentString)
|
||||||
|
|
Loading…
Reference in New Issue