#29 Projected cash flow

This commit is contained in:
2022-05-18 20:50:15 +02:00
parent c0de315cb6
commit b1f69a2aee
8 changed files with 91 additions and 83 deletions

View File

@@ -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();

View File

@@ -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;
}
} }

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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"/>

View File

@@ -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()"