fix: changed Expense relation with Person entity
This commit is contained in:
parent
13d5f1bf29
commit
6475f83dd8
5 changed files with 73 additions and 63 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue