Add chart report for expenses grouped by account
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
package de.financer.dto;
|
||||||
|
|
||||||
|
import de.financer.model.Account;
|
||||||
|
|
||||||
|
public class AccountExpense {
|
||||||
|
private Account account;
|
||||||
|
private Long expense;
|
||||||
|
|
||||||
|
public AccountExpense() {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountExpense(Account account, Long expense) {
|
||||||
|
this.account = account;
|
||||||
|
this.expense = expense;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account getAccount() {
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccount(Account account) {
|
||||||
|
this.account = account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getExpense() {
|
||||||
|
return expense;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpense(Long expense) {
|
||||||
|
this.expense = expense;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.financer.controller;
|
package de.financer.controller;
|
||||||
|
|
||||||
import de.financer.ResponseReason;
|
import de.financer.ResponseReason;
|
||||||
|
import de.financer.dto.AccountExpense;
|
||||||
import de.financer.model.Account;
|
import de.financer.model.Account;
|
||||||
import de.financer.service.AccountService;
|
import de.financer.service.AccountService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -101,4 +102,13 @@ public class AccountController {
|
|||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("getAccountExpenses")
|
||||||
|
public Iterable<AccountExpense> getAccountExpenses(String periodStart, String periodEnd) {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug(String.format("/accounts/getAccountExpenses got parameters: %s|%s", periodStart, periodEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.accountService.getAccountExpenses(periodStart, periodEnd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.financer.dba;
|
package de.financer.dba;
|
||||||
|
|
||||||
|
import de.financer.dto.AccountExpense;
|
||||||
import de.financer.model.Account;
|
import de.financer.model.Account;
|
||||||
import de.financer.model.AccountType;
|
import de.financer.model.AccountType;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
@@ -7,10 +8,15 @@ import org.springframework.data.repository.CrudRepository;
|
|||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
public interface AccountRepository extends CrudRepository<Account, Long> {
|
public interface AccountRepository extends CrudRepository<Account, Long> {
|
||||||
Account findByKey(String key);
|
Account findByKey(String key);
|
||||||
|
|
||||||
@Query("SELECT SUM(a.currentBalance) FROM Account a WHERE a.type IN :accountTypes")
|
@Query("SELECT SUM(a.currentBalance) FROM Account a WHERE a.type IN :accountTypes")
|
||||||
Long getCurrentAssets(AccountType... accountTypes);
|
Long getCurrentAssets(AccountType... accountTypes);
|
||||||
|
|
||||||
|
@Query("SELECT new de.financer.dto.AccountExpense(a, SUM(t.amount)) FROM Transaction t JOIN t.toAccount a WHERE a.type in :expenseTypes AND t.date BETWEEN :startDate AND :startEnd GROUP BY a")
|
||||||
|
Iterable<AccountExpense> getAccountExpenses(LocalDate startDate, LocalDate startEnd, AccountType... expenseTypes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package de.financer.service;
|
package de.financer.service;
|
||||||
|
|
||||||
import de.financer.ResponseReason;
|
import de.financer.ResponseReason;
|
||||||
|
import de.financer.config.FinancerConfig;
|
||||||
import de.financer.dba.AccountRepository;
|
import de.financer.dba.AccountRepository;
|
||||||
|
import de.financer.dto.AccountExpense;
|
||||||
import de.financer.model.Account;
|
import de.financer.model.Account;
|
||||||
import de.financer.model.AccountGroup;
|
import de.financer.model.AccountGroup;
|
||||||
import de.financer.model.AccountStatus;
|
import de.financer.model.AccountStatus;
|
||||||
@@ -15,8 +17,10 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.time.LocalDate;
|
||||||
import java.util.stream.Collectors;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class AccountService {
|
public class AccountService {
|
||||||
@@ -24,9 +28,13 @@ public class AccountService {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AccountRepository accountRepository;
|
private AccountRepository accountRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AccountGroupService accountGroupService;
|
private AccountGroupService accountGroupService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FinancerConfig financerConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the account identified by the given key.
|
* This method returns the account identified by the given key.
|
||||||
*
|
*
|
||||||
@@ -152,4 +160,22 @@ public class AccountService {
|
|||||||
public Long getCurrentAssets() {
|
public Long getCurrentAssets() {
|
||||||
return this.accountRepository.getCurrentAssets(AccountType.BANK, AccountType.CASH);
|
return this.accountRepository.getCurrentAssets(AccountType.BANK, AccountType.CASH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Iterable<AccountExpense> getAccountExpenses(String periodStart, String periodEnd) {
|
||||||
|
LocalDate startDate;
|
||||||
|
LocalDate endDate;
|
||||||
|
|
||||||
|
try {
|
||||||
|
startDate = LocalDate.parse(periodStart, DateTimeFormatter.ofPattern(this.financerConfig.getDateFormat()));
|
||||||
|
endDate = LocalDate.parse(periodEnd, DateTimeFormatter.ofPattern(this.financerConfig.getDateFormat()));
|
||||||
|
} catch (DateTimeParseException dtpe) {
|
||||||
|
LOGGER.error(String
|
||||||
|
.format("Could not parse periodStart (%s) or periodEnd (%s): %s", periodStart, periodEnd, dtpe
|
||||||
|
.getMessage()));
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.accountRepository.getAccountExpenses(startDate, endDate, AccountType.LIABILITY, AccountType.EXPENSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
public enum ChartType {
|
public enum ChartType {
|
||||||
ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD,
|
ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD,
|
||||||
ACCOUNT_GROUP_EXPENSES_FOR_PERIOD;
|
ACCOUNT_GROUP_EXPENSES_FOR_PERIOD,
|
||||||
|
ACCOUNT_EXPENSES_CURRENT_PERIOD,
|
||||||
|
ACCOUNT_EXPENSES_FOR_PERIOD;
|
||||||
|
|
||||||
public static List<String> valueList() {
|
public static List<String> valueList() {
|
||||||
return Arrays.stream(ChartType.values()).map(ChartType::name).collect(Collectors.toList());
|
return Arrays.stream(ChartType.values()).map(ChartType::name).collect(Collectors.toList());
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.financer.chart;
|
package de.financer.chart;
|
||||||
|
|
||||||
import de.financer.chart.impl.AccountGroupExpensesGenerator;
|
import de.financer.chart.impl.expense.AccountExpensesGenerator;
|
||||||
|
import de.financer.chart.impl.expense.AccountGroupExpensesGenerator;
|
||||||
import de.financer.config.FinancerConfig;
|
import de.financer.config.FinancerConfig;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
@@ -19,9 +20,17 @@ public class FinancerChartFactory {
|
|||||||
|
|
||||||
switch (chartType) {
|
switch (chartType) {
|
||||||
case ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD:
|
case ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD:
|
||||||
|
// Fall through
|
||||||
|
case ACCOUNT_GROUP_EXPENSES_FOR_PERIOD:
|
||||||
// TODO WHY IS THIS CAST NECESSARY???
|
// TODO WHY IS THIS CAST NECESSARY???
|
||||||
generator = (AbstractChartGenerator<P>) new AccountGroupExpensesGenerator();
|
generator = (AbstractChartGenerator<P>) new AccountGroupExpensesGenerator();
|
||||||
break;
|
break;
|
||||||
|
case ACCOUNT_EXPENSES_CURRENT_PERIOD:
|
||||||
|
// Fall through
|
||||||
|
case ACCOUNT_EXPENSES_FOR_PERIOD:
|
||||||
|
// TODO WHY IS THIS CAST NECESSARY???
|
||||||
|
generator = (AbstractChartGenerator<P>) new AccountExpensesGenerator();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
generator = null;
|
generator = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,24 @@
|
|||||||
package de.financer.chart.impl;
|
package de.financer.chart.impl.expense;
|
||||||
|
|
||||||
import de.financer.chart.AbstractChartGenerator;
|
import de.financer.chart.AbstractChartGenerator;
|
||||||
import de.financer.dto.AccountGroupExpense;
|
import de.financer.config.FinancerConfig;
|
||||||
import de.financer.template.GetAccountGroupExpensesTemplate;
|
|
||||||
import de.financer.util.ControllerUtils;
|
import de.financer.util.ControllerUtils;
|
||||||
import org.apache.commons.collections4.IterableUtils;
|
|
||||||
import org.jfree.chart.ChartFactory;
|
import org.jfree.chart.ChartFactory;
|
||||||
import org.jfree.chart.JFreeChart;
|
import org.jfree.chart.JFreeChart;
|
||||||
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
|
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
|
||||||
import org.jfree.chart.plot.PiePlot;
|
import org.jfree.chart.plot.PiePlot;
|
||||||
import org.jfree.data.general.DefaultPieDataset;
|
|
||||||
import org.jfree.data.general.PieDataset;
|
import org.jfree.data.general.PieDataset;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
|
||||||
public class AccountGroupExpensesGenerator extends AbstractChartGenerator<AccountGroupExpensesParameter> {
|
public abstract class AbstractExpensesGenerator extends AbstractChartGenerator<ExpensesParameter> {
|
||||||
@Override
|
@Override
|
||||||
public JFreeChart generateChart(AccountGroupExpensesParameter parameter) {
|
public JFreeChart generateChart(ExpensesParameter parameter) {
|
||||||
final String start = ControllerUtils.formatDate(this.getFinancerConfig(), parameter.getPeriodStart());
|
final String start = ControllerUtils.formatDate(this.getFinancerConfig(), parameter.getPeriodStart());
|
||||||
final String end = ControllerUtils.formatDate(this.getFinancerConfig(), parameter.getPeriodEnd());
|
final String end = ControllerUtils.formatDate(this.getFinancerConfig(), parameter.getPeriodEnd());
|
||||||
|
|
||||||
final Iterable<AccountGroupExpense> expenses = new GetAccountGroupExpensesTemplate()
|
final PieDataset dataSet = getDataset(start, end, this.getFinancerConfig());
|
||||||
.exchange(this.getFinancerConfig(), start, end).getBody();
|
|
||||||
|
|
||||||
final PieDataset dataSet = createDataSet(expenses);
|
|
||||||
|
|
||||||
final JFreeChart chart = ChartFactory
|
final JFreeChart chart = ChartFactory
|
||||||
.createPieChart(this.getMessage(parameter.getTitle(), parameter.getArgsForTitle()), dataSet);
|
.createPieChart(this.getMessage(parameter.getTitle(), parameter.getArgsForTitle()), dataSet);
|
||||||
@@ -40,12 +34,19 @@ public class AccountGroupExpensesGenerator extends AbstractChartGenerator<Accoun
|
|||||||
return chart;
|
return chart;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PieDataset createDataSet(Iterable<AccountGroupExpense> data) {
|
/**
|
||||||
final DefaultPieDataset dataSet = new DefaultPieDataset();
|
* This method obtains the chart data via a REST call from the backend server application and transforms them into
|
||||||
|
* a compatible dataset.
|
||||||
IterableUtils.toList(data).stream()
|
*
|
||||||
.forEach((ex) -> dataSet.setValue(ex.getAccountGroup().getName(), (ex.getExpense() / 100D)));
|
* TODO Getting the data here seems kinda wrong as the data access is usually done in the controllers. However,
|
||||||
|
* TODO this would require to pass the data from the calling controller via the ExpensesParameter. To do this
|
||||||
return dataSet;
|
* TODO the parameter class either needs to be extended into two subclasses that each declare the corresponding data
|
||||||
}
|
* TODO field or the data has to be generified.
|
||||||
|
*
|
||||||
|
* @param start - the start of the period
|
||||||
|
* @param end - the end of the period
|
||||||
|
* @param financerConfig - the financer config that holds the REST endpoint config
|
||||||
|
* @return the created dataset
|
||||||
|
*/
|
||||||
|
protected abstract PieDataset getDataset(String start, String end, FinancerConfig financerConfig);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package de.financer.chart.impl.expense;
|
||||||
|
|
||||||
|
import de.financer.config.FinancerConfig;
|
||||||
|
import de.financer.dto.AccountExpense;
|
||||||
|
import de.financer.dto.AccountGroupExpense;
|
||||||
|
import de.financer.template.GetAccountExpensesTemplate;
|
||||||
|
import de.financer.template.GetAccountGroupExpensesTemplate;
|
||||||
|
import org.apache.commons.collections4.IterableUtils;
|
||||||
|
import org.jfree.data.general.DefaultPieDataset;
|
||||||
|
import org.jfree.data.general.PieDataset;
|
||||||
|
|
||||||
|
public class AccountExpensesGenerator extends AbstractExpensesGenerator {
|
||||||
|
@Override
|
||||||
|
protected PieDataset getDataset(String start, String end, FinancerConfig financerConfig) {
|
||||||
|
final Iterable<AccountExpense> expenses = new GetAccountExpensesTemplate()
|
||||||
|
.exchange(financerConfig, start, end).getBody();
|
||||||
|
|
||||||
|
final DefaultPieDataset dataSet = new DefaultPieDataset();
|
||||||
|
|
||||||
|
IterableUtils.toList(expenses).stream()
|
||||||
|
.forEach((ex) -> dataSet.setValue(ex.getAccount().getKey(), (ex.getExpense() / 100D)));
|
||||||
|
|
||||||
|
return dataSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package de.financer.chart.impl.expense;
|
||||||
|
|
||||||
|
import de.financer.config.FinancerConfig;
|
||||||
|
import de.financer.dto.AccountGroupExpense;
|
||||||
|
import de.financer.template.GetAccountGroupExpensesTemplate;
|
||||||
|
import org.apache.commons.collections4.IterableUtils;
|
||||||
|
import org.jfree.data.general.DefaultPieDataset;
|
||||||
|
import org.jfree.data.general.PieDataset;
|
||||||
|
|
||||||
|
public class AccountGroupExpensesGenerator extends AbstractExpensesGenerator {
|
||||||
|
@Override
|
||||||
|
protected PieDataset getDataset(String start, String end, FinancerConfig financerConfig) {
|
||||||
|
final Iterable<AccountGroupExpense> expenses = new GetAccountGroupExpensesTemplate()
|
||||||
|
.exchange(financerConfig, start, end).getBody();
|
||||||
|
|
||||||
|
final DefaultPieDataset dataSet = new DefaultPieDataset();
|
||||||
|
|
||||||
|
IterableUtils.toList(expenses).stream()
|
||||||
|
.forEach((ex) -> dataSet.setValue(ex.getAccountGroup().getName(), (ex.getExpense() / 100D)));
|
||||||
|
|
||||||
|
return dataSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package de.financer.chart.impl;
|
package de.financer.chart.impl.expense;
|
||||||
|
|
||||||
import de.financer.chart.ChartParameter;
|
import de.financer.chart.ChartParameter;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
public class AccountGroupExpensesParameter implements ChartParameter {
|
public class ExpensesParameter implements ChartParameter {
|
||||||
private LocalDate periodStart;
|
private LocalDate periodStart;
|
||||||
private LocalDate periodEnd;
|
private LocalDate periodEnd;
|
||||||
private String title;
|
private String title;
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package de.financer.controller;
|
package de.financer.controller;
|
||||||
|
|
||||||
import de.financer.chart.impl.AccountGroupExpensesParameter;
|
import de.financer.chart.impl.expense.ExpensesParameter;
|
||||||
import de.financer.chart.ChartGenerator;
|
import de.financer.chart.ChartGenerator;
|
||||||
import de.financer.chart.ChartType;
|
import de.financer.chart.ChartType;
|
||||||
import de.financer.chart.FinancerChartFactory;
|
import de.financer.chart.FinancerChartFactory;
|
||||||
import de.financer.config.FinancerConfig;
|
import de.financer.config.FinancerConfig;
|
||||||
|
import de.financer.form.ConfigAccountExpenseForPeriodForm;
|
||||||
import de.financer.form.ConfigAccountGroupExpenseForPeriodForm;
|
import de.financer.form.ConfigAccountGroupExpenseForPeriodForm;
|
||||||
import de.financer.util.ControllerUtils;
|
import de.financer.util.ControllerUtils;
|
||||||
import de.financer.util.ExpensePeriod;
|
import de.financer.util.ExpensePeriod;
|
||||||
@@ -31,13 +32,13 @@ public class ChartController {
|
|||||||
public void getAccountGroupExpensesCurrentPeriod(HttpServletResponse response) {
|
public void getAccountGroupExpensesCurrentPeriod(HttpServletResponse response) {
|
||||||
final ExpensePeriod period = ExpensePeriod
|
final ExpensePeriod period = ExpensePeriod
|
||||||
.getCurrentExpensePeriod(this.financerConfig.getMonthPeriodStartDay());
|
.getCurrentExpensePeriod(this.financerConfig.getMonthPeriodStartDay());
|
||||||
final AccountGroupExpensesParameter parameter = new AccountGroupExpensesParameter();
|
final ExpensesParameter parameter = new ExpensesParameter();
|
||||||
|
|
||||||
parameter.setPeriodStart(period.getStart());
|
parameter.setPeriodStart(period.getStart());
|
||||||
parameter.setPeriodEnd(period.getEnd());
|
parameter.setPeriodEnd(period.getEnd());
|
||||||
parameter.setTitle("financer.chart.account-group-expenses-current-period.title");
|
parameter.setTitle("financer.chart.account-group-expenses-current-period.title");
|
||||||
|
|
||||||
final ChartGenerator<AccountGroupExpensesParameter> generator =
|
final ChartGenerator<ExpensesParameter> generator =
|
||||||
this.financerChartFactory.getGenerator(ChartType.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD);
|
this.financerChartFactory.getGenerator(ChartType.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD);
|
||||||
|
|
||||||
final JFreeChart chart = generator.generateChart(parameter);
|
final JFreeChart chart = generator.generateChart(parameter);
|
||||||
@@ -47,7 +48,7 @@ public class ChartController {
|
|||||||
|
|
||||||
@PostMapping("/getAccountGroupExpensesForPeriod")
|
@PostMapping("/getAccountGroupExpensesForPeriod")
|
||||||
public void getAccountGroupExpensesForPeriod(HttpServletResponse response, ConfigAccountGroupExpenseForPeriodForm form) {
|
public void getAccountGroupExpensesForPeriod(HttpServletResponse response, ConfigAccountGroupExpenseForPeriodForm form) {
|
||||||
final AccountGroupExpensesParameter parameter = new AccountGroupExpensesParameter();
|
final ExpensesParameter parameter = new ExpensesParameter();
|
||||||
|
|
||||||
parameter.setPeriodStart(ControllerUtils.parseDate(this.financerConfig, form.getFromDate()));
|
parameter.setPeriodStart(ControllerUtils.parseDate(this.financerConfig, form.getFromDate()));
|
||||||
parameter.setPeriodEnd(ControllerUtils.parseDate(this.financerConfig, form.getToDate()));
|
parameter.setPeriodEnd(ControllerUtils.parseDate(this.financerConfig, form.getToDate()));
|
||||||
@@ -57,8 +58,46 @@ public class ChartController {
|
|||||||
.getLocale()), ControllerUtils.formatDate(this.financerConfig, form.getToDate(), LocaleContextHolder
|
.getLocale()), ControllerUtils.formatDate(this.financerConfig, form.getToDate(), LocaleContextHolder
|
||||||
.getLocale())});
|
.getLocale())});
|
||||||
|
|
||||||
final ChartGenerator<AccountGroupExpensesParameter> generator =
|
final ChartGenerator<ExpensesParameter> generator =
|
||||||
this.financerChartFactory.getGenerator(ChartType.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD);
|
this.financerChartFactory.getGenerator(ChartType.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD);
|
||||||
|
|
||||||
|
final JFreeChart chart = generator.generateChart(parameter);
|
||||||
|
|
||||||
|
writeChart(response, chart);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getAccountExpensesCurrentPeriod")
|
||||||
|
public void getAccountExpensesCurrentPeriod(HttpServletResponse response) {
|
||||||
|
final ExpensePeriod period = ExpensePeriod
|
||||||
|
.getCurrentExpensePeriod(this.financerConfig.getMonthPeriodStartDay());
|
||||||
|
final ExpensesParameter parameter = new ExpensesParameter();
|
||||||
|
|
||||||
|
parameter.setPeriodStart(period.getStart());
|
||||||
|
parameter.setPeriodEnd(period.getEnd());
|
||||||
|
parameter.setTitle("financer.chart.account-expenses-current-period.title");
|
||||||
|
|
||||||
|
final ChartGenerator<ExpensesParameter> generator =
|
||||||
|
this.financerChartFactory.getGenerator(ChartType.ACCOUNT_EXPENSES_CURRENT_PERIOD);
|
||||||
|
|
||||||
|
final JFreeChart chart = generator.generateChart(parameter);
|
||||||
|
|
||||||
|
writeChart(response, chart);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/getAccountExpensesForPeriod")
|
||||||
|
public void getAccountExpensesForPeriod(HttpServletResponse response, ConfigAccountExpenseForPeriodForm form) {
|
||||||
|
final ExpensesParameter parameter = new ExpensesParameter();
|
||||||
|
|
||||||
|
parameter.setPeriodStart(ControllerUtils.parseDate(this.financerConfig, form.getFromDate()));
|
||||||
|
parameter.setPeriodEnd(ControllerUtils.parseDate(this.financerConfig, form.getToDate()));
|
||||||
|
parameter.setTitle("financer.chart.account-expenses-for-period.title");
|
||||||
|
parameter.setArgsForTitle(new Object[]{ControllerUtils.formatDate(this.financerConfig, form
|
||||||
|
.getFromDate(), LocaleContextHolder
|
||||||
|
.getLocale()), ControllerUtils.formatDate(this.financerConfig, form.getToDate(), LocaleContextHolder
|
||||||
|
.getLocale())});
|
||||||
|
|
||||||
|
final ChartGenerator<ExpensesParameter> generator =
|
||||||
|
this.financerChartFactory.getGenerator(ChartType.ACCOUNT_EXPENSES_FOR_PERIOD);
|
||||||
|
|
||||||
final JFreeChart chart = generator.generateChart(parameter);
|
final JFreeChart chart = generator.generateChart(parameter);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ public enum Function {
|
|||||||
ACC_CLOSE_ACCOUNT("accounts/closeAccount"),
|
ACC_CLOSE_ACCOUNT("accounts/closeAccount"),
|
||||||
ACC_OPEN_ACCOUNT("accounts/openAccount"),
|
ACC_OPEN_ACCOUNT("accounts/openAccount"),
|
||||||
ACC_CURRENT_ASSETS("accounts/getCurrentAssets"),
|
ACC_CURRENT_ASSETS("accounts/getCurrentAssets"),
|
||||||
|
ACC_GET_ACC_EXPENSES("accounts/getAccountExpenses"),
|
||||||
|
|
||||||
ACC_GP_CREATE_ACCOUNT_GROUP("accountGroups/createAccountGroup"),
|
ACC_GP_CREATE_ACCOUNT_GROUP("accountGroups/createAccountGroup"),
|
||||||
ACC_GP_GET_ALL("accountGroups/getAll"),
|
ACC_GP_GET_ALL("accountGroups/getAll"),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package de.financer.controller;
|
|||||||
|
|
||||||
import de.financer.chart.ChartType;
|
import de.financer.chart.ChartType;
|
||||||
import de.financer.config.FinancerConfig;
|
import de.financer.config.FinancerConfig;
|
||||||
|
import de.financer.form.ConfigAccountExpenseForPeriodForm;
|
||||||
import de.financer.form.ConfigAccountGroupExpenseForPeriodForm;
|
import de.financer.form.ConfigAccountGroupExpenseForPeriodForm;
|
||||||
import de.financer.form.SelectChartForm;
|
import de.financer.form.SelectChartForm;
|
||||||
import de.financer.util.ControllerUtils;
|
import de.financer.util.ControllerUtils;
|
||||||
@@ -56,6 +57,16 @@ public class ReportController {
|
|||||||
ControllerUtils.addCurrencySymbol(model, this.financerConfig);
|
ControllerUtils.addCurrencySymbol(model, this.financerConfig);
|
||||||
|
|
||||||
return "report/configureAccountGroupExpensesForPeriod";
|
return "report/configureAccountGroupExpensesForPeriod";
|
||||||
|
case ACCOUNT_EXPENSES_CURRENT_PERIOD:
|
||||||
|
// Special case: this chart does not require parameters, so we can
|
||||||
|
// directly redirect to the actual chart instead of the config page
|
||||||
|
return "redirect:/getAccountExpensesCurrentPeriod";
|
||||||
|
case ACCOUNT_EXPENSES_FOR_PERIOD:
|
||||||
|
model.addAttribute("form", new ConfigAccountExpenseForPeriodForm());
|
||||||
|
ControllerUtils.addVersionAttribute(model, this.financerConfig);
|
||||||
|
ControllerUtils.addCurrencySymbol(model, this.financerConfig);
|
||||||
|
|
||||||
|
return "report/configureAccountExpensesForPeriod";
|
||||||
default:
|
default:
|
||||||
// Cannot happen
|
// Cannot happen
|
||||||
throw new IllegalStateException("Unexpected value: " + selectedChartType);
|
throw new IllegalStateException("Unexpected value: " + selectedChartType);
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package de.financer.form;
|
||||||
|
|
||||||
|
public class ConfigAccountExpenseForPeriodForm {
|
||||||
|
private String fromDate;
|
||||||
|
private String toDate;
|
||||||
|
|
||||||
|
public String getFromDate() {
|
||||||
|
return fromDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromDate(String fromDate) {
|
||||||
|
this.fromDate = fromDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToDate() {
|
||||||
|
return toDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToDate(String toDate) {
|
||||||
|
this.toDate = toDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package de.financer.template;
|
||||||
|
|
||||||
|
import de.financer.config.FinancerConfig;
|
||||||
|
import de.financer.controller.Function;
|
||||||
|
import de.financer.dto.AccountExpense;
|
||||||
|
import de.financer.dto.AccountGroupExpense;
|
||||||
|
import de.financer.util.ControllerUtils;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
public class GetAccountExpensesTemplate {
|
||||||
|
public ResponseEntity<Iterable<AccountExpense>> exchange(FinancerConfig financerConfig, String start, String end) {
|
||||||
|
final UriComponentsBuilder expensesBuilder = UriComponentsBuilder
|
||||||
|
.fromHttpUrl(ControllerUtils.buildUrl(financerConfig, Function.ACC_GET_ACC_EXPENSES))
|
||||||
|
.queryParam("periodStart", start)
|
||||||
|
.queryParam("periodEnd", end);
|
||||||
|
|
||||||
|
return new FinancerRestTemplate<Iterable<AccountExpense>>()
|
||||||
|
.exchange(expensesBuilder.toUriString(), new ParameterizedTypeReference<Iterable<AccountExpense>>() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -115,6 +115,11 @@ financer.chart-config-account-group-expenses-for-period.label.from-date=From dat
|
|||||||
financer.chart-config-account-group-expenses-for-period.label.to-date=To date\:
|
financer.chart-config-account-group-expenses-for-period.label.to-date=To date\:
|
||||||
financer.chart-config-account-group-expenses-for-period.submit=Generate
|
financer.chart-config-account-group-expenses-for-period.submit=Generate
|
||||||
|
|
||||||
|
financer.chart-config-account-expenses-for-period.title=Configure account expenses for period chart
|
||||||
|
financer.chart-config-account-expenses-for-period.label.from-date=From date\:
|
||||||
|
financer.chart-config-account-expenses-for-period.label.to-date=To date\:
|
||||||
|
financer.chart-config-account-expenses-for-period.submit=Generate
|
||||||
|
|
||||||
financer.interval-type.DAILY=Daily
|
financer.interval-type.DAILY=Daily
|
||||||
financer.interval-type.WEEKLY=Weekly
|
financer.interval-type.WEEKLY=Weekly
|
||||||
financer.interval-type.MONTHLY=Monthly
|
financer.interval-type.MONTHLY=Monthly
|
||||||
@@ -147,14 +152,19 @@ financer.heading.recurring-transaction-list.all=financer\: all recurring transac
|
|||||||
financer.heading.recurring-to-transaction-with-amount=financer\: create transaction from recurring with amount
|
financer.heading.recurring-to-transaction-with-amount=financer\: create transaction from recurring with amount
|
||||||
financer.heading.chart-select=financer\: select a chart to generate
|
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-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.cancel-back-to-overview=Cancel and back to overview
|
financer.cancel-back-to-overview=Cancel and 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-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
|
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.name.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD=Expenses of the current period grouped by account group
|
financer.chart.name.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD=Expenses of the current period grouped by account group
|
||||||
financer.chart.name.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD=Expenses for a configurable period grouped by account group
|
financer.chart.name.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD=Expenses for a configurable period grouped by account group
|
||||||
|
financer.chart.name.ACCOUNT_EXPENSES_CURRENT_PERIOD=Expenses of the current period grouped by account
|
||||||
|
financer.chart.name.ACCOUNT_EXPENSES_FOR_PERIOD=Expenses for a configurable period grouped by account
|
||||||
|
|
||||||
financer.error-message.UNKNOWN_ERROR=An unknown error occurred!
|
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.INVALID_ACCOUNT_TYPE=The selected account type is not valid!
|
||||||
|
|||||||
@@ -115,6 +115,11 @@ financer.chart-config-account-group-expenses-for-period.label.from-date=Von Datu
|
|||||||
financer.chart-config-account-group-expenses-for-period.label.to-date=Bis Datum\:
|
financer.chart-config-account-group-expenses-for-period.label.to-date=Bis Datum\:
|
||||||
financer.chart-config-account-group-expenses-for-period.submit=Erzeugen
|
financer.chart-config-account-group-expenses-for-period.submit=Erzeugen
|
||||||
|
|
||||||
|
financer.chart-config-account-expenses-for-period.title=Konfigurieren von Ausgaben f\u00FCr Periode gruppiert nach Konto Diagramm
|
||||||
|
financer.chart-config-account-expenses-for-period.label.from-date=Von Datum\:
|
||||||
|
financer.chart-config-account-expenses-for-period.label.to-date=Bis Datum\:
|
||||||
|
financer.chart-config-account-expenses-for-period.submit=Erzeugen
|
||||||
|
|
||||||
financer.interval-type.DAILY=T\u00E4glich
|
financer.interval-type.DAILY=T\u00E4glich
|
||||||
financer.interval-type.WEEKLY=W\u00F6chentlich
|
financer.interval-type.WEEKLY=W\u00F6chentlich
|
||||||
financer.interval-type.MONTHLY=Monatlich
|
financer.interval-type.MONTHLY=Monatlich
|
||||||
@@ -152,6 +157,10 @@ financer.cancel-back-to-overview=Abbrechen und zur \u00DCbersicht
|
|||||||
|
|
||||||
financer.chart.account-group-expenses-current-period.title=Ausgaben in der aktuellen Periode gruppiert nach Konto-Gruppe
|
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
|
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.name.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD=Ausgaben in der aktuellen Periode gruppiert nach Konto-Gruppe
|
financer.chart.name.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD=Ausgaben in der aktuellen Periode gruppiert nach Konto-Gruppe
|
||||||
financer.chart.name.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD=Ausgaben f\u00FCr eine konfigurierbare Periode gruppiert nach Konto-Gruppe
|
financer.chart.name.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD=Ausgaben f\u00FCr eine konfigurierbare Periode gruppiert nach Konto-Gruppe
|
||||||
|
financer.chart.name.ACCOUNT_EXPENSES_CURRENT_PERIOD=Ausgaben in der aktuellen Periode gruppiert nach Konto
|
||||||
|
financer.chart.name.ACCOUNT_EXPENSES_FOR_PERIOD=Ausgaben f\u00FCr eine konfigurierbare Periode gruppiert nach Konto
|
||||||
@@ -2,3 +2,4 @@ v16 -> v17:
|
|||||||
- Add this changelog to the footer
|
- Add this changelog to the footer
|
||||||
- Locale of the recurring transaction reminder email is now configurable
|
- Locale of the recurring transaction reminder email is now configurable
|
||||||
- Recurring transaction indicator in transaction overview (account details) is now properly translated
|
- 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
|
||||||
@@ -68,7 +68,8 @@ tr:hover {
|
|||||||
#new-recurring-transaction-form *,
|
#new-recurring-transaction-form *,
|
||||||
#recurring-to-transaction-with-amount-form *,
|
#recurring-to-transaction-with-amount-form *,
|
||||||
#new-account-group-form *,
|
#new-account-group-form *,
|
||||||
#chart-config-account-group-expenses-for-period-form * {
|
#chart-config-account-group-expenses-for-period-form *,
|
||||||
|
#chart-config-account-expenses-for-period-form * {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
width: 20em;
|
width: 20em;
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<title th:text="#{financer.chart-config-account-expenses-for-period.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}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 th:text="#{financer.heading.chart-config-account-expenses-for-period}"/>
|
||||||
|
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
|
||||||
|
<a th:href="@{/accountOverview}" th:text="#{financer.cancel-back-to-overview}"/>
|
||||||
|
<form id="chart-config-account-expenses-for-period-form" action="#"
|
||||||
|
th:action="@{/getAccountExpensesForPeriod}" th:object="${form}" method="post">
|
||||||
|
<label for="fromDate" th:text="#{financer.chart-config-account-expenses-for-period.label.from-date}"/>
|
||||||
|
<input type="date" id="fromDate" th:field="*{fromDate}"/>
|
||||||
|
<label for="toDate" th:text="#{financer.chart-config-account-expenses-for-period.label.to-date}"/>
|
||||||
|
<input type="date" id="toDate" th:field="*{toDate}"/>
|
||||||
|
<input type="submit" th:value="#{financer.chart-config-account-expenses-for-period.submit}"/>
|
||||||
|
</form>
|
||||||
|
<div th:replace="includes/footer :: footer" />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user