#29 Projected cash flow
This commit is contained in:
@@ -169,18 +169,15 @@ public class ReportController {
|
|||||||
|
|
||||||
ConfigProjectedCashFlowForPeriodTransactionsForm formTransactions =
|
ConfigProjectedCashFlowForPeriodTransactionsForm formTransactions =
|
||||||
new ConfigProjectedCashFlowForPeriodTransactionsForm(incomeTransactions, expenseTransactions,
|
new ConfigProjectedCashFlowForPeriodTransactionsForm(incomeTransactions, expenseTransactions,
|
||||||
form.isByAccount(), ControllerUtils.parseDate(this.financerConfig, form.getFromDate()),
|
ControllerUtils.parseDate(this.financerConfig, form.getFromDate()),
|
||||||
ControllerUtils.parseDate(this.financerConfig, form.getToDate()));
|
ControllerUtils.parseDate(this.financerConfig, form.getToDate()));
|
||||||
|
|
||||||
if(form.isByAccount()) {
|
final ResponseEntity<Iterable<Account>> response = new GetAllAccountsTemplate().exchange(this.financerConfig);
|
||||||
final ResponseEntity<Iterable<Account>> response = new GetAllAccountsTemplate().exchange(this.financerConfig);
|
|
||||||
|
|
||||||
decorateAccounts(ControllerUtils.filterAndSortAccounts(response.getBody(), false, LIABILITY, EXPENSE))
|
decorateAccounts(ControllerUtils.filterAndSortAccounts(response.getBody(), false, LIABILITY, EXPENSE))
|
||||||
.forEach(formTransactions::addAccountContainer);
|
.stream().filter(ad -> ad.getAccountGroup() != null)
|
||||||
}
|
.collect(Collectors.groupingBy(ad -> ad.getAccountGroup().getName()))
|
||||||
else {
|
.forEach(formTransactions::addAccountGroupAccountList);
|
||||||
// TODO by account group
|
|
||||||
}
|
|
||||||
|
|
||||||
formTransactions.refresh();
|
formTransactions.refresh();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package de.financer.form;
|
|||||||
public class ConfigProjectedCashFlowForPeriodForm {
|
public class ConfigProjectedCashFlowForPeriodForm {
|
||||||
private String fromDate;
|
private String fromDate;
|
||||||
private String toDate;
|
private String toDate;
|
||||||
private boolean byAccount;
|
|
||||||
|
|
||||||
public String getFromDate() {
|
public String getFromDate() {
|
||||||
return fromDate;
|
return fromDate;
|
||||||
@@ -20,12 +19,4 @@ public class ConfigProjectedCashFlowForPeriodForm {
|
|||||||
public void setToDate(String toDate) {
|
public void setToDate(String toDate) {
|
||||||
this.toDate = toDate;
|
this.toDate = toDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isByAccount() {
|
|
||||||
return byAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setByAccount(boolean byAccount) {
|
|
||||||
this.byAccount = byAccount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,40 @@ import de.financer.model.Account;
|
|||||||
import de.financer.model.RecurringTransaction;
|
import de.financer.model.RecurringTransaction;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
import java.util.stream.Collectors;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ConfigProjectedCashFlowForPeriodTransactionsForm {
|
public class ConfigProjectedCashFlowForPeriodTransactionsForm {
|
||||||
|
public static class AccountGroupAccountContainer {
|
||||||
|
private String accountGroup;
|
||||||
|
private List<AccountContainer> accounts;
|
||||||
|
|
||||||
|
public AccountGroupAccountContainer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountGroupAccountContainer(String accountGroup, List<AccountContainer> accounts) {
|
||||||
|
this.accountGroup = accountGroup;
|
||||||
|
this.accounts = accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccountGroup() {
|
||||||
|
return accountGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountGroup(String accountGroup) {
|
||||||
|
this.accountGroup = accountGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AccountContainer> getAccounts() {
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccounts(List<AccountContainer> accounts) {
|
||||||
|
this.accounts = accounts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class AccountContainer {
|
public static class AccountContainer {
|
||||||
private Account account;
|
private Account account;
|
||||||
private long spending;
|
private long spending;
|
||||||
@@ -25,7 +53,7 @@ public class ConfigProjectedCashFlowForPeriodTransactionsForm {
|
|||||||
this.spending = spending;
|
this.spending = spending;
|
||||||
this.averageSpending = averageSpending;
|
this.averageSpending = averageSpending;
|
||||||
|
|
||||||
if(this.spending == 0 && this.averageSpending != 0) {
|
if (this.spending == 0 && this.averageSpending != 0) {
|
||||||
this.spending = this.averageSpending;
|
this.spending = this.averageSpending;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,11 +85,10 @@ public class ConfigProjectedCashFlowForPeriodTransactionsForm {
|
|||||||
|
|
||||||
private List<RecurringTransaction> incomeTransactions;
|
private List<RecurringTransaction> incomeTransactions;
|
||||||
private List<RecurringTransaction> expenseTransactions;
|
private List<RecurringTransaction> expenseTransactions;
|
||||||
private List<AccountContainer> accountContainers;
|
private List<AccountGroupAccountContainer> accountGroupAccountContainers;
|
||||||
private long incomeSum;
|
private long incomeSum;
|
||||||
private long expenseSum;
|
private long expenseSum;
|
||||||
private long cashFlow;
|
private long cashFlow;
|
||||||
private boolean byAccount;
|
|
||||||
private long accountSum;
|
private long accountSum;
|
||||||
private LocalDate fromDate;
|
private LocalDate fromDate;
|
||||||
private LocalDate toDate;
|
private LocalDate toDate;
|
||||||
@@ -69,17 +96,16 @@ public class ConfigProjectedCashFlowForPeriodTransactionsForm {
|
|||||||
public ConfigProjectedCashFlowForPeriodTransactionsForm() {
|
public ConfigProjectedCashFlowForPeriodTransactionsForm() {
|
||||||
this.incomeTransactions = new ArrayList<>();
|
this.incomeTransactions = new ArrayList<>();
|
||||||
this.expenseTransactions = new ArrayList<>();
|
this.expenseTransactions = new ArrayList<>();
|
||||||
this.accountContainers = new ArrayList<>();
|
this.accountGroupAccountContainers = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigProjectedCashFlowForPeriodTransactionsForm(List<RecurringTransaction> incomeTransactions,
|
public ConfigProjectedCashFlowForPeriodTransactionsForm(List<RecurringTransaction> incomeTransactions,
|
||||||
List<RecurringTransaction> expenseTransactions,
|
List<RecurringTransaction> expenseTransactions,
|
||||||
boolean byAccount, LocalDate fromDate, LocalDate toDate
|
LocalDate fromDate, LocalDate toDate
|
||||||
) {
|
) {
|
||||||
this.incomeTransactions = incomeTransactions;
|
this.incomeTransactions = incomeTransactions;
|
||||||
this.expenseTransactions = expenseTransactions;
|
this.expenseTransactions = expenseTransactions;
|
||||||
this.accountContainers = new ArrayList<>();
|
this.accountGroupAccountContainers = new ArrayList<>();
|
||||||
this.byAccount = byAccount;
|
|
||||||
this.fromDate = fromDate;
|
this.fromDate = fromDate;
|
||||||
this.toDate = toDate;
|
this.toDate = toDate;
|
||||||
|
|
||||||
@@ -92,14 +118,11 @@ public class ConfigProjectedCashFlowForPeriodTransactionsForm {
|
|||||||
this.expenseSum = expenseTransactions.stream().mapToLong(RecurringTransaction::getAmount).sum();
|
this.expenseSum = expenseTransactions.stream().mapToLong(RecurringTransaction::getAmount).sum();
|
||||||
this.cashFlow = this.incomeSum - this.expenseSum;
|
this.cashFlow = this.incomeSum - this.expenseSum;
|
||||||
|
|
||||||
if(this.byAccount) {
|
this.accountSum = this.accountGroupAccountContainers.stream().map(AccountGroupAccountContainer::getAccounts)
|
||||||
this.accountSum = this.accountContainers.stream().filter(ac -> ac.spending != 0).mapToLong(AccountContainer::getSpending).sum();
|
.flatMap(List::stream).filter(ac -> ac.spending != 0)
|
||||||
|
.mapToLong(AccountContainer::getSpending).sum();
|
||||||
|
|
||||||
this.cashFlow = this.cashFlow - this.accountSum;
|
this.cashFlow = this.cashFlow - this.accountSum;
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO account group calc
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RecurringTransaction> getIncomeTransactions() {
|
public List<RecurringTransaction> getIncomeTransactions() {
|
||||||
@@ -118,16 +141,20 @@ public class ConfigProjectedCashFlowForPeriodTransactionsForm {
|
|||||||
this.expenseTransactions = expenseTransactions;
|
this.expenseTransactions = expenseTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AccountContainer> getAccountContainers() {
|
public List<AccountGroupAccountContainer> getAccountGroupAccountContainers() {
|
||||||
return accountContainers;
|
return accountGroupAccountContainers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAccountContainers(List<AccountContainer> accountContainers) {
|
public void setAccountGroupAccountContainers(List<AccountGroupAccountContainer> accountGroupAccountContainers) {
|
||||||
this.accountContainers = accountContainers;
|
this.accountGroupAccountContainers = accountGroupAccountContainers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAccountContainer(AccountDecorator account) {
|
public void addAccountGroupAccountList(String accountGroup, List<AccountDecorator> accounts) {
|
||||||
this.accountContainers.add(new AccountContainer(account.getAccount(), account.getSpendingCurrentExpensePeriod(), account.getAverageSpendingExpensePeriod()));
|
this.accountGroupAccountContainers.add(new AccountGroupAccountContainer(accountGroup, accounts.stream()
|
||||||
|
.map(ad -> new AccountContainer(ad.getAccount(),
|
||||||
|
ad.getSpendingCurrentExpensePeriod(),
|
||||||
|
ad.getAverageSpendingExpensePeriod()))
|
||||||
|
.collect(Collectors.toList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getIncomeSum() {
|
public long getIncomeSum() {
|
||||||
@@ -150,14 +177,6 @@ public class ConfigProjectedCashFlowForPeriodTransactionsForm {
|
|||||||
return cashFlow;
|
return cashFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isByAccount() {
|
|
||||||
return byAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setByAccount(boolean byAccount) {
|
|
||||||
this.byAccount = byAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getAccountSum() {
|
public long getAccountSum() {
|
||||||
return accountSum;
|
return accountSum;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,9 +219,6 @@ financer.chart-config-account-expenses-for-period.submit=Generate
|
|||||||
financer.report-config-projected-cashflow-for-period.title=Configure projected cash flow report
|
financer.report-config-projected-cashflow-for-period.title=Configure projected cash flow report
|
||||||
financer.report-config-projected-cashflow-for-period.label.from-date=From date\:
|
financer.report-config-projected-cashflow-for-period.label.from-date=From date\:
|
||||||
financer.report-config-projected-cashflow-for-period.label.to-date=To date\:
|
financer.report-config-projected-cashflow-for-period.label.to-date=To date\:
|
||||||
financer.report-config-projected-cashflow-for-period.label.account-or-account-group-summary=By account or account group
|
|
||||||
financer.report-config-projected-cashflow-for-period.label.by-account=Account
|
|
||||||
financer.report-config-projected-cashflow-for-period.label.by-account-group=Account group
|
|
||||||
financer.report-config-projected-cashflow-for-period.submit=Next step
|
financer.report-config-projected-cashflow-for-period.submit=Next step
|
||||||
|
|
||||||
financer.report-select.title=Select a report to generate
|
financer.report-select.title=Select a report to generate
|
||||||
|
|||||||
@@ -219,9 +219,6 @@ financer.chart-config-account-expenses-for-period.submit=Erzeugen
|
|||||||
financer.report-config-projected-cashflow-for-period.title=Konfigurieren von prognostizierter Cashflow Bericht
|
financer.report-config-projected-cashflow-for-period.title=Konfigurieren von prognostizierter Cashflow Bericht
|
||||||
financer.report-config-projected-cashflow-for-period.label.from-date=Von Datum\:
|
financer.report-config-projected-cashflow-for-period.label.from-date=Von Datum\:
|
||||||
financer.report-config-projected-cashflow-for-period.label.to-date=Bis Datum\:
|
financer.report-config-projected-cashflow-for-period.label.to-date=Bis Datum\:
|
||||||
financer.report-config-projected-cashflow-for-period.label.account-or-account-group-summary=Konto oder Kontogruppe
|
|
||||||
financer.report-config-projected-cashflow-for-period.label.by-account=Konto
|
|
||||||
financer.report-config-projected-cashflow-for-period.label.by-account-group=Kontogruppe
|
|
||||||
financer.report-config-projected-cashflow-for-period.submit=N\u00E4chster Schritt
|
financer.report-config-projected-cashflow-for-period.submit=N\u00E4chster Schritt
|
||||||
|
|
||||||
financer.report-select.title=Einen Bericht zum Erzeugen ausw\u00E4hlen
|
financer.report-select.title=Einen Bericht zum Erzeugen ausw\u00E4hlen
|
||||||
|
|||||||
@@ -429,6 +429,10 @@ input[type=submit] {
|
|||||||
padding-left: 1em !important;
|
padding-left: 1em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.projected-cashflow-account {
|
||||||
|
padding-left: 2em !important;
|
||||||
|
}
|
||||||
|
|
||||||
.projected-cashflow-sum > * {
|
.projected-cashflow-sum > * {
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
padding-top: 1em !important;
|
padding-top: 1em !important;
|
||||||
|
|||||||
@@ -19,16 +19,6 @@
|
|||||||
<input type="date" id="fromDate" th:field="*{fromDate}"/>
|
<input type="date" id="fromDate" th:field="*{fromDate}"/>
|
||||||
<label for="toDate" th:text="#{financer.report-config-projected-cashflow-for-period.label.to-date}"/>
|
<label for="toDate" th:text="#{financer.report-config-projected-cashflow-for-period.label.to-date}"/>
|
||||||
<input type="date" id="toDate" th:field="*{toDate}"/>
|
<input type="date" id="toDate" th:field="*{toDate}"/>
|
||||||
<details>
|
|
||||||
<summary th:text="#{financer.show-options}"/>
|
|
||||||
<fieldset class="report-config-projected-cashflow-fieldset">
|
|
||||||
<legend th:text="#{financer.report-config-projected-cashflow-for-period.label.account-or-account-group-summary}"/>
|
|
||||||
<label for="by-account" th:text="#{financer.report-config-projected-cashflow-for-period.label.by-account}"/>
|
|
||||||
<input type="radio" th:value="${true}" th:field="*{byAccount}" id="by-account" checked />
|
|
||||||
<label for="by-account-group" th:text="#{financer.report-config-projected-cashflow-for-period.label.by-account-group}"/>
|
|
||||||
<input type="radio" th:value="${false}" th:field="*{byAccount}" id="by-account-group"/>
|
|
||||||
</fieldset>
|
|
||||||
</details>
|
|
||||||
<input type="submit" th:value="#{financer.report-config-projected-cashflow-for-period.submit}"/>
|
<input type="submit" th:value="#{financer.report-config-projected-cashflow-for-period.submit}"/>
|
||||||
</form>
|
</form>
|
||||||
<div th:replace="includes/footer :: footer"/>
|
<div th:replace="includes/footer :: footer"/>
|
||||||
|
|||||||
@@ -58,22 +58,36 @@
|
|||||||
<td th:text="#{financer.account-overview.table-header.average-spending-period}"
|
<td th:text="#{financer.account-overview.table-header.average-spending-period}"
|
||||||
class="report-config-projected-cashflow-for-period-transactions-table-average-spending noprint"/>
|
class="report-config-projected-cashflow-for-period-transactions-table-average-spending noprint"/>
|
||||||
</tr>
|
</tr>
|
||||||
<tr th:each="entry, i : ${form.accountContainers}">
|
<th:block th:each="entry, i : ${form.accountGroupAccountContainers}">
|
||||||
<td class="projected-cashflow-transaction">
|
<tr>
|
||||||
<span th:text="*{accountContainers[__${i.index}__].account.key}" />
|
<td class="projected-cashflow-transaction">
|
||||||
<input type="hidden" th:field="*{accountContainers[__${i.index}__].account.key}" class="display-none" />
|
<span th:text="*{accountGroupAccountContainers[__${i.index}__].accountGroup}" />
|
||||||
</td>
|
<input type="hidden" th:field="*{accountGroupAccountContainers[__${i.index}__].accountGroup}" class="display-none" />
|
||||||
<td class="report-config-projected-cashflow-for-period-transactions-table-amount noprint">
|
</td>
|
||||||
<input type="text" th:field="*{accountContainers[__${i.index}__].spending}" />
|
<td>
|
||||||
</td>
|
<span></span>
|
||||||
<td class="report-config-projected-cashflow-for-period-transactions-table-amount print">
|
</td>
|
||||||
<span th:utext="${#numbers.formatDecimal(form.accountContainers[__${i.index}__].spending/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
<td>
|
||||||
</td>
|
<span></span>
|
||||||
<td class="noprint report-config-projected-cashflow-for-period-transactions-table-average-spending">
|
</td>
|
||||||
<span th:utext="${#numbers.formatDecimal(form.accountContainers[__${i.index}__].averageSpending/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
</tr>
|
||||||
<input type="hidden" th:field="*{accountContainers[__${i.index}__].averageSpending}" class="display-none" />
|
<tr th:each="listEntry, j : ${entry.accounts}">
|
||||||
</td>
|
<td class="projected-cashflow-account">
|
||||||
</tr>
|
<span th:text="*{accountGroupAccountContainers[__${i.index}__].accounts[__${j.index}__].account.key}" />
|
||||||
|
<input type="hidden" th:field="*{accountGroupAccountContainers[__${i.index}__].accounts[__${j.index}__].account.key}" class="display-none" />
|
||||||
|
</td>
|
||||||
|
<td class="report-config-projected-cashflow-for-period-transactions-table-amount noprint">
|
||||||
|
<input type="text" th:field="*{accountGroupAccountContainers[__${i.index}__].accounts[__${j.index}__].spending}" />
|
||||||
|
</td>
|
||||||
|
<td class="report-config-projected-cashflow-for-period-transactions-table-amount print">
|
||||||
|
<span th:utext="${#numbers.formatDecimal(form.accountGroupAccountContainers[__${i.index}__].accounts[__${j.index}__].spending/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||||
|
</td>
|
||||||
|
<td class="noprint report-config-projected-cashflow-for-period-transactions-table-average-spending">
|
||||||
|
<span th:utext="${#numbers.formatDecimal(form.accountGroupAccountContainers[__${i.index}__].accounts[__${j.index}__].averageSpending/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"/>
|
||||||
|
<input type="hidden" th:field="*{accountGroupAccountContainers[__${i.index}__].accounts[__${j.index}__].averageSpending}" class="display-none" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</th:block>
|
||||||
<tr class="projected-cashflow-sum">
|
<tr class="projected-cashflow-sum">
|
||||||
<td th:text="#{financer.report-config-projected-cashflow-for-period-transactions.table.cash-flow.sum}"/>
|
<td th:text="#{financer.report-config-projected-cashflow-for-period-transactions.table.cash-flow.sum}"/>
|
||||||
<td th:utext="${#numbers.formatDecimal(form.cashFlow/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"
|
<td th:utext="${#numbers.formatDecimal(form.cashFlow/100D, 1, 'DEFAULT', 2, 'DEFAULT') + currencySymbol}"
|
||||||
@@ -83,7 +97,6 @@
|
|||||||
</table>
|
</table>
|
||||||
<input type="hidden" th:field="*{fromDate}" class="display-none"/>
|
<input type="hidden" th:field="*{fromDate}" class="display-none"/>
|
||||||
<input type="hidden" th:field="*{toDate}" class="display-none"/>
|
<input type="hidden" th:field="*{toDate}" class="display-none"/>
|
||||||
<input type="hidden" th:field="*{byAccount}" class="display-none"/>
|
|
||||||
<input type="submit" th:formaction="@{/configureProjectedCashFlowForPeriodTransactionsRefresh}"
|
<input type="submit" th:formaction="@{/configureProjectedCashFlowForPeriodTransactionsRefresh}"
|
||||||
th:value="#{financer.report-config-projected-cashflow-for-period-transactions.label.button.refresh}" class="noprint"/>
|
th:value="#{financer.report-config-projected-cashflow-for-period-transactions.label.button.refresh}" class="noprint"/>
|
||||||
<input type="submit" onClick="window.print()"
|
<input type="submit" onClick="window.print()"
|
||||||
|
|||||||
Reference in New Issue
Block a user