diff --git a/financer-web-client/src/main/java/de/financer/controller/AccountController.java b/financer-web-client/src/main/java/de/financer/controller/AccountController.java index 5d0dd29..9a2eee6 100644 --- a/financer-web-client/src/main/java/de/financer/controller/AccountController.java +++ b/financer-web-client/src/main/java/de/financer/controller/AccountController.java @@ -12,6 +12,7 @@ import de.financer.notification.Notification; import de.financer.notification.PushServiceProxy; import de.financer.notification.Urgency; import de.financer.template.*; +import de.financer.template.StringTemplate; import de.financer.template.exception.FinancerRestException; import de.financer.util.ControllerUtils; import de.financer.util.TransactionUtils; diff --git a/financer-web-client/src/main/java/de/financer/controller/RecurringTransactionController.java b/financer-web-client/src/main/java/de/financer/controller/RecurringTransactionController.java index 8bb5ad7..745dac4 100644 --- a/financer-web-client/src/main/java/de/financer/controller/RecurringTransactionController.java +++ b/financer-web-client/src/main/java/de/financer/controller/RecurringTransactionController.java @@ -6,6 +6,7 @@ import de.financer.model.*; import de.financer.template.*; import de.financer.form.NewRecurringTransactionForm; import de.financer.form.RecurringToTransactionWithOverrideForm; +import de.financer.template.StringTemplate; import de.financer.util.ControllerUtils; import org.apache.commons.collections4.IterableUtils; import org.springframework.beans.factory.annotation.Autowired; diff --git a/financer-web-client/src/main/java/de/financer/controller/TransactionController.java b/financer-web-client/src/main/java/de/financer/controller/TransactionController.java index 9ca40fa..a0494f6 100644 --- a/financer-web-client/src/main/java/de/financer/controller/TransactionController.java +++ b/financer-web-client/src/main/java/de/financer/controller/TransactionController.java @@ -33,8 +33,10 @@ import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.util.UriComponentsBuilder; +import org.thymeleaf.expression.Numbers; import java.io.IOException; +import java.time.LocalDate; import java.util.*; import java.util.stream.Collectors; @@ -349,9 +351,17 @@ public class TransactionController { final RecurringTransaction emptyRecurring = new RecurringTransaction(); emptyRecurring.setDescription("-"); + emptyRecurring.setAmount(0L); + emptyRecurring.setFirstOccurrence(LocalDate.EPOCH); + emptyRecurring.setLastOccurrence(LocalDate.of(9999, 12, 31)); recurringTransactionList.add(emptyRecurring); - recurringTransactionList.addAll(IterableUtils.toList(response.getBody())); + recurringTransactionList.addAll(IterableUtils.toList(response.getBody()).stream().peek(rt -> { + if(rt.getLastOccurrence() == null) { + rt.setLastOccurrence(LocalDate.of(9999, 12, 31)); + } + + }).collect(Collectors.toList())); model.addAttribute("recurringTransactions", recurringTransactionList); diff --git a/financer-web-client/src/main/java/de/financer/form/CreateUploadedTransactionForm.java b/financer-web-client/src/main/java/de/financer/form/CreateUploadedTransactionForm.java index 2b5aa9d..4f4f9cf 100644 --- a/financer-web-client/src/main/java/de/financer/form/CreateUploadedTransactionForm.java +++ b/financer-web-client/src/main/java/de/financer/form/CreateUploadedTransactionForm.java @@ -14,7 +14,7 @@ public class CreateUploadedTransactionForm { public static CreateUploadedTransactionForm of(Collection uploadedTransactions, Long newPeriodOnRecurringTransaction) { final CreateUploadedTransactionForm form = new CreateUploadedTransactionForm(); - uploadedTransactions.stream().forEach(e -> form.getEntries().add(CreateUploadedTransactionFormEntry.of(e))); + uploadedTransactions.forEach(e -> form.getEntries().add(CreateUploadedTransactionFormEntry.of(e))); form.setNewPeriodOnRecurringTransaction(newPeriodOnRecurringTransaction); return form; @@ -46,6 +46,7 @@ public class CreateUploadedTransactionForm { private Boolean taxRelevant; private MultipartFile file; private Long recurringTransactionId; + private boolean matched; protected static CreateUploadedTransactionFormEntry of(UploadedTransaction uploadedTransaction) { final CreateUploadedTransactionFormEntry entry = new CreateUploadedTransactionFormEntry(); @@ -55,6 +56,8 @@ public class CreateUploadedTransactionForm { entry.setDescription(uploadedTransaction.getDescription()); entry.setDate(uploadedTransaction.getDate()); entry.setToAccountKey(uploadedTransaction.getToAccountKey()); + entry.setFromAccountKey(uploadedTransaction.getFromAccountKey()); + entry.setMatched(uploadedTransaction.isMatched()); return entry; } @@ -130,5 +133,13 @@ public class CreateUploadedTransactionForm { public void setCreate(Boolean create) { this.create = create; } + + public boolean isMatched() { + return matched; + } + + public void setMatched(boolean matched) { + this.matched = matched; + } } } diff --git a/financer-web-client/src/main/java/de/financer/transactionUpload/AbstractTransactionUploadWorker.java b/financer-web-client/src/main/java/de/financer/transactionUpload/AbstractTransactionUploadWorker.java index 9741892..6df1498 100644 --- a/financer-web-client/src/main/java/de/financer/transactionUpload/AbstractTransactionUploadWorker.java +++ b/financer-web-client/src/main/java/de/financer/transactionUpload/AbstractTransactionUploadWorker.java @@ -40,7 +40,7 @@ public abstract class AbstractTransactionUploadWorker implements TransactionUplo for (Account a : this.accounts) { final String[] regexps = Optional.ofNullable(a.getUploadMatchRegexps()).orElse("").split("\r\n"); - if (regexps.length > 0) { + if (regexps.length > 0 && StringUtils.isNotEmpty(regexps[0])) { for(String regex : regexps) { Matcher matcher = Pattern.compile(regex).matcher(rawDescription); diff --git a/financer-web-client/src/main/java/de/financer/transactionUpload/MT940CSVTransactionUploadWorker.java b/financer-web-client/src/main/java/de/financer/transactionUpload/MT940CSVTransactionUploadWorker.java index a473e4b..befd991 100644 --- a/financer-web-client/src/main/java/de/financer/transactionUpload/MT940CSVTransactionUploadWorker.java +++ b/financer-web-client/src/main/java/de/financer/transactionUpload/MT940CSVTransactionUploadWorker.java @@ -3,6 +3,7 @@ package de.financer.transactionUpload; import de.financer.config.FinancerConfig; import de.financer.dto.TransactionUploadFormat; import de.financer.model.Account; +import de.financer.model.AccountType; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; @@ -41,36 +42,41 @@ public class MT940CSVTransactionUploadWorker extends AbstractTransactionUploadWo try (InputStream is = file.getInputStream()) { final CSVParser parser = CSVFormat.DEFAULT.builder() - .setDelimiter(";") - .setNullString(null) - .setIgnoreEmptyLines(this.getFormatConfig().isRemoveEmptyLines()) - .build() - .parse(new InputStreamReader(is)); + .setDelimiter(";") + .setNullString(null) + .setIgnoreEmptyLines(this.getFormatConfig().isRemoveEmptyLines()) + .build() + .parse(new InputStreamReader(is)); final List records = parser.getRecords(); final long limit = records.size() - (this.getFormatConfig().getSkipLinesHead() + - this.getFormatConfig().getSkipLinesTail()); + this.getFormatConfig().getSkipLinesTail()); retVal.addAll(records.stream() - .skip(this.getFormatConfig().getSkipLinesHead()) - .limit(limit) - .map(r -> { - final Pair accountAndDescription = - this.getAccountAndDescription(buildDescription(r)); + .skip(this.getFormatConfig().getSkipLinesHead()) + .limit(limit) + .map(r -> { + final Pair accountAndDescription = + this.getAccountAndDescription(buildDescription(r)); - return new UploadedTransaction( - // Amount - formatAmount(r.get(AMOUNT_INDEX)), - // Description - accountAndDescription.getRight(), - // Date - formatDate(r.get(DATE_INDEX)), - // To account key - Optional.ofNullable(accountAndDescription.getLeft()) - .map(Account::getKey).orElse(null)); - } - ) - .collect(Collectors.toList())); + boolean isIncome = Optional.ofNullable(accountAndDescription.getLeft()).map(a -> a.getType() == AccountType.INCOME).orElse(false); + + return new UploadedTransaction( + // Amount + formatAmount(r.get(AMOUNT_INDEX)), + // Description + accountAndDescription.getRight(), + // Date + formatDate(r.get(DATE_INDEX)), + // To account key + isIncome ? null : Optional.ofNullable(accountAndDescription.getLeft()) + .map(Account::getKey).orElse(null), + // From account key + isIncome ? Optional.ofNullable(accountAndDescription.getLeft()) + .map(Account::getKey).orElse(null) : null); + } + ) + .collect(Collectors.toList())); } catch (IOException | RuntimeException e) { if (e instanceof RuntimeException) { if (e.getCause() instanceof ParseException) { diff --git a/financer-web-client/src/main/java/de/financer/transactionUpload/UploadedTransaction.java b/financer-web-client/src/main/java/de/financer/transactionUpload/UploadedTransaction.java index 8462d9d..15075ae 100644 --- a/financer-web-client/src/main/java/de/financer/transactionUpload/UploadedTransaction.java +++ b/financer-web-client/src/main/java/de/financer/transactionUpload/UploadedTransaction.java @@ -1,16 +1,20 @@ package de.financer.transactionUpload; public class UploadedTransaction { + private boolean matched; private Long amount; private String description; private String date; private String toAccountKey; + private String fromAccountKey; - public UploadedTransaction(Long amount, String description, String date, String toAccountKey) { + public UploadedTransaction(Long amount, String description, String date, String toAccountKey, String fromAccountKey) { this.amount = amount; this.description = description; this.date = date; this.toAccountKey = toAccountKey; + this.fromAccountKey = fromAccountKey; + this.matched = toAccountKey != null || fromAccountKey != null; } public Long getAmount() { @@ -44,4 +48,16 @@ public class UploadedTransaction { public void setToAccountKey(String toAccountKey) { this.toAccountKey = toAccountKey; } + + public String getFromAccountKey() { + return fromAccountKey; + } + + public void setFromAccountKey(String fromAccountKey) { + this.fromAccountKey = fromAccountKey; + } + + public boolean isMatched() { + return matched; + } } diff --git a/financer-web-client/src/main/java/de/financer/transactionUpload/VBCSVTransactionUploadWorker.java b/financer-web-client/src/main/java/de/financer/transactionUpload/VBCSVTransactionUploadWorker.java index d4d6f86..5b38269 100644 --- a/financer-web-client/src/main/java/de/financer/transactionUpload/VBCSVTransactionUploadWorker.java +++ b/financer-web-client/src/main/java/de/financer/transactionUpload/VBCSVTransactionUploadWorker.java @@ -3,6 +3,7 @@ package de.financer.transactionUpload; import de.financer.config.FinancerConfig; import de.financer.dto.TransactionUploadFormat; import de.financer.model.Account; +import de.financer.model.AccountType; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; @@ -51,6 +52,8 @@ public class VBCSVTransactionUploadWorker extends AbstractTransactionUploadWorke final Pair accountAndDescription = this.getAccountAndDescription(buildDescription(r)); + boolean isIncome = Optional.ofNullable(accountAndDescription.getLeft()).map(a -> a.getType() == AccountType.INCOME).orElse(false); + return new UploadedTransaction( // Amount formatAmount(r.get(AMOUNT_INDEX)), @@ -59,8 +62,11 @@ public class VBCSVTransactionUploadWorker extends AbstractTransactionUploadWorke // Date formatDate(r.get(DATE_INDEX)), // To account key - Optional.ofNullable(accountAndDescription.getLeft()) - .map(Account::getKey).orElse(null)); + isIncome ? null : Optional.ofNullable(accountAndDescription.getLeft()) + .map(Account::getKey).orElse(null), + // From account key + isIncome ? Optional.ofNullable(accountAndDescription.getLeft()) + .map(Account::getKey).orElse(null) : null); } ) .collect(Collectors.toList())); diff --git a/financer-web-client/src/main/resources/static/changelog.txt b/financer-web-client/src/main/resources/static/changelog.txt index 64c3e7b..5b1a74a 100644 --- a/financer-web-client/src/main/resources/static/changelog.txt +++ b/financer-web-client/src/main/resources/static/changelog.txt @@ -1,5 +1,8 @@ v55 -> v56: -- +- Change description field in transaction upload from input to textarea and increase its width +- Recurring transaction selection in transaction upload now shows additional information like amount and dates +- From account regex support for transaction upload +- Add matching indicator to transaction upload v54 -> v55: - Add new deployment profile diff --git a/financer-web-client/src/main/resources/static/css/main.css b/financer-web-client/src/main/resources/static/css/main.css index 229b866..5ffb390 100644 --- a/financer-web-client/src/main/resources/static/css/main.css +++ b/financer-web-client/src/main/resources/static/css/main.css @@ -97,6 +97,10 @@ a { vertical-align: top; } +#create-upload-transactions-table textarea { + width: 80% !important; +} + #account-overview-table th, #transaction-table th, #recurring-transaction-list-table th, diff --git a/financer-web-client/src/main/resources/templates/transaction/createUploadedTransactions.html b/financer-web-client/src/main/resources/templates/transaction/createUploadedTransactions.html index 3c2db59..6e9c664 100644 --- a/financer-web-client/src/main/resources/templates/transaction/createUploadedTransactions.html +++ b/financer-web-client/src/main/resources/templates/transaction/createUploadedTransactions.html @@ -19,6 +19,7 @@ + @@ -33,6 +34,10 @@ + + + + +