PROJECT: ExpenseLa


Overview

ExpenseLa is a desktop expense tracker application used for users to track expense and view insights. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.

Summary of contributions

  • Major enhancement 1 : added Monthly Data Tracking

    • What it does: allows user to keep track of monthly expense, income and budget.

    • Justification: This feature allows the user to keep track of how much money they have spend for the month and how much money they have earned

    • Highlights: This enhancement is vital to the functionality of the expense tracker as one of the major reasons users use an expense tracker is to keep track of this monthly information

  • Major enhancement 2 : Budget Tracking and Insights

    • What it does: allows user to keep track of how much budget they have left with a graphical interface that shows ratio of expense and budget for the month.

    • Justification: This feature makes it easy for user to visualize how much money they have left that they can spend for the month

    • Highlights: The enhancement is a huge quality of life update for users as it has a graphical interface that makes it easy for user to visualize how much budget they have left. It is also color coded as to serve as a warning if the user only has very little money left that they can spend

      BudgetGraphic
  • Major enhancement 3 : Recurring Budget

    • What it does: allows user to set a budget for every subsequent months.

    • Justification: Usually budgets for every month are constant so it makes sense to be able to set budget for every subsequent months

    • Highlights: This enhancement made it easier for users to use the app as they only need to set their budget once provided that it remains the same

  • Minor enhancement: added a history command that allows the user to navigate to previous commands using up/down keys.

  • Code contributed: [Commits][Pull requests][RepoSense Code Contribution Dashboard]

  • Other contributions:

    • Project management:

      • Managed releases v1.1 - v1.4 (4 releases) on GitHub

    • Enhancements to existing features:

      • Wrote additional tests for existing features to increase coverage (Pull requests #66, #70)

    • Documentation:

      • Added graphics and screenshots to user guide: #155

{you can add/remove categories in the list above}

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

Product Overview

ExpenseLA is for money-conscious NUS students who wish to track their spending, in order to make better informed decisions when it comes to saving money. ExpenseLA maintains a record of your daily incoming and outgoing transactions to constantly keep track of your finances! ExpenseLA is optimized for those who prefer to work with a Command Line Interface (CLI) while still enjoying the benefits of having a Graphical User Interface (GUI). If you want a simple, no-frills expense tracker, look no further than ExpenseLA!

Quick Start

  1. Ensure you have Java 11 or above installed in your Computer.

  2. Download the latest expensela.jar here.

  3. Copy the file to the folder you want to use as the home folder for your Address Book.

  4. Double-click the file to start the app. The GUI should appear in a few seconds.

    Ui
  5. The UI has 5 different components: Command Input box, Command Result box, Monthly Data panel Filter panel and Transaction List panel(Chart Analytics Panel)

    UI annotated
  6. Filters are only to filter transaction list, MonthlyData is data for the current month and not the month shown in the filter

  7. Type the command in the command box and press Enter to execute it.
    e.g. typing help and pressing Enter will open the help window.

  8. You can navigate through your command history by pressing the Up or Down arrow key. Only successful commands are stored in the command history. There can be at most 50 commands stored. This feature is just like the command navigation feature in your favourite command line or shell.

  9. An example sequence of commands you can try:

    • clear : clear the expenseLa app to start at a clean slate

    • budget b/1000 rc/ : set a recurring budget of $1000 for the current month and subsequent months

    • *add i/ c/Income n/salary a/2500 d/2020-04-02 rc/ : adds a recurring income with amount $2500.00

    • add a/100n/Wagyu Steak c/FOOD : adds an expense named Wagyu Steak with amount $100.00 spent on the day it is added in category FOOD to the expense tracker

    • add a/10n/Laksa c/FOOD : adds an expense named Laksa with amount $10.00 spent on the day it is added in category FOOD to the expense tracker

    • add a/5.5n/Chicken Rice c/FOOD : adds an expense named Chicken Rice with amount $5.50 spent on the day it is added in category FOOD to the expense tracker

    • add a/50n/shirt c/SHOPPING d/2020-04-08 : adds an expense named shirt with amount 50.00 spent on 2020-04-08 in category SHOPPING to the expense tracker

    • filterm/ 2020-04 : filters to only show transactions made on 2020-04

    • delete1 : deletes the expense with id 1 in the current list

    • exit : exits the app

  10. Refer to [Features] for details of each command.

Set a monthly budget : budget (Hubert Halim)

Sets a spendable budget for the current month

Format: budget b/AMOUNT (to set a budget for the given month only) budget b/AMOUNT rc/ (to set repeating budget of $AMOUNT for the coming months)

Example Usage:

  • budget b/1000 - set a non-recurring budget of $1000.00

    BeforeSetBudget
    AfterSetBudget
  • budget b/1500 rc/ - set a recurring budget of $1500.00

    BeforeSetBudget

Reset total balance resetbalance

Reset Balance value to the total from the amount of all transactions in stored in the application so far. This command is used in case user messes up with json file or there is an unhandled bug in the app that causes difference in the value of total balance and the net balance of all the transactions added together. This command will rectify that issue.

Clear all data : clear

Clear all data in expenseLa including monthly data and global data

Expected Outcome: All transactions are deleted, balance is set to 0 and monthly data is also set to 0. All recurring data such as budget and transactions are also cleared

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Logic component (Hubert Halim)

LogicClassDiagram
Figure 1. Structure of the Logic Component

API : Logic.java

Logic is an interface which LogicManager implements, allowing access to the API. The following items are examples on how the LogicManager class can be interacted with:

  1. Logic uses the ExpenseLaParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a Transaction).

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

  5. In addition, the CommandResult object can also instruct the Ui to perform certain actions, such as displaying help to the user.

Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.

DeleteSequenceDiagram
Figure 2. Interactions Inside the Logic Component for the delete 1 Command
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
ClearSequenceDiagram
Figure 3. Interactions Inside the Logic Component for the clear Command

Setting budgets (Hubert Halim)

We allow the user to maintain a Budget for the current month and subsequent months. This section details how ExpenseLa handles requests made by the user who is trying to set a budget both for a one time and recurring budget. Budget is contained inside MonthlyData object along with Expense and Income and application only has 1 MonthlyData object for the current month. object looks like:

BudgetClassDiagram

If user decides to create a recurring budget, there’ll be additional step of updating the recurringBudget variable in GlobalData. BudgetCommand in addition to modifying Budget in MonthlyData, it will also modify recurringBudget in GlobalData.

GlobalDataClassDiagram

Implementation

Whenever the user attempts to set a new Budget, ExpenseLa will create a new MonthlyData object with the given amount. The application will then call ModelManager#setMonthlyData(MonthlyData toSet). During the creation of the new MonthlyData, the Budget class will internally check if the budget amount is valid.

We will demonstrate what happens at the back-end whenever the user sets a budget:

Case 1. The user wishes to set their budget to $1500, non-recurring. They execute the command: budget b/1500. The user’s entry is checked by BudgetCommandParser#parse() and an attempt to parse each parameter occurs:

  • Budget is parsed by ParseUtil#parseBudget(ArgumentMultimap)

  • rc/ prefix does not exist, so it is not recurring

ArgumentMultimap is a class that stores all the parsed parameters taken from the user input.

Since the user input is valid, the Budget is successfully created and inserted into a newly created MonthlyData.

Case 2. The user made a typo when setting their budget. They execute the command budget b/1500. The user’s entry is checked by BudgetCommandParser#parse() and an attempt to parse each parameter occurs:

  • Budget is parsed by ParseUtil#parseBudget(ArgumentMultimap)

Budget class then is attempted to be created with the parsed budget amount in the constructor. Internally Budget will do a validity check using Regex and throw a ParseExection since amount is not valid.

Case 3. The user wishes to set their budget to $1500, recurring. They execute the command: budget b/1500 rc/. The user’s entry is checked by BudgetCommandParser#Parse() and an attempt to parse each parameter occurs:

  • Budget is parsed by ParseUtil#parseBudget(ArgumentMultimap)

  • rc/ prefix exists, so it is recurring

Since the user input is valid, the Budget is successfully created and inserted into a newly created MonthlyData. BudgetCommand will then modify GlobalData in Model by calling Logic#setGlobalData. RecurringBudget value in GlobalData is now set to the new Budget

The sequence diagram below depicts what was just elaborated:

SetBudgetSequenceDiagram
Figure 4. Sequence diagram showing how a Budget is set
SetBudgetActivityDiagram
Figure 5. Activity diagram showing how a Budget is set

Design considerations

We have considered various ways as to how Budget should be stored in ExpenseLa. In this section, we will explain the rationale on our course of actions.

Aspect: Make Budget a part of a bigger class called MonthlyData
  • Alternative 1 (current choice): Budget is a part of MonthlyData and any Budget operations is through MonthlyData

    • Pros: Easier to handle Budget together with other MonthlyData objects and all data inside is synchronised as it is handled by a single object.

    • Cons: Overhead when modifying Budget as to maintain immutability, a new MonthlyData object has to be created.

  • Alternative 2: Budget should be an independent class with a direct reference in ExpenseLa.

    • Pros: More freedom and efficiency in doing modifications on Budget

    • Cons: Need to maintain more references for all different objects.

Again, we went with alternative 1 because it is easier to view Budget along with the other MonthlyData components as a collective. And easier to just handle 1 reference in ExpenseLa.

Command History navigation (Hubert Halim)

Users can navigate to previous commands by pressing the up or down button on the keyboard. Only successful commands are stored in the CommandHistory list and only a maximum of 50 commands can be stored at a time.

Implementation

Every time the user key in a command and press Enter, CommandBox#handleCommandEntered method will be called. The method will attempt to execute the command by calling CommandExecutor#execute method. That method throws an error if command is invalid. So if the command is valid, the CommandBox#handleCommandEntered method will call Logic#deleteCommandFromHistory to delete the command if it exists in the current command history. It will then call Logic#addToCommandhistory to add the command to the command history as its latest entry. Both commands for add and delete takes in an integer variable called offset. This variable is maintained by CommandBox and determines which command the user is currently at in the command history. Offset starts from -1 indicating CommandBox is empty and resets to -1 every time a successful command is entered

Command History is an array list that resides in ModelManager object. It can be accessed through Logic by calling

The diagrams below depicts what was just elaborated:

CommandHistorySequenceDiagram
Figure 6. Sequence diagram showing what happens when user enters a Command
CommandHistoryActivityDiagram
Figure 7. Activity diagram showing what happens when user enters a Command
CommandHistoryNavigateSequenceDiagram
Figure 8. Sequence diagram showing what happens when presses Up/Down button
CommandHistoryNavigateActivityDiagram
Figure 9. Activity diagram showing what happens when presses Up/Down button

Design considerations

We have considered various ways as to how to implement CommandHistory to support navigation to previous commands Since we need to capture keyboard events when user press the keyboard, we decided to implement the event listener and handler in CommandBox component as it is more convenient because when a keyboard event is captured, the app can straight away modify the TextField in CommandBox. Since the event when user enter a command is also handled in CommandBox and we only store successful commands in CommandHistory, we wait for execution of the Command by CommandExecutor, if it is successful, the String for the command is added to, otherwise due to the error thrown and caught somewhere else, the command is not stored.

Appendix A: Use Cases (Hubert Halim)

(For all use cases below, the System is the ExpenseLa and the Actor is the user, unless specified otherwise)

Use case: Delete expense

MSS

  1. User requests to list all transactions

  2. System removes all filters and show all expenses

  3. User requests to delete a specific transaction in the list

  4. System deletes the transaction

    Use case ends.

Extensions

  • 2a. The list is empty.

    Use case ends.

  • 3a. The given index is invalid.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

Use case: filter transactions by category

MSS

  1. User requests to list filtered transactions

  2. System queries list of transactions

  3. Apply filter predicate to update list of filtered transactions

  4. System shows filtered list

    Use case ends.

Extensions

  • 2a. The list is empty.

    Use case ends.

  • 3a. The category given is not valid.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

Use case: Set recurring monthly budget

  1. User requests to set a recurring budget of a specified amount.

  2. ExpenseLa processes the request and sets the specified amount as the budget for the current month.

  3. ExpenseLa then update the value of recurringBudget variable in GlobalData to the specified amount.

    Use case ends.

Extensions

  • 1a. The parameters specified by the user are not valid.

    • 1a1. ExpenseLa displays an invalid parameter error to the user and the monthly budget is not updated.

      Use case ends.

Use Case: Add an expense

MSS

  1. User requests to add a new expense into their expensela.

  2. The system processes the request and adds the expense transaction into the transactions list.

    Use case ends.

Extensions

  • 1a. The parameters specified by the user are not valid.

    • 1a1. The system displays an invalid parameter error to the user and the transactions list is not updated.

      Use case ends.

Use Case: Add a recurring income

MSS

  1. User requests to add a new recurring income into their expensela.

  2. The system processes the request and adds the income transaction into the transactions list.

  3. The system then add the income transaction to RecurringTransactionList in GlobalData.

    Use case ends.

Extensions

  • 1a. The parameters specified by the user are not valid.

    • 1a1. The system displays an invalid parameter error to the user and the transactions list is not updated.

      Use case ends.

Use Case: Show chart analytics view

MSS

  1. User requests to toggle to chart analytics view.

  2. The system switches the view to charts view.

    • 2a. The filter for month is set to all, bar chart displays data of the last 2 years by month.

    • 2b. The filter for month is set to a specific month, bar chart displays data by day of the week.

      Use case ends.

Use Case: Clear transaction list

MSS*

  1. User requests to clear all transactions.

  2. The system clears transaction list in ExpenseLa.

  3. The system resets MonthlyData and GlobalData

    Use case ends.

Use Case: Export to CSV file

MSS

  1. User requests to export current list being viewed to a CSV file.

  2. The system saves the transactions to that csv file named transactions.csv by the system.

Use case ends.

Extensions

  • 1a. The file does not exists.

    • 1a1. The system creates a file with the name transactions.csv.

      Use case resumes at step 2.

Use Case: Import from CSV file

MSS

  1. User requests to import transaction data from a CSV file.

  2. Import the transactions data from the file specified by the user ignoring duplicate and invalid transactions

    Use case ends.

  • 1a. The file specified by user does not exists.

    • 1a1. The system shows an error message prompting user to rectify their command.

      Use case ends.

Use Case: Find transactions whose name contains certain words

MSS

  1. User requests to list transactions whose name contains certain words.

  2. The system queries all transactions

  3. The system applies predicate to filter only transactions that contain the words specified by user

    Use case ends.

  • 2a. The list is empty.

    Use case ends.

  • 3a. The list is empty.

    Use case ends.

PROJECT: PowerPointLabs