Add expense period total chart
This commit is contained in:
@@ -20,6 +20,14 @@
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>javax.persistence-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.financer.dto;
|
||||
|
||||
import de.financer.model.AccountType;
|
||||
|
||||
public class ExpensePeriodTotal {
|
||||
private Long total;
|
||||
private String periodShortCode;
|
||||
private AccountType type;
|
||||
|
||||
public ExpensePeriodTotal() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public ExpensePeriodTotal(String periodShortCode, Long total, AccountType type) {
|
||||
this.total = total;
|
||||
this.periodShortCode = periodShortCode;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Long getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(Long total) {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public String getPeriodShortCode() {
|
||||
return periodShortCode;
|
||||
}
|
||||
|
||||
public void setPeriodShortCode(String periodShortCode) {
|
||||
this.periodShortCode = periodShortCode;
|
||||
}
|
||||
|
||||
public AccountType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(AccountType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
package de.financer.util;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.time.Period;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ExpensePeriod {
|
||||
private LocalDate start;
|
||||
@@ -24,27 +31,65 @@ public class ExpensePeriod {
|
||||
// => 10 < 15
|
||||
// now - one month = 2019-05-10
|
||||
// set the day = 2019-05-15 = start
|
||||
// end = start + one month = 2019-06-15
|
||||
// Period from 2019-05-15 to 2019-06-15
|
||||
// end = start + one month - one day = 2019-06-14
|
||||
// Period from 2019-05-15 to 2019-06-14
|
||||
periodStart = LocalDate.now().minusMonths(1).withDayOfMonth(periodStartDay);
|
||||
periodEnd = periodStart.plusMonths(1);
|
||||
}
|
||||
else {
|
||||
periodEnd = periodStart.plusMonths(1).minusDays(1);
|
||||
} else {
|
||||
// Else, the current day of month is greater or equals the configured period
|
||||
// start day, just reset the day of month to the configured day, for example:
|
||||
// configured start day of month for period = 15
|
||||
// now = 2019-06-26
|
||||
// => 26 > 15
|
||||
// set the day = 2019-06-15 = start
|
||||
// end = start + one month = 2019-07-15
|
||||
// Period from 2019-06-15 to 2019-07-15
|
||||
// end = start + one month - one day = 2019-07-14
|
||||
// Period from 2019-06-15 to 2019-07-14
|
||||
periodStart = LocalDate.now().withDayOfMonth(periodStartDay);
|
||||
periodEnd = periodStart.plusMonths(1);
|
||||
periodEnd = periodStart.plusMonths(1).minusDays(1);
|
||||
}
|
||||
|
||||
return new ExpensePeriod(periodStart, periodEnd);
|
||||
}
|
||||
|
||||
public static final List<ExpensePeriod> generateExpensePeriodsForYear(int periodStartDay, int year) {
|
||||
Stream<LocalDate> localDateStreamStart;
|
||||
Stream<LocalDate> localDateStreamEnd;
|
||||
|
||||
if (periodStartDay == 1) {
|
||||
localDateStreamStart = LocalDate.of(year, Month.JANUARY, 1)
|
||||
.datesUntil(LocalDate.of(year, Month.DECEMBER, 2), Period
|
||||
.ofMonths(1));
|
||||
|
||||
localDateStreamEnd = LocalDate.of(year, Month.JANUARY, 31)
|
||||
.datesUntil(LocalDate.of(year + 1, Month.JANUARY, 1), Period
|
||||
.ofMonths(1));
|
||||
}
|
||||
// If the start of the period is not the 1st we need to look to the previous year as well
|
||||
// because the period in January actually started in December last year
|
||||
else {
|
||||
localDateStreamStart = LocalDate.of(year, Month.JANUARY, periodStartDay).minusMonths(1)
|
||||
.datesUntil(LocalDate.of(year, Month.DECEMBER, periodStartDay + 1).plusDays(1), Period
|
||||
.ofMonths(1));
|
||||
|
||||
localDateStreamEnd = LocalDate.of(year, Month.JANUARY, periodStartDay - 1)
|
||||
.datesUntil(LocalDate.of(year, Month.DECEMBER, periodStartDay + 1).plusDays(1), Period
|
||||
.ofMonths(1));
|
||||
}
|
||||
|
||||
return Streams
|
||||
.zip(localDateStreamStart, localDateStreamEnd, (start, end) -> new ExpensePeriod(start, end))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String generatePeriodShortCode() {
|
||||
return String.format("%s/%s", this.start.getYear(), this.start.getMonthValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Start[%s], End[%s], ShortCode[%s]", this.start, this.end, this.generatePeriodShortCode());
|
||||
}
|
||||
|
||||
public LocalDate getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.financer.controller;
|
||||
|
||||
import de.financer.ResponseReason;
|
||||
import de.financer.dto.ExpensePeriodTotal;
|
||||
import de.financer.model.Transaction;
|
||||
import de.financer.service.TransactionService;
|
||||
import org.slf4j.Logger;
|
||||
@@ -10,9 +11,6 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("transactions")
|
||||
public class TransactionController {
|
||||
@@ -94,4 +92,20 @@ public class TransactionController {
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@RequestMapping("getExpensePeriodTotals")
|
||||
public Iterable<ExpensePeriodTotal> getExpensePeriodTotals(Integer monthPeriodStartDay, Integer year) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("/transactions/getExpensePeriodTotals got parameters: %s, %s", monthPeriodStartDay, year));
|
||||
}
|
||||
|
||||
final Iterable<ExpensePeriodTotal> expensePeriodTotals = this.transactionService
|
||||
.getExpensePeriodTotals(monthPeriodStartDay, year);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("/transactions/getExpensePeriodTotals returns with %s", expensePeriodTotals));
|
||||
}
|
||||
|
||||
return expensePeriodTotals;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.financer.dba;
|
||||
|
||||
import de.financer.dto.ExpensePeriodTotal;
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.AccountType;
|
||||
import de.financer.model.Transaction;
|
||||
@@ -9,6 +10,7 @@ import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public interface TransactionRepository extends CrudRepository<Transaction, Long> {
|
||||
@@ -16,4 +18,11 @@ public interface TransactionRepository extends CrudRepository<Transaction, Long>
|
||||
|
||||
@Query("SELECT SUM(t.amount) FROM Transaction t JOIN t.toAccount a WHERE t.date BETWEEN :periodStart AND :periodEnd AND a.type IN :expenseTypes")
|
||||
Long getExpensesCurrentPeriod(LocalDate periodStart, LocalDate periodEnd, AccountType... expenseTypes);
|
||||
|
||||
// The HQL contains a hack because Hibernate can't resolve the alias of the CASE column in the GROUP BY clause
|
||||
// That's why the generated alias is used directly in the HQL. It will break if the columns in the SELECT clause get reordered
|
||||
// col_0_0_ instead of periodShortCode
|
||||
// col_2_0_ instead of AccType
|
||||
@Query("SELECT new de.financer.dto.ExpensePeriodTotal(CASE WHEN EXTRACT(DAY FROM t.date) >= :startDay THEN CONCAT(CAST(EXTRACT(YEAR FROM t.date) AS string), '/', CAST(EXTRACT(MONTH FROM t.date) AS string)) ELSE CASE WHEN EXTRACT(MONTH FROM t.date) = 1 THEN CONCAT(CAST(EXTRACT(YEAR FROM t.date) - 1 AS string), '/12') ELSE CONCAT(CAST(EXTRACT(YEAR FROM t.date) AS string), '/', CAST(EXTRACT(MONTH FROM t.date) - 1 AS string)) END END AS periodShortCode, SUM(t.amount), CASE WHEN fa.type = :incomeType THEN fa.type ELSE ta.type END AS AccType) FROM Transaction t JOIN t.toAccount ta JOIN t.fromAccount fa WHERE ((ta.type IN :expenseTypes AND fa.type <> :startType) OR (fa.type = :incomeType)) AND t.date BETWEEN :lowerBound AND :upperBound GROUP BY col_0_0_, col_2_0_ ORDER BY periodShortCode, AccType ASC")
|
||||
List<ExpensePeriodTotal> getAccountExpenseTotals(int startDay, LocalDate lowerBound, LocalDate upperBound, AccountType incomeType, AccountType startType, AccountType... expenseTypes);
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package de.financer.service;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import de.financer.ResponseReason;
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.dba.TransactionRepository;
|
||||
import de.financer.dto.ExpensePeriodTotal;
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.AccountType;
|
||||
import de.financer.model.RecurringTransaction;
|
||||
@@ -21,6 +23,7 @@ import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@@ -239,4 +242,17 @@ public class TransactionService {
|
||||
|
||||
return Optional.ofNullable(expensesCurrentPeriod).orElse(Long.valueOf(0l));
|
||||
}
|
||||
|
||||
public Iterable<ExpensePeriodTotal> getExpensePeriodTotals(Integer monthPeriodStartDay, Integer year) {
|
||||
final List<ExpensePeriod> expensePeriods = ExpensePeriod.generateExpensePeriodsForYear(monthPeriodStartDay, year);
|
||||
|
||||
final ExpensePeriod lowerBound = Iterables.get(expensePeriods, 0);
|
||||
final ExpensePeriod upperBound = Iterables.getLast(expensePeriods);
|
||||
|
||||
final List<ExpensePeriodTotal> expensePeriodTotals = this.transactionRepository
|
||||
.getAccountExpenseTotals(monthPeriodStartDay, lowerBound.getStart(), upperBound
|
||||
.getEnd(), AccountType.INCOME, AccountType.START, AccountType.EXPENSE, AccountType.LIABILITY);
|
||||
|
||||
return expensePeriodTotals;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ public enum ChartType {
|
||||
ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD,
|
||||
ACCOUNT_GROUP_EXPENSES_FOR_PERIOD,
|
||||
ACCOUNT_EXPENSES_CURRENT_PERIOD,
|
||||
ACCOUNT_EXPENSES_FOR_PERIOD;
|
||||
ACCOUNT_EXPENSES_FOR_PERIOD,
|
||||
EXPENSE_PERIOD_TOTALS_CURRENT_YEAR;
|
||||
|
||||
public static List<String> valueList() {
|
||||
return Arrays.stream(ChartType.values()).map(ChartType::name).collect(Collectors.toList());
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.financer.chart;
|
||||
|
||||
import de.financer.chart.impl.expense.AccountExpensesGenerator;
|
||||
import de.financer.chart.impl.expense.AccountGroupExpensesGenerator;
|
||||
import de.financer.chart.impl.total.PeriodTotalGenerator;
|
||||
import de.financer.config.FinancerConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
@@ -31,6 +32,10 @@ public class FinancerChartFactory {
|
||||
// TODO WHY IS THIS CAST NECESSARY???
|
||||
generator = (AbstractChartGenerator<P>) new AccountExpensesGenerator();
|
||||
break;
|
||||
case EXPENSE_PERIOD_TOTALS_CURRENT_YEAR:
|
||||
// TODO WHY IS THIS CAST NECESSARY???
|
||||
generator = (AbstractChartGenerator<P>) new PeriodTotalGenerator();
|
||||
break;
|
||||
default:
|
||||
generator = null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package de.financer.chart.impl.total;
|
||||
|
||||
import de.financer.chart.AbstractChartGenerator;
|
||||
import de.financer.dto.ExpensePeriodTotal;
|
||||
import de.financer.template.GetExpensePeriodTotalsTemplate;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import de.financer.util.ExpensePeriod;
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.data.category.CategoryDataset;
|
||||
import org.jfree.data.category.DefaultCategoryDataset;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.List;
|
||||
|
||||
public class PeriodTotalGenerator extends AbstractChartGenerator<PeriodTotalParameter> {
|
||||
@Override
|
||||
public JFreeChart generateChart(PeriodTotalParameter parameter) {
|
||||
final CategoryDataset dataSet = getDataset(parameter);
|
||||
|
||||
final JFreeChart chart = ChartFactory
|
||||
.createBarChart(this.getMessage(parameter.getTitle(), parameter.getArgsForTitle()),
|
||||
this.getMessage(parameter.getyAxis()),
|
||||
this.getMessage(parameter.getxAxis()),
|
||||
dataSet, PlotOrientation.VERTICAL, true, true, false);
|
||||
|
||||
final NumberAxis axis = (NumberAxis) chart.getCategoryPlot().getRangeAxis();
|
||||
|
||||
axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits(LocaleContextHolder
|
||||
.getLocale()));
|
||||
|
||||
final NumberFormat currencyInstance = NumberFormat.getCurrencyInstance(LocaleContextHolder.getLocale());
|
||||
currencyInstance.setCurrency(this.getFinancerConfig().getCurrency());
|
||||
|
||||
axis.setNumberFormatOverride(currencyInstance);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
private CategoryDataset getDataset(PeriodTotalParameter parameter) {
|
||||
final DefaultCategoryDataset result = new DefaultCategoryDataset();
|
||||
final List<ExpensePeriod> expensePeriods = ExpensePeriod
|
||||
.generateExpensePeriodsForYear(this.getFinancerConfig().getMonthPeriodStartDay(), parameter.getYear());
|
||||
|
||||
final Iterable<ExpensePeriodTotal> totalData = new GetExpensePeriodTotalsTemplate()
|
||||
.exchange(this.getFinancerConfig(), parameter.getYear()).getBody();
|
||||
|
||||
IterableUtils.toList(totalData).stream()
|
||||
.forEach((ept) -> result.addValue((ept.getTotal() / 100D),
|
||||
this.getMessage("financer.account-type." + ept.getType()),
|
||||
expensePeriods.stream()
|
||||
.filter((ep) -> ep.generatePeriodShortCode()
|
||||
.equals(ept.getPeriodShortCode()))
|
||||
.map((ep) -> formatDateY(ep))
|
||||
.findFirst().get()));
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String formatDateY(ExpensePeriod ep) {
|
||||
return String.format("%s - %s",
|
||||
ep.getStart().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
|
||||
.withLocale(LocaleContextHolder.getLocale())),
|
||||
ep.getEnd().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
|
||||
.withLocale(LocaleContextHolder.getLocale())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.financer.chart.impl.total;
|
||||
|
||||
import de.financer.chart.ChartParameter;
|
||||
|
||||
public class PeriodTotalParameter implements ChartParameter {
|
||||
private String title;
|
||||
private Object[] argsForTitle;
|
||||
private String yAxis;
|
||||
private String xAxis;
|
||||
private int year;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Object[] getArgsForTitle() {
|
||||
return argsForTitle;
|
||||
}
|
||||
|
||||
public void setArgsForTitle(Object[] argsForTitle) {
|
||||
this.argsForTitle = argsForTitle;
|
||||
}
|
||||
|
||||
public int getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public void setYear(int year) {
|
||||
this.year = year;
|
||||
}
|
||||
|
||||
public String getyAxis() {
|
||||
return yAxis;
|
||||
}
|
||||
|
||||
public void setyAxis(String yAxis) {
|
||||
this.yAxis = yAxis;
|
||||
}
|
||||
|
||||
public String getxAxis() {
|
||||
return xAxis;
|
||||
}
|
||||
|
||||
public void setxAxis(String xAxis) {
|
||||
this.xAxis = xAxis;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import de.financer.chart.impl.expense.ExpensesParameter;
|
||||
import de.financer.chart.ChartGenerator;
|
||||
import de.financer.chart.ChartType;
|
||||
import de.financer.chart.FinancerChartFactory;
|
||||
import de.financer.chart.impl.total.PeriodTotalParameter;
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.form.ConfigAccountExpenseForPeriodForm;
|
||||
import de.financer.form.ConfigAccountGroupExpenseForPeriodForm;
|
||||
@@ -19,6 +20,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Controller
|
||||
public class ChartController {
|
||||
@@ -104,6 +106,23 @@ public class ChartController {
|
||||
writeChart(response, chart);
|
||||
}
|
||||
|
||||
@GetMapping("/getExpensePeriodTotalCurrentYear")
|
||||
public void getExpensePeriodTotalCurrentYear(HttpServletResponse response) {
|
||||
PeriodTotalParameter parameter = new PeriodTotalParameter();
|
||||
|
||||
parameter.setYear(LocalDate.now().getYear());
|
||||
parameter.setTitle("financer.chart.expense-period-totals-current-year.title");
|
||||
parameter.setxAxis("financer.chart.expense-period-totals-current-year.x");
|
||||
parameter.setyAxis("financer.chart.expense-period-totals-current-year.y");
|
||||
|
||||
final ChartGenerator<PeriodTotalParameter> generator =
|
||||
this.financerChartFactory.getGenerator(ChartType.EXPENSE_PERIOD_TOTALS_CURRENT_YEAR);
|
||||
|
||||
final JFreeChart chart = generator.generateChart(parameter);
|
||||
|
||||
writeChart(response, chart);
|
||||
}
|
||||
|
||||
private void writeChart(HttpServletResponse response, JFreeChart chart) {
|
||||
response.setContentType("image/png");
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ public enum Function {
|
||||
TR_CREATE_TRANSACTION("transactions/createTransaction"),
|
||||
TR_DELETE_TRANSACTION("transactions/deleteTransaction"),
|
||||
TR_EXPENSES_CURRENT_PERIOD("transactions/getExpensesCurrentPeriod"),
|
||||
TR_EXPENSE_PERIOD_TOTALS("transactions/getExpensePeriodTotals"),
|
||||
|
||||
RT_GET_ALL("recurringTransactions/getAll"),
|
||||
RT_GET_ALL_ACTIVE("recurringTransactions/getAllActive"),
|
||||
|
||||
@@ -67,6 +67,10 @@ public class ReportController {
|
||||
ControllerUtils.addCurrencySymbol(model, this.financerConfig);
|
||||
|
||||
return "report/configureAccountExpensesForPeriod";
|
||||
case EXPENSE_PERIOD_TOTALS_CURRENT_YEAR:
|
||||
// Special case: this chart does not require parameters, so we can
|
||||
// directly redirect to the actual chart instead of the config page
|
||||
return "redirect:/getExpensePeriodTotalCurrentYear";
|
||||
default:
|
||||
// Cannot happen
|
||||
throw new IllegalStateException("Unexpected value: " + selectedChartType);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package de.financer.template;
|
||||
|
||||
import de.financer.config.FinancerConfig;
|
||||
import de.financer.controller.Function;
|
||||
import de.financer.dto.ExpensePeriodTotal;
|
||||
import de.financer.util.ControllerUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
public class GetExpensePeriodTotalsTemplate {
|
||||
public ResponseEntity<Iterable<ExpensePeriodTotal>> exchange(FinancerConfig financerConfig, int year) {
|
||||
final UriComponentsBuilder builder = UriComponentsBuilder
|
||||
.fromHttpUrl(ControllerUtils.buildUrl(financerConfig, Function.TR_EXPENSE_PERIOD_TOTALS))
|
||||
.queryParam("monthPeriodStartDay", financerConfig.getMonthPeriodStartDay())
|
||||
.queryParam("year", year);
|
||||
|
||||
return new FinancerRestTemplate<Iterable<ExpensePeriodTotal>>()
|
||||
.exchange(builder.toUriString(), new ParameterizedTypeReference<Iterable<ExpensePeriodTotal>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -160,11 +160,16 @@ financer.chart.account-group-expenses-current-period.title=Expenses of the curre
|
||||
financer.chart.account-group-expenses-for-period.title=Expenses for period from {0} to {1} grouped by account group
|
||||
financer.chart.account-expenses-current-period.title=Expenses of the current period grouped by account
|
||||
financer.chart.account-expenses-for-period.title=Expenses for period from {0} to {1} grouped by account
|
||||
financer.chart.expense-period-totals-current-year.title=Expense period totals for the current year
|
||||
financer.chart.expense-period-totals-current-year.x=Amount
|
||||
financer.chart.expense-period-totals-current-year.y=Period
|
||||
|
||||
financer.chart.name.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD=Expenses of the current period grouped by account group (pie chart)
|
||||
financer.chart.name.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD=Expenses for a configurable period grouped by account group (pie chart)
|
||||
financer.chart.name.ACCOUNT_EXPENSES_CURRENT_PERIOD=Expenses of the current period grouped by account (pie chart)
|
||||
financer.chart.name.ACCOUNT_EXPENSES_FOR_PERIOD=Expenses for a configurable period grouped by account (pie chart)
|
||||
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.error-message.UNKNOWN_ERROR=An unknown error occurred!
|
||||
financer.error-message.INVALID_ACCOUNT_TYPE=The selected account type is not valid!
|
||||
|
||||
@@ -159,11 +159,16 @@ financer.chart.account-group-expenses-current-period.title=Ausgaben in der aktue
|
||||
financer.chart.account-group-expenses-for-period.title=Ausgaben in der Periode vom {0} bis {1} gruppiert nach Konto-Gruppe
|
||||
financer.chart.account-expenses-current-period.title=Ausgaben in der aktuellen Periode gruppiert nach Konto
|
||||
financer.chart.account-expenses-for-period.title=Ausgaben in der Periode vom {0} bis {1} gruppiert nach Konto
|
||||
financer.chart.expense-period-totals-current-year.title=Gesamtbetr\u00E4ge gruppiert nach Periode für das aktuelle Jahr
|
||||
financer.chart.expense-period-totals-current-year.x=Betrag
|
||||
financer.chart.expense-period-totals-current-year.y=Periode
|
||||
|
||||
financer.chart.name.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD=Ausgaben in der aktuellen Periode gruppiert nach Konto-Gruppe (Kuchendiagramm)
|
||||
financer.chart.name.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD=Ausgaben f\u00FCr eine konfigurierbare Periode gruppiert nach Konto-Gruppe (Kuchendiagramm)
|
||||
financer.chart.name.ACCOUNT_EXPENSES_CURRENT_PERIOD=Ausgaben in der aktuellen Periode gruppiert nach Konto (Kuchendiagramm)
|
||||
financer.chart.name.ACCOUNT_EXPENSES_FOR_PERIOD=Ausgaben f\u00FCr eine konfigurierbare Periode gruppiert nach Konto (Kuchendiagramm)
|
||||
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.error-message.UNKNOWN_ERROR=Ein unbekannter Fehler ist aufgetreten!
|
||||
financer.error-message.INVALID_ACCOUNT_TYPE=Der ausgew\u00E4hlte Kontotyp ist ung\u00FCltig!
|
||||
|
||||
@@ -2,6 +2,7 @@ v17 -> v18:
|
||||
- Add readme to the footer
|
||||
- Translate error messages to German
|
||||
- Add chart type to chart description in chart type selection page
|
||||
- Add expense period total chart
|
||||
|
||||
v16 -> v17:
|
||||
- Add this changelog to the footer
|
||||
|
||||
5
pom.xml
5
pom.xml
@@ -66,6 +66,11 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>28.0-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.77zzcx7.financer</groupId>
|
||||
<artifactId>financer-common</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user