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
-
-
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:
{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
-
Ensure you have Java
11
or above installed in your Computer. -
Download the latest
expensela.jar
here. -
Copy the file to the folder you want to use as the home folder for your Address Book.
-
Double-click the file to start the app. The GUI should appear in a few seconds.
-
The UI has 5 different components: Command Input box, Command Result box, Monthly Data panel Filter panel and Transaction List panel(Chart Analytics Panel)
-
Filters are only to filter transaction list, MonthlyData is data for the current month and not the month shown in the filter
-
Type the command in the command box and press Enter to execute it.
e.g. typinghelp
and pressing Enter will open the help window. -
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.
-
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/100
n/Wagyu Steak c/FOOD
: adds an expense namedWagyu Steak
with amount$100.00
spent on the day it is added in categoryFOOD
to the expense tracker -
add a/10
n/Laksa c/FOOD
: adds an expense namedLaksa
with amount$10.00
spent on the day it is added in categoryFOOD
to the expense tracker -
add a/5.5
n/Chicken Rice c/FOOD
: adds an expense namedChicken Rice
with amount$5.50
spent on the day it is added in categoryFOOD
to the expense tracker -
add a/50
n/shirt c/SHOPPING d/2020-04-08
: adds an expense namedshirt
with amount50.00
spent on2020-04-08
in categorySHOPPING
to the expense tracker -
filter
m/ 2020-04
: filters to only show transactions made on2020-04
-
delete
1
: deletes the expense with id1
in the current list -
exit
: exits the app
-
-
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 -
budget b/1500 rc/
- set a recurring budget of $1500.00
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)
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:
-
Logic
uses theExpenseLaParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding aTransaction
). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
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.
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.
|
clear
CommandSetting 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:
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
.
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 byParseUtil#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 byParseUtil#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 byParseUtil#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:
Budget
is setBudget
is setDesign 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 ofMonthlyData
and anyBudget
operations is throughMonthlyData
-
Pros: Easier to handle
Budget
together with otherMonthlyData
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 newMonthlyData
object has to be created.
-
-
Alternative 2:
Budget
should be an independent class with a direct reference inExpenseLa
.-
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:
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
-
User requests to list all transactions
-
System removes all filters and show all expenses
-
User requests to delete a specific transaction in the list
-
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
-
User requests to list filtered transactions
-
System queries list of transactions
-
Apply filter predicate to update list of filtered transactions
-
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
-
User requests to set a recurring budget of a specified amount.
-
ExpenseLa
processes the request and sets the specified amount as the budget for the current month. -
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
-
User requests to add a new expense into their expensela.
-
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
-
User requests to add a new recurring income into their expensela.
-
The system processes the request and adds the income transaction into the transactions list.
-
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
-
User requests to toggle to chart analytics view.
-
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*
-
User requests to clear all transactions.
-
The system clears transaction list in ExpenseLa.
-
The system resets MonthlyData and GlobalData
Use case ends.
Use Case: Export to CSV file
MSS
-
User requests to export current list being viewed to a CSV file.
-
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
-
User requests to import transaction data from a CSV file.
-
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
-
User requests to list transactions whose name contains certain words.
-
The system queries all transactions
-
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.