From 2d8ad91410a875b2ba210e2babfeaba64dcd6a67 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Sun, 22 Jan 2023 11:22:03 +0100 Subject: [PATCH 01/29] updated version --- BudgetMasterServer/pom.xml | 2 +- pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BudgetMasterServer/pom.xml b/BudgetMasterServer/pom.xml index 0c5f9624..5daef247 100644 --- a/BudgetMasterServer/pom.xml +++ b/BudgetMasterServer/pom.xml @@ -5,7 +5,7 @@ BudgetMaster de.deadlocker8 - 2.13.0 + 2.14.0 4.0.0 diff --git a/pom.xml b/pom.xml index 7e090178..c932b67a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ de.deadlocker8 BudgetMaster pom - 2.13.0 + 2.14.0 BudgetMaster @@ -51,7 +51,7 @@ ${maven.build.timestamp} dd.MM.yy - 41 + 42 Robert Goldmann 1.17.6 From bd968ab0cd5370064a63b54d7158ce00be230fb2 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Sun, 22 Jan 2023 19:45:03 +0100 Subject: [PATCH 02/29] fixed localization --- .../src/main/resources/languages/base_de.properties | 1 + .../src/main/resources/languages/base_en.properties | 1 + .../src/main/resources/templates/settings/settings.ftl | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BudgetMasterServer/src/main/resources/languages/base_de.properties b/BudgetMasterServer/src/main/resources/languages/base_de.properties index c553d3e8..776663e5 100644 --- a/BudgetMasterServer/src/main/resources/languages/base_de.properties +++ b/BudgetMasterServer/src/main/resources/languages/base_de.properties @@ -320,6 +320,7 @@ settings.category.circle.style=Kategorien anzeigen als settings.category.circle.style.description=Legt die Darstellung von Kategorien in der Buchungsübersicht fest settings.category.circle.style.deactivated=Quadrate settings.category.circle.style.activated=Kreise +settings.security=Sicherheit settings.personalization=Personalisierung settings.personalization.reload.page=Zum Anwenden visueller Änderungen Seite neu laden settings.transactions=Buchungen diff --git a/BudgetMasterServer/src/main/resources/languages/base_en.properties b/BudgetMasterServer/src/main/resources/languages/base_en.properties index 4f6183d1..00f35973 100644 --- a/BudgetMasterServer/src/main/resources/languages/base_en.properties +++ b/BudgetMasterServer/src/main/resources/languages/base_en.properties @@ -320,6 +320,7 @@ settings.category.circle.style=Show categories as settings.category.circle.style.description=Defines how categories are displayed in the transaction overview settings.category.circle.style.deactivated=Squares settings.category.circle.style.activated=Circles +settings.security=Security settings.personalization=Personalization settings.personalization.reload.page=Reload page to apply visual changes settings.transactions=Transactions diff --git a/BudgetMasterServer/src/main/resources/templates/settings/settings.ftl b/BudgetMasterServer/src/main/resources/templates/settings/settings.ftl index d5877069..50e01d2b 100644 --- a/BudgetMasterServer/src/main/resources/templates/settings/settings.ftl +++ b/BudgetMasterServer/src/main/resources/templates/settings/settings.ftl @@ -39,7 +39,7 @@
    - <@settingsMacros.settingsCollapsibleItem "securitySettingsContainer" "vpn_key" "Security"> + <@settingsMacros.settingsCollapsibleItem "securitySettingsContainer" "vpn_key" locale.getString("settings.security")> <@settingsSecurityMacros.securitySettingsContainer importScripts=false/> From 35daa092de9467cf26f28e5e16e2b95e596d1ce6 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Mon, 13 Feb 2023 23:08:11 +0100 Subject: [PATCH 03/29] #731 - amount parser should respect grouping separators --- .../TransactionImportService.java | 2 +- .../transactions/csvimport/AmountParser.java | 28 ++++-- .../csvimport/AmountParserTest.java | 98 ++++++++++++++----- 3 files changed, 95 insertions(+), 33 deletions(-) diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java index eaf3ecde..cc7ddc64 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java @@ -41,7 +41,7 @@ public CsvTransaction createCsvTransactionFromCsvRow(CsvRow csvRow, CsvColumnSet final String description = csvRow.getColumns().get(csvColumnSettings.columnDescription() - 1); final String amount = csvRow.getColumns().get(csvColumnSettings.columnAmount() - 1); - final Optional parsedAmountOptional = AmountParser.parse(amount); + final Optional parsedAmountOptional = AmountParser.parse(amount, '.', ','); if(parsedAmountOptional.isEmpty()) { throw new CsvTransactionParseException(Localization.getString("transactions.import.error.parse.amount", index + 1)); diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/AmountParser.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/AmountParser.java index 2d87372d..4b3ef7fd 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/AmountParser.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/AmountParser.java @@ -1,19 +1,22 @@ package de.deadlocker8.budgetmaster.transactions.csvimport; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.text.MessageFormat; +import java.text.ParseException; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; public class AmountParser { - private static final Pattern PATTERN_AMOUNT = Pattern.compile("^\\s*([-+]?)\\s*(\\d+(,\\d+)?(\\.\\d+)?)"); + private static final Pattern PATTERN_AMOUNT = Pattern.compile("^\\s*([-+]?)\\s*(\\d+(.*\\d+)?)"); private AmountParser() { } - public static Optional parse(String amountString) + public static Optional parse(String amountString, char decimalSeparator, char groupingSeparator) { if(amountString == null) { @@ -24,17 +27,28 @@ public static Optional parse(String amountString) boolean matchFound = matcher.find(); if(matchFound) { - final String sign = matcher.group(1); - String amount = matcher.group(2); - amount = amount.replace(',', '.'); + String sign = matcher.group(1); + if(sign.equals("+")) + { + sign = ""; + } + + final String amount = matcher.group(2); + + final DecimalFormat decimalFormat = new DecimalFormat(); + final DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + symbols.setDecimalSeparator(decimalSeparator); + symbols.setGroupingSeparator(groupingSeparator); + decimalFormat.setNegativePrefix("-"); + decimalFormat.setDecimalFormatSymbols(symbols); final String parseableString = MessageFormat.format("{0}{1}", sign, amount); try { - final double parseDouble = Double.parseDouble(parseableString); + final double parseDouble = decimalFormat.parse(parseableString).doubleValue(); return Optional.of((int) (parseDouble * 100)); } - catch(NumberFormatException e) + catch(ParseException e) { return Optional.empty(); } diff --git a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/transaction/csvimport/AmountParserTest.java b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/transaction/csvimport/AmountParserTest.java index 5fdf610d..ed074cb5 100644 --- a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/transaction/csvimport/AmountParserTest.java +++ b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/transaction/csvimport/AmountParserTest.java @@ -13,7 +13,7 @@ class AmountParserTest @Test void test_dot_positive_noCurrency() { - assertThat(AmountParser.parse("12.03")) + assertThat(AmountParser.parse("12.03", '.', ',')) .isPresent() .get().isEqualTo(1203); } @@ -21,7 +21,7 @@ void test_dot_positive_noCurrency() @Test void test_dot_negative_noCurrency() { - assertThat(AmountParser.parse("-18.41")) + assertThat(AmountParser.parse("-18.41", '.', ',')) .isPresent() .get().isEqualTo(-1841); } @@ -29,7 +29,7 @@ void test_dot_negative_noCurrency() @Test void test_dot_negativeWithSpace_noCurrency() { - assertThat(AmountParser.parse("- 200.30")) + assertThat(AmountParser.parse("- 200.30", '.', ',')) .isPresent() .get().isEqualTo(-20030); } @@ -37,7 +37,7 @@ void test_dot_negativeWithSpace_noCurrency() @Test void test_dot_positive_currency() { - assertThat(AmountParser.parse("12.03 €")) + assertThat(AmountParser.parse("12.03 €", '.', ',')) .isPresent() .get().isEqualTo(1203); } @@ -45,7 +45,7 @@ void test_dot_positive_currency() @Test void test_dot_negative_currency() { - assertThat(AmountParser.parse("-18.41€")) + assertThat(AmountParser.parse("-18.41€", '.', ',')) .isPresent() .get().isEqualTo(-1841); } @@ -53,7 +53,7 @@ void test_dot_negative_currency() @Test void test_dot_positiveWithSign_noCurrency() { - assertThat(AmountParser.parse("+12.03")) + assertThat(AmountParser.parse("+12.03", '.', ',')) .isPresent() .get().isEqualTo(1203); } @@ -61,7 +61,7 @@ void test_dot_positiveWithSign_noCurrency() @Test void test_dot_positiveWithSignWithSpace_noCurrency() { - assertThat(AmountParser.parse("+ 12.03")) + assertThat(AmountParser.parse("+ 12.03", '.', ',')) .isPresent() .get().isEqualTo(1203); } @@ -69,7 +69,7 @@ void test_dot_positiveWithSignWithSpace_noCurrency() @Test void test_comma_positive_noCurrency() { - assertThat(AmountParser.parse("12,03")) + assertThat(AmountParser.parse("12,03", ',', '.')) .isPresent() .get().isEqualTo(1203); } @@ -77,7 +77,7 @@ void test_comma_positive_noCurrency() @Test void test_comma_negative_noCurrency() { - assertThat(AmountParser.parse("-18,41")) + assertThat(AmountParser.parse("-18,41", ',', '.')) .isPresent() .get().isEqualTo(-1841); } @@ -85,7 +85,7 @@ void test_comma_negative_noCurrency() @Test void test_comma_negativeWithSpace_noCurrency() { - assertThat(AmountParser.parse("- 200,30")) + assertThat(AmountParser.parse("- 200,30", ',', '.')) .isPresent() .get().isEqualTo(-20030); } @@ -93,7 +93,7 @@ void test_comma_negativeWithSpace_noCurrency() @Test void test_comma_positive_currency() { - assertThat(AmountParser.parse("12,03 €")) + assertThat(AmountParser.parse("12,03 €", ',', '.')) .isPresent() .get().isEqualTo(1203); } @@ -101,7 +101,7 @@ void test_comma_positive_currency() @Test void test_comma_negative_currency() { - assertThat(AmountParser.parse("-18,41€")) + assertThat(AmountParser.parse("-18,41€", ',', '.')) .isPresent() .get().isEqualTo(-1841); } @@ -109,7 +109,7 @@ void test_comma_negative_currency() @Test void test_comma_positiveWithSign_noCurrency() { - assertThat(AmountParser.parse("+12,03")) + assertThat(AmountParser.parse("+12,03", ',', '.')) .isPresent() .get().isEqualTo(1203); } @@ -117,7 +117,7 @@ void test_comma_positiveWithSign_noCurrency() @Test void test_comma_positiveWithSignWithSpace_noCurrency() { - assertThat(AmountParser.parse("+12,03")) + assertThat(AmountParser.parse("+12,03", ',', '.')) .isPresent() .get().isEqualTo(1203); } @@ -125,35 +125,35 @@ void test_comma_positiveWithSignWithSpace_noCurrency() @Test void test_invalid_null() { - assertThat(AmountParser.parse(null)) + assertThat(AmountParser.parse(null, '.', ',')) .isEmpty(); } @Test void test_invalid_empty() { - assertThat(AmountParser.parse("")) + assertThat(AmountParser.parse("", '.', ',')) .isEmpty(); } @Test void test_invalid_empty2() { - assertThat(AmountParser.parse(" ")) + assertThat(AmountParser.parse(" ", '.', ',')) .isEmpty(); } @Test void test_invalid() { - assertThat(AmountParser.parse("abc.42€")) + assertThat(AmountParser.parse("abc.42€", '.', ',')) .isEmpty(); } @Test void test_integer_positive_noCurrency() { - assertThat(AmountParser.parse("12")) + assertThat(AmountParser.parse("12", '.', ',')) .isPresent() .get().isEqualTo(1200); } @@ -161,7 +161,7 @@ void test_integer_positive_noCurrency() @Test void test_integer_negative_noCurrency() { - assertThat(AmountParser.parse("-18")) + assertThat(AmountParser.parse("-18", '.', ',')) .isPresent() .get().isEqualTo(-1800); } @@ -169,7 +169,7 @@ void test_integer_negative_noCurrency() @Test void test_integer_negativeWithSpace_noCurrency() { - assertThat(AmountParser.parse("- 200")) + assertThat(AmountParser.parse("- 200", '.', ',')) .isPresent() .get().isEqualTo(-20000); } @@ -177,7 +177,7 @@ void test_integer_negativeWithSpace_noCurrency() @Test void test_integer_positive_currency() { - assertThat(AmountParser.parse("12 €")) + assertThat(AmountParser.parse("12 €", '.', ',')) .isPresent() .get().isEqualTo(1200); } @@ -185,7 +185,7 @@ void test_integer_positive_currency() @Test void test_integer_negative_currency() { - assertThat(AmountParser.parse("-18€")) + assertThat(AmountParser.parse("-18€", '.', ',')) .isPresent() .get().isEqualTo(-1800); } @@ -193,7 +193,7 @@ void test_integer_negative_currency() @Test void test_integer_positiveWithSign_noCurrency() { - assertThat(AmountParser.parse("+12")) + assertThat(AmountParser.parse("+12", '.', ',')) .isPresent() .get().isEqualTo(1200); } @@ -201,8 +201,56 @@ void test_integer_positiveWithSign_noCurrency() @Test void test_integer_positiveWithSignWithSpace_noCurrency() { - assertThat(AmountParser.parse("+ 12")) + assertThat(AmountParser.parse("+ 12", '.', ',')) .isPresent() .get().isEqualTo(1200); } + + @Test + void test_thousandsDelimiter_integer() + { + assertThat(AmountParser.parse("1,234", '.', ',')) + .isPresent() + .get().isEqualTo(123400); + } + + @Test + void test_thousandsDelimiter_dot() + { + assertThat(AmountParser.parse("1,234.03", '.', ',')) + .isPresent() + .get().isEqualTo(123403); + } + + @Test + void test_thousandsDelimiter_withCurrency() + { + assertThat(AmountParser.parse("1,234.03 €", '.', ',')) + .isPresent() + .get().isEqualTo(123403); + } + + @Test + void test_thousandsDelimiter_negative() + { + assertThat(AmountParser.parse("-1,234.03 €", '.', ',')) + .isPresent() + .get().isEqualTo(-123403); + } + + @Test + void test_thousandsDelimiter_specialDelimiter() + { + assertThat(AmountParser.parse("-1.234,03 €", ',', '.')) + .isPresent() + .get().isEqualTo(-123403); + } + + @Test + void test_thousandsDelimiter_bigNumber() + { + assertThat(AmountParser.parse("-1.234.567,03 €", ',', '.')) + .isPresent() + .get().isEqualTo(-123456703); + } } From 32f9078151b1baf105a120bc6a20143a0511eb74 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Mon, 13 Feb 2023 23:33:14 +0100 Subject: [PATCH 04/29] #731 - added new inputs for decimal and grouping delimiter --- .../TransactionImportService.java | 2 +- .../csvimport/CsvColumnSettings.java | 29 +++++++++++++------ .../resources/languages/base_de.properties | 2 ++ .../resources/languages/base_en.properties | 2 ++ .../transactions/transactionImport.ftl | 22 ++++++++++---- .../unit/TransactionImportServiceTest.java | 6 ++-- 6 files changed, 45 insertions(+), 18 deletions(-) diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java index cc7ddc64..747cc5fc 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java @@ -41,7 +41,7 @@ public CsvTransaction createCsvTransactionFromCsvRow(CsvRow csvRow, CsvColumnSet final String description = csvRow.getColumns().get(csvColumnSettings.columnDescription() - 1); final String amount = csvRow.getColumns().get(csvColumnSettings.columnAmount() - 1); - final Optional parsedAmountOptional = AmountParser.parse(amount, '.', ','); + final Optional parsedAmountOptional = AmountParser.parse(amount, csvColumnSettings.getDecimalSeparator().charAt(0), csvColumnSettings.getGroupingSeparator().charAt(0)); if(parsedAmountOptional.isEmpty()) { throw new CsvTransactionParseException(Localization.getString("transactions.import.error.parse.amount", index + 1)); diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvColumnSettings.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvColumnSettings.java index bae02c77..7ecc044f 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvColumnSettings.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvColumnSettings.java @@ -5,17 +5,21 @@ public final class CsvColumnSettings { private final int columnDate; - private String datePattern; + private final String datePattern; private final int columnName; private final int columnAmount; + private final String decimalSeparator; + private final String groupingSeparator; private final int columnDescription; - public CsvColumnSettings(int columnDate, String datePattern, int columnName, int columnAmount, int columnDescription) + public CsvColumnSettings(int columnDate, String datePattern, int columnName, int columnAmount, String decimalSeparator, String groupingSeparator, int columnDescription) { this.columnDate = columnDate; this.datePattern = datePattern; this.columnName = columnName; this.columnAmount = columnAmount; + this.decimalSeparator = decimalSeparator; + this.groupingSeparator = groupingSeparator; this.columnDescription = columnDescription; } @@ -29,11 +33,6 @@ public String getDatePattern() return datePattern; } - public void setDatePattern(String datePattern) - { - this.datePattern = datePattern; - } - public int columnName() { return columnName; @@ -44,6 +43,16 @@ public int columnAmount() return columnAmount; } + public String getDecimalSeparator() + { + return decimalSeparator; + } + + public String getGroupingSeparator() + { + return groupingSeparator; + } + public int columnDescription() { return columnDescription; @@ -55,13 +64,13 @@ public boolean equals(Object o) if(this == o) return true; if(o == null || getClass() != o.getClass()) return false; CsvColumnSettings that = (CsvColumnSettings) o; - return columnDate == that.columnDate && columnName == that.columnName && columnAmount == that.columnAmount && columnDescription == that.columnDescription && Objects.equals(datePattern, that.datePattern); + return columnDate == that.columnDate && columnName == that.columnName && columnAmount == that.columnAmount && columnDescription == that.columnDescription && Objects.equals(datePattern, that.datePattern) && Objects.equals(decimalSeparator, that.decimalSeparator) && Objects.equals(groupingSeparator, that.groupingSeparator); } @Override public int hashCode() { - return Objects.hash(columnDate, datePattern, columnName, columnAmount, columnDescription); + return Objects.hash(columnDate, datePattern, columnName, columnAmount, decimalSeparator, groupingSeparator, columnDescription); } @Override @@ -72,6 +81,8 @@ public String toString() ", datePattern='" + datePattern + '\'' + ", columnName=" + columnName + ", columnAmount=" + columnAmount + + ", decimalSeparator='" + decimalSeparator + '\'' + + ", groupingSeparator='" + groupingSeparator + '\'' + ", columnDescription=" + columnDescription + '}'; } diff --git a/BudgetMasterServer/src/main/resources/languages/base_de.properties b/BudgetMasterServer/src/main/resources/languages/base_de.properties index 776663e5..8ab8cc20 100644 --- a/BudgetMasterServer/src/main/resources/languages/base_de.properties +++ b/BudgetMasterServer/src/main/resources/languages/base_de.properties @@ -376,6 +376,8 @@ transactions.import.separator=Trennzeichen transactions.import.encoding=Kodierung transactions.import.numberOfLinesToSkip=Zeilen überspringen transactions.import.datePattern=Datumsformat +transactions.import.decimalSeparator=Dezimaltrennzeichen +transactions.import.groupingSeparator=Gruppierungstrennzeichen transactions.import.status=Status transactions.import.status.pending=ausstehend transactions.import.status.imported=importiert diff --git a/BudgetMasterServer/src/main/resources/languages/base_en.properties b/BudgetMasterServer/src/main/resources/languages/base_en.properties index 00f35973..7d36f341 100644 --- a/BudgetMasterServer/src/main/resources/languages/base_en.properties +++ b/BudgetMasterServer/src/main/resources/languages/base_en.properties @@ -376,6 +376,8 @@ transactions.import.encoding=Encoding transactions.import.numberOfLinesToSkip=Skip lines transactions.import.datePattern=Date pattern transactions.import.status=Status +transactions.import.decimalSeparator=Decimal separator +transactions.import.groupingSeparator=Grouping separator transactions.import.status.pending=pending transactions.import.status.imported=imported transactions.import.status.skipped=skipped diff --git a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl index 882c0b1f..4e87a20d 100644 --- a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl +++ b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl @@ -131,13 +131,13 @@ ${locale.getString("transaction.new.label.date")}
-
+
value="<#if csvColumnSettings??>${csvColumnSettings.columnDate()}">
-
+
value="<#if csvColumnSettings??>${csvColumnSettings.datePattern()}<#else>dd.MM.yyyy">
@@ -153,7 +153,7 @@ ${locale.getString("transaction.new.label.name")}
-
+
value="<#if csvColumnSettings??>${csvColumnSettings.columnName()}">
@@ -165,11 +165,23 @@ ${locale.getString("transaction.new.label.amount")}
-
+
value="<#if csvColumnSettings??>${csvColumnSettings.columnAmount()}">
+
+
+ value="<#if csvColumnSettings??>${csvColumnSettings.decimalSeparator()}<#else>."> + +
+ +
+ value="<#if csvColumnSettings??>${csvColumnSettings.groupingSeparator()}<#else>,"> + +
+
+
@@ -177,7 +189,7 @@ ${locale.getString("transaction.new.label.description")}
-
+
value="<#if csvColumnSettings??>${csvColumnSettings.columnDescription()}">
diff --git a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionImportServiceTest.java b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionImportServiceTest.java index 4bd90cea..cbc2a34e 100644 --- a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionImportServiceTest.java +++ b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionImportServiceTest.java @@ -110,7 +110,7 @@ void test_createCsvTransactionFromCsvRow() throws CsvTransactionParseException final LocalDate date = LocalDate.of(2023, 1, 21); final CsvRow csvRow = new CsvRow("21.01.2023", "Groceries", "-12.00", "dolor sit amet"); - final CsvColumnSettings csvColumnSettings = new CsvColumnSettings(1, "dd.MM.yyyy", 2, 3, 4); + final CsvColumnSettings csvColumnSettings = new CsvColumnSettings(1, "dd.MM.yyyy", 2, 3, ".", ",", 4); final CsvTransaction expectedCsvTransaction = new CsvTransaction(date, "Groceries", -1200, "dolor sit amet", CsvTransactionStatus.PENDING, CATEGORY_NONE); @@ -129,7 +129,7 @@ void test_createCsvTransactionFromCsvRow() throws CsvTransactionParseException void test_createCsvTransactionFromCsvRow_dateParseException() { final CsvRow csvRow = new CsvRow("21.01.2023", "Groceries", "-12.00", "dolor sit amet"); - final CsvColumnSettings csvColumnSettings = new CsvColumnSettings(1, "dd.MM.", 2, 3, 4); + final CsvColumnSettings csvColumnSettings = new CsvColumnSettings(1, "dd.MM.", 2, 3, ".", ",", 4); final Settings settings = new Settings(); settings.setLanguage(LanguageType.ENGLISH); @@ -145,7 +145,7 @@ void test_createCsvTransactionFromCsvRow_dateParseException() void test_createCsvTransactionFromCsvRow_amountParseException() { final CsvRow csvRow = new CsvRow("21.01.2023", "Groceries", "non_amount", "dolor sit amet"); - final CsvColumnSettings csvColumnSettings = new CsvColumnSettings(1, "dd.MM.yyyy", 2, 3, 4); + final CsvColumnSettings csvColumnSettings = new CsvColumnSettings(1, "dd.MM.yyyy", 2, 3, ".", ",", 4); final Settings settings = new Settings(); settings.setLanguage(LanguageType.ENGLISH); From 14e39fffbe928273c2f6f1cd186da7adff049b53 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Mon, 13 Feb 2023 23:34:42 +0100 Subject: [PATCH 05/29] #731 - refactoring: convert CsvColumnSettings to record --- .../TransactionImportService.java | 6 +- .../csvimport/CsvColumnSettings.java | 87 +------------------ 2 files changed, 5 insertions(+), 88 deletions(-) diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java index 747cc5fc..26604fd7 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportService.java @@ -31,17 +31,17 @@ public TransactionImportService(HelpersService helpersService, SettingsService s public CsvTransaction createCsvTransactionFromCsvRow(CsvRow csvRow, CsvColumnSettings csvColumnSettings, Integer index) throws CsvTransactionParseException { final String date = csvRow.getColumns().get(csvColumnSettings.columnDate() - 1); - final Optional parsedDateOptional = DateParser.parse(date, csvColumnSettings.getDatePattern(), settingsService.getSettings().getLanguage().getLocale()); + final Optional parsedDateOptional = DateParser.parse(date, csvColumnSettings.datePattern(), settingsService.getSettings().getLanguage().getLocale()); if(parsedDateOptional.isEmpty()) { - throw new CsvTransactionParseException(Localization.getString("transactions.import.error.parse.date", index + 1, date, csvColumnSettings.getDatePattern())); + throw new CsvTransactionParseException(Localization.getString("transactions.import.error.parse.date", index + 1, date, csvColumnSettings.datePattern())); } final String name = csvRow.getColumns().get(csvColumnSettings.columnName() - 1); final String description = csvRow.getColumns().get(csvColumnSettings.columnDescription() - 1); final String amount = csvRow.getColumns().get(csvColumnSettings.columnAmount() - 1); - final Optional parsedAmountOptional = AmountParser.parse(amount, csvColumnSettings.getDecimalSeparator().charAt(0), csvColumnSettings.getGroupingSeparator().charAt(0)); + final Optional parsedAmountOptional = AmountParser.parse(amount, csvColumnSettings.decimalSeparator().charAt(0), csvColumnSettings.groupingSeparator().charAt(0)); if(parsedAmountOptional.isEmpty()) { throw new CsvTransactionParseException(Localization.getString("transactions.import.error.parse.amount", index + 1)); diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvColumnSettings.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvColumnSettings.java index 7ecc044f..9eabb569 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvColumnSettings.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvColumnSettings.java @@ -1,89 +1,6 @@ package de.deadlocker8.budgetmaster.transactions.csvimport; -import java.util.Objects; - -public final class CsvColumnSettings +public record CsvColumnSettings(int columnDate, String datePattern, int columnName, int columnAmount, + String decimalSeparator, String groupingSeparator, int columnDescription) { - private final int columnDate; - private final String datePattern; - private final int columnName; - private final int columnAmount; - private final String decimalSeparator; - private final String groupingSeparator; - private final int columnDescription; - - public CsvColumnSettings(int columnDate, String datePattern, int columnName, int columnAmount, String decimalSeparator, String groupingSeparator, int columnDescription) - { - this.columnDate = columnDate; - this.datePattern = datePattern; - this.columnName = columnName; - this.columnAmount = columnAmount; - this.decimalSeparator = decimalSeparator; - this.groupingSeparator = groupingSeparator; - this.columnDescription = columnDescription; - } - - public int columnDate() - { - return columnDate; - } - - public String getDatePattern() - { - return datePattern; - } - - public int columnName() - { - return columnName; - } - - public int columnAmount() - { - return columnAmount; - } - - public String getDecimalSeparator() - { - return decimalSeparator; - } - - public String getGroupingSeparator() - { - return groupingSeparator; - } - - public int columnDescription() - { - return columnDescription; - } - - @Override - public boolean equals(Object o) - { - if(this == o) return true; - if(o == null || getClass() != o.getClass()) return false; - CsvColumnSettings that = (CsvColumnSettings) o; - return columnDate == that.columnDate && columnName == that.columnName && columnAmount == that.columnAmount && columnDescription == that.columnDescription && Objects.equals(datePattern, that.datePattern) && Objects.equals(decimalSeparator, that.decimalSeparator) && Objects.equals(groupingSeparator, that.groupingSeparator); - } - - @Override - public int hashCode() - { - return Objects.hash(columnDate, datePattern, columnName, columnAmount, decimalSeparator, groupingSeparator, columnDescription); - } - - @Override - public String toString() - { - return "CsvColumnSettings{" + - "columnDate=" + columnDate + - ", datePattern='" + datePattern + '\'' + - ", columnName=" + columnName + - ", columnAmount=" + columnAmount + - ", decimalSeparator='" + decimalSeparator + '\'' + - ", groupingSeparator='" + groupingSeparator + '\'' + - ", columnDescription=" + columnDescription + - '}'; - } } From 29a273cbd3b517f31f3c3330c3511a0c273af716 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Mon, 13 Feb 2023 23:38:22 +0100 Subject: [PATCH 06/29] #731 - prefill inputs with values depending on locale --- .../budgetmaster/services/HelpersService.java | 11 +++++++++++ .../templates/transactions/transactionImport.ftl | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java index 78df3ee9..4c55b3e5 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.text.DecimalFormatSymbols; import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; @@ -218,4 +219,14 @@ public Hint getHintByLocalizationKey(String localizationKey) { return hintService.findByLocalizationKey(localizationKey); } + + public char getDecimalSeparator() + { + return new DecimalFormatSymbols(settingsService.getSettings().getLanguage().getLocale()).getDecimalSeparator(); + } + + public char getGroupingSeparator() + { + return new DecimalFormatSymbols(settingsService.getSettings().getLanguage().getLocale()).getGroupingSeparator(); + } } \ No newline at end of file diff --git a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl index 4e87a20d..b52ac474 100644 --- a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl +++ b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl @@ -172,12 +172,12 @@
- value="<#if csvColumnSettings??>${csvColumnSettings.decimalSeparator()}<#else>."> + value="<#if csvColumnSettings??>${csvColumnSettings.decimalSeparator()}<#else>${helpers.getDecimalSeparator()}">
- value="<#if csvColumnSettings??>${csvColumnSettings.groupingSeparator()}<#else>,"> + value="<#if csvColumnSettings??>${csvColumnSettings.groupingSeparator()}<#else>${helpers.getGroupingSeparator()}">
From 45083c44e8349bafac0101ac796b7beb097fa7c6 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Sun, 19 Feb 2023 12:39:20 +0100 Subject: [PATCH 07/29] #731 - only allow one character per separator input --- .../resources/templates/transactions/transactionImport.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl index b52ac474..e1c7ab9e 100644 --- a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl +++ b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl @@ -172,12 +172,12 @@
- value="<#if csvColumnSettings??>${csvColumnSettings.decimalSeparator()}<#else>${helpers.getDecimalSeparator()}"> + value="<#if csvColumnSettings??>${csvColumnSettings.decimalSeparator()}<#else>${helpers.getDecimalSeparator()}">
- value="<#if csvColumnSettings??>${csvColumnSettings.groupingSeparator()}<#else>${helpers.getGroupingSeparator()}"> + value="<#if csvColumnSettings??>${csvColumnSettings.groupingSeparator()}<#else>${helpers.getGroupingSeparator()}">
From 86b4e0333efc2c4c2daf37c24dab272f2c84585e Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Sun, 19 Feb 2023 12:39:51 +0100 Subject: [PATCH 08/29] #731 - AmountParser: check if whole string is used otherwise throw an error --- .../transactions/csvimport/AmountParser.java | 17 +++++++++++------ .../transaction/csvimport/AmountParserTest.java | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/AmountParser.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/AmountParser.java index 4b3ef7fd..11a00e24 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/AmountParser.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/AmountParser.java @@ -1,9 +1,8 @@ package de.deadlocker8.budgetmaster.transactions.csvimport; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.MessageFormat; -import java.text.ParseException; +import org.springframework.security.core.parameters.P; + +import java.text.*; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,7 +34,7 @@ public static Optional parse(String amountString, char decimalSeparator final String amount = matcher.group(2); - final DecimalFormat decimalFormat = new DecimalFormat(); + final DecimalFormat decimalFormat = new DecimalFormat("#,###.#"); final DecimalFormatSymbols symbols = new DecimalFormatSymbols(); symbols.setDecimalSeparator(decimalSeparator); symbols.setGroupingSeparator(groupingSeparator); @@ -43,9 +42,15 @@ public static Optional parse(String amountString, char decimalSeparator decimalFormat.setDecimalFormatSymbols(symbols); final String parseableString = MessageFormat.format("{0}{1}", sign, amount); + final ParsePosition parsePosition = new ParsePosition(0); try { - final double parseDouble = decimalFormat.parse(parseableString).doubleValue(); + final double parseDouble = decimalFormat.parse(parseableString, parsePosition).doubleValue(); + if(parsePosition.getIndex() != parseableString.length()) + { + throw new ParseException("String not fully parsed", parsePosition.getIndex()); + } + return Optional.of((int) (parseDouble * 100)); } catch(ParseException e) diff --git a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/transaction/csvimport/AmountParserTest.java b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/transaction/csvimport/AmountParserTest.java index ed074cb5..3f64af30 100644 --- a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/transaction/csvimport/AmountParserTest.java +++ b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/transaction/csvimport/AmountParserTest.java @@ -246,6 +246,21 @@ void test_thousandsDelimiter_specialDelimiter() .get().isEqualTo(-123403); } + @Test + void test_thousandsDelimiter_specialDelimiter_invalid() + { + assertThat(AmountParser.parse("-234.03 €", 'e', 't')) + .isEmpty(); + } + + @Test + void test_thousandsDelimiter_specialDelimiter_valid() + { + assertThat(AmountParser.parse("-1t234e03 €", 'e', 't')) + .isPresent() + .get().isEqualTo(-123403); + } + @Test void test_thousandsDelimiter_bigNumber() { From 51c9c8f73659b32fad1c6d4892c657bc405aee7a Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Sun, 19 Feb 2023 12:42:07 +0100 Subject: [PATCH 09/29] #731 - added selenium tests --- .../integration/selenium/CsvImportTest.java | 64 +++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CsvImportTest.java b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CsvImportTest.java index 4b3fdd37..01c5b069 100644 --- a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CsvImportTest.java +++ b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CsvImportTest.java @@ -203,7 +203,7 @@ void test_upload_emptyDatePattern_showValidationError() assertThat(driver.findElement(By.id("csv-file-name")).getText()).isEqualTo("three_entries.csv"); - fillColumnSettings(1, "", 2, 3, 2); + fillColumnSettings(1, "", 2, 3, ".", ",", 2); wait = new WebDriverWait(driver, Duration.ofSeconds(5)); wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#datePattern.invalid"))); @@ -226,7 +226,7 @@ void test_upload_invalidColumnSettings_showValidationError() assertThat(driver.findElement(By.id("csv-file-name")).getText()).isEqualTo("three_entries.csv"); - fillColumnSettings(-3, "dd.MM.yyyy", 200, -12, 115); + fillColumnSettings(-3, "dd.MM.yyyy", 200, -12, ".", ",", 115); wait = new WebDriverWait(driver, Duration.ofSeconds(5)); wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#columnDate.invalid"))); @@ -237,6 +237,52 @@ void test_upload_invalidColumnSettings_showValidationError() assertThat(driver.findElement(By.cssSelector("#columnDescription.invalid"))).isNotNull(); } + @Test + void test_upload_emptyDecimalSeparator_showValidationError() + { + driver.get(helper.getUrl() + "/transactionImport"); + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(ExpectedConditions.textToBePresentInElementLocated(By.cssSelector(".headline"), "Import from bank CSV")); + + final String csvPath = new File(getClass().getClassLoader().getResource("csv/three_entries.csv").getFile()).getAbsolutePath(); + + uploadCsv(csvPath, ";", "UTF-8", "1"); + wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("button-cancel-csv-import"))); + + assertThat(driver.findElement(By.id("csv-file-name")).getText()).isEqualTo("three_entries.csv"); + + fillColumnSettings(1, "", 2, 3, "", ",",2); + + wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#decimalSeparator.invalid"))); + + assertThat(driver.findElement(By.cssSelector("#decimalSeparator.invalid"))).isNotNull(); + } + + @Test + void test_upload_emptyGroupingSeparator_showValidationError() + { + driver.get(helper.getUrl() + "/transactionImport"); + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(ExpectedConditions.textToBePresentInElementLocated(By.cssSelector(".headline"), "Import from bank CSV")); + + final String csvPath = new File(getClass().getClassLoader().getResource("csv/three_entries.csv").getFile()).getAbsolutePath(); + + uploadCsv(csvPath, ";", "UTF-8", "1"); + wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("button-cancel-csv-import"))); + + assertThat(driver.findElement(By.id("csv-file-name")).getText()).isEqualTo("three_entries.csv"); + + fillColumnSettings(1, "", 2, 3, "", ",",2); + + wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#decimalSeparator.invalid"))); + + assertThat(driver.findElement(By.cssSelector("#decimalSeparator.invalid"))).isNotNull(); + } + @Test void test_upload_valid() { @@ -268,7 +314,7 @@ void test_upload_valid_parseErrors() assertThat(driver.findElement(By.id("csv-file-name")).getText()).isEqualTo("three_entries.csv"); - fillColumnSettings(1, "dd.MM.yyyy", 2, 3, 2); + fillColumnSettings(1, "dd.MM.yyyy", 2, 3, ".", ",",2); wait = new WebDriverWait(driver, Duration.ofSeconds(5)); wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("button-confirm-csv-column-settings"))); @@ -494,7 +540,7 @@ private void uploadAndSetColumnSettings() assertThat(columns.get(1).getText()).isEqualTo("Lorem"); assertThat(columns.get(2).getText()).isEqualTo("50.00"); - fillColumnSettings(1, "dd.MM.yyyy", 2, 3, 2); + fillColumnSettings(1, "dd.MM.yyyy", 2, 3, ".", ",",2); wait = new WebDriverWait(driver, Duration.ofSeconds(5)); wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("button-confirm-csv-column-settings"))); @@ -519,7 +565,7 @@ private void uploadCsv(String csvPath, String separator, String encoding, String driver.findElement(By.id("button-confirm-csv-import")).click(); } - private void fillColumnSettings(int columnDate, String datePattern, int columnName, int columnAmount, int columnDescription) + private void fillColumnSettings(int columnDate, String datePattern, int columnName, int columnAmount, String decimalSeparator, String groupingSeparator, int columnDescription) { final WebElement columnDateInput = driver.findElement(By.name("columnDate")); columnDateInput.clear(); @@ -537,6 +583,14 @@ private void fillColumnSettings(int columnDate, String datePattern, int columnNa columnAmountInput.clear(); columnAmountInput.sendKeys(String.valueOf(columnAmount)); + final WebElement decimalSeparatorInput = driver.findElement(By.name("decimalSeparator")); + decimalSeparatorInput.clear(); + decimalSeparatorInput.sendKeys(String.valueOf(decimalSeparator)); + + final WebElement groupingSeparatorInput = driver.findElement(By.name("groupingSeparator")); + groupingSeparatorInput.clear(); + groupingSeparatorInput.sendKeys(String.valueOf(groupingSeparator)); + final WebElement columnDescriptionInput = driver.findElement(By.name("columnDescription")); columnDescriptionInput.clear(); columnDescriptionInput.sendKeys(String.valueOf(columnDescription)); From 4e38ca1b1ccee90a36fed81272d803e351ea3898 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Sun, 19 Feb 2023 13:15:17 +0100 Subject: [PATCH 10/29] #732 - persist and prefill csv import settings --- .../TransactionImportController.java | 10 +- .../csvimport/CsvImportSettings.java | 165 ++++++++++++++++++ .../CsvImportSettingsRepository.java | 8 + .../csvimport/CsvImportSettingsService.java | 103 +++++++++++ .../transactions/transactionImport.ftl | 20 +-- .../integration/selenium/CsvImportTest.java | 22 ++- 6 files changed, 309 insertions(+), 19 deletions(-) create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettings.java create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettingsRepository.java create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettingsService.java diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportController.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportController.java index e935ea0f..59b29e41 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportController.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionImportController.java @@ -31,6 +31,7 @@ private static class ModelAttributes { public static final String ERROR = "error"; public static final String CATEGORIES = "categories"; + public static final String CSV_IMPORT_SETTINGS = "csvImportSettings"; } private static class ReturnValues @@ -61,14 +62,16 @@ private RequestAttributeNames() private final CategoryService categoryService; private final AccountService accountService; private final TransactionImportService transactionImportService; + private final CsvImportSettingsService csvImportSettingsService; @Autowired - public TransactionImportController(TransactionService transactionService, CategoryService categoryService, AccountService accountService, TransactionImportService transactionImportService) + public TransactionImportController(TransactionService transactionService, CategoryService categoryService, AccountService accountService, TransactionImportService transactionImportService, CsvImportSettingsService csvImportSettingsService) { this.transactionService = transactionService; this.categoryService = categoryService; this.accountService = accountService; this.transactionImportService = transactionImportService; + this.csvImportSettingsService = csvImportSettingsService; } @GetMapping @@ -88,6 +91,7 @@ public String transactionImport(WebRequest request, Model model) } model.addAttribute(ModelAttributes.CATEGORIES, categoryService.getAllEntitiesAsc()); + model.addAttribute(ModelAttributes.CSV_IMPORT_SETTINGS, csvImportSettingsService.getCsvImportSettings()); return ReturnValues.TRANSACTION_IMPORT; } @@ -97,6 +101,8 @@ public String upload(WebRequest request, @ModelAttribute("CsvImport") CsvImport csvImport, BindingResult bindingResult) { + csvImportSettingsService.updateSettings(csvImport); + if(csvImport.file().isEmpty()) { removeAllAttributes(request); @@ -156,6 +162,8 @@ public String columnSettings(WebRequest request, return ReturnValues.REDIRECT_CANCEL; } + csvImportSettingsService.updateSettings(csvColumnSettings); + final List csvRows = (List) attribute; final List csvTransactions = new ArrayList<>(); final List errors = new ArrayList<>(); diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettings.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettings.java new file mode 100644 index 00000000..277a241c --- /dev/null +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettings.java @@ -0,0 +1,165 @@ +package de.deadlocker8.budgetmaster.transactions.csvimport; + + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class CsvImportSettings +{ + @Id + private int ID = 1; + private String separator; + private String encoding; + private int numberOfLinesToSkip; + + // column settings + private Integer columnDate; + private String datePattern; + private Integer columnName; + private Integer columnAmount; + private String decimalSeparator; + private String groupingSeparator; + private Integer columnDescription; + + public CsvImportSettings() + { + // empty + } + + public static CsvImportSettings getDefault() + { + CsvImportSettings defaultSettings = new CsvImportSettings(); + defaultSettings.setSeparator(";"); + defaultSettings.setEncoding("UTF-8"); + defaultSettings.setNumberOfLinesToSkip(0); + + defaultSettings.setColumnDate(null); + defaultSettings.setDatePattern("dd.MM.yyyy"); + defaultSettings.setColumnName(null); + defaultSettings.setColumnAmount(null); + defaultSettings.setDecimalSeparator("."); + defaultSettings.setDecimalSeparator(","); + defaultSettings.setColumnDescription(null); + + return defaultSettings; + } + + public String getSeparator() + { + return separator; + } + + public void setSeparator(String separator) + { + this.separator = separator; + } + + public String getEncoding() + { + return encoding; + } + + public void setEncoding(String encoding) + { + this.encoding = encoding; + } + + public int getNumberOfLinesToSkip() + { + return numberOfLinesToSkip; + } + + public void setNumberOfLinesToSkip(int numberOfLinesToSkip) + { + this.numberOfLinesToSkip = numberOfLinesToSkip; + } + + public Integer getColumnDate() + { + return columnDate; + } + + public void setColumnDate(Integer columnDate) + { + this.columnDate = columnDate; + } + + public String getDatePattern() + { + return datePattern; + } + + public void setDatePattern(String datePattern) + { + this.datePattern = datePattern; + } + + public Integer getColumnName() + { + return columnName; + } + + public void setColumnName(Integer columnName) + { + this.columnName = columnName; + } + + public Integer getColumnAmount() + { + return columnAmount; + } + + public void setColumnAmount(Integer columnAmount) + { + this.columnAmount = columnAmount; + } + + public String getDecimalSeparator() + { + return decimalSeparator; + } + + public void setDecimalSeparator(String decimalSeparator) + { + this.decimalSeparator = decimalSeparator; + } + + public String getGroupingSeparator() + { + return groupingSeparator; + } + + public void setGroupingSeparator(String groupingSeparator) + { + this.groupingSeparator = groupingSeparator; + } + + public Integer getColumnDescription() + { + return columnDescription; + } + + public void setColumnDescription(Integer columnDescription) + { + this.columnDescription = columnDescription; + } + + @Override + public String toString() + { + return "CsvImportSettings{" + + "ID=" + ID + + ", separator='" + separator + '\'' + + ", encoding='" + encoding + '\'' + + ", numberOfLinesToSkip=" + numberOfLinesToSkip + + ", columnDate=" + columnDate + + ", datePattern='" + datePattern + '\'' + + ", columnName=" + columnName + + ", columnAmount=" + columnAmount + + ", decimalSeparator='" + decimalSeparator + '\'' + + ", groupingSeparator='" + groupingSeparator + '\'' + + ", columnDescription=" + columnDescription + + '}'; + } +} diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettingsRepository.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettingsRepository.java new file mode 100644 index 00000000..175d58df --- /dev/null +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettingsRepository.java @@ -0,0 +1,8 @@ +package de.deadlocker8.budgetmaster.transactions.csvimport; + +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface CsvImportSettingsRepository extends JpaRepository +{ +} \ No newline at end of file diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettingsService.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettingsService.java new file mode 100644 index 00000000..dbade921 --- /dev/null +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/csvimport/CsvImportSettingsService.java @@ -0,0 +1,103 @@ +package de.deadlocker8.budgetmaster.transactions.csvimport; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; + +@Service +public class CsvImportSettingsService +{ + private static final Logger LOGGER = LoggerFactory.getLogger(CsvImportSettingsService.class); + + private final CsvImportSettingsRepository csvImportSettingsRepository; + + @Autowired + public CsvImportSettingsService(CsvImportSettingsRepository csvImportSettingsRepository) + { + this.csvImportSettingsRepository = csvImportSettingsRepository; + } + + @PostConstruct + public void postInit() + { + this.createDefaultSettingsIfNotExists(); + } + + public void createDefaultSettingsIfNotExists() + { + if(csvImportSettingsRepository.findById(1).isEmpty()) + { + csvImportSettingsRepository.save(CsvImportSettings.getDefault()); + LOGGER.debug("Created default settings"); + } + } + + public CsvImportSettings getCsvImportSettings() + { + return csvImportSettingsRepository.findById(1).orElseThrow(); + } + + @Transactional + public void updateSettings(CsvImport csvImport) + { + final CsvImportSettings settings = getCsvImportSettings(); + if(hasContent(csvImport.separator())) + { + settings.setSeparator(csvImport.separator()); + } + + if(hasContent(csvImport.encoding())) + { + settings.setEncoding(csvImport.encoding()); + } + + settings.setNumberOfLinesToSkip(csvImport.numberOfLinesToSkip()); + } + + @Transactional + public void updateSettings(CsvColumnSettings columnSettings) + { + final CsvImportSettings settings = getCsvImportSettings(); + + settings.setColumnDate(columnSettings.columnDate()); + + if(hasContent(columnSettings.datePattern())) + { + settings.setDatePattern("dd.MM.yyyy"); + } + + settings.setColumnName(columnSettings.columnName()); + settings.setColumnAmount(columnSettings.columnAmount()); + + if(hasContent(columnSettings.decimalSeparator())) + { + settings.setDecimalSeparator(columnSettings.decimalSeparator()); + + } + if(hasContent(columnSettings.groupingSeparator())) + { + settings.setGroupingSeparator(columnSettings.groupingSeparator()); + } + + settings.setColumnDescription(columnSettings.columnDescription()); + } + + private boolean hasContent(String value) + { + if(value == null) + { + return false; + } + + if(value.isEmpty()) + { + return false; + } + + return !value.isBlank(); + } +} \ No newline at end of file diff --git a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl index e1c7ab9e..9960c36b 100644 --- a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl +++ b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl @@ -90,15 +90,15 @@
- value="<#if csvImport??>${csvImport.separator()}"> + value="<#if csvImportSettings.getSeparator()??>${csvImportSettings.getSeparator()}">
- value="<#if csvImport??>${csvImport.encoding()?upper_case}"> + value="<#if csvImportSettings.getEncoding()??>${csvImportSettings.getEncoding()?upper_case}">
- value="<#if csvImport??>${csvImport.numberOfLinesToSkip()?c}"> + value="<#if csvImportSettings.getNumberOfLinesToSkip()??>${csvImportSettings.getNumberOfLinesToSkip()?c}">
@@ -132,13 +132,13 @@
- value="<#if csvColumnSettings??>${csvColumnSettings.columnDate()}"> + value="<#if csvImportSettings.getColumnDate()??>${csvImportSettings.getColumnDate()}">
- value="<#if csvColumnSettings??>${csvColumnSettings.datePattern()}<#else>dd.MM.yyyy"> + value="<#if csvImportSettings.getDatePattern()??>${csvImportSettings.getDatePattern()}<#else>dd.MM.yyyy">
@@ -154,7 +154,7 @@
- value="<#if csvColumnSettings??>${csvColumnSettings.columnName()}"> + value="<#if csvImportSettings.getColumnName()??>${csvImportSettings.getColumnName()}">
@@ -166,18 +166,18 @@
- value="<#if csvColumnSettings??>${csvColumnSettings.columnAmount()}"> + value="<#if csvImportSettings.getColumnAmount()??>${csvImportSettings.getColumnAmount()}">
- value="<#if csvColumnSettings??>${csvColumnSettings.decimalSeparator()}<#else>${helpers.getDecimalSeparator()}"> + value="<#if csvImportSettings.getDecimalSeparator()??>${csvImportSettings.getDecimalSeparator()}<#else>${helpers.getDecimalSeparator()}">
- value="<#if csvColumnSettings??>${csvColumnSettings.groupingSeparator()}<#else>${helpers.getGroupingSeparator()}"> + value="<#if csvImportSettings.getGroupingSeparator()??>${csvImportSettings.getGroupingSeparator()}<#else>${helpers.getGroupingSeparator()}">
@@ -190,7 +190,7 @@
- value="<#if csvColumnSettings??>${csvColumnSettings.columnDescription()}"> + value="<#if csvImportSettings.getColumnDescription()??>${csvImportSettings.getColumnDescription()}">
diff --git a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CsvImportTest.java b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CsvImportTest.java index 01c5b069..00c21729 100644 --- a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CsvImportTest.java +++ b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CsvImportTest.java @@ -178,7 +178,8 @@ void test_upload_emptyColumnSettings_showValidationError() wait = new WebDriverWait(driver, Duration.ofSeconds(5)); wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("button-cancel-csv-import"))); - driver.findElement(By.id("button-confirm-csv-column-settings")).click(); + fillColumnSettings("", "dd.MM.YYYY", "", "", ".", ",", ""); + wait = new WebDriverWait(driver, Duration.ofSeconds(5)); wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#columnDate.invalid"))); @@ -566,34 +567,39 @@ private void uploadCsv(String csvPath, String separator, String encoding, String } private void fillColumnSettings(int columnDate, String datePattern, int columnName, int columnAmount, String decimalSeparator, String groupingSeparator, int columnDescription) + { + fillColumnSettings(String.valueOf(columnDate), datePattern, String.valueOf(columnName), String.valueOf(columnAmount), decimalSeparator, groupingSeparator, String.valueOf(columnDescription)); + } + + private void fillColumnSettings(String columnDate, String datePattern, String columnName, String columnAmount, String decimalSeparator, String groupingSeparator, String columnDescription) { final WebElement columnDateInput = driver.findElement(By.name("columnDate")); columnDateInput.clear(); - columnDateInput.sendKeys(String.valueOf(columnDate)); + columnDateInput.sendKeys(columnDate); final WebElement datePatternInput = driver.findElement(By.name("datePattern")); datePatternInput.clear(); - datePatternInput.sendKeys(String.valueOf(datePattern)); + datePatternInput.sendKeys(datePattern); final WebElement columnNameInput = driver.findElement(By.name("columnName")); columnNameInput.clear(); - columnNameInput.sendKeys(String.valueOf(columnName)); + columnNameInput.sendKeys(columnName); final WebElement columnAmountInput = driver.findElement(By.name("columnAmount")); columnAmountInput.clear(); - columnAmountInput.sendKeys(String.valueOf(columnAmount)); + columnAmountInput.sendKeys(columnAmount); final WebElement decimalSeparatorInput = driver.findElement(By.name("decimalSeparator")); decimalSeparatorInput.clear(); - decimalSeparatorInput.sendKeys(String.valueOf(decimalSeparator)); + decimalSeparatorInput.sendKeys(decimalSeparator); final WebElement groupingSeparatorInput = driver.findElement(By.name("groupingSeparator")); groupingSeparatorInput.clear(); - groupingSeparatorInput.sendKeys(String.valueOf(groupingSeparator)); + groupingSeparatorInput.sendKeys(groupingSeparator); final WebElement columnDescriptionInput = driver.findElement(By.name("columnDescription")); columnDescriptionInput.clear(); - columnDescriptionInput.sendKeys(String.valueOf(columnDescription)); + columnDescriptionInput.sendKeys(columnDescription); driver.findElement(By.id("button-confirm-csv-column-settings")).click(); } From b5caefc098bce98d4abd6cf1281e85209d59be78 Mon Sep 17 00:00:00 2001 From: Robert Goldmann Date: Mon, 20 Feb 2023 23:18:55 +0100 Subject: [PATCH 11/29] #732 - add csv import settings to database export and import --- .../budgetmaster/database/DatabaseParser.java | 10 +- .../database/DatabaseParser_v10.java | 47 + .../database/DatabaseService.java | 34 +- .../database/InternalDatabase.java | 10 +- .../importer/CsvImportSettingsImporter.java | 29 + .../converter/CsvImportSettingsConverter.java | 53 + .../v10/BackupCsvImportSettings_v10.java | 158 + .../model/v10/BackupDatabase_v10.java | 217 ++ .../database/model/v9/BackupDatabase_v9.java | 41 +- .../budgetmaster/services/ImportService.java | 8 +- .../csvimport/CsvImportSettings.java | 34 +- .../csvimport/CsvImportSettingsService.java | 23 +- .../unit/database/DatabaseExportTest.java | 15 +- .../unit/database/DatabaseParser_v10Test.java | 302 ++ ...baseParser_v10_convertToInternalTest.java} | 62 +- .../unit/database/ImportServiceTest.java | 26 +- .../resources/DatabaseParser_v10Test.json | 3360 +++++++++++++++++ .../src/test/resources/ImportServiceTest.json | 16 +- 18 files changed, 4374 insertions(+), 71 deletions(-) create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v10.java create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/importer/CsvImportSettingsImporter.java create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/CsvImportSettingsConverter.java create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/model/v10/BackupCsvImportSettings_v10.java create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/model/v10/BackupDatabase_v10.java create mode 100644 BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v10Test.java rename BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/database/{DatabaseParser_v9_convertToInternalTest.java => DatabaseParser_v10_convertToInternalTest.java} (84%) create mode 100644 BudgetMasterServer/src/test/resources/DatabaseParser_v10Test.json diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java index 93887340..e5694328 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java @@ -3,6 +3,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import de.deadlocker8.budgetmaster.database.model.BackupDatabase; +import de.deadlocker8.budgetmaster.database.model.v10.BackupDatabase_v10; import de.deadlocker8.budgetmaster.database.model.v4.BackupDatabase_v4; import de.deadlocker8.budgetmaster.database.model.v5.BackupDatabase_v5; import de.deadlocker8.budgetmaster.database.model.v6.BackupDatabase_v6; @@ -20,7 +21,7 @@ public class DatabaseParser final Logger LOGGER = LoggerFactory.getLogger(this.getClass()); private static final int MINIMUM_VERSION = 4; - public static final int LATEST_VERSION = 9; + public static final int LATEST_VERSION = 10; private final String jsonString; @@ -82,6 +83,13 @@ public InternalDatabase parseDatabaseFromJSON() throws IllegalArgumentException importedDatabase = parsedDatabase; } + if(version == 10) + { + BackupDatabase_v10 parsedDatabase = new DatabaseParser_v10(jsonString).parseDatabaseFromJSON(); + LOGGER.debug(MessageFormat.format("Parsed database with {0} transactions, {1} categories, {2} accounts, {3} templates {4} charts {5} images {6} icons and {7} transaction name keywords", parsedDatabase.getTransactions().size(), parsedDatabase.getCategories().size(), parsedDatabase.getAccounts().size(), parsedDatabase.getTemplates().size(), parsedDatabase.getCharts().size(), parsedDatabase.getImages().size(), parsedDatabase.getIcons().size(), parsedDatabase.getTransactionNameKeywords().size())); + importedDatabase = parsedDatabase; + } + if(importedDatabase == null) { throw new IllegalArgumentException(Localization.getString("error.database.import.unknown.version")); diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v10.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v10.java new file mode 100644 index 00000000..a53e3f6f --- /dev/null +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v10.java @@ -0,0 +1,47 @@ +package de.deadlocker8.budgetmaster.database; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import de.deadlocker8.budgetmaster.database.model.v10.BackupCsvImportSettings_v10; +import de.deadlocker8.budgetmaster.database.model.v10.BackupDatabase_v10; +import de.deadlocker8.budgetmaster.database.model.v5.BackupChart_v5; +import de.deadlocker8.budgetmaster.database.model.v5.BackupImage_v5; +import de.deadlocker8.budgetmaster.database.model.v6.BackupTransaction_v6; +import de.deadlocker8.budgetmaster.database.model.v7.BackupAccount_v7; +import de.deadlocker8.budgetmaster.database.model.v7.BackupCategory_v7; +import de.deadlocker8.budgetmaster.database.model.v8.BackupIcon_v8; +import de.deadlocker8.budgetmaster.database.model.v8.BackupTemplateGroup_v8; +import de.deadlocker8.budgetmaster.database.model.v8.BackupTemplate_v8; +import de.deadlocker8.budgetmaster.database.model.v9.BackupTransactionNameKeyword_v9; + +public class DatabaseParser_v10 +{ + private final String jsonString; + + private BackupDatabase_v10 database; + + public DatabaseParser_v10(String json) + { + this.jsonString = json; + this.database = new BackupDatabase_v10(); + } + + public BackupDatabase_v10 parseDatabaseFromJSON() throws IllegalArgumentException + { + database = new BackupDatabase_v10(); + + final JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject(); + database.setImages(BackupItemParser.parseItems(root.get("images").getAsJsonArray(), BackupImage_v5.class)); + database.setIcons(BackupItemParser.parseItems(root.get("icons").getAsJsonArray(), BackupIcon_v8.class)); + database.setAccounts(BackupItemParser.parseItems(root.get("accounts").getAsJsonArray(), BackupAccount_v7.class)); + database.setCategories(BackupItemParser.parseItems(root.get("categories").getAsJsonArray(), BackupCategory_v7.class)); + database.setTransactions(BackupItemParser.parseItems(root.get("transactions").getAsJsonArray(), BackupTransaction_v6.class)); + database.setTemplateGroups(BackupItemParser.parseItems(root.get("templateGroups").getAsJsonArray(), BackupTemplateGroup_v8.class)); + database.setTemplates(BackupItemParser.parseItems(root.get("templates").getAsJsonArray(), BackupTemplate_v8.class)); + database.setCharts(BackupItemParser.parseItems(root.get("charts").getAsJsonArray(), BackupChart_v5.class)); + database.setTransactionNameKeywords(BackupItemParser.parseItems(root.get("transactionNameKeywords").getAsJsonArray(), BackupTransactionNameKeyword_v9.class)); + database.setCsvImportSettings(BackupItemParser.parseItems(root.get("csvImportSettings").getAsJsonArray(), BackupCsvImportSettings_v10.class)); + + return database; + } +} \ No newline at end of file diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java index 64403d98..5bc406b1 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java @@ -10,7 +10,7 @@ import de.deadlocker8.budgetmaster.charts.ChartService; import de.deadlocker8.budgetmaster.charts.ChartType; import de.deadlocker8.budgetmaster.database.model.BackupDatabase; -import de.deadlocker8.budgetmaster.database.model.v9.BackupDatabase_v9; +import de.deadlocker8.budgetmaster.database.model.v10.BackupDatabase_v10; import de.deadlocker8.budgetmaster.hints.HintService; import de.deadlocker8.budgetmaster.icon.Icon; import de.deadlocker8.budgetmaster.icon.IconService; @@ -26,6 +26,8 @@ import de.deadlocker8.budgetmaster.templates.TemplateService; import de.deadlocker8.budgetmaster.transactions.Transaction; import de.deadlocker8.budgetmaster.transactions.TransactionService; +import de.deadlocker8.budgetmaster.transactions.csvimport.CsvImportSettings; +import de.deadlocker8.budgetmaster.transactions.csvimport.CsvImportSettingsService; import de.deadlocker8.budgetmaster.transactions.keywords.TransactionNameKeyword; import de.deadlocker8.budgetmaster.transactions.keywords.TransactionNameKeywordService; import de.deadlocker8.budgetmaster.utils.DateHelper; @@ -69,11 +71,12 @@ public class DatabaseService private final IconService iconService; private final HintService hintService; private final TransactionNameKeywordService transactionNameKeywordService; + private final CsvImportSettingsService csvImportSettingsService; private final List services; @Autowired - public DatabaseService(AccountService accountService, CategoryService categoryService, TransactionService transactionService, TagService tagService, TemplateService templateService, TemplateGroupService templateGroupService, ChartService chartService, SettingsService settingsService, ImageService imageService, IconService iconService, HintService hintService, TransactionNameKeywordService transactionNameKeywordService) + public DatabaseService(AccountService accountService, CategoryService categoryService, TransactionService transactionService, TagService tagService, TemplateService templateService, TemplateGroupService templateGroupService, ChartService chartService, SettingsService settingsService, ImageService imageService, IconService iconService, HintService hintService, TransactionNameKeywordService transactionNameKeywordService, CsvImportSettingsService csvImportSettingsService) { this.accountService = accountService; this.categoryService = categoryService; @@ -87,6 +90,7 @@ public DatabaseService(AccountService accountService, CategoryService categorySe this.iconService = iconService; this.hintService = hintService; this.transactionNameKeywordService = transactionNameKeywordService; + this.csvImportSettingsService = csvImportSettingsService; this.services = List.of(transactionService, templateService, templateGroupService, categoryService, accountService, tagService, chartService, iconService, imageService, tagService, hintService, transactionNameKeywordService); } @@ -213,22 +217,24 @@ public static String getExportFileName() public BackupDatabase getDatabaseForJsonSerialization() { - List categories = categoryService.getAllEntitiesAsc(); - List accounts = accountService.getRepository().findAll(); - List transactions = transactionService.getRepository().findAll(); - List filteredTransactions = filterRepeatingTransactions(transactions); - List templateGroups = templateGroupService.getRepository().findAll(); - List