fix: changed Expense relation with Person entity

This commit is contained in:
filippo-ferrari 2024-09-07 22:18:37 +02:00
parent 13d5f1bf29
commit 6475f83dd8
5 changed files with 73 additions and 63 deletions

View file

@ -8,7 +8,6 @@ import lombok.Setter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Set;
@Entity @Entity
@Getter @Getter
@ -45,19 +44,13 @@ public class Expense extends AbstractEntity {
@Column(name = "PeriodInterval") @Column(name = "PeriodInterval")
private Integer periodInterval; private Integer periodInterval;
@ManyToMany(fetch = FetchType.EAGER) @ManyToOne
@JoinTable( @JoinColumn(name = "CreditorId")
name = "Creditor_expenses", private Person creditor;
joinColumns = @JoinColumn(name = "expense_id"),
inverseJoinColumns = @JoinColumn(name = "people_id"))
private Set<Person> creditors;
@ManyToMany(fetch = FetchType.EAGER) @ManyToOne
@JoinTable( @JoinColumn(name = "DebtorId")
name = "Debtors_expenses", private Person debtor;
joinColumns = @JoinColumn(name = "expense_id"),
inverseJoinColumns = @JoinColumn(name = "people_id"))
private Set<Person> debtors;
@ManyToOne @ManyToOne
@JoinColumn(name = "EventId") @JoinColumn(name = "EventId")
@ -69,9 +62,6 @@ public class Expense extends AbstractEntity {
@Column(name = "PaymentDate") @Column(name = "PaymentDate")
private LocalDateTime paymentDate; private LocalDateTime paymentDate;
/**
* the isPaid field starts as always false
*/
@Column(name = "isPaid", nullable = false) @Column(name = "isPaid", nullable = false)
private Boolean isPaid = false; private Boolean isPaid = false;

View file

@ -40,11 +40,11 @@ public class Person extends AbstractEntity {
@Column(name = "credit") @Column(name = "credit")
private BigDecimal credit; private BigDecimal credit;
@ManyToMany(mappedBy = "creditors") @OneToMany(mappedBy = "creditor")
private Set<Expense> creditorExpenses; private Set<Expense> creditExpenses;
@ManyToMany(mappedBy = "debtors") @OneToMany(mappedBy = "debtor")
private Set<Expense> debtorExpenses; private Set<Expense> debtExpenses;
@ManyToMany(mappedBy = "participants") @ManyToMany(mappedBy = "participants")
private Set<Event> events; private Set<Event> events;

View file

@ -13,24 +13,33 @@ import java.util.Set;
public interface ExpenseRepository extends JpaRepository<Expense, Long>, JpaSpecificationExecutor<Expense> { public interface ExpenseRepository extends JpaRepository<Expense, Long>, JpaSpecificationExecutor<Expense> {
@Query("SELECT e FROM Expense e JOIN e.creditors c WHERE c.id = :personId") // Find expenses where the creditor is a specific person
@Query("SELECT e FROM Expense e WHERE e.creditor.id = :personId")
Set<Expense> findCreditorsExpensesByPersonId(@Param("personId") Long personId); Set<Expense> findCreditorsExpensesByPersonId(@Param("personId") Long personId);
@Query("SELECT e FROM Expense e JOIN e.debtors d WHERE d.id = :personId") // Find expenses where the debtor is a specific person
@Query("SELECT e FROM Expense e WHERE e.debtor.id = :personId")
Set<Expense> findDebtorsExpensesByPersonId(@Param("personId") Long personId); Set<Expense> findDebtorsExpensesByPersonId(@Param("personId") Long personId);
// Find all expenses for a given year
@Query("SELECT e FROM Expense e WHERE YEAR(e.date) = :year") @Query("SELECT e FROM Expense e WHERE YEAR(e.date) = :year")
List<Expense> findAllByYear(@Param("year") int year); List<Expense> findAllByYear(@Param("year") int year);
@Query("SELECT e FROM Expense e JOIN e.creditors c WHERE c.id = :personId AND e.isPaid = false") // Find unpaid expenses where the creditor is a specific person
@Query("SELECT e FROM Expense e WHERE e.creditor.id = :personId AND e.isPaid = false")
Set<Expense> findUnpaidCreditorsExpensesByPersonId(@Param("personId") Long personId); Set<Expense> findUnpaidCreditorsExpensesByPersonId(@Param("personId") Long personId);
@Query("SELECT e FROM Expense e JOIN e.debtors d WHERE d.id = :personId AND e.isPaid = false") // Find unpaid expenses where the debtor is a specific person
@Query("SELECT e FROM Expense e WHERE e.debtor.id = :personId AND e.isPaid = false")
Set<Expense> findUnpaidDebtorsExpensesByPersonId(@Param("personId") Long personId); Set<Expense> findUnpaidDebtorsExpensesByPersonId(@Param("personId") Long personId);
// Find expenses for a given year and filter by expense type and paid status
@Query("SELECT e FROM Expense e WHERE YEAR(e.date) = :year AND NOT (e.expenseType = :expenseType AND e.isPaid = true)") @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); List<Expense> findByYearAndFilterCreditPaid(@Param("year") int year, @Param("expenseType") ExpenseType expenseType);
// Check if an expense with the given ID exists and is paid
boolean existsByIdAndIsPaidTrue(Long id); boolean existsByIdAndIsPaidTrue(Long id);
List<Expense> findAllByOrderByDateDesc();} // Find all expenses ordered by date descending
List<Expense> findAllByOrderByDateDesc();
}

View file

@ -13,6 +13,7 @@ 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;
@ -140,14 +141,21 @@ public class ExpenseService {
* @param expense the expense to set the type of * @param expense the expense to set the type of
*/ */
private void setExpenseType(final @Nonnull Expense expense) { private void setExpenseType(final @Nonnull Expense expense) {
if (!expense.getCreditors().isEmpty()) // Check if the creditor is present
// If creditors are present, set type to CREDIT if (Objects.nonNull(expense.getCreditor())) {
// If creditor is present, set type to CREDIT
expense.setExpenseType(ExpenseType.CREDIT); expense.setExpenseType(ExpenseType.CREDIT);
else if (!expense.getDebtors().isEmpty()) }
// If debtors are present and no creditors, set type to DEBIT // Check if the debtor is present and no creditor
else if (Objects.nonNull(expense.getDebtor())) {
// If debtor is present and no creditor, set type to DEBIT
expense.setExpenseType(ExpenseType.DEBIT); expense.setExpenseType(ExpenseType.DEBIT);
else }
// If neither creditors nor debtors are present, set type to NONE // If neither creditor nor debtor is present
else {
// If neither creditor nor debtor is present, set type to NONE
expense.setExpenseType(ExpenseType.NONE); expense.setExpenseType(ExpenseType.NONE);
} }
} }
}

View file

@ -8,7 +8,6 @@ import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.Checkbox; import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.combobox.MultiSelectComboBox;
import com.vaadin.flow.component.datepicker.DatePicker; import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.Uses; import com.vaadin.flow.component.dependency.Uses;
import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.formlayout.FormLayout;
@ -31,10 +30,8 @@ import jakarta.annotation.security.PermitAll;
import org.springframework.orm.ObjectOptimisticLockingFailureException; import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.vaadin.klaudeta.PaginatedGrid; import org.vaadin.klaudeta.PaginatedGrid;
import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
@PermitAll @PermitAll
@PageTitle("Expenses") @PageTitle("Expenses")
@ -69,9 +66,10 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
private ComboBox<PeriodUnit> periodUnit; private ComboBox<PeriodUnit> periodUnit;
private TextField periodInterval; private TextField periodInterval;
private DatePicker date; private DatePicker date;
private MultiSelectComboBox<Person> creditors; private ComboBox<Person> creditor;
private MultiSelectComboBox<Person> debtors; private ComboBox<Person> debtor;
private ComboBox<Event> event; private ComboBox<Event> event;
public ExpensesView(ExpenseService expenseService, CategoryService categoryService, PersonService personService, EventService eventService, ViewService viewService) { public ExpensesView(ExpenseService expenseService, CategoryService categoryService, PersonService personService, EventService eventService, ViewService viewService) {
this.expenseService = expenseService; this.expenseService = expenseService;
this.categoryService = categoryService; this.categoryService = categoryService;
@ -155,21 +153,22 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
} }
}); });
// Event listeners that will remove the selected creditors from the debtors list and vice versa //TODO: THIS NEEDS TO BE IMPLEMENTED BUT FOR THE SINGLE PERSON NOW, STILL NEEDED
// Done so that the user cant create an expense with the same person as creditor and debtor // // Event listeners that will remove the selected creditors from the debtors list and vice versa
debtors.addValueChangeListener(event -> { // // Done so that the user cant create an expense with the same person as creditor and debtor
Set<Person> selectedDebtors = event.getValue(); // debtors.addValueChangeListener(event -> {
final var creditorsSet = new HashSet<>(personService.findAll()); // Set<Person> selectedDebtors = event.getValue();
creditorsSet.removeIf(selectedDebtors::contains); // final var creditorsSet = new HashSet<>(personService.findAll());
creditors.setItems(creditorsSet); // creditorsSet.removeIf(selectedDebtors::contains);
}); // creditors.setItems(creditorsSet);
// });
creditors.addValueChangeListener(event -> { //
Set<Person> selectedCreditors = event.getValue(); // creditors.addValueChangeListener(event -> {
final var debtorsSet = new HashSet<>(personService.findAll()); // Set<Person> selectedCreditors = event.getValue();
debtorsSet.removeIf(selectedCreditors::contains); // final var debtorsSet = new HashSet<>(personService.findAll());
debtors.setItems(debtorsSet); // debtorsSet.removeIf(selectedCreditors::contains);
}); // debtors.setItems(debtorsSet);
// });
cancel.addClickListener(e -> { cancel.addClickListener(e -> {
clearForm(); clearForm();
@ -205,7 +204,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
UI.getCurrent().navigate(ExpensesView.class); UI.getCurrent().navigate(ExpensesView.class);
} catch (ObjectOptimisticLockingFailureException exception) { } catch (ObjectOptimisticLockingFailureException exception) {
Notification n = Notification.show( Notification n = Notification.show(
"Error updating the data. Somebody else has updated the record while you were making changes."); "Error deleting the data. Somebody else has updated the record while you were making changes.");
n.setPosition(Position.MIDDLE); n.setPosition(Position.MIDDLE);
n.addThemeVariants(NotificationVariant.LUMO_ERROR); n.addThemeVariants(NotificationVariant.LUMO_ERROR);
} }
@ -248,15 +247,15 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
periodUnit = new ComboBox<>("Period Unit"); periodUnit = new ComboBox<>("Period Unit");
periodUnit.setItems(PeriodUnit.values()); periodUnit.setItems(PeriodUnit.values());
periodInterval = new TextField("Period Interval"); periodInterval = new TextField("Period Interval");
creditors = new MultiSelectComboBox<>("Creditors"); creditor = new ComboBox<>("Creditor");
creditors.setItems(personService.findAll()); creditor.setItems(personService.findAll());
creditors.setItemLabelGenerator(Person::getFirstName); creditor.setItemLabelGenerator(Person::getFirstName);
event = new ComboBox<>("Event"); event = new ComboBox<>("Event");
event.setItems(eventService.findAll()); event.setItems(eventService.findAll());
event.setItemLabelGenerator(Event::getName); event.setItemLabelGenerator(Event::getName);
debtors = new MultiSelectComboBox<>("Debtors"); debtor = new ComboBox<>("Debtor");
debtors.setItems(personService.findAll()); debtor.setItems(personService.findAll());
debtors.setItemLabelGenerator(Person::getFirstName); debtor.setItemLabelGenerator(Person::getFirstName);
date = new DatePicker("Date"); date = new DatePicker("Date");
// Horizontal layout for checkboxes // Horizontal layout for checkboxes
@ -265,7 +264,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
isPaid = new Checkbox("Paid"); isPaid = new Checkbox("Paid");
checkboxLayout.add(isPeriodic, isPaid); checkboxLayout.add(isPeriodic, isPaid);
formLayout.add(name, cost, category, description, checkboxLayout, periodUnit, periodInterval, date, creditors, debtors, event); formLayout.add(name, cost, category, description, checkboxLayout, periodUnit, periodInterval, date, creditor, debtor, event);
editorDiv.add(formLayout); editorDiv.add(formLayout);
createButtonLayout(editorLayoutDiv); createButtonLayout(editorLayoutDiv);
@ -305,5 +304,9 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
boolean isPeriodicChecked = (value != null) && value.getIsPeriodic(); boolean isPeriodicChecked = (value != null) && value.getIsPeriodic();
periodUnit.setVisible(isPeriodicChecked); periodUnit.setVisible(isPeriodicChecked);
periodInterval.setVisible(isPeriodicChecked); periodInterval.setVisible(isPeriodicChecked);
// Set selected items for creditor and debtor
creditor.setValue(value != null ? value.getCreditor() : null);
debtor.setValue(value != null ? value.getDebtor() : null);
} }
} }