Developer Guide
Around the World in $80 (AWE) is a desktop application for keeping track of spending and expenditure during travels, splitting expenses with travel-mates, and facilitating easy recollection of debts at the end of every trip. AWE is the world’s only bespoke app designed for group travellers.
The app promises to revolutionize the group-travel space. With AWE, bills can be split and monitored in a centralized manner that maximizes the potential for disputes and maximizes the efficiency of payment and recollection of debts.
AWE’s vision is a more interconnected world where relationships are more easily built and maintained. Our mission is to accomplish through a user-centric approach that seeks to provide the user with what they need, at the tip of their fingertips. This document marks the first step towards the accomplishment of that mission, and the beginning of your journey around the world.
Table of Contents
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
-
Appendix: Instructions for manual testing
- Launch and shutdown
- Deleting a contact
- Editing a contact
- Creating a group
- Deleting a Group
- Editing group name
- Adding a contact to group
- Removing a contact from group
- Adding a tag to group
- Removing a tag from group
- Searching for groups
- Viewing expenses
- Finding expenses
- Adding an expense
- Deleting an expense
- Calculating transaction summary
- Calculating payments
Acknowledgements
This project is based on the AddressBook-Level3 project created by the SE-EDU initiative.
Setting up, getting started
Refer to the guide Setting up and getting started.
Click here to return to table of contents
Design
.puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
Fig 1. Architecture Diagram
The Architecture Diagram given above explains the high-level design of the App.
Click here to return to table of contents
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main has two classes called Main and MainApp. It is responsible for,
- At app launch: Initializes the components in the correct sequence, and connects them up with each other.
- At shut down: Shuts down the components and invokes cleanup methods where necessary.
Commons represents a collection of classes used by multiple other components.
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.
How 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 deletecontact 1.
Fig 2. Architecture Sequence Diagram
Click here to return to table of contents
Each of the four main components (also shown in the diagram above),
- defines its API in an
interfacewith the same name as the Component. - implements its functionality using a concrete
{Component Name}Managerclass (which follows the corresponding APIinterfacementioned in the previous point.
For example, the Logic component defines its API in the Logic.java interface and implements its functionality using the LogicManager.java class which follows the Logic interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
Fig 3. Component Managers
The sections below give more details of each component.
Click here to return to table of contents
UI component
The API of this component is specified in Ui.java
Fig 4. Ui Class Diagram
The UI consists of a MainWindow that is made up of parts e.g. CommandBox, ResultDisplay, ViewPanel, NavigationButton etc.
All these, except for GroupButtonListener and PersonButtonListener in NavigationButton, inherit from the abstract UiPart class which captures the commonalities between classes that represent parts of the visible GUI.
Click here to return to table of contents
The UI component uses the 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
Logiccomponent. - listens for changes to
Modeldata so that the UI can be updated with the modified data. - keeps a reference to the
Logiccomponent, because theUIrelies on theLogicto execute commands. - depends on some classes in the
Modelcomponent, as it displaysPersonobject residing in theModel.
Click here to return to table of contents
View Panel
Fig 5. Ui View Panel Diagram
The ViewPanel consist of the following parts:
GroupListPanelContactListPanelExpenseListPanelTransactionSummaryPaymentListPanel
Each panel will display the corresponding list accordingly. The ViewPanel will only show up a single list panel at a time. We have decided to opt for this way of implementation due to the following:
- Able to make use of existing AB3 implementation of
PersonList - Will not increase code complexity as compared to both list using the same panel.
- Able to toggle easily with CLI commands
In addition to using CLI command, we will also be implementing the toggling of list panel with the use of buttons.
Click here to return to table of contents
Navigation Buttons
Fig 6. Ui Navigation Button Diagram
The NavigationButtonPanel consist of the following parts:
- GroupViewButton
- ContactViewButton
Clicking each button will show the respective list view in ViewPanel. The clicking of the button is handled by EventHandler.
Click here to return to table of contents
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic component:
Fig 7. Logic Class Diagram
Click here to return to table of contents
How the Logic component works:
- When
Logicis called upon to execute a command, it uses theAweParserclass to parse the user command. - This results in a
Commandobject (more precisely, an object of one of its subclasses e.g.,AddCommand) which is executed by theLogicManager. - The command can communicate with the
Modelwhen it is executed (e.g. to add a contact). - The result of the command execution is encapsulated as a
CommandResultobject which is returned back fromLogic.
The Sequence Diagram below illustrates the interactions within the Logic component for the execute("deletecontact 1") API call.
Fig 8. Delete Contact Sequence Diagram
DeleteContactCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Click here to return to table of contents
Here are the other classes in Logic (omitted from the class diagram above) that are used for parsing a user command:
Fig 9. Parser Classes
How the parsing works:
- When called upon to parse a user command, the
AweParserclass creates anXYZCommandParser(XYZis a placeholder for the specific command name e.g.,AddContactCommandParser) which uses the other classes shown above to parse the user command and create aXYZCommandobject (e.g.,AddContactCommand) which theAweParserreturns back as aCommandobject. - All
XYZCommandParserclasses (e.g.,AddContactCommandParser,DeleteContactCommandParser, …) inherit from theParserinterface so that they can be treated similarly where possible e.g, during testing.
Click here to return to table of contents
Model component
API : Model.java
Fig 10. Model Class Diagram
Click here to return to table of contents
The Model component,
- stores AWE data
- all
Personobjects (which are contained in aUniquePersonListobject). - all
Groupobjects (which are contained in aUniqueGroupListobject). - all
Expenseobjects (which are contained in aExpenseListobject). - all
TransactionSummaryobjects (which are contained in aTransactionSummaryListobject). - all
Paymentobjects (which are contained in aPaymentListobject).
- all
- stores the currently ‘selected’
Person/Group/Expense/TransactionSummary/Paymentobjects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<>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. - stores a
UserPrefobject that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPrefobjects. - does not depend on any of the other three components (as the
Modelrepresents data entities of the domain, they should make sense on their own without depending on other components)
Fig 11. Person Class Diagram
The Person component,
- Handles the storing of each contact in AWE.
- Stores a
Nameand aPhoneobject for each person. - Stores any amount of
Tagobjects.
Click here to return to table of contents
Fig 12. Expense Class Diagram
The Expense component,
- Handles the storing of each expense in AWE.
- Expenses will store a reference to all instance of
Personinvolved in the expenses. - Stores a
Costand aDescriptionfor eachExpense.

Fig 13. Group Class Diagram
The Group component,
- Handles the data of each group in AWE.
- Groups will store a list of reference to all
ExpenseandPersonin the group. - Stores a
GroupNamefor each group. - Stores any amount of
Tagobject.
Click here to return to table of contents
Fig 14. Transaction Summary Class Diagram
The TransactionSummary component,
- Handles the display of all the individual split expenses in a group.
- Stores a reference to a
Personand aCost.
Fig 15. Payment Class Diagram
The Payment component,
- Handles the display of all the payments to be made between contacts in a group.
- Stores 2
Personobjects and aCost.
Click here to return to table of contents
Storage component
API : Storage.java
Fig 16. Storage Class Diagram
The Storage component,
- can save both AWE data and user preference data in json format, and read them back into corresponding objects.
- inherits from both
AweStorageandUserPrefStorage, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Modelcomponent (because theStoragecomponent’s job is to save/retrieve objects that belong to theModel) - has the
IndividualAmountclass which is composed of aPersonand aCost, similar to the entries within theHashMapswithinExpense. SinceHashMapis not serializable in Json format, we utilize a list ofIndividualAmountobjects to store theHashMap.
Click here to return to table of contents
Implementation
This section describes some noteworthy details on how certain features are implemented.
Note: The words contact and person will be used interchangeably in this section.
Add Contact Feature
The add contact mechanism is facilitated by defining a Person model and adding a Unique Person List field to
AWE. The Person model contains a Name field containing the name of the contact, a Phone field containing the
number of the contact, and optional Tags to attach to the contact.
The following activity diagram shows what happens when a user executes an addcontact command.
Fig 17. Add Contact Activity Diagram
Click here to return to table of contents
Given below is an example usage scenario and how the addcontact mechanism behaves at each step.
Step 1. A valid addcontact command is given as user input. This prompts the LogicManager to run its execute()
method.
Step 2. The AddContactCommandParser parses the input and checks for presence of the relevant prefixes.
It also checks that the name is valid and all members specified are in the contact list.
It returns a AddContactCommand.
Step 3. AddContactCommand runs its execute() method which checks if a contact with the same name has already been
created. If not, the newly created contact is added into the AWE model. Upon successful execution, CommandResult is returned.
Click here to return to table of contents
The following sequence operation shows how the addcontact operation works.
Fig 18. Add Contact Sequence Diagram
AddContactCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Fig 19. Add Contact Reference Sequence Diagram
Click here to return to table of contents
Design considerations:
Aspect: Case-sensitivity of Name parameter in addcontact command:
-
Alternative 1 (current choice):
Nameis case-sensitive (for instance,Alexandalexare treated as unique names, and effectively, unique persons as well).- Pros: Easy to implement.
- Pros: Many cultures have names that are common. Allowing users to enter the same name but in different case allows unique users with the same name to store their contacts.
- Pros: Many cultures have names that are spelled in different case. For instance, in Singapore, the characters “s/o” (often used to denote “son of”) are spelled in different case by different people. Should multiple users have the same name but different case-spelling, it would be respectful to accept all versions of the name, regardless of case.
- Pros: Provides the user with a greater level of flexibility and user-choice.
- Cons: Possibility of user referring to the wrong person in commands due to creation of multiple persons with the same names but in different case.
-
Alternative 2 :
Nameis not case-sensitive.- Pros: Difficult to implement.
- Pros: Safeguards user from erroneously referring to the wrong person in commands.
- Cons: Difficult for users with the same name.
- Cons: May offend some people if the casing of their name is regarded as unacceptable or not given recognition.
- Cons: User has limited flexibility and restricted user-choice.
-
Justification
- The two cases described in the alternatives, where multiple persons of the same name but different case are necessary, are quite prevalent.
- Moreover, we trust the user to be careful with the casing of the
Namewhen entering the commands. - As such, we chose to make the
Nameparameter case-sensitive.
Click here to return to table of contents
Create Group Feature
The create group mechanism is facilitated by defining a Group model and adding a Unique Group List field to
AWE. The Group model contains a GroupName field containing the name of the group, an ArrayList of Person
objects who are members of the Group, an ArrayList of Expense objects that keeps track of the expenditures of the
Group, a HashMap that contains details of how much each member has paid in total across the expenses, and a HashMap
that contains details of the total expenditure incurred by each member across the trip.
The following activity diagram shows what happens when a user executes a createGroup command.
Fig 20. Create Group Activity Diagram
Click here to return to table of contents
Given below is an example usage scenario and how the creategroup mechanism behaves at each step.
Step 1. A valid creategroup command is given as user input. This prompts the LogicManager to run its execute()
method.
Step 2. The CreateGroupCommandParser parses the input and checks for presence of the relevant prefixes.
It also checks that the group name is valid and all members specified are in the contact list.
It returns a CreateGroupCommand.
Step 3. CreateGroupCommand runs its execute() method which checks if a group with the same name has already been
created. If not, the newly created group is added into the AWE model and all members within the group are updated in
the model. Upon successful execution, CommandResult is returned.
The following sequence operation shows how the creategroup operation works.
Fig 21. Create Group Sequence Diagram
Click here to return to table of contents
CreateGroupCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Fig 22. Create Group Reference Sequence Diagram
Design considerations:
Aspect: User command for creategroup:
-
Alternative 1 (current choice): Create Travel Group with specified members and tags.
- Pros: Intuitive for user to create a travel group with specified members and tags.
- Pros: Provides user with convenience of setting up a travel group with minimal commands.
- Cons: Harder to implement.
- Cons: Easier for user to make an erroneous command.
-
Alternative 2 : Create Travel Group only.
- Pros: Easy to implement.
- Pros: Command has single responsibility. Easy to remember the sole purpose of
creategroupcommand. - Cons: Unintuitive for user as travel group is created without any members or tags.
- Cons: Inconvenient for user to use multiple commands to set up a travel group.
Click here to return to table of contents
-
Justification
- User will have at least one member in mind when creating a group.
- As such, it is only natural for the
creategroupcommand to support addition of members and tags into the group upon creation. - This minimizes the number of commands a user has to make in setting up a functional Group.
- As such, it is better to choose Alternative 1, as this provides the user with a far better user experience.
Aspect: Case-sensitivity of GroupName parameter in creategroup command:
-
Alternative 1 (current choice):
GroupNameis case-sensitive (for instance,BALIandbaliare treated as unique group names, and effectively, unique groups as well).- Pros: Easy to implement.
- Pros: If the user goes on multiple trips to the same place, they can keep track of multiple groups by adding multiple groups of a similar name, different by case.
- Pros: If multiple groups of users go on trips to the same place, they can keep track of multiple trips by adding multiple groups of a similar name, different by case.
- Pros: Provides the user with a greater level of flexibility and user-choice.
- Cons: Possibility of user referring to the wrong group in commands due to creation of multiple-groups with the same names but in different case.
-
Alternative 2 :
GroupNameis not case-sensitive.- Pros: Difficult to implement.
- Pros: Safeguards user from erroneously referring to the wrong group in commands.
- Cons: Difficult for users who go on a trip to the same place multple times to keep track of their trips.
- Cons: Difficult to keep track of trips or groups if multiple groups of users go on trips to the same place.
- Cons: User has limited flexibility and restricted user-choice.
Click here to return to table of contents
-
Justification
- The two cases described in the alternatives, where multiple groups of the same name are necessary, are quite prevalent.
- Moreover, we trust the user to be careful with the casing of the
GroupNamewhen entering the commands. - As such, we chose to make the
GroupNameparameter case-sensitive.
-
Improvements
- The solution of making the
GroupNameparameter case-sensitive to permit users to create groups of the same name should the use case demand it is not ideal. - In the long-term, we plan to make
GroupNamecase-insensitive, but this will require changes to the command. - One such change currently being worked on is to include a
DATETIMEparameter for this command, so that users who go on multiple trips to the same location at different times can keep track of their trips. - Other solutions are necessary to satisfy the use case wherein different sets of members wish to go on a trip to the same location at the same time and wish to create groups of the same name.
- A solution that is being considered is to check for uniqueness of the group by checking that the members in each group are different.
- However, this will require changes to other commands as presently most commands operate on the assumption that
GroupNameis unique (case-sensitivity considered).
- The solution of making the
Click here to return to table of contents
Delete Group Feature
The delete group mechanism is facilitated by maintaining the constraint that every Group has a unique GroupName.
This allows the Model class to easily retrieve the Group based on the name entered by the user and remove the group from the model.
The following activity diagram shows what happens when a user executes a deletegroup command.
Fig 23. Delete Group Activity Diagram
Click here to return to table of contents
Given below is an example usage scenario and how the deletegroup mechanism behaves at each step.
Step 1. A valid deletegroup command is given as user input. This prompts the LogicManager to run its execute()
method.
Step 2. The DeleteGroupCommandParser parses the input and checks for presence of the relevant prefixes.
It also checks that the group name is valid (does not have any non-alphanumeric characters).
It returns a DeleteGroupCommand.
Step 3. DeleteGroupCommand runs its execute() method which checks if a group with the same name has been
created in the past. If so, this group is retrieved from the model. Subsequently, the group is removed from the AWE.
Upon successful execution, CommandResult is returned.
The following sequence operation shows how the deletegroup operation works.
Fig 24. Delete Group Sequence Diagram
DeleteGroupCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Click here to return to table of contents
Fig 25. Delete Group Reference Sequence Diagram
Design considerations:
Aspect: User command for deletegroup:
-
Alternative 1 (current choice): Delete based on
GroupName.- Pros: Easy to implement.
- Pros: Difficult for user to make an erroneous command.
- Cons: Long user command.
- Cons: Requires imposition of constraint that group names are unique.
-
Alternative 2 (index based): Delete based on index position in
ObservableList.- Pros: Easy to implement.
- Pros: Short user command
- Cons: Unintuitive for user.
- Cons: Easy for user to make an erroneous command.
-
Justification
- Group contains large mass of information such as multiple expenses, individual expenditures, and payments.
- This information is unrecoverable once deleted.
- As such, it is better to choose Alternative 1, as this makes it difficult for user to accidentally delete a group.
Click here to return to table of contents
Aspect: Internal delete mechanism:
-
Alternative 1 (current choice): Retrieve group from list and delete.
- Pros: Easy to implement.
- Pros: Easier to modify in future.
- Cons: Extra step of retrieval leads to slower execution.
-
Alternative 2 (name based): Delete based on
GroupName.- Pros: Easy to implement.
- Pros: Process is completed faster.
- Cons: Might cause issues in case of future modifications.
-
Justification
- Retrieving the group and subsequently deleting the group is a slower process.
- However, the alternative implementation relies on the uniqueness of the
GroupNamefield ofGroupobjects. - Should we modify or remove the constraint, the alternative implementation would require significant alterations.
- To make the feature more extendable, we choose alternative 1.
Click here to return to table of contents
Group Edit Features
The group edit mechanism is facilitated by defining a Group model and adding a Unique Group List field to
AWE. The Group model contains a GroupName field containing the name of the group, an ArrayList of Person
objects who are members of the Group, an ArrayList of Expense objects that keeps track of the expenditures of the
Group. The group edit mechanism comprises the following commands.
groupeditnamegroupaddcontactgroupremovecontactgroupaddtaggroupremovetag
Given the high degree of similarity in implementation and design considerations between these commands, only the
groupeditname command will be explained comprehensively in this section.
Given below is an example usage scenario and how the groupeditname command behaves at each step.
Step 1. A valid groupeditname command is given as user input. This prompts the LogicManager to run its execute()
method.
Step 2. The GroupEditNameCommandParser parses the input and checks for presence of the relevant prefixes.
It also checks that both the old and new group names are valid.
It returns a GroupEditNameCommand.
Step 3. GroupEditNameCommand runs its execute() method which updates the name of the group in the AWE model.
Upon successful execution,CommandResult is returned.
Click here to return to table of contents
The following sequence operation shows how the groupeditname command works.
Fig 26. Group Edit Name Sequence Diagram
oldGroup:Group
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Click here to return to table of contents
Design considerations:
Aspect: User command for groupeditname:
-
Alternative 1 (current choice): Edit each attribute of a group with separate commands.
- Pros: Significantly shorter commands.
- Pros: Provides user with convenience of editing a group with minimal input.
- Cons: More commands for user to work with. Harder to remember relevant commands.
-
Alternative 2 : Edit groups with a single command, as is implemented in
editcontact.- Pros: Easy to implement.
- Cons: Inconvenient for user to edit a person if there are multiple attributes they wish to change.
- Cons: Easy for user to make an erroneous command.
-
Justification
- Unlike Person objects, Group objects have many more attributes that users may wish to change.
- The length of a single edit command that can change all attributes will be extremely long if a user wishes to add and remove multiple members simultaneously.
- This significantly increases the chances of users inputting erroneous commands as well
- Hence, editing attributes of a group using separate commands is more convenient and appropriate.
Click here to return to table of contents
Find group feature
The find group feature supports both single keyword and multi keyword search. This allows the displayed view panel to show the entries related to the search keywords entered by the user.
The following activity diagram shows what happens when a user executes a findgroups command:
Fig 27. Find Groups Activity Diagram
Given below is an example usage scenario and how the findgroup operation behaves at each step:
Assuming the programs only have the initial data when the user first starts the app, the FilteredList should contain only 2 groups - London and Bali.
Step 1. When the user executes findgroups London command, the message is passed into LogicManager and parsed by AweParser.
Step 2. FindGroupsCommandParser is created and the arguments are parsed by it. The arguments are used to create GroupContainsKeywordsPredicate and FindGroupsCommand is returned to the LogicManager.
Click here to return to table of contents
Step 3. The LogicManager then calls FindGroupCommand execute(model) method, which updated the FilteredList<Group> in ModelManager. Thereafter, the FilteredList<Group> should contains only London.
Step 4. The GUI listens for updates in the FilteredList<Group> and updates the display to display London only.
Step 5. CommandResult is returned to the LogicManager, which also switches the view panel to GroupsListPanel if needed. See UI implementation below for more details of switching view panel.
Step 6. The output from CommandResult is then displayed as an output for the user.
The following sequence diagram shows how the findgroups operation works:
Fig 28. Find Groups Sequence Diagram
Click here to return to table of contents
Fig 29. Find Groups Reference Sequence Diagram
Click here to return to table of contents
Add expense feature
The add expense mechanism is facilitated by defining an Expense model and adding an Expense List field to
Awe. The Expense model contains a Person field containing the payer of the Expense, a Cost field
containing the cost of the expense, a List of Person objects that keeps track of the people involved in the
expense, a HashMap that contains details of how much each member has paid in total for the expense.
The following activity diagram shows what happens when a user executes a addexpense command.
Fig 30. Add Expense Activity Diagram
Click here to return to table of contents
Given below is an example usage scenario and how the addexpense mechanism behaves at each step.
Step 1. A valid addexpense command is given as user input. This prompts the LogicManager to run its execute()
method.
Step 2. The AddExpenseCommandParser parses the input and checks for presence of the relevant prefixes.
It also checks that the group name is valid and all members specified are in the specified group.
It returns a AddExpenseCommand.
Step 3. AddExpenseCommand runs its execute() method which adds the newly created expense involving the into the
relevant group members into the group and the group is updated in the AWE model.Upon successful execution,
CommandResult is returned.
The following sequence operation shows how the addexpense operation works.
Fig 31. Add Expense Sequence Diagram
AddExpenseCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Click here to return to table of contents
Fig 32. Add Expense Reference Sequence Diagram
Design considerations:
Aspect: User command for addexpense:
-
Alternative 1 (current choice): Create Expense with specified group and group members.
- Pros: Intuitive for user to create an expense with specified group and group members via their names.
- Pros: Provides user with convenience of creating an expense with minimal input.
- Cons: Harder to implement.
- Cons: Easier for user to make an erroneous command.
-
Alternative 2 (index based): Create Expense with based on index position in
ObservableList.- Pros: Easy to implement.
- Cons: Inconvenient for user to add an expense as they have to check again the index of both the person and group.
- Cons: Easy for user to make an erroneous command.
-
Justification
- Each person has a unique name and the implementation for adding an expense based on a person’s and group’s name is simple.
- Users may need a long time to find the index of a person or group if the list of either is very long.
- Hence, adding expenses based on the specified person and group name is more appropriate.
Click here to return to table of contents
Find Expenses Feature
The find expenses mechanism is facilitated by Group. Each group has a unique group name and also an expense list
required for finding expenses within a group.
The following activity diagram shows what happens when a user executes a findexpenses command.
Fig 33. Find Expenses Activity Diagram
Click here to return to table of contents
Given below is an example usage scenario and how the findexpenses mechanism behaves at each step.
Step 1. The user executes a valid findexpenses eat gn/London command. This prompts the LogicManager
to run its execute() method.
Step 2. The FindExpensesCommandParser parses the input and checks for presence of the group name prefix.
It also checks that the group name is valid (does not have any non-alphanumeric characters). The arguments are
used to create DescriptionContainsKeywordsPredicate and FindExpensesCommand is returned to the LogicManager.
Step 3. The LogicManager then calls FindExpensesCommand execute(model) method, which updates the
FilteredList<Expense> in ModelManager using the predicate created in step 2.
Step 4. The GUI listens for updates in the FilteredList<Expense> and updates the display accordingly.
Step 5. CommandResult is returned to the LogicManager, which also switches the viewpanel to ExpensesListPanel if needed.
Step 6. The output from CommandResult is then displayed as an output for the user.
The following sequence operation shows how the findexpenses operation works.
Fig 34. Find Expenses Sequence Diagram
FindExpensesCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Click here to return to table of contents
Fig 35. Find Expenses Reference Sequence Diagram
Design considerations:
Aspect: User command for findexpenses:
-
Alternative 1 (current choice): Find based on
GroupName- Pros: Easy to implement.
- Cons: Long user command if group name is long.
- Cons: Requires imposition of constraint that group names are unique.
-
Alternative 2 (index based): Find expenses in the group indicated by index position in
ObservableList- Pros: Short user command with just the index.
- Cons: User needs to check for the right index of the group.
- Cons: Easy for user to make an erroneous command.
-
Justification
- Each group has a unique name and can be used easily in the implementation to find expenses within the specified group.
- Users may need a long time to find the index of the group if the list of groups is very long.
- This would be more inconvenient for the user.
- Hence, finding expenses based on the specified group name is more appropriate.
Click here to return to table of contents
Delete Expense Feature
The delete expense mechanism is facilitated by the addition of an ExpenseList field within the Awe object maintained by the model.
Each Expense belongs to a Group object, also maintained within the Awe.
Deletion of an expense must be accompanied by deletion of the expense from the Group object to which it belongs.
The command allows the user to delete an expense based on the index position of the expense in the page viewed by the user.
This means that the user is constrained to only being permitted to delete expenses when they are viewing a list of expenses; that is, after they enter the findexpenses or expenses command.
The following activity diagram shows what happens when a user executes a deleteexpense command.
Fig 36. Delete Expense Activity Diagram
Click here to return to table of contents
Given below is an example usage scenario and how the deleteexpense mechanism behaves at each step.
Step 1. A valid deleteexpense command is given as user input. This prompts the LogicManager to run its execute()
method.
Step 2. The DeleteExpenseCommandParser parses the input and checks for presence of the INDEX input.
It returns a DeleteExpenseCommand.
Step 3. DeleteExpenseCommand runs its execute() method which checks if the INDEX entered is within the range of the size of the list of expneses seen by the user.
If so, the Expense at the INDEX position is deleted from the ExpenseList. The ObservableList within ExpenseList is updated, meaniing the UI updates and the user can see the new list of expenses, without the deleted expense.
Step 4. The Group to which this expense belongs is retrieved from the ExpenseList.
The expense is subsequently deleted from the expenses field present in the Group object.
The updated Group is then placed back into the GroupList within the Awe.
Step 5: Upon successful execution, CommandResult is returned.
Click here to return to table of contents
The following sequence operation shows how the deleteexpense operation works.
Fig 37. Delete Expense Sequence Diagram
DeleteExpenseCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Fig 38. Delete Expense Reference Sequence Diagram
Click here to return to table of contents
Design considerations
Aspect: User command for deleteexpense:
-
Alternative 1 (current choice): Delete based on index position in
ObservableList- Pros: Easy to implement.
- Pros: Short user command.
- Cons: Less intuitive for user.
- Cons: Easy for user to make an erroneous command.
-
Alternative 2 (description based): Delete based on
description- Pros: Easy to implement.
- Pros: Difficult for user to make an erroneous command.
- Cons: Long user command.
- Cons: Requires imposition of constraint that expense description names are unique.
-
Justification
- Expenses, unlike Groups, do not contain a large volume of information.
- This information is unrecoverable once deleted.
- However, the damage to a user as a result of an error is not significant. The user can re-enter the details with a single command.
- Therefore, the need to protect the user from erroneous decisions is not significant.
- Furthermore, many expenses are likely to have similar descriptions. Constraining users to using unique descriptions for expenses is likely to compromise the user experience.
- As such, it is better to choose Alternative 1, as this allows the user to quickly delete expenses, and not compromise on the flexibility of the user.
Click here to return to table of contents
Calculate Payments Feature
The purpose of this feature is to provide users with a simple set of transactions that would allow all debts within the group to be settled.
The UI mechanism is facilitated by the addition of a PaymentList field of Payment objects, present within the Awe object maintained by the model.
The functionality of this feature is facilitated by the fact that group objects maintain two hashmaps: -
-
paidByPayers, which maintains how much each member of the group has paid (total payments) during the course of the trip. -
splitExpenses, which maintains how much expenditure each member of the group has incurred (total expenditure) during the course of the trip. These maps allow calculations with respect to how much each individual is owed, and how much each individual owes.
The Algorithm
The invariant maintained is that the sum of all payments made (values within paidByPayers) should equal the total expenditures incurred by the group (values within splitExpenses).
Define surplus as the net amount each individual is owed by others. This ultimately means that some members have negative surplus, and some have positive surplus.
The goal is to ensure that the deficits balance the surpluses with the minimum number of transactions.
To assist with the tracking of each individual and their surplus, an inner Pair class was created with a Person field and a primitive double field for the surplus.
-
Initialize an empty list of Pairs and an empty list of
Paymentobjects. -
Iterate through the
membersof the group and retrieve each individual’s total payments and total expenditures. -
Calculate the surplus of each individual by subtracting their total expenditures from their total payments. Initialize a
Pairobject with thePersonobject of the individual, and their surplus. Add this pair to the list if the surplus is not 0.
Click here to return to table of contents
- Iterate until the list is empty and perform the following steps.
- Sort the list in ascending order of surplus. This means that those who owe more are placed in the earlier part of the list and those who are owed more are placed towards the end of the
Pairlist. - Retrieve the first
Pairand lastPairin the list. It is invariant that the first pair will have negative surplus and the last pair will have positive surplus. - Check to see which pair has a smaller magnitude. Define this value to be
SMALL_VAL. - Create a
Paymentobject with aCostofSMALL_VAL, and payee and payer as the two individuals within the first pair and last pair retrieved respectively. Add thisPaymentobject to the list ofPaymentobjects. - If the pairs do not have equal magnitude, remove the pair with the surplus value of smaller magnitude from the list. Calculate the new surplus value of the other pair to be the sum of the surpluses of both pairs. Update the other pair with this new surplus value and place it back into the list.
- If the pairs do have equal magnitude, remove both pairs from the list.
- Sort the list in ascending order of surplus. This means that those who owe more are placed in the earlier part of the list and those who are owed more are placed towards the end of the
- Return the list of
Paymentobjects.
Click here to return to table of contents
The following diagram shows the flow of the algorithm.
Fig 39. Calculate Payments Command Algorithm Diagram
Click here to return to table of contents
The following activity diagram shows what happens when a user executes a calculatepayments command.
Fig 40. Calculate Payments Activity Diagram
Given below is an example usage scenario and how the calculatepayments mechanism behaves at each step.
Step 1. A valid calculatepayments command is given as user input. This prompts the LogicManager to run its execute()
method.
Step 2. The CalculatePaymentsCommandParser parses the input and checks for presence of the GROUP_NAME prefix.
It checks that the GROUP_NAME is valid (does not have any non-alphanumeric characters).
It returns a CalculatePaymentsCommand.
Step 3. CalculatePaymentsCommand runs its execute() method which checks if a group with the GROUP_NAME entered by the user has been
created in the past. If so, this group is retrieved from the model.
Step 4. Subsequently, the Algorithm is used to tabulate a list of Payment objects.
Step 5. The PaymentList field is updated with the generated list of payments, triggering a change in the UI to show the user the list of payments.
Step 6. Upon successful execution, CommandResult is returned.
Click here to return to table of contents
The following sequence operation shows how the calculatepayments operation works.
Fig 41. Calculate Payments Sequence Diagram
CalculatePaymentsCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Fig 42. Calculate Payments Reference Sequence Diagram
Note: When a Person is deleted from contacts or removed from the group, the functioning of this command does not change. The deleted person may still be part of the list of payments depending on the expenses they had previously.
Click here to return to table of contents
Design considerations
Aspect: Algorithm utilized for calculatepayments:
-
Alternative 1 (current choice): Prioritize settling of bigger debts
- Pros: Easy to implement.
- Pros: Smaller number of transactions.
- Cons: Larger value transactions.
-
Alternative 2: Prioritize settling of smaller debts
- Pros: Smaller value transactions.
- Cons: Greater number of transactions.
- Cons: More difficult to implement.
-
Justification
- The size of the transaction matters less to the user than the volume of transactions.
- Moreover, an easier implementation reduces the possibility of bugs.
- As such, we chose to prioritize the settling of bigger debts in our algorithm.
Click here to return to table of contents
UI
AWE has multiple lists / views to display such as for groups, contacts and expenses.
The display, called view panel, will only be able to show up 1 view at a time depending on the command. It is of upmost importance to get it to display the correct view.
To achieve the toggling between each view panels, we implemented the following:
- An enumeration
UiViewto contain the followingCONTACT_PAGE,GROUP_PAGE,EXPENSE_PAGE,TRANSACTION_SUMMARY,PAYMENT_PAGE. Each enum represents a different view. -
CommandResultwas given 6 more boolean fields, each representing a different view as well. -
MainWindowchecks for the 6 boolean fields inCommandResultand passesUiViewtoViewPanelfor toggling the view.
The following activity diagram shows how the MainWindow checks and sends the UiView to ViewPanel.
Click here to return to table of contents
Fig 43. Ui Toggling Activity Diagram
Click here to return to table of contents
Proposed Implementation
Aspect: Navigating between different view
-
Alternative 1: Make use of JavaFx’s tab
- Pros: Easy to implement.
- Cons: Unable to fully customized the layout. Have to use the standard JavaFx’s tab layout.
-
Alternative 2 (current choice): Replacing the child of the view panel node
(Refer to JavaFx tutorial for more information about JavaFx)- Pros: More customizable in terms of layout.
- Pros: Able to make use of existing codes.
- Cons: More classes to implement to handle the toggling between views.
-
Justification
- We want to place the command result display below the buttons according to our wireframe.
- Using JavaFx’s tab will not let us customize the layout as such.
- Hence, replacing the child of a view panel is more appropriate.
Ui Navigation Buttons
To improve the usability of AWE, buttons are implemented into the Ui to allow switching of view easily.
However, only 2 main views can be toggled by the buttons - Contacts page and Groups page.
Navigation Buttons is designed using Model View Controller (MVC) pattern.
- View: Buttons
- Controller: EventHandler
- Model: Backend codes for displaying the list
To achieve this, the following is implemented:
- 2 buttons (
GroupViewButtonandContactViewButton) for the user to click. - Event listener for each button -
GroupButtonListenerandContactButtonListener. The event listener works by callingViewPanel#toggleViewwhen the button is clicked.
Click here to return to table of contents
Given below is an example usage scenario and how the button mechanism behaves at each step. In this example, the button used is GroupViewButton but it can also be replaced with ContactViewButton.
Step 1. When GroupViewButton is initiated, an event listener GroupButtonListener is created and used.
Step 2. Once the user clicks on GroupViewButton, the event listener will trigger and the GroupButtonListener#handle will run. This calls ViewPanel#toggleView and passes UiView.GROUP_PAGE as parameters.
Step 3. ViewPanel will change the child of itself to ContactListPanel (Refer to JavaFx tutorial for more information about JavaFx). Hence, GUI will update to show contact page
Documentation, logging, testing, configuration, dev-ops
Click here to return to table of contents
Appendix: Requirements
Product scope
Target user profile:
- travels in groups
- wants to split expenses in a convenient and efficient manner
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition:
Travellers have big notes that make settling payments inconvenient. Most travel groups often designate one person to pay. This method of settling payments poses a vexing task of splitting costs at the end of the day or on-the-spot. Our app effectively splits bills between different contacts to serve this purpose.
Click here to return to table of contents
User stories
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
* * * |
beginner user who first opened the app | view the help page | so that I can learn how to use the app |
* * * |
user with contacts to remember | add a contact | keep track of my contacts |
* * * |
user who has lots of contacts to keep track of | view contacts | easily see my contacts in one centralized location |
* * * |
user who wants to find contacts with a certain string of characters in their name | find contacts by a regex | search for contacts easily |
* * * |
user who has lots of contacts to keep track of | tag a contact | keep track of contacts by certain characteristics/tags |
* * * |
user with contacts that no longer exist | delete a contact | keep my contacts relevant and current |
* * * |
user with contacts that have changed | edit a contact | keep my contacts accurate and current |
* * * |
user with a trip to go on | add a group | keep track of my groups |
* * * |
user who has lots of trips to keep track of | view groups | easily see my groups in one centralized location |
* * * |
user who wants to find groups with a certain string of characters in their name | find groups by a regex | search for groups easily |
* * * |
user who has lots of groups to keep track of | tag a group | keep track of groups by certain characteristics/tags |
* * * |
user with groups that no longer exist | delete a group | keep my groups relevant and current |
* * * |
user with flexible travel plans | edit a group | keep my groups accurate and current |
* * * |
user that has paid for a shared experience | easily check how much I have paid up front | ensure I have liquidity for emergencies and or other unforeseen expenses |
* * * |
user who has paid for others | easily check how much I am owed by friends | recoup the money I have paid on their behalf |
* * * |
user paying for a shared expense | enter the amount I have paid | update the total amount they have to pay |
* * * |
user that owes my friend money | easily check how much I owe each person | conveniently proceed to pay my friend |
* * * |
busy user who does not want to remember phone numbers | easily save all my friends’ numbers | conveniently proceed to pay my friend |
* * * |
user with flexible travel plans | edit the details of a trip/group (members, group name, tags) | modify the records quickly and easily |
* * * |
beginner user | run the app easily with a click of a button | avoid wasting time trying to figure out how to get the app to work |
* * * |
inexperienced user in the app who types fast | type in the commands for the app | do more things in the app with the same amount of time compared to using a mouse to click |
* * * |
user who wants an easy workflow | easily toggle between contacts and groups page with a command or a click of a button | make my workflow on the app smoother |
* * |
user who has to recoup the money | divide up the expenses suitably amongst my friends | know how much to recoup from each person |
* * |
user who worries about individual expenses | check the breakdown of my personal expenditure | keep track of how much money I have spent |
* * |
user who likes to differentiate work from leisure | use this app to separate the different types of contacts I have | I won’t mix them up |
* * |
user who wants to stay in contact with friends | use this app to easily save their phone numbers | I can remain in contact |
* * |
potential user exploring the app | see the app containing sample data | see what the app generally looks like when it is used |
* * |
potential user testing the app | run the app on different platforms (windows, linux and os-x) | not have to specifically run a certain platform |
* |
user whose friends frequently change numbers | use this app to easily edit their numbers or save multiple numbers with notes | easily remember which number to use |
* |
beginner user that is tech-savvy | view the documentation | figure out how to use the app |
* |
beginner user | easily distinguish functions in the app | use it without the app being too daunting |
* |
expert user | refer to previous trips and the expenditure | plan future trips efficiently |
Click here to return to table of contents
Use Cases
(For all use cases below, the System is the AWE and the Actor is the user, unless specified otherwise)
Contacts Use Cases
Use case: UC1 - Add a contact
MSS
- User chooses to add a contact to the AWE.
- User enters add command into CLI along with contact name, phone number, and tags if applicable.
- AWE displays confirmation message.
Use case ends.
Extensions
- 2a. AWE detects invalid command format that does not contain all 2 parameter identifiers (“n/”, “p/”).
- 2a1. AWE returns invalid command format error and displays
addcommand format and example.
Use case ends.
- 2a1. AWE returns invalid command format error and displays
- 2b. Command contains 2 parameters identifiers but name is blank.
- 2b1. AWE reminds user that names should only contain alphanumeric characters and should not be blank.
Use case ends.
- 2b1. AWE reminds user that names should only contain alphanumeric characters and should not be blank.
- 2c. Command contains 2 parameters identifiers but phone number is less than 3 digits or not a number.
- 2c1. AWE reminds user that phone numbers should only contain numbers and be at least 3 digits long.
Use case ends.
- 2c1. AWE reminds user that phone numbers should only contain numbers and be at least 3 digits long.
Click here to return to table of contents
Use case: UC2 - Delete a contact
MSS
- User finds contacts (UC4) or views all contacts (UC5).
- User requests to delete a specific contact in the list.
- AWE deletes the contact.
- AWE removes the contact from groups of which the person was a member.
- AWE displays confirmation message.
Use case ends.
Extensions
- 1a. The contacts page is empty.
Use case ends. - 2a. The given index is invalid.
- 2a1. AWE shows an error message.
- 2b. User is not viewing a list of contacts when entering command.
- 2b1. AWE shows an error message asking user to enter
findcontactsorcontactscommand first.
Use case ends.
- 2b1. AWE shows an error message asking user to enter
Click here to return to table of contents
Use case: UC3 - Edit a contact
MSS
- User finds contacts (UC4) or views all contacts (UC5).
- User requests to edit a specific contacts in the list.
- User enters edited information.
- AWE edits the contacts.
Extensions
- 1a. The contacts page is empty.
Use case ends. - 3a. The given index is invalid.
- 3a1. AWE shows an error message.
Use case resumes at step 2.
- 3a1. AWE shows an error message.
- 3b. The given information has an invalid format.
- 3b1. AWE shows an error message. Use case resumes at step 2.
- 3c. User is not viewing a list of contacts when entering command.
- 3c1. AWE shows an error message asking user to enter
findcontactsorcontactscommand first.
Use case ends.
- 3c1. AWE shows an error message asking user to enter
Click here to return to table of contents
Use case: UC4 - Find contacts
MSS
- User request to find contacts based on keyword(s).
- AWE shows a list of contacts that matches the keyword(s).
- AWE displays a message with number of contacts found
Use case continues.
Extensions
- 2a. There isn’t any contacts saved.
- 2a1. AWE displays nothing in the contacts page ie an empty screen.
Use case ends.
- 2a1. AWE displays nothing in the contacts page ie an empty screen.
- 2b. There is no contacts matching the search parameters.
- 2b1. AWE displays nothing in the contacts page ie an empty screen.
Use case continues.
- 2b1. AWE displays nothing in the contacts page ie an empty screen.
Use case: UC5 - View all contacts
MSS
- User requests to view contacts.
- AWE shows list of contacts.
Use case ends.
Extensions
- 2a. There are no contacts to be listed.
- 2a1. AWE does not display any contacts but an empty list.
Use case ends.
- 2a1. AWE does not display any contacts but an empty list.
Click here to return to table of contents
Groups Use Cases
Use case: UC6 - Create travel group
MSS
- User chooses to create a group.
- User enters create group command into CLI along with group name and names of members.
- AWE displays confirmation message.
Use case ends.
Extensions
- 2a. AWE detects group member whose name is not in the AWE.
- 2a1. AWE displays message to remind User to type in full name of members as in the AWE.
Use case ends.
- 2a1. AWE displays message to remind User to type in full name of members as in the AWE.
Use case: UC7 - Delete travel group
MSS
- User requests to delete group with a specific name.
- AWE deletes group with specified group name.
- AWE shows updated list of groups.
- AWE displays confirmation message.
Use case ends.
Extensions
- 2a. AWE detects group name that contains non-alphanumeric characters.
- 2a1. AWE displays message to remind User to type in a group name that contains only alphanumeric characters.
Use case ends.
- 2a1. AWE displays message to remind User to type in a group name that contains only alphanumeric characters.
- 2b. AWE detects group name that is not in AWE.
- 2a1. AWE displays message to remind User to type in name of a group inside the AWE.
Use case ends.
- 2a1. AWE displays message to remind User to type in name of a group inside the AWE.
Click here to return to table of contents
Use case: UC8 - Change group name
MSS
- User requests to change group name.
- Named is changed for relevant group.
- AWE shows updated list of groups and contacts.
- AWE displays confirmation message.
Use case ends.
Extension
- 1a. AWE detects that the user input does not follow the command format.
- 1a1. AWE displays message of invalid command format as well as the appropriate command usage.
Use case ends.
- 1a1. AWE displays message of invalid command format as well as the appropriate command usage.
- 1b. AWE detects that there is no valid old group name or new group name being specified.
- 1b1 AWE displays message informing user that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Use case ends.
- 1b1 AWE displays message informing user that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
- 1c. AWE detects group name that is not in AWE.
- 1c1. AWE displays message to remind User to type in name of a group inside the AWE.
Use case ends.
- 1c1. AWE displays message to remind User to type in name of a group inside the AWE.
Click here to return to table of contents
Use case: UC9 - Add contact to group
MSS
- User requests to add contact to a group.
- Contact added to group.
- AWE shows updated list of groups and contacts.
- AWE displays confirmation message.
Use case ends.
Extension
- 1a. AWE detects that the user input does not follow the command format.
- 1a1. AWE displays message of invalid command format as well as the appropriate command usage.
Use case ends.
- 1a1. AWE displays message of invalid command format as well as the appropriate command usage.
- 1b. AWE detects that there is no valid group name being specified.
- 1b1 AWE displays error message informing user that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Use case ends.
- 1b1 AWE displays error message informing user that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
- 1c. AWE detects group name that is not in AWE.
- 1c1. AWE displays message to remind User to type in name of a group inside the AWE.
Use case ends.
- 1c1. AWE displays message to remind User to type in name of a group inside the AWE.
- 1d. AWE detects that there is no contact names being specified.
- 1d1. AWE displays message informing user that there should be at least one group member in each group.
Use case ends.
- 1d1. AWE displays message informing user that there should be at least one group member in each group.
- 1e. AWE detects contact name that is not in AWE.
- 1e1. AWE displays message to inform user that none of the specified contact names are in AWE.
Use case ends.
- 1e1. AWE displays message to inform user that none of the specified contact names are in AWE.
Click here to return to table of contents
Use case: UC10 - Remove contact from group
MSS
- User requests to remove contact from a group.
- Contact removed from group.
- AWE shows updated list of groups and contacts.
- AWE displays confirmation message.
Use case ends.
Extension
- 1a. AWE detects that the user input does not follow the command format.
- 1a1. AWE displays message of invalid command format as well as the appropriate command usage.
Use case ends.
- 1a1. AWE displays message of invalid command format as well as the appropriate command usage.
- 1b. AWE detects that there is no valid group name being specified.
- 1b1 AWE displays message informing user that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Use case ends.
- 1b1 AWE displays message informing user that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
- 1c. AWE detects group name that is not in AWE.
- 1c1. AWE displays message to remind User to type in name of a group inside the AWE.
Use case ends.
- 1c1. AWE displays message to remind User to type in name of a group inside the AWE.
- 1d. AWE detects that there is no contact names being specified.
- 1d1 AWE displays message informing user that there should be at least one group member in each group.
Use case ends.
- 1d1 AWE displays message informing user that there should be at least one group member in each group.
- 1e. AWE detects contact name that is not in AWE.
- 1e1. AWE displays message to inform user that none of the specified contact names are in AWE.
Use case ends.
- 1e1. AWE displays message to inform user that none of the specified contact names are in AWE.
- 2a. AWE detects that the removal of person from group results in the group having 0 members.
- 2a1. AWE deletes the group with 0 members
- 2a2. AWE shows updated list of groups and contacts.
- 2a3. AWE displays confirmation message and informs user that the group with 0 members has been deleted.
Use case ends.
Click here to return to table of contents
Use case: UC11 - Add tag to group
MSS
- User requests to add tag to a group.
- Tag added to group.
- AWE shows updated list of groups.
- AWE displays confirmation message.
Use case ends.
Extension
- 1a. AWE detects that the user input does not follow the command format.
- 1a1. AWE displays error message of invalid command format as well as the appropriate command usage.
Use case ends.
- 1a1. AWE displays error message of invalid command format as well as the appropriate command usage.
- 1b. AWE detects that there is no valid group name being specified.
- 1b1 AWE displays message informing user that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Use case ends.
- 1b1 AWE displays message informing user that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
- 1c. AWE detects group name that is not in AWE.
- 1c1. AWE displays message to remind User to type in name of a group inside the AWE.
Use case ends.
- 1c1. AWE displays message to remind User to type in name of a group inside the AWE.
- 1d. AWE detects that there is no valid tags being specified.
- 1d1. AWE displays error message informing user that tags should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Use case ends.
- 1d1. AWE displays error message informing user that tags should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Use case: UC12 - Remove tag from group
MSS
- User requests to remove tag from a group.
- Tag removed from group.
- AWE shows updated list of groups.
- AWE displays confirmation message.
Use case ends.
Click here to return to table of contents
Use case: UC13 - Find groups
MSS
- User request to find groups based on keyword(s).
- AWE shows a list of groups that matches the keyword(s).
- AWE displays a message with number of groups found.
Use case ends.
Extensions
- 2a. There isn’t any groups created.
- 2a1. AWE displays nothing in the groups page ie an empty screen.
Use case continues.
- 2a1. AWE displays nothing in the groups page ie an empty screen.
- 2b. There is not groups matching the search parameters.
- 2b1. AWE displays nothing in the groups page ie an empty screen.
Use case continues.
- 2b1. AWE displays nothing in the groups page ie an empty screen.
Use case: UC14 - View all travel groups
MSS
- User choose to list all groups
- GroupsPage shows a list of groups
Use case ends.
Extension
- 2a. AWE detects that there is no group created.
- 2a1. AWE displays a blank screen.
Use case ends.
- 2a1. AWE displays a blank screen.
Click here to return to table of contents
Expenses Use Cases
Use case: UC15 - Add an expense
Preconditions: User has is a member of the specified travel group.
MSS
- User requests to add an expense to the specified travel group
- AWE displays confirmation message.
Use case ends.
Extensions
- 1a. AWE detects that the specified travel group does not exist.
- 1a1. AWE informs user that the specified travel group does not exist.
Use case ends.
- 1a1. AWE informs user that the specified travel group does not exist.
- 1b. AWE detects that inputted command is an incorrect format.
- 1b1. AWE informs user that expense was not added and reminds the user of the correct format.
Use case ends.
- 1b1. AWE informs user that expense was not added and reminds the user of the correct format.
- 1c. AWE detects that the cost inputted into the expense is more than one billion.
- 1c1. AWE inform user that the cost of the expense has to be less than one billion.
Use case ends.
- 1c1. AWE inform user that the cost of the expense has to be less than one billion.
- 1d. AWE detects that the payer is not part of the specified travel group.
- 1d1. AWE informs user that the payer has to be a part of the specified travel group.
Use case ends.
- 1d1. AWE informs user that the payer has to be a part of the specified travel group.
- 1e. AWE detects that individual payer are not part of the specified travel group.
- 1e1. AWE informs user that the individual payer has to be part of the specified travel group.
Use case ends.
- 1e1. AWE informs user that the individual payer has to be part of the specified travel group.
- 1f. AWE detects that the excluded member is not part of the specified travel group.
- 1f1. AWE informs user that the excluded member has to be part of the specified travel group.
Use case ends.
- 1f1. AWE informs user that the excluded member has to be part of the specified travel group.
Click here to return to table of contents
- 1g. AWE detects that all members in the specified travel group are excluded from the expense.
- 1g1. AWE informs user that they cannot exclude all members in the travel group from the expense.
Use case ends.
- 1g1. AWE informs user that they cannot exclude all members in the travel group from the expense.
- 1h. AWE detects that the total expenditure of the specified group is over one billion.
- 1h1. AWE informs user that the total expenses of the travel group has reached its limit of one billion.
Use case ends.
- 1h1. AWE informs user that the total expenses of the travel group has reached its limit of one billion.
Click here to return to table of contents
Use case: UC16 - Delete an expense
MSS
- User finds expenses in a travel group (UC17) or lists expenses in a travel group (UC18).
- User requests to delete an expense from list of expenses viewed by its position on screen.
- AWE deletes the specified expense.
- AWE shows updated list of expenses.
- AWE displays confirmation message.
Extensions
- 2a. User is not viewing a list of expenses when entering command.
- 2a1. AWE shows an error message asking user to enter
findexpensesorexpensescommand first.
Use case ends.
- 2a1. AWE shows an error message asking user to enter
- 2b. The given index is not within range 1 to length of list of expenses on screen.
- 2b1. AWE shows an error message saying index is invalid.
Use case ends.
- 2b1. AWE shows an error message saying index is invalid.
Click here to return to table of contents
Use case: UC17 - Find expenses in a travel group
MSS
- User request to find expense(s) based on keyword(s) and group name.
- AWE shows a list of expenses in specified group that matches the keyword(s).
- AWE displays confirmation message.
Use case ends.
Extensions
- 2a. The specified group does not exist in AWE.
- 2a1. AWE shows a message saying that there is no such existing group.
Use case ends.
- 2a1. AWE shows a message saying that there is no such existing group.
- 2b. There are no expenses matching the search parameters.
- 2b1. AWE displays nothing in the ExpensesPage.
Use case ends.
- 2b1. AWE displays nothing in the ExpensesPage.
- 2c. The given group name is invalid.
- 2c1. AWE displays error message saying that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Use case ends.
- 2c1. AWE displays error message saying that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Click here to return to table of contents
Use case: UC18 - List expenses of a travel group
MSS
- User request to list expenses of a specific group.
- AWE displays all the expenses of the group in ExpensesPage.
- AWE displays confirmation message.
Use case ends.
Extensions
- 2a. The specified group does not exist in AWE.
- 2a1. AWE displays message saying that there is no such group in AWE.
Use case ends.
- 2a1. AWE displays message saying that there is no such group in AWE.
- 2b. The given group name is invalid.
- 2b1. AWE displays error message saying that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
Use case ends.
- 2b1. AWE displays error message saying that group names should only comprise letters, numbers, and spaces,
should be within 50 characters, and should not be blank.
- 2c. AWE detect no expenses logged under the group.
- 2c1. AWE displays an empty list in the ExpensesPage.
Use case ends.
- 2c1. AWE displays an empty list in the ExpensesPage.
Use case: UC19 - Calculate individual expenses
MSS
- User requests to calculate and show individual expenses made in a specified group.
- AWE shows list of individual expenses.
- AWE displays confirmation message.
Use case ends.
Extensions
- 2a. AWE detects group name that is not in AWE.
- 2a1. AWE displays message to remind User to type in name of a group inside the AWE.
Use case ends.
- 2a1. AWE displays message to remind User to type in name of a group inside the AWE.
Click here to return to table of contents
Use case: UC20 - Calculate payments
MSS
- User requests to calculate and show payments to be made for a specified group.
- AWE calculate payments for the specified group.
- AWE shows list of payments.
- AWE displays confirmation message.
Use case ends.
Extensions
- 2a. AWE detects group name that is not in AWE.
- 2a1. AWE displays message to remind User to type in name of a group inside the AWE.
Use case ends.
- 2a1. AWE displays message to remind User to type in name of a group inside the AWE.
- 3a. There are no payments to be made.
- 3a1. AWE shows an empty list of payments.
- 3a2. AWE displays a confirmation message stating that there are no payments to be made.
Use case ends.
Click here to return to table of contents
Miscellaneous Use Cases
Use case: UC21 - Clear AWE of all entries
MSS
- User enters clearalldata command.
- All entries are deleted from AWE.
Use case ends.
Use case: UC22 - Help user understand AWE
MSS
- User request to find commands and their explanations.
- AWE shows a list of command keyword(s) and explanations.
Use case ends.
Extensions
- 2a. AWE detects errant command.
- 2a1. AWE displays the list of command keyword(s) and explanations.
Use case ends.
- 2a1. AWE displays the list of command keyword(s) and explanations.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11or above installed. - Should be able to hold up to 500 contacts without a noticeable sluggishness in performance for typical usage.
- 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.
- Should be able to hold up to 50 groups without a noticeable sluggishness in performance for typical usage.
- Layout between contacts and groups should be intuitive and easy to understand and navigate.
- Usage of
$should be standardized for money.
Click here to return to table of contents
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Private contact detail: A contact detail that is not meant to be shared with others
- Transaction Summary: The amount each contact spent on a trip
- Payment: The amount one contact has to pay another
- ContactsPage: The page displaying all the contacts
- GroupsPage: The page displaying all the travel groups
- ExpensesPage: The page displaying all the expenses of a travel group
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
Click here to return to table of contents
Deleting a contact
-
Deleting a contact while contacts are being shown.
-
Prerequisites: The preloaded data for contacts are not modified. (No contacts are removed or added). List contacts using command
contacts. -
Test case:
deletecontact 1
Expected: First contact is deleted from the visible list. List is updated. -
Test case:
deletecontact 0
Expected: No contact is deleted. Error details shown in the status message. Status bar remains the same. -
Test case:
deletecontact -1
Expected: No contact is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
deletecontact,deletecontact x,...(where x is larger than the visible list size)
Expected: Similar to previous.
-
-
Deleting a contact while filtered contacts are being shown.
-
Prerequisites: The preloaded data for contacts are not modified. (No contacts are removed or added). List contacts using command
findcontacts alex. -
Test case:
deletecontact 1
Expected: First contact is deleted from the visible list. List is updated. -
Test case:
deletecontact 0
Expected: No contact is deleted. Error details shown in the status message. Status bar remains the same. -
Test case:
deletecontact -1
Expected: No contact is deleted. Error details shown in the status message. Status bar remains the same.
-
Click here to return to table of contents
-
Other incorrect delete commands to try:
deletecontact,deletecontact x,...(where x is larger than the visible list size)
Expected: Similar to previous. -
Attempting to delete a contact when not viewing a list of contacts.
-
Prerequisites: The preloaded data for contacts are not modified. (No contacts are removed or added). The current page must not be an
ContactsPage. -
Test case:
deletecontact 1
Expected: No contact is deleted. Error details shown in the status message. Status bar remains the same.
-
Editing a contact
-
Editing a contact while contacts are being shown.
-
Prerequisites: The preloaded data for contacts are not modified. (No contacts are removed or added). List contacts using command
contacts. -
Test case:
editcontact 1 n/Alex
Expected: First contact is edited from the visible list. List is updated to show edited contact with new name. -
Test case:
editcontact 1 p/92748316
Expected: First contact is edited from the visible list. List is updated to show edited contact with new phone number. -
Test case:
editcontact 1 n/Brandon p/93359216
Expected: First contact is edited from the visible list. List is updated to show edited contact with new name and phone number. -
Test case:
editcontact 0 n/Alex
Expected: No contact is edited. Error details shown in the status message. Status bar remains the same. -
Test case:
editcontact 1
Expected: No contact is edited. Error details shown in the status message. Status bar remains the same.
-
Click here to return to table of contents
-
Other incorrect edit commands to try:
editcontact,editcontact x n/NAME p/PHONE,...(where x is larger than the visible list size)
Expected: Similar to previous. -
Editing a contact while filtered contacts are being shown.
-
Prerequisites: The preloaded data for contacts are not modified. (No contacts are removed or added). List contacts using command
findcontacts alex. -
Test case:
editcontact 1 n/Alex
Expected: First contact is edited from the visible list. List is updated to show edited contact with new name. -
Test case:
editcontact 1 p/92748316
Expected: First contact is edited from the visible list. List is updated to show edited contact with new phone number. -
Test case:
editcontact 1 n/Brandon p/93359216
Expected: First contact is edited from the visible list. List is updated to show edited contact with new name and phone number. -
Test case:
editcontact 0 n/Alex
Expected: No contact is edited. Error details shown in the status message. Status bar remains the same. -
Test case:
editcontact 2 n/Bernice Yu
Expected: No contact is edited as this name is identical to the name of the current contact at INDEX 2. Error details shown in the status message. Status bar remains the same. -
Test case:
editcontact 1
Expected: No contact is edited. Error details shown in the status message. Status bar remains the same. -
Other incorrect edit commands to try:
editcontact,editcontact x n/NAME p/PHONE,...(where x is larger than the visible list size)
Expected: Similar to previous.
-
Click here to return to table of contents
- Attempting to delete a contact when not viewing a list of contacts.
-
Prerequisites: The preloaded data for contacts are not modified. (No contacts are removed or added). The current page must not be
ContactsPage. -
Test case:
editcontact 1 n/Alex
Expected: No contact is deleted. Error details shown in the status message. Status bar remains the same.
-
Creating a group
-
Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
creategroup gn/London n/Irfan IbrahimExpected: Group not created. Status message indicates that group already exists. -
Test case:
creategroup gn/Toronto n/Expected: Group not created. Status message indicates that the command requires at least 1 member. -
Test case:
creategroup gn/Toronto n/Irfan IbrahimExpected: Group Toronto created with member Irfan Ibrahim. Status message indicates new group has been created.
Click here to return to table of contents
Deleting a Group
-
Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added).
-
Test case:
deletegroup gn/LondonExpected: GroupList displayed. Group with name London not seen on the list. Status message will confirm deletion of the group. -
Test case:
deletegroup gn/TurkeyExpected: No changes as group does not exist. Error details shown in the status message.
Editing group name
- Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
groupeditname gn/London gn/BaliExpected: Name of London group remains unchanged. Status message indicates that group name Bali already exists. -
Test case:
groupeditname gn/London gn/Expected: Name of London group remains unchanged. Status message indicates that group name cannot be blank. - Test case:
groupeditname gn/London gn/ThailandExpected: Name of London group will change to Thailand. Status message indicates that the group name has been changed to Thailand.
Click here to return to table of contents
Adding a contact to group
- Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
groupaddcontact gn/London n/Bernice YuExpected: Group membership unchanged. Status message indicates that Bernice Yu is already in the group. -
Test case:
groupaddcontact gn/London n/Expected: Group membership remains unchanged. Status message indicates that the command requires at least 1 member. - Test case:
groupaddcontact gn/London n/Irfan IbrahimExpected: Irfan Ibrahim added to group. Status message indicates that the new member has been added to group.
Removing a contact from group
- Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
groupremovecontact gn/London n/Irfan IbrahimExpected: Group membership unchanged. Status message indicates that contact is not removed as the contact was not previously in the group. -
Test case:
groupremovecontact gn/London n/Expected: Group membership remains unchanged. Status message indicates that the command requires at least 1 member. - Test case:
groupremovecontact gn/London n/Bernice YuExpected: Bernice Yu removed from group. Status message indicates that the member has been removed from group.
Click here to return to table of contents
Adding a tag to group
- Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
groupaddtag gn/London t/SchoolTripExpected: Tags unchanged. Status message indicates that the tag SchoolTrip is already in the group. -
Test case:
groupaddtag gn/London t/Expected: Tags unchanged. Status message indicates that tag cannot be blank. - Test case:
groupaddtag gn/London t/FriendsExpected: Friends tag added to group. Status message indicates that the new tag has been added to group.
Removing a tag from group
- Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
groupremovetag gn/London t/FriendsExpected: Tags unchanged. Status message indicates that the tag is not removed as the tag was not previously in the group. -
Test case:
groupremovetag gn/London t/Expected: Tags unchanged. Status message indicates that tag cannot be blank. - Test case:
groupremovetag gn/London t/SchoolTripExpected: SchoolTrip tag removed from group. Status message indicates that the tag has been removed from group.
Click here to return to table of contents
Searching for groups
-
Search for groups in GroupsPage
-
Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
findgroups LondonExpected: GroupList will list out 1 group with the name ‘London’. 1 groups found shown in the status message. -
Test case:
findgroups London SingaporeExpected: GroupList will list out 1 group with the name ‘London’. 1 groups found shown in the status message. -
Test case:
findgroups SingaporeExpected: GroupList will display a blank page. 0 groups found shown in status message.
-
-
Search for groups when not viewing GroupsPage.
-
Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
findgroups LondonExpected: GroupList displayed. GroupList will list out 1 group with the name ‘London’. 1 groups found shown in the status message. -
Test case:
findgroups London SingaporeExpected: GroupList displayed. GroupList will list out 1 group with the name ‘London’. 1 groups found shown in the status message. -
Test case:
findgroups SingaporeExpected: GroupList displayed. GroupList will display a blank page. 0 groups found shown in status message.
-
Click here to return to table of contents
Viewing expenses
-
Viewing all expenses of a specific group in ContactsPage or GroupsPage.
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups and expenses are removed or added)
-
Test case:
expenses gn/LondonExpected: ExpenseList will list out all the expenses added to the London group. Status message confirms that all expenses are listed. -
Test case:
expenses gn/SingaporeExpected: No changes as group does not exist. Error details stating that specified group does not exist will be shown in status message.
Finding expenses
-
Finding expenses for a specific group in ContactsPage or GroupsPage.
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups and expenses are removed or added)
-
Test case:
findexpenses Transportation gn/LondonExpected: ExpenseList displayed. ExpenseList will list out expenses in the London group with descriptions containing “Transportation”. Status message says that 1 expense is found. -
Test case:
findexpenses Transportation Buffet gn/LondonExpected: ExpenseList displayed. ExpenseList will list out 2 expenses with the matching keywords. 2 expenses found shown in the status message. -
Test case:
findexpenses Transportation gn/BaliExpected: ExpenseList displayed. ExpenseList will display a blank page. 0 expenses found shown in status message. -
Test case:
findexpenses Test gn/SingaporeExpected: No change occurs. Status message says that the specified group does not exist.
Click here to return to table of contents
Adding an expense
-
Adding an expense involving an existing member of a specific travel group.
-
Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
addexpense n/Alex Yeoh gn/London $/50 d/Dinner
Expected: An expense of $50 for Dinner is added to the travel group London with Alex Yeoh as its payer. -
Test case:
addexpense gn/London $/50 d/Dinner
Expected: No expense added. Status message will display the correct format of the addexpense command.
-
-
Adding an expense involving a payer not part of the specified travel group.
-
Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
addexpense n/David Li gn/London $/50 d/Dinner
Expected: No expense added. Status message will indicate that the payer is not part of the specified travel group.
-
-
Adding an expense involving a travel group that does not exist.
-
Prerequisites: The preloaded data for groups are not modified. (No groups are removed or added)
-
Test case:
addexpense n/Alex Yeoh gn/Sweden $/50 d/Arcade
Expected: No expense added. Status message will indicate that the specified travel group does not exist.
-
Click here to return to table of contents
Deleting an expense
-
Deleting an expense while expenses of a group are being shown.
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups or expenses are removed or added). List expenses using command
expenses gn/London. -
Test case:
deleteexpense 1
Expected: First expense is deleted from the visible list. List is updated. -
Test case:
deleteexpense 0
Expected: No expense is deleted. Error details shown in the status message. Status bar remains the same. -
Test case:
deleteexpense -1
Expected: No expense is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
deleteexpense,deleteexpense x,...(where x is larger than the visible list size)
Expected: Similar to previous.
-
-
Deleting an expense while filtered expenses of a group are being shown.
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups or expenses are removed or added). List expenses using command
findexpenses transport gn/London. -
Test case:
deleteexpense 1
Expected: First expense is deleted from the visible list. List is updated. -
Test case:
deleteexpense 0
Expected: No expense is deleted. Error details shown in the status message. Status bar remains the same. -
Test case:
deleteexpense -1
Expected: No expense is deleted. Error details shown in the status message. Status bar remains the same.
-
Click here to return to table of contents
-
Other incorrect delete commands to try:
deleteexpense,deleteexpense x,...(where x is larger than the visible list size)
Expected: Similar to previous. -
Attempting to delete an expense when not viewing a list of expenses.
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups or expenses are removed or added). The current page must not be an
ExpensesPage. -
Test case:
deleteexpense 1
Expected: No expense is deleted. Error details shown in the status message. Status bar remains the same.
-
Calculating transaction summary
-
Calculating individual spending of a group with expenses.
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups or expenses are removed or added).
-
Test case:
calculatepayments gn/LondonExpected: Transaction summary list populated with individual spending is displayed. Status message will indicate successful execution of the command. -
Test case:
calculatepayments gn/TurkeyExpected: No changes as group does not exist. Error details shown in the status message.
-
-
Calculating payments of a group without expenses.
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups or expenses are removed or added).
-
Test case:
calculatepayments gn/ColombiaExpected: Transaction summary list for each person will be displayed. Each person will have $0 as the amount of money they spent. Status message will indicate successful execution of the command.
-
Click here to return to table of contents
Calculating payments
-
Calculating payments of a group with expenses.
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups or expenses are removed or added).
-
Test case:
calculatepayments gn/LondonExpected: PaymentList populated with payments is displayed. Status message will indicate successful execution of the command. -
Test case:
calculatepayments gn/TurkeyExpected: No changes as group does not exist. Error details shown in the status message.
-
-
Calculating payments of a group without expenses
-
Prerequisites: The preloaded data for groups and expenses are not modified. (No groups or expenses are removed or added).
-
Test case:
calculatepayments gn/ColombiaExpected: Empty PaymentList is displayed. Status message will indicate successful execution of the command.
-