Add colors, fix bugs
This commit is contained in:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
/* --------------------- */
|
/* --------------------- */
|
||||||
|
|
||||||
@@ -140,3 +147,44 @@ input[type=submit] {
|
|||||||
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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
===============
|
===============
|
||||||
|
|||||||
@@ -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}"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user