From 2ee77f9d4f6d6bdae8cac6a7cd67a9b187258ac9 Mon Sep 17 00:00:00 2001 From: MK13 Date: Fri, 9 Oct 2020 16:44:05 +0200 Subject: [PATCH] Add calendar, SKIP and fix some bugs --- ...rringTransactionDueInRangeResponseDto.java | 41 +++++ .../de/financer/model/HolidayWeekendType.java | 9 +- financer-server/pom.xml | 2 +- .../src/main/antlr4/de/financer/fql/FQL.g4 | 2 +- .../RecurringTransactionController.java | 20 +++ .../service/RecurringTransactionService.java | 59 +++++-- .../java/de/financer/service/RuleService.java | 2 + .../main/java/de/financer/calendar/Day.java | 49 ++++++ .../main/java/de/financer/calendar/Week.java | 32 ++++ .../de/financer/config/FinancerConfig.java | 10 ++ .../controller/CalendarController.java | 146 ++++++++++++++++++ .../java/de/financer/controller/Function.java | 1 + .../RecurringTransactionController.java | 11 +- .../controller/TransactionController.java | 4 + .../de/financer/util/ControllerUtils.java | 2 +- .../resources/config/application.properties | 6 +- .../main/resources/i18n/message.properties | 18 +++ .../resources/i18n/message_de_DE.properties | 20 ++- .../src/main/resources/static/changelog.txt | 13 +- .../src/main/resources/static/css/main.css | 114 +++++++++++++- .../src/main/resources/static/readme.txt | 4 +- .../templates/account/accountDetails.html | 2 +- .../templates/account/accountOverview.html | 12 +- .../recurringTransaction/calendar.html | 63 ++++++++ .../newRecurringTransaction.html | 4 +- .../recurringTransactionList.html | 2 +- .../templates/transaction/newTransaction.html | 4 +- .../transaction/transactionList.html | 5 +- pom.xml | 32 +++- 29 files changed, 649 insertions(+), 40 deletions(-) create mode 100644 financer-common/src/main/java/de/financer/dto/RecurringTransactionDueInRangeResponseDto.java create mode 100644 financer-web-client/src/main/java/de/financer/calendar/Day.java create mode 100644 financer-web-client/src/main/java/de/financer/calendar/Week.java create mode 100644 financer-web-client/src/main/java/de/financer/controller/CalendarController.java create mode 100644 financer-web-client/src/main/resources/templates/recurringTransaction/calendar.html diff --git a/financer-common/src/main/java/de/financer/dto/RecurringTransactionDueInRangeResponseDto.java b/financer-common/src/main/java/de/financer/dto/RecurringTransactionDueInRangeResponseDto.java new file mode 100644 index 0000000..391c548 --- /dev/null +++ b/financer-common/src/main/java/de/financer/dto/RecurringTransactionDueInRangeResponseDto.java @@ -0,0 +1,41 @@ +package de.financer.dto; + +import de.financer.model.RecurringTransaction; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; + +import java.time.LocalDate; + +public class RecurringTransactionDueInRangeResponseDto { + private LocalDate date; + private Iterable recurringTransactions; + + public RecurringTransactionDueInRangeResponseDto() { + + } + + public RecurringTransactionDueInRangeResponseDto(LocalDate date, Iterable recurringTransactions) { + this.date = date; + this.recurringTransactions = recurringTransactions; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public Iterable getRecurringTransactions() { + return recurringTransactions; + } + + public void setRecurringTransactions(Iterable recurringTransactions) { + this.recurringTransactions = recurringTransactions; + } + + @Override + public String toString() { + return ReflectionToStringBuilder.toString(this); + } +} diff --git a/financer-common/src/main/java/de/financer/model/HolidayWeekendType.java b/financer-common/src/main/java/de/financer/model/HolidayWeekendType.java index 6b79ab6..411e7c8 100644 --- a/financer-common/src/main/java/de/financer/model/HolidayWeekendType.java +++ b/financer-common/src/main/java/de/financer/model/HolidayWeekendType.java @@ -53,7 +53,14 @@ public enum HolidayWeekendType { * X' -> Earlier, effective due date of action * */ - PREVIOUS_WORKDAY; + PREVIOUS_WORKDAY, + + /** + *

+ * Indicates that the action should be skipped on the particular occurrence + *

+ */ + SKIP; /** * This method validates whether the given string represents a valid holiday weekend type. diff --git a/financer-server/pom.xml b/financer-server/pom.xml index c67634f..93ffdd5 100644 --- a/financer-server/pom.xml +++ b/financer-server/pom.xml @@ -17,7 +17,7 @@ jar - hsqldb,dev + postgres,dev mk diff --git a/financer-server/src/main/antlr4/de/financer/fql/FQL.g4 b/financer-server/src/main/antlr4/de/financer/fql/FQL.g4 index 7e7000d..13088a0 100644 --- a/financer-server/src/main/antlr4/de/financer/fql/FQL.g4 +++ b/financer-server/src/main/antlr4/de/financer/fql/FQL.g4 @@ -96,7 +96,7 @@ L_PAREN : '(' ; R_PAREN : ')' ; IDENTIFIER : [a-zA-Z]+ ; INT_VALUE : [0-9]+ ; -STRING_VALUE : '\'' [a-zA-Z0-9- ]+ '\'' ; +STRING_VALUE : '\'' [a-zA-Z0-9\-/ ]+ '\'' ; DATE_VALUE : [0-9-]+ ; NEWLINE : ('\r'? '\n' | '\r')+ ; diff --git a/financer-server/src/main/java/de/financer/controller/RecurringTransactionController.java b/financer-server/src/main/java/de/financer/controller/RecurringTransactionController.java index 120bf14..a9498a8 100644 --- a/financer-server/src/main/java/de/financer/controller/RecurringTransactionController.java +++ b/financer-server/src/main/java/de/financer/controller/RecurringTransactionController.java @@ -1,12 +1,14 @@ package de.financer.controller; import de.financer.ResponseReason; +import de.financer.dto.RecurringTransactionDueInRangeResponseDto; import de.financer.model.RecurringTransaction; import de.financer.service.RecurringTransactionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -114,4 +116,22 @@ public class RecurringTransactionController { return responseReason.toResponseEntity(); } + + @GetMapping("getAllDueInRange") + public Iterable getAllDueInRange(String start, String end) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(String + .format("/recurringTransactions/getAllDueInRange got parameters: %s, %s", + start, end)); + } + + final Iterable dueInRange = this.recurringTransactionService.getAllDueInRange(start, end); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(String + .format("/recurringTransactions/getAllDueInRange returns with %s", dueInRange)); + } + + return dueInRange; + } } diff --git a/financer-server/src/main/java/de/financer/service/RecurringTransactionService.java b/financer-server/src/main/java/de/financer/service/RecurringTransactionService.java index a84858f..8436202 100644 --- a/financer-server/src/main/java/de/financer/service/RecurringTransactionService.java +++ b/financer-server/src/main/java/de/financer/service/RecurringTransactionService.java @@ -3,7 +3,11 @@ package de.financer.service; import de.financer.ResponseReason; import de.financer.config.FinancerConfig; import de.financer.dba.RecurringTransactionRepository; -import de.financer.model.*; +import de.financer.dto.RecurringTransactionDueInRangeResponseDto; +import de.financer.model.Account; +import de.financer.model.HolidayWeekendType; +import de.financer.model.IntervalType; +import de.financer.model.RecurringTransaction; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; @@ -17,9 +21,12 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; +import java.time.Period; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -144,8 +151,19 @@ public class RecurringTransactionService { // If so the recurring transaction is due today .anyMatch((d) -> d.equals(now)); final boolean weekend = this.ruleService.isWeekend(now); - boolean defer = false; + // If a recurring transaction has holiday weekend type SKIP and today is either a weekend day or a holiday that + // transaction cannot be due today + if (recurringTransaction.getHolidayWeekendType() == HolidayWeekendType.SKIP && (holiday || weekend)) { + LOGGER.debug(String + .format("Recurring transaction %s not due today because it has HWT %s and today is(holiday=%s or weekend=%s)", + ReflectionToStringBuilder.toString(recurringTransaction), recurringTransaction + .getHolidayWeekendType(), holiday, weekend)); + + return false; + } + + boolean defer = false; if (holiday || weekend) { defer = recurringTransaction.getHolidayWeekendType() == HolidayWeekendType.NEXT_WORKDAY @@ -174,7 +192,7 @@ public class RecurringTransactionService { * @return true if the recurring transaction is due today, false otherwise */ private boolean checkRecurringTransactionDuePast(RecurringTransaction recurringTransaction, LocalDate now) { - // Recurring transactions with holiday weekend type SAME_DAY or PREVIOUS_WORKDAY can't be due in the past + // Recurring transactions with holiday weekend type SAME_DAY, SKIP or PREVIOUS_WORKDAY can't be due in the past if (!HolidayWeekendType.NEXT_WORKDAY.equals(recurringTransaction.getHolidayWeekendType())) { LOGGER.debug(String.format("Recurring transaction %s has HWT %s and thus cannot be due in the past", ReflectionToStringBuilder.toString(recurringTransaction), @@ -255,7 +273,7 @@ public class RecurringTransactionService { * @return true if the recurring transaction is due today, false otherwise */ private boolean checkRecurringTransactionDueFuture(RecurringTransaction recurringTransaction, LocalDate now) { - // Recurring transactions with holiday weekend type SAME_DAY or PREVIOUS_WORKDAY can't be due in the future + // Recurring transactions with holiday weekend type SAME_DAY, SKIP or PREVIOUS_WORKDAY can't be due in the future if (!HolidayWeekendType.PREVIOUS_WORKDAY.equals(recurringTransaction.getHolidayWeekendType())) { LOGGER.debug(String.format("Recurring transaction %s has HWT %s and thus cannot be due in the future", ReflectionToStringBuilder.toString(recurringTransaction), @@ -267,12 +285,12 @@ public class RecurringTransactionService { // If today is a weekend day or holiday the recurring transaction cannot be due today, because the // holiday weekend type says PREVIOUS_WORKDAY. if (this.ruleService.isHoliday(now) || this.ruleService.isWeekend(now)) { - LOGGER.debug(String.format("Recurring transaction %s has HWT %s and today is either a holiday or weekend," + - " thus it cannot be due in the future", - ReflectionToStringBuilder.toString(recurringTransaction), - recurringTransaction.getHolidayWeekendType())); + LOGGER.debug(String.format("Recurring transaction %s has HWT %s and today is either a holiday or weekend," + + " thus it cannot be due in the future", + ReflectionToStringBuilder.toString(recurringTransaction), + recurringTransaction.getHolidayWeekendType())); - return false; // early return + return false; // early return } @@ -313,7 +331,6 @@ public class RecurringTransactionService { } - @Transactional(propagation = Propagation.REQUIRED) public ResponseReason createRecurringTransaction(String fromAccountKey, String toAccountKey, Long amount, String description, String holidayWeekendType, @@ -512,4 +529,26 @@ public class RecurringTransactionService { return response; } + + /** + * This method calculates all {@link RecurringTransaction}s due in the given date range. + * + * @param start the start of the range, inclusive + * @param end the end of the range, inclusive + * + * @return a list of date->recurring transactions due mappings + */ + public Iterable getAllDueInRange(String start, String end) { + final List dueInRange = new ArrayList<>(); + final LocalDate startDate = LocalDate + .parse(start, DateTimeFormatter.ofPattern(this.financerConfig.getDateFormat())); + final LocalDate tmpEndDate = LocalDate + .parse(end, DateTimeFormatter.ofPattern(this.financerConfig.getDateFormat())); + final LocalDate endDate = tmpEndDate.plusDays(1); // Range end is always exclusive in Java API + + startDate.datesUntil(endDate, Period.ofDays(1)).forEach(d -> dueInRange + .add(new RecurringTransactionDueInRangeResponseDto(d, this.getAllDueToday(d)))); + + return dueInRange; + } } diff --git a/financer-server/src/main/java/de/financer/service/RuleService.java b/financer-server/src/main/java/de/financer/service/RuleService.java index 35436bc..f326672 100644 --- a/financer-server/src/main/java/de/financer/service/RuleService.java +++ b/financer-server/src/main/java/de/financer/service/RuleService.java @@ -68,6 +68,7 @@ public class RuleService implements InitializingBean { *

* The multiplier controls whether the current amount of the given from account is increased or decreased depending * on the {@link AccountType} of the given account. + *

* * @param fromAccount the from account to get the multiplier for * @@ -102,6 +103,7 @@ public class RuleService implements InitializingBean { *

* The multiplier controls whether the current amount of the given to account is increased or decreased depending on * the {@link AccountType} of the given account. + *

* * @param toAccount the to account to get the multiplier for * diff --git a/financer-web-client/src/main/java/de/financer/calendar/Day.java b/financer-web-client/src/main/java/de/financer/calendar/Day.java new file mode 100644 index 0000000..0a6cc9a --- /dev/null +++ b/financer-web-client/src/main/java/de/financer/calendar/Day.java @@ -0,0 +1,49 @@ +package de.financer.calendar; + +import de.financer.model.RecurringTransaction; + +import java.time.LocalDate; +import java.time.temporal.ChronoField; + +public class Day { + private LocalDate date; + private Iterable transactions; + + public Day(LocalDate date) { + this.date = date; + } + + public int getDay() { + return this.date.get(ChronoField.DAY_OF_MONTH); + } + + public LocalDate getDate() { + return this.date; + } + + public Iterable getTransactions() { + return transactions; + } + + public boolean isPreviousOrNextMonth(Integer offset) { + LocalDate now = LocalDate.now().plusMonths(offset); + + return !now.getMonth().equals(this.date.getMonth()); + } + + public boolean isToday() { + return LocalDate.now().equals(this.date); + } + + public void setTransactions(Iterable transactions) { + this.transactions = transactions; + } + + @Override + public String toString() { + return "Day{" + + "date=" + date + + ", transactions=" + transactions + + '}'; + } +} diff --git a/financer-web-client/src/main/java/de/financer/calendar/Week.java b/financer-web-client/src/main/java/de/financer/calendar/Week.java new file mode 100644 index 0000000..2429a0b --- /dev/null +++ b/financer-web-client/src/main/java/de/financer/calendar/Week.java @@ -0,0 +1,32 @@ +package de.financer.calendar; + +import java.util.List; + +public class Week { + private int weekNumber; + private List days; + + public int getWeekNumber() { + return weekNumber; + } + + public void setWeekNumber(int weekNumber) { + this.weekNumber = weekNumber; + } + + public List getDays() { + return days; + } + + public void setDays(List days) { + this.days = days; + } + + @Override + public String toString() { + return "Week{" + + "weekNumber=" + weekNumber + + ", days=" + days + + '}'; + } +} diff --git a/financer-web-client/src/main/java/de/financer/config/FinancerConfig.java b/financer-web-client/src/main/java/de/financer/config/FinancerConfig.java index 6eec601..f655d3f 100644 --- a/financer-web-client/src/main/java/de/financer/config/FinancerConfig.java +++ b/financer-web-client/src/main/java/de/financer/config/FinancerConfig.java @@ -6,6 +6,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import java.time.DayOfWeek; import java.util.Currency; @Configuration @@ -19,6 +20,7 @@ public class FinancerConfig { private String version; private String currencyCode; private Currency currency; + private DayOfWeek firstDayOfWeek; public String getServerUrl() { return serverUrl; @@ -53,4 +55,12 @@ public class FinancerConfig { public Currency getCurrency() { return currency; } + + public DayOfWeek getFirstDayOfWeek() { + return firstDayOfWeek; + } + + public void setFirstDayOfWeek(String firstDayOfWeek) { + this.firstDayOfWeek = DayOfWeek.valueOf(firstDayOfWeek); + } } diff --git a/financer-web-client/src/main/java/de/financer/controller/CalendarController.java b/financer-web-client/src/main/java/de/financer/controller/CalendarController.java new file mode 100644 index 0000000..35a82c9 --- /dev/null +++ b/financer-web-client/src/main/java/de/financer/controller/CalendarController.java @@ -0,0 +1,146 @@ +package de.financer.controller; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import de.financer.calendar.Day; +import de.financer.calendar.Week; +import de.financer.config.FinancerConfig; +import de.financer.dto.RecurringTransactionDueInRangeResponseDto; +import de.financer.dto.SearchTransactionsResponseDto; +import de.financer.template.FinancerRestTemplate; +import de.financer.template.exception.FinancerRestException; +import de.financer.util.ControllerUtils; +import org.apache.commons.collections4.IterableUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.util.UriComponentsBuilder; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.format.TextStyle; +import java.time.temporal.TemporalField; +import java.time.temporal.WeekFields; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +@Controller +public class CalendarController { + @Autowired + private FinancerConfig financerConfig; + + @GetMapping("/recurringTransactionCalendar") + public String recurringTransactionCalendar(Model model, String offset) { + Integer offsetNumber = null; + + if (!NumberUtils.isCreatable(offset)) { + // TODO + } + + offsetNumber = Integer.valueOf(offset); + + // 1. Add days for calendar headings + model.addAttribute("firstWeekDay", this.financerConfig.getFirstDayOfWeek()); + model.addAttribute("secondWeekDay", this.financerConfig.getFirstDayOfWeek().plus(1)); + model.addAttribute("thirdWeekDay", this.financerConfig.getFirstDayOfWeek().plus(2)); + model.addAttribute("fourthWeekDay", this.financerConfig.getFirstDayOfWeek().plus(3)); + model.addAttribute("fifthWeekDay", this.financerConfig.getFirstDayOfWeek().plus(4)); + model.addAttribute("sixthWeekDay", this.financerConfig.getFirstDayOfWeek().plus(5)); + model.addAttribute("seventhWeekDay", this.financerConfig.getFirstDayOfWeek().plus(6)); + + // 2. Calculate the days in the calendar + DayOfWeek firstDayOfWeek = this.financerConfig.getFirstDayOfWeek(); + int tmpLastDayOfWeek = firstDayOfWeek.getValue() - 1; + DayOfWeek lastOfWeek = DayOfWeek.of(tmpLastDayOfWeek == 0 ? 7 : tmpLastDayOfWeek); + + LocalDate today = LocalDate.now().plusMonths(offsetNumber); + LocalDate firstOfMonth = today.withDayOfMonth(1); + LocalDate start = null; + + model.addAttribute("today", today); + + if (firstOfMonth.getDayOfWeek() == firstDayOfWeek) { + // nothing to do, first is firstDayOfWeek + start = firstOfMonth; + } + // walk back till we have firstDayOfWeek + else { + LocalDate tmp = firstOfMonth; + + while ((tmp = tmp.minusDays(1)).getDayOfWeek() != firstDayOfWeek) { + // Just spinning + } + + start = tmp; // last firstDayOfWeek of last month + } + + List days = new ArrayList<>(); + LocalDate end = today.plusMonths(1).withDayOfMonth(1); + + // Go till first lastOfWeek in next month, but only if the last day of the current month is + // not lastOfWeek + if (end.minusDays(1).getDayOfWeek() != lastOfWeek) { + + while (end.getDayOfWeek() != lastOfWeek) { + end = end.plusDays(1); + } + + end = end.plusDays(1); // because datesUntil parameter is exclusive + } + + start.datesUntil(end).forEach((ld) -> days.add(new Day(ld))); + + // 3. Get the recurring transactions due at the calculated days from the server + final String rangeStart = ControllerUtils.formatDate(this.financerConfig, days.get(0).getDate()); + final String rangeEnd = ControllerUtils.formatDate(this.financerConfig, days.get(days.size() - 1).getDate()); + + try { + final UriComponentsBuilder transactionBuilder = UriComponentsBuilder + .fromHttpUrl(ControllerUtils.buildUrl(this.financerConfig, Function.RT_GET_ALL_DUE_IN_RANGE)); + + transactionBuilder.queryParam("start", rangeStart); + transactionBuilder.queryParam("end", rangeEnd); + + final Iterable trxs = FinancerRestTemplate.exchangeGet(transactionBuilder, + new ParameterizedTypeReference>() { + }); + + // 3a. Match days and recurring transactions from server + IterableUtils.toList(trxs).stream().forEach(trx -> days.stream() + .filter(d -> d.getDate().equals(trx.getDate())) + .findFirst() + .get() + .setTransactions(trx.getRecurringTransactions())); + } + catch(FinancerRestException e) { + // TODO + model.addAttribute("errorMessage", e.getResponseReason().name()); + } + + // 4. Build the actual weeks from the data calculated before + List weeks = Lists.partition(days, 7).stream().map(l -> { + Week w = new Week(); + + LocalDate firstOfWeek = l.get(0).getDate(); + TemporalField woy = WeekFields.of(Locale.getDefault()).weekOfWeekBasedYear(); // Not sure about using Default locale, but well ... + + w.setWeekNumber(firstOfWeek.get(woy)); + w.setDays(l); + + return w; + }).collect(Collectors.toList()); + + model.addAttribute("weeks", weeks); + model.addAttribute("offset", offsetNumber); + + ControllerUtils.addVersionAttribute(model, this.financerConfig); + ControllerUtils.addCurrencySymbol(model, this.financerConfig); + + return "recurringTransaction/calendar"; + } +} diff --git a/financer-web-client/src/main/java/de/financer/controller/Function.java b/financer-web-client/src/main/java/de/financer/controller/Function.java index ebae840..34c55bc 100644 --- a/financer-web-client/src/main/java/de/financer/controller/Function.java +++ b/financer-web-client/src/main/java/de/financer/controller/Function.java @@ -30,6 +30,7 @@ public enum Function { RT_CREATE_RECURRING_TRANSACTION("recurringTransactions/createRecurringTransaction"), RT_DELETE_RECURRING_TRANSACTION("recurringTransactions/deleteRecurringTransaction"), RT_CREATE_TRANSACTION("recurringTransactions/createTransaction"), + RT_GET_ALL_DUE_IN_RANGE("recurringTransactions/getAllDueInRange"), P_GET_CURRENT_EXPENSE_PERIOD("periods/getCurrentExpensePeriod"), P_CLOSE_CURRENT_EXPENSE_PERIOD("periods/closeCurrentExpensePeriod"), 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 dfcf36f..ed8f430 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 @@ -1,6 +1,9 @@ package de.financer.controller; +import com.google.common.collect.Lists; import de.financer.ResponseReason; +import de.financer.calendar.Day; +import de.financer.calendar.Week; import de.financer.config.FinancerConfig; import de.financer.model.*; import de.financer.template.*; @@ -15,8 +18,15 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.util.UriComponentsBuilder; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalField; +import java.time.temporal.WeekFields; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.stream.Collectors; @Controller @@ -257,5 +267,4 @@ public class RecurringTransactionController { return "redirect:/accountOverview"; } - } 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 c5b0f16..c0f4021 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 @@ -11,6 +11,7 @@ import de.financer.form.NewTransactionForm; import de.financer.model.Account; import de.financer.template.exception.FinancerRestException; import de.financer.util.ControllerUtils; +import org.apache.commons.collections4.IterableUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; @@ -21,6 +22,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.util.UriComponentsBuilder; import java.io.IOException; +import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.Optional; @@ -56,10 +58,12 @@ public class TransactionController { model.addAttribute("transactions", trxs); + model.addAttribute("transactionCount", IterableUtils.size(trxs)); } catch(FinancerRestException e) { // TODO model.addAttribute("errorMessage", e.getResponseReason().name()); + model.addAttribute("transactionCount", 0); } model.addAttribute("form", form); diff --git a/financer-web-client/src/main/java/de/financer/util/ControllerUtils.java b/financer-web-client/src/main/java/de/financer/util/ControllerUtils.java index 7da2eb1..9f6f885 100644 --- a/financer-web-client/src/main/java/de/financer/util/ControllerUtils.java +++ b/financer-web-client/src/main/java/de/financer/util/ControllerUtils.java @@ -97,6 +97,6 @@ public class ControllerUtils { public static void addCurrencySymbol(Model model, FinancerConfig financerConfig) { // Add a space right in front of the currency symbol, so it's not glued to the amount - model.addAttribute("currencySymbol", " " + financerConfig.getCurrency().getSymbol()); + model.addAttribute("currencySymbol", " " + financerConfig.getCurrency().getSymbol()); } } diff --git a/financer-web-client/src/main/resources/config/application.properties b/financer-web-client/src/main/resources/config/application.properties index 21eba0e..dd7edc7 100644 --- a/financer-web-client/src/main/resources/config/application.properties +++ b/financer-web-client/src/main/resources/config/application.properties @@ -35,4 +35,8 @@ spring.messages.basename=i18n/message financer.currencyCode=EUR push-service-client.serverUrl=http://localhost:8077/push-service-server/ -logging.level.de.pushservice=DEBUG \ No newline at end of file +logging.level.de.pushservice=DEBUG + +# The first day of a week in a calendar +# Possible values: MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY +financer.firstDayOfWeek=MONDAY \ No newline at end of file diff --git a/financer-web-client/src/main/resources/i18n/message.properties b/financer-web-client/src/main/resources/i18n/message.properties index 1ac87b1..143c3bb 100644 --- a/financer-web-client/src/main/resources/i18n/message.properties +++ b/financer-web-client/src/main/resources/i18n/message.properties @@ -10,6 +10,7 @@ financer.account-overview.available-actions.recurring-transaction-all=Show all r financer.account-overview.available-actions.create-account-group=Create new account group financer.account-overview.available-actions.select-chart=Generate a chart financer.account-overview.available-actions.close-current-period=Close the current expense period +financer.account-overview.available-actions.recurring-transaction-calendar=Recurring transaction calendar financer.account-overview.status=Status\: financer.account-overview.status.recurring-transaction-due-today=Recurring transactions due today\: financer.account-overview.status.recurring-transaction-active=Active recurring transactions\: @@ -118,6 +119,7 @@ financer.transaction-list.table.recurring.yes=Yes financer.transaction-list.table.recurring.no=No financer.transaction-list.table.taxRelevant.true=Yes financer.transaction-list.table.taxRelevant.false=No +financer.transaction-list.transaction-count=Found {0} transactions financer.recurring-to-transaction-with-amount.title=financer\: create transaction from recurring with amount financer.recurring-to-transaction-with-amount.label.amount=Amount\: @@ -174,6 +176,7 @@ financer.interval-type.YEARLY=Yearly financer.holiday-weekend-type.SAME_DAY=Same day financer.holiday-weekend-type.NEXT_WORKDAY=Next workday financer.holiday-weekend-type.PREVIOUS_WORKDAY=Previous workday +financer.holiday-weekend-type.SKIP=Skip once financer.account-type.BANK=Bank financer.account-type.CASH=Cash @@ -199,8 +202,10 @@ financer.heading.chart-select=financer\: select a chart to generate financer.heading.chart-config-account-group-expenses-for-period=financer\: configure account group expenses for period chart financer.heading.chart-config-account-expenses-for-period=financer\: configure account expenses for period chart financer.heading.search-transactions=financer\: search transactions +financer.heading.recurring-transaction-calendar=financer\: recurring transaction calendar financer.cancel-back-to-overview=Cancel and back to overview +financer.back-to-overview=Back to overview financer.chart.account-group-expenses-current-period.title=Expenses of the current period grouped by account group financer.chart.account-group-expenses-for-period.title=Expenses for period from {0} to {1} grouped by account group @@ -218,6 +223,19 @@ financer.chart.name.ACCOUNT_EXPENSES_FOR_PERIOD=Expenses for a configurable peri financer.chart.name.EXPENSE_PERIOD_TOTALS_CURRENT_YEAR=Overview about the income and expenses in the current year (bar chart) financer.chart.name.EXPENSE_PERIOD_TOTALS_FOR_YEAR=Overview about the income and expenses for a configurable year (bar chart) +financer.recurring-transaction-calendar.title=financer\: recurring transaction calendar +financer.calendar.calendarweek=CW +financer.calendar.weekdays.MONDAY=Monday +financer.calendar.weekdays.TUESDAY=Tuesday +financer.calendar.weekdays.WEDNESDAY=Wednesday +financer.calendar.weekdays.THURSDAY=Thursday +financer.calendar.weekdays.FRIDAY=Friday +financer.calendar.weekdays.SATURDAY=Saturday +financer.calendar.weekdays.SUNDAY=Sunday +financer.calendar.previous=Previous month +financer.calendar.next=Next month +financer.calendar.current=Current month + financer.error-message.UNKNOWN_ERROR=An unknown error occurred! financer.error-message.INVALID_ACCOUNT_TYPE=The selected account type is not valid! financer.error-message.FROM_ACCOUNT_NOT_FOUND=The specified from account has not been found! diff --git a/financer-web-client/src/main/resources/i18n/message_de_DE.properties b/financer-web-client/src/main/resources/i18n/message_de_DE.properties index cfae917..7a41d71 100644 --- a/financer-web-client/src/main/resources/i18n/message_de_DE.properties +++ b/financer-web-client/src/main/resources/i18n/message_de_DE.properties @@ -10,6 +10,7 @@ financer.account-overview.available-actions.recurring-transaction-all=Zeige alle financer.account-overview.available-actions.create-account-group=Neue Konto-Gruppe erstellen financer.account-overview.available-actions.select-chart=Ein Diagramm erzeugen financer.account-overview.available-actions.close-current-period=Aktuelle Periode schlie\u00DFen +financer.account-overview.available-actions.recurring-transaction-calendar=Kalender wiederkehrende Buchung financer.account-overview.status=Status\: financer.account-overview.status.recurring-transaction-due-today=Wiederkehrende Buchungen heute f\u00E4llig\: financer.account-overview.status.recurring-transaction-active=Aktive wiederkehrende Buchungen\: @@ -118,6 +119,7 @@ financer.transaction-list.table.recurring.yes=Ja financer.transaction-list.table.recurring.no=Nein financer.transaction-list.table.taxRelevant.true=Ja financer.transaction-list.table.taxRelevant.false=Nein +financer.transaction-list.transaction-count={0} Buchungen gefunden financer.recurring-to-transaction-with-amount.title=financer\: Buchung mit Betrag aus wiederkehrender Buchung erstellen financer.recurring-to-transaction-with-amount.label.amount=Betrag\: @@ -174,6 +176,7 @@ financer.interval-type.YEARLY=J\u00E4hrlich financer.holiday-weekend-type.SAME_DAY=Gleicher Tag financer.holiday-weekend-type.NEXT_WORKDAY=N\u00E4chster Werktag financer.holiday-weekend-type.PREVIOUS_WORKDAY=Vorheriger Werktag +financer.holiday-weekend-type.SKIP=Einmalig \u00FCberspringen financer.account-type.BANK=Bank financer.account-type.CASH=Bar @@ -198,8 +201,10 @@ financer.heading.recurring-to-transaction-with-amount=financer\: Buchung mit Bet financer.heading.chart-select=financer\: Ein Diagramm zum Erzeugen ausw\u00E4hlen financer.heading.chart-config-account-group-expenses-for-period=financer\: Konfigurieren von Ausgaben f\u00FCr Periode gruppiert nach Konto-Gruppe Diagramm financer.heading.search-transactions=financer\: Buchungen suchen +financer.heading.recurring-transaction-calendar=financer\: Kalender wiederkehrende Buchung -financer.cancel-back-to-overview=Abbrechen und zur \u00DCbersicht +financer.cancel-back-to-overview=Abbrechen und zur\u00FCck zur \u00DCbersicht +financer.back-to-overview=Zur\u00FCck zur \u00DCbersicht financer.chart.account-group-expenses-current-period.title=Ausgaben in der aktuellen Periode gruppiert nach Konto-Gruppe financer.chart.account-group-expenses-for-period.title=Ausgaben in der Periode vom {0} bis {1} gruppiert nach Konto-Gruppe @@ -217,6 +222,19 @@ financer.chart.name.ACCOUNT_EXPENSES_FOR_PERIOD=Ausgaben f\u00FCr eine konfiguri financer.chart.name.EXPENSE_PERIOD_TOTALS_CURRENT_YEAR=\u00DCbersicht über das Einkommen und die Ausgaben im laufenden Jahr (Balkendiagramm) financer.chart.name.EXPENSE_PERIOD_TOTALS_FOR_YEAR=\u00DCbersicht über das Einkommen und die Ausgaben für ein konfigurierbares Jahr (Balkendiagramm) +financer.recurring-transaction-calendar.title=financer\: Kalender wiederkehrende Buchung +financer.calendar.calendarweek=KW +financer.calendar.weekdays.MONDAY=Montag +financer.calendar.weekdays.TUESDAY=Dienstag +financer.calendar.weekdays.WEDNESDAY=Mittwoch +financer.calendar.weekdays.THURSDAY=Donnerstag +financer.calendar.weekdays.FRIDAY=Freitag +financer.calendar.weekdays.SATURDAY=Samstag +financer.calendar.weekdays.SUNDAY=Sonntag +financer.calendar.previous=Letzter Monat +financer.calendar.next=N\u00E4chster Monat +financer.calendar.current=Aktueller Monat + financer.error-message.UNKNOWN_ERROR=Ein unbekannter Fehler ist aufgetreten! financer.error-message.INVALID_ACCOUNT_TYPE=Der ausgew\u00E4hlte Kontotyp ist ung\u00FCltig! financer.error-message.FROM_ACCOUNT_NOT_FOUND=Das ausgew\u00E4hlte Von-Konto wurde nicht gefunden! diff --git a/financer-web-client/src/main/resources/static/changelog.txt b/financer-web-client/src/main/resources/static/changelog.txt index e0c7dca..8c37afe 100644 --- a/financer-web-client/src/main/resources/static/changelog.txt +++ b/financer-web-client/src/main/resources/static/changelog.txt @@ -1,3 +1,10 @@ +v32 -> v33: +- Introduce Holiday/Weekend Type SKIP to skip an occurrence of a recurring transaction once, if the due date is either a + holiday or a weekend day +- Implement a calendar for recurring transactions +- Add result count to transaction search +- Fix a bug in the parsing of FQL + v31 -> v32: - Integrate new push-service release with VAPID support for Chrome based browsers @@ -26,13 +33,13 @@ v26 -> v27: usage) v25 -> v26: -- Close of the current expense period now creates null statistic entries for accounts that have not been used in +- Closing the current expense period now creates null statistic entries for accounts that have not been used in bookings in the period to close. This way the average spending better reflects the period average - Introduce period type GRAND TOTAL, that denotes a continuous, cumulative period, starting with the inception of the financer app, without an end - Introduce period type EXPENSE YEAR, that acts as a group for all expense periods in a year. This may not be a calendar year, if e.g. the EXPENSE periods do not start at the first of every month. This includes all periods that - start the in the year. This is a preparation for extended reports and year-based booking + start in the year - Transactions with a date in the past are now assigned to the proper EXPENSE and EXPENSE YEAR periods - Add a fav icon @@ -80,4 +87,4 @@ v16 -> v17: - Add this changelog to the footer - Locale of the recurring transaction reminder email is now configurable - Recurring transaction indicator in transaction overview (account details) is now properly translated -- Add chart report to visualize the expenses of the current/a configurable period grouped by account \ No newline at end of file +- Add chart report to visualize the expenses of the current/a configurable period grouped by account 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 70c5f4f..07f676e 100644 --- a/financer-web-client/src/main/resources/static/css/main.css +++ b/financer-web-client/src/main/resources/static/css/main.css @@ -93,7 +93,8 @@ tr:hover { text-align: center; } -#status-container > span, div { +#status-container > span, +#status-container > div { display: block; } @@ -135,7 +136,8 @@ input[type=submit] { margin-top: 1em; } -#footer-container > hr, div { +#footer-container > hr, +#footer-container > div { display: block; } @@ -203,4 +205,112 @@ input[type=submit] { #search-transactions-fql-detail > * { font-size: 0.7em; +} + +#cal { + width: 100%; + margin-top: 1.5em; + margin-bottom: 1.5em; + border-collapse: collapse; +} + +#cal th { + border-bottom: 1px solid #ddd; + border-right: 1px solid #ddd; +} + +#cal th:nth-last-child(1) { + border-right: 0px solid #ddd; +} + +#cal-control-con { + width: 100%; +} + +#cal-control-con-table { + width: 100%; +} + +#cal-control-con-table > tbody > tr > * { + width: 33%; + text-align: center; +} + +#cal-control-con-table > tbody > tr:hover { + background-color: transparent; +} + +.cal-day-previous { + background-color: #F0EEEE; +} + +.cal-day-con { + display: inline-block; + width: 100%; +} + +.cal-week-row:hover { + background-color: transparent; +} + +#cal-header-row:hover { + background-color: transparent; +} + +.cal-calendarweek { + text-align: center; + vertical-align: top; +} + +.cal-calendarweek-con-content { + margin-top: 0.5em; +} + +.cal-day-con-content-con-text { + margin-left: 0.5em; + margin-right: 0.5em; + margin-top: 0.3em; + margin-bottom: 0.3em; + background-color: #e9f9f9; + border: 1px; + border-style: solid; + border-color: #b9dFdF; + border-radius: 4px; + padding-left: 1em; + padding-right: 1em; + color: #000000; + display: inline-block; +} + +#transaction-list-container-count-con-text { + margin-bottom: 0px; + margin-top: 2em; +} + +#transaction-table { + margin-top: 0.2em; +} + +.cal-day-con-number-con-text { + margin: 0.5em; + color: #444242; +} + +.cal-day { + vertical-align: top; + border-bottom: 1px solid #ddd; + border-right: 1px solid #ddd; +} + +.cal-calendarweek { + border-right: 1px solid #ddd; + border-bottom: 1px solid #ddd; +} + +.cal-week-row td:nth-last-child(1) { + border-right: 0px solid #ddd; +} + +.cal-day-con-today { + background-color: #f5e5b8; } \ No newline at end of file diff --git a/financer-web-client/src/main/resources/static/readme.txt b/financer-web-client/src/main/resources/static/readme.txt index f3dfec8..e22b4e8 100644 --- a/financer-web-client/src/main/resources/static/readme.txt +++ b/financer-web-client/src/main/resources/static/readme.txt @@ -199,6 +199,4 @@ ==================== This chapter lists planned features. The list is in no particular order: - Transaction import from online banking (file based) - - Extended reports, e.g. forecasting based on recurring transactions and average spending - - Receivable account type - - Edit masks for accounts, transactions, recurring transactions \ No newline at end of file + - Extended reports, e.g. forecasting based on recurring transactions and average spending \ No newline at end of file diff --git a/financer-web-client/src/main/resources/templates/account/accountDetails.html b/financer-web-client/src/main/resources/templates/account/accountDetails.html index c510f1b..c48f2fb 100644 --- a/financer-web-client/src/main/resources/templates/account/accountDetails.html +++ b/financer-web-client/src/main/resources/templates/account/accountDetails.html @@ -17,7 +17,7 @@
- +
diff --git a/financer-web-client/src/main/resources/templates/account/accountOverview.html b/financer-web-client/src/main/resources/templates/account/accountOverview.html index 5a14b03..6a10108 100644 --- a/financer-web-client/src/main/resources/templates/account/accountOverview.html +++ b/financer-web-client/src/main/resources/templates/account/accountOverview.html @@ -17,12 +17,12 @@
- +
@@ -58,6 +58,8 @@ th:text="#{financer.account-overview.available-actions.create-recurring-transaction}"/> +
- + + th:utext="${#numbers.formatDecimal(acc.averageSpendingExpensePeriod/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/> - - diff --git a/financer-web-client/src/main/resources/templates/recurringTransaction/calendar.html b/financer-web-client/src/main/resources/templates/recurringTransaction/calendar.html new file mode 100644 index 0000000..5e8abb0 --- /dev/null +++ b/financer-web-client/src/main/resources/templates/recurringTransaction/calendar.html @@ -0,0 +1,63 @@ + + + + + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" th:href="@{/css/main.css}"> + <link rel="shortcut icon" th:href="@{/favicon.ico}"/> +</head> +<body> +<h1 th:text="#{financer.heading.recurring-transaction-calendar} + ' — ' + ${#temporals.monthName(today)} + ' ' + ${#temporals.year(today)}"/> +<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/> +<a th:href="@{/accountOverview}" th:text="#{financer.back-to-overview}"/> +<div id="calendar-container" th:fragment="recurring-transaction-calendar"> + <table id="cal"> + <tr id="cal-header-row"> + <th class="header-col" th:text="#{'financer.calendar.calendarweek'}"/> + <th class="header-col" th:text="#{'financer.calendar.weekdays.' + ${firstWeekDay}}"/> + <th class="header-col" th:text="#{'financer.calendar.weekdays.' + ${secondWeekDay}}"/> + <th class="header-col" th:text="#{'financer.calendar.weekdays.' + ${thirdWeekDay}}"/> + <th class="header-col" th:text="#{'financer.calendar.weekdays.' + ${fourthWeekDay}}"/> + <th class="header-col" th:text="#{'financer.calendar.weekdays.' + ${fifthWeekDay}}"/> + <th class="header-col" th:text="#{'financer.calendar.weekdays.' + ${sixthWeekDay}}"/> + <th class="header-col" th:text="#{'financer.calendar.weekdays.' + ${seventhWeekDay}}"/> + </tr> + <tr class="cal-week-row" th:each="week : ${weeks}"> + <td class="cal-calendarweek"> + <div class="cal-calendarweek-con"> + <p class="cal-calendarweek-con-content" th:text="${week.weekNumber}"/> + </div> + </td> + <td th:class="${day.isPreviousOrNextMonth(offset) ? 'cal-day-previous cal-day' : 'cal-day'}" th:each="day : ${week.days}"> + <div th:class="${day.today ? 'cal-day-con cal-day-con-today' : 'cal-day-con'}"> + <div class="cal-day-con-number-con"> + <p class="cal-day-con-number-con-text" th:text="${day.day}"/> + </div> + <div th:if="${!day.isPreviousOrNextMonth(offset)}" class="cal-day-con-content"> + <div class="cal-day-con-content-con" th:each="transaction : ${day.transactions}"> + <p class="cal-day-con-content-con-text" th:utext="${transaction.description + ' — ' + #numbers.formatDecimal(transaction.amount/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}" /> + </div> + </div> + </div> + </td> + </table> + <div id="cal-control-con"> + <table id="cal-control-con-table"> + <tr> + <td> + <a id="cal-control-con-prev" th:href="@{'/recurringTransactionCalendar?offset=' + ${offset-1} + ''}" th:text="#{financer.calendar.previous}" /> + </td> + <td> + <a id="cal-control-con-curr" th:href="@{'/recurringTransactionCalendar?offset=0'}" th:text="#{financer.calendar.current}" /> + </td> + <td> + <a id="cal-control-con-next" th:href="@{'/recurringTransactionCalendar?offset=' + ${offset+1} + ''}" th:text="#{financer.calendar.next}" /> + </td> + </tr> + </table> + </div> +</div> +<div th:replace="includes/footer :: footer"/> +</body> +</html> \ No newline at end of file diff --git a/financer-web-client/src/main/resources/templates/recurringTransaction/newRecurringTransaction.html b/financer-web-client/src/main/resources/templates/recurringTransaction/newRecurringTransaction.html index 17c3267..e4ce874 100644 --- a/financer-web-client/src/main/resources/templates/recurringTransaction/newRecurringTransaction.html +++ b/financer-web-client/src/main/resources/templates/recurringTransaction/newRecurringTransaction.html @@ -16,12 +16,12 @@ <label for="selectFromAccount" th:text="#{financer.recurring-transaction-new.label.from-account}"/> <select id="selectFromAccount" th:field="*{fromAccountKey}"> <option th:each="acc : ${fromAccounts}" th:value="${acc.key}" - th:text="#{'financer.recurring-transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')},${currencySymbol})}"/> + th:utext="#{'financer.recurring-transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')},${currencySymbol})}"/> </select> <label for="selectToAccount" th:text="#{financer.recurring-transaction-new.label.to-account}"/> <select id="selectToAccount" th:field="*{toAccountKey}"> <option th:each="acc : ${toAccounts}" th:value="${acc.key}" - th:text="#{'financer.recurring-transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')},${currencySymbol})}"/> + th:utext="#{'financer.recurring-transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')},${currencySymbol})}"/> </select> <label for="inputAmount" th:text="#{financer.recurring-transaction-new.label.amount}"/> <input type="text" id="inputAmount" th:field="*{amount}"/> diff --git a/financer-web-client/src/main/resources/templates/recurringTransaction/recurringTransactionList.html b/financer-web-client/src/main/resources/templates/recurringTransaction/recurringTransactionList.html index b746890..3b0c706 100644 --- a/financer-web-client/src/main/resources/templates/recurringTransaction/recurringTransactionList.html +++ b/financer-web-client/src/main/resources/templates/recurringTransaction/recurringTransactionList.html @@ -35,7 +35,7 @@ </td> <td th:text="${#temporals.format(rt.firstOccurrence)}"/> <td th:text="${#temporals.format(rt.lastOccurrence)}"/> - <td th:text="${#numbers.formatDecimal(rt.amount/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/> + <td th:utext="${#numbers.formatDecimal(rt.amount/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/> <td th:text="${rt.description}"/> <td th:text="#{'financer.interval-type.' + ${rt.intervalType}}"/> <td th:text="#{'financer.holiday-weekend-type.' + ${rt.holidayWeekendType}}"/> diff --git a/financer-web-client/src/main/resources/templates/transaction/newTransaction.html b/financer-web-client/src/main/resources/templates/transaction/newTransaction.html index e13c6c5..06d359b 100644 --- a/financer-web-client/src/main/resources/templates/transaction/newTransaction.html +++ b/financer-web-client/src/main/resources/templates/transaction/newTransaction.html @@ -16,12 +16,12 @@ <label for="selectFromAccount" th:text="#{financer.transaction-new.label.from-account}"/> <select id="selectFromAccount" th:field="*{fromAccountKey}"> <option th:each="acc : ${fromAccounts}" th:value="${acc.key}" - th:text="#{'financer.transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')},${currencySymbol})}"/> + th:utext="#{'financer.transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')},${currencySymbol})}"/> </select> <label for="selectToAccount" th:text="#{financer.transaction-new.label.to-account}"/> <select id="selectToAccount" th:field="*{toAccountKey}"> <option th:each="acc : ${toAccounts}" th:value="${acc.key}" - th:text="#{'financer.transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')},${currencySymbol})}"/> + th:utext="#{'financer.transaction-new.account-type.' + ${acc.type}(${acc.key},${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT')},${currencySymbol})}"/> </select> <label for="inputAmount" th:text="#{financer.transaction-new.label.amount}"/> <input type="text" id="inputAmount" th:field="*{amount}"/> diff --git a/financer-web-client/src/main/resources/templates/transaction/transactionList.html b/financer-web-client/src/main/resources/templates/transaction/transactionList.html index 916e303..5a9da76 100644 --- a/financer-web-client/src/main/resources/templates/transaction/transactionList.html +++ b/financer-web-client/src/main/resources/templates/transaction/transactionList.html @@ -1,4 +1,7 @@ <div id="transaction-list-container" th:fragment="transaction-list"> + <div id="transaction-list-container-count-con" th:if="${transactionCount != null}"> + <p id="transaction-list-container-count-con-text" th:text="#{'financer.transaction-list.transaction-count'(${transactionCount})}"/> + </div> <table id="transaction-table"> <tr> <th class="hideable-column" th:text="#{financer.transaction-list.table-header.id}"/> @@ -16,7 +19,7 @@ <td th:text="${transaction.fromAccount.key}" /> <td th:text="${transaction.toAccount.key}" /> <td th:text="${#temporals.format(transaction.date)}" /> - <td th:text="${#numbers.formatDecimal(transaction.amount/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/> + <td th:utext="${#numbers.formatDecimal(transaction.amount/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/> <td th:text="${transaction.description}" /> <td th:if="${transaction.recurring}" th:text="#{financer.transaction-list.table.recurring.yes}" /> <td th:if="${!transaction.recurring}" th:text="#{financer.transaction-list.table.recurring.no}" /> diff --git a/pom.xml b/pom.xml index c0fd917..5eeba60 100644 --- a/pom.xml +++ b/pom.xml @@ -30,8 +30,6 @@ </properties> <modules> - <module>financer-server</module> - <module>financer-web-client</module> <module>financer-common</module> </modules> @@ -90,7 +88,7 @@ <dependency> <groupId>de.77zzcx7.push-service</groupId> <artifactId>push-service-client-lib</artifactId> - <version>3</version> + <version>4-SNAPSHOT</version> </dependency> </dependencies> </dependencyManagement> @@ -122,5 +120,33 @@ </plugins> </build> </profile> + + <profile> + <id>all</id> + <modules> + <module>financer-common</module> + <module>financer-server</module> + <module>financer-web-client</module> + </modules> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + </profile> + + <profile> + <id>web-client</id> + <modules> + <module>financer-common</module> + <module>financer-web-client</module> + </modules> + </profile> + + <profile> + <id>server</id> + <modules> + <module>financer-common</module> + <module>financer-server</module> + </modules> + </profile> </profiles> </project>