fix: excluded paid credit from total expenses (its a loan)
This commit is contained in:
parent
91d4f4245f
commit
3070ed7571
5 changed files with 61 additions and 20 deletions
|
@ -73,4 +73,8 @@ public class Expense extends AbstractEntity {
|
||||||
*/
|
*/
|
||||||
@Column(name = "isPaid", nullable = false)
|
@Column(name = "isPaid", nullable = false)
|
||||||
private Boolean isPaid = false;
|
private Boolean isPaid = false;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Column(name = "expenseType", nullable = false)
|
||||||
|
private ExpenseType expenseType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.application.munera.data;
|
||||||
|
|
||||||
|
public enum ExpenseType {
|
||||||
|
CREDIT,
|
||||||
|
DEBIT,
|
||||||
|
NONE
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package com.application.munera.repositories;
|
||||||
|
|
||||||
|
|
||||||
import com.application.munera.data.Expense;
|
import com.application.munera.data.Expense;
|
||||||
|
import com.application.munera.data.ExpenseType;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
@ -27,6 +28,9 @@ public interface ExpenseRepository extends JpaRepository<Expense, Long>, JpaSpec
|
||||||
@Query("SELECT e FROM Expense e JOIN e.debtors d WHERE d.id = :personId AND e.isPaid = false")
|
@Query("SELECT e FROM Expense e JOIN e.debtors d WHERE d.id = :personId AND e.isPaid = false")
|
||||||
Set<Expense> findUnpaidDebtorsExpensesByPersonId(@Param("personId") Long personId);
|
Set<Expense> findUnpaidDebtorsExpensesByPersonId(@Param("personId") Long personId);
|
||||||
|
|
||||||
|
@Query("SELECT e FROM Expense e WHERE YEAR(e.date) = :year AND NOT (e.expenseType = :expenseType AND e.isPaid = true)")
|
||||||
|
List<Expense> findByYearAndFilterCreditPaid(@Param("year") int year, @Param("expenseType") ExpenseType expenseType);
|
||||||
|
|
||||||
boolean existsByIdAndIsPaidTrue(Long id);
|
boolean existsByIdAndIsPaidTrue(Long id);
|
||||||
|
|
||||||
List<Expense> findAllByOrderByDateDesc();}
|
List<Expense> findAllByOrderByDateDesc();}
|
|
@ -1,6 +1,7 @@
|
||||||
package com.application.munera.services;
|
package com.application.munera.services;
|
||||||
|
|
||||||
import com.application.munera.data.Expense;
|
import com.application.munera.data.Expense;
|
||||||
|
import com.application.munera.data.ExpenseType;
|
||||||
import com.application.munera.data.Person;
|
import com.application.munera.data.Person;
|
||||||
import com.application.munera.repositories.ExpenseRepository;
|
import com.application.munera.repositories.ExpenseRepository;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
@ -8,23 +9,25 @@ import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ExpenseService {
|
public class ExpenseService {
|
||||||
|
|
||||||
private final ExpenseRepository repository;
|
private final ExpenseRepository expenseRepository;
|
||||||
|
|
||||||
public ExpenseService(ExpenseRepository repository) {
|
public ExpenseService(ExpenseRepository expenseRepository) {
|
||||||
this.repository = repository;
|
this.expenseRepository = expenseRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Expense> get(Long id) {
|
public Optional<Expense> get(Long id) {
|
||||||
return repository.findById(id);
|
return expenseRepository.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +36,7 @@ public class ExpenseService {
|
||||||
* @return the collections of expenses found
|
* @return the collections of expenses found
|
||||||
*/
|
*/
|
||||||
public Collection<Expense> findDebtByUser(final Person person) {
|
public Collection<Expense> findDebtByUser(final Person person) {
|
||||||
return repository.findDebtorsExpensesByPersonId(person.getId());
|
return expenseRepository.findDebtorsExpensesByPersonId(person.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +45,7 @@ public class ExpenseService {
|
||||||
* @return the collections of expenses found
|
* @return the collections of expenses found
|
||||||
*/
|
*/
|
||||||
public Collection<Expense> findCreditByUser(final Person person) {
|
public Collection<Expense> findCreditByUser(final Person person) {
|
||||||
return repository.findCreditorsExpensesByPersonId(person.getId());
|
return expenseRepository.findCreditorsExpensesByPersonId(person.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +54,7 @@ public class ExpenseService {
|
||||||
* @return the collections of expenses found
|
* @return the collections of expenses found
|
||||||
*/
|
*/
|
||||||
public Collection<Expense> findUnpaidDebtByUser(final Person person) {
|
public Collection<Expense> findUnpaidDebtByUser(final Person person) {
|
||||||
return repository.findUnpaidDebtorsExpensesByPersonId(person.getId());
|
return expenseRepository.findUnpaidDebtorsExpensesByPersonId(person.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,7 +63,7 @@ public class ExpenseService {
|
||||||
* @return the collections of expenses found
|
* @return the collections of expenses found
|
||||||
*/
|
*/
|
||||||
public Collection<Expense> findUnpaidCreditByUser(final Person person) {
|
public Collection<Expense> findUnpaidCreditByUser(final Person person) {
|
||||||
return repository.findUnpaidCreditorsExpensesByPersonId(person.getId());
|
return expenseRepository.findUnpaidCreditorsExpensesByPersonId(person.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +77,7 @@ public class ExpenseService {
|
||||||
return Stream.concat(credits.stream(), debits.stream()).toList();
|
return Stream.concat(credits.stream(), debits.stream()).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Expense> findAll() {return repository.findAll();}
|
public List<Expense> findAll() {return expenseRepository.findAll();}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* updates an expense
|
* updates an expense
|
||||||
|
@ -82,7 +85,8 @@ public class ExpenseService {
|
||||||
*/
|
*/
|
||||||
public void update(Expense entity) {
|
public void update(Expense entity) {
|
||||||
if (Boolean.TRUE.equals(entity.getIsPaid())) entity.setPaymentDate(LocalDateTime.now());
|
if (Boolean.TRUE.equals(entity.getIsPaid())) entity.setPaymentDate(LocalDateTime.now());
|
||||||
repository.save(entity);
|
this.setExpenseType(entity);
|
||||||
|
expenseRepository.save(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,23 +94,27 @@ public class ExpenseService {
|
||||||
* @param id the id of the expense to delete
|
* @param id the id of the expense to delete
|
||||||
*/
|
*/
|
||||||
public void delete(Long id) {
|
public void delete(Long id) {
|
||||||
repository.deleteById(id);
|
expenseRepository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page<Expense> list(Pageable pageable) {
|
public Page<Expense> list(Pageable pageable) {
|
||||||
return repository.findAll(pageable);
|
return expenseRepository.findAll(pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page<Expense> list(Pageable pageable, Specification<Expense> filter) {
|
public Page<Expense> list(Pageable pageable, Specification<Expense> filter) {
|
||||||
return repository.findAll(filter, pageable);
|
return expenseRepository.findAll(filter, pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int count() {
|
public int count() {
|
||||||
return (int) repository.count();
|
return (int) expenseRepository.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Expense> findAllByYear(final int year ) {
|
public List<Expense> findAllByYear(final int year ) {
|
||||||
return this.repository.findAllByYear(year);
|
return this.expenseRepository.findAllByYear(year);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Expense> findExpensesByYearExcludingCreditPaid(int year) {
|
||||||
|
return expenseRepository.findByYearAndFilterCreditPaid(year, ExpenseType.CREDIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,7 +123,7 @@ public class ExpenseService {
|
||||||
* @return true if the expense has been paid, false otherwise
|
* @return true if the expense has been paid, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isExpensePaid(final Expense expense) {
|
public boolean isExpensePaid(final Expense expense) {
|
||||||
return this.repository.existsByIdAndIsPaidTrue(expense.getId());
|
return this.expenseRepository.existsByIdAndIsPaidTrue(expense.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,6 +131,24 @@ public class ExpenseService {
|
||||||
* @return the list of expenses found
|
* @return the list of expenses found
|
||||||
*/
|
*/
|
||||||
public List<Expense> findAllOrderByDateDescending() {
|
public List<Expense> findAllOrderByDateDescending() {
|
||||||
return this.repository.findAllByOrderByDateDesc();
|
return this.expenseRepository.findAllByOrderByDateDesc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the Expense type depending on the presence or absence of creditors and debtors
|
||||||
|
* this is used to filter expenses with a creditor that are paid, since they are not part of
|
||||||
|
* the actual money the user has spent, it's just a load technically
|
||||||
|
* @param expense the expense to set the type of
|
||||||
|
*/
|
||||||
|
private void setExpenseType(final @Nonnull Expense expense) {
|
||||||
|
if (Objects.nonNull(expense.getCreditors()) && !expense.getCreditors().isEmpty())
|
||||||
|
// If creditors are present, set type to CREDIT
|
||||||
|
expense.setExpenseType(ExpenseType.CREDIT);
|
||||||
|
else if (Objects.nonNull(expense.getDebtors()) && !expense.getDebtors().isEmpty())
|
||||||
|
// If debtors are present and no creditors, set type to DEBIT
|
||||||
|
expense.setExpenseType(ExpenseType.DEBIT);
|
||||||
|
else
|
||||||
|
// If neither creditors nor debtors are present, set type to NONE
|
||||||
|
expense.setExpenseType(ExpenseType.NONE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class DashboardView extends Div {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateBarChartScript() {
|
private String generateBarChartScript() {
|
||||||
List<Expense> expenses = expenseService.findAllByYear(Year.now().getValue());
|
List<Expense> expenses = expenseService.findExpensesByYearExcludingCreditPaid(Year.now().getValue());
|
||||||
|
|
||||||
// Prepare data for Highcharts
|
// Prepare data for Highcharts
|
||||||
Map<String, Double> monthlyData = new LinkedHashMap<>();
|
Map<String, Double> monthlyData = new LinkedHashMap<>();
|
||||||
|
@ -150,7 +150,7 @@ public class DashboardView extends Div {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generatePieChartScript() {
|
private String generatePieChartScript() {
|
||||||
List<Expense> expenses = expenseService.findAllByYear(Year.now().getValue());
|
List<Expense> expenses = expenseService.findExpensesByYearExcludingCreditPaid(Year.now().getValue());
|
||||||
|
|
||||||
// Group expenses by category name and sum their costs
|
// Group expenses by category name and sum their costs
|
||||||
Map<String, Double> categoryData = expenses.stream()
|
Map<String, Double> categoryData = expenses.stream()
|
||||||
|
@ -258,7 +258,7 @@ public class DashboardView extends Div {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateExpensesOverTimeByCategoryScript() {
|
private String generateExpensesOverTimeByCategoryScript() {
|
||||||
List<Expense> expenses = expenseService.findAllByYear(Year.now().getValue());
|
List<Expense> expenses = expenseService.findExpensesByYearExcludingCreditPaid(Year.now().getValue());
|
||||||
|
|
||||||
// Group expenses by category and by month
|
// Group expenses by category and by month
|
||||||
Map<String, Map<String, Double>> categoryMonthlyData = new LinkedHashMap<>();
|
Map<String, Map<String, Double>> categoryMonthlyData = new LinkedHashMap<>();
|
||||||
|
|
Loading…
Reference in a new issue