Add calendar, SKIP and fix some bugs
This commit is contained in:
@@ -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<RecurringTransaction> recurringTransactions;
|
||||
|
||||
public RecurringTransactionDueInRangeResponseDto() {
|
||||
|
||||
}
|
||||
|
||||
public RecurringTransactionDueInRangeResponseDto(LocalDate date, Iterable<RecurringTransaction> recurringTransactions) {
|
||||
this.date = date;
|
||||
this.recurringTransactions = recurringTransactions;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public Iterable<RecurringTransaction> getRecurringTransactions() {
|
||||
return recurringTransactions;
|
||||
}
|
||||
|
||||
public void setRecurringTransactions(Iterable<RecurringTransaction> recurringTransactions) {
|
||||
this.recurringTransactions = recurringTransactions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ReflectionToStringBuilder.toString(this);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,14 @@ public enum HolidayWeekendType {
|
||||
* X' -> Earlier, effective due date of action
|
||||
* </pre>
|
||||
*/
|
||||
PREVIOUS_WORKDAY;
|
||||
PREVIOUS_WORKDAY,
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Indicates that the action should be skipped on the particular occurrence
|
||||
* </p>
|
||||
*/
|
||||
SKIP;
|
||||
|
||||
/**
|
||||
* This method validates whether the given string represents a valid holiday weekend type.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<properties>
|
||||
<packaging.type>jar</packaging.type>
|
||||
<activeProfiles>hsqldb,dev</activeProfiles>
|
||||
<activeProfiles>postgres,dev</activeProfiles>
|
||||
<deploymentProfile>mk</deploymentProfile>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -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')+ ;
|
||||
|
||||
@@ -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<RecurringTransactionDueInRangeResponseDto> getAllDueInRange(String start, String end) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String
|
||||
.format("/recurringTransactions/getAllDueInRange got parameters: %s, %s",
|
||||
start, end));
|
||||
}
|
||||
|
||||
final Iterable<RecurringTransactionDueInRangeResponseDto> dueInRange = this.recurringTransactionService.getAllDueInRange(start, end);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String
|
||||
.format("/recurringTransactions/getAllDueInRange returns with %s", dueInRange));
|
||||
}
|
||||
|
||||
return dueInRange;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <code>true</code> if the recurring transaction is due today, <code>false</code> 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 <code>true</code> if the recurring transaction is due today, <code>false</code> 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<RecurringTransactionDueInRangeResponseDto> getAllDueInRange(String start, String end) {
|
||||
final List<RecurringTransactionDueInRangeResponseDto> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ public class RuleService implements InitializingBean {
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @param fromAccount the from account to get the multiplier for
|
||||
*
|
||||
@@ -102,6 +103,7 @@ public class RuleService implements InitializingBean {
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @param toAccount the to account to get the multiplier for
|
||||
*
|
||||
|
||||
@@ -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<RecurringTransaction> 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<RecurringTransaction> 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<RecurringTransaction> transactions) {
|
||||
this.transactions = transactions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Day{" +
|
||||
"date=" + date +
|
||||
", transactions=" + transactions +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package de.financer.calendar;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Week {
|
||||
private int weekNumber;
|
||||
private List<Day> days;
|
||||
|
||||
public int getWeekNumber() {
|
||||
return weekNumber;
|
||||
}
|
||||
|
||||
public void setWeekNumber(int weekNumber) {
|
||||
this.weekNumber = weekNumber;
|
||||
}
|
||||
|
||||
public List<Day> getDays() {
|
||||
return days;
|
||||
}
|
||||
|
||||
public void setDays(List<Day> days) {
|
||||
this.days = days;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Week{" +
|
||||
"weekNumber=" + weekNumber +
|
||||
", days=" + days +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Day> 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<RecurringTransactionDueInRangeResponseDto> trxs = FinancerRestTemplate.exchangeGet(transactionBuilder,
|
||||
new ParameterizedTypeReference<Iterable<RecurringTransactionDueInRangeResponseDto>>() {
|
||||
});
|
||||
|
||||
// 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<Week> 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";
|
||||
}
|
||||
}
|
||||
@@ -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"),
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
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
|
||||
@@ -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!
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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
|
||||
- Add chart report to visualize the expenses of the current/a configurable period grouped by account
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
- Extended reports, e.g. forecasting based on recurring transactions and average spending
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div id="balance-container">
|
||||
<span th:text="#{financer.account-details.details.balance}"/>
|
||||
<span th:text="${#numbers.formatDecimal(account.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||
<span th:utext="${#numbers.formatDecimal(account.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||
</div>
|
||||
<div id="group-container" th:if="${account.accountGroup != null}">
|
||||
<span th:text="#{financer.account-details.details.group}"/>
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
<span th:text="#{financer.account-overview.status}"/>
|
||||
<div th:title="#{financer.account-overview.tooltip.status.current-assets}">
|
||||
<span th:text="#{financer.account-overview.status.current-assets}"/>
|
||||
<span th:text="${#numbers.formatDecimal(currentAssets/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||
<span th:utext="${#numbers.formatDecimal(currentAssets/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||
</div>
|
||||
<div th:title="#{'financer.account-overview.tooltip.status.current-expenses'(${#temporals.format(periodStart)})}">
|
||||
<span th:text="#{financer.account-overview.status.current-expenses}"/>
|
||||
<a th:href="@{/getAccountGroupExpensesCurrentPeriod}">
|
||||
<span th:text="${#numbers.formatDecimal(currentExpenses/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}" />
|
||||
<span th:utext="${#numbers.formatDecimal(currentExpenses/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}" />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
@@ -58,6 +58,8 @@
|
||||
th:text="#{financer.account-overview.available-actions.create-recurring-transaction}"/>
|
||||
<a th:href="@{/recurringTransactionAll}"
|
||||
th:text="#{financer.account-overview.available-actions.recurring-transaction-all}"/>
|
||||
<a th:href="@{'/recurringTransactionCalendar?offset=0'}"
|
||||
th:text="#{financer.account-overview.available-actions.recurring-transaction-calendar}"/>
|
||||
</div>
|
||||
<div id="action-container-sub-period">
|
||||
<a th:href="@{/closePeriod}"
|
||||
@@ -91,14 +93,14 @@
|
||||
<td>
|
||||
<a th:href="@{/accountDetails(key=${acc.key})}" th:text="${acc.key}"/>
|
||||
</td>
|
||||
<td th:text="${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||
<td th:utext="${#numbers.formatDecimal(acc.currentBalance/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||
<td class="hideable-column"
|
||||
th:if="${acc.spendingCurrentExpensePeriod != null}"
|
||||
th:text="${#numbers.formatDecimal(acc.spendingCurrentExpensePeriod/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"
|
||||
th:utext="${#numbers.formatDecimal(acc.spendingCurrentExpensePeriod/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"
|
||||
th:classappend="${acc.spendingCurrentExpensePeriod > acc.averageSpendingExpensePeriod} ? overspend"/>
|
||||
<td class="hideable-column"
|
||||
th:if="${acc.averageSpendingExpensePeriod != null}"
|
||||
th:text="${#numbers.formatDecimal(acc.averageSpendingExpensePeriod/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||
th:utext="${#numbers.formatDecimal(acc.averageSpendingExpensePeriod/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||
<td class="hideable-column" th:if="${acc.spendingCurrentExpensePeriod == null}">-</td>
|
||||
<td class="hideable-column" th:if="${acc.averageSpendingExpensePeriod == null}">-</td>
|
||||
<td class="hideable-column" th:text="${acc.accountGroup?.name}"/>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="#{financer.recurring-transaction-calendar.title}"/>
|
||||
<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>
|
||||
@@ -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}"/>
|
||||
|
||||
@@ -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}}"/>
|
||||
|
||||
@@ -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}"/>
|
||||
|
||||
@@ -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}" />
|
||||
|
||||
32
pom.xml
32
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>
|
||||
|
||||
Reference in New Issue
Block a user