Add charts (based on JFreeChart)

Currently only an expense report is supported, but more will come.
Also moved rest templates into own toplevel package.
This commit is contained in:
2019-06-30 03:03:36 +02:00
parent 53e46a418c
commit 477d3c203a
29 changed files with 229 additions and 32 deletions

View File

@@ -0,0 +1,40 @@
package de.financer.chart;
import de.financer.config.FinancerConfig;
import de.financer.dto.AccountGroupExpense;
import de.financer.template.GetAccountGroupExpensesTemplate;
import de.financer.util.ControllerUtils;
import org.apache.commons.collections4.IterableUtils;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import java.time.LocalDate;
public class AccountGroupExpensesChartGenerator {
public JFreeChart generateChart(FinancerConfig financerConfig, LocalDate periodStart, LocalDate periodEnd, MessageSource messageSource) {
final String start = ControllerUtils.formatDate(financerConfig, periodStart);
final String end = ControllerUtils.formatDate(financerConfig, periodEnd);
final Iterable<AccountGroupExpense> expenses = new GetAccountGroupExpensesTemplate()
.exchange(financerConfig, start, end).getBody();
final PieDataset dataSet = createDataSet(expenses);
return ChartFactory.createPieChart(messageSource
.getMessage("financer.chart.account-group-expenses-current-period.title", null, LocaleContextHolder
.getLocale()), dataSet);
}
private PieDataset createDataSet(Iterable<AccountGroupExpense> data) {
final DefaultPieDataset dataSet = new DefaultPieDataset();
IterableUtils.toList(data).stream()
.forEach((ex) -> dataSet.setValue(ex.getAccountGroup().getName(), ex.getExpense()));
return dataSet;
}
}

View File

@@ -2,7 +2,7 @@ package de.financer.controller;
import de.financer.ResponseReason;
import de.financer.config.FinancerConfig;
import de.financer.controller.template.*;
import de.financer.template.*;
import de.financer.form.NewAccountForm;
import de.financer.model.*;
import de.financer.util.ControllerUtils;
@@ -19,7 +19,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.util.UriComponentsBuilder;
import java.time.LocalDate;
import java.util.List;
@Controller

View File

@@ -2,7 +2,7 @@ package de.financer.controller;
import de.financer.ResponseReason;
import de.financer.config.FinancerConfig;
import de.financer.controller.template.StringTemplate;
import de.financer.template.StringTemplate;
import de.financer.form.NewAccountGroupForm;
import de.financer.util.ControllerUtils;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -0,0 +1,40 @@
package de.financer.controller;
import de.financer.chart.AccountGroupExpensesChartGenerator;
import de.financer.config.FinancerConfig;
import de.financer.util.ExpensePeriod;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class ChartController {
@Autowired
private FinancerConfig financerConfig;
@Autowired
private MessageSource messageSource;
@GetMapping("/getAccountGroupExpensesCurrentPeriod")
public void getAccountGroupExpensesCurrentPeriod(HttpServletResponse response) {
final ExpensePeriod period = ExpensePeriod
.getCurrentExpensePeriod(this.financerConfig.getMonthPeriodStartDay());
JFreeChart chart = new AccountGroupExpensesChartGenerator()
.generateChart(this.financerConfig, period.getStart(), period.getEnd(), this.messageSource);
response.setContentType("image/png");
try {
ChartUtils.writeChartAsPNG(response.getOutputStream(), chart, 1024, 768);
} catch (IOException ioe) {
// TODO
}
}
}

View File

@@ -10,6 +10,7 @@ public enum Function {
ACC_GP_CREATE_ACCOUNT_GROUP("accountGroups/createAccountGroup"),
ACC_GP_GET_ALL("accountGroups/getAll"),
ACC_GP_GET_ACC_GP_EXPENSES("accountGroups/getAccountGroupExpenses"),
TR_GET_ALL("transactions/getAll"),
TR_GET_ALL_FOR_ACCOUNT("transactions/getAllForAccount"),

View File

@@ -2,7 +2,7 @@ package de.financer.controller;
import de.financer.ResponseReason;
import de.financer.config.FinancerConfig;
import de.financer.controller.template.*;
import de.financer.template.*;
import de.financer.form.NewRecurringTransactionForm;
import de.financer.form.RecurringToTransactionWithAmountForm;
import de.financer.model.Account;

View File

@@ -2,10 +2,10 @@ package de.financer.controller;
import de.financer.ResponseReason;
import de.financer.config.FinancerConfig;
import de.financer.controller.template.GetAccountByKeyTemplate;
import de.financer.controller.template.GetAllAccountsTemplate;
import de.financer.controller.template.GetAllTransactionsForAccountTemplate;
import de.financer.controller.template.StringTemplate;
import de.financer.template.GetAccountByKeyTemplate;
import de.financer.template.GetAllAccountsTemplate;
import de.financer.template.GetAllTransactionsForAccountTemplate;
import de.financer.template.StringTemplate;
import de.financer.form.NewTransactionForm;
import de.financer.model.Account;
import de.financer.model.AccountStatus;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;

View File

@@ -0,0 +1,24 @@
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;
import de.financer.dto.AccountGroupExpense;
import de.financer.model.Account;
import de.financer.model.Transaction;
import de.financer.util.ControllerUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.ResponseEntity;
import org.springframework.web.util.UriComponentsBuilder;
public class GetAccountGroupExpensesTemplate {
public ResponseEntity<Iterable<AccountGroupExpense>> exchange(FinancerConfig financerConfig, String start, String end) {
final UriComponentsBuilder expensesBuilder = UriComponentsBuilder
.fromHttpUrl(ControllerUtils.buildUrl(financerConfig, Function.ACC_GP_GET_ACC_GP_EXPENSES))
.queryParam("periodStart", start)
.queryParam("periodEnd", end);
return new FinancerRestTemplate<Iterable<AccountGroupExpense>>()
.exchange(expensesBuilder.toUriString(), new ParameterizedTypeReference<Iterable<AccountGroupExpense>>() {
});
}
}

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;

View File

@@ -1,8 +1,7 @@
package de.financer.controller.template;
package de.financer.template;
import de.financer.config.FinancerConfig;
import de.financer.controller.Function;
import de.financer.model.Transaction;
import de.financer.util.ControllerUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.ResponseEntity;

View File

@@ -1,4 +1,4 @@
package de.financer.controller.template;
package de.financer.template;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.ResponseEntity;

View File

@@ -136,6 +136,8 @@ financer.heading.recurring-to-transaction-with-amount=financer\: create transact
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.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!

View File

@@ -134,4 +134,6 @@ financer.heading.recurring-transaction-list.active=financer\: aktive wiederkehre
financer.heading.recurring-transaction-list.all=financer\: alle wiederkehrende Buchungen
financer.heading.recurring-to-transaction-with-amount=financer\: Buchung mit Betrag aus wiederkehrender Buchung erstellen
financer.cancel-back-to-overview=Abbrechen und zur \u00DCbersicht
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

View File

@@ -16,7 +16,9 @@
</div>
<div th:title="#{'financer.account-overview.tooltip.status.current-expenses'(${#temporals.format(periodStart)}, ${#temporals.format(periodEnd)})}">
<span th:text="#{financer.account-overview.status.current-expenses}"/>
<span th:text="${#numbers.formatDecimal(currentExpenses/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
<a th:href="@{/getAccountGroupExpensesCurrentPeriod}">
<span th:text="${#numbers.formatDecimal(currentExpenses/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}" />
</a>
</div>
<div>
<span th:text="#{financer.account-overview.status.recurring-transaction-due-today}"/>