Add colors, fix bugs

This commit is contained in:
2019-10-18 22:09:25 +02:00
parent b23bfb9ff5
commit 5286c94dca
8 changed files with 132 additions and 8 deletions

View File

@@ -17,7 +17,7 @@
<properties> <properties>
<packaging.type>jar</packaging.type> <packaging.type>jar</packaging.type>
<activeProfiles>hsqldb,dev</activeProfiles> <activeProfiles>postgres,dev</activeProfiles>
<deploymentProfile>mk</deploymentProfile> <deploymentProfile>mk</deploymentProfile>
</properties> </properties>

View File

@@ -20,8 +20,8 @@ public interface TransactionRepository extends CrudRepository<Transaction, Long>
@Query("SELECT SUM(t.amount) FROM Transaction t JOIN t.periods p JOIN t.toAccount a WHERE a.type IN :expenseTypes AND p = :period") @Query("SELECT SUM(t.amount) FROM Transaction t JOIN t.periods p JOIN t.toAccount a WHERE a.type IN :expenseTypes AND p = :period")
Long getExpensesForPeriod(Period period, AccountType... expenseTypes); Long getExpensesForPeriod(Period period, AccountType... expenseTypes);
@Query("SELECT SUM(t.amount) FROM Transaction t JOIN t.periods p JOIN t.toAccount a WHERE a.type IN :expenseTypes GROUP BY p ORDER BY p.start ASC") @Query("SELECT SUM(t.amount) FROM Transaction t JOIN t.periods p JOIN t.toAccount a JOIN t.fromAccount f WHERE a.type IN :expenseTypes AND f.type != :startType GROUP BY p ORDER BY p.start ASC")
List<Long> getExpensesForAllPeriods(AccountType... expenseTypes); List<Long> getExpensesForAllPeriods(AccountType startType, AccountType... expenseTypes);
// The HQL contains a hack because Hibernate can't resolve the alias of the CASE column in the GROUP BY clause // The HQL contains a hack because Hibernate can't resolve the alias of the CASE column in the GROUP BY clause
// That's why the generated alias is used directly in the HQL. It will break if the columns in the SELECT clause get reordered // That's why the generated alias is used directly in the HQL. It will break if the columns in the SELECT clause get reordered

View File

@@ -235,6 +235,13 @@ public class TransactionService {
return response; return response;
} }
/**
* This method calculates the expenses done in the current period; this is the sum of
* all bookings to {@link AccountType#EXPENSE EXPENSE} or {@link AccountType#LIABILITY LIABILITY}
* accounts.
*
* @return the sum of expenses - may be <code>0</code>
*/
public Long getExpensesCurrentPeriod() { public Long getExpensesCurrentPeriod() {
final Period expensePeriod = this.periodService.getCurrentExpensePeriod(); final Period expensePeriod = this.periodService.getCurrentExpensePeriod();
@@ -244,10 +251,25 @@ public class TransactionService {
return Optional.ofNullable(expensesCurrentPeriod).orElse(Long.valueOf(0l)); return Optional.ofNullable(expensesCurrentPeriod).orElse(Long.valueOf(0l));
} }
/**
* This method gets all sums of expenses of all periods, ordered from oldest to newest.
*
* @return the sums of expenses - may be empty
* @see TransactionService#getExpensesCurrentPeriod()
*/
public List<Long> getExpensesAllPeriods() { public List<Long> getExpensesAllPeriods() {
return this.transactionRepository.getExpensesForAllPeriods(AccountType.EXPENSE, AccountType.LIABILITY); return this.transactionRepository.getExpensesForAllPeriods(AccountType.START, AccountType.EXPENSE, AccountType.LIABILITY);
} }
/**
* This method gets the total values of all expense periods of the given year; that is
* the sum of all bookings for {@link AccountType#EXPENSE EXPENSE},
* {@link AccountType#LIABILITY LIABILITY} and {@link AccountType#INCOME INCOME} accounts
* grouped by the account type and period.
*
* @param year the year to get the expense period totals for
* @return the expense period totals for the given year
*/
public Iterable<ExpensePeriodTotal> getExpensePeriodTotals(Integer year) { public Iterable<ExpensePeriodTotal> getExpensePeriodTotals(Integer year) {
final Iterable<Period> periods = this.periodService.getAllExpensePeriodsForYear(year); final Iterable<Period> periods = this.periodService.getAllExpensePeriodsForYear(year);

View File

@@ -1,7 +1,6 @@
package de.financer.chart.impl.expense; package de.financer.chart.impl.expense;
import de.financer.chart.AbstractChartGenerator; import de.financer.chart.AbstractChartGenerator;
import de.financer.chart.ChartDefinitions;
import de.financer.config.FinancerConfig; import de.financer.config.FinancerConfig;
import de.financer.util.ControllerUtils; import de.financer.util.ControllerUtils;
import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartFactory;
@@ -24,8 +23,6 @@ public abstract class AbstractExpensesGenerator extends AbstractChartGenerator<E
final JFreeChart chart = ChartFactory final JFreeChart chart = ChartFactory
.createPieChart(this.getMessage(parameter.getTitle(), parameter.getArgsForTitle()), dataSet); .createPieChart(this.getMessage(parameter.getTitle(), parameter.getArgsForTitle()), dataSet);
chart.getCategoryPlot().setBackgroundPaint(ChartDefinitions.TRANSPARENT);
final NumberFormat currencyInstance = NumberFormat.getCurrencyInstance(LocaleContextHolder.getLocale()); final NumberFormat currencyInstance = NumberFormat.getCurrencyInstance(LocaleContextHolder.getLocale());
currencyInstance.setCurrency(this.getFinancerConfig().getCurrency()); currencyInstance.setCurrency(this.getFinancerConfig().getCurrency());

View File

@@ -1,3 +1,8 @@
v24 -> v25:
- Add color column in account overview
- Fix a bug that caused the chart generation to crash
- Exclude START bookings from expense history
v23 -> v24: v23 -> v24:
- Mark accounts that are overspend, meaning their spending in the current period is greater than the average spending of - Mark accounts that are overspend, meaning their spending in the current period is greater than the average spending of
that account that account

View File

@@ -1,6 +1,13 @@
/* Variable declarations */ /* Variable declarations */
:root { :root {
--error-color: #D30000/*#ff6666*/; --error-color: #D30000/*#ff6666*/;
--bank-color: #008FFB;
--cash-color: #FFCB00;
--income-color: #00A900;
--liability-color: #D36000;
--expense-color: #D30000;
--start-color: #AB005D;
--type-row-width: 5px;
} }
/* --------------------- */ /* --------------------- */
@@ -139,4 +146,45 @@ input[type=submit] {
.errorMessage { .errorMessage {
color: var(--error-color); color: var(--error-color);
display: block; display: block;
}
.bank-row {
background-color: var(--bank-color) !important;
width: var(--type-row-width);
padding: 0px !important
}
.cash-row {
background-color: var(--cash-color) !important;
width: var(--type-row-width);
padding: 0px !important
}
.income-row {
background-color: var(--income-color) !important;
width: var(--type-row-width);
padding: 0px !important
}
.liability-row {
background-color: var(--liability-color) !important;
width: var(--type-row-width);
padding: 0px !important
}
.expense-row {
background-color: var(--expense-color) !important;
width: var(--type-row-width);
padding: 0px !important
}
.start-row {
background-color: var(--start-color) !important;
width: var(--type-row-width);
padding: 0px !important
}
#type-row {
width: var(--type-row-width);
padding: 0px !important
} }

View File

@@ -19,13 +19,40 @@
1. About 1. About
======== ========
This is the manual for the financer application - a simple app to manage your personal finances. This is the manual for the financer application - a simple app to support you in managing your personal finances.
The main goal of the financer application is to keep things simple by not attempting to provide sophisticated
automation. Instead it is merely a tool that provides basic key values to support you.
2. Overview 2. Overview
=========== ===========
3. Architectural overview 3. Architectural overview
========================= =========================
The financer application currently consists of two components - a server and a client. They communicate via a JSON
REST API. The only available client is a web client that supports a boiled down view for mobile devices, though.
Both client (-web-client) and server (-server) reside in dedicated Maven modules, with a common (-common) module
that holds common model classes and DTOs. Both components are layered:
____________ C
| Controller | L
|------------| I
| Chart | E
S ____________ |------------| N
E | Controller |<-------REST--------| Template | T
R |------------| '------------'
V | Service |
E |------------|
R | DBA |
'------------'
|
|
,-------,
| DB |
'-------'
Each component is contained in a distinct artifact.
4. Account types 4. Account types
================ ================
@@ -115,6 +142,24 @@
6. Account groups 6. Account groups
================= =================
Account groups are a simple way to group account into topics. Imagine the following accounts:
- Rent
- Electricity
- Water
- Groceries
- Takeaway
- Coffee shop
- Cinema
- Netflix
They could be grouped via the following three groups:
- Housing for Rent, Electricity and Water
- Food for Groceries, Takeaway and Coffee shop
- Entertainment for Cinema and Netflix
This additional hierarchy level is actively used by reports to provide a better picture about where money is spent.
The financer application makes no hard guidelines on how to model your accounts and account groups, so you can model
them matching your needs.
7. Transactions 7. Transactions
=============== ===============

View File

@@ -66,6 +66,7 @@
</div> </div>
<table id="account-overview-table"> <table id="account-overview-table">
<tr> <tr>
<th id="type-row" />
<th class="hideable-column" th:text="#{financer.account-overview.table-header.id}"/> <th class="hideable-column" th:text="#{financer.account-overview.table-header.id}"/>
<th th:text="#{financer.account-overview.table-header.key}"/> <th th:text="#{financer.account-overview.table-header.key}"/>
<th th:text="#{financer.account-overview.table-header.balance}"/> <th th:text="#{financer.account-overview.table-header.balance}"/>
@@ -76,6 +77,12 @@
<th class="hideable-column" th:text="#{financer.account-overview.table-header.status}"/> <th class="hideable-column" th:text="#{financer.account-overview.table-header.status}"/>
</tr> </tr>
<tr th:each="acc : ${accounts}"> <tr th:each="acc : ${accounts}">
<th class="bank-row" th:if="${acc.type == T(de.financer.model.AccountType).BANK}" />
<th class="cash-row" th:if="${acc.type == T(de.financer.model.AccountType).CASH}" />
<th class="income-row" th:if="${acc.type == T(de.financer.model.AccountType).INCOME}" />
<th class="liability-row" th:if="${acc.type == T(de.financer.model.AccountType).LIABILITY}" />
<th class="expense-row" th:if="${acc.type == T(de.financer.model.AccountType).EXPENSE}" />
<th class="start-row" th:if="${acc.type == T(de.financer.model.AccountType).START}" />
<td class="hideable-column" th:text="${acc.id}"/> <td class="hideable-column" th:text="${acc.id}"/>
<td> <td>
<a th:href="@{/accountDetails(key=${acc.key})}" th:text="${acc.key}"/> <a th:href="@{/accountDetails(key=${acc.key})}" th:text="${acc.key}"/>