Add expense period total chart
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user