PROJECT: Personal Finance Tracker


Overview

This portfolio aims to document the contributions made by Goh Yin Hao to the Personal Finance Tracker.

Personal Finance Tracker is a desktop finance tracker application used for tracking personal finances such as daily expenses, recurring expenses such as monthly electricity bills, budgets and debts owed to another party. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 30 kLoC. The product was morphed from an Address Book over a period of 8 weeks under the constraints described here.

Summary of contributions

  • Major enhancement: added the ability to manage debts in the finance tracker application

    • What it does: allows the user to add, edit, delete, select debts, as well as easily convert these debts into an expense once the debt is cleared. Integrated to work with current undo/redo, history and list commands.

    • Justification: This feature improves the product significantly because a user can now easily and conveniently keep track of their debts owed to other entities.

    • Highlights: This enhancement is a core feature of any typical finance tracker. It required adjustments and integration with the existing model, logic, UI components and builds the foundation for any future enhancements involving debts.

  • Code contributed: [code collated by reposense]

  • Other contributions:

    • Project management:

      • Check all pull requests done by group mates

      • Create issues for tracking in GitHub Issue Tracker

      • In charge of code in model component

    • Documentation:

      • Update model component in Developer’s Guide (Pull Request #112)

      • Added the implementation of debts in Developer’s Guide (Pull Request #221)

    • Enhancements to existing features:

      • Refactored and cleaned up initial tests from AddressBook4 to FinanceTracker (Pull Requests #109, #117)

      • Update validation checks for Name and Amount classes (Pull Requests #207, #264)

    • Community:

      • PRs reviewed (with non-trivial review comments): #22, #81

      • Contributed to forum discussions (example: #11)

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.

Adding a debt: adddebt

Adds a debt to the finance tracker.
Format: adddebt n/PERSON_OWED $/AMOUNT_OWED c/CATEGORY due/DEADLINE [r/REMARK]
Shortcut: ad n/PERSON_OWED $/AMOUNT_OWED c/CATEGORY due/DEADLINE [r/REMARK]

  • The PERSON_OWED should only contain alphanumeric characters and spaces, and it should not be blank.

  • The AMOUNT_OWED should only contain positive numbers and reflect the value in dollars. Values accepted are in the range of $0.01 to $9,999,999.99. A maximum of 2 decimal places are allowed.

  • The CATEGORY is case insensitive and should only be one of the following: FOOD, TRANSPORT, SHOPPING, WORK, UTILITIES, HEALTHCARE, ENTERTAINMENT, TRAVEL, OTHERS.

  • The DEADLINE should be in dd-mm-yyyy format and should not be a date before today’s date.

  • If REMARK is omitted, no remarks will be stored.

You can omit (optional) parameters by leaving them empty.

Examples:

  • adddebt n/John Doe $/50.00 c/shopping due/25-02-2019 r/Loan from John to finance my new earphones

  • ad n/Jane Doe $/200 c/FOOD due/03-03-2019

Editing a debt: editdebt

Edits an existing debt in the finance tracker.
Format: editdebt INDEX [n/PERSON_OWED] [$/AMOUNT_OWED] [c/CATEGORY] [due/DEADLINE] [r/REMARK]
Shortcut: ed INDEX [n/PERSON_OWED] [$/AMOUNT_OWED] [c/CATEGORY] [due/DEADLINE] [r/REMARK]

  • Edits the debt at the specified INDEX.

  • The index refers to the index number shown in the displayed debt list. The index must be a positive integer.

  • At least one of the optional fields must be provided.

  • Existing values will be updated to the input values.

You can omit [optional] parameters by leaving them empty. If all parameters are empty, no edits will occur.

Examples:

  • editdebt 5 n/Tommy $/60 Edits debt owed and amount owed of the 5th debt to be Tommy and $60 respectively.

Deleting a debt: deletedebt

Deletes the specified debt from the finance tracker. Format: deletedebt INDEX
Shortcut: dd INDEX

  • Deletes the debt at the specified INDEX.

  • The index refers to the index number shown in the displayed debt list. The index must be a positive integer.

Examples:

  • listdebt v/all
    deletedebt 5
    Deletes the 5th debt in the finance tracker.

Selecting a debt: selectdebt

Selects the specified debt from the finance tracker. Format: selectdebt INDEX
Shortcut: sd INDEX

  • Selects the debt at the specified INDEX.

  • The index refers to the index number shown in the displayed debt list. The index must be a positive integer.

Examples:

  • listdebt v/all
    selectdebt 5
    Selects the 5th debt in the finance tracker.

Clearing all debts: cleardebt

Clears all debts from the finance tracker.
Format: cleardebt
Shortcut: cd

Paying off a debt: paydebt

Converts the specified debt into an expense.
Format: paydebt INDEX [d/DATE]
Shortcut: pd INDEX [d/DATE]

  • Converts the debt at the specified INDEX.

  • The index refers to the index number shown in the displayed debt list. The index must be a positive integer.

  • After converting the debt into an expense, the debt is deleted.

  • The DATE should be in dd-mm-yyyy format and can be used to indicate actual day when user paid off the debt.

  • If DATE is omitted, current date will be used.

Examples:

  • listdebt v/all
    paydebt 3
    Converts the 3rd debt in the finance tracker into an expense.

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.

Model component

ModelClassDiagram
Figure 1. Structure of the Model Component

API : Model.java

The Model,

  • stores a UserPref object that represents the user’s preferences.

  • stores the Finance Tracker data.

  • exposes unmodifiable ObservableList<Expense>, ObservableList<Recurring>, ObservableList<Debt>, ObservableList<Budget> that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.

  • does not depend on any of the other three components.

Debt Feature

The Debt feature consists of adddebt, editdebt, listdebt, deletedebt, selectdebt, cleardebt and paydebt.

This feature allows users to add debts to the finance tracker and be able to constantly keep track of them. This is done by calling Logic#execute which creates an AddDebtCommand. This command then calls Model#addDebt, adding the specified debt into the debt list.

Editing, deleting, selecting and clearing of debts work in a similar manner.

Pay Debt Feature

The purpose of this feature is to provide the convenience for users to indicate that they have paid off a particular debt and seamlessly convert that into an expense.

Current Implementation

Below is the UML sequence diagram and a step-by-step explanation of an example usage scenario for paydebt.

PayDebtSequenceDiagram
  1. User enters the command paydebt 1, to convert the first listed debt on the user interface into an expense. This command is executed by LogicManager, which calls FinanceTrackerParser#parseCommand("paydebt 1"). This creates a new PayDebtCommandParser object which will help parse the input by the user.

  2. The newly created object calls parse("1") which in turns calls ArgumentTokenizer#tokenize("1", "d/") to split the arguments into its preamble(the index) and the date(if inputted by the user). This returns an argMultiMap containing the split input.

  3. The PayDebtCommandParser object then calls ParserUtil#parseIndex(argMultiMap.getPreamble()) and ParserUtil#parseDate(argMultiMap.getValue("d/").get()) to parse the arguments into the index and date into its correct form respectively. If the user does not input a date, the program will use the local date on the system’s clock. A PayDebtCommand object containing the index and date is then created and returned to the LogicManager.

  4. The LogicManager calls PayDebtCommand#execute(), which will call Model#getFilteredDebtList() to retrieve the list of debts stored in the finance tracker. The method get(index) is then called to retrieve the debt the user was intending to convert.

  5. An expense is then created by retrieving out the following relevant information from the debt entry:

    • Person Owed

    • Amount

    • Category

    • Remarks

  6. The programme then take this information and creates a new Expense convertedExpense with the following fields:

    • Name : Paid Debt to Person Owed

    • Amount : Same amount will be used

    • Category : Same category will be used

    • Date : Based on user’s input on when the debt is paid, else the program will use the local date in the system’s clock

    • Remarks : Same remarks will be used

  7. Model#deleteDebt(debt) and Model#addExpense(convertedExpense) are then called to delete the targeted debt from the debt list and add the convertedExpense into the expense list accordingly.

  8. The command result is then returned to the LogicManager which then returns it to the UI where the changes are then reflected on the user interface.

Design Consideration

This feature can be implemented in different ways in terms of the architecture of the Model component. The alternative ways of implementation are shown below.

  • Alternative 1 (current choice): Debt and Expense classes do not inherit from a common Interface. Container objects such as expense list and debt list, will be initialized to hold objects of their own individual classes.

    • Pros: Lower level of coupling between Expense and Debt classes.

    • Cons: Slower and less flexibility. Conversion between classes, e.g. from Debt to Expense, requires extracting information from debt, creating a new expense, then deleting the old debt.

  • Alternative 2: Debt and Expense classes inherit from a common Interface. Container objects such as expense list and debt list, will be initialized to hold objects of this common Interface.

    • Pros: Greater flexibility. Polymorphism allows for easy conversion between different types of entries, such as from debt to expense, simply by moving them across different lists. This will be useful considering that our Finance Tracker will need significant amounts of conversion between different objects.

    • Cons: Higher level of coupling between Expense and Debt classes.

Ultimately, the first option was chosen because a lower level of coupling will allow for easier maintenance, integration and testing. Also, it is not significantly slower thus the Finance Tracker will still be able to complete debt-related commands within 2 seconds, which is one of our non-functional requirements.

Debt Notifications (Coming in v2.0)

This is still a work in progress.

The purpose of this feature is to alert users when the deadline for their debts is approaching. These alerts come in the form of either a pop-up notification or an email alert.

It is up to the user on when they would like to receive this notification. Currently, there are plans to implement the following options:

  • 1 month before debt deadline

  • 1 week before debt deadline

  • 3 days before debt deadline

  • 1 day before debt deadline

Future Implementation

Once the duration option is set, each time the main application loads, the programme will go through every debt in Model#getFilteredDebtList(), deduct duration from each Debt#getDeadline() to get its notificationDate and add them to a new list notificationDates.

Each notificationDate is then checked against LocalDate#now(). If notificationDate is before or equals to LocalDate#now, they are then added to a new list notificationsToBeAlerted.

Every item in notificationsToBeAlerted is then printed on an alert box, reminding the user of the upcoming deadlines for their debts.