By: Team W14-4
Since: August 2018
Licence: MIT
- 1. Setting Up
- 2. Design
- 3. Implementation
- 4. Documentation
- 5. Testing
- 6. Dev Ops
- Appendix A: Suggested Programming Tasks to Get Started
- Appendix B: Product Scope
- Appendix C: User Stories
- Appendix D: Use Cases
- Appendix E: Non Functional Requirements
- Appendix F: Project Management
- Appendix G: Glossary
- Appendix H: Acronyms
- Appendix I: Instructions for Manual Testing
The steps for developers to setup Inventory Manager locally is described below.
The prerequisites for setting up Inventory Manager is described below.
-
JDK
9
or later⚠️ JDK 10
on Windows will fail to run tests in headless mode due to a JavaFX bug. Windows developers are highly recommended to use JDK9
. -
IntelliJ IDE
ℹ️IntelliJ by default has Gradle and JavaFx plugins installed.
Do not disable them. If you have disabled them, go toFile
>Settings
>Plugins
to re-enable them.
Begin setting up Inventory Manager in your computer by following the steps below.
-
Fork this repo, and clone the fork to your computer.
-
Open IntelliJ (if you are not in the welcome screen, click
File
>Close Project
to close the existing project dialog first). -
Set up the correct JDK version for Gradle.
-
Click
Configure
>Project Defaults
>Project Structure
. -
Click
New…
and find the directory where the JDK is stored.
-
-
Click
Import Project
. -
Locate the
build.gradle
file and select it. ClickOK
. -
Click
Open as Project
. -
Click
OK
to accept the default settings. -
Open a console and run the command
gradlew processResources
(Mac/Linux:./gradlew processResources
). It should finish with theBUILD SUCCESSFUL
message.
This will generate all resources required by the application and tests. -
Open
XmlAdaptedItem.java
andMainWindow.java
and check for any code errors.-
Due to an ongoing issue with some of the newer versions of IntelliJ, code errors may be detected even if the project can be built and run successfully
-
To resolve this, place your cursor over any of the code section highlighted in red. Press the keys:[ALT + ENTER], and select
Add '--add-modules=…' to module compiler options
for each error.
-
-
Repeat the above step for the test folder as well (i.e. check
XmlUtilTest.java
andHelpWindowTest.java
for code errors, and if so, resolve it the same way as above).
After setting up, you can verify if Inventory Manager is setup correctly by performing the steps below.
-
Run the
seedu.inventory.MainApp
and try a few commands (e.g.help
orlist
). -
Run the tests to ensure all tests pass.
You are encouraged to customise your setup in your local computer by following the steps below.
This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. To rectify, please follow the steps described below.
-
Go to
File
>Settings…
(Windows/Linux), orIntelliJ IDEA
>Preferences…
(macOS). -
Select
Editor
>Code Style
>Java
. -
Click on the
Imports
tab to set the order.-
For
Class count to use import with '*'
andNames count to use static import with '*'
: Set to999
to prevent IntelliJ from contracting the import statements. -
For
Import Layout
: The order isimport static all other imports
,import java.*
,import javax.*
,import org.*
,import com.*
,import all other imports
. Add a<blank line>
between eachimport
.
-
Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.
After forking the repo, the documentation will still have the SE-EDU branding and reference to the se-edu/addressbook-level4
repo.
If you plan to develop this fork as a separate product (i.e. instead of contributing to se-edu/addressbook-level4
), you should do the following:
-
Configure the site-wide documentation settings in
build.gradle
, such as thesite-name
, to suit your own project. -
Replace the URL in the attribute
repoURL
inDeveloperGuide.adoc
andUserGuide.adoc
with the URL of your fork.
Set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.
After setting up Travis, you can optionally set up coverage reporting for your team fork (see UsingCoveralls.adoc).
ℹ️
|
Coverage reporting may be useful for a team repository that hosts the final version but it is not that useful for your personal fork. |
Optionally, you can set up AppVeyor as a second CI (see UsingAppVeyor.adoc).
ℹ️
|
Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based). |
Below you start coding, do take note of the below two points.
-
Get some sense of the overall design by reading Section 2.1, “Architecture”.
-
Take a look at Appendix A, Suggested Programming Tasks to Get Started.
This section describes and explains the design and structure behind the App, as well as all the core components that form the entire structure.
The Architecture Diagram given above explains the high-level design of the application. There are a total of 6 major components:
Main
, Commons
, UI
, Logic
, Model
, and Storage
. Given below is a quick overview of each component.
💡
|
The .pptx files used to create diagrams in this document can be found in the diagrams folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose Save as picture .
|
Main
has only one class called MainApp
. It is responsible for:
-
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 method where necessary.
Commons
represents a collection of classes used by multiple other components. Classes used by multiple components are in the seedu.inventory.commons
package.
Two of those classes play important roles at the architecture level:
-
EventsCenter
: This class (written using Google’s Event Bus library) is used by components to communicate with other components using events (i.e. a form of Event Driven design) -
LogsCenter
: Used by many classes to write log messages to the App’s log file.
UI
consists of the different parts that make up the User Interface (UI) of the App.
Logic
is the App’s command executor.
It takes care of parsing, executing and processing commands entered by the users.
Model
holds the data of the App in-memory.
Storage
reads data from, and writes data to, the hard disk.
It is responsible for storing data used by the App.
Each of the four components Ui
, Logic
, Model
, and Storage
:
-
Defines its API in an
interface
with the same name as the Component. -
Exposes its functionality using a
{Component Name}Manager
class.
For example, the Logic
component (see the class diagram given below) defines it’s API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class.
The Sequence Diagram below shows how the components interact for the scenario where the user issues the command delete-item 1
.
ℹ️
|
Note how the Model simply raises an InventoryChangedEvent when the Inventory List data are changed, instead of asking the Storage to save the updates to the hard disk.
|
The diagram below shows how the EventsCenter
reacts to that event, which eventually results in the updates being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.
ℹ️
|
Note how the event is propagated through the EventsCenter to the Storage and UI without Model having to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct coupling between components.
|
The sections below give more details of the UI
, Logic
, Model
, Storage
components.
API : Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, ItemListPanel
, StatusBarFooter
, BrowserPanel
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
-
Executes user commands using the
Logic
component. -
Binds itself to some data in the
Model
so that the UI can auto-update when data in theModel
change. -
Responds to events raised from various parts of the App and updates the UI accordingly.
API :
Logic.java
-
Logic
uses theInventoryParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding a item) and/or raise events. -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
.
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("delete 1")
API call.
API : Model.java
The Model
,
-
stores a
UserPref
object that represents the user’s preferences. -
stores the Inventory Manager data.
-
exposes an unmodifiable
ObservableList<Item>
that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -
does not depend on any of the other three components.
API : Storage.java
The Storage
component,
-
can save
UserPref
objects in json format and read it back. -
can save the Inventory Manager data in xml format and read it back.
This section describes some noteworthy details on how certain features are implemented.
The undo/redo mechanism is facilitated by VersionedInventory
.
It extends Inventory
with an undo/redo history, stored internally as an inventoryStateList
and currentStatePointer
.
Additionally, it implements the following operations:
-
VersionedInventory#commit()
— Saves the current inventory state in its history. -
VersionedInventory#undo()
— Restores the previous inventory state from its history. -
VersionedInventory#redo()
— Restores a previously undone inventory state from its history.
These operations are exposed in the Model
interface as Model#commitInventory()
, Model#undoInventory()
and Model#redoInventory()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedInventory
will be initialized with the initial state, and the currentStatePointer
pointing to that single state.
Step 2. The user executes delete-item 5
command to delete the 5th item in Inventory Manager. The delete
command calls Model#commitInventory()
, causing the modified state of Inventory Manager after the delete-item 5
command executes to be saved in the InventoryStateList
, and the currentStatePointer
is shifted to the newly inserted Inventory Manager state.
Step 3. The user executes add-item n/iPhone …
to add a new item. The add
command also calls Model#commitInventory()
, causing another modified inventory state to be saved into the inventoryStateList
.
ℹ️
|
If a command fails its execution, it will not call Model#commitInventory() , so the inventory state will not be saved into the inventoryStateList .
|
Step 4. The user now decides that adding the item was a mistake, and decides to undo that action by executing the undo
command. The undo
command will call Model#undoInventory()
, which will shift the currentStatePointer
once to the left, pointing it to the previous inventory state, and restores the inventory to that state.
ℹ️
|
If the currentStatePointer is at index 0, pointing to the initial inventory state, then there is no previous inventory state to restore. The undo command uses Model#canUndoInventory() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.
|
The following sequence diagram shows how the undo operation works:
The redo
command does the opposite — it calls Model#redoInventory()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and restores the inventory to that state.
ℹ️
|
If the currentStatePointer is at index inventoryStateList.size() - 1 , pointing to the latest inventory state, then there is no undone inventory state to restore. The redo command uses Model#canRedoAInventory() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
|
Step 5. The user then decides to execute the command list-item
. Commands that do not modify Inventory Manager, such as list-item
,
will usually not call Model#commitInventory()
, Model#undoInventory()
or Model#redoInventory()
. Thus, the inventoryStateList
remains unchanged.
Step 6. The user executes clear
, which calls Model#commitInventory()
. Since the currentStatePointer
is not pointing at the end of the inventoryStateList
, all inventory states after the currentStatePointer
will be purged. We designed it this way because it no longer makes sense to redo the add-item n/iPhone …
command. This is the behavior that most modern desktop applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
-
Alternative 1 (current choice): Saves the entire inventory.
-
Pros: Easy to implement.
-
Cons: May have performance issues in terms of memory usage.
-
-
Alternative 2: Individual command knows how to undo/redo by itself.
-
Pros: Will use less memory (e.g. for
delete
, just save the item being deleted). -
Cons: We must ensure that the implementation of each individual command are correct.
-
-
Alternative 1 (current choice): Use a list to store the history of inventory states.
-
Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project.
-
Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both
HistoryManager
andVersionedInventory
.
-
-
Alternative 2: Use
HistoryManager
for undo/redo-
Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.
-
Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as
HistoryManager
now needs to do two different things.
-
Inventory management is introduced in Inventory manager as a core feature to allow users to easily manage items in their inventory list.
An Item
consists of Name
, Price
, Quantity
, unique SKU
, Image Path
, and optional Tags
. An item
is considered unique based on its SKU
.
An item can only be successfully added into the inventory if the following criteria are met:
-
Name
contains only alphanumeric characters -
Price
contains only positive whole numbers or decimals -
Quantity
contains only positive whole numbers -
SKU
is unique and contains only alphanumeric characters and the dash '-' or underscore '_' symbols -
Image Path
is a valid file path and the file must be a valid image (i.e. either .png or .jpeg format)
Items are stored and maintained in the Model in a UniqueItemList
, allowing only unique items to be stored in the inventory.
Individual items are represented by the Item
object with attributes Name
, Price
, Quantity
, SKU
, Image
and Tag
.
Items are stored in XmlAdaptedItem
objects, and physically stored in XML files. An item is stored in an XML file in the following format:
<inventory>
<items>
<name>iPhone XR</name>
<price>1500.00</price>
<quantity>30</quantity>
<sku>apple-iphone-xr</sku>
<image>/images/iphone.jpg</image>
</items>
</inventory>
The main window contains a ListPanel
, which can be used interchangeably to display any lists based on the command entered by the user.
Inventory list is displayed in the ListPanel
upon executing the list-item
command, and
individual items are represented using ItemCard
. The items' attribute fields uses Label
.
An example of the ItemCard
in Inventory Manager UI is shown in Figure 11 below:
The following commands were added and/or modified to handle inventory management operations:
-
list-item
: List all items in the inventory -
list-low-qty
: List all items with quantities less than or equal to 10 in the inventory -
find-item-sku
: Search for items based on SKU -
filter-item
: Filter items based on quantity and/or price -
add-item
: Add a unique item into the inventory -
delete-item
: Delete an existing item in the inventory -
edit-item
: Edit an existing item in the inventory
Operations performed on items follow the sequence of operations as described below:
-
Command input is received by the UI component.
-
The command execution is handled by the Logic component.
-
The changes to data are effected by the Model component.
-
The new Inventory Manager data is saved by the Storage component.
This sequence of events is summarized in the following sequence diagram:
Aspect: Where updateItem
is executed
There are various places where updateItem
can be executed. The pros and cons for each option is shown below.
Alternative 1 (current choice): Executed at Logic
Pros: Easy to implement.
Cons: Direct calling of Model.updateItem()
will not be validated.
Alternative 2: Executed at Model
Pros: Ensures that all entries are validated before item can be edited.
Cons:Model.updateItem()
will need to access inventory to perform validation.
Based on the above consideration, the first option is chosen as it is easier to implement, and it does not require
Model.updateItem()
to read the inventory and perform validation.
Since an item is considered unique based on its SKU, it is important to validate that an item has a unique SKU before it is allowed to be added or edited in the inventory.
Before an item is allowed to be added or edited, it is checked against every item in the inventory list. There are two checks to verify if two items are the same: 1. comparing the two items against every field, and 2. comparing only SKU.
The following code snippet shows how the item is checked for uniqueness:
public boolean isSameItem(Item otherItem) {
if (otherItem == this) {
return true;
}
return otherItem != null
&& otherItem.getSku().equals(getSku());
}
Inventory Manager supports images for items, therefore, it is important to validate that images supplied by users are stored in a valid file path, and that the image is a valid image file.
Inventory Manager checks if the directory supplied by the user is a valid file path. Then, the file’s mime-type will be verified to ensure that it is a valid image file.
The following code snippet shows how the image URL is checked and validated:
public static boolean isValidImage(String test) {
if (test.matches(IMAGE_VALIDATION_REGEX)) {
File file = new File(test);
if (file.exists()) {
try {
String mimeType = Files.probeContentType(file.toPath());
return (mimeType != null && mimeType.split("/")[0].equals("image"));
} catch (IOException e) {
e.printStackTrace();
return false;
}
} else {
return (Image.class.getResource(test) != null && (test.endsWith("png") || test.endsWith("jpg")));
}
} else {
return false;
}
}
The sale order creation command was developed to allow users to easily deduct item quantity from the inventory.
Creating a sale order requires the item SKU and the quantity that has been sold to be entered. The sale ID and sale date will then be automatically generated by the system.
Creating a new sale requires SaleID
, Item
, Quantity
and SaleDate
.
The creation of sale order is handled by the AddSaleCommand
. The use of it will trigger Model#updateItem
,
which will then update the item’s quantity. After Model#updateItem
has complete, the sale order will be stored into
the XML file.
For AddSaleCommand#execute
to be successful, there are two conditions which needs to be met. The following two conditions are:
-
The item must exists in Inventory Manager.
-
The available item quantity must be more than or equal to the quantity sold.
AddSaleCommand#execute
will perform the validation before proceeding. If any of the above validation fails,
CommandException
will be thrown and it will not call Model#updateItem
.
The sequence diagram below shows the interactions inside the logic component for the AddSaleCommand
.
The sale orders created are stored into a XML file, named sale.xml
, in the data
folder. Below shows an example of
how each sale is stored in the XML file.
<sale>
<saleId>1</saleId>
<saleSku>apple-iphone-xr</saleSku>
<saleQuantity>1</saleQuantity>
<saleDate>2018-08-01</saleDate>
</sale>
Each sale created is represented as a sale
element in the XML file as seen above. Each tag represents information for the sale order,
which is further explained below.
-
saleID - This represents the sale ID of the created sale order.
-
saleSku - This represents the sold item SKU.
-
saleQuantity - This represents the sold quantity for the created sale order.
-
saleDate - This represents the date the sale order was created.
On starting Inventory Manager, the XML file will be loaded, and each sale will be validated for corruption before being loaded into memory.
There are a few design considerations when creating a sale order. Below will explain the various considerations and the choices made.
There are various places where updateItem
can be executed. The pros and cons for each option is shown below.
-
Executed at Logic
-
Pros: Easy to implement
-
Cons: Direct calling of
Model#addSale
will not be validated.
-
-
Executed at Model
-
Pros: Ensures that all entries are validated before sale can be created.
-
Cons:
Model#addSale
will need to access inventory to perform validations.
-
Based on the above pros and cons, the first option is chosen as it is easier to implement, and it does not require
Model#addSale
to read the inventory and perform validations.
We are using java.util.logging
package for logging. The LogsCenter
class is used to manage the logging levels and logging destinations.
-
The logging level can be controlled using the
logLevel
setting in the configuration file (See Section 3.5, “Configuration”) -
The
Logger
for a class can be obtained usingLogsCenter.getLogger(Class)
which will log messages according to the specified logging level -
Currently log messages are output through:
Console
and to a.log
file.
Logging levels
-
SEVERE
: Critical problem detected which may possibly cause the termination of the application -
WARNING
: Can continue, but with caution -
INFO
: Information showing the noteworthy actions by the App -
FINE
: Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size
Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file (default: config.json
).
Authentication is introduced in Inventory Manager which allows the users to authenticate themselves to perform their inventory management tasks. This is to prevent any unauthorized users from accessing the system.
The authentication of the user is handled by LoginCommand
. The use of it will trigger Model#authenticateUser
,
which will authenticate the user in the Inventory Manager. However, for LoginCommand#execute
to be successful,
there are two conditions which need to be met.
The following two conditions must be met before executing:
-
The current user who is executing the command must be providing a valid username and password.
-
The user must have an account exists in the system.
LoginCommand#execute
will perform the validation before proceeding. If any of the above validation fails,
CommandException
will be thrown and it will not call Model#authenticateUser
.
There are a few design considerations when authenticating a staff. Below will explain the various considerations and the choices made.
There are various places where authenticateUser
can be executed. The pros and cons of each option are shown below.
Alternative 1 (current choice): Executed at Logic
Pros: Easy to implement.
Cons: Direct calling of Model.authenticateUser()
will not be validated.
Alternative 2: Executed as an Event
Pros: Able to be used by any component of the application.
Cons: AuthenticateUserEvent.execute()
will need to access the staff list to perform validations.
Based on the above pros and cons, the first option is chosen as it is easier to implement, and it does not require
AuthenticateUserEvent.execute()
to read the inventory and perform validations.
The following commands are added for Authentication:
-
login
: Authenticates a staff -
change-password
: Changes the current user’s password -
logout
: Logout a staff and clears all the command history
The sequence diagram below shows how login is executed at the logic component.
Authentication has a UserSession
object stores in the Model Component of the system. This is due to this component has to be
largely relied on when the commands are executed.
Newly created user session object comes with a Staff
object to store the current user’s information.
The class diagram below shows the relationship between each object used in authentication feature.
Editing a user will have the staff’s account information updated. Below will describe how this feature is implemented in the Inventory Manager.
The update of the user is handled by EditStaffCommand
. The use of it will trigger Model#updateStaff
,
which will edit the user in the Inventory Manager. However, for EditStaffCommand#execute
to be successful,
there are two conditions which need to be met.
The following two conditions must be met before:
-
Ther current user who is executing the command must be a user with admin role.
-
The index of the staff must be a valid number and existing in the staff list shown.
EditStaffCommand#execute
will perform the validation before proceeding. If any of the above validation fails,
CommandException
will be thrown and it will not call Model#updateStaff
.
There are a few design considerations when editing a staff. Below will explain the various considerations and the choices made.
There are various places where edit-staff
can be executed. The pros and cons of each option are shown below.
-
Executed at Logic
-
Pros: Easy to implement
-
Cons: The direct calling of
Model#editStaff
will not be validated.
-
-
Executed at Model
-
Pros: Ensures that all entries are validated before staff can be updated.
-
Cons:
Model#editStaff
will need to access the staff list to perform validations.
-
Based on the above pros and cons, the first option is chosen as it is easier to implement, and it does not require
Model#editStaff
to read the inventory and perform validations.
The following commands are added for User Management:
-
add-staff
: Add a staff -
list-staff
: List all staffs -
edit-staff
: Edit a staff -
delete-staff
: Delete a staff
The sequence diagram below shows how edit-staff
is executed at the logic component.
Staffs are managed in the Model as a UniqueStaffList which disallows duplicated staff to be added.
The class diagram shows the relationship of the objects involved in the user management feature.
Staffs are stored as XmlAdaptedStaff
objects in XMLSerializableStaffList
, which maintain a class relationship as shown in this diagram.
An example staff stored in XML format is reproduced below:
<staffs>
<username>johndoe</username>
<password>5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8</password>
<name>John Doe</name>
<role>user</role>
</staffs>
ℹ️
|
Passwords are stored in hashed format using SHA-256 encoding. |
In order to enable users to have further analysis of the data in Inventory Manager,
we support several export-csv
commands to export the data in Inventory Manager to CSV files.
We are using export-csv-items
, export-csv-sales
, export-csv-staffs
, export-csv-orders
to support exporting of Inventory Manager data through CSV files.
In the following sections, we will focus on how these commands depend on the Model
and Storage
component
to retrieve external data and where to validate the given file path.
In order to achieve their tasks, all export
commands require direct access to the data and output to the
external environment. Unlike other commands, these commands highly depend on the Storage
component.
However, if we only directly set a Storage
for the command and manipulate on the Storage
in export
command,
we also need Storage
component to directly access the data in Model
component which will violate
Single Responsibility Principle.
So we decide to use the same method as other command use to export data. When executing the export
commands,
a DataExportEvent
will be raised in the EventsCenter
through Model
component. Since Logic
directly has
Model
as one field, it will not violate the Single Responsibility Principle. Then, the handler function in Storage
component will catch this DataExportingEvent
and export data to the external environment.
File paths, as required by export
commands, need to be validated during the execution of the commands.
However, where to implement it can be decided. It can be implemented in CommandParser
or Command
or even in Storage
.
In our implementation, we choose to validate the file path during the execution of export
Command. A static method
in FileUtil
will be called to test whether the given file path is valid when executing the command. In doing so,
we are able to make sure that the path parameter passed to Model
component and Storage
component is a valid
file path. Also, it is easier for the implementation of command feedback to the users.
Further details can be found in the sequence diagram of the next section.
Considering that all the export
commands have similar sequence diagrams. So we will just show the sequence diagrams
for export-csv-items
command to illustrate how the export
commands work.
The Sequence Diagram below shows how the components interact for the scenario where the user issues the
command export-csv-items f/items.csv
.
The diagram below shows how the EventsCenter
reacts to that event, which eventually results in the item list being
exported and the alert window of the UI being popped up to reflect the success of exporting.
The diagram below is the lower level sequence diagram for export-csv-items f/items.csv
command inside Logic
component.
-
Alternative 1 (current choice): Raises a
DataExportEvent
in theEventsCenter
throughModel
and handles it inStorage
.-
Pros: Avoids direct access of
Storage
fromexport
commands. Does not violate the Single Responsibility Principle. -
Cons: Needs a middle Component to achieve the goal. Needs to raise an additional event.
-
-
Alternative 2: Couples
Command
withStorage
-
Pros: Provides direct access to
Storage
for commands that is highly depend it. -
Cons: Needs directly access of data in
Model
component forStorage
which will violate the Single Responsibility Principle.
-
Aspect: Location for implementation of file path validation and location to check file path validation
-
Alternative 1 (current choice): Implements in
FileUtil
and checks inexport
command.-
Pros: It’s sure that the path passed to
Model
component andStorage
component is a valid file path. The implementation of command feedback is easier. File Validation is reusable in other component. -
Cons: File Validation needs to interact with
Commons
component.
-
-
Alternative 2: Implements in
CommandParser
and checks inCommandParser
class.-
Pros: There is no need to interact with other component.
-
Cons: File Validation is not reusable in other component.
-
-
Alternative 3: Implements in
Storage
and checks inStorage
.-
Pros: There is no need to interact with other component. File Validation is reusable in other method of
Storage
. -
Cons: The path passed to
Storage
component may not be valid. The implementation of command feedback is more difficult.Storage
needs to raise an additional event for invalid file path.
-
Since Csv file do not have standardized format for storing objects. So we designed a format that need to be followed when importing csv files. If the process of importing fails due to unrecognizable failure, do check the file to import meets the requirement.
An example of recognizable csv file storing the items is reproduced below: (Opened with a Plain Text Editor,not Excel)
Item,,,,, name,price,quantity,sku,image,tags iPhone XR,1500.00,30,apple-iphone-xr,/images/iphone.jpg,"apple,iphone" LG G7,1250.50,90,lg-g7,/images/lg.jpg,"smartphone,lg" Samsung S9,1499.99,14,samsung-s9,/images/samsung.jpg,"samsung,smartphone" HTC U6 ,999.00,88,htc-u6,/images/htc.jpg,"samsung,phablet" Google Pixel XL,1435.90,3,google-pixel-xl,/images/google.jpg,google
The first two lines are headers to determine which kind of object is this csv file storing.
Following lines are the details of the objects. Empty lines are not allowed. If a cell contains commas(,
), it must be surrounded
by double quotation marks("
"
).
The required format can be gotten by simply exporting each kind of objects first.
Purchase order management is introduced in Inventory manager to allow user to restock item easily and manage the purchase order details efficiently.
The purchase order details includes the item’s SKU, restock quantity, required date and supplier.
Purchase order can only be added if it matches the item’s SKU.
Newly added purchase order comes with a default PENDING
status which subsequently can be edited, approved, rejected and deleted.
Purchase orders are maintained in the Model in a NonUniquePurchaseOrderList, allowing non unique purchase order among the stored individual purchase orders. The UML diagram is as shown in the figure below.
Individual purchase order are represented by the PurchaseOrder
object with attributes Sku
, Quantity
, RequiredDate
and Supplier
. The class relationship is shown
in Figure 11 below.
Purchase orders are stored in XmlAdaptedPurchaseOrder
objects, which maintain a class relationship as shown in the diagram below:
To save the XmlAdaptedPurchaseOrder objects created, it is stored in a plain text file following the XML format.
An example purchase order stored in XML format is reproduced below:
<purchaseOrders>
<sku>apple-iphone-xr</sku>
<quantity>1000</quantity>
<reqDate>2018-12-12</reqDate>
<supplier>Apple Inc.</supplier>
<status>APPROVED</status>
</purchaseOrders>
The main window contains a ListPanel, which is interchangeable to display any list based on the
command entered. Purchase order list is shown in the ListPanel upon executing list-po
.
Individual purchase orders are represented using PurchaseOrderCards that contains the
attributes fields using labels and flowPanes.
The diagram below shows how purchase order panel is integrated in the Ui class diagram.
The following commands were added to handle the purchase order:
-
list-po
: List all purchase orders -
add-po
: Add a purchase order -
delete-po
: Delete a purchase order -
approve-po
: Approve a purchase order -
reject-po
: Reject a purchase order -
edit-po
: Edit a purchase order
The following diagram details the class relationship for the Purchase order Commands.
Operations performed on purchase orders follow the sequence of operations described in the diagram below.
-
Command input is received by the UI component.
-
The command execution is handled by the Logic component.
-
The changes to data are effected by the Model component.
-
The new Inventory Manager data is saved by the Storage component.
This sequence of events is summarized in the following sequence diagrams:
Aspect: Implementation of purchase order commands that requires the item to be updated.
Commands such as approve-po
will update the item quantity upon approval. Consequently, there are various places where
updateItem
can be executed. The pros and cons for each option is shown below.
Alternative 1 (current choice): Executed at Logic
Pros: Allows the user to get the item list from the model directly; less hassle.
Cons: Complicates the test cases as everything is done in one method.
Alternative 2: Executed at Model
Pros: Allows the user to call the item directly from the list that is stored in the model.
Cons: Requires additional method in the model which in turns requires to update 4 relevant model files.
Based on the above pros and cons, the first option is chosen as it is easier to implement and only requires 1 logic file to be edited.
Aspect: Implementation of purchase order storage
There are various design on how to integrate purchase order in the existing storage system. The pros and cons for each option is shown below.
Alternative 1 (current choice): Stored in the same file as the item but with different xml tag
Pros: Eases the implementation by adding in relevant purchase order detail in the existing storage implementation.
Cons: Disorganizes the storage file as all the different data is clunked together
Alternative 2: Created a whole new standalone storage for purchase order
Pros: Organizes the data separately into it’s own file.
Cons: Requires a lot of work, additional files and test cases.
Based on the above pros and cons, the first option is chosen as it is easier to implement, requires lesser test case and more efficient work load.
The documentation for this project is written and maintained using asciidoc, it can found in the docs folder.
ℹ️
|
We chose asciidoc over Markdown because asciidoc provides more flexibility in formatting. |
We use IntelliJ to edit the documentation. The documentation can be rendered and previewed on IntelliJ.
💡
|
See UsingGradle.adoc to learn how to render .adoc files locally to preview the end result of your edits.
Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc files in real-time.
|
We use Travis as an automation tool to deploy the documentation to Github Page.
💡
|
See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis. |
We use Google Chrome for converting the documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.
Here are the steps to convert the project documentation files to PDF format.
-
Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the
docs/
directory to HTML format. -
Go to your generated HTML files in the
build/docs
folder, right click on them and selectOpen with
→Google Chrome
. -
Click on the
Print
option in Google Chrome’s menu. -
Set the destination to
Save as PDF
, then clickSave
to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.
We specify project-specific asciidoc attributes in build.gradle
file which affects how all documentation files within this project are rendered.
💡
|
Attributes left unset in the build.gradle file will use their default value, if any.
|
Attribute name | Description | Default value |
---|---|---|
|
The name of the website. If set, the name will be displayed near the top of the page. |
not set |
|
The URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar. |
not set |
|
The attribute to indicate if the project is an official SE-EDU project. This will render the SE-EDU navigation bar at the top of the page, and add some SE-EDU-specific navigation items. |
not set |
We specify the file-specific asciidoc attributes in each .adoc
file which affects how the file is rendered.
Asciidoctor’s built-in attributes may be specified and used as well.
💡
|
Attributes left unset in .adoc files will use their default value, if any.
|
Attribute name | Description | Default value |
---|---|---|
|
Site section that the document belongs to.
This will cause the associated item in the navigation bar to be highlighted.
One of: * Official SE-EDU projects only |
not set |
|
Set this attribute to remove the site navigation bar. |
not set |
The files in docs/stylesheets
are the CSS stylesheets of the site.
You can modify them to change some properties of the site’s design.
The files in docs/templates
controls the rendering of .adoc
files into HTML5.
These template files are written in a mixture of Ruby and Slim.
|
Modifying the template files in |
Testing the software will provide a better user experience for the users. Below will describe the type of tests available, the ways it can be run and the steps to troubleshooting the tests when it fails.
Below describe the two types of tests available.
-
GUI tests - These are tests involving the GUI. They include the below.
-
System Tests that test the entire App by simulating user actions on the GUI. These are in the
systemtests
package. -
Unit tests that test the individual components. These are in
seedu.inventory.ui
package.
-
-
Non-GUI tests - These are tests not involving the GUI. They include the below.
-
Unit tests targeting the lowest level methods / classes.
e.g.seedu.inventory.commons.StringUtilTest
-
Integration tests that are checking the integration of multiple code units (those code units are assumed to be working).
e.g.seedu.inventory.storage.StorageManagerTest
-
Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
e.g.seedu.inventory.logic.LogicManagerTest
-
There are three ways to run tests.
💡
|
The most reliable way to run tests is the third method. The first two methods might fail some GUI tests due to platform / resolution-specific idiosyncrasies. |
Method 1: Using IntelliJ JUnit test runner
-
To run all tests, right-click on the
src/test/java
folder and chooseRun 'All Tests'
. -
To run a subset of tests, you can right-click on a test package, test class, or a test and choose
Run 'X'
.
Method 2: Using Gradle
-
Open a console and run the command
gradlew clean allTests
(Mac/Linux:./gradlew clean allTests
).
ℹ️
|
See UsingGradle.adoc for more information on how to run tests using Gradle. |
Method 3: Using Gradle (headless)
Thanks to the TestFX library we use, our GUI tests can run in the headless mode. In the headless mode, GUI tests do not show up on the screen. That means the developer can perform other tasks on the computer while the tests are running.
To run the tests in headless mode, open a console and run the command gradlew clean headless allTests
(Mac/Linux: ./gradlew clean headless allTests
).
This part will guide you through on the approach of integration we used.
We use Gradle as our build automation tool to automate the build process.
💡
|
See UsingGradle.adoc to learn how to use Gradle for build automation. |
💡
|
See UsingTravis.adoc and UsingAppVeyor.adoc for more details. |
We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.
When a pull request has changes to asciidoc files, you can use Netlify to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged.
💡
|
See UsingNetlify.adoc for more details. |
Here are the steps to create a new release.
-
Update the version number in
MainApp.java
. -
Generate a JAR file using Gradle.
-
Tag the repo with the version number. e.g.
v0.1
-
Create a new release using GitHub and upload the JAR file you created.
A project often depends on third-party libraries. For example, Inventory Manager depends on the Jackson library for XML parsing. Managing these dependencies can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives.
a. Include those libraries in the repo (this bloats the repo size)
b. Require developers to download those libraries manually (this creates extra work for developers)
Suggested path for new programmers:
-
First, add small local-impact (i.e. the impact of the change does not go beyond the component) enhancements to one component at a time. Some suggestions are given in Section A.1, “Improving each component”.
-
Next, add a feature that touches multiple components to learn how to implement an end-to-end feature across all components. Section A.2, “Creating a new command:
remark
” explains how to go about adding such a feature.
Each individual exercise in this section is component-based (i.e. you would not need to modify the other components to get it to work).
Scenario: You are in charge of logic
. During dog-fooding, your team realize that it is troublesome for the user to type the whole command in order to execute a command. Your team devise some strategies to help cut down the amount of typing necessary, and one of the suggestions was to implement aliases for the command words. Your job is to implement such aliases.
💡
|
Do take a look at Section 2.3, “Logic component” before attempting to modify the Logic component.
|
-
Add a shorthand equivalent alias for each of the individual commands. For example, besides typing
clear
, the user can also typec
to remove all items in the list.-
Hints
-
Just like we store each individual command word constant
COMMAND_WORD
inside*Command.java
(e.g.FindItemCommand#COMMAND_WORD
,DeleteItemCommand#COMMAND_WORD
), you need a new constant for aliases as well (e.g.FindItemCommand#COMMAND_ALIAS
). -
InventoryParser
is responsible for analyzing command words.
-
-
Solution
-
Modify the switch statement in
InventoryParser#parseCommand(String)
such that both the proper command word and alias can be used to execute the same intended command. -
Add new tests for each of the aliases that you have added.
-
Update the user guide to document the new aliases.
-
See this PR for the full solution.
-
-
Scenario: You are in charge of model
. One day, the logic
-in-charge approaches you for help. He wants to implement a command such that the user is able to remove a particular tag from everyone in the image book, but the model API does not support such a functionality at the moment. Your job is to implement an API method, so that your teammate can use your API to implement his command.
💡
|
Do take a look at Section 2.4, “Model component” before attempting to modify the Model component.
|
-
Add a
removeTag(Tag)
method. The specified tag will be removed from everyone in the image book.-
Hints
-
Think about how you can use SLAP to design the method. Where should we place the main logic of deleting tags?
-
Find out which of the existing API methods in
Inventory
andItem
classes can be used to implement the tag removal logic.Inventory
allows you to update a item, andItem
allows you to update the tags.
-
Solution
-
Implement a
removeTag(Tag)
method inInventory
. Loop through each item, and remove thetag
from each item. -
Add a new API method
deleteTag(Tag)
inModelManager
. YourModelManager
should callInventory#removeTag(Tag)
. -
Add new tests for each of the new public methods that you have added.
-
See this PR for the full solution.
-
-
Scenario: You are in charge of ui
. During a beta testing session, your team is observing how the users use your image book application. You realize that one of the users occasionally tries to delete non-existent tags from a contact, because the tags all look the same visually, and the user got confused. Another user made a typing mistake in his command, but did not realize he had done so because the error message wasn’t prominent enough. A third user keeps scrolling down the list, because he keeps forgetting the index of the last item in the list. Your job is to implement improvements to the UI to solve all these problems.
💡
|
Do take a look at Section 2.2, “UI component” before attempting to modify the UI component.
|
-
Use different colors for different tags inside item cards. For example,
friends
tags can be all in brown, andcolleagues
tags can be all in yellow.Before
After
-
Hints
-
The tag labels are created inside the
ItemCard
constructor (new Label(tag.tagName)
). JavaFX’sLabel
class allows you to modify the style of each Label, such as changing its color. -
Use the .css attribute
-fx-background-color
to add a color. -
You may wish to modify
DarkTheme.css
to include some pre-defined colors using css, especially if you have experience with web-based css.
-
-
Solution
-
You can modify the existing test methods for
ItemCard
's to include testing the tag’s color as well. -
See this PR for the full solution.
-
The PR uses the hash code of the tag names to generate a color. This is deliberately designed to ensure consistent colors each time the application runs. You may wish to expand on this design to include additional features, such as allowing users to set their own tag colors, and directly saving the colors to storage, so that tags retain their colors even if the hash code algorithm changes.
-
-
-
-
Modify
NewResultAvailableEvent
such thatResultDisplay
can show a different style on error (currently it shows the same regardless of errors).Before
After
-
Hints
-
NewResultAvailableEvent
is raised byCommandBox
which also knows whether the result is a success or failure, and is caught byResultDisplay
which is where we want to change the style to. -
Refer to
CommandBox
for an example on how to display an error.
-
-
Solution
-
Modify
NewResultAvailableEvent
's constructor so that users of the event can indicate whether an error has occurred. -
Modify
ResultDisplay#handleNewResultAvailableEvent(NewResultAvailableEvent)
to react to this event appropriately. -
You can write two different kinds of tests to ensure that the functionality works:
-
The unit tests for
ResultDisplay
can be modified to include verification of the color. -
The system tests
InventorySystemTest#assertCommandBoxShowsDefaultStyle() and InventorySystemTest#assertCommandBoxShowsErrorStyle()
to include verification forResultDisplay
as well.
-
-
See this PR for the full solution.
-
Do read the commits one at a time if you feel overwhelmed.
-
-
-
-
Modify the
StatusBarFooter
to show the total number of people in the image book.Before
After
-
Hints
-
StatusBarFooter.fxml
will need a newStatusBar
. Be sure to set theGridPane.columnIndex
properly for eachStatusBar
to avoid misalignment! -
StatusBarFooter
needs to initialize the status bar on application start, and to update it accordingly whenever the image book is updated.
-
-
Solution
-
Modify the constructor of
StatusBarFooter
to take in the number of items when the application just started. -
Use
StatusBarFooter#handleInventoryChangedEvent(InventoryChangedEvent)
to update the number of items whenever there are new changes to the inventory. -
For tests, modify
StatusBarFooterHandle
by adding a state-saving functionality for the total number of people status, just like what we did for save location and sync status. -
For system tests, modify
InventorySystemTest
to also verify the new total number of items status bar. -
See this PR for the full solution.
-
-
Scenario: You are in charge of storage
. For your next project milestone, your team plans to implement a new feature of saving the image book to the cloud. However, the current implementation of the application constantly saves the image book after the execution of each command, which is not ideal if the user is working on limited internet connection. Your team decided that the application should instead save the changes to a temporary local backup file first, and only upload to the cloud after the user closes the application. Your job is to implement a backup API for the image book storage.
💡
|
Do take a look at Section 2.5, “Storage component” before attempting to modify the Storage component.
|
-
Add a new method
backupInventory(ReadOnlyInventory)
, so that the image book can be saved in a fixed temporary location.-
Hint
-
Add the API method in
InventoryStorage
interface. -
Implement the logic in
StorageManager
andXmlInventoryStorage
class.
-
-
Solution
-
See this PR for the full solution.
-
-
By creating this command, you will get a chance to learn how to implement a feature end-to-end, touching all major components of the app.
Scenario: You are a software maintainer for inventory
, as the former developer team has moved on to new projects. The current users of your application have a list of new feature requests that they hope the software will eventually have. The most popular request is to allow adding additional comments/notes about a particular contact, by providing a flexible remark
field for each contact, rather than relying on tags alone. After designing the specification for the remark
command, you are convinced that this feature is worth implementing. Your job is to implement the remark
command.
Edits the remark for a item specified in the INDEX
.
Format: remark INDEX r/[REMARK]
Examples:
-
remark 1 r/Likes to drink coffee.
Edits the remark for the first item toLikes to drink coffee.
-
remark 1 r/
Removes the remark for the first item.
Let’s start by teaching the application how to parse a remark
command. We will add the logic of remark
later.
Main:
-
Add a
RemarkCommand
that extendsCommand
. Upon execution, it should just throw anException
. -
Modify
InventoryParser
to accept aRemarkCommand
.
Tests:
-
Add
RemarkCommandTest
that tests thatexecute()
throws an Exception. -
Add new test method to
InventoryParserTest
, which tests that typing "remark" returns an instance ofRemarkCommand
.
Let’s teach the application to parse arguments that our remark
command will accept. E.g. 1 r/Likes to drink coffee.
Main:
-
Modify
RemarkCommand
to take in anIndex
andString
and print those two parameters as the error message. -
Add
RemarkCommandParser
that knows how to parse two arguments, one index and one with prefix 'r/'. -
Modify
InventoryParser
to use the newly implementedRemarkCommandParser
.
Tests:
-
Modify
RemarkCommandTest
to test theRemarkCommand#equals()
method. -
Add
RemarkCommandParserTest
that tests different boundary values forRemarkCommandParser
. -
Modify
InventoryParserTest
to test that the correct command is generated according to the user input.
Let’s add a placeholder on all our ItemCard
s to display a remark for each item later.
Main:
-
Add a
Label
with any random text insideItemListCard.fxml
. -
Add FXML annotation in
ItemCard
to tie the variable to the actual label.
Tests:
-
Modify
ItemCardHandle
so that future tests can read the contents of the remark label.
We have to properly encapsulate the remark in our Item
class. Instead of just using a String
, let’s follow the conventional class structure that the codebase already uses by adding a Remark
class.
Main:
-
Add
Remark
to model component (you can copy fromInventory
, remove the regex and change the names accordingly). -
Modify
RemarkCommand
to now take in aRemark
instead of aString
.
Tests:
-
Add test for
Remark
, to test theRemark#equals()
method.
Now we have the Remark
class, we need to actually use it inside Item
.
Main:
-
Add
getRemark()
inItem
. -
You may assume that the user will not be able to use the
add
andedit
commands to modify the remarks field (i.e. the item will be created without a remark). -
Modify
SampleDataUtil
to add remarks for the sample data (delete yourinventory.xml
so that the application will load the sample data when you launch it.)
We now have Remark`s for `Item`s, but they will be gone when we exit the application. Let’s modify `XmlAdapteItem
to include a Remark
field so that it will be saved.
Main:
-
Add a new Xml field for
Remark
.
Tests:
-
Fix
invalidAndValidItemInventory.xml
,typicalItemsInventory.xml
,validInventory.xml
etc., such that the XML tests will not fail due to a missing<remark>
element.
Since Item
can now have a Remark
, we should add a helper method to ItemBuilder
, so that users are able to create remarks when building a Item
.
Tests:
-
Add a new method
withRemark()
forItemBuilder
. This method will create a newRemark
for the item that it is currently building. -
Try and use the method on any sample
Item
inTypicalItems
.
Our remark label in ItemCard
is still a placeholder. Let’s bring it to life by binding it with the actual remark
field.
Main:
-
Modify
ItemCard
's constructor to bind theRemark
field to theItem
's remark.
Tests:
-
Modify
GuiTestAssert#assertCardDisplaysItem(…)
so that it will compare the now-functioning remark label.
We now have everything set up… but we still can’t modify the remarks. Let’s finish it up by adding in actual logic for our remark
command.
Main:
-
Replace the logic in
RemarkCommand#execute()
(that currently just throws anException
), with the actual logic to modify the remarks of a item.
Tests:
-
Update
RemarkCommandTest
to test that theexecute()
logic works.
See this PR for the step-by-step solution.
Target user profile:
-
Small to medium enterprises to manage their inventory
-
Experienced computer user with basic knowledge on Command Line Interface (CLI)
-
Organised business owners who wish to manage multiple groups of staffs
-
Efficient user who prefers typing over mouse input
Value proposition: Inventory Manager assists small to medium enterprises (SMEs) in managing their staff and inventory without a need to invest a huge sum in complicated and expensive inventory management systems.
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
|
user |
login through CLI |
use the features of the app |
`* * ` |
user |
change my password |
ensure the security of my account |
|
user |
logout through CLI |
ensure no one can access the system without my presence |
|
user |
be able to create sale order |
deduct inventory quantity |
|
user |
be able to show created sale order |
check created sale order |
|
user |
be able to delete sale order |
restore deducted inventory quantity |
|
user |
be able to update sale order |
update wrongly deducted inventory quantity |
|
user |
be able to view all the items as a list |
|
|
new user |
view all commands that I can use |
learn how to use the app |
|
manager |
export sales report to a CSV file |
better manage the inventory |
|
manager |
export all users to a CSV file |
better manage staff under me |
|
manager |
send sku to users |
send important information to staff |
|
manager |
search for item |
better manage items in inventory |
|
manager |
duplicate items |
create items efficiently |
|
manager |
update / modify existing items |
better manage items in inventory |
|
manager |
add items into inventory |
|
|
manager |
generate purchase order |
restock the inventories |
|
manager |
delete items from inventory |
remove items that are out-of-stock |
|
manager |
be notified for low inventory |
generate the purchase order |
|
admin |
add users to the system |
allow stakeholders of the system to use the apps |
|
admin |
remove users from the system |
remove the users who are no longer using the system. |
|
admin |
update users in the system |
update users' detail if necessary |
|
admin |
view all existing users in the system |
ensure that the system is always up to date |
|
admin |
assign roles to users |
restrict their user permissions |
|
expert user |
use shortcuts for commands |
use the app more efficiently |
|
user |
group items according to categories |
For all use cases below, the System is the Inventory Manager
application and the Actor is the user
, unless specified otherwise.
Below are various use cases for the System.
MSS
-
User requests to add item into Inventory.
-
Inventory Manager adds the item into the Inventory list.
Use case ends.
Extensions
-
1a. Item name does not follow the correct format.
-
1a1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
-
1b. Item SKU does not follow the correct format.
-
1b1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
-
1c. Item Quantity does not follow the correct format.
-
1c1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
-
1d. Item Image does not follow the correct format or is an invalid image/path.
-
1d1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
MSS
-
User requests to list items.
-
Inventory Manager shows a list of items
-
User requests to edit a specific item in the list
-
Inventory Manager edits the item
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
User requests to list items.
-
Inventory Manager shows a list of items
-
User requests to delete a specific item in the list
-
Inventory Manager deletes the item
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
Admin requests to add item into Inventory Manager.
-
Inventory Manager adds the staff into the Staff list.
Use case ends.
Extensions
-
1a. Staff name does not follow the correct format.
-
1a1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
-
1b. Staff username does not follow the correct format.
-
1b1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
-
1c. Staff password does not follow the correct format.
-
1c1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
-
1d. Staff Role does not equal to user, manager or admin.
-
1d1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
MSS
-
User requests to list staffs.
-
Inventory Manager shows a list of staffs
-
User requests to edit a specific staff in the list
-
Inventory Manager edits the staff
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
Admin requests to list staffs
-
Inventory Manager shows a list of staffs
-
Admins requests to delete a specific staff in the list
-
Inventory Manager deletes the staff
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given username is invalid.
-
3a1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
User requests to export data with a filepath given.
-
Inventory Manager exports the data to the filepath given.
-
Inventory Manager shows a preview of the data exported
Use case ends.
Extensions
-
1a. The filepath is empty or invalid.
-
1a1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
-
2a. The exporting progress fails.
-
2a1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
MSS
-
User requests to import data with a filepath given.
-
Inventory Manager imports the data from the filepath given.
-
Inventory Manager shows a preview of the data imported
Use case ends.
Extensions
-
1a. The filepath is empty or invalid.
-
1a1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
-
2a. The importing progress fails.
-
2a1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
MSS
-
User requests to list items.
-
Inventory Manager shows a list of items
-
User requests to add purchase order on an item based on it’s SKU
-
Inventory Manager adds purchase order
-
Inventory Manager shows a successful purchase order added message
Use case ends.
Extensions
-
2. The item list is empty.
Use case ends.
-
3a. The given command does not contain any item’s sku in the item list.
-
3a1. Inventory Manager shows an item not found message.
Use case resumes at step 2.
-
-
3b. The given command format is invalid.
-
3b1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
User requests to list purchase orders
-
Inventory Manager shows a list of purchase orders
-
User requests to approve a specific pending Purchase order in the list
-
Inventory Manager updates purchase order status
-
Inventory Manager shows a successful approval message
Use case ends.
Extensions
-
2. The purchase order list is empty.
Use case ends.
-
3a. The given purchase order ID is invalid.
-
3a1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
-
3b. The given command format is invalid.
-
3b1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
-
3c. The given purchase order status is not 'PENDING'.
-
3c1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
User requests to list purchase orders
-
Inventory Manager shows a list of purchase orders
-
User requests to reject a specific pending Purchase order in the list
-
Inventory Manager updates purchase order status
-
Inventory Manager shows a successful rejection message
Use case ends.
Extensions
-
2. The purchase order list is empty.
Use case ends.
-
3a. The given purchase order ID is invalid.
-
3a1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
-
3b. The given command format is invalid.
-
3b1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
-
3c. The given purchase order status is not 'PENDING'.
-
3c1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
User requests to list purchase orders
-
Inventory Manager shows a list of purchase orders
-
User requests to edit a specific purchase order in the list
-
Inventory Manager edits the purchase order
-
Inventory Manager shows a successful edit message
Use case ends.
Extensions
-
2. The purchase order list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
-
3b. The given command format is invalid.
-
3b1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
-
3c. The given purchase order status is not 'PENDING'.
-
3c1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
User requests to list purchase orders
-
Inventory Manager shows a list of purchase orders
-
User requests to delete a specific purchase order in the list
-
Inventory Manager deletes the purchase order
-
Inventory Manager shows a successful deletion message
Use case ends.
Extensions
-
2. The purchase order list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
-
3b. The given command format is invalid.
-
3b1. Inventory Manager shows an error message.
Use case resumes at step 2.
-
MSS
-
User requests to add a sale into the System.
-
System adds the sale into the sales list.
Use case ends.
Extensions
-
1a. SKU cannot be found in the System.
-
1a1. System shows an error message.
Use case resumes at step 1.
-
-
1b. Item SKU does not follow the correct format.
-
1b1. System shows an error message.
Use case resumes at step 1.
-
-
1c. Sale Quantity does not follow the correct format.
-
1c1. Inventory Manager shows an error message.
Use case resumes at step 1.
-
MSS
-
User request to list sale orders.
-
System shows a list of sale orders.
-
User requests to delete a specific sale order in the list.
-
System deletes the sale order.
Use case ends.
Extensions
-
1a. There is no sale order to list.
Use case ends.
-
1b. The given sale order ID is invalid.
-
1b1. System shows an error message.
Use case resumes at step 2.
-
-
Inventory manager to be compatible with most of the mainstream Operating Systems.
-
Support up to 100 products for inventory management without affecting performance of the application.
-
Generate each report within 3 seconds
-
Darren Ong Yun Kai
-
Authentication and User management
-
V1.1 Develop a users management API
-
V1.2 Support authentication of users and users management
-
V1.3 Support hashing of password
-
-
-
Esmond Tan
-
Sale Orders
-
V1.1 Support sale orders create
-
V1.2 Support sale orders delete
-
V1.3 Support sale orders list
-
-
-
Wang Chao
-
Reporting Module
-
V1.1 Support daily sales report
-
V1.2 Support exporting users and sales to sku and excel
-
V1.3 Support exporting inventory to sku and excel
-
-
-
Yao TengXiong
-
Inventory Management
-
V1.1 Support inventory create, read, update, delete
-
V1.2 Image support for inventory items
-
V1.3 Develop inventory management API
-
-
-
Zulqarnain
-
Purchase Order
-
V1.1 Support purchase order create, read, update, delete
-
V1.2 Integrate with Inventory API to update inventory
-
V1.3 Develop purchase order management API
-
-
- SKU
-
SKU stands for Stock Keeping Unit. It is a product and service identification code for a store or product.
- UML
-
UML stands for Unified Modeling Language which is used to specify, visualize, construct and document the behavior of a software.
- MSS
-
MSS stands for Main Success Scenario where it describes the shortest and most straightforward interaction by which the post-conditions can be achieved
- PO
-
PO stands for purchase order.
Given below are instructions to test the app manually.
ℹ️
|
These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. |
-
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.
-
-
Login
-
Prerequisites: The username and password of the staff must be in the staffs record.
-
Test case:
login u/admin p/password
Expected: User will be logged in and granted access on using other functions of the application. -
Test case:
login u/asd1231 p/
Expected: User will be prompted to fill in the empty password field. -
Test case:
login
,login u/ p/password
Expected: Similar to previous.
-
-
Change password
-
Prerequisites: User must be logged in and the new password must be different from the old password.
-
Test case:
change-password p/newpassword
Expected: User’s password will be updated and need to login using the new password in the next session. -
Test case:
change-password p/passworddd p/newpassword
Expected:newpassword
will be used as the new password. -
Test case:
change-password p/
Expected: User will be prompted to fill in the empty password field. -
Test case:
change-password
Expected: Similar to previous.
-
-
Logout
-
Prerequisites: User must be logged in.
-
Test case:
logout
Expected: User will be logged out.
-
-
Adding a user
-
Prerequisites: The staff to be added must not be a duplicated entry in the list and must login as an admin.
-
Test case:
add-staff u/johnd p/johndoe n/John Doe r/user
Expected: Staff will be added into the system. Details of the added staff shown in the status message. Timestamp in the status bar is updated. -
Test case:
add-staff u/
Expected: No staff is added. Error details shown in the status message. Status bar remains the same. -
Other incorrect add-staff commands to try:
add-staff
, `add-staff ,,,`_
Expected: Similar to previous.
-
-
Listing all the users
-
Prerequisites: Must login as an admin.
-
Test case:
list-staff
Expected: Staffs will be listed at the panel on the left of the UI.
-
-
Editing a user
-
Prerequisites: The staff to be edited must be an existing entry in the list
-
Test case:
edit-staff 1 u/johnd p/johndoe n/John Doe r/user
Expected: Edited staff will replace the existing staff in the system. Details of the edited staff shown in the status message. Timestamp in the status bar is updated. -
Test case:
edit-staff u/
Expected: No staff is edited. Error details shown in the status message. Status bar remains the same. -
Other incorrect add-staff commands to try:
edit-staff
, `edit-staff ,,,`_
Expected: Similar to previous.
-
-
Deleting a user
-
Prerequisites: The index provided must be the index in the existing list of staff shown
-
Test case:
delete-staff 2
Expected: Staff listed as second in the list will be deleted. Details of the deleted staff shown in the status message. Timestamp in the status bar is updated. -
Test case: `delete-staff `
Expected: No staff is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete-staff
, `delete-staff ,,,`_
Expected: Similar to previous.
-
-
Adding an item
-
Pre-requisites: The item to be added must not have the same SKU as another existing item in the inventory and must be logged in.
-
Test case:
add-item n/iPhone XR p/1500.00 q/70 s/apple-iphone-xr i/iphone.jpg
Expected: Item will be added into the inventory. Details of the added item shown in the status message. Timestamp in the status bar is updated. -
Test case:
add-item n/
Expected: No item is added. Error details shown in the status message. Status bar remains the same. -
Other incorrect add-item commands to try:
add-item
, `add-item ,,,`_
Expected: Similar to previous.
-
-
Listing all the items
-
Prerequisites: Must be logged in.
-
Test case:
list-item
Expected: All items will be listed at the panel on the left of the UI.
-
-
Listing all the items that are low on stock
-
Prerequisites: Must be logged in.
-
Test case:
list-low-qty
Expected: All items thath as quantities equal or less than 10 will be listed at the panel on the left of the UI.
-
-
Editing an item
-
Prerequisites: The item to be edited must be an existing entry in the inventory list
-
Test case:
edit-item 1 n/iPhone XS Midnight Blue
Expected: Edited item will replace the existing item in the system. Details of the edited item shown in the status message. Timestamp in the status bar is updated. -
Test case:
edit-item n/
Expected: No item is edited. Error details shown in the status message. Status bar remains the same. -
Other incorrect edit-item commands to try:
edit-item
, `edit-item ,,,`_
Expected: Similar to previous.
-
-
Deleting an item while all items are listed
-
Prerequisites: List all items using the
list-item
command. Multiple items in the list. -
Test case:
delete-item 1
Expected: First item is deleted from the list. Details of the deleted item shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete-item 0
Expected: No item is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete-item
,delete-item x
(where x is larger than the list size)
-
-
Adding a sale
-
Prerequisites: The sale to be added must be for an existing item.
-
Test case:
add-sale q/lg-g7 q/10
Expected: Sale will be added into the system. Details of the added sale shown in the status message. -
Test case:
add-sale q/123456
Expected: No sale is added. Error details shown in the status message. Status bar remains the same. -
Other incorrect add-staff commands to try:
add-sale
,add-sale abc
Expected: Similar to previous.
-
-
Deleting a sale
-
Prerequisites: The sale ID provided must be the sale ID as shown when the sale is listed.
-
Test case:
delete-sale 1
Expected: Sale listed with sale ID "1" will be deleted. Details of the deleted sale shown in the status message. -
Test case:
delete-sale
Expected: No sale is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete-sale
,delete-sale ABC
Expected: Similar to previous.
-
-
Listing all purchase orders
-
Prerequisites: User must be logged in
-
Test case:
list-po
Expected: Purchase orders will be listed at the panel on the left of the UI.
-
-
Adding a purchase order
-
Prerequisites: User must be logged, item sku must exist in the inventory manager, required date must be beyond the current date and the quantity must be valid.
-
Test case:
add-po s/apple-iphone-xr q/1000 d/2018-12-12 sp/Apple Inc
Expected: Purchase order will be added into the system. Details of the added purchase order is shown in the status message. Timestamp in the status bar is updated. -
Test case:
add-po s/
Expected: No purchase order is added. Error details shown in the status message. Status bar remains the same. -
Other incorrect add-po commands to try:
add-po
, `add-po ,,,`_
Expected: Similar to previous.
-
-
Editing a purchase order
-
Prerequisites: User must be logged, purchase order index must exist in the list and purchase order status must be in 'PENDING' status.
-
Test case:
edit-po 2 q/1000
Expected: Edited purchase order will replace the existing purchase order in the system. Details of the edited purchase order is shown in the status message. Timestamp in the status bar is updated. -
Test case:
edit-po asd sd/
Expected: No purchase order is edited. Error details shown in the status message. Status bar remains the same. -
Other incorrect edit-po commands to try:
edit-po
, `edit-po ,,,`_
Expected: Similar to previous.
-
-
Deleting a purchase order
-
Prerequisites: User must be logged, purchase order index must exist in the list.
-
Test case:
delete-po 2
Expected: Purchase order at index 2 will be deleted. Details of the deleted purchase order is shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete-po asd
Expected: No purchase order is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete-po commands to try:
delete-po
, `delete-po ,,,`_
Expected: Similar to previous.
-
-
Approving a purchase order
-
Prerequisites: User must be logged, purchase order index must exist in the list and purchase order status must be in 'PENDING' status.
-
Test case:
approve-po 2
Expected: Purchase order at index 2 will be approved. Details of the approved purchase order is shown in the status message. Timestamp in the status bar is updated. -
Test case:
approve-po asd sd/
Expected: No purchase order is approved. Error details shown in the status message. Status bar remains the same. -
Other incorrect approve-po commands to try:
approve-po
, `approve-po ,,,`_
Expected: Similar to previous.
-
-
Export the item list to csv file
-
Prerequisites: User must be logged in as an
admin
-
Test case:
export-csv-items f/items.csv
Expected: The item list is exported successfully to items.csv in the installed directory. -
Test case:
export-csv-items n/items.csv
Expected: The item list is not exported due to invalid prefix. Error details shown in the feedback. -
Test case:
export-csv-items f/items.xml
Expected: The item list is not exported due to invalid file format. Error details shown in the feedback.
-