By: Team W17-3      Since: March 2019      Licence: MIT

1. Introduction

Welcome to the In-Credit-Ble Developer Guide!

In-Credit-Ble is a finance tracker application created to simplify the managing and tracking of the user’s personal finances. With In-Credit-Ble, users will be able to stick to their budget and be more aware of their spending habits.

This developer guide specifies the design and implementation of In-Credit-Ble. The intended audience of this document is the developers, designers and software testers of our application.

Please continue on to the Setting Up section to get started. You can also read AboutUs.adoc and ContactUs.adoc for more information on how to contact us!

2. Setting Up


2.1. Prerequisites


  1. JDK 9 or later

    JDK 10 on Windows will fail to run tests in headless mode due to a JavaFX bug. Windows developers are highly recommended to use JDK 9.
  2. IntelliJ IDE

    IntelliJ by default has Gradle and JavaFx plugins installed.
    Do not disable them. If you have disabled them, go to File  Settings  Plugins to re-enable them.


2.2. Setting up the project in your computer


  1. Fork this repo, and clone the fork to your computer.

  2. Open IntelliJ (if you are not in the welcome screen, click File  Close Project to close the existing project dialog first).

  3. Set up the correct JDK version for Gradle.

    1. Click Configure  Project Defaults  Project Structure

    2. Click New…​ and find the directory of the JDK.

  4. Click Import Project

  5. Locate the build.gradle file and select it. Click OK

  6. Click Open as Project

  7. Click OK to accept the default settings.

  8. Open a console and run the command gradlew processResources (Mac/Linux: ./gradlew processResources). It should finish with the BUILD SUCCESSFUL message.
    This will generate all resources required by the application and tests.

  9. Open MainWindow.java and check for any code errors.

    1. Due to an ongoing issue with some of the newer versions of IntelliJ, code errors may be detected even if the project can be built and run successfully.

    2. To resolve this, place your cursor over any of the code section highlighted in red. Press ALT+ENTER, and select Add '--add-modules=…​' to module compiler options for each error.

  10. Repeat this for the test folder as well (e.g. check HelpWindowTest.java for code errors, and if so, resolve it the same way).


2.3. Verifying the setup


  1. Run seedu.finance.MainApp and try a few commands.

  2. Run the tests to ensure they all pass.


2.4. Configurations to do before writing code


2.4.1. Configuring the coding style


This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. To rectify,

  1. Go to File  Settings…​ (Windows/Linux), or IntelliJ IDEA  Preferences…​ (macOS).

  2. Select Editor  Code Style  Java

  3. Click on the Imports tab to set the order.

    • For Class count to use import with '*' and Names count to use static import with '*': Set to 999 to prevent IntelliJ from contracting the import statements.

    • For Import Layout: The order is import static all other imports, import java.*, import javax.*, import org.*, import com.*, import all other imports. Add a <blank line> between each import.

Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.


2.4.2. Updating documentation to match your fork


After forking the repo, the documentation will still refer to the CS2103-AY1819S2-W17-3/main repo.

If you plan to develop this fork as a separate product (i.e. instead of contributing to In-Credit-Ble), you should do the following:

  1. Configure the site-wide documentation settings in build.gradle, such as the site-name, to suit your own project.

  2. Replace the URL in the attribute repoURL in DeveloperGuide.adoc and UserGuide.adoc with the URL of your fork.


2.4.3. Setting up CI


Set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.

After setting up Travis, you can optionally set up coverage reporting for your team fork (see UsingCoveralls.adoc).

Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork.

Optionally, you can set up AppVeyor as a second CI (see UsingAppVeyor.adoc).

Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based)


2.4.4. Getting started with coding


When you are ready to start coding,

  1. Get some sense of the overall design by reading Section 3.1, “Architecture”.

  2. Take a look at [GetStartedProgramming].


3. Design


3.1. Architecture


Architecture
Figure 1. Architecture Diagram


The Architecture Diagram above explains the high-level design of In-Credit-Ble. Given below is a quick overview of each component.

The .pptx files used to create diagrams in this document can be found in the link:https://github.com/CS2103-AY1819S2-W17-3/main/tree/master/docs/diagrams/diagrams] folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose Save as picture.

Main has only one class called MainApp. It is responsible for,

  • App launch: Initializes the components in the correct sequence, and connects them up with each other.

  • App shut down: Shuts down the components and invokes cleanup method where necessary.


Commons represents a collection of classes used by multiple other components. The following class plays an important role at the architecture level:

  • LogsCenter : Used by many classes to write log messages to the App’s log file.


The rest of the App consists of four components.

  • UI: The UI of the App.

  • Logic: The command executor.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.


Each of the four components

  • Defines its API in an interface with the same name as the Component.

  • Exposes its functionality using a {Component Name}Manager class.

For example, the Logic component (see the class diagram given below) defines its API in the Logic.java interface and exposes its functionality using the LogicManager.java class.


LogicClassDiagram
Figure 2. Class Diagram of the Logic Component


How do the architecture components interact with each other?


The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.

SDforDeleteRecord
Figure 3. Component interactions for delete 1 command


The sections below give more details of each component.


3.2. UI component

UiClassDiagram
Figure 4. Structure of the UI Component


API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g. CommandBox, ResultDisplay, RecordListPanel, StatusBarFooter, BrowserPanel, BudgetPanel, SummaryPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class.

The UI component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml.

The UI component,

  • Executes user commands using the Logic component.

  • Listens for changes to Model data so that the UI can be updated with the modified data.

3.3. Logic component


LogicClassDiagram
Figure 5. Structure of the Logic Component


API : Logic.java

  1. Logic uses the FinanceTrackerParser 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 record).

  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.

DeletePersonSdForLogic
Figure 6. Interactions Inside the Logic Component for the delete 1 Command


3.4. Model component


ModelClassDiagram
Figure 7. Structure of the Model Component


API : Model.java

The Model component,

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

  • stores the Finance Tracker data.

  • exposes an unmodifiable ObservableList<Record> 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.


3.5. Storage component


StorageClassDiagram
Figure 8. Structure of the Storage Component


API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the Finance Tracker data in json format and read it back.


3.6. Common classes


Classes used by multiple components are in the seedu.finance.commons package.

4. Implementation


This section describes in detail the implementation of certain features in In-Credit-Ble.

4.1. Search feature

This feature allows the user to filter out specific expenses based on keywords that correspond to the name, category or date.

This implementation is under Logic and Model Component.


4.1.1. Current Implementation

The search command uses predicates that implement the java.util.Predicate interface. These predicates are used to filter the records that are inputted into the finance tracker. Each of these predicates contain a List<String> of keywords and a test() command that is used to test if a record satisfy the conditions set in the predicate. These predicates are found in the Model component.

Table 1. Predicates implemented in Model component

Types of predicate

Functions

CategoryContainsKeywordsPredicate

Filters out records by a given category

DateContainsKeywordsPredicate

Filters out records by a given date

NameContainsKeywordPredicate

Filters out records with names that matches a keyword

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

SearchCommandSequenceDiagram
Figure 9. Sequence Diagram of Search Command
  1. User enters a search command (eg. search -cat food). The command is received by the UI components and the method LogicManger#execute() is called.

  2. The command is received by FinanceTrackerParser, which then creates a SearchCommandParser Object and calls SearchCommandParser#parse() method.

  3. Depending on the -FLAG that is entered by the user, SearchCommandParser will create different predicates objects that correspond to the -FLAG.

    • If -cat is inputted, CategoryContainsKeywordsPredicate will be created.

    • If -date is inputted, DateContainsKeywordPredicate will be created.

    • If -name is inputted, NameContainsKeywordPredicate will be created.

  4. A SearchCommand Object with the correct predicate Object as parameter is created and returned to the FinanceTrackerParser and then to the LogicManager.

  5. LogicManager then calls SearchCommand#execute(), which calls Model#updateFilteredExpenseList() method to update the predicate of FilterList<Record>. FilterList<Record> now contains a new set of records which is filtered by the new predicate.

  6. SearchCommand then calls getFilteredRecordList method to access the filtered records in an ObservableList<Record> in order to calculate the sum of the money that is spent in all the filtered records.

  7. Then the record list panel will show a set of records according to the keywords. A CommandResult is then created and returned to Logic Manager.


4.1.2. Design Consideration

This feature can be implemented in different ways in terms of how the records are found.

  • Alternative 1 : Check through all records and select those with the matched keywords based on the flag.

    • Pros: Easy to implement without changing original architecture.

    • Cons: Slow. Tends to take a long time to search through large number of records.

  • Alternative 2 : Each time a new category/date is called when making a record, create a new list. Each of these lists will hold all the records that correspond to these category or dates.

    • Pros: Very efficient, each time the command is called, just need to retrieve the list of the wanted field.

    • Cons: Need to change the original architecture of storage to introduce storing of different list corresponding to each tag. Will take up more space if there is many different tags.

We have implemented Alternative 1 as we want the search function to be more dynamic and more generic to accept different kind of search in the future implementation. If we were to choose Alternative 2, the search conditions will only be restricted to category and date where it is likely for different records to have the same value (eg. same date or same category). However, it is not feasible to create a different list for every single name that is inputted into the finance tracker.


4.2. Sort feature

By default, the list of entries is ordered according to the time the entry is entered into the application, where the entry entered first will be at the top of the list, and the entry entered last is at the bottom of the list. The sort mechanism allows users to view their expense records in a different way.


4.2.1. Current Implementation

The sort command uses comparators that implement java.util.Comparator interface to provide the comparison functions.

Table 2. Sort commands (default ordering)
Command Comparator used Effect

sort -name, sort -name -asc

RecordNameComparator

Lexicographical order

sort -amount, sort -amount -desc

RecordAmountComparator

Descending order

sort -date, sort -date -desc

RecordDateComparator

Reverse chronological order

sort -cat, sort -cat -asc

RecordCategoryComparator

Lexicographical order


Table 3. Sort commands (Specified order opposite to that of default)
Command Comparator used Effect

sort -name -desc

RecordNameComparator#reversed()

Reverse lexicographical order

sort -amount - asc

RecordAmountComparator#reversed()

Ascending order

sort -date - asc

RecordDateComparator#reversed()

Chronological order

sort -cat -desc

RecordCategoryComparator#reversed()

Reverse lexicographical order

Here is the list of operations involved in the execution of command, sort -name.
See Figure 10 for steps 1 to 4, and Figure 11 for steps 5 to 10.

SortSequenceDiagram1
Figure 10. Sequence Diagram of Sort Command I
  1. LogicManager#execute("sort -name") calls FinanceTrackerParser#parseCommand("sort -name").

  2. FinanceTracker#parseCommand("sort -name") creates a new SortCommandParser object and calls SortCommandParser#parse(" -name").

  3. SortCommandParser#parse() creates a new RecordNameComparator() object, comparator and passes it as a parameter into the SortCommand constructor.

  4. The SortCommand object, s, is then passed back to the SortCommandParser, FinanceTrackerParser, and finally back to the LogicManager.

    SortSequenceDiagram2
    Figure 11. Sequence Diagram of Sort Command II
  5. LogicManager#execute("sort -name") then continues to call SortCommand#execute().

  6. SortCommand#execute() calls Model#SortFilteredRecordList(comparator).

  7. Model#SortFilteredRecordList(comparator) calls FinanceTracker#sortRecordList(comparator).

  8. FinanceTracker#sortRecordList(comparator) calls UniqueRecordList#sortList(comparator).

  9. UniqueRecordList#sortList(comparator) then uses FXCollection’s static method sort() to sort the records.

  10. SortCommand#execute() then creates a CommandResult object and returns it back to the LogicManager.


4.2.2. Design Considerations

Aspect: How sort is executed
  • Alternative 1 (current choice): Use the Comparator interface.

    • Pros 1: Sorting can be done based on different attributes of the records (name, amount, date, category).

    • Pros 2: Allows an alternative ordering to be applied, does not have to be the natural ordering. Therefore, dates can be sorted in reverse chronological order, and amount in descending order.

    • Cons: A new class that implements the interface Comparator needs to be created.

  • Alternative 2: Use the Comparable interface.

    • Pros: Type-safe with compiler as Comparable#compareTo() only accepts object of type T, instead of java.lang.Object.

    • Cons 1: There can only be one form or way of sorting the records.

    • Cons 2: Uses the natural order for sorting. Therefore, dates will be sorted in chronological order, amount in ascending order, and names and categories in lexicographical order.

Aspect: How sort is executed when [ORDER] argument is supplied and specified order is opposite to that of default. (E.g. sort -name -desc)
  • Alternative 1 (current choice): A new comparator that imposes the reverse ordering of one of the four defined comparator classes is created.
    (E.g. To sort the list by name in reverse lexicographical order, a new comparator, RecordNameComparator#reversed() is created.)

    • Pros: Easy to implement.

    • Cons: List needs to be sorted again using the new comparator. Time will be needed to compare the records in the list.

  • Alternative 2: Reverse the list after sorting it using one of the four defined comparator classes.
    (E.g. Sort list using RecordNameComparator. Then use the reverse command to reverse the list.)

    • Pros: We can reuse what is already in the codebase (reverse command).

    • Cons: Harder to implement, need to execute two commands internally when one command is entered in the CommandBox.


4.3. Reverse feature

The reverse feature allows users to reverse the list of entries displayed on the graphic user interface. The sort features are implemented with a default ordering. The reverse command provides a convenient way for users to sort their entries in reverse order.

4.3.1. Current Implementation

This is how the reverse command is implemented:

ReverseSequenceDiagram
Figure 12. Sequence Diagram of Reverse Command
  1. LogicManager#execute("reverse") calls FinanceTrackerParser#parseCommand("reverse").

  2. FinanceTrackerParser#parseCommand("reverse") creates a ReverseCommand object, r.

  3. r is passed back to the FinanceTrackerParser, and then back to the LogicManager.

  4. LogicManager#execute("reverse") then moves on to call ReverseCommand#execute().

  5. ReverseCommand#execute() calls Model#reverseFilteredRecordList().

  6. Model#reverseFilteredRecordList() calls FinanceTracker#reverseRecordList().

  7. FinanceTracker#reverseRecordList() calls UniqueRecordList#reverseList().

  8. UniqueRecordList#reverseList() uses FXCollection’s static method reverse() to reverse the list of records.

  9. ReverseCommand#execute() then creates a CommandResult object and returns it back to the LogicManager.

4.4. Undo/Redo feature

4.4.1. Current Implementation

The undo/redo mechanism is facilitated by VersionedFinanceTracker. It extends FinanceTracker with an undo/redo history, stored internally as a FinanceTrackerStateList and currentStatePointer. Additionally, it implements the following operations:

  • VersionedFinanceTracker#commit() — Saves the current finance tracker state in its history.

  • VersionedFinanceTracker#undo() — Restores the previous finance tracker state from its history.

  • VersionedFinanceTracker#redo() — Restores a previously undone finance tracker state from its history.

These operations are exposed in the Model interface as Model#commitFinanceTracker(), Model#undoFinanceTracker() and Model#redoFinanceTracker() respectively.

Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.


Step 1.
The user launches the application for the first time. The VersionedFinanceTracker will be initialized with the initial finance tracker state, and the currentStatePointer pointing to that single finance tracker state.

UndoRedoStartingStateListDiagram


Step 2.
The user executes delete 5 command to delete the 5th record in the finance tracker. The delete command calls Model#commitFinanceTracker(), causing the modified state of the finance tracker after the delete 5 command executes to be saved in the financeTrackerStateList, and the currentStatePointer is shifted to the newly inserted finance tracker state.

UndoRedoNewCommand1StateListDiagram


Step 3.
The user executes spend n/burger …​ to add a new record. The spend command also calls Model#commitFinanceTracker(), causing another modified finance tracker state to be saved into the financeTrackerStateList.

UndoRedoNewCommand2StateListDiagram
If a command fails its execution, it will not call Model#commitFinanceTracker(), so the finance tracker state will not be saved into the financeTrackerStateList.


Step 4.
The user now decides that adding the record was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoFinanceTracker(), which will shift the currentStatePointer once to the left, pointing it to the previous finance tracker state, and restores the finance tracker to that state.

UndoRedoExecuteUndoStateListDiagram
If the currentStatePointer is at index 0, pointing to the initial finance tracker state, then there are no previous finance tracker states to restore. The undo command uses Model#canUndoFinanceTracker() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.

The following sequence diagram shows how the undo operation works:

UndoRedoSequenceDiagram

The redo command does the opposite — it calls Model#redoFinanceTracker(), which shifts the currentStatePointer once to the right, pointing to the previously undone state, and restores the finance tracker to that state.

If the currentStatePointer is at index financeTrackerStateList.size() - 1, pointing to the latest finance tracker state, then there are no undone finance tracker states to restore. The redo command uses Model#canRedoFinanceTracker() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.


Step 5.
The user then decides to execute the command list. Commands that do not modify the finance tracker, such as list, will usually not call Model#commitFinanceTracker(), Model#undoFinanceTracker() or Model#redoFinanceTracker(). Thus, the financeTrackerStateList remains unchanged.

UndoRedoNewCommand3StateListDiagram


Step 6.
The user executes clear, which calls Model#commitFinanceTracker(). Since the currentStatePointer is not pointing at the end of the financeTrackerStateList, all finance tracker states after the currentStatePointer will be purged. We designed it this way because it no longer makes sense to redo the spend n/burger …​ command. This is the behavior that most modern desktop applications follow.

UndoRedoNewCommand4StateListDiagram

The following activity diagram summarizes what happens when a user executes a new command:

UndoRedoActivityDiagram


4.4.2. Design Considerations

Aspect: How undo & redo executes
  • Alternative 1 (current choice): Saves the entire finance tracker.

    • Pros: Easy to implement.

    • Cons: May have performance issues in terms of memory usage.

  • Alternative 2: Individual command knows how to undo/redo by itself.

    • Pros: Will use less memory (e.g. for delete, just save the record being deleted).

    • Cons: We must ensure that the implementation of each individual command are correct.

Aspect: Data structure to support the undo/redo commands
  • Alternative 1 (current choice): Use a list to store the history of finance tracker states.

    • Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project.

    • Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both HistoryManager and VersionedFinanceTracker.

  • Alternative 2: Use HistoryManager for undo/redo

    • Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.

    • Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as HistoryManager now needs to do two different things.


4.5. Budget Management

This group of features allows the user to set a total budget and allocate a portion of the total budget to different categories. The current spending will increase when records are added.

This implementation is under Logic, Model, Storage and UI Component.

The classes associated with Budget are shown in the class diagram below:

budget classdiagram
Figure 13. Class Diagram for Budget

The above diagram shows the structure of the classes associated with Budget. TotalBudget and CategoryBudget are sub-classes of Budget and TotalBudget can contain any number of CategoryBudget.

As seen in the class diagram, the CategoryBudget in TotalBudget is kept in a HashSet.


4.5.1. Setting a Budget

This feature allows the user to set a budget for the FinanceTracker. The budget can be changed by setting the budget again.

Given below is a sequence diagram and step by step explanation of how Finance Tracker creates a budget when the user uses the set command to set a budget.

SetSequenceDiagram
Figure 14. Sequence diagram of user setting a budget
  1. The user enters a set command (e.g. set $/120). The command is passed down and received by the LogicManager.

  2. The LogicManger calls the FinanceTrackerParser#ParseCommand() method which creates a SetCommandParser object. The FinanceTrackerParser#ParseCommand() method then calls the SetCommandParser#parse() method, passing in the amount argument entered by the user ("120" in example).

  3. SetCommandParser#parse() calls ParserUtil#ParseAmount() to handle the parsing of the amount. The method checks if the argument is a valid amount value and throws an exception if it is not. If there are no exceptions, ParserUtil#ParseAmount() returns the processed amount string. SetCommandParser#parse() then creates a SetCommand with the processed amount ("120" in example) and the new SetCommand gets passed back to the LogicManager.

  4. Now that the command is processed, LogicManager#execute() calls SetCommand#execute() to execute the command. SetCommand#execute() creates a new Budget object initialised with the amount (budget of 120 created in example). The Budget object (labelled p) is then passed to the ModelManager by the ModelManager#addBudget() method.

  5. ModelManager#addBudget() calls FinanceTracker#addBudget() to update the budget of the current instance of the Finance Tracker. FinanceTracker#addBudget() updates the TotalBudget object field (labelled q) in FinanceTracker by calling TotalBudget#updateBudget() and passing the Budget p and the records stored in the FinanceTracker.

  6. TotalBudget#updateBudget() first checks whether the new budget set is more than or equal to the sum of the category budgets and throws an exception if it is not. It then gets the budget data (totalBudget, currentBudget) from Budget p and sets it using TotalBudget#set() (total budget of app is now 120 in example). It then updates the current budget and spending based on the records that was stored and passed in by the FinanceTracker. This is shown in the code snippet below:

    public void updateBudget(Budget budget, ObservableList<Record> records) throws
                CategoryBudgetExceedTotalBudgetException {
            Double totalCategoryBudget = 0.0;
            for (CategoryBudget cb: this.categoryBudgets) {
                totalCategoryBudget += cb.getTotalBudget();
            }
            if (budget.getTotalBudget() < totalCategoryBudget) {
                throw new CategoryBudgetExceedTotalBudgetException(budget, totalCategoryBudget);
            }
            set(budget.getTotalBudget(), budget.getCurrentBudget());
            updateBudget(records);
        }
  7. Once TotalBudget q has finished updating, control is passed all the way back to SetCommand#execute() which will create a CommandResult (labelled result). The result is passed back to LogicManager#execute and all the way to the user to show that the budget has been set (Budget set to 120 in example).

  8. Although not shown in the diagram, the UI is then updated with the new budget. The UI update of budget data will be covered in Section 4.5.7, “Updating the UI with Budget Data”.


4.5.2. Design Consideration

Aspect: Updating budget data after Record updates
  • Solution 1: Maintaining one updateBudget method to update current expenditure and budget left based on iterating through changed record list.

    • Pros: Easier to implement and manage a single method.

    • Cons: Updates for even single addition/edit/deletion of record could be slow if record list gets too large.

  • Solution 2: Maintain individual methods for each update of budget data (add/edit/remove records) (Current Implementation)

    • Pros: App would run updates faster with more targeted methods.

    • Cons: More code and test cases to be written to implement and maintain several methods for updating budget.


4.5.3. Allocating a budget to category

This feature allows user to set a category budget after the total budget is set.

Given below is a sequence diagram and step by step explanation of how Finance Tracker executes when a user sets a category budget.

AllocateSequenceDiagram
Figure 15. Sequence diagram of user setting a category budget
  1. User enters command allocate $/10 c/Food. The command is received by FinanceTrackerParser

  2. FinanceTrackerParser will then create a AllocateCommandParser Object and calls AllocateCommandParser#parse() method

  3. AllocateCommandParser#parse() method calls ArgumentTokenizer#tokenize() method to tokenize the user input String into arguments and prefixes in an ArgumentMultimap Object.

  4. AllocateCommandParser#parse() method then calls another method within the same class AllocateCommandParser#arePrefixesPresent() to check if there are any missing prefixes. If there are missing prefixes, ParseException will be thrown

  5. If no exceptions are thrown from the step 4, a new AllocateCommand object is created with the given arguments.

  6. Control is returned to LogicManager which then calls AllocateCommand#execute() method.

  7. AllocateCommand#execute() calls ModelManager#addCategoryBudget() method and control is transferred to ModelManager which is in the Model Component.

  8. ModelManager#addCategoryBudget() then calls FinanceTracker#addCategoryBudget() which then calls TotalBudget#setNewCategoryBudget().

  9. TotalBudget#setNewCategoryBudget() takes into account if there are any previous budget allocated to a category and if so, adds the expenses to the new budget assigned to the category.


4.5.4. Design consideration

Aspect: allocating Category Budget
  • Alternative 1 (current choice): Allocating Category Budget is done with only one command allocate

    • Pros: User only needs to make use of one command to control the budget of the category and will not be confused with too many other commands.

    • Cons: Requires the developer to ensure the application checks that if there is a current budget allocated to the same category, it should be reflected accordingly.

  • Alternative 2: Have two other commands increaseCatBudget and decreaseCatBudget to allow user to control the budget of the category

    • Pros: User is able to adjust the budget by increasing/decreasing the budget and error message will be shown. if the category was not previously allocated with a budget

    • Cons: User might be confused with too many commands and not intuitive.


4.5.5. Listing Category Budgets allocated

This feature allows user to list the category budgets and the current spending in these categories after category budgets are allocated.


4.5.6. Implementation

  1. User enters command show in Command Box.

  2. ShowCategoryBudgetCommand#execute() is executed and the method first checks whether there are any allocated category budgets.

  3. If there are no allocated category budgets, a message will be printed in the ResultDisplay.

  4. If there are allocated category budgets, Model#getCatBudget() is called to obtain the set of CategoryBudget.

  5. An Iterator is then used to iterate through the set of CategoryBudgets and the currentSpending is printed with the totalBudget allocated to the CategoryBudget.


4.5.7. Updating the UI with Budget Data

Previous sections have covered how the budget of the Finance Tracker is updated within the App. This section aims to give a overview of the logic for updating the User Interface of the App to reflect the budget updates to the user.

To explain the update, an Activity Diagram accompanied with a step-by-step walk-through is proved. The Activity Diagram is modelled after MainWindow#execute() which calls the appropriate methods to update the budget UI.

BudgetUiUpdateActivityDiagram
Figure 16. Activity diagram of the UI being updated after budget data changes
  1. The command is first executed by the LogicManager. The execution of commands will update the budget data in the Finance Tracker as specified in previous sections. The success message of the command is then displayed to the user (Result of command that user typed).

  2. There is then a conditional check on whether the command has changed the budget data (Based on CommandResult passed back from command execution). For brevity and based on the scope of the section, the other conditional checks for the command will be excluded. List of Commands that change budget: spend, edit, delete, set, allocate, clear, setfile, undo, redo

  3. When it has been determined that the command has altered budget data, 3 components of the UI need to be updated before continuing. If you are unfamiliar with the components of the UI, refer to the Graphical User Interface section of our User Guide.

    1. BudgetPanel: The BudgetPanel consists of 2 sections, the Budget Bar and the text below the bar. The bar and text is updated with data retrieved from the Logic component of the App, with the changes to Budget Bar being animated. The colour of the bar is then set based on the difference in current spending and total budget set (Red: Budget Exceeded, Yellow: Spending is >= 80% of budget, Green: Spending is <80% of budget).

    2. Browser Panel: The BrowserPanel only contains text and is updated similar to the text in the BudgetPanel.

    3. Summary Panel: The SummaryPanel consists of a pie chart. If the updated budget data shows no expense recorded within the specified time period, text explaining that there is no recorded expenses is shown to the user instead. Else, the summary data is updated and the pie chart is edited to reflect changes in the expenditures. Refer to Section 4.6, “Summary” for a more detailed explanation of the implementation of the feature.

  4. After the UI is updated, there is another check to see if the command given was summary. If it was, the current Panel being displayed (BrowserPanel or SummaryPanel) is swapped to the other panel. Again, refer to the Summary section below for more implementation details.

  5. The method ends by returning the CommandResult that was returned from the execution of command to the MainApp.


4.6. Summary

The summary feature shows an overview of your previous expenditures in a pie chart. Each sector of the chart represents a category, labelled with the name and total expenditure for each category.

You can also set a report period by indicating the number of days or months. Specifying a report period is optional. If no parameters are defined, data of expenditures in the past week (ie. the last 7 days) will be displayed in the pie chart by default.


4.6.1. Implementation

The implementation of the Summary command can be divided into two phases – preparation and execution. Given below is an explanation of how the summary mechanism behaves at each phase.


Preparation

In the preparation phase, the application will parse the command. Below is the UML Sequence diagram and a step-by-step explanation of the preparation stage.

SummarySequenceDiagram
Figure 17. Sequence diagram of the preparation stage in the summary mechanism
  1. User first enters the command summary #/7 p/d. This command is received by FinanceTrackerParser, which then calls SummaryCommandParser#parse() to create SummaryCommand.

  2. If no parameters are provided by the user, SummaryCommand#SummaryCommand() is called to create SummaryCommand with the default parameters of periodAmount as 7 and period as d. Otherwise, SummaryCommand#SummaryCommand(periodAmount, period) is called to create SummaryCommand with the specified parameters.

  3. SummaryCommand then checks if the parameters are valid. If any parameter is invalid, an exception will be thrown, and an error message will be shown to the user. Else, the parameters are stored in instance variables and SummaryCommand is returned to LogicManager.

  4. LogicManager then calls SummaryCommand#execute(), which updates the variables RecordSummaryPredicate, summaryPeriod and periodAmount in ModelManager.

Execution

In the execution phase, the program handles ShowSummaryRequestEvent posted by SummaryCommand to retrieve the data to be displayed. The data will be rendered as a JavaFX PieChart and then displayed. Below is the UML sequence diagram and a step-by-step explanation of the execution stage.

SummarySequenceDiagram2
Figure 18. Sequence diagram of the execution stage in the summary mechanism


  1. The handleShowSummary will be handled by MainWindow#handleShowSummary(), which will call SummaryPanel#setData() and pass the data as parameters by calling Logic#getRecordSummary(), Logic#getSummaryPeriod() and Logic#getPeriodAmount().

  2. Logic#getRecordSummary() gets the filtered record list by calling Model#getRecordSummary(), which returns an unmodifiable ObservableList, containing only expenses in the last 7 days.

  3. Logic#getRecordSummary() then organises the data into a LinkedHashMap<String, Double>, where the key value pair represents category and cost.

  4. Logic#getSummaryPeriod() and Logic#getPeriodAmount() get their respective data by calling the method of the same name in Model.

  5. Once the parameters are passed into SummaryPanel#setData(), StackPane#getChildren()#clear() is called to clear any display elements in StackPane. JavaFX’s PieChart is then used to render the summary pie chart. There are two possible scenarios which could happen:

    1. If the data received is empty, a Text object is generated and StackPane#getChildren()#add() is called, which informs the user that there are no expenditures.

    2. Else, SummaryPanel#setSummaryData() will be called, which generates a Pie Chart and calls StackPane#getChildren()#add(), which adds it to StackPane. This is shown in the code snippet below:

      public void setSummaryData(LinkedHashMap<String, Double> summaryData) {
              PieChart pieChart = new PieChart();
              Set<String> keySet = summaryData.keySet();
              for (String s : keySet) {
                  pieChart.getData().add(new PieChart.Data(s, summaryData.get(s)));
              }
              for (int i = 0; i < pieChart.getData().size(); i++) {
                  PieChart.Data data = pieChart.getData().get(i);
                  data.getNode().getStyleClass().add(getPieChartColorStyleFor(data.getName()));
                  data.nameProperty().bind(Bindings.concat(data.getName(), " - $",
                                          String.format("%.2f", data.getPieValue())));
              }
              pieChart.setLegendSide(Side.BOTTOM);
              chartArea.getChildren().add(pieChart);
      }


4.6.2. Design Consideration

Aspect: Representation for Summary of Expenditure

Alternative 1 (current choice): Represent summary of expenses using a pie chart.

summaryPanel
Figure 19. Current Implementation of Summary Panel using JavaFX’s PieChart
  • Pros: Labels can act as a legend as well as there might be categories with similar colours. This will help the user to easily identify the expenditures in different categories.

  • Cons: If there are too many categories, the labels may not show up as it will clash with the other labels. The data presented may also become too cluttered as well.

Alternative 2 (planned for [v2.0]): Represent summary of expenses using an Aster Plot graph.

In v2.0 of In-Credit-Ble, the summary feature intends to use a D3.js Aster Plot graph to display the summary of expenditures instead of the current pie chart. This will help contribute to the aesthetics and user-friendliness of displaying the data in In-Credit-Ble.

asterPlot
Figure 20. Example of Aster Plot Graph

Each sector of the chart represents a category. The area of each sector indicates the total budget amount allocated for a particular category, while the coloured area of the sector denotes the amount spent for that category. On mouseover of each sector, a pop-up display of the category name and amount spent for each category will be shown. The colours used for the category in the aster plot graph should also correspond to the same colour palette used for the category labels.

  • Pros: More effective in showing the user what is the remaining budget amount for each category. It also allows users to easily perceive whether their spending is within their budget for each category.

  • Cons: Difficult to implement as it requires linking to D3, a third party JavaScript library for data visualisations via HTML, SVG, and CSS.

4.7. Theme

The theme feature allows users to change the colour theme of the application to provide them with some customisation.


4.7.1. Implementation

  1. User enters command theme COLOUR in Command Box, where COLOUR is either dark, light, blue or pink.

  2. ThemeCommand#formatTheme() is executed to change the user input of COLOUR to a word that has first character in uppercase and the rest of the characters in lowercase.

  3. ThemeCommand#isValidTheme() is then used to check if the COLOUR is one of the four specified above.

  4. ThemeCommand then returns a CommandResult that sets the boolean field changeTheme to true.

  5. MainWindow#handleSwitchTheme() is then executed to call the appropriate method to switch the theme of the application to the user-specified input.


4.8. Logging

We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (See Section 4.9, “Configuration”).

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class) which will log messages according to the specified logging level.

  • Currently log messages are output through: Console and to a .log file.


Logging Levels

  • SEVERE : Critical problem detected which may possibly cause the termination of the application

  • WARNING : Can continue, but with caution

  • INFO : Information showing noteworthy actions by the application

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

4.9. Configuration

Certain properties of the application can be controlled (e.g. user prefs file location, logging level) through the configuration file (default: config.json).

5. Documentation


We use asciidoc for writing documentation.

We chose asciidoc over Markdown because asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting.


5.1. Editing Documentation


See UsingGradle.adoc to learn how to render .adoc files locally to preview the end result of your edits. Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc files in real-time.


5.2. Publishing Documentation


See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.


5.3. Converting Documentation to PDF format


We use Google Chrome for converting documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.

Here are the steps to convert the project documentation files to PDF format.

  1. Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the docs/ directory to HTML format.

  2. Go to your generated HTML files in the build/docs folder, right click on them and select Open With  Google Chrome.

  3. Within Chrome, click on the Print option in Chrome’s menu.

  4. Set the destination to Save as PDF, then click Save to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.

chrome save as pdf
Figure 21. Saving project documentation files to PDF format


5.4. Site-wide Documentation Settings


The build.gradle file specifies some project-specific asciidoc attributes which affects how all documentation files within this project are rendered.

Attributes left unset in the build.gradle file will use their default value, if any.


Table 4. List of site-wide attributes
Attribute name Description Default value

site-name

The name of the website. If set, the name will be displayed near the top of the page.

not set

site-githuburl

URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar.

not set

site-seedu

Define this attribute if the project is an official SE-EDU project. This will render the SE-EDU navigation bar at the top of the page, and add some SE-EDU-specific navigation items.

not set

5.5. Per-file Documentation Settings


Each .adoc file may also specify some file-specific asciidoc attributes which affects how the file is rendered.

Asciidoctor’s built-in attributes may be specified and used as well.

Attributes left unset in .adoc files will use their default value, if any.


Table 5. List of per-file attributes, excluding Asciidoctor’s built-in attributes
Attribute name Description Default value

site-section

Site section that the document belongs to. This will cause the associated item in the navigation bar to be highlighted. One of: UserGuide, DeveloperGuide, LearningOutcomes*, AboutUs, ContactUs

* Official SE-EDU projects only

not set

no-site-header

Set this attribute to remove the site navigation bar.

not set

5.6. Site Template


The files in docs/stylesheets are the CSS stylesheets of the site. You can modify them to change some properties of the site’s design.

The files in docs/templates controls the rendering of .adoc files into HTML5. These template files are written in a mixture of Ruby and Slim.

Modifying the template files in docs/templates requires some knowledge and experience with Ruby and Asciidoctor’s API. You should only modify them if you need greater control over the site’s layout than what stylesheets can provide.


6. Testing


6.1. Running Tests


There are three ways to run tests.

The most reliable way to run tests is the 3rd one. The first two methods might fail some GUI tests due to platform/resolution-specific idiosyncrasies.


Method 1: Using IntelliJ JUnit test runner

  • To run all tests, right-click on the src/test/java folder and choose Run 'All Tests'.

  • To run a subset of tests, you can right-click on a test package, test class, or a test and choose Run 'ABC'.


Method 2: Using Gradle

  • Open a console and run the command gradlew clean allTests (Mac/Linux: ./gradlew clean allTests).

See UsingGradle.adoc for more info on how to run tests using Gradle.


Method 3: Using Gradle (headless)

Thanks to the TestFX library we use, our GUI tests can be run in the headless mode. In the headless mode, GUI tests do not show up on the screen. That means the developer can do other things on the Computer while the tests are running.

To run tests in headless mode, open a console and run the command gradlew clean headless allTests (Mac/Linux: ./gradlew clean headless allTests).

6.2. Types of tests


We have two types of tests:

  1. GUI Tests - These are tests involving the GUI. They include,

    1. System Tests that test the entire application by simulating user actions on the GUI. These are in the systemtests package.

    2. Unit tests that test the individual components. These are in seedu.finance.ui package.

  2. Non-GUI Tests - These are tests not involving the GUI. They include,

    1. Unit tests targeting the lowest level methods/classes.
      e.g. seedu.finance.commons.StringUtilTest

    2. Integration tests that are checking the integration of multiple code units (those code units are assumed to be working).
      e.g. seedu.finance.storage.StorageManagerTest

    3. Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
      e.g. seedu.finance.logic.LogicManagerTest


6.3. Troubleshooting Testing


Problem: HelpWindowTest fails with a NullPointerException.

  • Reason: One of its dependencies, HelpWindow.html in src/main/resources/docs is missing.

  • Solution: Execute Gradle task processResources.


7. Dev Ops


7.1. Build Automation


See UsingGradle.adoc to learn how to use Gradle for build automation.


7.2. Continuous Integration


We use Travis CI and AppVeyor to perform Continuous Integration on our projects. See UsingTravis.adoc and UsingAppVeyor.adoc for more details.


7.3. Coverage Reporting


We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.


7.4. Documentation Previews


When a pull request has changes to asciidoc files, you can use Netlify to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged. See UsingNetlify.adoc for more details.


7.5. Making a Release


Here are the steps to create a new release.

  1. Update the version number in MainApp.java.

  2. Generate a JAR file using Gradle.

  3. Tag the repo with the version number. e.g. v0.1

  4. Create a new release using GitHub and upload the JAR file you created.


7.6. Managing Dependencies


A project often depends on third-party libraries. For example, In-Credit-Ble depends on the Jackson library for JSON parsing. Managing these dependencies can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives:

  1. Include those libraries in the repo (this bloats the repo size)

  2. Require developers to download those libraries manually (this creates extra work for developers)


Appendix A: Product Scope


Target user profile:

  • has a need to manage a significant amount of expenses/finances

  • has a need to be more aware of his/her spending habits/patterns

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI applications


Value proposition: Manage expenses faster than a typical mouse/GUI driven application


8. User Stories


Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *


Priority As a …​ I want to …​ So that I can…​

* * *

new user

see usage instructions

refer to it when I forget how to use the application

* * *

user

have a record of my recent expenses (day, week, month, category)

be more aware of where I am spending my money

* * *

user

add a new entry

* * *

user

delete an entry

remove an entry that is no longer needed anymore

* * *

user

categorise my expenses

be aware of what I am spending most of my money on

* * *

user

be able to set a budget (a total for the month and for which category)

be more thrifty in terms of my expenditure

* *

user

summarise my daily spending in a pictorial form

easily see how on track I am in adhering to my budget

* *

user

locate a specific entry easily

recall how much I spent

* *

user

save my data

refer to it when I use the application next time

* *

user

sort my expenses in terms of amount

be aware of what costs the most

* *

user

set daily budgets

limit the amount I spend each day

*

user

analyse my spending habits/patterns

derive a savings plan and better plan my expenses

*

spendthrift user

receive tips to be a better saver

be more aware of different ways to keep within my budget

*

IT savvy user

categorise my expenses based on the different methods of payment

automatically track my cashless expenditures as well as credit card transactions


9. Use Cases


(For all use cases below, the System is In-Credit-Ble and the User is the user, unless specified otherwise)


Use case: Setting a budget for the month

MSS

  1. User requests to set a budget for the current month

  2. System displays current budget amount for the month

    Use case ends.

Extensions

  • 2a. With addition of expense entries, System updates the remaining amount in the current month’s budget

    Use case ends.


Use case: Allocate budget to a category

MSS

  1. User requests to list summary of budget based on category

  2. System shows a summary of budget based on category

  3. User requests to allocate a certain amount to a category

  4. System allocates the user input amount to the given category

    Use case ends.


Use case: Increasing budget for the month

MSS

  1. User requests to list entries

  2. System shows a list of expense entries

  3. User requests to increase budget for the month (can be associated with a category)

  4. System will increase the budget for the month (that is associated with category input)

    Use case ends.


Use case: Add expense entry

MSS

  1. User requests to list entries

  2. System shows a list of expense entries

  3. User requests to add a specific expense entry in the list

  4. System adds the expense entry

    Use case ends.

Extensions

  • 3a. Some fields are missing.

    • 3a1. System shows an error message.

      Use case resumes at step 2.


Use case: Editing an expense entry

MSS

  1. User requests to list expense entries

  2. System shows a list of expense entries

  3. User requests to edit a specific expense entry in the list

  4. System updates the expense entry as well as the budget summary accordingly

    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: Delete expense entry

MSS

  1. User requests to list expense entries

  2. System shows a list of expense entries

  3. User requests to delete a specific expense entry in the list

  4. System deletes the entry

    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: Listing history of entered commands

MSS

  1. User requests to list history of entered commands

  2. System shows history of commands in reverse chronological order (latest command first)

    Use case ends.

Extensions

  • 1a. There was no entered commands

    Use case ends.


Use case: User wants to undo previous command

MSS

  1. User requests to undo previous command

  2. System undo previous command and updates budget accordingly

    Use case ends.

Extensions

  • 1a. There was no previous command

    Use case ends with message to let User know there is no previous command


Use case: User wants to redo previous undone command

MSS

  1. User requests to redo previous undone command

  2. System redo previous undone command and updates budget accordingly

    Use case ends.

Extensions

  • 1a. There was no previous undone command

    Use case ends with message to let User know there is no previous undone command


Use case: User wants to clear all entries

MSS

  1. User requests to clear all entries

  2. System clears all entries and updates the budget accordingly

    Use case ends.

Extensions

  • 1a. There are no entries in the System

    Use case ends with message to let User know there are no entries in System


10. Non Functional Requirements


  1. Should work on any mainstream OS as long as it has Java 9 or higher installed.

  2. Should work on both 32-bit and 64-bit environments.

  3. Should be able to hold up to 1000 expenditure records without a noticeable sluggishness in performance for typical usage.

  4. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.

  5. The user interface should be intuitive and easy to use for people who are not IT-savvy.

  6. Responses by the system should be fast (~5 seconds).


11. Glossary


Amount

The amount of money for expenditure and budget

Entry

A listed item/activity tracked by the application. It generally consists of the name, amount and date along with a category tag (if specified)

Mainstream OS

Windows, Linux, Unix, OS-X

Records

The list of all entries stored in the application


12. Product Survey


Monefy - Money Manager

Author: Aimbity AS

Pros:

  • Interface is easy to use

  • Able to track expenses and income over various periods of time

  • Free

Cons:

  • Unable to synchronise and restore or backup data between devices

  • Do not have an auto-income function

  • Do not have an option for reminder

  • Do not have a feature for recurrent spending

Money Lover: Expense Tracker & Budget Planner


Author: Finsify

Pros:

  • Allows setting of recurring payments

  • Able to see what expenses add up to in the forthcoming months

  • Able to sync across phone and computer

  • Able to download to own excel worksheet

Cons:

  • Need to make a budget for every wallet

  • Unable to choose multiple categories for a budget

  • Unable to edit a transaction

  • Budgets are based per account


Seedly - Personal Finance App

Author: Seedly Pte Ltd

Pros:

  • Visually appealing

  • Able to import transactions from ibanking accounts and allow manual inputs for cash transactions

  • Pie charts give a visual illustration on expenditure

  • Search function present

Cons:

  • Sync feature takes a long time

  • Crash every now and then

  • Categories are hard to identify in pie charts

  • Not smart enough to recognise similar entries

  • Summary presented is confusing

  • Unable to add in sub-categories to further pinpoint area of spending


13. Instructions for Manual Testing


Given below are instructions to test the application manually.

These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.


13.1. Launch and Shutdown


  1. Initial launch

    1. Download the JAR file and copy into an empty folder.

    2. Double-click the JAR file.
      Expected: Shows the GUI with a set of sample records. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size. Move the window to a different location. Close the window.

    2. Re-launch the application by double-clicking the JAR file.
      Expected: The most recent window size and location is retained.


13.2. Setting a budget


  1. Setting a initial budget

    1. Test case: set $/500
      Expected: The budget is set to $500. The Budget Panel and Browser Panel are updated accordingly.

    2. Test case: set $/500.50
      Expected: The budget is changed to $500.50. The Budget Panel and Browser Panel are updated accordingly.

    3. Test case: set 500
      Expected: The budget is not changed. Error details shown in the status message. Status bar remains the same.

    4. Test case: set $/$500
      Expected: The budget is not changed. Error details shown in status message about amount.

    5. Test case: set $/-1
      Expected: Similar to previous.

    6. Test case: set $/0
      Expected: Similar to previous.


13.3. Allocating category budgets and showing allocated category budgets


  1. Allocating category budget (no spending in category; we assume that total budget set is $500)

    1. Test case: allocate $/50 c/Shopping, then show
      Expected: Category Budget is allocated in Shopping category. Result Display shows current spending over budget. for allocated category budgets

    2. Test case: allo $/30 c/Transport, then show
      Expected: Category Budget is allocated in Transport category. Result Display shows current spending over budget. for allocated category budgets

    3. Test case: allocate $/30 c/Books c/Movies, then show
      Expected: Category Budget allocated in Movies category. Result Display current spending over budget. for allocated category budgets

    4. Test case: allocate $/$30 c/Holiday
      Expected: Category Budget not allocated. Error details shown in status message.

    5. Test case: allocate $/30 c/Holiday In Melbourne
      Expected: Category Budget not allocated. Error details shown in status message.

    6. Test case: allocate $/600 c/School
      Expected: Category Budget not allocated. Category Budget more than Total budget. Error details in status message.

  2. Allocating category budget (previously had spending in the category)
    Assume that Food category has $16.50 spent so far

    1. Test case: allocate $/17 c/Food
      Expected: Category Budget allocated in Food category. Result Display shows current spending over budget for allocated category budgets.

    2. Test case: allocate $/10 c/Food
      Expected: Category Budget not allocated. Current Spending in category more than user input for category budget. Error details shown in status message.


13.4. Adding an expense


  1. Adding an entry no matter what is listed.

    1. Test case: spend n/Chicken Rice $/5.50 c/Food d/1/4/2019 r/Tasty
      Expected: Entry is added to the back of the list. Timestamp in the status bar is updated.

    2. Test case: spend n/Tshirt $/10.00 d/31/03/2019 c/Food c/Clothes
      Expected: Entry is added to the back of the list. Category recorded down is Clothes. Timestamp in the status bar is updated.

    3. Test case: spend n/Chicken Rice $/5.50 c/Food
      Expected: Entry is added to the back of the list. Since date is not supplied, today’s date will be recorded. Timestamp in the status bar is updated.

    4. Test case: add n/Chicken Rice $/5.50 c/Food
      Expected: Entry is added to the back of the list. Since date is not supplied, today’s date will be recorded. Timestamp in the status bar is updated.

    5. Test case: spend n/Chicken Rice $/5.50
      Expected: No entry is added. Error details shown in the status message. Status bar remains the same.

    6. Other incorrect spend commands to try: spend n/Chicken Rice c/Food, spend $.5.50 c/Food, spend n/Chicken Rice $/5.5 c/Food, spend n/Chicken Rice $/5.50 c/Food d/12/12/2045, spend n/Chicken Rice $/$5.50 c/Food
      Expected: Similar to previous


13.5. Editing an expense


  1. Edit an entry while all entries are listed

    1. Prerequisites: List all entries using the list command. The list must have some entries in it.

    2. Editing one parameter of an entry.

      1. Test case: edit 1 n/test
        Expected: The name of the first entry is being changed to test. Time stamp in the status bar is updated.

      2. Test case: edit 1 d/01/02/2003
        Expected: The date of the first entry is being changed to 01/02/2003. Time stamp in the status bar is updated.

      3. Test case: edit 1 $/100
        Expected: The amount spent of the first entry is changed to $100. The budget shown in the budget panel and the browser panel is updated. Time stamp in the status bar is updated.

      4. Test case: edit 1 c/Test
        Expected: The category of the first entry is changed to Test. Time stamp in the status bar is updated.

      5. Test case: edit 1 r/Testing testing
        Expected: The description of the first entry is changed to "Testing testing". Time stamp in the status bar is updated.

    3. Editing more than one parameter of an entry

      1. Test case: edit 1 n/test1 $/123
        Expected: The first entry is being changed based on the command. The budget shown in the budget panel and the browser panel is updated. Time stamp in the status bar is updated.

      2. Test case: edit 1 n/test2 $/1234 d/01/01/2001
        Expected: Similar to previous.

      3. Test case: edit 1 n/test3 $/12345 d/01/01/2002 c/Test1
        Expected: Similar to previous.

      4. Test case: edit 1 n/test4 $/123456 d/01/01/2003 c/Test2 r/Testing test
        Expected: Similar to previous.

    4. Removing description for an entry

      1. Prerequisites: The first entry of the list must have a description.

      2. Test case: edit 1 r/
        Expected: The description for the first entry is removed.

    5. Invalid command due to index

      1. Test case: edit 0 n/test
        Expected: No entry is edited. Error details shown in the status message. Status bar remains the same.

    6. Invalid command due to parameters

      1. Test case: edit 1 $/test
        Expected: No entry is added. Error details shown in the status message. Status bar remains the same.

      2. Other incorrect edit commands to try: edit 1 d/01/01/2045, edit 1 $/$100, edit 1 r/12345678901234567890123456789012345678901.


13.6. Deleting an entry


  1. Deleting an entry while all entries are listed.

    1. Prerequisites: List all entries using the list command. Multiple entries in the list.

    2. Test case: delete 1
      Expected: First entry is deleted from the list. Details of the deleted entry shown in the status message. Timestamp in the status bar is updated.

    3. Test case: delete 0
      Expected: No entry is deleted. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect delete commands to try: delete, delete x (where x is larger than the list size), delete three
      Expected: Similar to previous.


13.7. Searching an entry


In order for the expected results of the test to be accurate, please input the following commands below to set up your finance tracker.
1. clear
2. spend n/Chicken Rice $/5.50 c/Food d/1/4/2019
3. spend n/Chicken Rice $/5.50 c/Food d/2/4/2019
4. spend n/Cupcakes $/2.50 c/Food d/2/4/2019
5. spend n/Tshirt $/15 c/Clothes d/1/4/2019
6. spend n/Jeans $/40 c/Clothes d/2/4/2019
  1. Searching for an entry or entries in a list.

    1. Prerequisites: There must already be entries that are shown in the record list panel. Please set up the finance tracker as shown in the NOTE above.

    2. Search by name

      1. Test case: search -name chicken rice
        Expected: 2 records are shown in the records list panel. The result display shows that the total spent on the searched records is $11.00.

      2. Test case: search -name chicken
        Expected: Same as previous.

    3. Search by category

      1. Test case: search -cat clothes
        Expected: 2 records are shown in the records list panel. The result display shows that the total spent on the searched records is $55.00.

    4. Search by date

      1. Test case: search -date 2/4/2019
        Expected: 3 records are shown in the records list panel. The result display shows that the total spent on the searched records is $48.00.

      2. Test case: search -date 5/4/2019
        Expected: 0 records are shown in the records list panel. The result display shows that the total spent on the searched records is $0.00.

    5. Search with no records shown

      1. No matches in the keywords: search -date 5/4/2019
        Expected: 0 records are shown in the records list panel. The result display shows that the total spent on the searched records is $0.00.

      2. No parameters inputted after the search flag: search -date
        Expected: Same as previous.

    6. Invalid search command

      1. Test case: search -cat -date Expected: Error message is shown. The records list panel remains the same.

      2. Other incorrect search commands to try: search -food, search -cat -food, search -cat -date -name.


13.8. Sorting the entries


  1. Sort entries by name

    1. Prerequisites: List must have some entries in it.

    2. Test case: sort -name
      Expected: List is sorted by name in lexicographical order. Timestamp in the status bar is updated.

    3. Test case: sort -name -desc
      Expected: List is sorted by name in reverse lexicographical order. Timestamp in the status bar is updated.

    4. Test case: sort -name -asc
      Expected: List is sorted by name in lexicographical order. Timestamp in the status bar is updated.

    5. Test case: sort -asc -name
      Expected: List will not be sorted. Error message is shown. Status bar remains the same.

    6. Other incorrect sort commands to try: sort -desc -name, sort -name -inc, sort -name -asc a-z
      Expected: Similar to previous.

  2. Sort entries by amount

    1. Prerequisites: List must have some entries in it.

    2. Test case: sort -amount
      Expected: List is sorted by amount in descending order. Timestamp in the status bar is updated.

    3. Test case: sort -amount -asc
      Expected: List is sorted by amount in ascending order. Timestamp in the status bar is updated.

    4. Test case: sort -amount -desc
      Expected: List is sorted by amount in descending order. Timestamp in the status bar is updated.

    5. Test case: sort -asc -amount
      Expected: List will not be sorted. Error message is shown. Status bar remains the same.

    6. Other incorrect sort commands to try: sort -desc -amount, sort -amount -inc, sort -name -amount
      Expected: Similar to previous.


13.9. Obtaining a summary of entries


  1. Entering summary command when In-Credit-Ble is empty.

    1. Prerequisites: No existing entries in In-Credit-Ble.

    2. Test case: summary
      Expected: Error message is shown.

    3. Test case: summary #/6 p/d
      Expected: Error message is shown.

    4. Test case: summary #/10 p/m
      Expected: Error message is shown.

  2. Entering summary command when there are entries listed in the records list panel.

    1. Prerequisites: There is at least one entry that exists in the specified report period.

    2. Test case: summary
      Expected: Entries that have been entered in In-Credit-Ble in the past 7 days will be displayed in the pie chart. A success message will also be displayed in the result box.

    3. Test case: summary #/9 p/d
      Expected: Entries that have been entered in In-Credit-Ble in the past 9 days will be displayed in the pie chart. A success message will also be displayed in the result box.

    4. Test case: summary #/5 p/m
      Expected: Entries that have been entered in In-Credit-Ble in the past 5 months will be displayed in the pie chart. A success message will also be displayed in the result box.

On the other hand, if there are no existing entries in the specified report period (but In-Credit-Ble has other existing entries):

  1. Test case: summary #/9 p/m
    Expected: Error message is shown.


13.10. Changing the Finance Tracker data storage location

In order to test this command, please take note the name of the json file you are currently on. The name of the file can be seen at the right side of the status bar. By default, the json file is "finance.json".
  1. Changing the file when the filename does not belong to a file that exists or the file is wrongly formatted.

    1. Prerequisites: The filename does not belong to an existing json file with stored Finance Tracker data. The user is currently using finance.json file.

    2. Test case: setfile f/testfile
      Expected: A new finance tracker file will be created with no records in the records list and the budget will be shown as $0.00.

  2. Changing the file when the filename belongs to a file with existing data added by the In-Credit-Ble.

    1. Prerequisites: The filename belongs to a file that already exists with data added by In-Credit-Ble or data that is correctly formatted.

    2. Test case: setfile f/testfile
      Expected: The data previously added to testfile.json will be loaded into In-Credit-Ble.

    3. Test case: setfile f/finance
      Expected: No apparent change as the same file the user is currently on will be loaded again.