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
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned 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
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
object 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:
GroupListPanel
ContactListPanel
ExpenseListPanel
TransactionSummary
PaymentListPanel
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
Logic
is called upon to execute a command, it uses theAweParser
class to parse the user command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,AddCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to add a contact). - The result of the command execution is encapsulated as a
CommandResult
object 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
AweParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,AddContactCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,AddContactCommand
) which theAweParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,AddContactCommandParser
,DeleteContactCommandParser
, …) inherit from theParser
interface 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
Person
objects (which are contained in aUniquePersonList
object). - all
Group
objects (which are contained in aUniqueGroupList
object). - all
Expense
objects (which are contained in aExpenseList
object). - all
TransactionSummary
objects (which are contained in aTransactionSummaryList
object). - all
Payment
objects (which are contained in aPaymentList
object).
- all
- stores the currently ‘selected’
Person
/Group
/Expense
/TransactionSummary
/Payment
objects (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
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents 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
Name
and aPhone
object for each person. - Stores any amount of
Tag
objects.
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
Person
involved in the expenses. - Stores a
Cost
and aDescription
for 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
Expense
andPerson
in the group. - Stores a
GroupName
for each group. - Stores any amount of
Tag
object.
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
Person
and 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
Person
objects 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
AweStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
) - has the
IndividualAmount
class which is composed of aPerson
and aCost
, similar to the entries within theHashMaps
withinExpense
. SinceHashMap
is not serializable in Json format, we utilize a list ofIndividualAmount
objects 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):
Name
is case-sensitive (for instance,Alex
andalex
are 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 :
Name
is 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
Name
when entering the commands. - As such, we chose to make the
Name
parameter 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
creategroup
command. - 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
creategroup
command 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):
GroupName
is case-sensitive (for instance,BALI
andbali
are 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 :
GroupName
is 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
GroupName
when entering the commands. - As such, we chose to make the
GroupName
parameter case-sensitive.
-
Improvements
- The solution of making the
GroupName
parameter 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
GroupName
case-insensitive, but this will require changes to the command. - One such change currently being worked on is to include a
DATETIME
parameter 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
GroupName
is 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
GroupName
field ofGroup
objects. - 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.
groupeditname
groupaddcontact
groupremovecontact
groupaddtag
groupremovetag
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
Payment
objects. -
Iterate through the
members
of 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
Pair
object with thePerson
object 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
Pair
list. - Retrieve the first
Pair
and lastPair
in 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
Payment
object with aCost
ofSMALL_VAL
, and payee and payer as the two individuals within the first pair and last pair retrieved respectively. Add thisPayment
object to the list ofPayment
objects. - 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
Payment
objects.
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
UiView
to contain the followingCONTACT_PAGE
,GROUP_PAGE
,EXPENSE_PAGE
,TRANSACTION_SUMMARY
,PAYMENT_PAGE
. Each enum represents a different view. -
CommandResult
was given 6 more boolean fields, each representing a different view as well. -
MainWindow
checks for the 6 boolean fields inCommandResult
and passesUiView
toViewPanel
for 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 (
GroupViewButton
andContactViewButton
) for the user to click. - Event listener for each button -
GroupButtonListener
andContactButtonListener
. The event listener works by callingViewPanel#toggleView
when 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
add
command 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
findcontacts
orcontacts
command 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
findcontacts
orcontacts
command 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
findexpenses
orexpenses
command 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
11
or 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 Ibrahim
Expected: 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 Ibrahim
Expected: 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/London
Expected: GroupList displayed. Group with name London not seen on the list. Status message will confirm deletion of the group. -
Test case:
deletegroup gn/Turkey
Expected: 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/Bali
Expected: 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/Thailand
Expected: 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 Yu
Expected: 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 Ibrahim
Expected: 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 Ibrahim
Expected: 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 Yu
Expected: 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/SchoolTrip
Expected: 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/Friends
Expected: 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/Friends
Expected: 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/SchoolTrip
Expected: 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 London
Expected: GroupList will list out 1 group with the name ‘London’. 1 groups found shown in the status message. -
Test case:
findgroups London Singapore
Expected: GroupList will list out 1 group with the name ‘London’. 1 groups found shown in the status message. -
Test case:
findgroups Singapore
Expected: 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 London
Expected: GroupList displayed. GroupList will list out 1 group with the name ‘London’. 1 groups found shown in the status message. -
Test case:
findgroups London Singapore
Expected: GroupList displayed. GroupList will list out 1 group with the name ‘London’. 1 groups found shown in the status message. -
Test case:
findgroups Singapore
Expected: 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/London
Expected: ExpenseList will list out all the expenses added to the London group. Status message confirms that all expenses are listed. -
Test case:
expenses gn/Singapore
Expected: 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/London
Expected: 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/London
Expected: 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/Bali
Expected: ExpenseList displayed. ExpenseList will display a blank page. 0 expenses found shown in status message. -
Test case:
findexpenses Test gn/Singapore
Expected: 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/London
Expected: Transaction summary list populated with individual spending is displayed. Status message will indicate successful execution of the command. -
Test case:
calculatepayments gn/Turkey
Expected: 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/Colombia
Expected: 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/London
Expected: PaymentList populated with payments is displayed. Status message will indicate successful execution of the command. -
Test case:
calculatepayments gn/Turkey
Expected: 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/Colombia
Expected: Empty PaymentList is displayed. Status message will indicate successful execution of the command.
-