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 e935ea0fe22cd3f427c828cabc28eec1ff21693f..59b29e411407fb3b5ba3432c9e83e1e1bfa5c626 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 @@ public class TransactionImportController extends BaseController { 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 @@ public class TransactionImportController extends BaseController 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 class TransactionImportController extends BaseController } model.addAttribute(ModelAttributes.CATEGORIES, categoryService.getAllEntitiesAsc()); + model.addAttribute(ModelAttributes.CSV_IMPORT_SETTINGS, csvImportSettingsService.getCsvImportSettings()); return ReturnValues.TRANSACTION_IMPORT; } @@ -97,6 +101,8 @@ public class TransactionImportController extends BaseController @ModelAttribute("CsvImport") CsvImport csvImport, BindingResult bindingResult) { + csvImportSettingsService.updateSettings(csvImport); + if(csvImport.file().isEmpty()) { removeAllAttributes(request); @@ -156,6 +162,8 @@ public class TransactionImportController extends BaseController return ReturnValues.REDIRECT_CANCEL; } + csvImportSettingsService.updateSettings(csvColumnSettings); + final List<CsvRow> csvRows = (List<CsvRow>) attribute; final List<CsvTransaction> csvTransactions = new ArrayList<>(); final List<String> 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 0000000000000000000000000000000000000000..277a241ccb9826d9cc5fd7d9a8f9556d34cbf12a --- /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 0000000000000000000000000000000000000000..175d58dfaa8416da6e17da5dc1741f8751428474 --- /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<CsvImportSettings, Integer> +{ +} \ 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 0000000000000000000000000000000000000000..dbade9210c280a2116cd71da52754355c6e5f773 --- /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 e1c7ab9e28142f73eb406ef5c86f2a7ab4fd3880..9960c36bb676fd61378a2053b758c71adecfb7b1 100644 --- a/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl +++ b/BudgetMasterServer/src/main/resources/templates/transactions/transactionImport.ftl @@ -90,15 +90,15 @@ <div class="row"> <div class="input-field col s4 l2 offset-l3"> - <input id="separator" type="text" name="separator" <@validation.validation "separator" "center-align"/> value="<#if csvImport??>${csvImport.separator()}</#if>"> + <input id="separator" type="text" name="separator" <@validation.validation "separator" "center-align"/> value="<#if csvImportSettings.getSeparator()??>${csvImportSettings.getSeparator()}</#if>"> <label class="input-label" for="separator">${locale.getString("transactions.import.separator")}</label> </div> <div class="input-field col s4 l2"> - <input id="encoding" type="text" name="encoding" <@validation.validation "encoding" "center-align"/> value="<#if csvImport??>${csvImport.encoding()?upper_case}</#if>"> + <input id="encoding" type="text" name="encoding" <@validation.validation "encoding" "center-align"/> value="<#if csvImportSettings.getEncoding()??>${csvImportSettings.getEncoding()?upper_case}</#if>"> <label class="input-label" for="encoding">${locale.getString("transactions.import.encoding")}</label> </div> <div class="input-field col s4 l2"> - <input id="numberOfLinesToSkip" type="number" name="numberOfLinesToSkip" min="0" name="numberOfLinesToSkip" <@validation.validation "numberOfLinesToSkip" "center-align"/> value="<#if csvImport??>${csvImport.numberOfLinesToSkip()?c}</#if>"> + <input id="numberOfLinesToSkip" type="number" name="numberOfLinesToSkip" min="0" name="numberOfLinesToSkip" <@validation.validation "numberOfLinesToSkip" "center-align"/> value="<#if csvImportSettings.getNumberOfLinesToSkip()??>${csvImportSettings.getNumberOfLinesToSkip()?c}</#if>"> <label class="input-label" for="numberOfLinesToSkip">${locale.getString("transactions.import.numberOfLinesToSkip")}</label> </div> </div> @@ -132,13 +132,13 @@ </div> </div> <div class="input-field col s6 m6 l4 no-margin-top no-margin-bottom"> - <input id="columnDate" type="number" min="1" max="${csvRows?size}" name="columnDate" <@validation.validation "columnDate"/> value="<#if csvColumnSettings??>${csvColumnSettings.columnDate()}</#if>"> + <input id="columnDate" type="number" min="1" max="${csvRows?size}" name="columnDate" <@validation.validation "columnDate"/> value="<#if csvImportSettings.getColumnDate()??>${csvImportSettings.getColumnDate()}</#if>"> <label class="input-label" for="columnDate">${locale.getString("transactions.import.column")}</label> </div> </div> <div class="row"> <div class="input-field col s5 offset-s6 m5 offset-m6 l4 offset-l6 no-margin-top no-margin-bottom"> - <input id="datePattern" type="text" required name="datePattern" <@validation.validation "datePattern"/> value="<#if csvColumnSettings??>${csvColumnSettings.datePattern()}<#else>dd.MM.yyyy</#if>"> + <input id="datePattern" type="text" required name="datePattern" <@validation.validation "datePattern"/> value="<#if csvImportSettings.getDatePattern()??>${csvImportSettings.getDatePattern()}<#else>dd.MM.yyyy</#if>"> <label class="input-label" for="datePattern">${locale.getString("transactions.import.datePattern")}</label> </div> <div class="col s1 m1 l1"> @@ -154,7 +154,7 @@ </div> </div> <div class="input-field col s6 m6 l4 no-margin-top no-margin-bottom"> - <input id="columnName" type="number" min="1" max="${csvRows?size}" name="columnName" <@validation.validation "columnName"/> value="<#if csvColumnSettings??>${csvColumnSettings.columnName()}</#if>"> + <input id="columnName" type="number" min="1" max="${csvRows?size}" name="columnName" <@validation.validation "columnName"/> value="<#if csvImportSettings.getColumnName()??>${csvImportSettings.getColumnName()}</#if>"> <label class="input-label" for="columnName">${locale.getString("transactions.import.column")}</label> </div> </div> @@ -166,18 +166,18 @@ </div> </div> <div class="input-field col s6 m6 l4 no-margin-top no-margin-bottom"> - <input id="columnAmount" type="number" min="1" max="${csvRows?size}" name="columnAmount" <@validation.validation "columnAmount"/> value="<#if csvColumnSettings??>${csvColumnSettings.columnAmount()}</#if>"> + <input id="columnAmount" type="number" min="1" max="${csvRows?size}" name="columnAmount" <@validation.validation "columnAmount"/> value="<#if csvImportSettings.getColumnAmount()??>${csvImportSettings.getColumnAmount()}</#if>"> <label class="input-label" for="columnAmount">${locale.getString("transactions.import.column")}</label> </div> </div> <div class="row"> <div class="input-field col s3 offset-s6 m3 offset-m6 l2 offset-l6 no-margin-top no-margin-bottom"> - <input id="decimalSeparator" type="text" required maxlength="1" name="decimalSeparator" <@validation.validation "decimalSeparator"/> value="<#if csvColumnSettings??>${csvColumnSettings.decimalSeparator()}<#else>${helpers.getDecimalSeparator()}</#if>"> + <input id="decimalSeparator" type="text" required maxlength="1" name="decimalSeparator" <@validation.validation "decimalSeparator"/> value="<#if csvImportSettings.getDecimalSeparator()??>${csvImportSettings.getDecimalSeparator()}<#else>${helpers.getDecimalSeparator()}</#if>"> <label class="input-label" for="decimalSeparator">${locale.getString("transactions.import.decimalSeparator")}</label> </div> <div class="input-field col s3 m3 l2 no-margin-top no-margin-bottom"> - <input id="groupingSeparator" type="text" required maxlength="1" name="groupingSeparator" <@validation.validation "groupingSeparator"/> value="<#if csvColumnSettings??>${csvColumnSettings.groupingSeparator()}<#else>${helpers.getGroupingSeparator()}</#if>"> + <input id="groupingSeparator" type="text" required maxlength="1" name="groupingSeparator" <@validation.validation "groupingSeparator"/> value="<#if csvImportSettings.getGroupingSeparator()??>${csvImportSettings.getGroupingSeparator()}<#else>${helpers.getGroupingSeparator()}</#if>"> <label class="input-label" for="groupingSeparator">${locale.getString("transactions.import.groupingSeparator")}</label> </div> </div> @@ -190,7 +190,7 @@ </div> </div> <div class="input-field col s6 m6 l4 no-margin-top no-margin-bottom"> - <input id="columnDescription" type="number" min="1" max="${csvRows?size}" name="columnDescription" <@validation.validation "columnDescription"/> value="<#if csvColumnSettings??>${csvColumnSettings.columnDescription()}</#if>"> + <input id="columnDescription" type="number" min="1" max="${csvRows?size}" name="columnDescription" <@validation.validation "columnDescription"/> value="<#if csvImportSettings.getColumnDescription()??>${csvImportSettings.getColumnDescription()}</#if>"> <label class="input-label" for="columnDescription">${locale.getString("transactions.import.column")}</label> </div> </div> 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 01c5b069323f83fe04785219ce9607b851ca582f..00c217291eb8846f1ec239d531c41a5d09334b24 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 @@ class CsvImportTest extends SeleniumTestBase 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 @@ class CsvImportTest extends SeleniumTestBase } 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(); }