- Developer Guide
- GSON Library for JSON parsing
- Retrofit Library for HTTP requests
- AB-3 Developer Guide
- app.diagrams.net for creating diagrams
First, fork this repo, and clone the fork into your computer. If you plan to use Intellij IDEA (highly recommended):
- Configure the JDK: Follow the guide [se-edu/guides] IDEA: Configuring the JDK to ensure Intellij is configured to use JDK 11.
- Import the project as a Gradle project: Follow the guide [se-edu/guides] IDEA: Importing a Gradle
project to import the project into
IDEA.
Note: Importing a Gradle project is slightly different from importing a normal Java project. - Verify the setup:
- Run the
com.moneymoover.MoneyMoover
and try a few commands. - Run the tests using
./gradlew check
to ensure they all pass.
- Run the
- Configure the coding style
If using IDEA, you can use the following steps to import the code style settings.
- Go to
File → Settings → Editor → Code Style
- Click the Gear Icon next to the
Scheme
box and then clickImport Scheme → IntelliJ IDEA code style XML
. - Select the
DefaultCodeStyle.xml
file in the root of the project directory.
- Go to
- Set up CI
This project comes with a GitHub Actions config files (in
.github/workflows
folder). When GitHub detects those files, it will run the CI for your project automatically at each push to themaster
branch or to any PR. No set up required. - Learn the design When you are ready to start coding, we recommend that you get some sense of the overall design by reading about MoneyMoover’s architecture.
The diagram above provides a high-level overview of how the project is structured. The main components are:
- The
Main
class which initialises all the other components at startup, and connects them with each other - The
UI
component which is responsible for all user input and output - The
Parser
component which parses user input and creates the relevant Command objects - The
Command
component which executes the logic - The
Accounts
component which manages the user's accounts - The
Forex
(Foreign Exchange) component which handles exchange-rate related logic - The
Transactions
component which manages the user's transactions - The
Storage
component which handles the saving and loading of data to disk
The following is a high-level sequence of a single create-account SGD
command, which demonstrates how the components
interact with each other:
The API of this component is specified in the Ui.java
.
The UI class deals with the user interaction with the application, which includes the printing and the logic to read in
inputs. We will pass in the instance of UI into the execute
method of the Command
class. The main features includes:
-
Printing text such as new line, spacer, farewell message, greeting message.
-
Empowers the developers to print customised message in
printf
andprintMessage
method. -
Reads in the user input as
String
.
The Parser
Component
- Parses the user input and creates the relevant
Command
object - Makes use of the
CommandType
enum to determine the type of command to create
Here is a class diagram of the Accounts
component
The Accounts
Component
- Stores the
AccountList
which contains all the user's accounts AccountList
handles all logic dealing with accountsAccount
stores both its currency type and its balance- There can be only one
Currency
perAccount
- There can be only one
Account
of eachCurrency
Here is a class diagram of the Forex
component
The Forex
Component
- Stores the exchange rates of 1 SGD to all supported currencies in a hash map
- Each
Forex
object represents the relationship between two currencies convert
can be called on aForex
object to convert an amount using the relationship- Each
Forex
object has an initial and targetCurrency
- There is only one instance of the
exchangeRates
hash map.
The Currency
Enum
- Keeps all currency types supported by the exchange
- Exchange rates were manually pulled from https://openexchangerates.org
- Each
Forex
instance must have twoCurrency
associated with it
When MoneyMoover starts, the Forex class calls its static method initializeRates(). This method calls the constructor of the ExchangeRates class, then sleeps for 5 seconds, then retrieves the HashMap that ExchangeRates has created from the method fetchExchangeRates within its constructor. Forex copies the HashMap and uses it for the rest of the user session.
fetchExchangeRates retrieves a Retrofit instance from the ExchangeRatesApiClient class, and uses it to create an instance of the ExchangeRatesApi, an interface that defines the methods for retrieving the exchange rates data from Open Exchange Rates API.
fetchExchangeRates then makes a call to getLatestExchangeRates to retrieve the exchange rates using the ExchangeRatesApi instance, and a base currency of USD, and our API token from Open Exchange Rates.
getLatestExchangeRates returns a Call object, and we enqueue a Callback object to get the onResponse() and onFailure() methods that will be called depending on the outcome of the Call. If the call is successful, onResponse() returns an ExchangeRatesResponse object containing the HashMap of ISO currency tags as Strings for keys, and doubles for rates. This data is then extracted using saveMap, which filters out the rates for our supported currencies and performs type conversion. The savedMap attribute of ExchangeRates is set to this filtered map, which is then passed to Forex via getExchangeRates.
If onFailure() is called, it means an unexpected error was encountered, such as losing Internet connection.
Below is a UML Diagram of the classes and their respective methods.
Here is a class diagram of the Transactions
component
The Transactions
component
- A
Transaction
is recorded upon every command that changes the balance of an account - Certain commands allow the provision of a description parameter to associate a custom description to a transaction
Transactions
are only accessed through theTransactionManager
Transactions
associated to an account are deleted if and only if the account is deleted
The following is a class diagram of the Storage
component
- The
Storage
component is responsible for saving and loading data from disk. - It stores the account and transaction data in JSON format using the Gson library.
- The
Storage
component makes use of dependency injection with theStoreInterface
so that a stub (TestStore
) can be injected when running automated tests. This prevents the automated tests from modifying the actual data stored on disk or having to consider potential side effects from previous tests.
This feature is facilitated by AccountList
Class within the Accounts
Component.
The method called from AccountList
is the addAccount
method which creates a new Account
object.The deleteAccount
method called from AccountList
delete the specified Account
object.
The current implementation initialises the Account
with 0 balance.
Only currency account which 0 balance can be deleted.
Given below is an example of the usage of this feature and the mechanism at each step
Step 1: The user launches the application for the first time and AccountList
is created with no Account
Step 2: The user passes in the command create-account <CURRENCY>
, where CURRENCY
is a valid string representing one
of the elements of the Currency
enum
Step 3: The user passes in the command create-account <CURRENCY>
, where CURRENCY
is also valid but different to that
in step 1.
Step 4: The user passes the command delete-account CURRENCY
, for example delete-account SGD
.
The following sequence diagram shows how the Create Account operation works
The following sequence diagram shows how the Delete Account operation works
The add money(deposit) and withdraw money feature is facilitated by AddCommand
and WithdrawCommand
which both
extends the Command
class. With the provided input from user (CURRENCY
and AMOUNT
), AddCommand
and WithdrawCommand
update the balance of respective currency account accordingly.
Step 1. The newly created SGD
account has an initial balance of 0
Step 2. The user passes command add CURRENCY AMOUNT
(eg. add SGD 100
), where CURRENCY
must be one of the available
currency and AMOUNT
must be positive numbers.
Step 3. The user passes command withdraw
(eg. withdraw SGD 25
), where AMOUNT
must be smaller than the currency
account balance.
The following sequence diagram shows how the add money operation works.
The following sequence diagram shows how the money withdrawal operation works.
The view balance feature is facilitated using Account
instances stored within the AccountList
object. The main
functionality is to view the balance of a specific currency if the currency is specified, else view all the currencies
in the account.
The exchange feature is facilitated using two Forex
instances to represent the
exchange rates between two currencies. The current implementation reads manual exchange
rates from an online source. Future implementation will use an API to maintain up-to-date
exchange rates.
Exchange rate source: https://www.xe.com/currencyconverter/convert
The show-rate command executes as follows
- The initial and target currency are parsed from the input
- If the user included an amount, the amount is also parsed
- A
Forex
object showing the rate from the initial to the target currency is made - A
Forex
object showing the rate from the target to the initial currency is made - The Ui prints the exchanged amount if an amount was provided by the user for both rates
- The Ui will print the unit rate both ways if no amount was provided
The following sequence diagram shows how the Show Rate command works
The exchange feature is facilitated using Account
instances stored within an AccountList
object. The main functionality is facilitated by the convert
function within the Forex
component. The current implementation reads manual exchange rates from an online source. Future
implementation will use an API to maintain up-to-date exchange rates. An exchange call will produce two
transaction activity. A debit transaction will reflect on initial account and credit transaction will
reflect on target account
Exchange rate source: https://openexchangerates.org
This command is executed under the assumption that an Account
for both the initial and target
currencies exist. To avoid redundancy, please see the create-account
feature in the developer
guide for more specific steps on how Accounts
are created.
The exchange command executes as follows:
- Initial and target currencies are parsed from the user input
- A Forex object is created using the parsed currencies (see
Forex
component for more information) - The amount to be exchanged is parsed from the user input
- The
Accounts
for both currencies are retrieved - The converted value is calculated using the
Forex
object - The value of the initial
Account
is updated - The value of the target
Account
is updated - The new balances are printed
The following sequence diagram shows how the Exchange command works
The show transactions feature is facilitated by TransactionCommand
, extending from the Command
class.
Since any one user might have many transactions, flags are used to specify search parameters for the command.
The Transaction command executes as follows:
- The command is parsed to determine if there are additional search parameters
- Interaction with the
TransactionManager
to retrieve relevant accounts - The relevant transactions are printed
The following sequence diagram shows how the Transaction command works
- Students who are planning to travel overseas
- People who need to exchange money for travel
- People who are comfortable using a CLI
MoneyMoover is a CLI application for managing and transferring international currencies, optimized for use via a Command Line Interface (CLI) while still having the features of other money management applications.
Version | As a ... | I want to ... | So that I can ... |
---|---|---|---|
v1.0 | new user | see usage instructions | refer to them when I forget how to use the application |
v1.0 | student planning to travel | know the currency exchange rates | better plan out my budget |
v1.0 | user | create accounts for different currencies | |
v1.0 | user | top up my account | have sufficient balance in the app |
v1.0 | user | withdraw money from my accounts | I can spend it as cash |
v1.0 | user | delete accounts I am no longer using | |
v1.0 | student planning to travel | quickly exchange my money for local currency | spend in different currencies |
v2.0 | user | view my previously saved accounts | avoid having to key in the same information every time |
v2.0 | user | add descriptions to my transactions | categorise and track my spending and deposits |
v2.0 | user | view my previous transactions in reverse chronological order | view my most recent transactions more easily |
v2.0 | user | jump to a specific date | view transactions on that date |
v2.0 | user | view transactions with a specific description | view how much I spend on specific categories or items |
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 100 transactions without sluggishness in performance.
- A user that is able to type quickly should be able to accomplish most of the tasks faster than using a GUI equivalent with a mouse.
- Mainstream OS: Windows, Linux, Unix, OS-X
Given below are some instructions for testing the app manually. Note that they are meant to provide a starting point and are not an exhaustive list of test cases.
- Download the jar file and copy it into an empty folder
- Go to that directory in the command line and run
java -jar FILENAME.jar
. - The app should automatically create a data folder and the necessary files for the app to run.
- An internet connection is required to retrieve live exchange rates. If there is no internet, fallback values will be used instead.
- You can view the list of available commands by using the
help
command
- Before doing any other commands, you should create an account using the
create-account
command. - Example:
create-account SGD
- You can now begin to add or withdraw money from your account. Use the
add
andwithdraw
commands to do this. - You can then view the balances of your accounts using
balance
, or view past transactions usingtrans
.
- You can view the exchange rates between different currencies using the
show-rate
command.
- You can exchange money between different currencies using the
exchange
command if you have accounts in both currencies. The transactions should be reflected in thetrans
command.
- Before deleting an account, you must first make sure the balance is 0. This can be done either by exchanging to another currency or withdrawing all the money.
- You can then delete an account using the
delete-account
command.
- The API Key for retrieving exchange rates is stored in the
src/main/java/com/moneymoover/api/ExchangeRates.java
file as theAPP_ID
property. - If you wish to use your own API Key, you will need to go
to https://openexchangerates.org/signup/free and sign up
for a free account, then replace the
APP_ID
in theExchangeRates.java
file with your new key.