0

I'm curious to find a solution for this but couldn't find anything relatable and useful so far.

Lets say user have two transactions for 18/01/2023

I want to have a heading for example like separate <div> and to pass today date and each transaction from today, and below down for example 15/01/2023 because user also have a transactions on that date.

This is an example, as you can see I have today section because user made a transaction on today date, also for yesterday and then back on January 14, so I want to separate transactions for each that like that. Example

This is Transaction class:

@Entity
@Table(name = "transaction")
public class Transaction {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "transaction_id")
    private Long id;

    @Column(name = "user_id", nullable = false)
    private Long userId;

    @Column(name = "wallet_name", nullable = false)
    private String walletName;

    @NotNull(message = "Please, insert a amount")
    @Min(value = 0, message = "Please, insert a positive amount")
    private Double amount;

    private String note;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Column(name = "date")
    private LocalDate date;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "wallet_id", nullable = false)
    private Wallet wallet;

    @Enumerated(EnumType.STRING)
    @Column(name = "transaction_type", columnDefinition = "ENUM('EXPENSE', 'INCOME')")
    private TransactionType transactionType;

    @Nullable
    @Enumerated(EnumType.STRING)
    @Column(name = "expense_categories", columnDefinition = "ENUM('FOOD_AND_DRINK', 'SHOPPING', 'TRANSPORT', 'HOME'," +
            " 'BILLS_AND_FEES', 'ENTERTAINMENT', 'CAR', 'TRAVEL', 'FAMILY_AND_PERSONAL', 'HEALTHCARE'," +
            " 'EDUCATION', 'GROCERIES', 'GIFTS', 'BEAUTY', 'WORK', 'SPORTS_AND_HOBBIES', 'OTHER')")
    private ExpenseCategories expenseCategories;

    @Nullable
    @Enumerated(EnumType.STRING)
    @Column(name = "income_categories", columnDefinition = "ENUM('SALARY', 'BUSINESS', 'GIFTS', 'EXTRA_INCOME', 'LOAN', 'PARENTAL_LEAVE', 'INSURANCE_PAYOUT', 'OTHER')")
    private IncomeCategories incomeCategories;

I created a new class that will act as group and that is like this:

 class TransactionGroup {
 private LocalDate date;
 private List<Transaction> transactions;
 /* Getters and setters */
 }

And Thymeleaf:

    <div th:each="singleGroup  : ${transactionGroup}">
    <h1 th:text="${singleGroup .date}"></h1>

    <div th:each="singleTrans  : ${singleGroup.transactions}">
        <h2>Amount: <span th:text="${singleTrans .amount}"></span></h2><br>
        <h2>Note: <span th:text="${singleTrans .note}"></span></h2><br>
        <h2>Wallet name: <span th:text="${singleTrans .walletName}"></span></h2><br>
        <h2>Expense Category: <span th:text="${singleTrans .expenseCategories}"></span></h2><br>
        <h2>IncomeCategory: <span th:text="${singleTrans .incomeCategories}"></span></h2>
        <div>
        </div>
    </div>
</div>

And this is controller:

   @GetMapping("/userTransactions/{user_id}")
public String getUserTransactions(@PathVariable("user_id") long user_id, TransactionGroup transactionGroup, Model model) {
    List<Transaction> transactions = transactionRepository.getTransactionsByUserId(user_id);
    //create a TransactionGroup list
    List<TransactionGroup> transactionByDate = new ArrayList<>();
    //create a list that will hold all transactions for a day
    List<Transaction> transOnSingleDate = new ArrayList<>();
    //initialize currDate with the first transaction date
    LocalDate currDate = transactions.get(0).getDate();

    //create a TransactionGroup
    TransactionGroup transGroup = new TransactionGroup();

    //loop through your transactions and populate the wrapper list
    for(Transaction t : transactions){
        //create a new transaction group if the date has changed
        if(!currDate.isEqual(t.getDate())){
            //fill the wrapper list before creating a new list
            transGroup.setDate(currDate);
            transGroup.setTransactions(transOnSingleDate);
            transactionByDate.add(transGroup);
            //create new TransactionGroup and List<Transaction> for a new date
            transGroup = new TransactionGroup();
            transOnSingleDate = new ArrayList<>();
        }

        transOnSingleDate.add( t );
        currDate = t.getDate();
    }
    //add the final list
    transGroup.setDate(currDate);
    transGroup.setTransactions(transOnSingleDate);
    transactionByDate.add(transGroup);
    model.addAttribute("transactionGroup", transactionByDate);
    return "transactions";

}

You can see that I populate here transaction list in TransactionGroup by transactions from entity Transaction:

transactionGroup.setTransactions(transactionService.findDistinctIdByUserId(userId));

And on page I can see transactions, but I cant see a date how I want, I cant even see date, date is not displayed, because I didn't populate a date field on class TransactionGroup with date from Transaction class. How I can get a transaction date from each transaction that is created?

I guess I need to populate it somehow like transactionGroup.setTransactions... but now like transactionGroup.setDate... but Date is not a list type, so there is a problem.

Its obivous that if I try with transactionGroup.setDate(transaction.getDate); returning null

SOUT LOGS:

    transGroup TransactionGroup{date=2023-01-01, transactions=null}
transactionByDate [TransactionGroup{date=2023-03-01, transactions=[Transaction{id=18, userId=1, walletName='Dailyk', amount=4.0, note='Cetvrta transakcija', date=2023-03-01, wallet=com.budgettracker.demo.userProfile.models.Wallet@68e4f813, transactionType=INCOME, expenseCategories=null, incomeCategories=BUSINESS}]}, TransactionGroup{date=2023-02-01, transactions=[Transaction{id=17, userId=1, walletName='Dailyk', amount=3.0, note='Treca transakcija', date=2023-02-01, wallet=com.budgettracker.demo.userProfile.models.Wallet@68e4f813, transactionType=INCOME, expenseCategories=null, incomeCategories=EXTRA_INCOME}]}, TransactionGroup{date=2023-01-01, transactions=[Transaction{id=15, userId=1, walletName='Dailyk', amount=1.0, note='Prva transkacija', date=2023-01-01, wallet=com.budgettracker.demo.userProfile.models.Wallet@68e4f813, transactionType=INCOME, expenseCategories=null, incomeCategories=SALARY}, Transaction{id=16, userId=1, walletName='Dailyk', amount=2.0, note='Druga transkacija', date=2023-01-01, wallet=com.budgettracker.demo.userProfile.models.Wallet@68e4f813, transactionType=INCOME, expenseCategories=null, incomeCategories=GIFTS}]}]
Frosty Nah
  • 23
  • 5
  • the thymeleaf part is incorrect. see my update – dsp_user Feb 11 '23 at 15:38
  • Hi, thanks, I replaced my code with updated one, now I can see data, but its not the way how I want, I already had something similar like this, please see `Example` image from my question, I have two transactions on same date like in `Example` I posted in question, but this template thymeleaf again show it in separated dates – Frosty Nah Feb 11 '23 at 15:43
  • Hi, I managed to get it on the right way, see updated question – Frosty Nah Feb 11 '23 at 15:46
  • so does it work the way you want it now? Note that you can also use something like `
    0}>
    ` to do some action depending on the current record.
    – dsp_user Feb 11 '23 at 19:05
  • Yeah, it works fine now, thank you so much, I will try also with that – Frosty Nah Feb 12 '23 at 10:01
  • Hi, I have on question if you dont mind – Frosty Nah Feb 18 '23 at 18:44
  • what is your question? – dsp_user Feb 18 '23 at 20:16
  • You can join if you want https://stackoverflow.com/questions/75496021/how-to-show-appropriate-message-on-page-with-thymeleaf-if-list-is-empty?noredirect=1#comment133201793_75496021 – Frosty Nah Feb 18 '23 at 20:21

2 Answers2

0

I think you don't need TransactionGroup as a intermediate class, just store transaction by Transaction entity, and you can get query by userId and return list of transactions, and from this list you can get all distinct dates, If the specific user want to see all transactions in specific date you can define a query by two parameters with userId and Date from transaction repository.

So it can be better define a method with userId and Date(can be nullable) and return list of transactions.

amir-rad
  • 85
  • 7
  • Not sure about that, I would rather try on this way, since I only need to find a way how to populate date field in separated class `TransactionGroup` – Frosty Nah Feb 10 '23 at 15:14
  • Get all all distinct dates from Transaction list and return these dates, it means define dates in transactionGroup as a list and you can pass one of these dates to another method and filtered transaction for specific date. – amir-rad Feb 10 '23 at 16:22
0

This can be done in many ways. For instance, you can define a wrapper list ( List<List<Transaction>> or List<TransactionGroup>) where the contained list(s) will contain all the transactions on a given day. It would also make sense to create a native query to retrieve the transactions for a particular user sorted by date.

//your Transaction repository

@Query( value="select * from transaction where user_id = ?1 order by date desc", nativeQuery=true)
List<Transaction> getTransactionsByUserId(Integer userId);

The logic in your controller could then look something like

    ....
    //this list holds all the transactions for a particular user
    List<Transaction> transactions = transRepository.getTransactionsByUserId(userId);

   //create the wrapper list
   List<List<Transaction>> transactionByDate = new ArrayList<>();

   //initialize currDate with the first transaction date
   LocalDate currDate = transactions.get(0).getDate();

   //create a list that will hold transactions for a single date
   List<Transaction> transOnSingleDate = new ArrayList<>();

    //loop through your transactions and populate the wrapper list
    for(Transaction t : transactions){
        //create a new list of transactions if the date has changed 
        if(!currDate.isEqual(t.getDate()){
            //fill the wrapper list before creating a new list
            transactionByDate.add(transOnSingleDate);
            transOnSingleDate = new ArrayList<>();
         }
        transOnSingleDate.add( t );
        currDate = t.getDate();       
     }
     //add the final list
     
     transactionByDate.add(transOnSingleDate);
     model.addAtrribute("transByDate", transactionByDate);

or using List<TransactionGroup>

   ....
    //this list holds all the transactions for a particular user
    List<Transaction> transactions = transRepository.getTransactionsByUserId(userId);
   //create a TransactionGroup list
   List<TransactionGroup> transactionByDate = new ArrayList<>();
   //create a list that will hold all transactions for a day
    List<Transaction> transOnSingleDate = new ArrayList<>();
   //initialize currDate with the first transaction date
   LocalDate currDate = transactions.get(0).getDate();

   //create a TransactionGroup
   TransactionGroup transGroup = new TransactionGroup();

    //loop through your transactions and populate the wrapper list
    for(Transaction t : transactions){
        //create a new transaction group if the date has changed 
        if(!currDate.isEqual(t.getDate()){
            //fill the wrapper list before creating a new list
            transGroup.setDate(currDate);
            transGroup.setTransactions(transOnSingleDate);
            transactionByDate.add(transGroup);
            //create new TransactionGroup and List<Transaction> for a new date
            transGroup = new TransactionGroup();
            transOnSingleDate = new ArrayList<>();
         }
        
        transOnSingleDay.add( t );
        currDate = t.getDate();       
     }
     //add the final list
     transGroup.setDate(currDate);
     transGroup.setTransactions(transOnSingleDate);
     transactionByDate.add(transGroup);
     model.addAtrribute("transactionGroup", transactionByDate);

Hope this helps.

UPDATE:

The controller part is now ok. The List<TransactionGroup> object contains 3 transaction groups, one for each date. The thymeleaf template is wrong. It should be something like

<div th:each="singleGroup : ${transactionGroup}">  
<div th:each="singleTrans : ${singleGroup.transactions}"> 
<h2>Amount: <span th:text="${singleTrans.amount}"></span></h2><br>
<h2>Note: <span th:text="${singleTrans.note}"></span></h2><br>
<h2>Wallet name: <span th:text="${singleTrans.walletName}"></span></h2><br>
<h2>Expense Category: <span th:text="${singleTrans.expenseCategories}"></span></h2><br>
<h2>IncomeCategory: <span th:text="${singleTrans.incomeCategories}"></span></h2>
<h2>IncomeCategory: <span th:text="${singleTrans.date}"></span></h2>
<div>
</div>
dsp_user
  • 2,061
  • 2
  • 16
  • 23
  • Thank you for effort, but I tried to apply yours example into mine problem and it didnt work well. `Property or field 'amount' cannot be found on object of type 'java.util.ArrayList' - maybe not public or not valid?` ... And I guess that is like that for all fields – Frosty Nah Feb 11 '23 at 11:03
  • I managed to fix errors, but page is blank after load – Frosty Nah Feb 11 '23 at 11:20
  • @Frosty Nah, post the modified code and I'll have a look. Btw, use the List example because it's easier to fit that into your exisiting code. – dsp_user Feb 11 '23 at 11:21
  • Updated, take a look – Frosty Nah Feb 11 '23 at 11:27
  • You had some typos, so I dont know if you want to acheive something else `transOnSingleDay.add(t);` instead of `transOnSingleDate.add( t );` – Frosty Nah Feb 11 '23 at 11:28
  • Right now there is no errors, page is loaded but blank, like data is not retrieved – Frosty Nah Feb 11 '23 at 11:28
  • Also, I updated a thymeleaf code – Frosty Nah Feb 11 '23 at 11:29
  • @Frosty Nah, can you check the console for errors (in Eclipse or whatever IDE you're using)?. Also, open the Network tab in your browser and check the http response status codes? You can also add a couple of System.out.println statments to your getUserTransactions method. You need to do this to debug your code. And then we can move on. – dsp_user Feb 11 '23 at 11:37
  • No errors in console, all is fine, I updated question with logs from `system.out` also seems fine as I get returned objects, also status codes are obviously same fine, as I can load page but there are just no data, status codes are 200 – Frosty Nah Feb 11 '23 at 11:42
  • @Frosty Nah, these logs (system.out) are not good, they just show that the objects are created, not that they're correctly populated. You have to override the toString() method in your Transaction and TransactionGroup classes. (this is easy https://stackoverflow.com/questions/10734106/how-to-override-tostring-properly-in-java ) – dsp_user Feb 11 '23 at 11:54
  • Got it, I updated the question again with new logs – Frosty Nah Feb 11 '23 at 12:04
  • @Frosty Nah, that's better, I'll have a look later, – dsp_user Feb 11 '23 at 12:10