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

View file

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

View file

@ -13,24 +13,33 @@ import java.util.Set;
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);
@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);
// Find all expenses for a given year
@Query("SELECT e FROM Expense e WHERE YEAR(e.date) = :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);
@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);
// 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)")
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);
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.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
@ -140,14 +141,21 @@ public class ExpenseService {
* @param expense the expense to set the type of
*/
private void setExpenseType(final @Nonnull Expense expense) {
if (!expense.getCreditors().isEmpty())
// If creditors are present, set type to CREDIT
// Check if the creditor is present
if (Objects.nonNull(expense.getCreditor())) {
// If creditor is present, set type to 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);
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);
}
}
}

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.checkbox.Checkbox;
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.dependency.Uses;
import com.vaadin.flow.component.formlayout.FormLayout;
@ -31,10 +30,8 @@ import jakarta.annotation.security.PermitAll;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.vaadin.klaudeta.PaginatedGrid;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@PermitAll
@PageTitle("Expenses")
@ -69,9 +66,10 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
private ComboBox<PeriodUnit> periodUnit;
private TextField periodInterval;
private DatePicker date;
private MultiSelectComboBox<Person> creditors;
private MultiSelectComboBox<Person> debtors;
private ComboBox<Person> creditor;
private ComboBox<Person> debtor;
private ComboBox<Event> event;
public ExpensesView(ExpenseService expenseService, CategoryService categoryService, PersonService personService, EventService eventService, ViewService viewService) {
this.expenseService = expenseService;
this.categoryService = categoryService;
@ -102,7 +100,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
grid.setItems(this.expenseService.findAllOrderByDateDescending());
grid.setPaginatorSize(5);
grid.setPageSize(22); // setting page size
grid.setPageSize(22); // setting page size
grid.addThemeVariants(GridVariant.LUMO_NO_BORDER);
// when a row is selected or deselected, populate form
@ -125,7 +123,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
binder.forField(cost)
.asRequired("Cost is required")
.withConverter( new StringToBigDecimalConverter("Invalid cost"))
.withConverter(new StringToBigDecimalConverter("Invalid cost"))
.bind(Expense::getCost, Expense::setCost);
binder.forField(category)
@ -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
// Done so that the user cant create an expense with the same person as creditor and debtor
debtors.addValueChangeListener(event -> {
Set<Person> selectedDebtors = event.getValue();
final var creditorsSet = new HashSet<>(personService.findAll());
creditorsSet.removeIf(selectedDebtors::contains);
creditors.setItems(creditorsSet);
});
creditors.addValueChangeListener(event -> {
Set<Person> selectedCreditors = event.getValue();
final var debtorsSet = new HashSet<>(personService.findAll());
debtorsSet.removeIf(selectedCreditors::contains);
debtors.setItems(debtorsSet);
});
//TODO: THIS NEEDS TO BE IMPLEMENTED BUT FOR THE SINGLE PERSON NOW, STILL NEEDED
// // Event listeners that will remove the selected creditors from the debtors list and vice versa
// // Done so that the user cant create an expense with the same person as creditor and debtor
// debtors.addValueChangeListener(event -> {
// Set<Person> selectedDebtors = event.getValue();
// final var creditorsSet = new HashSet<>(personService.findAll());
// creditorsSet.removeIf(selectedDebtors::contains);
// creditors.setItems(creditorsSet);
// });
//
// creditors.addValueChangeListener(event -> {
// Set<Person> selectedCreditors = event.getValue();
// final var debtorsSet = new HashSet<>(personService.findAll());
// debtorsSet.removeIf(selectedCreditors::contains);
// debtors.setItems(debtorsSet);
// });
cancel.addClickListener(e -> {
clearForm();
@ -205,7 +204,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
UI.getCurrent().navigate(ExpensesView.class);
} catch (ObjectOptimisticLockingFailureException exception) {
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.addThemeVariants(NotificationVariant.LUMO_ERROR);
}
@ -218,7 +217,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
if (expenseId.isPresent()) {
Optional<Expense> expenseFromBackend = expenseService.get(expenseId.get());
if (expenseFromBackend.isPresent()) populateForm(expenseFromBackend.get());
else {
else {
Notification.show(
String.format("The requested expense was not found, ID = %s", expenseId.get()), 3000,
Notification.Position.BOTTOM_START);
@ -248,15 +247,15 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
periodUnit = new ComboBox<>("Period Unit");
periodUnit.setItems(PeriodUnit.values());
periodInterval = new TextField("Period Interval");
creditors = new MultiSelectComboBox<>("Creditors");
creditors.setItems(personService.findAll());
creditors.setItemLabelGenerator(Person::getFirstName);
creditor = new ComboBox<>("Creditor");
creditor.setItems(personService.findAll());
creditor.setItemLabelGenerator(Person::getFirstName);
event = new ComboBox<>("Event");
event.setItems(eventService.findAll());
event.setItemLabelGenerator(Event::getName);
debtors = new MultiSelectComboBox<>("Debtors");
debtors.setItems(personService.findAll());
debtors.setItemLabelGenerator(Person::getFirstName);
debtor = new ComboBox<>("Debtor");
debtor.setItems(personService.findAll());
debtor.setItemLabelGenerator(Person::getFirstName);
date = new DatePicker("Date");
// Horizontal layout for checkboxes
@ -265,7 +264,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
isPaid = new Checkbox("Paid");
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);
createButtonLayout(editorLayoutDiv);
@ -305,5 +304,9 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
boolean isPeriodicChecked = (value != null) && value.getIsPeriodic();
periodUnit.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);
}
}