implemented loading banking system from file

This commit is contained in:
Sven Vogel 2023-06-22 12:47:49 +02:00
parent 4b3f2bb59f
commit fae01ef464
9 changed files with 127 additions and 39 deletions

6
res/BankCSV_etwurf.csv Normal file
View File

@ -0,0 +1,6 @@
Bank;BLZ;Kontonummer;PIN;Kontostand;Kontoart;Zins %;Ueberziehungsbetrag;Kundennummer;Name;Vorname;Kunde Straße;Kunde PLZ;Kunde Ort
VR Bank Rhein-Neckar;MA2424;4711;1234;50,14 €;Sparkonto;3%;;123456;Mustermann;Max;Bahnhofstraße 1;68159;Mannheim
VR Bank Rhein-Neckar;MA2424;8321;1234;500,14;Girokonto;;1.000,27 €;123456;Mustermann;Max;Bahnhofstraße 1;68159;Mannheim
Berliner Bank;19087;1717;1234;500,14;Sparkonto;1,003;;717171;Mustermann;Max;Bahnhofstraße 1;68159;Mannheim
Berliner Bank;19087;1919;1234;540,2;Sparkonto;1,1;;717171;Mustermann;Max;Bahnhofstraße 1;68159;Mannheim
Zocker Bank;Zock7777;4444;7777;-8000,5;Girokonto;;50000,5;31124;Hogo;Gruber;Berlinestraß 33 / 1;7899;Berlin
1 Bank BLZ Kontonummer PIN Kontostand Kontoart Zins % Ueberziehungsbetrag Kundennummer Name Vorname Kunde Straße Kunde PLZ Kunde Ort
2 VR Bank Rhein-Neckar MA2424 4711 1234 50,14 € Sparkonto 3% 123456 Mustermann Max Bahnhofstraße 1 68159 Mannheim
3 VR Bank Rhein-Neckar MA2424 8321 1234 500,14 Girokonto 1.000,27 € 123456 Mustermann Max Bahnhofstraße 1 68159 Mannheim
4 Berliner Bank 19087 1717 1234 500,14 Sparkonto 1,003 717171 Mustermann Max Bahnhofstraße 1 68159 Mannheim
5 Berliner Bank 19087 1919 1234 540,2 Sparkonto 1,1 717171 Mustermann Max Bahnhofstraße 1 68159 Mannheim
6 Zocker Bank Zock7777 4444 7777 -8000,5 Girokonto 50000,5 31124 Hogo Gruber Berlinestraß 33 / 1 7899 Berlin

View File

@ -1,5 +1,7 @@
package me.teridax.jcash.banking; package me.teridax.jcash.banking;
import me.teridax.jcash.decode.Decoder;
import java.util.Objects; import java.util.Objects;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -9,10 +11,33 @@ public abstract class Account {
private final int pin; private final int pin;
private final double balance; private final double balance;
public Account(int iban, int pin) { public Account(int iban, int pin, double balance) {
this.iban = iban; this.iban = iban;
this.pin = pin; this.pin = pin;
this.balance = 0.0d; this.balance = balance;
}
public static Account fromColumns(String[] columns) {
Objects.requireNonNull(columns);
var iban = Decoder.decodeUniqueIdentificationNumber(columns[0]);
var pin = Decoder.decodeUniqueIdentificationNumber(columns[1]);
var balance = Decoder.decodeCurrency(columns[2]);
var type = Decoder.decodeName(columns[3]);
try {
if (type.equals("Sparkonto")) {
var interest = Decoder.decodePercent(columns[4]);
return new SavingsAccount(iban, pin, balance, interest);
} else if (type.equals("Girokonto")) {
var overdraft = Decoder.decodeCurrency(columns[5]);
return new Girokonto(iban, pin, balance, overdraft);
} else {
throw new IllegalArgumentException("Invalid account type: " + type);
}
} catch (IllegalArgumentException | NullPointerException e) {
throw new IllegalArgumentException("Account format: ", e);
}
} }
public int getIban() { public int getIban() {

View File

@ -8,7 +8,7 @@ public final class Bank {
private final String blz; private final String blz;
private final Map<Owner, Set<Account>> accounts; private final Map<Owner, Set<Account>> accounts;
private Bank(String blz, String name) { Bank(String blz, String name) {
this.blz = blz; this.blz = blz;
this.name = name; this.name = name;
this.accounts = new HashMap<>(); this.accounts = new HashMap<>();
@ -22,6 +22,12 @@ public final class Bank {
return name; return name;
} }
public void addAccount(Owner owner, Account account) {
var set = this.accounts.getOrDefault(owner, new HashSet<>());
set.add(account);
this.accounts.put(owner, set);
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj instanceof Bank) { if (obj instanceof Bank) {
@ -39,7 +45,7 @@ public final class Bank {
return accounts.get(owner).toArray(Account[]::new); return accounts.get(owner).toArray(Account[]::new);
} }
private static String validateBlz(String maybeBlz) { public static String validateBlz(String maybeBlz) {
var builder = new StringBuilder(); var builder = new StringBuilder();
maybeBlz.trim().chars().filter(ch -> Character.isDigit(ch) || Character.isLetter(ch)).forEach(builder::append); maybeBlz.trim().chars().filter(ch -> Character.isDigit(ch) || Character.isLetter(ch)).forEach(builder::append);
var blz = builder.toString(); var blz = builder.toString();

View File

@ -1,12 +1,11 @@
package me.teridax.jcash.banking; package me.teridax.jcash.banking;
import java.io.File; import me.teridax.jcash.decode.Decoder;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.ArrayList; import java.nio.file.Path;
import java.util.HashSet; import java.util.*;
import java.util.List;
import java.util.Set;
public final class BankingManagementSystem { public final class BankingManagementSystem {
@ -16,22 +15,43 @@ public final class BankingManagementSystem {
this.banks = new HashSet<>(); this.banks = new HashSet<>();
} }
public static BankingManagementSystem loadFromCsv(File file) { private static String[] tail(String[] array, int index) {
return Arrays.stream(array).skip(index).toArray(String[]::new);
}
public static BankingManagementSystem loadFromCsv(Path file) {
try { try {
var content = Files.readString(file.toPath()); var bms = new BankingManagementSystem();
var content = Files.readString(file);
var banks = new ArrayList<Bank>(); content.lines().skip(1).forEach(line -> {
var columns = line.split(";");
content.lines().forEach(line -> { if (columns.length != 14)
// load bank and account from line. throw new IllegalArgumentException("invalid column count: " + columns.length);
// transfer accounts to existing bank if already created
var owner = Owner.fromColumns(tail(columns, 8));
var account = Account.fromColumns(tail(columns, 2));
var blz = Bank.validateBlz(columns[1]);
var name = Decoder.decodeName(columns[0]);
var bankOfLine = new Bank(blz, name);
var bankOfSet = bms.banks.stream().filter(b -> b.equals(bankOfLine)).findFirst();
if (bankOfSet.isPresent()) {
bankOfSet.get().addAccount(owner, account);
} else {
bankOfLine.addAccount(owner, account);
bms.banks.add(bankOfLine);
}
}); });
} catch (IOException e) { return bms;
throw new IllegalArgumentException("Could not read file " + file);
}
return null; } catch (IOException e) {
throw new IllegalArgumentException("Could not read file " + file, e);
} catch (IllegalArgumentException | NullPointerException e) {
throw new IllegalArgumentException("Could not parse file " + file, e);
}
} }
} }

View File

@ -4,8 +4,8 @@ public class Girokonto extends Account {
private final double overdraft; private final double overdraft;
public Girokonto(int iban, int pin, double overdraft) { public Girokonto(int iban, int pin, double balance, double overdraft) {
super(iban, pin); super(iban, pin, balance);
this.overdraft = overdraft; this.overdraft = overdraft;
} }

View File

@ -1,5 +1,7 @@
package me.teridax.jcash.banking; package me.teridax.jcash.banking;
import me.teridax.jcash.decode.Decoder;
import java.util.Objects; import java.util.Objects;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -11,9 +13,7 @@ public final class Owner {
private int zip; private int zip;
private String city; private String city;
private Owner() { } private Owner(int uid, String familyName, String name, int zip, String city, String street) {
public Owner(int uid, String familyName, String name, int zip, String city, String street) {
this.uid = uid; this.uid = uid;
this.familyName = familyName; this.familyName = familyName;
this.name = name; this.name = name;
@ -22,6 +22,22 @@ public final class Owner {
this.street = street; this.street = street;
} }
public static Owner fromColumns(String... columns) throws IllegalArgumentException, NullPointerException {
Objects.requireNonNull(columns);
if (columns.length != 6)
throw new IllegalArgumentException("Invalid number of columns: " + columns.length);
var uid = Decoder.decodeUniqueIdentificationNumber(columns[0]);
var familyName = Decoder.decodeName(columns[1]);
var name = Decoder.decodeName(columns[2]);
var street = Decoder.decodeStreet(columns[3]);
var zip = Decoder.decodeUniqueIdentificationNumber(columns[4]);
var city = Decoder.decodeName(columns[5]);
return new Owner(uid, familyName, name, zip, city, street);
}
public long getUid() { public long getUid() {
return uid; return uid;
} }

View File

@ -5,8 +5,8 @@ public class SavingsAccount extends Account {
private final double interest; private final double interest;
public SavingsAccount(int iban, int pin, double interest) { public SavingsAccount(int iban, int pin, double balance, double interest) {
super(iban, pin); super(iban, pin, balance);
this.interest = interest; this.interest = interest;
} }

View File

@ -0,0 +1,13 @@
package me.teridax.jcash.banking;
import org.junit.Test;
import java.nio.file.Paths;
public class Testing {
@Test
public void test() {
BankingManagementSystem.loadFromCsv(Paths.get("res/BankCSV_etwurf.csv"));
}
}

View File

@ -38,7 +38,7 @@ public class Decoder {
} }
} }
public static int decodeSerialNumber(String number) throws IllegalArgumentException, NullPointerException { public static int decodeUniqueIdentificationNumber(String number) throws IllegalArgumentException, NullPointerException {
Objects.requireNonNull(number); Objects.requireNonNull(number);
// check if the string is a valid unsigned number // check if the string is a valid unsigned number
@ -57,11 +57,13 @@ public class Decoder {
var trimmed = name.trim(); var trimmed = name.trim();
// check if the string is a valid unsigned number var pattern = Pattern.compile("[\\w-\\s]+", Pattern.CASE_INSENSITIVE);
if (!trimmed.trim().chars().allMatch(Character::isLetter)) var matcher = pattern.matcher(trimmed);
throw new IllegalArgumentException("Not a valid name: " + name); if (matcher.find()) {
return matcher.group();
return trimmed; } else {
throw new IllegalArgumentException("not a void name");
}
} }
public static String decodeStreet(String street) throws IllegalArgumentException, NullPointerException { public static String decodeStreet(String street) throws IllegalArgumentException, NullPointerException {
@ -78,9 +80,9 @@ public class Decoder {
@Test @Test
public void testDecodeSuccessfulFunctions() { public void testDecodeSuccessfulFunctions() {
decodeSerialNumber("95786978625347895"); decodeUniqueIdentificationNumber("95786978625347895");
decodeSerialNumber(" 927856347 "); decodeUniqueIdentificationNumber(" 927856347 ");
decodeSerialNumber("0"); decodeUniqueIdentificationNumber("0");
decodeName("Adolf"); decodeName("Adolf");
decodeName("Günther"); decodeName("Günther");
@ -101,10 +103,10 @@ public class Decoder {
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testDecodeInvalidFunctions() { public void testDecodeInvalidFunctions() {
decodeSerialNumber("q0948tvb6q047t 740 t74z0tz 784"); decodeUniqueIdentificationNumber("q0948tvb6q047t 740 t74z0tz 784");
decodeSerialNumber("-39867.8475"); decodeUniqueIdentificationNumber("-39867.8475");
decodeSerialNumber("-398678475"); decodeUniqueIdentificationNumber("-398678475");
decodeSerialNumber(" ß9qu908t76q34798t6q734vb9843"); decodeUniqueIdentificationNumber(" ß9qu908t76q34798t6q734vb9843");
decodeName("John Doe"); decodeName("John Doe");
decodeName("3490qt67v 0b34"); decodeName("3490qt67v 0b34");