fix: major changes
This commit is contained in:
parent
6475f83dd8
commit
50a0325341
7 changed files with 224 additions and 136 deletions
|
@ -13,7 +13,7 @@ import java.time.LocalDateTime;
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@Table(name = "expenses")
|
@Table(name = "expenses")
|
||||||
public class Expense extends AbstractEntity {
|
public class Expense {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@ -46,11 +46,11 @@ public class Expense extends AbstractEntity {
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "CreditorId")
|
@JoinColumn(name = "CreditorId")
|
||||||
private Person creditor;
|
private Person payer;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "DebtorId")
|
@JoinColumn(name = "DebtorId")
|
||||||
private Person debtor;
|
private Person beneficiary;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "EventId")
|
@JoinColumn(name = "EventId")
|
||||||
|
|
|
@ -40,11 +40,12 @@ public class Person extends AbstractEntity {
|
||||||
@Column(name = "credit")
|
@Column(name = "credit")
|
||||||
private BigDecimal credit;
|
private BigDecimal credit;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "creditor")
|
// Updated to match the new field names in Expense
|
||||||
private Set<Expense> creditExpenses;
|
@OneToMany(mappedBy = "payer")
|
||||||
|
private Set<Expense> expensesAsPayer;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "debtor")
|
@OneToMany(mappedBy = "beneficiary")
|
||||||
private Set<Expense> debtExpenses;
|
private Set<Expense> expensesAsBeneficiary;
|
||||||
|
|
||||||
@ManyToMany(mappedBy = "participants")
|
@ManyToMany(mappedBy = "participants")
|
||||||
private Set<Event> events;
|
private Set<Event> events;
|
||||||
|
|
|
@ -14,24 +14,24 @@ import java.util.Set;
|
||||||
public interface ExpenseRepository extends JpaRepository<Expense, Long>, JpaSpecificationExecutor<Expense> {
|
public interface ExpenseRepository extends JpaRepository<Expense, Long>, JpaSpecificationExecutor<Expense> {
|
||||||
|
|
||||||
// Find expenses where the creditor is a specific person
|
// Find expenses where the creditor is a specific person
|
||||||
@Query("SELECT e FROM Expense e WHERE e.creditor.id = :personId")
|
@Query("SELECT e FROM Expense e WHERE e.payer.id = :personId")
|
||||||
Set<Expense> findCreditorsExpensesByPersonId(@Param("personId") Long personId);
|
Set<Expense> findExpensesByPayer(@Param("personId") Long personId);
|
||||||
|
|
||||||
// Find expenses where the debtor is a specific person
|
// Find expenses where the debtor is a specific person
|
||||||
@Query("SELECT e FROM Expense e WHERE e.debtor.id = :personId")
|
@Query("SELECT e FROM Expense e WHERE e.beneficiary.id = :personId")
|
||||||
Set<Expense> findDebtorsExpensesByPersonId(@Param("personId") Long personId);
|
Set<Expense> findExpensesByBeneficiary(@Param("personId") Long personId);
|
||||||
|
|
||||||
// Find all expenses for a given year
|
// 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);
|
||||||
|
|
||||||
// Find unpaid expenses where the creditor is a specific person
|
// 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")
|
@Query("SELECT e FROM Expense e WHERE e.payer.id = :personId AND e.isPaid = false")
|
||||||
Set<Expense> findUnpaidCreditorsExpensesByPersonId(@Param("personId") Long personId);
|
Set<Expense> findUnpaidExpensesByPayer(@Param("personId") Long personId);
|
||||||
|
|
||||||
// Find unpaid expenses where the debtor is a specific person
|
// 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")
|
@Query("SELECT e FROM Expense e WHERE e.beneficiary.id = :personId AND e.isPaid = false")
|
||||||
Set<Expense> findUnpaidDebtorsExpensesByPersonId(@Param("personId") Long personId);
|
Set<Expense> findUnapidExpensesByBeneficiary(@Param("personId") Long personId);
|
||||||
|
|
||||||
// Find expenses for a given year and filter by expense type and paid status
|
// 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)")
|
||||||
|
|
|
@ -26,99 +26,102 @@ public class ExpenseService {
|
||||||
this.expenseRepository = expenseRepository;
|
this.expenseRepository = expenseRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an expense by its ID.
|
||||||
|
* @param id the ID of the expense
|
||||||
|
* @return an Optional containing the expense if found, otherwise empty
|
||||||
|
*/
|
||||||
public Optional<Expense> get(Long id) {
|
public Optional<Expense> get(Long id) {
|
||||||
return expenseRepository.findById(id);
|
return expenseRepository.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finds all expenses tagged as debit given a user
|
* Finds all expenses where the specified person is the beneficiary.
|
||||||
* @param person the user of the expenses
|
* @param person the user of the expenses
|
||||||
* @return the collections of expenses found
|
* @return the collection of expenses found
|
||||||
*/
|
*/
|
||||||
public Collection<Expense> findDebtByUser(final Person person) {
|
public Collection<Expense> findExpensesWhereBeneficiary(final Person person) {
|
||||||
return expenseRepository.findDebtorsExpensesByPersonId(person.getId());
|
return expenseRepository.findExpensesByBeneficiary(person.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finds all expenses tagged as credit given a user
|
* Finds all expenses where the specified person is the payer.
|
||||||
* @param person the user of the expenses
|
* @param person the user of the expenses
|
||||||
* @return the collections of expenses found
|
* @return the collection of expenses found
|
||||||
*/
|
*/
|
||||||
public Collection<Expense> findCreditByUser(final Person person) {
|
public Collection<Expense> findExpensesWherePayer(final Person person) {
|
||||||
return expenseRepository.findCreditorsExpensesByPersonId(person.getId());
|
return expenseRepository.findExpensesByPayer(person.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finds all expenses tagged as debit and unpaid given a user
|
* Finds all expenses where the specified person is the beneficiary and the expense is unpaid.
|
||||||
* @param person the user of the expenses
|
* @param person the user of the expenses
|
||||||
* @return the collections of expenses found
|
* @return the collection of unpaid expenses found
|
||||||
*/
|
*/
|
||||||
public Collection<Expense> findUnpaidDebtByUser(final Person person) {
|
public Collection<Expense> findUnpaidExpensesWhereBeneficiary(final Person person) {
|
||||||
return expenseRepository.findUnpaidDebtorsExpensesByPersonId(person.getId());
|
return expenseRepository.findUnapidExpensesByBeneficiary(person.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finds all expenses tagged as credit and unpaid given a user
|
* Finds all expenses where the specified person is the payer and the expense is unpaid.
|
||||||
* @param person the user of the expenses
|
* @param person the user of the expenses
|
||||||
* @return the collections of expenses found
|
* @return the collection of unpaid expenses found
|
||||||
*/
|
*/
|
||||||
public Collection<Expense> findUnpaidCreditByUser(final Person person) {
|
public Collection<Expense> findUnpaidExpensesWherePayer(final Person person) {
|
||||||
return expenseRepository.findUnpaidCreditorsExpensesByPersonId(person.getId());
|
return expenseRepository.findUnpaidExpensesByPayer(person.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finds all expenses related to a user
|
* Finds all expenses related to a user, both where the user is a payer and a beneficiary.
|
||||||
* @param person the user of the expenses
|
* @param person the user of the expenses
|
||||||
* @return the collections of expenses found
|
* @return the list of expenses found
|
||||||
*/
|
*/
|
||||||
public List<Expense> findExpenseByUser(final Person person) {
|
public List<Expense> findExpensesByUser(final Person person) {
|
||||||
final var credits = this.findCreditByUser(person);
|
// Retrieve expenses where the person is the payer
|
||||||
final var debits = this.findDebtByUser(person);
|
final var payerExpenses = this.findExpensesWherePayer(person);
|
||||||
return Stream.concat(credits.stream(), debits.stream()).toList();
|
// Retrieve expenses where the person is the beneficiary
|
||||||
|
final var beneficiaryExpenses = this.findExpensesWhereBeneficiary(person);
|
||||||
|
// Combine both sets of expenses into a single list without duplicates
|
||||||
|
return Stream.concat(payerExpenses.stream(), beneficiaryExpenses.stream())
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Expense> findAll() {return expenseRepository.findAll();}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* updates an expense
|
* Retrieves all expenses.
|
||||||
* @param entity the expense to update
|
* @return the list of all expenses
|
||||||
*/
|
*/
|
||||||
public void update(Expense entity) {
|
public List<Expense> findAll() {
|
||||||
if (Boolean.TRUE.equals(entity.getIsPaid())) entity.setPaymentDate(LocalDateTime.now());
|
return expenseRepository.findAll();
|
||||||
this.setExpenseType(entity);
|
|
||||||
expenseRepository.save(entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* deletes an expense given the ID
|
* Finds all expenses for a given year.
|
||||||
* @param id the id of the expense to delete
|
* @param year the year for which to find expenses
|
||||||
|
* @return the list of expenses found
|
||||||
*/
|
*/
|
||||||
public void delete(Long id) {
|
public List<Expense> findAllByYear(final int year) {
|
||||||
expenseRepository.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Page<Expense> list(Pageable pageable) {
|
|
||||||
return expenseRepository.findAll(pageable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Page<Expense> list(Pageable pageable, Specification<Expense> filter) {
|
|
||||||
return expenseRepository.findAll(filter, pageable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int count() {
|
|
||||||
return (int) expenseRepository.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Expense> findAllByYear(final int year ) {
|
|
||||||
return this.expenseRepository.findAllByYear(year);
|
return this.expenseRepository.findAllByYear(year);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all expenses ordered by date in descending order.
|
||||||
|
* @return the list of expenses found
|
||||||
|
*/
|
||||||
|
public List<Expense> findAllOrderByDateDescending() {
|
||||||
|
return this.expenseRepository.findAllByOrderByDateDesc();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds expenses by year excluding those marked as credit and paid.
|
||||||
|
* @param year the year for which to find expenses
|
||||||
|
* @return the list of expenses found
|
||||||
|
*/
|
||||||
public List<Expense> findExpensesByYearExcludingCreditPaid(int year) {
|
public List<Expense> findExpensesByYearExcludingCreditPaid(int year) {
|
||||||
return expenseRepository.findByYearAndFilterCreditPaid(year, ExpenseType.CREDIT);
|
return expenseRepository.findByYearAndFilterCreditPaid(year, ExpenseType.CREDIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* checks if an expense has been paid
|
* Checks if an expense has been paid.
|
||||||
* @param expense the expense to check
|
* @param expense the expense to check
|
||||||
* @return true if the expense has been paid, false otherwise
|
* @return true if the expense has been paid, false otherwise
|
||||||
*/
|
*/
|
||||||
|
@ -127,35 +130,76 @@ public class ExpenseService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fetches all expenses ordered by date descending
|
* Updates an existing expense.
|
||||||
* @return the list of expenses found
|
* @param entity the expense to update
|
||||||
*/
|
*/
|
||||||
public List<Expense> findAllOrderByDateDescending() {
|
public void update(Expense entity) {
|
||||||
return this.expenseRepository.findAllByOrderByDateDesc();
|
if (Boolean.TRUE.equals(entity.getIsPaid())) {
|
||||||
|
entity.setPaymentDate(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
this.setExpenseType(entity);
|
||||||
|
expenseRepository.save(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the Expense type depending on the presence or absence of creditors and debtors
|
* Deletes an expense given its ID.
|
||||||
* this is used to filter expenses with a creditor that are paid, since they are not part of
|
* @param id the ID of the expense to delete
|
||||||
* the actual money the user has spent, it's just a load technically
|
*/
|
||||||
|
public void delete(Long id) {
|
||||||
|
expenseRepository.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists expenses in a paginated format.
|
||||||
|
* @param pageable the pagination information
|
||||||
|
* @return a page of expenses
|
||||||
|
*/
|
||||||
|
public Page<Expense> list(Pageable pageable) {
|
||||||
|
return expenseRepository.findAll(pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists expenses in a paginated format with filtering options.
|
||||||
|
* @param pageable the pagination information
|
||||||
|
* @param filter the filter specification
|
||||||
|
* @return a page of expenses matching the filter
|
||||||
|
*/
|
||||||
|
public Page<Expense> list(Pageable pageable, Specification<Expense> filter) {
|
||||||
|
return expenseRepository.findAll(filter, pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the total number of expenses.
|
||||||
|
* @return the count of expenses
|
||||||
|
*/
|
||||||
|
public int count() {
|
||||||
|
return (int) expenseRepository.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// Private methods
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the expense type depending on the presence or absence of a payer and beneficiary.
|
||||||
|
* This is used to filter expenses where the payer has been reimbursed.
|
||||||
* @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) {
|
||||||
// Check if the creditor is present
|
// Check if the payer is present
|
||||||
if (Objects.nonNull(expense.getCreditor())) {
|
if (Objects.nonNull(expense.getPayer())) {
|
||||||
// If creditor is present, set type to CREDIT
|
// If payer is present, set type to CREDIT
|
||||||
expense.setExpenseType(ExpenseType.CREDIT);
|
expense.setExpenseType(ExpenseType.CREDIT);
|
||||||
}
|
}
|
||||||
// Check if the debtor is present and no creditor
|
// Check if the beneficiary is present and no payer
|
||||||
else if (Objects.nonNull(expense.getDebtor())) {
|
else if (Objects.nonNull(expense.getBeneficiary())) {
|
||||||
// If debtor is present and no creditor, set type to DEBIT
|
// If beneficiary is present and no payer, set type to DEBIT
|
||||||
expense.setExpenseType(ExpenseType.DEBIT);
|
expense.setExpenseType(ExpenseType.DEBIT);
|
||||||
}
|
}
|
||||||
// If neither creditor nor debtor is present
|
// If neither payer nor beneficiary is present
|
||||||
else {
|
else {
|
||||||
// If neither creditor nor debtor is present, set type to NONE
|
// Set type to NONE
|
||||||
expense.setExpenseType(ExpenseType.NONE);
|
expense.setExpenseType(ExpenseType.NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -9,7 +9,7 @@ import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Collection;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -23,60 +23,108 @@ public class PersonService {
|
||||||
this.expenseService = expenseService;
|
this.expenseService = expenseService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a person by ID.
|
||||||
|
* @param id the ID of the person
|
||||||
|
* @return an optional containing the person if found, otherwise empty
|
||||||
|
*/
|
||||||
public Optional<Person> get(Long id) {
|
public Optional<Person> get(Long id) {
|
||||||
return personRepository.findById(id);
|
return personRepository.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Person> findAll() {
|
/**
|
||||||
|
* Finds all persons.
|
||||||
|
* @return a collection of all persons
|
||||||
|
*/
|
||||||
|
public List<Person> findAll() {
|
||||||
return this.personRepository.findAll();
|
return this.personRepository.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(Person person) {
|
/**
|
||||||
this.personRepository.save(person);
|
* Lists all persons with pagination.
|
||||||
}
|
* @param pageable the pagination information
|
||||||
|
* @return a page of persons
|
||||||
public void delete(Long id) {
|
*/
|
||||||
this.personRepository.deleteById(id);
|
public Page<Person> list(Pageable pageable) {
|
||||||
}
|
|
||||||
|
|
||||||
public Page<Person> list(Pageable pageable){
|
|
||||||
return personRepository.findAll(pageable);
|
return personRepository.findAll(pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all persons with pagination and filtering.
|
||||||
|
* @param pageable the pagination information
|
||||||
|
* @param filter the specification filter
|
||||||
|
* @return a page of persons matching the filter
|
||||||
|
*/
|
||||||
public Page<Person> list(Pageable pageable, Specification<Person> filter) {
|
public Page<Person> list(Pageable pageable, Specification<Person> filter) {
|
||||||
return this.personRepository.findAll(filter, pageable);
|
return this.personRepository.findAll(filter, pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the total number of persons.
|
||||||
|
* @return the total count of persons
|
||||||
|
*/
|
||||||
public int count() {
|
public int count() {
|
||||||
return (int) this.personRepository.count();
|
return (int) this.personRepository.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* calculates the debt a certain person has
|
* Updates a person in the repository.
|
||||||
* @param person the person of which you want to know the debt
|
* @param person the person to update
|
||||||
* @return the debt that a certain person has
|
|
||||||
*/
|
*/
|
||||||
public BigDecimal calculateDebt(final Person person){
|
public void update(Person person) {
|
||||||
return this.expenseService.findDebtByUser(person).stream().map(Expense::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);
|
this.personRepository.save(person);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* calculates the credit a certain person has
|
* Deletes a person by ID.
|
||||||
* @param person the person of which you want to know the credit
|
* @param id the ID of the person to delete
|
||||||
* @return the credit that a certain person has
|
*/
|
||||||
|
public void delete(Long id) {
|
||||||
|
this.personRepository.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the total debt of a person.
|
||||||
|
* @param person the person whose debt is to be calculated
|
||||||
|
* @return the total debt amount
|
||||||
|
*/
|
||||||
|
public BigDecimal calculateDebt(final Person person) {
|
||||||
|
return this.expenseService.findExpensesWherePayer(person).stream()
|
||||||
|
.filter(expense -> !expense.getBeneficiary().equals(person) && Boolean.FALSE.equals(expense.getIsPaid()))
|
||||||
|
.map(Expense::getCost)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the total credit of a person.
|
||||||
|
* @param person the person whose credit is to be calculated
|
||||||
|
* @return the total credit amount
|
||||||
*/
|
*/
|
||||||
public BigDecimal calculateCredit(final Person person) {
|
public BigDecimal calculateCredit(final Person person) {
|
||||||
return this.expenseService.findCreditByUser(person).stream().map(Expense::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);
|
return this.expenseService.findExpensesWhereBeneficiary(person).stream()
|
||||||
|
.filter(expense -> !expense.getPayer().equals(person) && Boolean.FALSE.equals(expense.getIsPaid()))
|
||||||
|
.map(Expense::getCost)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* calculates the balance of a person using the money owed or paid off to that person
|
* Calculates the net balance of a person.
|
||||||
* @param person the person of which you want to know the balance
|
* The net balance is the difference between the total amount the person is owed
|
||||||
* @return the amount of money owed or paid off to a certain person
|
* (expenses where they are the payer) and the total amount the person owes
|
||||||
|
* (expenses where they are the beneficiary).
|
||||||
|
*
|
||||||
|
* A positive net balance means the person is owed money.
|
||||||
|
* A negative net balance means the person owes money.
|
||||||
|
*
|
||||||
|
* @param person the person whose net balance is to be calculated
|
||||||
|
* @return the net balance amount
|
||||||
*/
|
*/
|
||||||
public BigDecimal calculateNetBalance(final Person person) {
|
public BigDecimal calculateNetBalance(final Person person) {
|
||||||
final var credit = this.expenseService.findUnpaidCreditByUser(person).stream().map(Expense::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);
|
// Calculate total debt (what others owe to the person)
|
||||||
final var debit = this.expenseService.findUnpaidDebtByUser(person).stream().map(Expense::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);
|
final BigDecimal debt = this.calculateDebt(person);
|
||||||
return credit.subtract(debit);
|
// Calculate total credit (what the person owes to others)
|
||||||
|
final BigDecimal credit = this.calculateCredit(person);
|
||||||
|
// Net balance calculation: debt (owed to the person) - credit (person owes)
|
||||||
|
return debt.subtract(credit);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -66,8 +66,8 @@ 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 ComboBox<Person> creditor;
|
private ComboBox<Person> payer;
|
||||||
private ComboBox<Person> debtor;
|
private ComboBox<Person> beneficiary;
|
||||||
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) {
|
||||||
|
@ -94,7 +94,6 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
|
||||||
grid.addColumn(Expense::getPeriodUnit).setHeader("Period Unit").setSortable(true);
|
grid.addColumn(Expense::getPeriodUnit).setHeader("Period Unit").setSortable(true);
|
||||||
grid.addColumn(Expense::getDate).setHeader("Date").setSortable(true).setSortProperty("date");
|
grid.addColumn(Expense::getDate).setHeader("Date").setSortable(true).setSortProperty("date");
|
||||||
// grid.addColumn(expenseEvent -> expenseEvent.getEvent().getName()).setHeader("Event").setSortable(true);
|
// grid.addColumn(expenseEvent -> expenseEvent.getEvent().getName()).setHeader("Event").setSortable(true);
|
||||||
|
|
||||||
grid.addColumn(new ComponentRenderer<>(this.viewService::createExpenseBadge)).setHeader("Status").setSortable(true);
|
grid.addColumn(new ComponentRenderer<>(this.viewService::createExpenseBadge)).setHeader("Status").setSortable(true);
|
||||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||||
|
|
||||||
|
@ -156,11 +155,11 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
|
||||||
//TODO: THIS NEEDS TO BE IMPLEMENTED BUT FOR THE SINGLE PERSON NOW, STILL NEEDED
|
//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
|
// // 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
|
// // Done so that the user cant create an expense with the same person as creditor and debtor
|
||||||
// debtors.addValueChangeListener(event -> {
|
// payer.addValueChangeListener(event -> {
|
||||||
// Set<Person> selectedDebtors = event.getValue();
|
// Person selectedDebtors = event.getValue();
|
||||||
// final var creditorsSet = new HashSet<>(personService.findAll());
|
// final var creditorsSet = new HashSet<>(personService.findAll());
|
||||||
// creditorsSet.removeIf(selectedDebtors::contains);
|
// creditorsSet.removeIf(creditorsSet.contains(selectedDebtors));
|
||||||
// creditors.setItems(creditorsSet);
|
// payer.setItems(creditorsSet);
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// creditors.addValueChangeListener(event -> {
|
// creditors.addValueChangeListener(event -> {
|
||||||
|
@ -232,10 +231,10 @@ public class ExpensesView extends Div implements BeforeEnterObserver {
|
||||||
private void createEditorLayout(SplitLayout splitLayout) {
|
private void createEditorLayout(SplitLayout splitLayout) {
|
||||||
Div editorLayoutDiv = new Div();
|
Div editorLayoutDiv = new Div();
|
||||||
editorLayoutDiv.setClassName("editor-layout");
|
editorLayoutDiv.setClassName("editor-layout");
|
||||||
|
|
||||||
Div editorDiv = new Div();
|
Div editorDiv = new Div();
|
||||||
editorDiv.setClassName("editor");
|
editorDiv.setClassName("editor");
|
||||||
editorLayoutDiv.add(editorDiv);
|
editorLayoutDiv.add(editorDiv);
|
||||||
|
final var people = this.personService.findAll();
|
||||||
|
|
||||||
FormLayout formLayout = new FormLayout();
|
FormLayout formLayout = new FormLayout();
|
||||||
name = new TextField("Name");
|
name = new TextField("Name");
|
||||||
|
@ -247,15 +246,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");
|
||||||
creditor = new ComboBox<>("Creditor");
|
payer = new ComboBox<>("Payer");
|
||||||
creditor.setItems(personService.findAll());
|
payer.setItems(people);
|
||||||
creditor.setItemLabelGenerator(Person::getFirstName);
|
payer.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);
|
||||||
debtor = new ComboBox<>("Debtor");
|
beneficiary = new ComboBox<>("Beneficiary");
|
||||||
debtor.setItems(personService.findAll());
|
beneficiary.setItems(people);
|
||||||
debtor.setItemLabelGenerator(Person::getFirstName);
|
beneficiary.setItemLabelGenerator(Person::getFirstName);
|
||||||
date = new DatePicker("Date");
|
date = new DatePicker("Date");
|
||||||
|
|
||||||
// Horizontal layout for checkboxes
|
// Horizontal layout for checkboxes
|
||||||
|
@ -264,7 +263,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, creditor, debtor, event);
|
formLayout.add(name, cost, category, description, checkboxLayout, periodUnit, periodInterval, date, payer, beneficiary, event);
|
||||||
editorDiv.add(formLayout);
|
editorDiv.add(formLayout);
|
||||||
createButtonLayout(editorLayoutDiv);
|
createButtonLayout(editorLayoutDiv);
|
||||||
|
|
||||||
|
@ -304,9 +303,5 @@ 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -83,9 +83,9 @@ public class PeopleView extends Div implements BeforeEnterObserver {
|
||||||
else return this.viewService.createExpenseBadge(((Expense) persona));
|
else return this.viewService.createExpenseBadge(((Expense) persona));
|
||||||
})).setHeader("Balance Status");
|
})).setHeader("Balance Status");
|
||||||
|
|
||||||
grid.addColumn(new ComponentRenderer<>(person -> {
|
grid.addColumn(new ComponentRenderer<>(persona -> {
|
||||||
if (person instanceof Person) {
|
if (persona instanceof Person) {
|
||||||
Button markPaidButton = new Button("Mark All Expenses Paid", event -> markExpensesPaid((Person) person));
|
Button markPaidButton = new Button("Mark All Expenses Paid", event -> markExpensesPaid((Person) persona));
|
||||||
markPaidButton.addThemeVariants(ButtonVariant.LUMO_SMALL, ButtonVariant.LUMO_PRIMARY);
|
markPaidButton.addThemeVariants(ButtonVariant.LUMO_SMALL, ButtonVariant.LUMO_PRIMARY);
|
||||||
return markPaidButton;
|
return markPaidButton;
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,7 +93,7 @@ public class PeopleView extends Div implements BeforeEnterObserver {
|
||||||
}
|
}
|
||||||
})).setHeader("Actions");
|
})).setHeader("Actions");
|
||||||
|
|
||||||
List<Person> people = (List<Person>) personService.findAll();
|
List<Person> people = personService.findAll();
|
||||||
|
|
||||||
this.setGridData(people);
|
this.setGridData(people);
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ public class PeopleView extends Div implements BeforeEnterObserver {
|
||||||
grid.getTreeData().addItem(null, user);
|
grid.getTreeData().addItem(null, user);
|
||||||
|
|
||||||
// Fetch expenses for the current person
|
// Fetch expenses for the current person
|
||||||
List<Expense> expenses = expenseService.findExpenseByUser(user);
|
List<Expense> expenses = expenseService.findExpensesByUser(user);
|
||||||
|
|
||||||
// Add each expense as a child item under the person
|
// Add each expense as a child item under the person
|
||||||
for (Expense expense : expenses) grid.getTreeData().addItem(user, expense);
|
for (Expense expense : expenses) grid.getTreeData().addItem(user, expense);
|
||||||
|
@ -257,7 +257,7 @@ public class PeopleView extends Div implements BeforeEnterObserver {
|
||||||
|
|
||||||
private void markExpensesPaid(Person person) {
|
private void markExpensesPaid(Person person) {
|
||||||
try {
|
try {
|
||||||
List<Expense> expenses = expenseService.findCreditByUser(person).stream().toList();
|
List<Expense> expenses = expenseService.findExpensesWherePayer(person).stream().toList();
|
||||||
for (Expense expense : expenses) {
|
for (Expense expense : expenses) {
|
||||||
expense.setIsPaid(true);
|
expense.setIsPaid(true);
|
||||||
expenseService.update(expense);
|
expenseService.update(expense);
|
||||||
|
|
Loading…
Reference in a new issue