From 3070ed7571a0030b2b4782004818db9fab96b6a3 Mon Sep 17 00:00:00 2001 From: filippo-ferrari Date: Sat, 7 Sep 2024 16:54:04 +0200 Subject: [PATCH] fix: excluded paid credit from total expenses (its a loan) --- .../com/application/munera/data/Expense.java | 4 ++ .../application/munera/data/ExpenseType.java | 7 +++ .../repositories/ExpenseRepository.java | 4 ++ .../munera/services/ExpenseService.java | 60 +++++++++++++------ .../munera/views/dashboard/DashboardView.java | 6 +- 5 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/application/munera/data/ExpenseType.java diff --git a/src/main/java/com/application/munera/data/Expense.java b/src/main/java/com/application/munera/data/Expense.java index 7fc2dce..aa718f9 100644 --- a/src/main/java/com/application/munera/data/Expense.java +++ b/src/main/java/com/application/munera/data/Expense.java @@ -73,4 +73,8 @@ public class Expense extends AbstractEntity { */ @Column(name = "isPaid", nullable = false) private Boolean isPaid = false; + + @Enumerated(EnumType.STRING) + @Column(name = "expenseType", nullable = false) + private ExpenseType expenseType; } diff --git a/src/main/java/com/application/munera/data/ExpenseType.java b/src/main/java/com/application/munera/data/ExpenseType.java new file mode 100644 index 0000000..91ce987 --- /dev/null +++ b/src/main/java/com/application/munera/data/ExpenseType.java @@ -0,0 +1,7 @@ +package com.application.munera.data; + +public enum ExpenseType { + CREDIT, + DEBIT, + NONE +} diff --git a/src/main/java/com/application/munera/repositories/ExpenseRepository.java b/src/main/java/com/application/munera/repositories/ExpenseRepository.java index 98c4468..ed1864b 100644 --- a/src/main/java/com/application/munera/repositories/ExpenseRepository.java +++ b/src/main/java/com/application/munera/repositories/ExpenseRepository.java @@ -2,6 +2,7 @@ package com.application.munera.repositories; 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.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; @@ -27,6 +28,9 @@ public interface ExpenseRepository extends JpaRepository, JpaSpec @Query("SELECT e FROM Expense e JOIN e.debtors d WHERE d.id = :personId AND e.isPaid = false") Set 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 findByYearAndFilterCreditPaid(@Param("year") int year, @Param("expenseType") ExpenseType expenseType); + boolean existsByIdAndIsPaidTrue(Long id); List findAllByOrderByDateDesc();} \ No newline at end of file diff --git a/src/main/java/com/application/munera/services/ExpenseService.java b/src/main/java/com/application/munera/services/ExpenseService.java index 991ecd0..629230f 100644 --- a/src/main/java/com/application/munera/services/ExpenseService.java +++ b/src/main/java/com/application/munera/services/ExpenseService.java @@ -1,6 +1,7 @@ package com.application.munera.services; import com.application.munera.data.Expense; +import com.application.munera.data.ExpenseType; import com.application.munera.data.Person; import com.application.munera.repositories.ExpenseRepository; 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.stereotype.Service; +import javax.annotation.Nonnull; import java.time.LocalDateTime; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; @Service public class ExpenseService { - private final ExpenseRepository repository; + private final ExpenseRepository expenseRepository; - public ExpenseService(ExpenseRepository repository) { - this.repository = repository; + public ExpenseService(ExpenseRepository expenseRepository) { + this.expenseRepository = expenseRepository; } public Optional get(Long id) { - return repository.findById(id); + return expenseRepository.findById(id); } /** @@ -33,7 +36,7 @@ public class ExpenseService { * @return the collections of expenses found */ public Collection 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 */ public Collection 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 */ public Collection 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 */ public Collection 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(); } - public List findAll() {return repository.findAll();} + public List findAll() {return expenseRepository.findAll();} /** * updates an expense @@ -82,7 +85,8 @@ public class ExpenseService { */ public void update(Expense entity) { 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 */ public void delete(Long id) { - repository.deleteById(id); + expenseRepository.deleteById(id); } public Page list(Pageable pageable) { - return repository.findAll(pageable); + return expenseRepository.findAll(pageable); } public Page list(Pageable pageable, Specification filter) { - return repository.findAll(filter, pageable); + return expenseRepository.findAll(filter, pageable); } public int count() { - return (int) repository.count(); + return (int) expenseRepository.count(); } public List findAllByYear(final int year ) { - return this.repository.findAllByYear(year); + return this.expenseRepository.findAllByYear(year); + } + + public List 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 */ 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 */ public List 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); + } } diff --git a/src/main/java/com/application/munera/views/dashboard/DashboardView.java b/src/main/java/com/application/munera/views/dashboard/DashboardView.java index 6bb4e4a..29ad37e 100644 --- a/src/main/java/com/application/munera/views/dashboard/DashboardView.java +++ b/src/main/java/com/application/munera/views/dashboard/DashboardView.java @@ -105,7 +105,7 @@ public class DashboardView extends Div { } private String generateBarChartScript() { - List expenses = expenseService.findAllByYear(Year.now().getValue()); + List expenses = expenseService.findExpensesByYearExcludingCreditPaid(Year.now().getValue()); // Prepare data for Highcharts Map monthlyData = new LinkedHashMap<>(); @@ -150,7 +150,7 @@ public class DashboardView extends Div { } private String generatePieChartScript() { - List expenses = expenseService.findAllByYear(Year.now().getValue()); + List expenses = expenseService.findExpensesByYearExcludingCreditPaid(Year.now().getValue()); // Group expenses by category name and sum their costs Map categoryData = expenses.stream() @@ -258,7 +258,7 @@ public class DashboardView extends Div { } private String generateExpensesOverTimeByCategoryScript() { - List expenses = expenseService.findAllByYear(Year.now().getValue()); + List expenses = expenseService.findExpensesByYearExcludingCreditPaid(Year.now().getValue()); // Group expenses by category and by month Map> categoryMonthlyData = new LinkedHashMap<>();