Implemented BankListPrettifier to remove duplicate bank entries and to set better names (e.g. 'Deutsche Bank' instead of 'DB Privat- und Firmenkundenbank ...')

This commit is contained in:
dankito 2020-09-17 01:34:47 +02:00
parent 2fd11b2e56
commit 826af7c8b8
10 changed files with 219 additions and 13 deletions

View File

@ -2,7 +2,7 @@ package net.dankito.banking.bankfinder
open class BankInfo constructor(
open val name: String,
open var name: String,
open val bankCode: String,
open val bic: String,
open val postalCode: String,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -19,9 +19,9 @@ dependencies {
implementation 'org.docx4j:docx4j-JAXB-ReferenceImpl:8.1.3'
testCompile "junit:junit:$junitVersion"
testCompile "org.assertj:assertj-core:$assertJVersion"
testImplementation "junit:junit:$junitVersion"
testImplementation "org.assertj:assertj-core:$assertJVersion"
testCompile "ch.qos.logback:logback-core:$logbackVersion"
testCompile "ch.qos.logback:logback-classic:$logbackVersion"
testImplementation "ch.qos.logback:logback-core:$logbackVersion"
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
}

View File

@ -1,20 +1,41 @@
package net.dankito.banking.banklistcreator
import net.dankito.banking.bankfinder.BankInfo
import net.dankito.banking.banklistcreator.parser.DeutscheKreditwirtschaftBankListParser
import net.dankito.banking.banklistcreator.prettifier.BankListPrettifier
import net.dankito.banking.banklistcreator.prettifier.BankListPrettifierOption
import net.dankito.utils.serialization.JacksonJsonSerializer
import java.io.File
open class BankListCreator @JvmOverloads constructor(
protected open val parser: DeutscheKreditwirtschaftBankListParser = DeutscheKreditwirtschaftBankListParser()
protected open val parser: DeutscheKreditwirtschaftBankListParser = DeutscheKreditwirtschaftBankListParser(),
protected open val prettifier: BankListPrettifier = BankListPrettifier()
) {
open fun createBankListFromDeutscheKreditwirtschaftXlsxFile(bankFileOutputFile: File,
deutscheKreditwirtschaftXlsxFile: File) {
open fun createBankListFromDeutscheKreditwirtschaftXlsxFile(deutscheKreditwirtschaftXlsxFile: File,
bankListOutputFile: File) {
val banks = parser.parse(deutscheKreditwirtschaftXlsxFile)
JacksonJsonSerializer().serializeObject(banks, bankFileOutputFile)
saveBankListAsJson(banks, bankListOutputFile)
}
open fun createDetailedAndPrettifiedBankListFromDeutscheKreditwirtschaftXlsxFile(
deutscheKreditwirtschaftXlsxFile: File, detailedBankListOutputFile: File,
prettifiedBankListOutputFile: File, prettifyOptions: List<BankListPrettifierOption>) {
val allBanks = parser.parse(deutscheKreditwirtschaftXlsxFile)
saveBankListAsJson(allBanks, detailedBankListOutputFile)
val mappedBanks = allBanks.map { BankInfo(it.name, it.bankCode, it.bic, it.postalCode, it.city, it.pinTanAddress, it.pinTanVersion) }
val prettifiedBanks = prettifier.prettify(mappedBanks, prettifyOptions)
saveBankListAsJson(prettifiedBanks, prettifiedBankListOutputFile)
}
open fun saveBankListAsJson(banks: List<BankInfo>, bankListOutputFile: File) {
JacksonJsonSerializer().serializeObject(banks, bankListOutputFile)
}
}

View File

@ -0,0 +1,108 @@
package net.dankito.banking.banklistcreator.prettifier
import net.dankito.banking.bankfinder.BankInfo
open class BankListPrettifier {
open fun prettify(banks: List<BankInfo>, options: List<BankListPrettifierOption>): List<BankInfo> {
var prettifiedList = banks
if (options.contains(BankListPrettifierOption.RemoveInstitutionInternalBank)) {
prettifiedList = removeInstitutionInternalBank(prettifiedList)
}
if (options.contains(BankListPrettifierOption.RemoveBanksWithSameBankCodeAndPostalCode)) {
prettifiedList = removeBanksWithSameBankCodeAndPostalCode(prettifiedList)
}
if (options.contains(BankListPrettifierOption.RemoveBanksWithSameBankCodeAndCity)) {
prettifiedList = removeBanksWithSameBankCodeAndCity(prettifiedList)
}
if (options.contains(BankListPrettifierOption.MapBankNamesToWellKnownNames)) {
prettifiedList = mapBankNamesToWellKnownNames(prettifiedList)
}
return prettifiedList
}
open fun mapBankNamesToWellKnownNames(banks: List<BankInfo>): List<BankInfo> {
banks.forEach { bank ->
when {
bank.name.contains("Postbank") -> bank.name = "Postbank"
bank.name.startsWith("Deutsche Kreditbank") -> bank.name = "DKB (Deutsche Kreditbank)"
bank.name.startsWith("Deutsche Bank") || bank.name.startsWith("DB Privat- und Firmenkundenbank") -> bank.name = "Deutsche Bank"
bank.name.startsWith("Commerzbank") -> bank.name = "Commerzbank" // TODO: keep "vormals Dresdner Bank"?
}
}
return banks
}
open fun removeInstitutionInternalBank(banks: List<BankInfo>): List<BankInfo> {
return banks.filterNot {
(it.name.contains("intern", true) && it.name.contains("international", true) == false)
|| it.name.startsWith("UniCredit Bank - HVB Settlement")
}
}
open fun removeBanksWithSameBankCodeAndPostalCode(banks: List<BankInfo>): List<BankInfo> {
val groupedByBankCodeAndPostalCode = banks.groupBy { it.bankCode + "_" + it.postalCode }
val banksToRemove = groupedByBankCodeAndPostalCode.values.flatMap { banksWithSameBankCodeAndPostalCode ->
if (banksWithSameBankCodeAndPostalCode.size > 1) {
val bankWithBestName = findBankWithShortestName(banksWithSameBankCodeAndPostalCode)
val banksWithoutBankWithBestName = banksWithSameBankCodeAndPostalCode.toMutableList()
banksWithoutBankWithBestName.remove(bankWithBestName)
return@flatMap banksWithoutBankWithBestName
}
listOf<BankInfo>()
}
val prettifiedList = banks.toMutableList()
prettifiedList.removeAll(banksToRemove)
return prettifiedList
}
// TODO: there are many banks like "Volksbank Nordmünsterland -alt-" and "Volksbank Nordmünsterland (Gf P2)" where each time "-alt-" gets selected
protected open fun findBankWithShortestName(banks: List<BankInfo>): BankInfo {
var bankWithBestName = banks.first()
for (i in 1 until banks.size) {
val bank = banks[i]
if (bank.name.length < bankWithBestName.name.length) {
bankWithBestName = bank
}
}
return bankWithBestName
}
open fun removeBanksWithSameBankCodeAndCity(banks: List<BankInfo>): List<BankInfo> {
val groupedByBankCodeAndCity = banks.groupBy { it.bankCode + "_" + it.city }
val banksToRemove = groupedByBankCodeAndCity.values.flatMap { banksWithSameBankCodeAndCity ->
if (banksWithSameBankCodeAndCity.size > 1) {
val banksToRemove = banksWithSameBankCodeAndCity.toMutableList()
banksToRemove.remove(banksWithSameBankCodeAndCity.first())
return@flatMap banksToRemove
}
listOf<BankInfo>()
}
val prettifiedList = banks.toMutableList()
prettifiedList.removeAll(banksToRemove)
return prettifiedList
}
}

View File

@ -0,0 +1,26 @@
package net.dankito.banking.banklistcreator.prettifier
enum class BankListPrettifierOption {
/**
* Maps e.g. 'DB Privat- und Firmenkundenbank ...' to 'Deutsche Bank' or 'Deutsche Kreditbank' to 'DKB'
*/
MapBankNamesToWellKnownNames,
/**
* Often the same bank is contained multiple times but with a '(Gf 2)' etc. suffix in name. Filters these out that have the same bank code and postal code.
*/
RemoveBanksWithSameBankCodeAndPostalCode,
/**
* Often the same bank is contained multiple times but with a '(Gf 2)' etc. suffix in name. Filters these out that have the same bank code and city.
*/
RemoveBanksWithSameBankCodeAndCity,
/**
* Removes banks like 'Deutsche Bank (Gf intern)' or 'UniCredit Bank - HVB Settlement EAC01' etc.
*/
RemoveInstitutionInternalBank
}

View File

@ -1,5 +1,6 @@
package net.dankito.banking.banklistcreator
import net.dankito.banking.banklistcreator.prettifier.BankListPrettifierOption
import org.junit.Test
import org.junit.Ignore
@ -15,9 +16,12 @@ class BankListCreatorTest {
@Test
fun createBankListJson() {
// TODO: set path to bank list file from Deutsche Kreditwirtschaft in TestConfig.DeutscheKreditwirtschaftBankListXlsxFile
underTest.createBankListFromDeutscheKreditwirtschaftXlsxFile(
underTest.createDetailedAndPrettifiedBankListFromDeutscheKreditwirtschaftXlsxFile(
TestConfig.DeutscheKreditwirtschaftBankListXlsxFile,
File("../BankFinder/src/commonMain/resources/DetailedBankList.json"),
File("../BankFinder/src/commonMain/resources/BankList.json"),
TestConfig.DeutscheKreditwirtschaftBankListXlsxFile)
BankListPrettifierOption.values().toList()
)
}
}

View File

@ -0,0 +1,46 @@
package net.dankito.banking.banklistcreator.prettifier
import net.dankito.banking.banklistcreator.TestConfig
import net.dankito.banking.banklistcreator.parser.DeutscheKreditwirtschaftBankListParser
import org.assertj.core.api.Assertions.assertThat
import org.junit.Ignore
import org.junit.Test
@Ignore // not an automatic test, set your path to your bank list file in TestConfig.DeutscheKreditwirtschaftBankListXlsxFile
class BankListPrettifierTest {
private val underTest = BankListPrettifier()
private val allBanks = DeutscheKreditwirtschaftBankListParser().parse(TestConfig.DeutscheKreditwirtschaftBankListXlsxFile)
@Test
fun mapBankNamesToWellKnownNames() {
// when
val result = underTest.mapBankNamesToWellKnownNames(allBanks)
// then
assertThat(result).hasSize(allBanks.size)
val resultingBanksNames = result.map { it.name }
assertThat(resultingBanksNames.filter { it.contains("DB Privat- und Firmenkundenbank") }).isEmpty()
}
@Test
fun removeBanksWithSameBankCodeAndPostalCode() {
// when
val result = underTest.removeBanksWithSameBankCodeAndPostalCode(allBanks)
// then
assertThat(result).hasSizeLessThan(allBanks.size)
val resultingBanksNames = result.map { it.name }
assertThat(resultingBanksNames.filter { it.contains("PSD Bank München (Gf P2)") }).isEmpty()
}
}

View File

@ -59,7 +59,7 @@ struct BankInfoListItem: View {
struct BankInfoListItem_Previews: PreviewProvider {
static var previews: some View {
BankInfoListItem(BankInfo(name: "Abzockbank Berlin", bankCode: "12345678", bic: "ABZODEBBXXX", postalCode: "12345", city: "Berlin", checksumMethod: "", pinTanAddress: nil, pinTanVersion: "FinTS 3.0", oldBankCode: nil))
BankInfoListItem(BankInfo(name: "Abzockbank Berlin", bankCode: "12345678", bic: "ABZODEBBXXX", postalCode: "12345", city: "Berlin", pinTanAddress: nil, pinTanVersion: "FinTS 3.0"))
}
}