Create null statistic entries for accounts not used in the period to close
This commit is contained in:
@@ -2,6 +2,7 @@ package de.financer.dba;
|
||||
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.AccountStatistic;
|
||||
import de.financer.model.AccountStatus;
|
||||
import de.financer.model.Period;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
@@ -12,4 +13,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public interface AccountStatisticRepository extends CrudRepository<AccountStatistic, Long> {
|
||||
@Query("SELECT accStat FROM AccountStatistic accStat WHERE accStat.account = :account AND accStat.period = :period")
|
||||
AccountStatistic findForAccountAndPeriod(Account account, Period period);
|
||||
|
||||
@Query("SELECT a FROM Account a WHERE a NOT IN (SELECT accStat.account FROM AccountStatistic accStat WHERE accStat.period = :period) AND a.status = :accountStatus")
|
||||
Iterable<Account> getAccountsWithoutStatisticInPeriod(Period period, AccountStatus accountStatus);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,16 @@ public class AccountGroupService {
|
||||
return ResponseReason.OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the expenses for all account groups that were used between the given from and to
|
||||
* dates. The result list contains one entry per account group that holds the sum of bookings.
|
||||
*
|
||||
* @param periodStart the start of the period as date without time
|
||||
* @param periodEnd the end of the period as date without time
|
||||
* @return a list containing the sum of bookings per account group in the given period, an empty list if
|
||||
* either no bookings have been done yet or if the given period start and end dates are not valid, but never
|
||||
* <code>null</code>
|
||||
*/
|
||||
public Iterable<AccountGroupExpense> getAccountGroupExpenses(String periodStart, String periodEnd) {
|
||||
LocalDate startDate;
|
||||
LocalDate endDate;
|
||||
@@ -96,12 +106,21 @@ public class AccountGroupService {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Actual calculation done via SQL
|
||||
return this.accountGroupRepository.getAccountGroupExpenses(startDate, endDate, AccountType.LIABILITY, AccountType.EXPENSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the expenses for all account groups that were used in the current expense period.
|
||||
* The result list contains one entry per account group that holds the sum of bookings.
|
||||
*
|
||||
* @return a list containing the sum of bookings per account group in the current expense period, an empty list if
|
||||
* no bookings have been done yet, but never <code>null</code>
|
||||
*/
|
||||
public Iterable<AccountGroupExpense> getAccountGroupExpensesCurrentExpensePeriod() {
|
||||
final Period period = this.periodService.getCurrentExpensePeriod();
|
||||
|
||||
// Actual calculation done via SQL
|
||||
return this.accountGroupRepository.getAccountGroupExpensesCurrentExpensePeriod(period, AccountType.LIABILITY, AccountType.EXPENSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,8 @@ public class AccountService {
|
||||
*
|
||||
* @param periodStart the start of the arbitrary period
|
||||
* @param periodEnd the end of the arbitrary period
|
||||
* @return a mapping of {@link Account}<->its expenses in the given period
|
||||
* @return a mapping of {@link Account}<->its expenses in the given period, an empty list of no
|
||||
* ookings have been done yet or the given start and end dates are invalid, but never <code>null</code>
|
||||
*/
|
||||
public Iterable<AccountExpense> getAccountExpenses(String periodStart, String periodEnd) {
|
||||
LocalDate startDate;
|
||||
@@ -183,17 +184,20 @@ public class AccountService {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Actual calculation done in SQL
|
||||
return this.accountRepository.getAccountExpenses(startDate, endDate, AccountType.LIABILITY, AccountType.EXPENSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the expenses per account in the current expense period.
|
||||
* This method gets the expenses per account in the current expense period.
|
||||
*
|
||||
* @return a mapping of {@link Account}<->its expenses in the current expense period
|
||||
* @return a mapping of {@link Account}<->its expenses in the current expense period, an empty list of no
|
||||
* bookings have been done yet, but never <code>null</code>
|
||||
*/
|
||||
public Iterable<AccountExpense> getAccountExpensesCurrentExpensePeriod() {
|
||||
final Period period = this.periodService.getCurrentExpensePeriod();
|
||||
|
||||
// Actual calculation done in SQL
|
||||
return this.accountRepository.getAccountExpenses(period, AccountType.LIABILITY, AccountType.EXPENSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package de.financer.service;
|
||||
|
||||
import de.financer.dba.AccountStatisticRepository;
|
||||
import de.financer.model.Account;
|
||||
import de.financer.model.AccountStatistic;
|
||||
import de.financer.model.Period;
|
||||
import de.financer.model.Transaction;
|
||||
import de.financer.model.*;
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -14,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class AccountStatisticService {
|
||||
@@ -22,6 +21,17 @@ public class AccountStatisticService {
|
||||
@Autowired
|
||||
private AccountStatisticRepository accountStatisticRepository;
|
||||
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
|
||||
/**
|
||||
* This method calculates the {@link AccountStatistic}s for the given transaction. The statistics are always
|
||||
* symmetric, meaning that one will be calculated for the from account and one for the to account, with their
|
||||
* respective from or to spending filled. As a transaction can be assigned to more than one period this method will
|
||||
* calculate two statistics per assigned period.
|
||||
*
|
||||
* @param transaction to calculate the statistics for
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void calculateStatistics(Transaction transaction) {
|
||||
final Account fromAccount = transaction.getFromAccount();
|
||||
@@ -52,6 +62,34 @@ public class AccountStatisticService {
|
||||
this.accountStatisticRepository.saveAll(resultList);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates an {@link AccountStatistic}s entry with from and to spending <code>0</code>,
|
||||
* for every account not used in a booking in the given period.
|
||||
*
|
||||
* @param period to generate the null statistic entries for
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void generateNullStatisticsForUnusedAccounts(Period period) {
|
||||
final Iterable<Account> accountsWithoutStat = this.accountStatisticRepository
|
||||
.getAccountsWithoutStatisticInPeriod(period, AccountStatus.OPEN);
|
||||
|
||||
this.accountStatisticRepository.saveAll(IterableUtils.toList(accountsWithoutStat)
|
||||
.stream()
|
||||
.map(a -> {
|
||||
final AccountStatistic as = new AccountStatistic();
|
||||
|
||||
as.setTransactionCountTo(0);
|
||||
as.setSpendingTotalTo(0);
|
||||
as.setTransactionCountFrom(0);
|
||||
as.setSpendingTotalFrom(0);
|
||||
as.setAccount(a);
|
||||
as.setPeriod(period);
|
||||
|
||||
return as;
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private AccountStatistic calculateInternal(Account account, Period period, long amount, boolean from, int multiplier) {
|
||||
AccountStatistic accountStatistic = this.accountStatisticRepository
|
||||
.findForAccountAndPeriod(account, period);
|
||||
@@ -66,8 +104,7 @@ public class AccountStatisticService {
|
||||
if (from) {
|
||||
accountStatistic.setSpendingTotalFrom(accountStatistic.getSpendingTotalFrom() + amount * multiplier);
|
||||
accountStatistic.setTransactionCountFrom(accountStatistic.getTransactionCountFrom() + multiplier);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
accountStatistic.setSpendingTotalTo(accountStatistic.getSpendingTotalTo() + amount * multiplier);
|
||||
accountStatistic.setTransactionCountTo(accountStatistic.getTransactionCountTo() + multiplier);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ public class PeriodService {
|
||||
@Autowired
|
||||
private PeriodRepository periodRepository;
|
||||
|
||||
@Autowired
|
||||
private AccountStatisticService accountStatisticService;
|
||||
|
||||
/**
|
||||
* @return the currently open expense period
|
||||
*/
|
||||
@@ -48,6 +51,8 @@ public class PeriodService {
|
||||
this.periodRepository.save(currentPeriod);
|
||||
this.periodRepository.save(nextPeriod);
|
||||
|
||||
this.accountStatisticService.generateNullStatisticsForUnusedAccounts(currentPeriod);
|
||||
|
||||
response = ResponseReason.OK;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Could not close current expense period!", e);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
v25 -> v26:
|
||||
- Close of the current expense period now creates null statistic entries for accounts that have not been used in
|
||||
bookings in the period to close. This way the average spending better reflects the period average
|
||||
|
||||
v24 -> v25:
|
||||
- Add color column in account overview
|
||||
- Fix a bug that caused the chart generation to crash
|
||||
|
||||
Reference in New Issue
Block a user