diff --git a/build.gradle b/build.gradle
index b0c5528fb5..91fffd027d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -43,4 +43,5 @@ checkstyle {
run{
standardInput = System.in
+ enableAssertions = true
}
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 7e1ce222a9..e8297cd72e 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -185,7 +185,7 @@
-
+
diff --git a/data/order.txt b/data/order.txt
new file mode 100644
index 0000000000..f6c46e97fb
--- /dev/null
+++ b/data/order.txt
@@ -0,0 +1,7 @@
+1|PANADOL|100|09-10-2021|PENDING
+2|VICODIN|30|09-10-2021|PENDING
+3|VICODIN|50|10-10-2021|DELIVERED
+4|SIMVASTATIN|20|11-10-2021|PENDING
+5|LISINOPRIL|200|12-10-2021|PENDING
+6|AZITHROMYCIN|100|13-10-2021|PENDING
+7|PANADOL|50|13-10-2021|PENDING
diff --git a/data/order_archive.txt b/data/order_archive.txt
new file mode 100644
index 0000000000..e07b9103d9
--- /dev/null
+++ b/data/order_archive.txt
@@ -0,0 +1 @@
+[ORDER ID: 3] 50 VICODIN WAS ORDERED ON 10-10-2021. STATUS: DELIVERED
diff --git a/data/prescription.txt b/data/prescription.txt
new file mode 100644
index 0000000000..c3e0a4c3a6
--- /dev/null
+++ b/data/prescription.txt
@@ -0,0 +1,5 @@
+1|PANADOL|10|S1234567A|09-10-2021|Jane|1
+2|VICODIN|10|S2345678B|10-10-2021|Peter|3
+3|SIMVASTATIN|10|S1234567A|11-10-2021|Sam|4
+4|LISINOPRIL|10|S3456789C|12-10-2021|Jane|5
+5|AZITHROMYCIN|10|S2345678B|13-10-2021|Peter|6
diff --git a/data/prescription_archive.txt b/data/prescription_archive.txt
new file mode 100644
index 0000000000..b4f854314b
--- /dev/null
+++ b/data/prescription_archive.txt
@@ -0,0 +1,2 @@
+[PRESCRIPTION ID: 1] 10 PANADOL [STOCK ID: 1] WAS PRESCRIBED BY JANE TO S1234567A ON 09-10-2021
+[PRESCRIPTION ID: 2] 10 VICODIN [STOCK ID: 3] WAS PRESCRIBED BY PETER TO S2345678B ON 10-10-2021
diff --git a/data/stock.txt b/data/stock.txt
new file mode 100644
index 0000000000..95526f894a
--- /dev/null
+++ b/data/stock.txt
@@ -0,0 +1,6 @@
+1|PANADOL|20.0|20|13-09-2021|BEST MEDICINE TO CURE HEADACHES, FEVER AND PAINS|1000|false
+2|PANADOL|20.0|10|14-09-2021|BEST MEDICINE TO CURE HEADACHES, FEVER AND PAINS|1000|false
+3|VICODIN|10.0|20|30-09-2021|POPULAR DRUG FOR TREATING ACUTE OR CHRONIC MODERATE TO MODERATELY SEVERE PAIN|500|false
+4|SIMVASTATIN|20.0|25|10-10-2021|TREATS HIGH CHOLESTEROL AND REDUCES THE RISK OF STROKE|800|false
+5|LISINOPRIL|20.0|25|15-10-2021|USED FOR TREATING HYPOTHYROIDISM|800|false
+6|AZITHROMYCIN|20.0|35|15-10-2021|USED FOR TREATING EAR, THROAT, AND SINUS INFECTIONS|100|false
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 0f072953ea..24b0c160dd 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -2,8 +2,10 @@
Display | Name | Github Profile | Portfolio
--------|:----:|:--------------:|:---------:
-![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
-![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
-![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
-![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
-![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+![](https://via.placeholder.com/100.png?text=Photo) | Alvin Tan Guo Hao | [Github](https://github.com/alvintan01) | [Portfolio](team/alvintan01.md)
+![](https://via.placeholder.com/100.png?text=Photo) | Deon Chung Hui | [Github](https://github.com/deonchung) | [Portfolio](team/deonchung.md)
+![](https://via.placeholder.com/100.png?text=Photo) | Jiang Weichen | [Github](https://github.com/jiangweichen835) | [Portfolio](team/jiangweichen835.md)
+![](https://via.placeholder.com/100.png?text=Photo) | Teo Chin Kai Remus | [Github](https://github.com/RemusTeo) | [Portfolio](team/remusteo.md)
+![](https://via.placeholder.com/100.png?text=Photo) | Teo Phing Huei, Aeron | [Github](https://github.com/a-tph) | [Portfolio](team/a-tph.md)
+
+
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 64e1f0ed2b..b759d3fbe4 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,38 +1,708 @@
# Developer Guide
+## Introduction
+
+MediVault is a Command Line Interface (CLI) application that will help to manage medication supplies within a pharmacy.
+It is an integrated solution that provides real-time tracking of stocks, prescriptions and orders. The
+purpose of this guide is to help developers set up and continue with the development of MediVault past version 2.1.
+
## Acknowledgements
-{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+* Inspiration for App Idea and OOP Structure: [https://github.com/se-edu/addressbook-level2](https://github.com/se-edu/addressbook-level2)
+* Inspiration for User Guide: [https://se-education.org/addressbook-level3/UserGuide.html](https://se-education.org/addressbook-level3/UserGuide.html)
+* Inspiration for Developer Guide: [https://se-education.org/addressbook-level3/DeveloperGuide.html](https://se-education.org/addressbook-level3/DeveloperGuide.html)
+* PlantUML Tutorial: [https://se-education.org/guides/tutorials/plantUml.html](https://se-education.org/guides/tutorials/plantUml.html)
+* Gradle: [https://github.com/gradle/gradle](https://github.com/gradle/gradle)
+
+## Contents
+
+* [Glossary](#glossary)
+* [Setting up environment](#setting-up-environment)
+ * [Setting up](#setting-up)
+ * [Before writing code](#before-writing-code)
+* [Design](#design)
+ * [Architecture](#architecture)
+ * [Command](#command)
+ * [Utilities](#utilities)
+ * [Validator](#validator)
+ * [Storage](#storage)
+ * [Inventory](#inventory)
+ * [Errors](#errors)
+* [Implementation](#implementation)
+ * [Main Logic](#main-logic)
+ * [List Command](#list-command)
+ * [Stock Commands](#stock-commands)
+ * [AddStockCommand](#addstockcommand)
+ * [DeleteStockCommand](#deletestockcommand)
+ * [UpdateStockCommand](#updatestockcommand)
+ * [Prescription Commands](#prescription-commands)
+ * [AddPrescriptionCommand](#addprescriptioncommand)
+ * [DeletePrescriptionCommand](#deleteprescriptioncommand)
+ * [UpdatePrescriptionCommand](#updateprescriptioncommand)
+ * [Order Commands](#order-commands)
+ * [AddOrderCommand](#addordercommand)
+ * [DeleteOrderCommand](#deleteordercommand)
+ * [UpdateOrderCommand](#updateordercommand)
+ * [ReceiveOrderCommand](#receiveordercommand)
+ * [Archive Commands](#archive-commands)
+ * [ArchivePrescriptionCommand](#archiveprescriptioncommand)
+ * [ArchiveOrderCommand](#archiveordercommand)
+* [Product Scope](#product-scope)
+ * [Target User Profile](#target-user-profile)
+ * [Value Proposition](#value-proposition)
+* [User Stories](#user-stories)
+* [Non-Functional Requirements](#non-functional-requirements)
+* [Instructions for Manual Testing](#instructions-for-manual-testing)
+* [Instructions for Automated Testing](#instructions-for-automated-testing)
+
+## Glossary
+
+Terminology | Meaning
+------ | ------
+Stock | Refers to a medication.
+Prescription | Refers to a prescription.
+Order | Refers to ordering new medications to replenish the stocks.
+Parameters | Prefixes for MediVault to understand the type of information you provide.
+
+Meaning of Icons:
+- :information_source: Note
+- :warning: Warning
+- :bulb: Tip
+
+## Setting up environment
+
+### Setting up
+
+1. Fork [this](https://github.com/AY2122S1-CS2113T-T10-1/tp/) repo, and clone the fork into your computer.
+2. Ensure that you have [IntelliJ IDEA](https://www.jetbrains.com/idea/download/#section=windows)
+ and [JDK 11](https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html) installed.
+3. Configure the JDK
+ * Follow the guide
+ at [se-edu/guides IDEA: Configuring the JDK](https://se-education.org/guides/tutorials/intellijJdk.html) to ensure
+ Intellij is configured to use JDK 11.
+4. Import the project as a Gradle project
+ * Follow the
+ guide [se-edu/guides IDEA: Importing a Gradle project](https://se-education.org/guides/tutorials/intellijImportGradleProject.html)
+ to import the project into IDEA.
+ * Note: Importing a Gradle project is slightly different from importing a normal Java project.
+5. Verify the setup
+ * Locate the file `src/main/java/MediVault.java` then run the `MediVault.main()` and try a few commands
+ * Run the [test](https://se-education.org/addressbook-level3/Testing.html) to ensure they all pass.
+
+### Before writing code
+
+1. Configure the coding style
+ * If using IDEA, follow the
+ guide [se-edu/guides IDEA: Configuring the code style](https://se-education.org/guides/tutorials/intellijCodeStyle.html)
+ to set up IDEA’s coding style to match ours.
+2. Set up CI
+ * This project comes with a GitHub Actions config files (in `.github/workflows folder`). When GitHub detects those
+ files, it runs the CI for your project automatically at each push to the `master` branch or to any PR. No set
+ up required.
+
+## Design
+
+### Architecture
+
+The **Architecture Diagram** for MediVault is shown below.
+
+![ArchitectureDiagram](diagrams/diagram_images/ArchitectureDiagram.png)
+
+A quick overview of the main components and how they interact with each other is given below.
+
+The main class that runs MediVault is called `MediVault`. It is responsible for,
+* At program launch: Initializes the components in the correct sequence, and connects them up with each other.
+* At shut down: Shuts down the components and invokes cleanup methods where necessary.
+
+The rest of the program consist of four components.
+* `Command`: Executes command based on the user input that is processed by `Utilities`
+ component. The list of commands can be found in our User Guide [here](UserGuide.md).
+* `Utilities`: Contains important driver classes for MediVault.
+ * Includes `parser`, `ui`, `storage` and `comparators`.
+* `Inventory`: Contains a collection of classes used by MediVault to represent
+different medication information.
+* `Errors`: Contains collection of classes that handles exceptions during execution of MediVault.
+
+### Command
+
+![CommandClassDiagram](diagrams/diagram_images/CommandClassDiagram.png)
+
+The **Command** class diagram above shows how **Command** interact with other classes in MediVault.
+
+The Command Component consists of **18** subclasses where each subclass represents a command feature.
+
+Let `*` be either of the three class: `Stock`, `Prescription` or `Order`.
+
+* `Add*Command`: Adds a new `*` information into MediVault.
+* `Delete*Command`: Removes the visibility of the `*` record in MediVault.
+* `Update*Command`: Updates the `*` information.
+* `List*Command`: Lists the `*` records.
+* `ReceiveOrderCommand`: Marks an order as received and adds the ordered medication into the current stocks.
+* `ArchivePresciptionCommand`: Archives all the prescription records before a given date.
+* `ArchiveOrderCommand`: Archives all the order records before a given date.
+* `PurgeCommand`: Wipes all records in MediVault.
+* `HelpCommand`: Shows the help page.
+* `ExitCommand`: Exits MediVault.
+
+### Utilities
+
+#### Validator
+
+The class diagram below shows how the validator classes is implemented to help ensure that the user input is
+valid. `StockValidator`, `PrescriptionValidator` and `OrderValidator` inherits from `MedicineValidator`. The class
+methods are also shown in the diagram.
+
+![ValidatorClassDiagram](diagrams/diagram_images/ValidatorClassDiagram.png)
+
+#### Storage
+
+The `Storage` component of MediVault is implemented for purpose of loading, storing and archiving of data. Basically, it
+handles all file related processes necessary for MediVault to function. After every operation that modifies the stock,
+prescription or order, data is automatically and dynamically saved into the corresponding data files.
+
+`Storage` class is associated with `FileParser` class because during startup of MediVault, data is loaded,
+and validation is done with methods in FileParser.
+
+`FileParser` class handles validation of data of the files `data/stock.txt`, `data/prescription.txt` and
+`data/order.txt`. If it detects anything invalid, it throws an exception with specific information about which row
+and which file the invalid data is.
+
+> :information_source: Note:
+> * MediVault cannot start up until data in data files are deemed valid.
+> * This is to prevent invalid data from entering the system caused by direct tampering of data files.
+
+The class diagram below shows the Storage component of MediVault.
+
+![StorageClassDiagram](diagrams/diagram_images/StorageClassDiagram.png)
+
+### Inventory
+
+The class diagram below shows how the objects in MediVault is implemented. `Stock`, `Prescription`
+and `Order` inherits from the abstract `Medicine` class. The attributes that each object has is also shown in the
+diagram.
+
+![InventoryClassDiagram](diagrams/diagram_images/InventoryClassDiagram.png)
+
+### Errors
+
+- `InvalidCommandException` is thrown when the user enters an invalid command.
+- `InvalidDataException` is thrown when MediVault encountered invalid data in the data files.
+
+## Implementation
+
+### Main Logic
+
+The main application logic shows how the commands are handled throughout the application. Below is the outline of the
+logic:
+
+* MediVault is called by the `main` method which calls the constructor of MediVault. Data is then loaded from the
+ `Storage` class to the application.
+* MediVault gets the user input via the `Ui` class and uses the `CommandParser` class to parse the input given by the
+ user.
+* The parameters is parsed to a `LinkedHashMap` to make the parameters easily accessible.
+* If a valid command is received, the `CommandParser` calls the `Command` object constructor and return the object
+ to MediVault.
+* MediVault invokes the `execute()` function of the `Command` object to execute the command.
+
+> :warning: Warning:
+> * Should there be an invalid command, `CommandParser` throws `InvalidCommandException` and MediVault displays the error message using the `Ui` class.
+
+Given below is the sequence diagram after `run()` is called for the interactions within the main application logic.
+
+![MainLogicSequenceDiagram](diagrams/diagram_images/MainLogicSequenceDiagram.png)
+- `changeMode()` is called when the user entered `stock`, `prescription` or `order` to help change modes.
+- `processCommand()` helps to parse the user's command to a `Command` object.
+- `parseParameters()` returns all the parameters entered as a `LinkedHashmap`. This helps to make the
+parameters entered by the user easily accessible by the `Command` objects.
+
+After the `.execute()` command is called, MediVault does the following validator checks as shown below.
+
+![ContainValidParametersAndValuesSequenceDiagram](diagrams/diagram_images/ContainValidParametersAndValuesSequenceDiagram.png)
+
+> :information_source: Note: Replace `*` with `Stock`, `Prescription` or `Order` depending on the command entered.
+
+1. `*Command` attempts to get the instances of the `Ui` and `Medicine` classes which are a singletons if they exists.
+Otherwise, it creates a new instance of the `Ui` and/or `Medicine` class.
+2. `*Command` creates a new `*Validator` instance which contains the methods to validate the user's input for the
+respective `*`.
+3. `*Command` runs `containsInvalidParametersAndValues()` and does validation checks explained in detail in **Step 4**
+and **Step 5**.
+4. The `MedicineValidator` class runs `containsInvalidParameters()` to check if parameters input by the user are valid.
+5. Then, `MedicineValidator` class runs `containsInvalidParameterValues()` in `*Validator` to check if
+parameter values input by the user is valid.
+6. `MedicineValidator` returns the result of the validity checks back to `*Command`.
+7. After running the Logic for `*Command`, commands that modifies the `*` information attempts to get the instance of
+`Storage` class which is a singleton if it exists. MediVault runs `saveData()` to save the latest information into the text file.
+
+The motivation to implement an **initial validity checker** was because most of the commands requires MediVault to check
+if user input provided by the user are valid. This **guarantees** that the parameters and parameter values provided by
+the user are valid after it passes the validity checks.
+
+The logic for all the `*Command` are further elaborated below.
+
+### List Command
+
+There are three variations of the list command.
+
+1. `liststock`
+2. `listprescription`
+3. `listorders`
+
+The sequence diagram below shows how the `list` operation works in general.
+
+![ListSequenceDiagram](diagrams/diagram_images/ListSequenceDiagram.png)
+
+* All three variations of `list` are similar as they are implemented by iterating through the `Medicine` ArrayList and
+ filtering out the respective object types.
+* If the parameter `sort` or `rsort` is provided, the respective constructor of the `Comparator` classes is invoked
+ to help sort the ArrayList.
+* For the rest of the valid command parameters, MediVault does a **contains** comparison for strings and **equals**
+ comparison for integers as well as dates except for `expiring` and `low` parameters where it does a **less than or
+ equal** comparison.
+* `getAttributeValue()` represents all the get methods available in each of the respective classes. At the end of the
+ execution the respective `print()` method from the `Ui` class is called to display the respective tables.
+
+### Stock Commands
+
+#### AddStockCommand
+
+MediVault creates an `AddStockCommand` object when `CommandParser` identifies `addstock` or `add` in `stock`
+mode.
+> :information_source: Note:
+> * MediVault adds medicine stock when the `parameter` and `parameterValues` provided by the user are valid.
+> * Users cannot input medication if `max_quantity` is less than `quantity`.
+> * MediVault ignores the `price`, `description` and `max_quantity` of user input if the same medication name and expiry date already exist.
+> * MediVault ignores the `description` and `max_quantity` of user input if the same medication name already exist.
+
+The sequence diagram for `AddStockCommand` is shown below.
+
+![AddStockSequenceDiagram](diagrams/diagram_images/AddStockSequenceDiagram.png)
+
+MediVault determines if there exist the medication with the same name.
+* If there exist medication with the same name, MediVault checks if there exist the same expiry date using the `isExpiryExist()` method.
+ * MediVault then checks if the quantity is valid using the `isValidQuantity()` method.
+ * If the same name and expiry date exist, Medivault updates the quantity of the existing stock.
+ * If the same expiry date does not exist, MediVault adds the medication using the existing description and maximum quantity.
+* If the same medication does not exist in MediVault, MediVault then checks if the quantity is valid using the `isValidQuantity()` method and a new medication is added.
+
+#### DeleteStockCommand
+
+MediVault creates an `DeleteStockCommand` object when `CommandParser` identifies `deletestock` or the `delete` keyword
+in `stock` mode.
+
+* MediVault allows deletion of a stock by specifying stock id through `i/ID`.
+* MediVault allows deletion of expiring stocks by specifying an expiry date through `expiring/EXPIRY_DATE`.
+
+> :information_source: Note:
+> * MediVault deletes medicine stock information when `parameter` and `parameterValues` provided by the user are valid.
+> * MediVault performs a check to determine if it is executing deletion by stock id or deletion by expiry then executes
+ accordingly.
+> * MediVault does not execute if both id and expiry date are specified.
+> * MediVault does not actually delete the stock. Rather, it sets it as deleted and hide from user view. This is
+for the purpose of retaining stock information in case it is needed again in the future.
+> * For example, if a prescription was deleted, the information of the medicine is still intact even if the stock was deleted.
+
+The sequence diagram for `DeleteStockCommand` is shown below.
+
+![DeleteStockSequenceDiagram](diagrams/diagram_images/DeleteStockSequenceDiagram.png)
+
+If MediVault determines that it is executing deletion by stock id, it executes accordingly. Currently, it only
+allows for deletion of 1 stock at a time.
+
+The sequence diagram for deletion by stock id is shown below.
+
+![DeletionOfStockByIdSequenceDiagram](diagrams/diagram_images/DeletionOfStockByIdSequenceDiagram.png)
+
+* `deleteStockById()` helps to delete a stock given an id.
+ * Loops through all medicines to `getStockId()` to compare and get the specified stock.
+ * Then call `setDeleted()` to delete the stock.
+
+If MediVault determines that it is executing deletion by expiry date, it executes accordingly. The behaviour of
+this command is to delete all stock before or equals to the specified date. This is because we would want to delete all
+expired stock and if a date is specified, all the date before is also expired.
+
+The sequence diagram for delete by expiry date is shown below.
+
+![DeletionOfStockByIdSequenceDiagram](diagrams/diagram_images/DeletionOfStockByExpirySequenceDiagram.png)
+
+* `deleteStockByExpiry()` helps to delete stocks given an expiry date.
+ * `stringToDate()` helps to parse a string to a Date object.
+ * Loops through all medicines to `getExpiry()` to compare and get the all expired stock.
+ * Then calls `setDeleted()` to delete the stock.
+
+#### UpdateStockCommand
+
+MediVault creates an `UpdateStockCommand` object when `CommandParser` identifies `updatestock` or
+the `update` keyword in `stock` mode.
-## Design & implementation
+The sequence diagram for `UpdateStockCommand` is shown below.
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+![UpdateStockSequenceDiagram](diagrams/diagram_images/UpdateStockSequenceDiagram.png)
+MediVault retrieves the stock object using the `i/ID` parameter specified by the user using the `extractStockObject()`
+method. MediVault conducts another validation check on the provided `q/QUANTITY`,`m/MAX_QUANTITY` and `e/EXPIRY_DATE`
+against the stock object retrieved earlier. This validation check is separated from the initial validation checker
+as enforcing `q/QUANTITY <= m/MAX_QUANTITY` can only be done **after** MediVault confirms what user input is
+provided. This is because the backend processing for either one or both parameters provided by the user are different.
-## Product scope
-### Target user profile
+MediVault adds a new stock record when a user update contains the `n/NAME` parameter. The old stock record still
+exists in MediVault, but it is not visible to the user when listed. This approach solves the issue when a user is
+unable to delete a prescription record when the medicine stock name gets updated.
-{Describe the target user profile}
+### Prescription Commands
-### Value proposition
+#### AddPrescriptionCommand
-{Describe the value proposition: what problem does it solve?}
+MediVault creates an `AddPrescriptionCommand` object when `CommandParser` identifies `addprescription` or `add` in `prescription` mode.
+
+> :information_source: Note:
+> * MediVault adds the prescription when the `parameter` and `parameterValues` provided by the user are valid.
+> * MediVault updates the quantity left in the stock automatically after prescribing.
+> * MediVault prescribes medication with the earliest date if there are medication with multiple expiry dates.
+> * Users cannot prescribe expired medication.
+> * Users cannot prescribe medication if the quantity is more than the total stock quantity.
+
+The sequence diagram for `AddPrescriptionCommand` is shown below.
+
+![AddPrescriptionCommandDiagram](diagrams/diagram_images/AddPrescriptionSequenceDiagram.png)
+
+- `prescribe()` method changes the stock quantity based on prescription quantity and add prescribed medication to prescription list.
+
+#### DeletePrescriptionCommand
+
+MediVault creates a `DeletePrescriptionCommand` object when `CommandParser` identifies `deleteprescription` or
+`delete` in `prescription` mode.
+
+> :information_source: Note:
+> * MediVault deletes the prescription when the `parameter` and `parameterValues` provided by the user are valid.
+> * MediVault deletes the prescription based on the user input of `PRESCRIPTION_ID`.
+> * MediVault adds the prescription quantity to the stock quantity after successful deletion of prescription.
+> * Users cannot delete prescriptions if the total stock quantity after restoration is more than the maximum
+ quantity.
+> * If the stock is deleted, MediVault recovers the stock and add the prescription quantity to the stock.
+
+The sequence diagram for `DeletePrescriptionCommand` is shown below.
+
+![DeletePrescriptionCommandDiagram](diagrams/diagram_images/DeletePrescriptionSequenceDiagram.png)
+
+- `setStockQuantity()` method helps to check if a stock exists. If the stock exists, it adds the prescribed quantity to the current stock quantity.
+- `isValidPrescriptionParameters()` helps to ensure that the parameters for the prescription to be deleted are valid.
+
+#### UpdatePrescriptionCommand
+
+MediVault initialises an `UpdatePrescriptionCommand` class when `CommandParser` identifies
+`updateprescription` or the `update` keyword in `prescription` mode.
+
+The sequence diagram for `UpdatePrescriptionCommand` is shown below.
+
+![UpdatePrescriptionSequenceDiagram](diagrams/diagram_images/UpdatePrescriptionSequenceDiagram.png)
+
+MediVault retrieves the prescription object using the `i/ID` parameter specified by the user using the
+`extractPrescriptionObject()` method.
+
+The main update logic is split into four sections.
+1. User provided both `n/NAME` and `q/QUANTITY` parameters.
+ 1. MediVault restores the stock quantity for the **original** `n/NAME` with the **original** `q/QUANTITY`.
+ 2. MediVault decrements the stock quantity for the **updated** `n/NAME` with the **updated** `q/QUANTITY`.
+2. User provided `n/NAME` parameter but not `q/QUANTITY`.
+ 1. MediVault restores the stock quantity for the **original** `n/NAME` with the `q/QUANTITY` present in the
+ prescription object.
+ 2. MediVault decrements the stock quantity for the **updated** `n/NAME` with the `q/QUANTITY` present in the
+ prescription object.
+3. User provided `q/QUANTITY` parameter but not `n/NAME`
+ 1. If the **updated** `q/QUANTITY` is more than the **original** `q/QUANTITY` MediVault decrements the stock quantity
+ for `n/NAME` present in the prescription object with the additional `q/QUANTITY` which is the difference between the
+ **updated** and **original** `q/QUANTITY`.
+ 2. Otherwise, MediVault restores the stock quantity for `n/NAME` present in the prescription object with the
+ difference between the **updated** and **original** `q/QUANTITY`.
+4. User did not provide both `q/QUANTITY` and `n/NAME` parameter.
+ 1. Restoring or decrement is not needed.
+
+Other parameters like `d/DATE`, `c/CUSTOMER_ID` and `s/STAFF` are not affected because they share the same
+update logic for sections 1 to 4 mentioned above.
+
+MediVault adds a new prescription record when a user updates contains either the `n/NAME`, `q/QUANTITY`
+parameter or both. The old prescription record is **permanently removed** from MediVault.
+
+This approach solves the issue when a medication is prescribed to a user with an amount that is
+**more than** the current batch of stock with the same Stock ID but **less than** the total
+stock quantity.
+
+> :information_source: Note: MediVault automatically adds new prescription records when a medication is prescribed
+> from stocks with different Stock IDs.
+
+### Order Commands
+
+#### AddOrderCommand
+
+MediVault creates an `AddOrderCommand` object when `CommandParser` identifies `addorder` or the `add` keyword
+in `order` mode.
+
+> :information_source: Note:
+> * MediVault adds order information when `parameter` and `parameterValues` provided by the user are valid.
+> * As the order date is an optional parameter, MediVault uses the date the order was placed as the default date.
+> * Users cannot add orders if the order quantity exceeds maximum stock quantity.
+
+The sequence diagram for `AddOrderCommand` is shown below.
+
+![AddOrderCommandDiagram](diagrams/diagram_images/AddOrderSequenceDiagram.png)
+
+`addDate()` method adds the order date based on whether the user provided the date parameter or not.
+
+`addOrder()` method adds the order based on user input.
+
+MediVault determines if there exist the medication with the same name in order and in stock.
+
+* If there exist medication with the same name in order and in stock, MediVault checks if the `orderQuantity +
+existingStockQuantity + existingOrderQuantity <= maxQuantity` to ensure total order quantity does not exceed the
+existing maximum stock quantity allowed.
+* If there exist medication with the same name in order but not in stock, MediVault checks if the `orderQuantity
+< maxQuantity`, where `maxQuantity = Integer.MAX_VALUE` to allow the user to add any quantity of medication.
+* If there does not exist medication with the same name in order but exist in stock, MediVault checks if the
+`orderQuantity < existingStockQuantity` to ensure total order quantity does not exceed the existing maximum stock
+quantity allowed.
+* If there does not exist medication with the same name in order and in stock, MediVault does not check for valid quantity and simply add the order as a new order.
+
+#### DeleteOrderCommand
+
+MediVault creates a `DeleteOrderCommand` object when `CommandParser` identifies `deleteorder` or `delete` in `order`
+mode.
+
+> :information_source: Note:
+> * MediVault deletes the order when the `parameter` and `parameterValues` provided by the user are valid.
+
+The sequence diagram for `DeleteOrderCommand` is shown below.
+
+![DeleteOrderCommandDiagram](diagrams/diagram_images/DeleteOrderSequenceDiagram.png)
+
+- `isValidOrderParameters()` helps to ensure that the parameters for the order to be deleted are valid.
+
+#### UpdateOrderCommand
+
+MediVault creates an `UpdateOrderCommand` object when `CommandParser` identifies
+`updateorder` or the `update` keyword in `order` mode.
+
+The sequence diagram for `UpdateOrderCommand` is shown below.
+
+![UpdateOrderSequenceDiagram](diagrams/diagram_images/UpdateOrderSequenceDiagram.png)
+
+MediVault retrieves the order object using the `i/ID` parameter specified by the user using the
+`extractOrderObject()` method.
+
+> :warning: Warning:
+> * MediVault disables updating an order that has been delivered. Users can only update information for pending orders.
+
+MediVault conducts a check if an order quantity is valid with the provided `q/QUANTITY`.
+This validation check is separated from the initial validation checker as enforcing `q/QUANTITY <= m/MAX_QUANTITY` in
+stocks can only be done **after** MediVault confirms that the user provides a `q/QUANTITY` is an integer.
+
+MediVault updates the order information only when all of the validation checks stated above are successful.
+
+#### ReceiveOrderCommand
+
+MediVault creates an `ReceiveOrderCommand` object when `CommandParser` identifies
+`receiveorder` or the `receive` keyword in `order` mode.
+
+> :information_source: Note:
+> * MediVault adds the order to stock if the `parameters` and `parameterValues` provided by the user are valid.
+> * `ReceiveOrderCommand` calls `AddStockCommand` once the `parameters` and `parameterValues` are validated.
+> * If the order contains a medication already in stock, the `d/DESCRIPTION` and `m/MAX_QUANTITY` are ignored
+> and existing values are used.
+> * If the `e/EXPIRY_DATE` provided is the same as the one in stock, `p/PRICE` is ignored as well.
+
+The sequence diagram for `ReceiveOrderCommand` is shown below.
+
+![ReceiveOrderSequenceDiagram](diagrams/diagram_images/ReceiveOrderSequenceDiagram.png)
+
+- `isStockParametersValid()` helps to ensure that the parameters for the stock to be added are valid.
+- `checkStockExist()` helps to check if a medication exists in stock.
+
+MediVault then checks if the quantity increased before setting the order as completed. This helps to ensure that
+only after the stock is successfully added, then the order would be complete.
+
+### Archive Commands
+
+#### ArchivePrescriptionCommand
+
+MediVault creates an `ArchivePrescriptionCommand` object when `CommandParser` identifies `archiveprescription` or the
+`archive` keyword in `prescription` mode.
+
+* MediVault archives prescription records by specifying a date through `d/DATE`.
+* MediVault removes prescription records that have date before or equals to the specified date and output it into
+the file named `data/prescription_archive.txt`
+
+> :information_source: Note:
+> * MediVault archive prescription information when `parameter` and `parameterValues` provided by the user are valid.
+> * MediVault outputs the prescription information into a user readable format in `data/prescription_archive.txt`.
+> * To modify the format, edit the code in `toArchiveFormat()` method in the Prescription Class.
+
+The sequence diagram for ArchivePrescriptionCommand is shown below.
+
+![ArchivePrescriptionSequenceDiagram](diagrams/diagram_images/ArchivePrescriptionSequenceDiagram.png)
+
+* `stringToDate()` helps to parse a string to a Date object.
+* `prescriptionsToArchive()` checks through all prescriptions and look for records that have prescription date before or
+equals to the specified date.
+* `removeFromPrescriptions()` removes prescriptions from prescription list after archive.
+
+#### ArchiveOrderCommand
+
+MediVault creates an `ArchiveOrderCommand` object when `CommandParser` identifies `archiveorder` or the
+`archive` keyword in `order` mode.
+
+* MediVault archives order records by specifying a date through `d/DATE`.
+* MediVault removes only DELIVERED order records that have date before or equals to the specified date and output it
+into the file named `data/order_archive.txt`
+
+> :information_source: Note:
+> * MediVault archive order information when `parameter` and `parameterValues` provided by the user are valid.
+> * MediVault outputs the order information into a user readable format in `data/order_archive.txt`.
+> * To modify the format, edit the code in `toArchiveFormat()` method in the Order Class.
+
+The sequence diagram for ArchiveOrderCommand is shown below.
+
+![ArchiveOrderSequenceDiagram](diagrams/diagram_images/ArchiveOrderSequenceDiagram.png)
+
+* `stringToDate()` helps to parse a string to a Date object.
+* `ordersToArchive()` checks through all orders and look for records that are DELIVERED and have order date
+before or equals to the specified date.
+* `removeFromOrders()` removes orders from order list after archive.
+
+## Product Scope
+
+### Target User Profile
+
+* Handles storing, ordering and prescribing of medication.
+* Has a need to manage large number of stocks in the pharmacy.
+* May forget how much medicine stock is left in the pharmacy.
+* Is a fast typist.
+
+### Value Proposition
+
+The main value proposition of MediVault is such that it provides the user with an interface for efficient stock taking
+purposes. It eradicates the need for manual tracking of medications which greatly lessen the administrative
+workload of a pharmacist. It automates stock taking process to a certain extent because it is a 3 in 1 integrated
+solution that provides real-time tracking of stock, prescriptions and orders in a pharmacy.
## User Stories
|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|
-|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list|
+|v1.0|pharmacist|list out all of the medicines currently on shelf| know the current quantity of the medicines on shelf
+|v1.0|manager| purge all data|start afresh
+|v1.0|user| exit the program|shutdown my computer
+|v1.0|pharmacist|list the price of each medication|know the price of each medication
+|v1.0|pharmacist|sort medication by price|recommend the customer the cheapest one if he asks
+|v1.0|pharmacist| update medication information| modify information using a single command instead of deleting and adding the updated medication information
+|v1.0|pharmacist|update the limit of a medication|have enough stocks in the event that I foresee a surge in demand
+|v1.0|pharmacist|add new types of medicines| keep track of all the medication supplies on 1 platform
+|v1.0|pharmacist|delete a medicine|remove it from the system in the event of a product recall or end of production
+|v1.0|pharmacist|search for medication for specific symptoms|give the right medication
+|v1.0|pharmacist|set a limit on the number of medications to be added to the stocks|prevent an oversupply of medication
+|v1.0|user|search for a specific medication|look for a medication without looking through the full list
+|v2.0|pharmacist|check which medication is expiring soon|order a new batch of supplies in time for my patients
+|v2.0|pharmacist| check which medication is low in quantity| order a new batch of supplies in time for my patients
+|v2.0|pharmacist|confirm a received order|know if an order is successfully received
+|v2.0|manager|create orders|order medication.
+|v2.0|pharmacist|archive past prescription records|prevent records from being cluttered
+|v2.0|pharmacist| archive past order records|prevent records from being cluttered
+|v2.0|pharmacist| list all orders|keep track of them
+|v2.0|pharmacist|know the status of order| know whether the supply is ordered or received.
+|v2.0|pharmacist|saved record of the current medicine stock| have a saved file record to refer to
+|v2.0|pharmacist|saved record of the current medicine orders| have a saved file record to refer to
+|v2.0|manager|saved record of the current medicine prescription| have a saved file record to refer to
+|v2.0|pharmacist|prescribe medication|tally the number of medications when I prescribed some to my patients
+|v2.0|pharmacist|delete prescription| delete a prescription record
+|v2.0|manager|delete orders|cancel orders
+|v2.0|pharmacist| update prescription information| modify information using a single command instead of deleting and adding the updated prescription information
+|v2.0|pharmacist|delete ALL expired medications|expired medications will not be sold to customers or patients
+|v2.0|manager|edit orders| update any wrong information
+|v2.0|manager|see the pending orders to reflect in my current stocks|ensure that I won't double order on the same medication
+|v2.0|pharmacist|search for records by a specific customer|see all his prescriptions
+|v2.0|manager|check who prescribe what medication|know who is responsible for the prescription
## Non-Functional Requirements
-{Give non-functional requirements}
+* **Accessibility Requirements:** MediVault should be able to run locally without internet connection.
+* **Capacity Requirements:** MediVault should try to store only important details to minimize data file size as there may be
+many data records after long usage. Perhaps could save into multiple files or archive data.
+* **Compliance with regulations requirements:** MediVault should comply with regulations related to storing of sensitive
+customer information.
+* **Documentation Requirements:** MediVault user guide should be documented in a way that a pharmacist without CLI
+experience can understand and learn how to use the application.
+* **Efficiency Requirements:** MediVault should make use of efficient data structures and algorithms where appropriate to
+optimise speed if possible. However, it is not really a top priority.
+* **Extensibility Requirements:** MediVault should minimally manage medications. In the future can probably expand inventory
+to handle medical supplies in general.
+* **Fault Tolerance Requirements:** MediVault should perform sufficient error handling and provide helpful error response
+messages to suggest correct input to user.
+* **Interoperability Requirements:** MediVault should be able to run on minimally Windows, Linux and macOS.
+* **Privacy Requirements:** MediVault may contain sensitive information such as customer health records. Thus, we should not
+publish our data to the internet and only store it on our local computer.
+* **Portability Requirements:** MediVault should be able to run on any computer that has Java 11 and `MediVault.jar`. Data
+should also be portable such that we can easily transfer data when changing computers.
+* **Reliability Requirements:** MediVault should not crash at any point in time. Even if it does, it must retain data.
+* **Response Time Requirements:** MediVault basic operations should respond within 3 seconds. For other processing heavy
+operations such as start up and loading of data, it should respond within maximum of 15 seconds.
+* **Robustness Requirements:** MediVault should have some had some testing done be it JUnit Tests or automated I/O
+redirection tests.
+* **Scalability Requirements:** MediVault should be built to handle amount of data a small to medium enterprise would have.
+* **Stability Requirements:** MediVault should function as per normal regardless of how many error user has made.
+* **User Requirements:** MediVault should be user-friendly such that it is usable by a pharmacist with no CLI experience.
-## Glossary
-* *glossary item* - Definition
+## Instructions for Manual Testing
+
+### Starting up and Shutting Down
+
+1. Download the latest release [here](https://github.com/AY2122S1-CS2113T-T10-1/tp/releases).
+2. Run MediVault using `java -jar MediVault.jar`
+3. To end program, enter the command `exit`.
+
+### Running commands
+
+1. You can refer to the list of commands and expected
+ outputs [here](https://ay2122s1-cs2113t-t10-1.github.io/tp/UserGuide.html).
+
+### Saving Data
+
+All data files are located in the `data` folder.
+
+1. Data is saved in `stock.txt`, `prescription.txt`, `order.txt`.
+ * Test Case:
+ 1. Run the application.
+ 2. Add an entry to stock, prescription and order into MediVault.
+ 3. Exit MediVault. The `stock.txt`, `prescription.txt` and `order.txt` will have one entry.
+ 4. Run the application.
+ 5. Delete entry to stock, prescription and order into MediVault.
+ 6. Exit MediVault.
+ * Expected: `stock.txt`, `prescription.txt` and `order.txt` will be empty.
+2. Archive data is saved in `order_archive.txt` and `prescription_archive.txt`.
+ * Test Case:
+ 1. Run the application.
+ 2. Add entries to prescription and order into MediVault.
+ 3. Run the `archiveorder` and `archiveprescription` command with date specified.
+ 4. Exit MediVault.
+ * Expected: `order_archive.txt` and `prescription_archive.txt` will have entries.
+
+## Instructions for Automated Testing
+
+### Gradle Build Tests
+
+MediVault uses Gradle for Continuous Integration during development. Gradle performs automated checking of
+coding style which helps in ensuring adherence to Java Coding Standards. Gradle also helps to automate testing by running
+our JUnit test cases to ensure that MediVault is bug-free based on our testing and is working as intended. It is helpful
+in catching unintended bugs while we continuously develop MediVault.
+
+### JUnit Tests
-## Instructions for manual testing
+> :bulb: Tip
+> * **Equivalence Partitions:** Create Effective and Efficient Test Cases by considering Equivalence Partitions
+> * **Boundary Value Analysis:** Focus on testing Boundary Values
-{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
+To contribute and develop JUnit Test Cases:
+1. Locate `tp/src/test/java/` folder.
+2. Decide which aspect of MediVault you will be creating JUnit Tests for.
+ * Command, Parsers, Validators, etc.
+3. Start coding JUnit Test Cases in the appropriate files.
+ * Aim to create both Positive and Negative test cases.
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..28f96d1518 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,8 +1,10 @@
-# Duke
+# MediVault
-{Give product intro here}
+MediVault is a Command Line Interface (CLI) application that will help to manage medication supplies within a pharmacy.
+It is an integrated solution that provides real-time tracking of stocks, prescriptions and orders.
Useful links:
+
* [User Guide](UserGuide.md)
* [Developer Guide](DeveloperGuide.md)
* [About Us](AboutUs.md)
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..91aeec3fc9 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -2,41 +2,1018 @@
## Introduction
-{Give a product intro}
+MediVault is a Command Line Interface (CLI) application that will help to manage medication supplies within a pharmacy.
+It is an integrated solution that provides real-time tracking of stocks, prescriptions and orders.
-## Quick Start
+## Contents
-{Give steps to get started quickly}
+* [Purpose](#purpose)
+* [Glossary](#glossary)
+* [Quick Start](#quick-start)
+ * [Setting up](#setting-up)
+ * [Changing modes](#changing-modes)
+* [Features](#features)
+ * [Managing Stocks](#managing-stocks)
+ * [Adding stocks](#adding-stocks-addstock)
+ * [Listing stocks](#listing-medication-stocks-liststock)
+ * [Updating stocks](#updating-stocks-updatestock)
+ * [Deleting stocks](#deleting-a-medication-stock-deletestock)
+ * [Managing Prescriptions](#managing-prescriptions)
+ * [Adding prescriptions](#adding-prescriptions-addprescription)
+ * [Listing prescriptions](#listing-prescriptions-listprescription)
+ * [Updating prescriptions](#updating-prescriptions-updateprescription)
+ * [Deleting prescriptions](#deleting-prescriptions-deleteprescription)
+ * [Managing Orders](#managing-orders)
+ * [Adding orders](#adding-an-order-addorder)
+ * [Listing orders](#listing-orders-listorder)
+ * [Updating orders](#updating-orders-updateorder)
+ * [Deleting orders](#deleting-an-order-deleteorder)
+ * [Receiving orders](#receiving-orders-receiveorder)
+ * [Managing Data](#managing-data)
+ * [Archive orders](#archive-orders-archiveorder)
+ * [Archive prescriptions](#archive-prescriptions-archiveprescription)
+ * [Purge data](#purging-existing-data--purge)
+ * [Miscellaneous](#miscellaneous)
+ * [Help](#showing-help-page--help)
+ * [Exit](#exiting-medivault--exit)
+* [Data Handling](#data-handling)
+ * [Data Storage](#data-storage)
+ * [Data Editing](#data-editing)
+* [FAQ](#faq)
+* [Command Summary](#command-summary)
-1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
+# Purpose
-## Features
+The purpose of this user guide is for users to have a more detailed understanding and reference to usage of commands in
+MediVault. In this user guide, you can expect to find examples and expected outputs of each command. MediVault caters
+for normal users and advanced users so you can expect to find information about how to efficiently use the commands or
+make use of the mode switching capabilities for convenience.
-{Give detailed description of each feature}
+As a pharmacist, you would probably focus more on the sections related to stock and prescriptions. As a manager of the
+pharmacy, you may be more interested in the order and data management sections of the user guide.
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+# Glossary
-Format: `todo n/TODO_NAME d/DEADLINE`
+Terminology | Meaning
+------ | ------
+Stock | Refers to a medication.
+Prescription | Refers to a prescription.
+Order | Refers to ordering new medications to replenish the stocks.
+Parameters | Prefixes for MediVault to understand the type of information you provide. Parameters must be specified with a `/`. For example `list sort/n` is considered a valid parameter whereas `list sort` is not a valid parameter.
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
+Meaning of Icons:
+- :information_source: Note
+- :warning: Warning
+- :bulb: Tip
-Example of usage:
+# Quick Start
-`todo n/Write the rest of the User Guide d/next week`
+### Setting up
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
+1. Ensure that you have **Java 11** or above installed.
+2. Download the latest version of `MediVault.jar`
+ from [here](https://github.com/AY2122S1-CS2113T-T10-1/tp/releases/download/v2.1/MediVault.jar).
+3. Copy the file to the folder you want to use as the **home** folder for `MediVault`.
+4. In the terminal, run `java -jar MediVault.jar`.
+5. You should see the following prompt if the program has started successfully.
+
+```
+| \/ | | |(_)| | | | | || |
+| . . | ___ __| | _ | | | | __ _ _ _ | || |_
+| |\/| | / _ \ / _` || || | | | / _` || | | || || __|
+| | | || __/| (_| || |\ \_/ /| (_| || |_| || || |_
+\_| |_/ \___| \__,_||_| \___/ \__,_| \__,_||_| \__|
+Welcome to MediVault!
+[STOCK] >
+```
+> :bulb: Tip: MediVault is best used when the window is maximised to ensure that all tables are rendered correctly.
+
+
+### Changing Modes
+
+> :bulb: Tip: Advanced users can choose to omit mode selection to get things done faster.
+
+MediVault includes a mode feature to make the commands simpler for you. Your current mode is indicated in the square
+brackets on the bottom left of the console `[STOCK] >`. It allows you to type `add`, `list`, `update`, `delete` without
+typing in the full command. Additionally, you can type `archive` in both `prescription` and `order` mode and `receive`
+in `order` mode. For example, when you are in `order` mode, typing `list` is equivalent to `listorder`.
+
+Type `stock`, `prescription` or `order` to change to the respective modes.
+
+Example (Current mode is Stock):
+
+Expected Output:
+
+```
+[STOCK] > listorder
++====+=========+==========+============+=========+
+| ID | NAME | QUANTITY | DATE | STATUS |
++====+=========+==========+============+=========+
+| 1 | PANADOL | 100 | 09-10-2021 | PENDING |
++----+---------+----------+------------+---------+
+| 2 | VICODIN | 30 | 09-10-2021 | PENDING |
++----+---------+----------+------------+---------+
+[STOCK] > order
+Mode has changed to ORDER.
+[ORDER] > list
++====+=========+==========+============+=========+
+| ID | NAME | QUANTITY | DATE | STATUS |
++====+=========+==========+============+=========+
+| 1 | PANADOL | 100 | 09-10-2021 | PENDING |
++----+---------+----------+------------+---------+
+| 2 | VICODIN | 30 | 09-10-2021 | PENDING |
++----+---------+----------+------------+---------+
+```
+
+# Features
+
+> :information_source: Notes about the commands:
+>
+> You can refer to [Glossary](#glossary) to understand technical terms mentioned below.
+> * Parameters enclosed in `[]` should contain **one or more** optional parameters.
+> * Parameters enclosed in `{}` are **totally** optional parameters.
+> * Parameters enclosed in `()` are **conditional** optional parameters. For `addstock` and `receiveorder`, parameters
+> `d/DESCRIPTION` and `m/MAX_QUANTITY` will be optional only if the stock exists.
+> * Parameters you specify can be in any order.
+> * E.g. `update i/1 q/100 m/200` and `update i/1 m/200 q/100` are both acceptable.
+> * MediVault ignores additional parameters provided when commands do not require one.
+> * If you specify the same parameter multiple times, MediVault will accept the last occurrence.
+> * E.g. `delete i/2 i/1`, MediVault interprets the command as `delete i/1`.
+> * MediVault also ignores all extra values that are not provided in parameters.
+> * E.g. `list abc123 i/1`, MediVault interprets the command as `list i/1`.
+> * MediVault's commands are case-insensitive.
+> * Dates in the `d/DATE` and `e/EXPIRY_DATE` field are in `DD-MM-YYYY` format.
+> * Column names in the `sort` parameter can be provided as the full column name or the column alias.
+> * E.g. `NAME` is equivalent to `n` and `QUANTITY` is equivalent to `q`.
+> * For the `list` commands, use the `sort` parameter to sort by a column in ascending order and `rsort` parameter to
+> sort in descending order.
+> * For the `delete` commands, ID will not reset after deletion as stock ID, order ID and prescription ID are unique so that MediVault
+> can identify each stock, order and prescription entry uniquely.
+> * `/` is not allowed to be entered for all input parameters, as MediVault uses it to identity the parameters.
+
+## Managing Stocks
+
+### Adding stocks: `addstock`
+
+Adds medication into the inventory.
+
+> :warning: Warning:
+> * If medication exists, description and maximum quantity will be optional parameters. If you include `d/DESCRIPTION` or `m/MAX_QUANTITY` parameter, it will be ignored and MediVault will add the medication with the existing description and existing maximum quantity.
+> * If medication and expiry date exists, price, description and maximum quantity will be optional parameters. If you include `p/PRICE` or `d/DESCRIPTION` or `m/MAX_QUANTITY` parameter, it will be ignored and MediVault will add the medication with the existing price, existing description and existing maximum quantity.
+
+> :information_source: Note:
+> * Description will be standardised in the stock so that it will be easier for users to search for medication by the symptoms.
+> * Users will be able to search for medication by symptoms using the list command as shown below.
+> * Expiry date is compulsory so that user will be able to track the expiry date for all medication.
+> * Users will be able to view all the expired medication or expiring medication easily using the list command as shown below.
+> * Medication with same name but different expiry date will be added into MediVault in different rows. This will allow users to have different prices for different expiry dates.
+> * Users might want to set a discount price for expiring medication.
+
+Format: `addstock n/NAME p/PRICE q/QUANTITY e/EXPIRY_DATE (d/DESCRIPTION m/MAX_QUANTITY)`
+
+Example 1 (If medication exists): `addstock n/panadol p/5 q/50 e/19-09-2025`
+
+Expected Output 1:
+
+```
+Medicine exists. Using existing description and maximum quantity.
+Medication added: PANADOL
++====+=========+=======+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+=======+==========+=============+=============+==============+
+| 7 | PANADOL | $5.00 | 50 | 19-09-2025 | HEADACHES | 1000 |
++----+---------+-------+----------+-------------+-------------+--------------+
+```
+
+Example 2 (If medication and expiry date exists): `addstock n/panadol q/50 e/19-09-2025`
+
+Expected Output 2:
+
+```
+Same Medication and Expiry Date exist. Using existing price, description and
+maximum quantity. Updating existing quantity.
++====+=========+=======+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+=======+==========+=============+=============+==============+
+| 8 | PANADOL | $5.00 | 100 | 19-09-2025 | HEADACHES | 1000 |
++----+---------+-------+----------+-------------+-------------+--------------+
+```
+
+Example 3 (If medication does not exist): `addstock n/paracetamol q/10 p/10 e/02-11-2021 d/fever m/500`
+
+Expected Output 3:
+
+```
+Medication added: PARACETAMOL
++====+=============+========+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=============+========+==========+=============+=============+==============+
+| 9 | PARACETAMOL | $10.00 | 10 | 02-11-2021 | FEVER | 500 |
++----+-------------+--------+----------+-------------+-------------+--------------+
+```
+
+### Listing medication stocks: `liststock`
+
+Lists all existing medications in the inventory.
+
+* All parameters for `liststock` command are optional, you can choose to list medication by any of the parameters.
+* You are able to `liststock` by any column and sort or reverse sort them.
+* When you update an order information, MediVault reflects the pending stocks shown here.
+* The total pending quantity will be shown if there are orders for a medication.
+* `low/LESS_THAN_OR_EQUAL_QUANTITY` and `expiring/LESS_THAN_OR_EQUAL_EXPIRY_DATE` parameters can be used to search for
+stocks with low **total** remaining quantity and expiring stocks respectively.
+
+Format: `liststock {i/ID n/NAME p/PRICE q/QUANTITY low/LESS_THAN_OR_EQUAL_QUANTITY e/EXPIRY_DATE expiring/LESS_THAN_OR_EQUAL_EXPIRY_DATE d/DESCRIPTION m/MAX_QUANTITY sort/COLUMN_NAME rsort/COLUMN_NAME}`
+
+Example 1 (Listing all medications): `liststock`
+
+Expected Output 1:
+
+```
++====+============+========+==========+=============+================+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+============+========+==========+=============+================+==============+
+| 1 | PANADOL | $20.00 | 20 | 13-09-2021 | HEADACHES | 1000 |
++----+------------+--------+----------+-------------+----------------+--------------+
+| 2 | PANADOL | $20.00 | 10 | 14-09-2021 | HEADACHES | 1000 |
++----+------------+--------+----------+-------------+----------------+--------------+
+| 3 | VICODIN | $10.00 | 20 | 30-09-2021 | SEVERE PAIN | 500 |
++----+------------+--------+----------+-------------+----------------+--------------+
+| 4 | LISINOPRIL | $20.00 | 25 | 15-10-2021 | HYPOTHYROIDISM | 800 |
++----+------------+--------+----------+-------------+----------------+--------------+
+```
+
+Example 2 (Filter by name): `liststock n/panadol`
+
+Expected Output 2:
+
+```
++====+=========+========+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+========+==========+=============+=============+==============+
+| 1 | PANADOL | $20.00 | 20 | 13-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 2 | PANADOL | $20.00 | 10 | 14-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+```
+
+### Updating stocks: `updatestock`
+
+Updates existing medication stock information in the inventory.
+
+> :warning: Warning:
+> * The Stock ID must exist in MediVault.
+> * You cannot update the Stock ID.
+> * The allocation of Stock ID is determined by MediVault.
+> * If you include the `n/NAME`, `d/DESCRIPTION` or `m/MAX_QUANTITY` parameter, MediVault updates **all** entries that
+has same existing medication name given the `i/ID` with your input values for these parameters.
+
+> :information_source: Note:
+> * A new Stock ID will be assigned to the current stock if your update has the `n/NAME` parameter.
+> * When you update the `n/NAME` parameter, there may be an existing prescription record that is present.
+> * By allocating a new Stock ID to the updated stock record, MediVault preserves the name of the old record so that
+when you delete a prescription record, it is **guaranteed** to automatically update the quantity of the stock.
+
+Format: `updatestock i/ID [n/NAME p/PRICE q/QUANTITY e/EXPIRY_DATE d/DESCRIPTION m/MAX_QUANTITY]`
+
+Initial stock records:
+
+```
++====+=========+========+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+========+==========+=============+=============+==============+
+| 1 | PANADOL | $20.00 | 20 | 13-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 2 | PANADOL | $20.00 | 10 | 14-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 3 | VICODIN | $10.00 | 20 | 30-09-2021 | SEVERE PAIN | 500 |
++----+---------+--------+----------+-------------+-------------+--------------+
+```
+
+> :information_source: Note:
+> * Examples stated below are **independent** from each other.
+
+Example 1 (Updating with medication name present):
+`update i/3 n/amoxil p/20 q/50 e/01-12-2021 d/body infections m/100`
+
+Expected Output 1:
+
+```
+Updated! Number of rows affected: 1
+Stock Id changed from:
+3 -> 4
++====+========+========+==========+=============+=================+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+========+========+==========+=============+=================+==============+
+| 4 | AMOXIL | $20.00 | 50 | 01-12-2021 | BODY INFECTIONS | 100 |
++----+--------+--------+----------+-------------+-----------------+--------------+
+```
+
+Example 2 (Updating only price and description):
+`update i/1 p/30 d/fever`
+
+Expected Output 2:
+
+```
+Updated! Number of rows affected: 2
++====+=========+========+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+========+==========+=============+=============+==============+
+| 1 | PANADOL | $30.00 | 20 | 13-09-2021 | FEVER | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 2 | PANADOL | $20.00 | 10 | 14-09-2021 | FEVER | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+```
+
+### Deleting a medication stock: `deletestock`
+
+If you made a mistake and want to delete a medication from the inventory, you may do so by using this command.
+
+* Able to delete a specific stock by specifying Stock ID using `i/ID`.
+* Able to delete multiple stocks that have expiry date before and equals to specified date using `expiring/EXPIRY_DATE`.
+
+Format: `deletestock [i/ID expiring/EXPIRY_DATE]`
+
+Example 1 (Deletion by Stock ID): `deletestock i/3`
+
+Expected Output 1:
+
+```
+Deleted row with Stock Id: 3
+```
+
+Example 2 (Deletion by expiry date): `deletestock expiring/10-10-2021`
+
+Expected Output 2:
+
+```
+Deleted expired medications! Rows deleted: 4
+```
+
+## Managing Prescriptions
+
+### Adding prescriptions: `addprescription`
+
+Adds a prescription record and subtracts the medication quantity from stocks.
+
+> :information_source: Note:
+> * MediVault will prescribe the medication with the shortest expiry date first.
+If the remaining quantity of the current batch of medication is insufficient, the next batch of medication will be used to supplement the prescription.
+> * MediVault will add another entry to prescription even if the medication name, customer's ID, date and staff name is exactly the same.
+This is so that MediVault can track all entries.
+> * If users want to increase the quantity of medication prescribed, users can use `updateprescription` command instead.
+> * MediVault will set the prescription date as today's date.
+
+
+Format: `addprescription n/NAME q/QUANTITY s/STAFF c/CUSTOMER_ID`
+
+Example: `addprescription n/panadol q/5 s/john c/123`
+
+Expected Output:
+
+```
+Prescribed:PANADOL Quantity:5 Expiry Date:14-09-2021
++====+=========+==========+=============+============+=======+==========+
+| ID | NAME | QUANTITY | CUSTOMER_ID | DATE | STAFF | STOCK_ID |
++====+=========+==========+=============+============+=======+==========+
+| 9 | PANADOL | 5 | 123 | 26-10-2021 | JOHN | 2 |
++----+---------+----------+-------------+------------+-------+----------+
+```
+
+### Listing prescriptions: `listprescription`
+
+Lists all prescription records in the application.
+
+* All parameters for `listprescription` command are optional, you can choose to list the records by any of the
+ parameters.
+* You are able to `listprescription` by any column and sort or reverse sort them.
+
+Format: `listprescription {i/ID n/NAME q/QUANTITY c/CUSTOMER_ID d/DATE s/STAFF_NAME sid/STOCK_ID sort/COLUMN_NAME rsort/COLUMN_NAME}`
+
+Example 1 (Listing all prescriptions): `listprescription`
+
+Expected Output 1:
+
+```
++====+==============+==========+=============+============+=======+==========+
+| ID | NAME | QUANTITY | CUSTOMER_ID | DATE | STAFF | STOCK_ID |
++====+==============+==========+=============+============+=======+==========+
+| 1 | PANADOL | 10 | S1234567A | 09-10-2021 | JANE | 1 |
++----+--------------+----------+-------------+------------+-------+----------+
+| 2 | VICODIN | 10 | S2345678B | 10-10-2021 | PETER | 3 |
++----+--------------+----------+-------------+------------+-------+----------+
+| 3 | SIMVASTATIN | 10 | S1234567A | 11-10-2021 | SAM | 4 |
++----+--------------+----------+-------------+------------+-------+----------+
+| 4 | LISINOPRIL | 10 | S3456789C | 12-10-2021 | JANE | 5 |
++----+--------------+----------+-------------+------------+-------+----------+
+| 5 | AZITHROMYCIN | 10 | S2345678B | 13-10-2021 | PETER | 6 |
++----+--------------+----------+-------------+------------+-------+----------+
+```
+
+Example 2 (Listing prescriptions sorted by staff): `listprescription sort/s`
+
+Expected Output 2:
+
+```
++====+==============+==========+=============+============+=======+==========+
+| ID | NAME | QUANTITY | CUSTOMER_ID | DATE | STAFF | STOCK_ID |
++====+==============+==========+=============+============+=======+==========+
+| 1 | PANADOL | 10 | S1234567A | 09-10-2021 | JANE | 1 |
++----+--------------+----------+-------------+------------+-------+----------+
+| 4 | LISINOPRIL | 10 | S3456789C | 12-10-2021 | JANE | 5 |
++----+--------------+----------+-------------+------------+-------+----------+
+| 2 | VICODIN | 10 | S2345678B | 10-10-2021 | PETER | 3 |
++----+--------------+----------+-------------+------------+-------+----------+
+| 5 | AZITHROMYCIN | 10 | S2345678B | 13-10-2021 | PETER | 6 |
++----+--------------+----------+-------------+------------+-------+----------+
+| 3 | SIMVASTATIN | 10 | S1234567A | 11-10-2021 | SAM | 4 |
++----+--------------+----------+-------------+------------+-------+----------+
+```
+
+### Updating prescriptions: `updateprescription`
+
+Updates an existing prescription information.
+
+> :warning: Warning:
+> * You **cannot** update the Stock or the Prescription ID.
+> * The allocation of Prescription ID is determined by MediVault.
+> * Your provided `n/NAME` parameter **must** exist in stocks.
+> * When you update a prescription record, the stock information may be affected as well.
+> * MediVault does not combine prescription information even if the column information are the same.
+> * You **cannot** update an existing prescription information with 0 quantity. You must use the `deleteprescription`
+command instead.
+> * You **cannot** update the prescription date with a date after today.
+
+> :information_source: Note:
+> * MediVault allocates a **new** Prescription ID when you update prescription records containing the `n/NAME` and
+`q/QUANTITY` parameter.
+> * This is because MediVault deletes the old prescription record and adds the updated prescription record as a **new**
+prescription record.
+
+Format: `updateprescription i/ID [n/NAME q/QUANTITY c/CUSTOMER_ID d/DATE s/STAFF_NAME]`
+
+Initial stock records:
+
+```
++====+=========+========+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+========+==========+=============+=============+==============+
+| 1 | PANADOL | $20.00 | 20 | 13-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 2 | PANADOL | $20.00 | 10 | 14-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 3 | VICODIN | $10.00 | 20 | 30-09-2021 | SEVERE PAIN | 500 |
++----+---------+--------+----------+-------------+-------------+--------------+
+```
+
+Initial prescription records:
+
+```
++====+=========+==========+=============+============+=======+==========+
+| ID | NAME | QUANTITY | CUSTOMER_ID | DATE | STAFF | STOCK_ID |
++====+=========+==========+=============+============+=======+==========+
+| 1 | PANADOL | 10 | S1234567A | 09-10-2021 | JANE | 1 |
++----+---------+----------+-------------+------------+-------+----------+
+| 2 | VICODIN | 10 | S2345678B | 10-10-2021 | PETER | 3 |
++----+---------+----------+-------------+------------+-------+----------+
+```
+
+> :information_source: Note:
+> * Examples stated below are **independent** from each other.
+
+Example 1 (Update prescribed quantity):
+`updateprescription i/1 q/5`
+
+Expected Output 1:
+
+```
+Restored 5 PANADOL
+Updated prescription information!
++====+=========+==========+=============+============+=======+==========+
+| ID | NAME | QUANTITY | CUSTOMER_ID | DATE | STAFF | STOCK_ID |
++====+=========+==========+=============+============+=======+==========+
+| 3 | PANADOL | 5 | S1234567A | 09-10-2021 | JANE | 1 |
++----+---------+----------+-------------+------------+-------+----------+
+```
+
+Updated stock record for Example 1:
+
+```
++====+=========+========+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+========+==========+=============+=============+==============+
+| 1 | PANADOL | $20.00 | 25 | 13-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 2 | PANADOL | $20.00 | 10 | 14-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 3 | VICODIN | $10.00 | 20 | 30-09-2021 | SEVERE PAIN | 500 |
++----+---------+--------+----------+-------------+-------------+--------------+
+```
+
+Example 2 (Update staff who prescribed the medication):
+`updateprescription i/1 s/jack`
+
+Expected Output 2:
+
+```
+Updated prescription information!
++====+=========+==========+=============+============+=======+==========+
+| ID | NAME | QUANTITY | CUSTOMER_ID | DATE | STAFF | STOCK_ID |
++====+=========+==========+=============+============+=======+==========+
+| 1 | PANADOL | 10 | S1234567A | 09-10-2021 | JACK | 1 |
++----+---------+----------+-------------+------------+-------+----------+
+```
+
+### Deleting prescriptions: `deleteprescription`
+
+If you made a mistake and want to delete a prescription record you may do so by using this command along with a specific
+Prescription ID.
+
+> :information_source: Note:
+> * Users will not be able to delete a prescription if deleting the prescription will lead to stock quantity exceeding the maximum quantity.
+
+Format: `deleteprescription i/PRESCRIPTION_ID`
+
+Example: `deleteprescription i/3`
+
+Expected Output:
+
+```
+Prescription deleted for Prescription ID 3
+```
+
+## Managing Orders
+
+### Adding an order: `addorder`
+
+Adds an order for a stock.
+
+> :information_source: Note:
+> * The date parameter is optional, MediVault will set it as the date you added in the order if the parameter is omitted.
+> * If the order quantity exceeds the maximum stock quantity allowed, you are unable to add the order.
+> * You **cannot** add an order date with a date after today.
+
+Format: `addorder n/NAME q/QUANTITY {d/DATE}`
+
+Initial stock records:
+```
++====+=========+========+==========+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+========+==========+=============+=============+==============+
+| 1 | PANADOL | $20.00 | 20 | 13-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+| 2 | PANADOL | $20.00 | 10 | 14-09-2021 | HEADACHES | 1000 |
++----+---------+--------+----------+-------------+-------------+--------------+
+```
+
+Example 1 (add order with date parameter): `addorder n/panadol q/150 d/21-10-2021`
+
+Expected Output 1:
+
+```
+Order added: PANADOL
++====+=========+==========+============+=========+
+| ID | NAME | QUANTITY | DATE | STATUS |
++====+=========+==========+============+=========+
+| 1 | PANADOL | 150 | 21-10-2021 | PENDING |
++----+---------+----------+------------+---------+
+```
+
+Example 2 (add order without date parameter): `addorder n/panadol q/100`
+> :information_source: Note:
+> This example was done on 5 Nov 2021.
+
+Expected Output 2:
+
+```
+Order added: PANADOL
++====+=========+==========+============+=========+
+| ID | NAME | QUANTITY | DATE | STATUS |
++====+=========+==========+============+=========+
+| 2 | PANADOL | 100 | 05-11-2021 | PENDING |
++----+---------+----------+------------+---------+
+```
+
+Example 3 (add order quantity exceeds maximum stock quantity allowed): `addorder n/panadol q/1000`
+
+Expected Output 3:
+```
+Unable to add order as total order quantity exceeds maximum stock quantity of 1000.
+Existing quantity in stock: 30
+Pending order quantity: 250
+```
+
+### Listing orders: `listorder`
+
+Lists all order records in the application.
+
+* All parameters for `listorder` command are optional, you can choose to list the records by any of the parameters.
+* You are able to `listorder` by any column and sort or reverse sort them.
+
+Format: `listorder {i/ID n/NAME q/QUANTITY d/DATE s/STATUS sort/COLUMN_NAME rsort/COLUMN_NAME}`
+
+Example 1 (List all orders): `listorder`
+
+Expected Output 1:
+
+```
++====+==============+==========+============+===========+
+| ID | NAME | QUANTITY | DATE | STATUS |
++====+==============+==========+============+===========+
+| 1 | PANADOL | 100 | 09-10-2021 | PENDING |
++----+--------------+----------+------------+-----------+
+| 2 | VICODIN | 30 | 09-10-2021 | PENDING |
++----+--------------+----------+------------+-----------+
+| 3 | VICODIN | 50 | 10-10-2021 | DELIVERED |
++----+--------------+----------+------------+-----------+
+| 4 | SIMVASTATIN | 20 | 11-10-2021 | PENDING |
++----+--------------+----------+------------+-----------+
+| 5 | LISINOPRIL | 200 | 12-10-2021 | PENDING |
++----+--------------+----------+------------+-----------+
+| 6 | AZITHROMYCIN | 100 | 13-10-2021 | PENDING |
++----+--------------+----------+------------+-----------+
+| 7 | PANADOL | 50 | 13-10-2021 | PENDING |
++----+--------------+----------+------------+-----------+
+```
+
+Example 2 (List pending orders): `listorder s/pending`
+
+Expected Output 2:
+
+```
++====+==============+==========+============+=========+
+| ID | NAME | QUANTITY | DATE | STATUS |
++====+==============+==========+============+=========+
+| 1 | PANADOL | 100 | 09-10-2021 | PENDING |
++----+--------------+----------+------------+---------+
+| 2 | VICODIN | 30 | 09-10-2021 | PENDING |
++----+--------------+----------+------------+---------+
+| 4 | SIMVASTATIN | 20 | 11-10-2021 | PENDING |
++----+--------------+----------+------------+---------+
+| 5 | LISINOPRIL | 200 | 12-10-2021 | PENDING |
++----+--------------+----------+------------+---------+
+| 6 | AZITHROMYCIN | 100 | 13-10-2021 | PENDING |
++----+--------------+----------+------------+---------+
+| 7 | PANADOL | 50 | 13-10-2021 | PENDING |
++----+--------------+----------+------------+---------+
+```
+
+### Updating orders: `updateorder`
+
+Updates an existing order information.
+
+> :warning: Warning:
+> * You cannot update the Order ID or the status of the order.
+> * The allocation of Order ID is determined by MediVault.
+> * The status of the order will only be changed when you run the `receiveorder` command.
+> * MediVault does not combine orders even if the column information are the same.
+> * You **cannot** update the order date with a date after today.
+
+Format: `updateorder i/ID [n/NAME q/QUANTITY d/DATE]`
+
+Initial order records:
+
+```
++====+=========+==========+============+===========+
+| ID | NAME | QUANTITY | DATE | STATUS |
++====+=========+==========+============+===========+
+| 1 | PANADOL | 100 | 09-10-2021 | PENDING |
++----+---------+----------+------------+-----------+
+```
+
+Example: `updateorder i/1 q/50 d/10-10-2021`
+
+Expected Output:
+
+```
+Updated! Number of rows affected: 1
++====+=========+==========+============+=========+
+| ID | NAME | QUANTITY | DATE | STATUS |
++====+=========+==========+============+=========+
+| 1 | PANADOL | 50 | 10-10-2021 | PENDING |
++----+---------+----------+------------+---------+
+```
+
+### Deleting an order: `deleteorder`
+
+If you made a mistake and want to delete an order, you may do so by using this command along with a specific Order ID.
+
+Format: `deleteorder i/ORDER_ID`
+
+Example: `deleteorder i/1`
+
+Expected Output:
+
+```
+Order deleted for Order ID 1
+```
+
+### Receiving orders: `receiveorder`
+
+Adds the medication you ordered into the current stocks.
+
+> :information_source: Note:
+> * Your input Order ID must exist.
+> * When you run `receiveorder` with the required parameters, the medication you ordered will be automatically added into your current stocks.
+> * The `e/EXPIRY_DATE` parameter is required so that MediVault knows the expiry date of the stock that just arrived.
+> * The `p/PRICE` parameter is also required so that stocks with different remaining shelf life can have different prices.
+
+> :warning: Warning:
+> * If medication exists, `d/DESCRIPTION` and `m/MAX_QUANTITY` will be optional parameters. If you include `d/DESCRIPTION` or `m/MAX_QUANTITY` parameter, it will be ignored and MediVault will add the medication with the existing description and existing maximum quantity in stocks.
+> * If medication exists, the medication to be added has the same `e/EXPIRY_DATE`, the value in the `p/PRICE` parameter will be ignored and the existing price will be used.
+> * You may not be able to `receiveorder` if the order `quantity + current stock quantity > max quantity`.
+
+Format: `receiveorder i/ID p/PRICE e/EXPIRY_DATE (d/DESCRIPTION m/MAX_QUANTITY)`
+
+Example 1 (If medication does not exist) : `receiveorder i/1 p/10 e/20-10-2021 d/severe pain m/500`
+
+Expected Output 1:
+
+```
+Medication added: VICODIN
++====+=========+========+=============+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+========+=============+=============+=============+==============+
+| 3 | VICODIN | $10.00 | 100 | 20-10-2021 | SEVERE PAIN | 500 |
++----+---------+--------+-------------+-------------+-------------+--------------+
+```
+
+Example 2 (If medication exists) : `receiveorder i/2 p/20 e/25-10-2021`
+
+Expected Output 2:
+
+```
+Same Medication and Expiry Date exist. Using existing price, description and
+maximum quantity. Updating existing quantity.
++====+=========+========+==============+=============+=============+==============+
+| ID | NAME | PRICE | QUANTITY | EXPIRY_DATE | DESCRIPTION | MAX_QUANTITY |
++====+=========+========+==============+=============+=============+==============+
+| 1 | PANADOL | $20.00 | 100 | 25-10-2021 | HEADACHE | 1000 |
++----+---------+--------+--------------+-------------+-------------+--------------+
+```
+
+## Managing Data
+
+This section of the user guide explains the features and usage of commands related to data management. This includes the
+archive commands, purge command as well as data storage files related information.
+
+### Archive orders: `archiveorder`
+
+Archive order records into data/order_archive.txt file.
+
+> :information_source: Note:
+> * MediVault will remove all order records that have status of DELIVERED from the current orders that matches the user specified date and before.
+> * MediVault will then archive it into data/order_archive.txt file.
+> * The date parameter is compulsory.
+
+> :warning: Warning:
+> * This is a one way command, there is no reversal except for you to manually add the archived records back into MediVault.
+
+Format: `archiveorder d/DATE`
+
+Example: `archiveorder d/10-10-2021`
+
+Expected Output:
+
+```
+Archived 2 delivered orders from 10-10-2021
+```
+
+Expected Output (in data/order_archive.txt):
+
+```
+[ORDER ID: 2] 10 PANADOL WAS ORDERED ON 09-10-2021. STATUS: DELIVERED
+[ORDER ID: 3] 50 VICODIN WAS ORDERED ON 10-10-2021. STATUS: DELIVERED
+```
+
+### Archive prescriptions: `archiveprescription`
+
+Archive prescription records into data/prescription_archive.txt file.
+
+> :information_source: Note:
+> * MediVault will remove all prescription records from the current prescriptions that matches the user specified date and before.
+> * MediVault will then archive it into data/prescription_archive.txt file.
+> * The date parameter for this command is compulsory.
+
+> :warning: Warning:
+> * This is a one way command, there is no reversal except for you to manually add the archived records back into MediVault.
+
+Format: `archiveprescription d/DATE`
+
+Example: `archiveprescription d/10-10-2021`
+
+Expected Output:
+
+```
+Archived 2 prescriptions from 10-10-2021
+```
+
+Expected Output (in data/prescription_archive.txt):
+
+```
+[PRESCRIPTION ID: 1] 1 AXID [STOCK ID: 8] WAS PRESCRIBED BY CJ TO S1234567A ON 09-10-2021
+[PRESCRIPTION ID: 2] 1 AZOR [STOCK ID: 9] WAS PRESCRIBED BY AJ TO S2345678B ON 10-10-2021
+```
+
+### Purging existing data : `purge`
+
+Should you want to clear all data in MediVault, you can use the `purge` command.
+
+Format: `purge`
+
+Example: `purge`
+
+Expected Output:
+
+```
+Are you sure you want to delete all data? (Y/N)
+Y
+All data has been cleared!
+```
+
+## Miscellaneous
+
+### Showing help page : `help`
+
+Should you require assistance on how to use MediVault, you can use the `help` command.
+
+Format:`help`
+
+Example: `help`
+
+Expected Output:
+
+```
+Welcome to the help page.
+Your current mode is indicated in the square brackets at the bottom left of the console.
+It allows you to type add, list, update, delete without typing in the full command.
+Additionally, you can type archive in both prescription and order mode and receive in
+order mode.
+Type stock, prescription or order to change to respective modes.
+Note that parameters in {curly braces} are optional.
+Parameters in [square braces] indicate that at least one of the parameter(s) must be
+provided.
+Parameters enclosed in (round brackets) are conditional optional parameters.
+For example, the parameters d/DESCRIPTION and m/MAX_QUANTITY in addstock and
+receiveorder will be optional only if the stock exists.
++=====================+====================================================+
+| COMMAND | COMMAND SYNTAX |
++=====================+====================================================+
+| addstock | addstock n/NAME p/PRICE q/QUANTITY e/EXPIRY_DATE |
+| | (d/DESCRIPTION m/MAX_QUANTITY) |
++---------------------+----------------------------------------------------+
+| deletestock | deletestock [i/ID expiring/EXPIRY_DATE] |
++---------------------+----------------------------------------------------+
+| updatestock | updatestock i/ID [n/NAME p/PRICE q/QUANTITY |
+| | e/EXPIRY_DATE d/DESCRIPTION m/MAX_QUANTITY] |
++---------------------+----------------------------------------------------+
+| liststock | liststock {i/ID n/NAME p/PRICE |
+| | q/QUANTITYlow/LESS_THAN_OR_EQUAL_QUANTITY |
+| | e/EXPIRY_DATE |
+| | expiring/LESS_THAN_OR_EQUAL_EXPIRY_DATE |
+| | d/DESCRIPTION m/MAX_QUANTITY sort/COLUMN_NAME |
+| | rsort/COLUMN_NAME} |
++---------------------+----------------------------------------------------+
+| addprescription | addprescription n/NAME q/QUANTITY c/CUSTOMER_ID |
+| | s/STAFF_NAME |
++---------------------+----------------------------------------------------+
+| deleteprescription | deleteprescription i/ID |
++---------------------+----------------------------------------------------+
+| updateprescription | updateprescription i/ID [n/NAME q/QUANTITY |
+| | c/CUSTOMER_ID d/DATE s/STAFF_NAME] |
++---------------------+----------------------------------------------------+
+| listprescription | listprescription {i/ID n/NAME q/QUANTITY |
+| | c/CUSTOMER_ID d/DATE s/STAFF_NAME sid/STOCK_ID |
+| | sort/COLUMN_NAME rsort/COLUMN_NAME} |
++---------------------+----------------------------------------------------+
+| archiveprescription | archiveprescription d/DATE |
++---------------------+----------------------------------------------------+
+| addorder | addorder n/NAME q/QUANTITY {d/DATE} |
++---------------------+----------------------------------------------------+
+| deleteorder | deleteorder i/ID |
++---------------------+----------------------------------------------------+
+| updateorder | updateorder i/ID [n/NAME q/QUANTITY d/DATE] |
++---------------------+----------------------------------------------------+
+| listorder | listorder {i/ID n/NAME q/QUANTITY d/DATE |
+| | s/STATUS sort/COLUMN_NAME rsort/COLUMN_NAME} |
++---------------------+----------------------------------------------------+
+| archiveorder | archiveorder d/DATE |
++---------------------+----------------------------------------------------+
+| receiveorder | receiveorder i/ID p/PRICE e/EXPIRY_DATE |
+| | (d/DESCRIPTION m/MAX_QUANTITY) |
++---------------------+----------------------------------------------------+
+| purge | purge |
++---------------------+----------------------------------------------------+
+| help | help |
++---------------------+----------------------------------------------------+
+| exit | exit |
++---------------------+----------------------------------------------------+
+For more information, refer to User Guide: https://ay2122s1-cs2113t-t10-1.github.io/tp/
+ ```
+
+### Exiting MediVault : `exit`
+
+Should you want to quit the program, you can use the `exit` command.
+
+Format: `exit`
+
+Example: `exit`
+
+Expected Output:
+
+```
+Quitting MediVault...
+```
+
+## Data Handling
+
+### Data Storage
+
+MediVault will automatically save your data after any operation that modifies stock, order or prescriptions. The data
+will be stored in 3 separate files `data/stock.txt`, `data/order.txt` and `data/prescription.txt`. Data is saved in a
+specific format with fields delimited by a pipe `|`.
+
+Data formats:
+
+* For `data/stock.txt`:
+ * `ID|NAME|PRICE|QUANTITY|EXPIRY_DATE|DESCRIPTION|MAX_QUANTITY|ISDELETED`
+* For `data/order.txt`:
+ * `ID|NAME|QUANTITY|DATE|STATUS`
+* For `data/prescription.txt`:
+ * `ID|NAME|QUANTITY|CUSTOMER_ID|DATE|STAFF|STOCK_ID`
+
+### Data Editing
+
+> :warning: Warning:
+> * It is possible for you to directly edit the data files, but it is **NOT** recommended unless you know exactly what you are doing because you risk corrupting it.
+> * If MediVault detects corruption or invalid data, you will **NOT** be able to start MediVault.
+> * In order for MediVault to work, you have to fix the error in the data file.
+> * Invalid data detected by MediVault will be highlighted on launch to hint you in the direction to fix it.
+> * In the worst case scenario where you are unable to fix it, you may have to delete the corresponding data file.
+> * It may result in **unintended behaviour** if data file is tampered with while the program is running.
+> * Editing the data directly poses a significant risk to corruption of data and may lead to **unintended behaviour**.
## FAQ
-**Q**: How do I transfer my data to another computer?
+**Q**: How do I transfer my data to another computer?
-**A**: {your answer here}
+**A**: You can transfer data to another computer by moving the `data` folder containing the 3 data files to where `MediVault.jar` is.
+You should expect to see `stock.txt`, `order.txt`, `prescription.txt` in that folder.
-## Command Summary
+**Q**: Can MediVault run on a Raspberry Pi?
+
+**A**: Yes, MediVault does not require a lot of processing power and only requires any computer capable of running **Java 11**.
-{Give a 'cheat sheet' of commands here}
+**Q**: How do I transfer my data from Excel to MediVault?
+
+**A**:
+- For Stocks:
+ - First, order the columns of your Excel sheet in the following order.
+ - `ID|NAME|PRICE|QUANTITY|EXPIRY_DATE|DESCRIPTION|MAX_QUANTITY|ISDELETED`
+ - Next, copy and paste the following command into Excel at the first row and on the right of last column of your data **(Cell I2)**.
+ - `=UPPER(CONCAT(A2,"|",B2,"|",C2,"|",D2,"|",TEXT(E2, "dd-mm-yyyy"),"|",F2,"|",G2,"|",H2))`
+ - Then, double-click on the square box at the bottom right of the cell so that the formula will be calculated for all rows.
+ - Finally, copy and paste the all entries in column **I** into `data/stock.txt`.
+- For Orders:
+ - First, order the columns of your Excel sheet in the following order.
+ - `ID|NAME|QUANTITY|DATE|STATUS`
+ - Next, copy and paste the following command into Excel at the first row and on the right of last column of your data **(Cell F2)**.
+ - `=UPPER(CONCAT(A2,"|",B2,"|",C2,"|",TEXT(D2, "dd-mm-yyyy"),"|",E2))`
+ - Then, double-click on the square box at the bottom right of the cell so that the formula will be calculated for all rows.
+ - Finally, copy and paste the all entries in column **F** into `data/order.txt`.
+- For Prescriptions:
+ - First, order the columns of your Excel sheet in the following order.
+ - `ID|NAME|QUANTITY|CUSTOMER_ID|DATE|STAFF|STOCK_ID`
+ - Next, copy and paste the following command into Excel at the first row and on the right of last column of your data **(Cell H2)**.
+ - `=UPPER(CONCAT(A2,"|",B2,"|",C2,"|",D2,"|",TEXT(E2, "dd-mm-yyyy"),"|",F2,"|",G2))`
+ - Then, double-click on the square box at the bottom right of the cell so that the formula will be calculated for all rows.
+ - Finally, copy and paste the all entries in column **H** into `data/prescription.txt`.
+
+**Q**: How secure is MediVault since it stores customer's information?
+
+**A**: MediVault does not require internet access and runs locally on the computer. For better security, do not connect
+the computer to the internet and ensure that the computer is password locked and only give authorised staff access.
+
+
+## Command Summary
-* Add todo `todo n/TODO_NAME d/DEADLINE`
+Command | Command Syntax
+------ | ------
+addstock | `addstock n/NAME p/PRICE q/QUANTITY e/EXPIRY_DATE (d/DESCRIPTION m/MAX_QUANTITY)`
+deletestock | `deletestock [i/ID expiring/DATE]`
+updatestock | `updatestock i/ID [n/NAME p/PRICE q/QUANTITY e/EXPIRY_DATE d/DESCRIPTION m/MAX_QUANTITY]`
+liststock | `liststock {i/ID n/NAME p/PRICE q/QUANTITY low/LESS_THAN_OR_EQUAL_QUANTITY e/EXPIRY_DATE expiring/LESS_THAN_OR_EQUAL_EXPIRY_DATE d/DESCRIPTION m/MAX_QUANTITY sort/COLUMN_NAME rsort/COLUMN_NAME}`
+addprescription | `addprescription n/NAME q/QUANTITY c/CUSTOMER_ID s/STAFF_NAME`
+deleteprescription | `deleteprescription i/ID`
+updateprescription | `updateprescription i/ID [n/NAME q/QUANTITY c/CUSTOMER_ID d/DATE s/STAFF_NAME]`
+listprescription | `listprescription {i/ID n/NAME q/QUANTITY c/CUSTOMER_ID d/DATE s/STAFF_NAME sid/STOCK_ID sort/COLUMN_NAME rsort/COLUMN_NAME}`
+archiveprescription | `archiveprescription d/DATE`
+addorder | `addorder n/NAME q/QUANTITY {d/DATE}`
+deleteorder | `deleteorder i/ID`
+updateorder | `updateorder i/ID [n/NAME q/QUANTITY d/DATE]`
+listorder | `listorder {i/ID n/NAME q/QUANTITY d/DATE s/STATUS sort/COLUMN_NAME rsort/COLUMN_NAME}`
+archiveorder | `archiveorder d/DATE`
+receiveorder | `receiveorder i/ID p/PRICE e/EXPIRY_DATE (d/DESCRIPTION m/MAX_QUANTITY)`
+purge | `no parameters`
+help | `no parameters`
+exit | `no parameters`
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..059155b857
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,3 @@
+theme: jekyll-theme-cayman
+gems:
+ - jemoji
diff --git a/docs/diagrams/AddOrderSequenceDiagram.puml b/docs/diagrams/AddOrderSequenceDiagram.puml
new file mode 100644
index 0000000000..f18d2e6602
--- /dev/null
+++ b/docs/diagrams/AddOrderSequenceDiagram.puml
@@ -0,0 +1,56 @@
+@startuml AddOrderSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":AddOrderCommand" as addorder COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:Ui" as ui COLOR_UTILITIES
+ participant ":OrderManager" as ordermanager COLOR_UTILITIES
+ participant ":StockManager" as stockmanager COLOR_UTILITIES
+end box
+
+autoactivate on
+mainFrame sd Logic for AddOrderCommand
+activate addorder
+alt orderQuantity != 0
+ alt nameExistsInOrder && !nameExistsInStock
+ alt orderQuantity < maxQuantity
+ addorder -> addorder : addDate(dateToAdd)
+ addorder --> addorder
+ addorder -> addorder : addOrder(ui: Ui, medicines: ArrayList, name: String, \nquantity: int, date: Date)
+ addorder --> addorder
+ else !orderQuantity < maxQuantity
+ addorder -> ui : print()
+ addorder <-- ui
+ end
+ else nameExistsInOrder && nameExistsInStock
+ addorder -> ordermanager : getTotalOrderQuantity()
+ addorder <-- ordermanager : TotalOrderQuantity
+ addorder -> stockmanager : getTotalStockQuantity()
+ addorder <-- stockmanager : TotalStockQuantity
+ addorder -> stockmanager : getMaxStockQuantity()
+ addorder <-- stockmanager : MaxStockQuantity
+ alt orderQuantity + totalExistingQuantity <= maxQuantity
+ addorder -> addorder : addDate(dateToAdd)
+ addorder --> addorder
+ addorder -> addorder : addOrder(ui: Ui, medicines: ArrayList, name: String, \nquantity: int, date: Date)
+ addorder --> addorder
+ else !orderQuantity + totalExistingQuantity <= maxQuantity
+ addorder -> ui : print()
+ addorder <-- ui
+ end
+ note right
+ This diagram shows the process for
+ adding order when medicine exist in
+ orders.
+ It does not include the process by
+ which medicine does not exist in
+ orders.
+ end note
+end
+deactivate addorder
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/AddPrescriptionSequenceDiagram.puml b/docs/diagrams/AddPrescriptionSequenceDiagram.puml
new file mode 100644
index 0000000000..f4c81206e1
--- /dev/null
+++ b/docs/diagrams/AddPrescriptionSequenceDiagram.puml
@@ -0,0 +1,64 @@
+@startuml AddPrescriptionSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":AddPrescriptionCommand" as addprescription COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:PrescriptionManager" as prescriptionManager COLOR_UTILITIES
+ participant "<>\n:StockManager" as stockManager COLOR_UTILITIES
+ participant ":StockComparator" as stockcomparator COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant ":Stock" as stock COLOR_INVENTORY
+end box
+
+autoactivate on
+mainframe sd AddPrescriptionCommand
+activate addprescription
+ addprescription -> stockManager: getFilteredStocksByName(medicines: ArrayList, stockName: String)
+ addprescription <-- stockManager: filteredStocks
+ create stockcomparator
+ addprescription -> stockcomparator : new StockComparator()
+ addprescription <-- stockcomparator : filteredStocks
+
+ addprescription -> prescriptionManager: getNotExpiredStockQuantity(medicines: ArrayList, \nname: String, prescribeDate: Date)
+ addprescription <-- prescriptionManager: totalStock
+
+
+
+ deactivate stockcomparator
+ addprescription -> addprescription : checkExpiredMedication(ui: Ui, filteredStocks: ArrayList, \nprescriptionQuantity: int)
+
+ loop stock : filteredStocks
+ opt existingExpiry.after(prescribeDate) || prescribeDateString.equals(expiryString)
+ opt existingQuantity == quantityToPrescribe
+ addprescription -> addprescription : prescribe(ui: Ui, medicines: ArrayList, medicationName: String, \ncustomerId: String, staffName: String, quantityToPrescribe: int, prescribeDate: Date, \nstock: Stock, existingId: int, existingExpiry: Date, setStockValue: int)
+ addprescription -> stock : setQuantity()
+ addprescription <-- stock
+ addprescription --> addprescription
+ end
+
+ opt existingQuantity > quantityToPrescribe
+ addprescription -> addprescription : prescribe(ui: Ui, medicines: ArrayList, medicationName: String, \ncustomerId: String, staffName: String, quantityToPrescribe: int, prescribeDate: Date, \nstock: Stock, existingId: int, existingExpiry: Date, setStockValue: int)
+ addprescription -> stock : setQuantity()
+ addprescription <-- stock
+ addprescription --> addprescription
+ end
+ opt existingQuantity < quantityToPrescribe
+ addprescription -> addprescription : prescribe(ui: Ui, medicines: ArrayList, medicationName: String, \ncustomerId: String, staffName: String, quantityToPrescribe: int, prescribeDate: Date, \nstock: Stock, existingId: int, existingExpiry: Date, setStockValue: int)
+ addprescription -> stock : setQuantity()
+ addprescription <-- stock
+ addprescription --> addprescription
+ end
+ end
+ end
+ addprescription --> addprescription
+
+
+
+@enduml
diff --git a/docs/diagrams/AddStockSequenceDiagram.puml b/docs/diagrams/AddStockSequenceDiagram.puml
new file mode 100644
index 0000000000..25bd08e9cb
--- /dev/null
+++ b/docs/diagrams/AddStockSequenceDiagram.puml
@@ -0,0 +1,65 @@
+@startuml AddStockSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":AddStockCommand" as addstock COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant ":StockValidator" as stockvalidator COLOR_UTILITIES
+ participant "<>\n:StockManager" as stockmanager COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant ":Stock" as stock COLOR_INVENTORY
+end box
+
+autoactivate on
+mainFrame sd Logic for AddStockCommand
+activate addstock
+addstock -> addstock : checkExpiryDate(ui: Ui, expiryDate: String)
+addstock --> addstock :
+
+ addstock -> stockmanager: getTotalStockQuantity()
+ addstock <-- stockmanager: totalStock
+ addstock -> addstock : isExpiryExist(ui: Ui, stockValidator: StockValidator, \nfilteredStock: ArrayList, quantityToAdd: String, \nformatExpiry: Date, totalStock: int)
+ loop stock : filteredStocks
+ opt isValidQuantity
+ addstock -> addstock : isValidQuantity(ui:Ui, stockValidator: StockValidator, \nmaxQuantity: int, quantity: int)
+ addstock -> stockvalidator : quantityValidityChecker(ui: Ui, quantity: int, maxQuantity: int)
+ addstock <-- stockvalidator : isValidQuantity
+ addstock --> addstock :
+ opt formatExpiry.equals(stock.getExpiry())
+ addstock -> stock : getQuantity()
+ addstock <-- stock : getQuantity
+ addstock -> stock : setQuantity()
+ addstock <-- stock :
+ end
+ end
+ end
+ addstock --> addstock :
+ addstock -> addstock : checkValidParametersAndValues(ui: Ui, parameters: LinkedHashMap, \nmedicines: ArrayList, requiredParameters: String[], optionalParameters: String[])
+ addstock -> addstock : addSameMedicine(ui: Ui, medicines: ArrayList, nameToAdd: String, \nstockValidator: StockValidator, filteredStocks: ArrayList, quantityToAdd: String, \nformatExpiry: Date, totalStock: int)
+ loop stock : filteredStocks
+ opt isValidQuantity
+ addstock -> addstock : isValidQuantity(ui:Ui, stockValidator: StockValidator, \nmaxQuantity: int, quantity: int)
+ addstock -> stockvalidator : quantityValidityChecker(ui: Ui, quantity: int, maxQuantity: int)
+ addstock <-- stockvalidator : isValidQuantity
+ addstock --> addstock :
+ addstock -> addstock : addMedicine(ui: Ui, medicines: ArrayList, name: String, \ndescription: String, price: Double, quantity: int, expiryDate: Date, maxQuantity: int)
+ addstock --> addstock :
+ end
+ addstock --> addstock :
+ end
+ addstock --> addstock :
+ note right
+ This diagram shows the process for adding medication
+ where medication exists.
+ It does not include the process whereby medication does
+ not exist in stock.
+ end note
+deactivate addstock
+
+@enduml
diff --git a/docs/diagrams/ArchitectureDiagram.puml b/docs/diagrams/ArchitectureDiagram.puml
new file mode 100644
index 0000000000..b8bf6ffb2e
--- /dev/null
+++ b/docs/diagrams/ArchitectureDiagram.puml
@@ -0,0 +1,31 @@
+@startuml ArchitectureDiagram
+!include
+!include
+!include style.puml
+
+' hide the circles in the diagram
+hide circle
+hide empty members
+
+package " "<>{
+ class MediVault COLOR_MEDIVAULT
+ class Utilities COLOR_UTILITIES
+ class Errors COLOR_ERRORS
+ class Command COLOR_COMMAND
+ class Inventory COLOR_INVENTORY
+}
+
+class "<$user>" as User COLOR_SPARE
+class "<$documents>" as Files COLOR_SPARE1
+
+User .[COLOR_SPARE].> Utilities
+MediVault -[COLOR_MEDIVAULT]> Utilities
+Errors --[COLOR_ERRORS]up> Utilities
+Utilities .[COLOR_UTILITIES]right>Files
+Utilities --[COLOR_UTILITIES]> Command
+MediVault --[COLOR_COMMAND]> Command
+Command --[COLOR_COMMAND]> Inventory
+Inventory --[COLOR_INVENTORY]> Utilities
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ArchiveOrderCommand.puml b/docs/diagrams/ArchiveOrderCommand.puml
new file mode 100644
index 0000000000..d56bea94a1
--- /dev/null
+++ b/docs/diagrams/ArchiveOrderCommand.puml
@@ -0,0 +1,28 @@
+@startuml DeleteStockSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":ArchiveOrderCommand" as archiveOrder COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:DateParser" as dateParser COLOR_UTILITIES
+ participant "<>\n:Storage" as storage COLOR_UTILITIES
+end box
+
+autoactivate on
+mainFrame sd Logic for ArchiveOrderCommand
+activate archiveOrder
+archiveOrder -> dateParser : stringToDate(date: String)
+archiveOrder <-- dateParser : date
+archiveOrder -> archiveOrder : ordersToArchive(medicines: ArrayList,\n orderArchiveDate: Date)
+archiveOrder --> archiveOrder : filteredOrders
+archiveOrder -> archiveOrder : removeFromOrders(medicines: ArrayList,\n filteredOrders: ArrayList)
+archiveOrder --> archiveOrder
+archiveOrder -> storage : getInstance()
+archiveOrder <-- storage
+archiveOrder -> storage : archiveData(filteredOrders: ArrayList)
+archiveOrder <-- storage
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ArchivePrescriptionCommand.puml b/docs/diagrams/ArchivePrescriptionCommand.puml
new file mode 100644
index 0000000000..9b78a45aec
--- /dev/null
+++ b/docs/diagrams/ArchivePrescriptionCommand.puml
@@ -0,0 +1,28 @@
+@startuml DeleteStockSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":ArchivePrescriptionCommand" as archivePrescription COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:DateParser" as dateParser COLOR_UTILITIES
+ participant "<>\n:Storage" as storage COLOR_UTILITIES
+end box
+
+mainFrame sd Logic for ArchivePrescriptionCommand
+autoactivate on
+activate archivePrescription
+archivePrescription -> dateParser : stringToDate(date: String)
+archivePrescription <-- dateParser : date
+archivePrescription -> archivePrescription : prescriptionsToArchive(medicines: ArrayList,\n prescriptionArchiveDate: Date)
+archivePrescription --> archivePrescription : filteredPrescriptions
+archivePrescription -> archivePrescription : removeFromPrescriptions(medicines: ArrayList,\n filteredPrescriptions: ArrayList)
+archivePrescription --> archivePrescription
+archivePrescription -> storage : getInstance()
+archivePrescription <-- storage
+archivePrescription -> storage : archiveData(filteredPrescriptions: ArrayList)
+archivePrescription <-- storage
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/CommandClassDiagram.puml b/docs/diagrams/CommandClassDiagram.puml
new file mode 100644
index 0000000000..3da3935176
--- /dev/null
+++ b/docs/diagrams/CommandClassDiagram.puml
@@ -0,0 +1,205 @@
+@startuml
+'https://plantuml.com/class-diagram
+
+!include style.puml
+!define ABSTRACT {abstract}
+
+' hide the circles in the diagram
+hide circle
+' hide the icons for access modifiers
+skinparam classAttributeIconSize 0
+' to join all the arrows
+'skinparam groupInheritance 3
+skinparam classBackgroundColor COLOR_COMMAND_BOX
+
+package "Command Component" <> {
+ class "{abstract}\nCommand" as Command
+ class AddPrescriptionCommand
+ class AddStockCommand
+ class AddOrderCommand
+ class ArchivePrescriptionCommand
+ class ArchiveOrderCommand
+ class DeletePrescriptionCommand
+ class DeleteStockCommand
+ class DeleteOrderCommand
+ class ExitCommand
+ class HelpCommand
+ class ListPrescriptionCommand
+ class ListStockCommand
+ class ListOrderCommand
+ class PurgeCommand
+ class ReceiveOrderCommand
+ class UpdatePrescriptionCommand
+ class UpdateStockCommand
+ class UpdateOrderCommand
+
+}
+
+package MediVault <> COLOR_MEDIVAULT_BOX {
+}
+
+package Inventory <> COLOR_INVENTORY_BOX {
+}
+
+class Command {
+ #parameters: LinkedHashMap
+ +execute(): void ABSTRACT
+}
+
+class AddPrescriptionCommand {
+ +AddPrescriptionCommand()
+ +execute(): void
+ -prescribe(): void
+}
+
+class AddStockCommand {
+ +AddStockCommand()
+ +execute(): void
+ -checkExpiryDate(): Date
+ -isExpiryExist(): boolean
+ -addSameMedicine(): boolean
+ -isValidQuantity(): boolean
+ -checkValidParametersAndValues(): boolean
+ -addMedicine(): void
+}
+
+class AddOrderCommand {
+ +AddOrderCommand()
+ +execute(): void
+ -addOrder(): void
+ -addDate(): Date
+ -checkvalidParameterValues(): boolean
+}
+
+class ArchivePrescriptionCommand {
+ +ArchivePrescriptionCommand()
+ +execute(): void
+ -prescriptionsToArchive(): ArrayList
+ -removeFromPrescriptions(): void
+}
+
+class ArchiveOrderCommand {
+ +ArchiveOrderCommand()
+ +execute(): void
+ -ordersToArchive(): ArrayList
+ -removeFromOrders(): void
+}
+
+class DeletePrescriptionCommand {
+ +DeletePrescriptionCommand()
+ +execute(): void
+ -isValidPrescriptionParameters(): boolean
+ -setStockQuantity(): boolean
+}
+
+class DeleteStockCommand {
+ +DeleteStockCommand()
+ +execute(): void
+ -deleteStockById(): void
+ -deleteStockByExpiry(): void
+}
+
+class DeleteOrderCommand {
+ +DeleteOrderCommand()
+ +execute(): void
+ -isValidOrderParameters(): boolean
+}
+
+class ExitCommand {
+ +execute(): void
+}
+
+class HelpCommand {
+ +execute(): void
+}
+
+class ListPrescriptionCommand {
+ +ListPrescriptionCommand()
+ +execute(): void
+ -filterPrescriptions(): ArrayList
+}
+
+class ListStockCommand {
+ +ListStockCommand()
+ +execute(): void
+}
+
+class ListOrderCommand {
+ +ListOrderCommand()
+ +execute(): void
+ -filterOrders(): ArrayList
+}
+
+class PurgeCommand {
+ +execute(): void
+}
+
+class ReceiveOrderCommand {
+ +ReceiveOrderCommand()
+ +execute(): void
+ -getCurrentQuantity(): int
+ -checkStockExist(): boolean
+ -checkOrderIdExist(): boolean
+ -isStockParametersValid(): boolean
+}
+
+class UpdatePrescriptionCommand {
+ +UpdatePrescriptionCommand()
+ +execute(): void
+ -processGivenNameAndQuantity(): boolean
+ -processGivenName(): boolean
+ -processGivenQuantity(): boolean
+ -processOtherFields(): boolean
+ -processPrescription(): boolean
+ -processRestoration(): boolean
+}
+
+class UpdateOrderCommand {
+ +UpdateOrderCommand()
+ +execute(): void
+ -setUpdatesByOrderId(): void
+}
+
+class UpdateStockCommand {
+ +UpdateStockCommand()
+ +execute(): void
+ -printUpdatedStockId: void
+ -checkAffectedCommand(): boolean
+ -getNewStock(): Stock
+ -addNewRowForUpdates(): void
+ -processDateInput(): boolean
+ -processQuantityValues(): boolean
+ -setUpdatesByStockId(): void
+}
+
+AddPrescriptionCommand ----|> Command
+AddStockCommand ----|> Command
+AddOrderCommand ----|> Command
+DeletePrescriptionCommand ---|> Command
+DeleteStockCommand ---|> Command
+DeleteOrderCommand ---|> Command
+ExitCommand --|> Command
+HelpCommand --|> Command
+PurgeCommand --|> Command
+ListPrescriptionCommand --up|> Command
+ListStockCommand --up|> Command
+ListOrderCommand --up|> Command
+ReceiveOrderCommand ---up|> Command
+ArchivePrescriptionCommand ---up|> Command
+ArchiveOrderCommand ---up|> Command
+UpdateOrderCommand ----up|> Command
+UpdatePrescriptionCommand ----up|> Command
+UpdateStockCommand ----up|> Command
+
+MediVault ---.right|> Command: executes >
+Command ---.right|> Inventory: affects >
+
+note as ConstraintsNote
+The input parameters for
+methods and constructors are
+left out as member details
+can get outdated over time.
+end note
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ContainValidParametersAndValuesSequenceDiagram.puml b/docs/diagrams/ContainValidParametersAndValuesSequenceDiagram.puml
new file mode 100644
index 0000000000..471d8ad290
--- /dev/null
+++ b/docs/diagrams/ContainValidParametersAndValuesSequenceDiagram.puml
@@ -0,0 +1,55 @@
+@startuml ContainValidParametersAndValuesSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":*Command" as command COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:Ui" as ui COLOR_UTILITIES
+ participant "<>\nMedicineValidator" as medicinevalidator COLOR_UTILITIES
+ participant ":*Validator" as xvalidator COLOR_UTILITIES
+ participant "<>\n:Storage" as storage COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant "<>\n:Medicine" as medicine COLOR_INVENTORY
+end box
+
+autoactivate on
+mainFrame sd Execution of *Command
+note right of command
+Replace * in the diagram with
+Stock, Prescription or Order
+depending on the command entered.
+end note
+activate command
+ command -> ui: getInstance()
+ command <-- ui
+ command -> medicine: getInstance()
+ command <-- medicine
+ create xvalidator
+ command -> xvalidator: new *Validator()
+ command <-- xvalidator
+ command -> medicinevalidator: containsInvalidParametersAndValues(ui: Ui,\nparameters: LinkedHashMap,\nmedicines: ArrayList, requiredParameters: String[],\noptionalParameters: String[], commandSyntax: String,\nrequiresOptionalParameters: boolean, validator: MedicineValidator)
+ medicinevalidator -> medicinevalidator: containsInvalidParameters(ui: Ui,\nparameters: LinkedHashMap,\nrequiredParameters: String[],\noptionalParameters: String[],\ncommandSyntax: String,\nrequiresOptionalParameters: boolean)
+ medicinevalidator --> medicinevalidator: isInvalidParameter
+ opt !isInvalidParameter
+ medicinevalidator -> xvalidator: containsInvalidParameterValues(ui: Ui,\nparameters: LinkedHashMap,\nmedicines: ArrayList,\ncommandSyntax: String,\ninvalidParameters: ArrayList)
+ medicinevalidator <-- xvalidator: isInvalidParameterValues
+ end
+ command <-- medicinevalidator: isInvalidInput
+ opt !isInvalidInput
+ ref over command, storage
+ Logic for *Command
+ end ref
+ command -> storage: getInstance()
+ command <-- storage
+ command -> storage: saveData()
+ command <-- storage
+ end
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/DeleteOrderSequenceDiagram.puml b/docs/diagrams/DeleteOrderSequenceDiagram.puml
new file mode 100644
index 0000000000..b2af1afc39
--- /dev/null
+++ b/docs/diagrams/DeleteOrderSequenceDiagram.puml
@@ -0,0 +1,44 @@
+@startuml DeleteOrderSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":DeleteOrderCommand" as deleteorder COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant ":OrderValidator" as ordervalidator COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant "<>\n:Medicine" as medicine COLOR_INVENTORY
+ participant ":Order" as order COLOR_INVENTORY
+end box
+autoactivate on
+
+mainframe sd DeleteOrderCommand
+activate deleteorder
+
+deleteorder -> deleteorder : isValidOrderParameters(ui: Ui, medicines: ArrayList)
+
+
+
+ loop medicine : medicines
+ opt medicine instanceof Order
+
+
+ deleteorder -> order : getOrderId()
+ deleteorder <-- order
+ opt order.getOrderId() == order.orderId
+ deleteorder -> medicine : remove()
+ deleteorder <-- medicine :
+ end
+ end
+ end
+
+
+deleteorder --> deleteorder :
+
+
+@enduml
diff --git a/docs/diagrams/DeletePrescriptionSequenceDiagram.puml b/docs/diagrams/DeletePrescriptionSequenceDiagram.puml
new file mode 100644
index 0000000000..e35c5d1087
--- /dev/null
+++ b/docs/diagrams/DeletePrescriptionSequenceDiagram.puml
@@ -0,0 +1,51 @@
+@startuml DeletePrescriptionSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":DeletePrescriptionCommand" as deleteprescription COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:PrescriptionManager" as prescriptionManager COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant ":Stock" as stock COLOR_INVENTORY
+end box
+
+autoactivate on
+mainframe sd DeletePrescriptionCommand
+activate deleteprescription
+
+deleteprescription -> deleteprescription : isValidPrescriptionParameters(ui: Ui, medicines: ArrayList)
+
+ deleteprescription -> deleteprescription : setStockQuantity()
+ loop medicine : medicines
+
+ opt medicine intanceof Stock
+
+ opt prescription.getPrescriptionId() == prescriptionId
+ deleteprescription -> deleteprescription : setStockQuantity(ui Ui, medicines: ArrayList, \nstockIdPrescribe: int, prescribeQuantity: int)
+ opt stock.isDeleted
+ deleteprescription -> stock : setDeleted()
+ deleteprescription <-- stock : setAsDeleted
+
+ deleteprescription -> stock : getStockID()
+ deleteprescription <-- stock :
+ opt stock.getStockID() == stockIdToDispense
+ deleteprescription -> stock : setQuantity()
+ deleteprescription <-- stock :
+ end
+ deleteprescription -->deleteprescription
+ end
+
+ end
+ end
+ end
+
+deactivate deleteprescription
+deleteprescription --> deleteprescription :
+
+@enduml
diff --git a/docs/diagrams/DeleteStockSequenceDiagram.puml b/docs/diagrams/DeleteStockSequenceDiagram.puml
new file mode 100644
index 0000000000..524bcbb014
--- /dev/null
+++ b/docs/diagrams/DeleteStockSequenceDiagram.puml
@@ -0,0 +1,34 @@
+@startuml DeleteStockSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":DeleteStockCommand" as deleteStock COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:Ui" as ui COLOR_UTILITIES
+ participant ":StockValidator" as stockValidator COLOR_UTILITIES
+ participant "<>\n:Storage" as storage COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant "<>\n:Medicine" as medicine COLOR_INVENTORY
+end box
+
+autoactivate on
+mainFrame sd Logic for DeleteStockCommand
+activate deleteStock
+opt !(hasStockId && hasExpiryDate)
+ alt hasStockId && !hasExpiryDate
+ ref over deleteStock, medicine
+ Deletion of stock by id
+ end ref
+ else !hasStockId && hasExpiryDate
+ ref over deleteStock, medicine
+ Deletion of stock by expiry
+ end ref
+ end
+end
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/DeletionOfStockByExpirySequenceDiagram.puml b/docs/diagrams/DeletionOfStockByExpirySequenceDiagram.puml
new file mode 100644
index 0000000000..6546bbf6be
--- /dev/null
+++ b/docs/diagrams/DeletionOfStockByExpirySequenceDiagram.puml
@@ -0,0 +1,42 @@
+@startuml DeleteStockSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":DeleteStockCommand" as deleteStock COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:Ui" as ui COLOR_UTILITIES
+ participant "<>\n:DateParser" as dateParser COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant ":Stock" as stock COLOR_INVENTORY
+end box
+
+autoactivate on
+mainFrame sd Deletion of stock by expiry
+activate deleteStock
+deleteStock -> deleteStock: deleteStockByExpiry(ui: Ui,\n medicines: ArrayList)
+deleteStock -> dateParser : stringToDate(date: String)
+deleteStock <-- dateParser : date
+loop medicine : medicines
+ deleteStock -> deleteStock : medicine
+ opt medicine instanceof Stock
+ deleteStock -> stock : getExpiry()
+ deleteStock <-- stock : stockExpiryDate
+ opt stockExpiryDate.before(date) || stockExpiryDate.equals(date)
+ deleteStock -> stock : setQuantity(quantity: int)
+ deleteStock <-- stock
+ deleteStock -> stock : setDeleted(deleted: boolean)
+ deleteStock <-- stock
+ end
+ end
+ deleteStock --> deleteStock
+end
+deleteStock --> deleteStock
+deleteStock -> ui : print()
+deleteStock <-- ui
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/DeletionOfStockByIdSequenceDiagram.puml b/docs/diagrams/DeletionOfStockByIdSequenceDiagram.puml
new file mode 100644
index 0000000000..09f97b5116
--- /dev/null
+++ b/docs/diagrams/DeletionOfStockByIdSequenceDiagram.puml
@@ -0,0 +1,40 @@
+@startuml DeleteStockSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":DeleteStockCommand" as deleteStock COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:Ui" as ui COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant ":Stock" as stock COLOR_INVENTORY
+end box
+
+autoactivate on
+mainFrame sd Deletion of stock by id
+activate deleteStock
+deleteStock -> deleteStock: deleteStockById(ui: Ui,\n medicines: ArrayList)
+loop medicine : medicines
+ deleteStock -> deleteStock : medicine
+ opt medicine instanceof Stock
+ deleteStock -> stock : getStockId()
+ deleteStock <-- stock : stockId
+ opt stock.getStockId() == stockId
+ deleteStock -> stock : setQuantity(quantity: int)
+ deleteStock <-- stock
+ deleteStock -> stock : setDeleted(deleted: boolean)
+ deleteStock <-- stock
+ end
+ end
+ deleteStock --> deleteStock
+end
+deleteStock --> deleteStock
+deleteStock -> ui : print()
+deleteStock <-- ui
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/InventoryClassDiagram.puml b/docs/diagrams/InventoryClassDiagram.puml
new file mode 100644
index 0000000000..208048128a
--- /dev/null
+++ b/docs/diagrams/InventoryClassDiagram.puml
@@ -0,0 +1,63 @@
+@startuml
+'https://plantuml.com/class-diagram
+' hide the circles in the diagram
+hide circle
+' hide the icons for access modifiers
+skinparam classAttributeIconSize 0
+' to join all the arrows
+skinparam groupInheritance 3
+
+class "{abstract}\nMedicine"{
+ #medicineName: String
+ #quantity: int
+ -{static} medicines: ArrayList
+ +{static} getInstance()
+ +Medicine(medicineName: String, quantity: int)
+ +toFileFormat() {abstract}
+ +toArchiveFormat() {abstract}
+}
+
+class "Stock"{
+ -{static} stockCount: int
+ #stockID: int
+ #price: double
+ #expiry: Date
+ #description: String
+ #maxQuantity: int
+ #isDeleted: boolean
+ +Stock(name: String, price: Double, quantity: int,
+ expiry: Date, description: String, maxQuantity: int)
+ +toFileFormat(): String
+ +toArchiveFormat(): String
+}
+
+class "Prescription"{
+ -{static} prescriptionCount: int
+ #prescriptionId: int
+ #customerId: int
+ #date: Date
+ #staff: String
+ #stockId: int
+ +Prescription(medicineName: String, quantity: int,
+ customerId: String, date: Date, staff: String, stockId: int)
+ +toFileFormat(): String
+ +toArchiveFormat(): String
+}
+
+class "Order"{
+ -{static} orderCount: int
+ #orderId: int
+ #date: Date
+ #isDelivered: boolean
+ +Order(medicineName: String,
+ quantity: int, date: Date)
+ +toFileFormat(): String
+ +toArchiveFormat(): String
+}
+
+"{abstract}\nMedicine" <|-- "Stock"
+"{abstract}\nMedicine" <|-- "Prescription"
+"{abstract}\nMedicine" <|-- "Order"
+
+note "Note: All the getters and setters are\nleft out in this diagram." as n1
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ListSequenceDiagram.puml b/docs/diagrams/ListSequenceDiagram.puml
new file mode 100644
index 0000000000..c418d47ea5
--- /dev/null
+++ b/docs/diagrams/ListSequenceDiagram.puml
@@ -0,0 +1,62 @@
+@startuml AddSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":List*Command" as list COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\nUi" as ui COLOR_UTILITIES
+ participant ":*Comparator" as comparator COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant ":*" as object COLOR_INVENTORY
+end box
+
+autoactivate on
+
+mainFrame sd Logic for List*
+
+activate list
+list -> list : filter*()
+
+loop until end of parameters
+
+ alt parameters.equals(SORT)
+ create comparator
+ list -> comparator : new *Comparator(column: String, isReversed: boolean)
+ list <-- comparator : sorted*
+ deactivate comparator
+ else parameters.equals(REVERSED_SORT)
+ create comparator
+ list -> comparator : new *Comparator(column: String, isReversed: boolean)
+ list <-- comparator : reverseSorted*
+ deactivate comparator
+ else default
+ loop until end of all * objects
+ list -> object : getAttributeValue()
+ list <-- object
+ end
+
+ end
+
+end
+
+list --> list : filtered*
+
+list -> ui : print*(medicines: Arraylist<*>)
+list <-- ui
+deactivate ui
+
+note left of object
+Replace * in the diagram with
+Stock, Prescription or Order
+depending on the command entered.
+end note
+
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/MainLogicSequenceDiagram.puml b/docs/diagrams/MainLogicSequenceDiagram.puml
new file mode 100644
index 0000000000..9b01b68aab
--- /dev/null
+++ b/docs/diagrams/MainLogicSequenceDiagram.puml
@@ -0,0 +1,63 @@
+@startuml AddSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box MediVault COLOR_MEDIVAULT_BOX
+ participant ":MediVault" as medivault COLOR_MEDIVAULT
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\nUi" as uiclass COLOR_UTILITIES
+ participant "Ui" as ui COLOR_UTILITIES
+ participant "CommandParser" as commandparser COLOR_UTILITIES
+end box
+
+box Command COLOR_COMMAND_BOX
+ participant ":Command" as command COLOR_COMMAND
+end box
+
+autoactivate on
+
+-> medivault: run()
+ medivault -> uiclass : getInstance()
+ medivault <-- uiclass
+ medivault -> uiclass : printWelcomeMessage()
+ medivault <-- uiclass
+ create commandparser
+ medivault -> commandparser : CommandParser()
+ medivault <-- commandparser
+
+ loop until exit is received
+ medivault -> ui : getInput()
+ medivault <-- ui : userInput
+ medivault -> commandparser : parseCommand(userInput: String)
+ medivault <-- commandparser : userCommand, parameters
+
+ alt command equals modes
+ medivault -> commandparser : changeMode(ui: Ui, commandString: String, mode: Mode)
+ medivault <-- commandparser
+ else else
+ medivault -> commandparser : processCommand(commandString: String,\ncommandParameters: LinkedHashMap,\nmode Mode)
+ commandparser -> commandparser : parseParameters(parametersString: String)
+ commandparser --> commandparser : parameterValues
+ create command
+ commandparser -> command : Command(parameters: LinkedHashMap)
+ commandparser <-- command
+ medivault <-- commandparser
+ medivault -> command : execute()
+
+ ref over medivault,command
+ Execution of *command
+ end ref
+ medivault <-- command
+ deactivate command
+ end
+ end
+
+note left of command
+Note that processCommand throws InvalidCommandException
+when an invalid command is entered.
+end note
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ReceiveOrderSequenceDiagram.puml b/docs/diagrams/ReceiveOrderSequenceDiagram.puml
new file mode 100644
index 0000000000..c912d157a7
--- /dev/null
+++ b/docs/diagrams/ReceiveOrderSequenceDiagram.puml
@@ -0,0 +1,41 @@
+@startuml AddSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":ReceiveOrderCommand" as receiveordercommand COLOR_COMMAND
+ participant ":AddStockCommand" as addstockcommand COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant ":StockValidator" as stockvalidator COLOR_UTILITIES
+end box
+
+autoactivate on
+
+mainFrame sd Logic for ReceiveOrderCommand
+
+activate receiveordercommand
+receiveordercommand -> receiveordercommand : isStockParametersValid(ui: Ui, medicines: ArrayList, name: String)
+receiveordercommand -> stockvalidator : new StockValidator()
+receiveordercommand <-- stockvalidator
+
+receiveordercommand -> receiveordercommand : checkStockExist(medicines: ArrayList, name: String)
+receiveordercommand --> receiveordercommand
+receiveordercommand -> stockvalidator : containsInvalidParametersAndValues(ui: Ui, medicines: ArrayList,\nparameters: LinkedHashMap, requiredParameters: String[],\noptionalParameters: String[], commandSyntax: String,\nrequiresOptionalParameters: boolean, validator: MedicineValidator)
+receiveordercommand <-- stockvalidator : isInvalidInput
+
+receiveordercommand --> receiveordercommand : isStockParametersValid
+opt isStockParametersValid
+ create addstockcommand
+ receiveordercommand -> addstockcommand : new AddStockCommand(parameters: LinkedHashMap)
+ receiveordercommand <-- addstockcommand
+ receiveordercommand -> addstockcommand : execute()
+ receiveordercommand <-- addstockcommand
+ deactivate addstockcommand
+end
+
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
new file mode 100644
index 0000000000..18126e3e57
--- /dev/null
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -0,0 +1,63 @@
+@startuml
+'https://plantuml.com/class-diagram
+' hide the circles in the diagram
+hide circle
+' hide the icons for access modifiers
+skinparam classAttributeIconSize 0
+!include style.puml
+skinparam classBackgroundColor COLOR_UTILITIES_BOX
+
+Storage -> FileParser
+
+class Storage {
+ -stockFile : File
+ -prescriptionFile : File
+ -orderFile : File
+ -prescriptionArchiveFile : File
+ -orderArchiveFile : File
+
+ +saveData(medicines: ArrayList) : void
+ +archiveData(medicines: ArrayList) : void
+ +loadData() : ArrayList
+ -writeToFile(data: String, filePath: String) : void
+ -appendToFile(data: String, filePath: String) : void
+ -readFromFile(fileType: String, file: File) : ArrayList
+ -parseStockData(stockDetails: String, stockRow: int) : Medicine
+ -parseOrderData(orderDetails: String, orderRow: int) : Medicine
+ -parsePrescriptionData(prescriptionDetails: String, prescriptionRow: int) : Medicine
+}
+
+class "FileParser"{
+ -stockIds : HashSet
+ -orderIds : HashSet
+ -prescriptionIds : Hashset
+
+ +parseStockId() : int
+ +parseStockName() : String
+ +parseStockPrice() : Double
+ +parseStockQuantity() : int
+ +parseStockExpiry() : Date
+ +parseStockDescription() : String
+ +parseStockMaxQuantity() : int
+ +parseStockIsDeleted() : boolean
+ +parseOrderId() : int
+ +parseOrderName() : String
+ +parseOrderQuantity() : int
+ +parseOrderDate() : Date
+ +parseOrderStatus() : boolean
+ +parsePrescriptionId() : int
+ +parsePrescriptionName() : String
+ +parsePrescriptionQuantity() : int
+ +parsePrescriptionCustomerId() : String
+ +parsePrescriptionDate() : Date
+ +parsePrescriptionStaff() : String
+ +parsePrescriptionStockId() : int
+}
+
+note bottom
+The input parameters are as follows:
+parseStock*(splitStockDetails: String[], stockRow: int)
+parseOrder*(splitOrderDetails: String[], orderRow: int)
+parsePrescription*(splitPrescriptionDetails: String[], prescriptionRow: int)
+end note
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/UpdateOrderSequenceDiagram.puml b/docs/diagrams/UpdateOrderSequenceDiagram.puml
new file mode 100644
index 0000000000..031582573d
--- /dev/null
+++ b/docs/diagrams/UpdateOrderSequenceDiagram.puml
@@ -0,0 +1,43 @@
+@startuml UpdateOrderSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":UpdateOrderCommand" as updateorder COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant ":StockValidator" as stockvalidator COLOR_UTILITIES
+ participant "<>\n:OrderManager" as ordermanager COLOR_UTILITIES
+ participant "<>\n:StockManager" as stockmanager COLOR_UTILITIES
+end box
+
+box Inventory COLOR_INVENTORY_BOX
+ participant ":Order" as order COLOR_INVENTORY
+end box
+
+autoactivate on
+mainFrame sd Logic for UpdateOrderCommand
+activate updateorder
+ updateorder -> ordermanager: extractOrderObject(parameters: LinkedHashMap,\nmedicines: ArrayList)
+ updateorder <-- ordermanager: order
+ updateorder -> order: isDelivered()
+ updateorder <-- order
+ opt !isDelivered
+ updateorder -> stockmanager: getMaxStockQuantity(medicines: ArrayList, orderName: String)
+ updateorder <-- stockmanager
+ opt existName && existQuantityParam
+ create stockvalidator
+ updateorder -> stockvalidator: new StockValidator()
+ updateorder <-- stockvalidator
+ updateorder -> stockvalidator: checkUpdateQuantity(ui: Ui,\nmedicines: ArrayList,\norder: Order, maxQuantity: int)
+ updateorder <-- stockvalidator: isValidQuantity
+ opt isValidQuantity
+ updateorder -> updateorder: setUpdatesByOrderId(filteredOrders: ArrayList,\norder: Order)
+ updateorder --> updateorder
+ end
+ end
+ end
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/UpdatePrescriptionSequenceDiagram.puml b/docs/diagrams/UpdatePrescriptionSequenceDiagram.puml
new file mode 100644
index 0000000000..837d0a4601
--- /dev/null
+++ b/docs/diagrams/UpdatePrescriptionSequenceDiagram.puml
@@ -0,0 +1,43 @@
+@startuml UpdatePrescriptionSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":UpdatePrescriptionCommand" as updateprescription COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant ":StockValidator" as stockvalidator COLOR_UTILITIES
+ participant "<>\n:PrescriptionManager" as prescriptionmanager COLOR_UTILITIES
+end box
+
+autoactivate on
+mainFrame sd Logic for UpdatePrescriptionCommand
+activate updateprescription
+ updateprescription -> prescriptionmanager: extractDispenseObject(parameters: LinkedHashMap,\nmedicines: ArrayList)
+ updateprescription <-- prescriptionmanager
+ create stockvalidator
+ updateprescription -> stockvalidator: new StockValidator()
+ updateprescription <-- stockvalidator
+ alt hasNameParam && hasQuantityParam
+ updateprescription -> updateprescription: processGivenNameAndQuantity()
+ note right
+ All methods takes in the same parameters.
+ process(ui: Ui, medicines: ArrayList,
+ prescription: Prescription, customerId: String,
+ date: Date, staffName: String)
+ end note
+ updateprescription --> updateprescription: isSuccessfulUpdate
+ else hasNameParam && !hasQuantityParam
+ updateprescription -> updateprescription: processGivenName()
+ updateprescription --> updateprescription: isSuccessfulUpdate
+ else !hasNameParam && hasQuantityParam
+ updateprescription -> updateprescription: processGivenQuantity()
+ updateprescription --> updateprescription: isSuccessfulUpdate
+ else containsParamOtherThanNameAndQuantity
+ updateprescription -> updateprescription: processOtherFields()
+ updateprescription --> updateprescription: isSuccessfulUpdate
+ end
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/UpdateStockSequenceDiagram.puml b/docs/diagrams/UpdateStockSequenceDiagram.puml
new file mode 100644
index 0000000000..51c7b65548
--- /dev/null
+++ b/docs/diagrams/UpdateStockSequenceDiagram.puml
@@ -0,0 +1,41 @@
+@startuml UpdateStockSequenceDiagram
+'https://plantuml.com/sequence-diagram
+
+!include style.puml
+
+box Command COLOR_COMMAND_BOX
+ participant ":UpdateStockCommand" as updatestock COLOR_COMMAND
+end box
+
+box Utilities COLOR_UTILITIES_BOX
+ participant "<>\n:StockManager" as stockmanager COLOR_UTILITIES
+end box
+
+autoactivate on
+mainFrame sd Logic for UpdateStockCommand
+activate updatestock
+ updatestock -> stockmanager: extractStockObject(parameters: LinkedHashMap,\nmedicines: ArrayList)
+ updatestock <-- stockmanager: stock
+
+ updatestock -> updatestock: processQuantityValues(ui: Ui, \nmedicines: ArrayList, stock: Stock)
+ updatestock --> updatestock: isValidQuantityValues
+
+ updatestock -> updatestock: processDateInput(ui: Ui, \nmedicines: ArrayList, stock: Stock)
+ updatestock --> updatestock: isValidExpDate
+
+ opt isValidQuantityValues && isValidExpDate
+ updatestock -> stockmanager: getFilteredStocksByName(medicines: ArrayList,\nstockName: String)
+ updatestock <-- stockmanager: oldFilteredStocks
+ opt parameters contains name
+ updatestock -> updatestock: addNewRowForUpdate(filteredStocks: ArrayList,\nmedicines: ArrayList)
+ deactivate updatestock
+ updatestock -> updatestock: getNewStock(medicines: ArrayList,\nstock: Stock)
+ deactivate updatestock
+ end
+ updatestock -> stockmanager: getFilteredStocksByName(medicines: ArrayList,\nstockName: String)
+ updatestock <-- stockmanager: filteredStocks
+ updatestock -> updatestock: setUpdatesByStockId(filteredStocks: ArrayList,\nstock: Stock)
+ deactivate updatestock
+ end
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ValidatorClassDiagram.puml b/docs/diagrams/ValidatorClassDiagram.puml
new file mode 100644
index 0000000000..970b9f4338
--- /dev/null
+++ b/docs/diagrams/ValidatorClassDiagram.puml
@@ -0,0 +1,63 @@
+@startuml
+'https://plantuml.com/class-diagram
+' hide the circles in the diagram
+hide circle
+' hide the icons for access modifiers
+skinparam classAttributeIconSize 0
+' to join all the arrows
+skinparam groupInheritance 3
+
+!include style.puml
+
+skinparam classBackgroundColor COLOR_UTILITIES_BOX
+
+class "{abstract}\n MedicineValidator"{
+ +containsInvalidParameterValues(): boolean {abstract}
+ +isValidColumn(): boolean {abstract}
+ +containsInvalidParametersAndValues(): boolean
+ +getInvalidParameters(): ArrayList
+ +containsInvalidParameters(): boolean
+ +isValidName(): boolean
+ +isValidQuantity(): boolean
+ +hasNameParamChecker(): boolean
+ +hasQuantityParamChecker(): boolean
+}
+
+class "StockValidator"{
+ +StockValidator()
+ +containsInvalidParameterValues(): boolean;
+ +isValidStockId(): boolean
+ +isValidPrice(): boolean
+ +isValidExpiry(): boolean
+ +isValidDescription(): boolean
+ +isValidMaxQuantity(): boolean
+ +isValidColumn(): boolean
+ +quantityValidityChecker(): boolean
+ +dateValidityChecker(): boolean
+}
+
+class "PrescriptionValidator"{
+ +PrescriptionValidator()
+ +containsInvalidParameterValues(): boolean;
+ +isValidPrescriptionId(): boolean
+ +isValidCustomerId(): boolean
+ +isValidStaffName(): boolean
+ +isValidColumn(): boolean
+ +isValidDate(): boolean
+}
+
+class "OrderValidator"{
+ +OrderValidator()
+ +containsInvalidParameterValues(): boolean;
+ +isValidOrderId(): boolean
+ +isValidDate(): boolean
+ +isValidStatus(): boolean
+ +isValidColumn(): boolean
+}
+
+"{abstract}\n MedicineValidator" <|---- "StockValidator"
+"{abstract}\n MedicineValidator" <|-- "PrescriptionValidator"
+"{abstract}\n MedicineValidator" <|---- "OrderValidator"
+
+note "The input parameters for all functions\nhas been left out to make this\ndiagram more compact." as n1
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/diagram_images/AddOrderSequenceDiagram.png b/docs/diagrams/diagram_images/AddOrderSequenceDiagram.png
new file mode 100644
index 0000000000..f9ff03828e
Binary files /dev/null and b/docs/diagrams/diagram_images/AddOrderSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/AddPrescriptionSequenceDiagram.png b/docs/diagrams/diagram_images/AddPrescriptionSequenceDiagram.png
new file mode 100644
index 0000000000..cbe2e354e8
Binary files /dev/null and b/docs/diagrams/diagram_images/AddPrescriptionSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/AddStockSequenceDiagram.png b/docs/diagrams/diagram_images/AddStockSequenceDiagram.png
new file mode 100644
index 0000000000..330707c215
Binary files /dev/null and b/docs/diagrams/diagram_images/AddStockSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/ArchitectureDiagram.png b/docs/diagrams/diagram_images/ArchitectureDiagram.png
new file mode 100644
index 0000000000..74bcab45cd
Binary files /dev/null and b/docs/diagrams/diagram_images/ArchitectureDiagram.png differ
diff --git a/docs/diagrams/diagram_images/ArchiveOrderSequenceDiagram.png b/docs/diagrams/diagram_images/ArchiveOrderSequenceDiagram.png
new file mode 100644
index 0000000000..55ea13cd73
Binary files /dev/null and b/docs/diagrams/diagram_images/ArchiveOrderSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/ArchivePrescriptionSequenceDiagram.png b/docs/diagrams/diagram_images/ArchivePrescriptionSequenceDiagram.png
new file mode 100644
index 0000000000..9e56a23802
Binary files /dev/null and b/docs/diagrams/diagram_images/ArchivePrescriptionSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/CommandClassDiagram.png b/docs/diagrams/diagram_images/CommandClassDiagram.png
new file mode 100644
index 0000000000..87dfe04bb7
Binary files /dev/null and b/docs/diagrams/diagram_images/CommandClassDiagram.png differ
diff --git a/docs/diagrams/diagram_images/ContainValidParametersAndValuesSequenceDiagram.png b/docs/diagrams/diagram_images/ContainValidParametersAndValuesSequenceDiagram.png
new file mode 100644
index 0000000000..a53ef143f1
Binary files /dev/null and b/docs/diagrams/diagram_images/ContainValidParametersAndValuesSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/DeleteOrderSequenceDiagram.png b/docs/diagrams/diagram_images/DeleteOrderSequenceDiagram.png
new file mode 100644
index 0000000000..4ac475c477
Binary files /dev/null and b/docs/diagrams/diagram_images/DeleteOrderSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/DeletePrescriptionSequenceDiagram.png b/docs/diagrams/diagram_images/DeletePrescriptionSequenceDiagram.png
new file mode 100644
index 0000000000..6262c16b54
Binary files /dev/null and b/docs/diagrams/diagram_images/DeletePrescriptionSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/DeleteStockSequenceDiagram.png b/docs/diagrams/diagram_images/DeleteStockSequenceDiagram.png
new file mode 100644
index 0000000000..6cfd864e8f
Binary files /dev/null and b/docs/diagrams/diagram_images/DeleteStockSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/DeletionOfStockByExpirySequenceDiagram.png b/docs/diagrams/diagram_images/DeletionOfStockByExpirySequenceDiagram.png
new file mode 100644
index 0000000000..36134ad9b4
Binary files /dev/null and b/docs/diagrams/diagram_images/DeletionOfStockByExpirySequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/DeletionOfStockByIdSequenceDiagram.png b/docs/diagrams/diagram_images/DeletionOfStockByIdSequenceDiagram.png
new file mode 100644
index 0000000000..1e775d6e24
Binary files /dev/null and b/docs/diagrams/diagram_images/DeletionOfStockByIdSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/InventoryClassDiagram.png b/docs/diagrams/diagram_images/InventoryClassDiagram.png
new file mode 100644
index 0000000000..a685670296
Binary files /dev/null and b/docs/diagrams/diagram_images/InventoryClassDiagram.png differ
diff --git a/docs/diagrams/diagram_images/ListSequenceDiagram.png b/docs/diagrams/diagram_images/ListSequenceDiagram.png
new file mode 100644
index 0000000000..e67b4f9178
Binary files /dev/null and b/docs/diagrams/diagram_images/ListSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/MainLogicSequenceDiagram.png b/docs/diagrams/diagram_images/MainLogicSequenceDiagram.png
new file mode 100644
index 0000000000..ae35f8c84e
Binary files /dev/null and b/docs/diagrams/diagram_images/MainLogicSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/ReceiveOrderSequenceDiagram.png b/docs/diagrams/diagram_images/ReceiveOrderSequenceDiagram.png
new file mode 100644
index 0000000000..4886200a80
Binary files /dev/null and b/docs/diagrams/diagram_images/ReceiveOrderSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/StorageClassDiagram.png b/docs/diagrams/diagram_images/StorageClassDiagram.png
new file mode 100644
index 0000000000..245add461f
Binary files /dev/null and b/docs/diagrams/diagram_images/StorageClassDiagram.png differ
diff --git a/docs/diagrams/diagram_images/UpdateOrderSequenceDiagram.png b/docs/diagrams/diagram_images/UpdateOrderSequenceDiagram.png
new file mode 100644
index 0000000000..0caf406327
Binary files /dev/null and b/docs/diagrams/diagram_images/UpdateOrderSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/UpdatePrescriptionSequenceDiagram.png b/docs/diagrams/diagram_images/UpdatePrescriptionSequenceDiagram.png
new file mode 100644
index 0000000000..46b606fe9a
Binary files /dev/null and b/docs/diagrams/diagram_images/UpdatePrescriptionSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/UpdateStockSequenceDiagram.png b/docs/diagrams/diagram_images/UpdateStockSequenceDiagram.png
new file mode 100644
index 0000000000..bcef386b68
Binary files /dev/null and b/docs/diagrams/diagram_images/UpdateStockSequenceDiagram.png differ
diff --git a/docs/diagrams/diagram_images/ValidatorClassDiagram.png b/docs/diagrams/diagram_images/ValidatorClassDiagram.png
new file mode 100644
index 0000000000..11ec7a71a4
Binary files /dev/null and b/docs/diagrams/diagram_images/ValidatorClassDiagram.png differ
diff --git a/docs/diagrams/style.puml b/docs/diagrams/style.puml
new file mode 100644
index 0000000000..95a13a9e21
--- /dev/null
+++ b/docs/diagrams/style.puml
@@ -0,0 +1,17 @@
+!define COLOR_MEDIVAULT #1E90FF
+!define COLOR_UTILITIES #FF8C00
+!define COLOR_COMMAND #00FFFF
+!define COLOR_ERRORS #DC143C
+!define COLOR_INVENTORY #BA55D3
+!define COLOR_SPARE #FF69B4
+!define COLOR_SPARE1 #FFFF00
+!define COLOR_SPARE3 #00FF00
+
+!define COLOR_MEDIVAULT_BOX #ADD8E6
+!define COLOR_UTILITIES_BOX #FAEBD7
+!define COLOR_COMMAND_BOX #E0FFFF
+!define COLOR_ERRORS_BOX #F08080
+!define COLOR_INVENTORY_BOX #DDA0DD
+!define COLOR_SPARE_BOX #FFC0CB
+!define COLOR_SPARE1_BOX #FFFACD
+!define COLOR_SPARE3_BOX #98FB98
diff --git a/docs/team/a-tph.md b/docs/team/a-tph.md
new file mode 100644
index 0000000000..cebf44eed8
--- /dev/null
+++ b/docs/team/a-tph.md
@@ -0,0 +1,69 @@
+# Teo Phing Huei, Aeron - Project Portfolio Page
+
+This is a student project for a university software development course and I am one of the contributors to `MediVault`.
+
+`MediVault` is a Command Line Interface (CLI) application that will help to manage medication supplies within a pharmacy. It is an integrated solution that provides real-time tracking of stocks, prescriptions and orders.
+
+## Summary of Contributions
+
+Given below are my contributions to the project.
+
+Code contributed: more than 3000 lines of
+code. [[RepoSense](https://nus-cs2113-ay2122s1.github.io/tp-dashboard/?search=a-tph&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-25&tabOpen=true&tabType=authorship&tabAuthor=a-tph&tabRepo=AY2122S1-CS2113T-T10-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false)]
+
+### Features
+
+v1.0:
+
+* Implemented `updatestock` command. [[#25](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/25)]
+
+v2.0:
+
+* Implemented `updateorder` command. [[#121](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/121)]
+* Implemented `updateprescription` command. [[#184](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/184)]
+
+v2.1:
+
+* Fixed functionality and documentation bugs raised during PE. [[#296](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/296)]
+* Fixed bugs found in `updateprescription` command. [[#324](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/324)]
+* Fixed bug found in `MedicineValidator` class. [[#328](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/328)]
+
+### Enhancements to Existing Features
+
+* Implemented universal `containsInvalidParameterValues()` method. [[#40](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/40)]
+
+* Included JUnit tests for:
+ * `StockValidator` [[#59](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/59)]
+ * `MedicineManager` [[#93](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/93)]
+ * `UpdateStockCommand`, `UpdateOrderCommand` and `UpdatePrescriptionCommand` [[#316](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/316)]
+
+* Wrote and refractored `Manager` classes for `stock`, `prescription` and `order`. [[#69](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/69), [#141](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/141)]
+
+* Added functionality for `deletestock` command to delete all expired stocks. [[#135](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/135)]
+
+### Documentation
+
+* [User Guide](../UserGuide.md)
+ * Added documentation for `updatestock`, `updateprescription` and `updateorder` commands. [[#186](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/186)]
+
+* [Developer Guide](../DeveloperGuide.md)
+ * Created skeleton Developer guide for the team. [[#210](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/210)]
+ * Included [[#213](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/213), [#270](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/270)]
+ * Design
+ * Architecture and Command components with class diagram and detailed explanation.
+ * Implementation
+ * Initial validation checker sequence diagram and detailed explanation under Main Logic
+ * `UpdateStockCommand`, `UpdatePrescriptionCommand` and `UpdateOrderCommand` sequence diagrams and detailed
+ explanation.
+
+### Team-Based
+
+* Created and contributed to [Trello](https://trello.com/b/nMVm0vgz/cs2113t-user-stories) dashboard.
+* Attended weekly team meetings.
+* Contributed to release managements.
+* Ensured UG and DG has a consistent format.
+* Pull Requests reviewed with non-trivial review comments. [[#171](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/171), [#295](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/295)]
+
+### Community
+
+* Reported bugs and provided suggestions for other teams in the class. [[#1](https://github.com/a-tph/ped/issues/1), [#2](https://github.com/a-tph/ped/issues/2), [#3](https://github.com/a-tph/ped/issues/3), [#4](https://github.com/a-tph/ped/issues/4), [#5](https://github.com/a-tph/ped/issues/5)]
\ No newline at end of file
diff --git a/docs/team/alvintan01.md b/docs/team/alvintan01.md
new file mode 100644
index 0000000000..4bbffc37b5
--- /dev/null
+++ b/docs/team/alvintan01.md
@@ -0,0 +1,68 @@
+# Alvin Tan Guo Hao - Project Portfolio Page
+
+This is a student project for a university software development course and I am one of the contributors to `MediVault`.
+
+`MediVault` is a Command Line Interface (CLI) application that will help to manage medication supplies within a pharmacy.
+It is an integrated solution that provides real-time tracking of stocks, prescriptions and orders.
+
+## Summary of Contributions
+
+Given below are my contributions to the project.
+
+Code contributed: more than 4000 lines of
+code. [[RepoSense](https://nus-cs2113-ay2122s1.github.io/tp-dashboard/?search=alvintan01&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-25&tabOpen=true&tabType=authorship&tabAuthor=alvintan01&tabRepo=AY2122S1-CS2113T-T10-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false)]
+
+### Features
+
+v1.0 tasks:
+
+- Implemented skeleton code for MediVault. [[#10](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/10)]
+- Implemented `Ui` class for MediVault. [[#10](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/10)]
+- Implemented sort for `liststock` command. [[#45](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/45)]
+- Implemented `exit`, `purge` and `help` command. [[#10](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/10), [#13](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/13), [#45](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/45)]
+
+v2.0 tasks:
+
+- Implemented `listprescription` command. [[#181](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/181)]
+- Implemented `receiveorder` command. [[#208](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/208)]
+- Implemented sort for `listorder` command and mode feature. [[#162](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/162), [#123](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/123)]
+
+v2.1 tasks:
+
+- Fixed bug where ID does not reset after `purge`, `receiveorder` does not mark an order as delivered and whitespace renders command invalid. [[#280](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/280)]
+- Demo video for stock features.
+
+### Enhancements to Existing Features
+
+- Added order quantity to `liststock` command. [[#109](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/109)]
+- Refactor `HashMap` to `LinkedHashMap`. [[#123](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/123)]
+- Refactor `command` objects. [[#133](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/133)]
+- Refactor `Dispense` to `Prescription` [[#208](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/208)]
+- Included JUnit tests for `CommandParser`, `ListPrescription`, `Help`, `Purge` and sort for `ListOrder` and `ListStock`. [[#92](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/92), [#305](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/305)]
+
+### Documentation
+
+- [User Guide](../UserGuide.md)
+ - Added documentation for `mode`, `purge`, `exit`, `help`, `listprescription` and `receiveorder`. [[#97](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/97), [#208](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/208)]
+ - Added command summary. [[#97](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/97)]
+ - Reordered the sections into add, list, delete and update. [[#229](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/229)]
+ - Added glossary section [[#309](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/309)]
+
+- [Developer Guide](../DeveloperGuide.md)
+ - Design
+ - Main application logic and explanation. [[#163](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/163)]
+ - Validator class diagram and explanation. [[#198](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/198)]
+ - Inventory class diagram and explanation. [[#198](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/198)]
+ - Sections on `list` and `receiveorder` and their respective sequence diagrams. [[#163](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/163), [#223](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/223)]
+
+### Team-Based
+- Setting up the GitHub team org/repo.
+- Assigning user stories to team members.
+- Maintaining [Trello](https://trello.com/b/nMVm0vgz/cs2113t-user-stories) dashboard.
+- Hosting weekly team meetings.
+- Release management.
+- Ensured UG and DG has a consistent format.
+- Pull Requests reviewed with non-trivial review comments. [[#74](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/74), [#143](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/143), [#172](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/172)]
+
+### Community
+- Reported bugs and suggestions for other teams in the class. [[#1](https://github.com/alvintan01/ped/issues/1), [#2](https://github.com/alvintan01/ped/issues/2), [#3](https://github.com/alvintan01/ped/issues/3), [#4](https://github.com/alvintan01/ped/issues/4), [#5](https://github.com/alvintan01/ped/issues/5), [#6](https://github.com/alvintan01/ped/issues/6), [#7](https://github.com/alvintan01/ped/issues/7), [#8](https://github.com/alvintan01/ped/issues/8), [#9](https://github.com/alvintan01/ped/issues/9), [#10](https://github.com/alvintan01/ped/issues/10)]
diff --git a/docs/team/deonchung.md b/docs/team/deonchung.md
new file mode 100644
index 0000000000..7d65e5d75e
--- /dev/null
+++ b/docs/team/deonchung.md
@@ -0,0 +1,69 @@
+# Deon Chung Hui - Project Portfolio Page
+
+This is a student project for a university software development course and I am one of the contributors to `MediVault`.
+
+`MediVault` is a Command Line Interface (CLI) application that will help to manage medication supplies within a pharmacy.
+It is an integrated solution that provides real-time tracking of stocks, prescriptions and orders.
+
+## Summary of Contributions
+
+Given below are my contributions to the project.
+
+Code contributed: more than 2300 lines of
+code. [RepoSense](https://nus-cs2113-ay2122s1.github.io/tp-dashboard/?search=deonchung&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-25)
+### Features
+
+v1.0:
+
+* Implemented `addstock` command. [[#23](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/23)]
+
+v2.0:
+
+* Implemented `addprescription` command. [[#74](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/74)]
+* Implemented `deleteprescription` command. [[#147](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/147)]
+* Implemented `deleteorder` command. [[#119](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/119)]
+
+v2.1:
+
+* Fix bug in `addstock` where maximum quantity can be exceeded if the same medication with the same expiry date is added. [[#255](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/255)]
+* Fix bug in `addprescription` where expired medication can be prescribed. [[#295](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/295)]
+* Fix bug in `addprescription` where the wrong error message is shown. [[#306](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/306)]
+* Demo video for prescription features.
+
+### Enhancements to Existing Features
+
+* Implemented `Prescription Validator` method. [[#86](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/86)]
+
+* Implemented `Order Validator` method. [[#119](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/119)]
+
+* Implemented `getNotExpiredStockQuantity` method in `PrescriptionManager`. [[#295](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/295)]
+
+* Added functionality for `addstock` command to limit number of medication for stock. [[#42](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/42)]
+
+* Included JUnit tests for:
+ * `Prescription Validator` and `Order Validator` class. [[#89](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/89) , [#140](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/140)]
+ * `AddStock`, `AddPrescription`, `DeletePrescription` and `DeleteStock`. [[#306](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/306)]
+
+### Documentation
+
+* [User Guide](../UserGuide.md)
+ * Added documentation for `addstock`, `addprescription`, `deleteprescription` and `deleteorder` commands. [[#96](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/96) , [#171](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/171)]
+
+* [Developer Guide](../DeveloperGuide.md)
+ * Acknowledgement. [[#194](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/194)]
+ * Setting up environment. [[#194](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/194)]
+ * Section on `addstock`, `addprescription` ,`deleteprescription` and `UpdateOrderCommand` and their respective sequence diagrams. [[#171](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/171)]
+ * User stories. [[#255](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/255)]
+ * Instruction for manual testing. [[#258](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/258)]
+
+### Team-Based
+
+* Attended all weekly team meetings.
+* Documentation of acknowledgement, setting up environment, user stories and instruction for manual testing in DG.
+* Pull Requests reviewed with non-trivial review comments [[#298](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/298)].
+
+### Community
+
+* Reported bugs and suggestions for other teams in the class. [[#1](https://github.com/deonchung/ped/issues/1), [#2](https://github.com/deonchung/ped/issues/2),
+ [#3](https://github.com/deonchung/ped/issues/3), [#4](https://github.com/deonchung/ped/issues/4), [#5](https://github.com/deonchung/ped/issues/5),
+ [#6](https://github.com/deonchung/ped/issues/6), [#7](https://github.com/deonchung/ped/issues/7)]
diff --git a/docs/team/jiangweichen835.md b/docs/team/jiangweichen835.md
new file mode 100644
index 0000000000..0e78dc2fd3
--- /dev/null
+++ b/docs/team/jiangweichen835.md
@@ -0,0 +1,71 @@
+# Jiang Weichen - Project Portfolio Page
+
+This is a student project for a university software development course and I am one of the contributors to `MediVault`.
+
+`MediVault` is a Command Line Interface (CLI) application that will help to manage medication
+supplies within a pharmacy. It is an integrated solution that provides real-time tracking of
+stocks, prescriptions and orders.
+
+## Summary of Contributions
+
+Given below are my contributions to the project.
+
+Code contributed: more than 1000 lines of
+code. [[RepoSense](https://nus-cs2113-ay2122s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-25&tabOpen=true&tabType=authorship&tabAuthor=jiangweichen835&tabRepo=AY2122S1-CS2113T-T10-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false)]
+### Features
+
+#### v1.0:
+
+* Implemented listing by medicine name and description to `liststock` command.
+ * Functionality: Users are able to search for medicine with one command.
+ * Justification: Users will be able to search for medicine by name or description.
+ * Pull request: [[#26](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/26)]
+
+#### v2.0:
+
+* Implemented `addorder` command.
+ * Functionality: Users are able to add order for medicine with one command.
+ * Justification: Users will be able to add medication's name, quantity and order date using a single command.
+ * Pull request: [[#139](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/139)]
+
+#### v2.1:
+
+* Fixed bug in `addorder` for medicine exist in stock but not in order
+ * Functionality: `addorder` should check for order quantity of first order of medicine that exists in stock.
+ * Justification: To prevent users from exceeding existing stock maximum quantity allowed.
+ * Pull request: [[#308](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/308)]
+* Demo video for order features
+
+### Enhancements to Existing Features
+
+* Included JUnit tests for:
+ * `StockValidator` and `MedicineValidator` class
+ * Pull request: [[#91](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/91)]
+ * `ListStockCommand` class and `AddOrderCommand` class
+ * Pull request: [[#308](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/308)]
+
+* Added functionality to `addorder` command to set order date as optional and limit order quantity
+ * Functionality: User will not be able to add order if total existing quantity in stock and order quantity exceeds maximum quantity.
+ Order date will be set as the date when user placed the order if order parameter not given.
+ * Pull request: [[#172](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/172)]
+
+### Documentation
+
+* [User Guide](../UserGuide.md)
+ * Added documentations for `liststock` and `addorder` commands
+ * Pull request: [[#99](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/99)
+ , [#188](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/188)]
+
+* [Developer Guide](../DeveloperGuide.md)
+ * Implementation
+ * `addorder` sequence diagram and detailed explanation.
+ * Pull request: [[#174](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/174)]
+
+### Team-Based
+
+* Attended weekly team meetings.
+
+### Community
+
+* Reported bugs and suggestions for other teams in the class. [[#1](https://github.com/jiangweichen835/ped/issues/1), [#2](https://github.com/jiangweichen835/ped/issues/2),
+[#3](https://github.com/jiangweichen835/ped/issues/3), [#4](https://github.com/jiangweichen835/ped/issues/4), [#5](https://github.com/jiangweichen835/ped/issues/5)]
\ No newline at end of file
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index ab75b391b8..0000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# John Doe - Project Portfolio Page
-
-## Overview
-
-
-### Summary of Contributions
diff --git a/docs/team/remusteo.md b/docs/team/remusteo.md
new file mode 100644
index 0000000000..369e027d31
--- /dev/null
+++ b/docs/team/remusteo.md
@@ -0,0 +1,77 @@
+# Teo Chin Kai Remus - Project Portfolio Page
+
+This is a student project for a university software development course and I am one of the contributors to `MediVault`.
+
+`MediVault` is a Command Line Interface (CLI) application that will help to manage medication supplies within a pharmacy. It is an integrated solution that provides real-time tracking of stocks, prescriptions and orders.
+
+## Summary of Contributions
+
+Given below are my contributions to the project.
+
+Code contributed: more than 2400 lines of code. [[RepoSense](https://nus-cs2113-ay2122s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-25&tabOpen=true&tabType=authorship&tabAuthor=RemusTeo&tabRepo=AY2122S1-CS2113T-T10-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false)]
+
+### Features
+
+#### v1.0:
+
+* Implemented `deletestock` command. [[#19](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/19)]
+* Implemented `help` command. [[#27](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/27)]
+
+#### v2.0:
+
+* Implemented `listorder` command. [[#116](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/116), [#134](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/134), [#178](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/178)]
+* Implemented `Storage` class. [[#127](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/127), [#183](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/183)]
+* Implemented `FileParser` class. [[#154](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/154), [#200](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/200)]
+* Implemented `archiveprescription` and `archiveorder` command. [[#193](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/193), [#226](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/226)]
+
+#### v2.1:
+
+* Fix bug for `archive*` commands where time affected exact date matching. [[#222](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/222/files)]
+* Improved `archiveorder` and `archiveprescription` commands. [[#297](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/297)]
+* Standardized data in storage and archive to Upper Case for consistency. [[#314](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/314)]
+
+### Enhancements to Existing Features
+
+* Added checking for existing stock in `StockValidator isValidStockId()` method. [[#19](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/19)]
+* Included JUnit tests:
+ * `isValidStockId()`. [[#55](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/55)]
+ * `DateParserTest`. [[#90](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/90), [#125](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/125), [#304](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/304)]
+ * `DeleteStockCommandTest`. [[#304](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/304)]
+ * `ListOrderCommandTest`, `ArchiveOrderCommandTest`, `ArchivePrescriptionCommandTest`. [[#314](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/314)]
+* Refactor all usage of `stockID` to `stockId` to maintain consistency with `orderId` and `prescriptionId`. [[#200](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/200)]
+* Implemented `removeTime()` method in `DateParser`. [[#222](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/222)]
+
+### Documentation
+
+* [User Guide](../UserGuide.md)
+ * Added documentation for `deletestock`, `listorder`, `archiveorder`, `archiveprescription` commands
+ . [[#101](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/101), [#176](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/176), [#202](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/202), [#228](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/228)]
+ * Added documentation for `Data Storage`, `Data Editing`, `FAQ` sections in UG
+ . [[#202](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/202)]
+ * Added documentation for `Purpose` section in UG
+ . [[#294](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/294)]
+
+
+* [Developer Guide](../DeveloperGuide.md)
+ * Section on `Storage` component
+ . [[#282](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/282)]
+ * Sections on `DeleteStockCommand`, `ArchivePrescriptionCommand`, `ArchiveOrderCommand`
+ . [[#219](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/219), [#274](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/274)]
+ * Value Proposition & Non Functional Requirements
+ . [[#266](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/266)]
+ * Instructions for Automated Testing
+ . [[#317](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/317)]
+
+### Team-Based
+
+* Attended all team meetings
+* Documentation of the Purpose & FAQ in UG.
+* Documentation of Value Proposition & NFRs & Automated Testing in DG.
+* Providing feedback and communication with TA for advice on sequence diagrams in DG.
+* Github pages emoji plugin.
+* Pull Requests reviewed with non-trivial review comments
+ . [[#45](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/45), [#99](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/99), [#204](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/204), [#211](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/211), [#280](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/280), [#316](https://github.com/AY2122S1-CS2113T-T10-1/tp/pull/316)]
+
+### Community
+
+* Reported bugs and suggestions for other teams in the class [[#1](https://github.com/RemusTeo/ped/issues/1), [#2](https://github.com/RemusTeo/ped/issues/2), [#3](https://github.com/RemusTeo/ped/issues/3), [#4](https://github.com/RemusTeo/ped/issues/4), [#5](https://github.com/RemusTeo/ped/issues/5), [#6](https://github.com/RemusTeo/ped/issues/6), [#7](https://github.com/RemusTeo/ped/issues/7), [#8](https://github.com/RemusTeo/ped/issues/8)]
\ No newline at end of file
diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..535d7121f2
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: MediVault
+
diff --git a/src/main/java/MediVault.java b/src/main/java/MediVault.java
new file mode 100644
index 0000000000..6cfc677529
--- /dev/null
+++ b/src/main/java/MediVault.java
@@ -0,0 +1,83 @@
+import command.Command;
+import command.CommandList;
+import errors.InvalidCommandException;
+import inventory.Medicine;
+import utilities.parser.CommandParser;
+import utilities.parser.Mode;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+import static utilities.parser.Mode.ORDER;
+import static utilities.parser.Mode.PRESCRIPTION;
+import static utilities.parser.Mode.STOCK;
+
+//@@author alvintan01
+
+/**
+ * Helps to start the application, and initialise all variables.
+ * It will continuously prompt for input from the user until "EXIT" is received.
+ */
+public class MediVault {
+ private static Logger logger = Logger.getLogger("MediVault");
+ private Mode mode = Mode.STOCK;
+
+ public MediVault() {
+ ArrayList medicines = Medicine.getInstance();
+ Storage storage = Storage.getInstance();
+ medicines.addAll(storage.loadData());
+ logger.log(Level.INFO, "All variables are initialised.");
+ }
+
+ public static void main(String[] args) {
+ LogManager.getLogManager().reset();
+ logger.log(Level.INFO, "MediVault is starting up");
+ new MediVault().run();
+ }
+
+ /**
+ * Prompts input from user and processes it indefinitely until "EXIT" is received.
+ */
+ private void run() {
+ Ui ui = Ui.getInstance();
+ ui.printWelcomeMessage();
+ CommandParser commandParser = new CommandParser();
+
+ String userInput = "";
+
+ // Loops till exit is received
+ while (true) {
+ System.out.print("[" + mode + "] > ");
+ // Reads user input
+ userInput = ui.getInput();
+ try {
+ String[] userCommand = commandParser.parseCommand(userInput);
+ String commandString = userCommand[0];
+ String commandParameters = userCommand[1];
+
+ // Check is user is changing modes
+ if (commandString.equalsIgnoreCase(STOCK.name()) || commandString.equalsIgnoreCase(PRESCRIPTION.name())
+ || commandString.equalsIgnoreCase(ORDER.name())) {
+ mode = commandParser.changeMode(ui, commandString, mode);
+ continue;
+ }
+
+ Command command = commandParser.processCommand(commandString, commandParameters, mode);
+ command.execute();
+
+ if (commandString.equals(CommandList.EXIT)) { // User entered exit
+ break;
+ }
+ } catch (InvalidCommandException e) {
+ // Invalid Command
+ ui.printInvalidCommandMessage();
+ logger.log(Level.WARNING, "An invalid command was entered!");
+ }
+ }
+ logger.log(Level.INFO, "MediVault is shutting down");
+ }
+}
diff --git a/src/main/java/command/Command.java b/src/main/java/command/Command.java
new file mode 100644
index 0000000000..6ad3847e8d
--- /dev/null
+++ b/src/main/java/command/Command.java
@@ -0,0 +1,12 @@
+package command;
+
+import java.util.LinkedHashMap;
+
+/**
+ * Represents the generic command. Helps to declare the abstract methods. It is inherited by all commands.
+ */
+public abstract class Command {
+ protected LinkedHashMap parameters;
+
+ public abstract void execute();
+}
diff --git a/src/main/java/command/CommandList.java b/src/main/java/command/CommandList.java
new file mode 100644
index 0000000000..ab8509eb38
--- /dev/null
+++ b/src/main/java/command/CommandList.java
@@ -0,0 +1,31 @@
+package command;
+
+/**
+ * Represents all the commands available in the application.
+ */
+public class CommandList {
+ public static final String ADD = "add";
+ public static final String ADD_PRESCRIPTION = "addprescription";
+ public static final String ADD_STOCK = "addstock";
+ public static final String ADD_ORDER = "addorder";
+ public static final String ARCHIVE = "archive";
+ public static final String ARCHIVE_ORDER = "archiveorder";
+ public static final String ARCHIVE_PRESCRIPTION = "archiveprescription";
+ public static final String DELETE = "delete";
+ public static final String DELETE_PRESCRIPTION = "deleteprescription";
+ public static final String DELETE_STOCK = "deletestock";
+ public static final String DELETE_ORDER = "deleteorder";
+ public static final String EXIT = "exit";
+ public static final String HELP = "help";
+ public static final String LIST = "list";
+ public static final String LIST_PRESCRIPTION = "listprescription";
+ public static final String LIST_STOCK = "liststock";
+ public static final String LIST_ORDER = "listorder";
+ public static final String PURGE = "purge";
+ public static final String RECEIVE = "receive";
+ public static final String RECEIVE_ORDER = "receiveorder";
+ public static final String UPDATE = "update";
+ public static final String UPDATE_STOCK = "updatestock";
+ public static final String UPDATE_PRESCRIPTION = "updateprescription";
+ public static final String UPDATE_ORDER = "updateorder";
+}
diff --git a/src/main/java/command/CommandParameters.java b/src/main/java/command/CommandParameters.java
new file mode 100644
index 0000000000..95bb39a7f6
--- /dev/null
+++ b/src/main/java/command/CommandParameters.java
@@ -0,0 +1,23 @@
+package command;
+
+/**
+ * Represents all the commands parameters used in the application.
+ */
+public class CommandParameters {
+ public static final String CUSTOMER_ID = "c";
+ public static final String DATE = "d";
+ public static final String DESCRIPTION = "d";
+ public static final String EXPIRING = "expiring";
+ public static final String EXPIRY_DATE = "e";
+ public static final String ID = "i";
+ public static final String MAX_QUANTITY = "m";
+ public static final String NAME = "n";
+ public static final String PRICE = "p";
+ public static final String LOW = "low";
+ public static final String QUANTITY = "q";
+ public static final String REVERSED_SORT = "rsort";
+ public static final String SORT = "sort";
+ public static final String STAFF = "s";
+ public static final String STATUS = "s";
+ public static final String STOCK_ID = "sid";
+}
diff --git a/src/main/java/command/CommandSyntax.java b/src/main/java/command/CommandSyntax.java
new file mode 100644
index 0000000000..b5a88affbb
--- /dev/null
+++ b/src/main/java/command/CommandSyntax.java
@@ -0,0 +1,64 @@
+package command;
+
+/**
+ * Contains all the valid command syntax accepted by the application. Also contains methods to validate if the
+ * parameter and its value is valid for a given command.
+ */
+public class CommandSyntax {
+ private String commandName;
+ private String commandSyntax;
+ public static final String COMMAND = "COMMAND";
+ public static final String COMMAND_SYNTAX = "COMMAND SYNTAX";
+ public static final String[] COLUMNS = {COMMAND, COMMAND_SYNTAX};
+ public static final int NO_OF_COLUMNS = 2;
+
+ public static final String ADD_PRESCRIPTION_COMMAND = "addprescription n/NAME q/QUANTITY c/CUSTOMER_ID "
+ + "s/STAFF_NAME";
+ public static final String ADD_STOCK_COMMAND = "addstock n/NAME p/PRICE q/QUANTITY e/EXPIRY_DATE "
+ + "(d/DESCRIPTION m/MAX_QUANTITY)";
+ public static final String ADD_ORDER_COMMAND = "addorder n/NAME q/QUANTITY {d/DATE}";
+ public static final String ARCHIVE_PRESCRIPTION_COMMAND = "archiveprescription d/DATE";
+ public static final String ARCHIVE_ORDER_COMMAND = "archiveorder d/DATE";
+ public static final String DELETE_STOCK_COMMAND = "deletestock [i/ID expiring/EXPIRY_DATE]";
+ public static final String DELETE_ORDER_COMMAND = "deleteorder i/ID";
+ public static final String DELETE_PRESCRIPTION_COMMAND = "deleteprescription i/ID";
+ public static final String EXIT_COMMAND = "exit";
+ public static final String HELP_COMMAND = "help";
+ public static final String LIST_PRESCRIPTION_COMMAND = "listprescription {i/ID n/NAME q/QUANTITY c/CUSTOMER_ID "
+ + "d/DATE s/STAFF_NAME sid/STOCK_ID sort/COLUMN_NAME rsort/COLUMN_NAME}";
+ public static final String LIST_ORDER_COMMAND = "listorder {i/ID n/NAME q/QUANTITY d/DATE s/STATUS "
+ + "sort/COLUMN_NAME rsort/COLUMN_NAME}";
+ public static final String LIST_STOCK_COMMAND = "liststock {i/ID n/NAME p/PRICE q/QUANTITY"
+ + "low/LESS_THAN_OR_EQUAL_QUANTITY e/EXPIRY_DATE expiring/LESS_THAN_OR_EQUAL_EXPIRY_DATE "
+ + "d/DESCRIPTION m/MAX_QUANTITY sort/COLUMN_NAME rsort/COLUMN_NAME}";
+ public static final String PURGE_COMMAND = "purge";
+ public static final String RECEIVE_ORDER_COMMAND = "receiveorder i/ID p/PRICE e/EXPIRY_DATE (d/DESCRIPTION "
+ + "m/MAX_QUANTITY)";
+ public static final String UPDATE_PRESCRIPTION_COMMAND = "updateprescription i/ID [n/NAME q/QUANTITY c/CUSTOMER_ID "
+ + "d/DATE s/STAFF_NAME]";
+ public static final String UPDATE_ORDER_COMMAND = "updateorder i/ID [n/NAME q/QUANTITY d/DATE]";
+ public static final String UPDATE_STOCK_COMMAND = "updatestock i/ID [n/NAME p/PRICE q/QUANTITY e/EXPIRY_DATE "
+ + "d/DESCRIPTION m/MAX_QUANTITY]";
+
+ public CommandSyntax(String commandName, String commandSyntax) {
+ this.commandName = commandName;
+ this.commandSyntax = commandSyntax;
+ }
+
+ public String getCommandName() {
+ return commandName;
+ }
+
+ public void setCommandName(String commandName) {
+ this.commandName = commandName;
+ }
+
+ public String getCommandSyntax() {
+ return commandSyntax;
+ }
+
+ public void setCommandSyntax(String commandSyntax) {
+ this.commandSyntax = commandSyntax;
+ }
+
+}
diff --git a/src/main/java/command/ExitCommand.java b/src/main/java/command/ExitCommand.java
new file mode 100644
index 0000000000..52f728ea7f
--- /dev/null
+++ b/src/main/java/command/ExitCommand.java
@@ -0,0 +1,25 @@
+package command;
+
+import inventory.Medicine;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.util.ArrayList;
+
+//@@author alvintan01
+
+/**
+ * Helps to process the exit command and prints the exit message.
+ */
+public class ExitCommand extends Command {
+
+ @Override
+ public void execute() {
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+ Storage storage = Storage.getInstance();
+
+ storage.saveData(medicines);
+ ui.printExit();
+ }
+}
diff --git a/src/main/java/command/HelpCommand.java b/src/main/java/command/HelpCommand.java
new file mode 100644
index 0000000000..9061b44d5b
--- /dev/null
+++ b/src/main/java/command/HelpCommand.java
@@ -0,0 +1,45 @@
+package command;
+
+import utilities.ui.Ui;
+
+import java.util.ArrayList;
+
+//@@author alvintan01
+
+/**
+ * Display help message containing command usage information.
+ */
+public class HelpCommand extends Command {
+
+ @Override
+ public void execute() {
+ ArrayList commandSyntaxes = new ArrayList<>();
+ commandSyntaxes.add(new CommandSyntax(CommandList.ADD_STOCK, CommandSyntax.ADD_STOCK_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.DELETE_STOCK, CommandSyntax.DELETE_STOCK_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.UPDATE_STOCK, CommandSyntax.UPDATE_STOCK_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.LIST_STOCK, CommandSyntax.LIST_STOCK_COMMAND));
+
+ commandSyntaxes.add(new CommandSyntax(CommandList.ADD_PRESCRIPTION, CommandSyntax.ADD_PRESCRIPTION_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.DELETE_PRESCRIPTION,
+ CommandSyntax.DELETE_PRESCRIPTION_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.UPDATE_PRESCRIPTION,
+ CommandSyntax.UPDATE_PRESCRIPTION_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.LIST_PRESCRIPTION, CommandSyntax.LIST_PRESCRIPTION_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.ARCHIVE_PRESCRIPTION,
+ CommandSyntax.ARCHIVE_PRESCRIPTION_COMMAND));
+
+ commandSyntaxes.add(new CommandSyntax(CommandList.ADD_ORDER, CommandSyntax.ADD_ORDER_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.DELETE_ORDER, CommandSyntax.DELETE_ORDER_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.UPDATE_ORDER, CommandSyntax.UPDATE_ORDER_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.LIST_ORDER, CommandSyntax.LIST_ORDER_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.ARCHIVE_ORDER, CommandSyntax.ARCHIVE_ORDER_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.RECEIVE_ORDER, CommandSyntax.RECEIVE_ORDER_COMMAND));
+
+ commandSyntaxes.add(new CommandSyntax(CommandList.PURGE, CommandSyntax.PURGE_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.HELP, CommandSyntax.HELP_COMMAND));
+ commandSyntaxes.add(new CommandSyntax(CommandList.EXIT, CommandSyntax.EXIT_COMMAND));
+
+ Ui ui = Ui.getInstance();
+ ui.printHelpMessage(commandSyntaxes);
+ }
+}
diff --git a/src/main/java/command/PurgeCommand.java b/src/main/java/command/PurgeCommand.java
new file mode 100644
index 0000000000..29cdcf24bb
--- /dev/null
+++ b/src/main/java/command/PurgeCommand.java
@@ -0,0 +1,39 @@
+package command;
+
+import inventory.Medicine;
+import inventory.Order;
+import inventory.Prescription;
+import inventory.Stock;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+
+//@@author alvintan01
+
+/**
+ * Helps to process the purge command and prompts the user for confirmation.
+ */
+public class PurgeCommand extends Command {
+ @Override
+ public void execute() {
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+ Storage storage = Storage.getInstance();
+
+ ui.print("Are you sure you want to delete all data? (Y/N)");
+ Scanner in = new Scanner(System.in);
+ if ("Y".equals(in.nextLine())) {
+ medicines.clear();
+ // Reset the IDs for Stock, Prescription and Orders
+ Stock.setStockCount(0);
+ Prescription.setPrescriptionCount(0);
+ Order.setOrderCount(0);
+ ui.print("All data has been cleared!");
+ storage.saveData(medicines);
+ } else {
+ ui.print("Purge aborted!");
+ }
+ }
+}
diff --git a/src/main/java/command/order/AddOrderCommand.java b/src/main/java/command/order/AddOrderCommand.java
new file mode 100644
index 0000000000..cbfe6c339b
--- /dev/null
+++ b/src/main/java/command/order/AddOrderCommand.java
@@ -0,0 +1,183 @@
+package command.order;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Order;
+import inventory.Stock;
+import utilities.parser.DateParser;
+import utilities.parser.OrderManager;
+import utilities.parser.OrderValidator;
+import utilities.parser.StockManager;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author jiangweichen835
+
+/**
+ * Add order for medication based on user input.
+ * User input include medication name, quantity and the order date.
+ */
+public class AddOrderCommand extends Command {
+ private static Logger logger = Logger.getLogger("AddOrder");
+
+ public AddOrderCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start addition of orders");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+ String[] requiredParameters = {CommandParameters.NAME, CommandParameters.QUANTITY};
+ String[] optionalParameter = {CommandParameters.DATE};
+
+ OrderValidator orderValidator = new OrderValidator();
+ if (checkValidParameterValues(ui, parameters, medicines, requiredParameters, optionalParameter,
+ orderValidator)) {
+ return;
+ }
+
+ boolean nameExistsInOrder = false;
+ boolean nameExistsInStock = false;
+ String nameToAdd = parameters.get(CommandParameters.NAME);
+ String quantityToAdd = parameters.get(CommandParameters.QUANTITY);
+ int orderQuantity = Integer.parseInt(quantityToAdd);
+ String dateToAdd = parameters.get(CommandParameters.DATE);
+ int maxQuantity = Integer.MAX_VALUE;
+
+ if (orderQuantity == 0) {
+ ui.print("Order Quantity cannot be 0.");
+ return;
+ }
+
+ if (parameters.containsKey(CommandParameters.NAME)) {
+ nameToAdd = parameters.get(CommandParameters.NAME);
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Order && medicine.getMedicineName().equalsIgnoreCase(nameToAdd)) {
+ nameExistsInOrder = true;
+ break;
+ }
+ }
+ }
+
+ if (parameters.containsKey(CommandParameters.NAME)) {
+ nameToAdd = parameters.get(CommandParameters.NAME);
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Stock && medicine.getMedicineName().equalsIgnoreCase(nameToAdd)
+ && !((Stock) medicine).isDeleted()) {
+ nameExistsInStock = true;
+ break;
+ }
+ }
+ }
+
+ if (nameExistsInOrder && !nameExistsInStock) {
+ if (orderQuantity < maxQuantity) {
+ addOrder(ui, medicines, nameToAdd, orderQuantity, addDate(dateToAdd));
+ }
+ } else if (nameExistsInOrder && nameExistsInStock) {
+ int existingOrdersQuantity = OrderManager.getTotalOrderQuantity(medicines, nameToAdd);
+ int existingStockQuantity = StockManager.getTotalStockQuantity(medicines, nameToAdd);
+ int totalQuantity = existingStockQuantity + existingOrdersQuantity;
+ maxQuantity = StockManager.getMaxStockQuantity(medicines, nameToAdd);
+
+ if (orderQuantity + totalQuantity <= maxQuantity) {
+ addOrder(ui, medicines, nameToAdd, orderQuantity, addDate(dateToAdd));
+ } else {
+ ui.print("Unable to add order as total order quantity exceeds maximum stock quantity of "
+ + maxQuantity + ".\nExisting quantity in stock: " + existingStockQuantity
+ + "\nPending order quantity: " + existingOrdersQuantity);
+ }
+ } else if (!nameExistsInOrder && nameExistsInStock) {
+ int existingStockQuantity = StockManager.getTotalStockQuantity(medicines, nameToAdd);
+ maxQuantity = StockManager.getMaxStockQuantity(medicines, nameToAdd);
+ if (orderQuantity + existingStockQuantity <= maxQuantity) {
+ addOrder(ui, medicines, nameToAdd, orderQuantity, addDate(dateToAdd));
+ } else {
+ ui.print("Unable to add order as total order quantity exceeds maximum stock quantity of "
+ + maxQuantity + ".\nExisting quantity in stock: " + existingStockQuantity);
+ }
+ } else {
+ addOrder(ui, medicines, nameToAdd, orderQuantity, addDate(dateToAdd));
+ }
+ }
+
+ /**
+ * Add order based on user input.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param name Medication name to order.
+ * @param quantity Quantity of medication to order.
+ * @param date Order date.
+ */
+ private void addOrder(Ui ui, ArrayList medicines, String name, int quantity, Date date) {
+ Order order = new Order(name, quantity, date);
+ medicines.add(order);
+ ui.print("Order added: " + name);
+ ui.printOrder(order);
+
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ logger.log(Level.INFO, "Successful addition of order");
+ }
+
+ /**
+ * Add date based on user input.
+ *
+ * @param dateToAdd Order date input by user (check if it is in correct date format).
+ * @return Default date or order date.
+ */
+ private Date addDate(String dateToAdd) {
+ if (dateToAdd == null) {
+ Date defaultDate = null;
+ defaultDate = new Date();
+ return defaultDate;
+ }
+
+ try {
+ Date orderDate = null;
+ orderDate = DateParser.stringToDate(dateToAdd);
+ return orderDate;
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Checks if user inputs are valid.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param parameters The parameter that is not found.
+ * @param medicines List of all medicines.
+ * @param requiredParameters The required parameters to check.
+ * @param optionalParameters The optional parameters to check.
+ * @param orderValidator Reference to OrderValidator object.
+ * @return Boolean value indicating if parameter and parameter values are valid.
+ */
+ private boolean checkValidParameterValues(Ui ui, LinkedHashMap parameters,
+ ArrayList medicines, String[] requiredParameters,
+ String[] optionalParameters, OrderValidator orderValidator) {
+ boolean isInvalidInput = orderValidator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.ADD_ORDER_COMMAND,
+ false, orderValidator);
+
+ if (isInvalidInput) {
+ logger.log(Level.WARNING, "Invalid parameter or value specified by user");
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/command/order/ArchiveOrderCommand.java b/src/main/java/command/order/ArchiveOrderCommand.java
new file mode 100644
index 0000000000..35baf77976
--- /dev/null
+++ b/src/main/java/command/order/ArchiveOrderCommand.java
@@ -0,0 +1,106 @@
+package command.order;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Order;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.OrderValidator;
+import utilities.ui.Ui;
+import utilities.storage.Storage;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author RemusTeo
+
+/**
+ * Archive orders based on user input given date.
+ */
+public class ArchiveOrderCommand extends Command {
+ private static Logger logger = Logger.getLogger("ArchiveOrder");
+
+ public ArchiveOrderCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start archiving of order");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String[] requiredParameters = {CommandParameters.DATE};
+ String[] optionalParameters = {};
+
+ MedicineValidator validator = new OrderValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.ARCHIVE_ORDER_COMMAND, true, validator);
+ if (isInvalidInput) {
+ logger.log(Level.INFO, "Unsuccessful archive of order");
+ return;
+ }
+
+ Date orderArchiveDate = null;
+ String orderArchiveDateStr = parameters.get(CommandParameters.DATE);
+ try {
+ orderArchiveDate = DateParser.stringToDate(orderArchiveDateStr);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ ArrayList filteredOrders = ordersToArchive(medicines, orderArchiveDate);
+ removeFromOrders(medicines, filteredOrders);
+
+ Storage storage = Storage.getInstance();
+ storage.archiveData(filteredOrders);
+ storage.saveData(medicines);
+ ui.print("Archived " + filteredOrders.size() + " delivered orders from "
+ + DateParser.dateToString(orderArchiveDate));
+ logger.log(Level.INFO, "Successful archive of order");
+ }
+
+ /**
+ * Checks through all orders and look for records that are DELIVERED and have order date <= specified date.
+ *
+ * @param medicines Arraylist of all medicines.
+ * @param orderArchiveDate Date that user specified to archive.
+ * @return Arraylist of orders that meet the archive requirements.
+ */
+ private ArrayList ordersToArchive(ArrayList medicines, Date orderArchiveDate) {
+ ArrayList filteredOrders = new ArrayList<>();
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Order)) {
+ continue;
+ }
+ Order order = (Order) medicine;
+ Date orderDate = DateParser.removeTime(order.getDate());
+ if (order.getStatus().equalsIgnoreCase("DELIVERED")) {
+ if (orderDate.before(orderArchiveDate) || orderDate.equals(orderArchiveDate)) {
+ filteredOrders.add(order);
+ }
+ }
+ }
+ return filteredOrders;
+ }
+
+ /**
+ * Removal of orders from order list after archive.
+ *
+ * @param medicines Arraylist of all medicines.
+ * @param filteredOrders Arraylist of orders that meet the archive requirements.
+ */
+ private void removeFromOrders(ArrayList medicines, ArrayList filteredOrders) {
+ for (Medicine medicine : filteredOrders) {
+ medicines.remove(medicine);
+ }
+ }
+}
+
diff --git a/src/main/java/command/order/DeleteOrderCommand.java b/src/main/java/command/order/DeleteOrderCommand.java
new file mode 100644
index 0000000000..f2033af416
--- /dev/null
+++ b/src/main/java/command/order/DeleteOrderCommand.java
@@ -0,0 +1,94 @@
+package command.order;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Order;
+import utilities.parser.MedicineValidator;
+import utilities.parser.OrderValidator;
+import utilities.ui.Ui;
+import utilities.storage.Storage;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author deonchung
+
+/**
+ * Delete order based on user input given order id.
+ */
+public class DeleteOrderCommand extends Command {
+ private static Logger logger = Logger.getLogger("Delete Order");
+
+ public DeleteOrderCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start deletion of order");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+ String orderIdToDelete = parameters.get(CommandParameters.ID);
+
+ if (!isValidOrderParameters(ui, medicines)) {
+ return;
+ }
+
+ int orderId = Integer.parseInt(orderIdToDelete);
+
+ assert orderId <= Order.getOrderCount() : "order Id should not exceed max order count";
+
+ for (Medicine medicine : medicines) {
+
+ if (!(medicine instanceof Order)) {
+ continue;
+ }
+
+ Order order = (Order) medicine;
+
+ if (order.getOrderId() == orderId) {
+ medicines.remove(order);
+ logger.log(Level.INFO, "Order id found and deleted");
+ break;
+ }
+ }
+
+ ui.print("Order deleted for Order ID " + orderId);
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ logger.log(Level.INFO, "Successful deletion of order");
+
+ }
+
+ /**
+ * Check if parameters values for Order are valid and if Order ID exist.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of medicines
+ * @return Boolean Value indicating if parameters values for Order are valid and Order ID exist.
+ */
+ private boolean isValidOrderParameters(Ui ui, ArrayList medicines) {
+
+ MedicineValidator validator = new OrderValidator();
+
+ String[] requiredParameters = {CommandParameters.ID};
+ String[] optionalParameters = {};
+
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.DELETE_ORDER_COMMAND, false, validator);
+
+ if (isInvalidInput) {
+ logger.log(Level.WARNING, "Invalid parameter or value specified by user");
+ logger.log(Level.INFO, "Unsuccessful deletion of order");
+ return false;
+ }
+
+ return true;
+ }
+}
+
diff --git a/src/main/java/command/order/ListOrderCommand.java b/src/main/java/command/order/ListOrderCommand.java
new file mode 100644
index 0000000000..16904d405e
--- /dev/null
+++ b/src/main/java/command/order/ListOrderCommand.java
@@ -0,0 +1,120 @@
+package command.order;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Order;
+import utilities.comparators.OrderComparator;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.OrderValidator;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+//@@author RemusTeo
+
+/**
+ * Helps to process the listorder command together with filters and sort.
+ */
+public class ListOrderCommand extends Command {
+ private static Logger logger = Logger.getLogger("ListOrder");
+
+ public ListOrderCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start listing of order records");
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String[] requiredParameters = {};
+ String[] optionalParameters = {CommandParameters.ID, CommandParameters.NAME, CommandParameters.QUANTITY,
+ CommandParameters.DATE, CommandParameters.STATUS, CommandParameters.SORT,
+ CommandParameters.REVERSED_SORT};
+
+ MedicineValidator validator = new OrderValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.LIST_ORDER_COMMAND, false, validator);
+ if (isInvalidInput) {
+ return;
+ }
+
+ ArrayList filteredOrders = new ArrayList<>();
+
+ assert (filteredOrders != null) : "Array is not initialised";
+
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Order) {
+ filteredOrders.add((Order) medicine);
+ }
+ }
+ filteredOrders = filterOrders(parameters, filteredOrders);
+
+ ui.printOrders(filteredOrders);
+ logger.log(Level.INFO, "Successful listing of order");
+ }
+
+
+ /**
+ * Helps to filter order records based on the user's input.
+ *
+ * @param parameters HashMap Key-Value set for parameter and user specified parameter value.
+ * @param filteredOrders Arraylist of Order objects.
+ * @return Arraylist of filtered Order objects based on the user's parameters values.
+ */
+ private ArrayList filterOrders(LinkedHashMap parameters, ArrayList filteredOrders) {
+ for (String parameter : parameters.keySet()) {
+ String parameterValue = parameters.get(parameter);
+ switch (parameter) {
+ case CommandParameters.ID:
+ filteredOrders = (ArrayList) filteredOrders.stream()
+ .filter((m) -> (m).getOrderId() == Integer.parseInt(parameterValue))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.NAME:
+ filteredOrders = (ArrayList) filteredOrders.stream()
+ .filter((m) -> (m.getMedicineName().toUpperCase()).contains(parameterValue.toUpperCase()))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.QUANTITY:
+ filteredOrders = (ArrayList) filteredOrders.stream().filter((m) ->
+ m.getQuantity() == Integer.parseInt(parameterValue)).collect(Collectors.toList());
+ break;
+ case CommandParameters.DATE:
+ try {
+ Date date = DateParser.stringToDate(parameterValue);
+ filteredOrders = (ArrayList) filteredOrders.stream()
+ .filter((m) -> (m).getDate().equals(date))
+ .collect(Collectors.toList());
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ break;
+ case CommandParameters.STATUS:
+ filteredOrders = (ArrayList) filteredOrders.stream()
+ .filter((m) -> (m.getStatus()).equalsIgnoreCase(parameterValue))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.SORT:
+ filteredOrders.sort(new OrderComparator(parameterValue.toLowerCase(), false));
+ break;
+ case CommandParameters.REVERSED_SORT:
+ filteredOrders.sort(new OrderComparator(parameterValue.toLowerCase(), true));
+ break;
+ default:
+ return filteredOrders;
+ }
+ }
+ return filteredOrders;
+ }
+}
diff --git a/src/main/java/command/order/ReceiveOrderCommand.java b/src/main/java/command/order/ReceiveOrderCommand.java
new file mode 100644
index 0000000000..3fa4efffa8
--- /dev/null
+++ b/src/main/java/command/order/ReceiveOrderCommand.java
@@ -0,0 +1,186 @@
+package command.order;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import command.stock.AddStockCommand;
+import inventory.Medicine;
+import inventory.Order;
+import inventory.Stock;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.OrderValidator;
+import utilities.parser.StockValidator;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author alvintan01
+
+/**
+ * Helps to add an order to stocks and mark the order as delivered.
+ */
+public class ReceiveOrderCommand extends Command {
+ private static Logger logger = Logger.getLogger("ReceiveOrder");
+
+ public ReceiveOrderCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ if (!checkOrderIdExist(ui, medicines)) {
+ return;
+ }
+ int orderId = Integer.parseInt(parameters.get(CommandParameters.ID));
+ parameters.remove(CommandParameters.ID); // Remove ID to prevent checks against stock ID
+ String name = "";
+ Order existingOrder = null;
+
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Order && ((Order) medicine).getOrderId() == orderId
+ && !((Order) medicine).isDelivered()) {
+ existingOrder = (Order) medicine; // Found existing order, add to parameters
+ name = existingOrder.getMedicineName();
+ parameters.put(CommandParameters.NAME, name);
+ parameters.put(CommandParameters.QUANTITY, String.valueOf(existingOrder.getQuantity()));
+ break;
+ }
+ }
+
+ if (!isStockParametersValid(ui, medicines, name)) {
+ return;
+ }
+
+ assert (existingOrder != null) : "Order object is not initialised!";
+ int currentQuantity = getCurrentQuantity(medicines, name);
+
+ new AddStockCommand(parameters).execute(); // Add to stock
+
+ int afterAddedQuantity = getCurrentQuantity(medicines, name);
+
+ // Check if quantity increased
+ if (afterAddedQuantity > currentQuantity) {
+ existingOrder.setDelivered();
+ }
+ }
+
+ /**
+ * Check if same medication name and expiry date exist and returns the current quantity.
+ *
+ * @param medicines Arraylist of all medicines.
+ * @param name Medication name to be searched.
+ * @return Integer value indicating the current quantity.
+ */
+ private int getCurrentQuantity(ArrayList medicines, String name) {
+ int currentQuantity = 0;
+ String expiryToAdd = parameters.get(CommandParameters.EXPIRY_DATE);
+ Date expiryDate = null;
+ try {
+ expiryDate = DateParser.stringToDate(expiryToAdd);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Stock && medicine.getMedicineName().equalsIgnoreCase(name)
+ && !((Stock) medicine).isDeleted() && ((Stock) medicine).getExpiry().equals(expiryDate)) {
+ currentQuantity = medicine.getQuantity();
+ break;
+ }
+ }
+ return currentQuantity;
+ }
+
+ /**
+ * Checks if a medication exists in stock.
+ *
+ * @param medicines Arraylist of all medicines.
+ * @param name Medication name to be searched.
+ * @return Boolean value indicating if the stock exists.
+ */
+ private boolean checkStockExist(ArrayList medicines, String name) {
+ // Search if current medication exist in stock
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Stock && medicine.getMedicineName().equalsIgnoreCase(name)
+ && !((Stock) medicine).isDeleted()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if an order ID exists and is not delivered.
+ *
+ * @param ui Reference to UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @return Boolean value indicating if order ID is valid.
+ */
+ private boolean checkOrderIdExist(Ui ui, ArrayList medicines) {
+ MedicineValidator validator = new OrderValidator();
+ String[] orderRequiredParameters = {CommandParameters.ID};
+ String[] optionalParameters = {};
+ LinkedHashMap orderParameters = new LinkedHashMap<>();
+ if (parameters.containsKey(CommandParameters.ID)) {
+ orderParameters.put(CommandParameters.ID, parameters.get(CommandParameters.ID));
+ }
+
+ boolean orderIdNotProvided = validator.containsInvalidParametersAndValues(ui, medicines, orderParameters,
+ orderRequiredParameters, optionalParameters, CommandSyntax.RECEIVE_ORDER_COMMAND, false, validator);
+ if (orderIdNotProvided) {
+ logger.log(Level.WARNING, "Order id is not specified by user!");
+ return false;
+ }
+
+ int orderId = Integer.parseInt(parameters.get(CommandParameters.ID));
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Order)) {
+ continue;
+ }
+ Order order = (Order) medicine;
+ if (order.getOrderId() == orderId) {
+ if (order.isDelivered()) {
+ ui.print("Order is already delivered!");
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Helps to ensure that the parameters values for Stock are valid.
+ *
+ * @param ui Reference to UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param name Medication name to be searched.
+ * @return Boolean value indicating if Stock parameters are valid.
+ */
+ private boolean isStockParametersValid(Ui ui, ArrayList medicines, String name) {
+ MedicineValidator validator = new StockValidator();
+ String[] requiredParameters = {CommandParameters.PRICE, CommandParameters.EXPIRY_DATE};
+ String[] optionalParameters = {};
+ if (!checkStockExist(medicines, name)) {
+ requiredParameters = new String[]{CommandParameters.PRICE, CommandParameters.EXPIRY_DATE,
+ CommandParameters.DESCRIPTION, CommandParameters.MAX_QUANTITY};
+ }
+
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.RECEIVE_ORDER_COMMAND, false, validator);
+ if (isInvalidInput) {
+ logger.log(Level.WARNING, "Invalid parameter or value specified by user");
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/command/order/UpdateOrderCommand.java b/src/main/java/command/order/UpdateOrderCommand.java
new file mode 100644
index 0000000000..52458f1e42
--- /dev/null
+++ b/src/main/java/command/order/UpdateOrderCommand.java
@@ -0,0 +1,142 @@
+package command.order;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Order;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.OrderManager;
+import utilities.parser.OrderValidator;
+import utilities.parser.StockManager;
+import utilities.parser.StockValidator;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author a-tph
+
+/**
+ * Update medication information based on user input given order id.
+ */
+public class UpdateOrderCommand extends Command {
+ private static Logger logger = Logger.getLogger("UpdateOrder");
+
+ public UpdateOrderCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start of UpdateOrder command execution.");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String[] requiredParameters = {CommandParameters.ID};
+ String[] optionalParameters = {CommandParameters.NAME, CommandParameters.QUANTITY, CommandParameters.DATE};
+
+ MedicineValidator validator = new OrderValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.UPDATE_ORDER_COMMAND, true, validator);
+ if (isInvalidInput) {
+ return;
+ }
+
+ Order order = OrderManager.extractOrderObject(parameters, medicines);
+ if (order.isDelivered()) {
+ ui.print("Update aborted! Unable to update order that has been delivered");
+ return;
+ }
+
+ int maxQuantity = StockManager.getMaxStockQuantity(medicines, order.getMedicineName());
+ assert maxQuantity >= 0 : "Max quantity must not be less than 0";
+ boolean existName = maxQuantity > 0;
+ boolean existQuantityParam = parameters.containsKey(CommandParameters.QUANTITY);
+
+ if (existName && existQuantityParam) {
+ boolean isValidQuantity = checkUpdateQuantity(ui, medicines, order, maxQuantity);
+ if (!isValidQuantity) {
+ return;
+ }
+ }
+
+ ArrayList filteredOrders = OrderManager.getFilteredOrdersByName(medicines, order.getMedicineName());
+
+ // Default value for updating all affected rows
+ int rowsAffected = filteredOrders.size();
+ if (!parameters.containsKey(CommandParameters.NAME)) {
+ filteredOrders.clear();
+ filteredOrders.add(order);
+ rowsAffected = filteredOrders.size();
+ }
+
+ setUpdatesByOrderId(filteredOrders, order);
+ ui.print("Updated! Number of rows affected: " + rowsAffected);
+ ui.printOrders(filteredOrders);
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ logger.log(Level.INFO, "End of UpdateOrder command execution.");
+ }
+
+ /**
+ * Checks if the updated order quantity exceeds the maximum quantity.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param order Order object to be updated.
+ * @param maxQuantity Maximum quantity for the provided stock.
+ * @return Boolean true if quantity given can be updated.
+ */
+ private boolean checkUpdateQuantity(Ui ui, ArrayList medicines, Order order, int maxQuantity) {
+ int totalQuantity = OrderManager.getTotalOrderQuantity(medicines, order.getMedicineName());
+ int orderQuantity = Integer.parseInt(parameters.get(CommandParameters.QUANTITY));
+ int actualTotalQuantity = totalQuantity - order.getQuantity() + orderQuantity;
+ StockValidator stockValidator = new StockValidator();
+ boolean isValidQuantity = stockValidator.quantityValidityChecker(ui, actualTotalQuantity, maxQuantity);
+ if (!isValidQuantity) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Update values provided by user for a given order id.
+ *
+ * @param filteredOrders Arraylist of filtered medicine orders.
+ * @param order Order object of the given order id.
+ */
+ private void setUpdatesByOrderId(ArrayList filteredOrders, Order order) {
+ logger.log(Level.INFO, "Attempt to update order information.");
+ for (String parameter : parameters.keySet()) {
+ String parameterValue = parameters.get(parameter);
+ switch (parameter) {
+ case CommandParameters.NAME:
+ for (Order targetOrder : filteredOrders) {
+ targetOrder.setMedicineName(parameterValue);
+ }
+ break;
+ case CommandParameters.QUANTITY:
+ order.setQuantity(Integer.parseInt(parameterValue));
+ break;
+ case CommandParameters.DATE:
+ try {
+ order.setDate(DateParser.stringToDate(parameterValue));
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ logger.log(Level.INFO, "Updated order information with given user input.");
+ }
+
+}
diff --git a/src/main/java/command/prescription/AddPrescriptionCommand.java b/src/main/java/command/prescription/AddPrescriptionCommand.java
new file mode 100644
index 0000000000..3a1ed9c249
--- /dev/null
+++ b/src/main/java/command/prescription/AddPrescriptionCommand.java
@@ -0,0 +1,198 @@
+package command.prescription;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Prescription;
+import inventory.Medicine;
+import inventory.Stock;
+import utilities.parser.MedicineValidator;
+import utilities.parser.PrescriptionValidator;
+import utilities.parser.DateParser;
+import utilities.parser.PrescriptionManager;
+import utilities.parser.StockManager;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+
+//@@author deonchung
+
+/**
+ * Prescribes medication based on user input.
+ * User input includes medication name, quantity to prescribe, Customer's NRIC and Staff name.
+ */
+public class AddPrescriptionCommand extends Command {
+
+ public AddPrescriptionCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String medicationName = parameters.get(CommandParameters.NAME);
+ String quantity = parameters.get(CommandParameters.QUANTITY);
+ String customerId = parameters.get(CommandParameters.CUSTOMER_ID);
+ String staffName = parameters.get(CommandParameters.STAFF);
+
+ String[] requiredParameters = {CommandParameters.NAME, CommandParameters.QUANTITY,
+ CommandParameters.CUSTOMER_ID, CommandParameters.STAFF};
+ String[] optionalParameters = {};
+
+ MedicineValidator validator = new PrescriptionValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.ADD_PRESCRIPTION_COMMAND, false, validator);
+ if (isInvalidInput) {
+ return;
+ }
+
+ int prescriptionQuantity = Integer.parseInt(quantity);
+ int quantityToPrescribe = prescriptionQuantity;
+
+ if (quantityToPrescribe == 0) {
+ ui.print("Prescription Quantity cannot be 0.");
+ return;
+ }
+
+ ArrayList filteredStocks = StockManager.getFilteredStocksByName(medicines, medicationName);
+
+ if (filteredStocks.isEmpty()) {
+ ui.print("Medicine not available!");
+ return;
+ }
+
+ Date prescribeDate = new Date(); //prescribe date will be today's date
+ String prescribeDateString = DateParser.dateToString(prescribeDate);
+
+ filteredStocks.sort(new utilities.comparators.StockComparator(CommandParameters.EXPIRY_DATE, false));
+
+ if (checkExpiredMedication(ui, filteredStocks, prescriptionQuantity)) {
+ return;
+ }
+
+ int totalStock = PrescriptionManager.getNotExpiredStockQuantity(medicines, medicationName, prescribeDate);
+
+ if (prescriptionQuantity > totalStock) {
+ ui.print("Unable to Prescribe! Prescription quantity is more than stock available!");
+ ui.print("Prescription quantity: " + prescriptionQuantity + " Stock available: " + totalStock);
+ return;
+ }
+
+ for (Stock stock : filteredStocks) {
+ int existingQuantity = stock.getQuantity();
+ int existingId = stock.getStockId();
+ Date existingExpiry = stock.getExpiry();
+ String expiryString = DateParser.dateToString(existingExpiry);
+
+ if (existingExpiry.after(prescribeDate) || prescribeDateString.equals(expiryString)) {
+
+ int setStockValue = 0;
+
+ if (existingQuantity == quantityToPrescribe) {
+ prescribe(ui, medicines, medicationName, customerId, staffName, existingQuantity, prescribeDate,
+ stock, existingId, existingExpiry, setStockValue);
+ return;
+ }
+
+ if (existingQuantity > quantityToPrescribe) {
+ setStockValue = existingQuantity - quantityToPrescribe;
+ prescribe(ui, medicines, medicationName, customerId, staffName, quantityToPrescribe, prescribeDate,
+ stock, existingId, existingExpiry, setStockValue);
+ return;
+ }
+
+ if (existingQuantity < prescriptionQuantity && existingQuantity != 0) {
+ quantityToPrescribe = quantityToPrescribe - existingQuantity;
+ prescribe(ui, medicines, medicationName, customerId, staffName, existingQuantity, prescribeDate,
+ stock, existingId, existingExpiry, setStockValue);
+ }
+ }
+
+ }
+
+ ui.print("Unable to Prescribe! Medicine has expired!");
+
+ }
+
+ /**
+ * Check if non-expired medication exist.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param filteredStocks List of stock sorted by expiry date.
+ * @param prescriptionQuantity Quantity to prescribe.
+ * @return Boolean Value indicating if expired medication exist.
+ */
+ private boolean checkExpiredMedication(Ui ui, ArrayList filteredStocks, int prescriptionQuantity) {
+ boolean existNonExpiredMed = false;
+ boolean noStockLeft = false;
+ for (Stock stock : filteredStocks) {
+ Date expiryDate = stock.getExpiry();
+ Date todayDate = new Date();
+
+ String todayDateString = DateParser.dateToString(todayDate);
+ String latestExpiryString = DateParser.dateToString(expiryDate);
+
+ boolean isNotExpired = expiryDate.after(todayDate) || todayDateString.equals(latestExpiryString);
+
+ if (isNotExpired && stock.getQuantity() != 0 && !(stock.isDeleted())) {
+ existNonExpiredMed = true;
+ }
+ if (isNotExpired && stock.getQuantity() == 0 && !(stock.isDeleted())) {
+ noStockLeft = true;
+ }
+ }
+
+ if (noStockLeft) {
+ ui.print("Unable to Prescribe! Prescription quantity is more than stock available!");
+ ui.print("Prescription quantity: " + prescriptionQuantity + " Stock available: 0");
+ return true;
+ }
+
+ if (!existNonExpiredMed) {
+ ui.print("Unable to Prescribe! Medication has expired!");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Change the stock quantity based on prescription quantity. Add prescribed medication to prescription list.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param medicationName Medication to prescribe.
+ * @param customerId Customer ID whom medicine will be prescribed to.
+ * @param staffName Staff who prescribe the medication.
+ * @param quantityToPrescribe Quantity of medication to prescribe.
+ * @param prescribeDate Date which medication is prescribed
+ * @param stock Stock object of the given stock id.
+ * @param existingId Existing id of the stock object.
+ * @param existingExpiry Existing expiry of the stock object.
+ * @param setStockValue Stock quantity to set to after prescription.
+ */
+ private void prescribe(Ui ui, ArrayList medicines, String medicationName, String customerId,
+ String staffName, int quantityToPrescribe, Date prescribeDate, Stock stock,
+ int existingId, Date existingExpiry, int setStockValue) {
+ String expiry = DateParser.dateToString(existingExpiry);
+ stock.setQuantity(setStockValue);
+ Prescription prescription = new Prescription(medicationName, quantityToPrescribe, customerId, prescribeDate,
+ staffName, existingId);
+ medicines.add(prescription);
+ ui.print("Prescribed:" + medicationName + " Quantity:" + quantityToPrescribe + " Expiry "
+ + "Date:" + expiry);
+ ui.printPrescription(prescription);
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ }
+
+}
+
+
+
+
+
diff --git a/src/main/java/command/prescription/ArchivePrescriptionCommand.java b/src/main/java/command/prescription/ArchivePrescriptionCommand.java
new file mode 100644
index 0000000000..cd891b27a3
--- /dev/null
+++ b/src/main/java/command/prescription/ArchivePrescriptionCommand.java
@@ -0,0 +1,106 @@
+package command.prescription;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Prescription;
+import inventory.Medicine;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.OrderValidator;
+import utilities.parser.PrescriptionValidator;
+import utilities.ui.Ui;
+import utilities.storage.Storage;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author RemusTeo
+
+/**
+ * Archive prescription based on user input given date.
+ */
+public class ArchivePrescriptionCommand extends Command {
+ private static Logger logger = Logger.getLogger("ArchivePrescription");
+
+ public ArchivePrescriptionCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start archiving of prescription");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String[] requiredParameters = {CommandParameters.DATE};
+ String[] optionalParameters = {};
+
+ MedicineValidator validator = new PrescriptionValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.ARCHIVE_PRESCRIPTION_COMMAND, true, validator);
+ if (isInvalidInput) {
+ logger.log(Level.INFO, "Unsuccessful archive of prescription");
+ return;
+ }
+
+ Date prescriptionArchiveDate = null;
+ String prescriptionArchiveDateStr = parameters.get(CommandParameters.DATE);
+ try {
+ prescriptionArchiveDate = DateParser.stringToDate(prescriptionArchiveDateStr);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ ArrayList filteredPrescriptions = prescriptionsToArchive(medicines, prescriptionArchiveDate);
+ removeFromPrescriptions(medicines, filteredPrescriptions);
+
+ Storage storage = Storage.getInstance();
+ storage.archiveData(filteredPrescriptions);
+ storage.saveData(medicines);
+ ui.print("Archived " + filteredPrescriptions.size() + " prescriptions from "
+ + DateParser.dateToString(prescriptionArchiveDate));
+ logger.log(Level.INFO, "Successful archive of prescriptions");
+ }
+
+ /**
+ * Checks through all prescriptions and look for records that have prescription date <= specified date.
+ *
+ * @param medicines Arraylist of all medicines.
+ * @param prescriptionArchiveDate Date that user specified to archive.
+ * @return Arraylist of prescriptions that meet the archive requirements.
+ */
+ private ArrayList prescriptionsToArchive(ArrayList medicines, Date prescriptionArchiveDate) {
+ ArrayList filteredPrescriptions = new ArrayList<>();
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Prescription)) {
+ continue;
+ }
+ Prescription prescription = (Prescription) medicine;
+ Date prescriptionDate = DateParser.removeTime(prescription.getDate());
+ if (prescriptionDate.before(prescriptionArchiveDate)
+ || prescriptionDate.equals(prescriptionArchiveDate)) {
+ filteredPrescriptions.add(prescription);
+ }
+ }
+ return filteredPrescriptions;
+ }
+
+ /**
+ * Removal of prescriptions from prescription list after archive.
+ *
+ * @param medicines Arraylist of all medicines.
+ * @param filteredPrescriptions Arraylist of prescriptions that meet the archive requirements.
+ */
+ private void removeFromPrescriptions(ArrayList medicines, ArrayList filteredPrescriptions) {
+ for (Medicine medicine : filteredPrescriptions) {
+ medicines.remove(medicine);
+ }
+ }
+}
+
diff --git a/src/main/java/command/prescription/DeletePrescriptionCommand.java b/src/main/java/command/prescription/DeletePrescriptionCommand.java
new file mode 100644
index 0000000000..d413676875
--- /dev/null
+++ b/src/main/java/command/prescription/DeletePrescriptionCommand.java
@@ -0,0 +1,139 @@
+package command.prescription;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Prescription;
+import inventory.Medicine;
+import inventory.Stock;
+import utilities.parser.MedicineValidator;
+import utilities.parser.PrescriptionValidator;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author deonchung
+
+/**
+ * Delete prescription based on user input given prescription id.
+ */
+public class DeletePrescriptionCommand extends Command {
+ private static Logger logger = Logger.getLogger("DeletePrescription");
+
+ public DeletePrescriptionCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start deletion of prescription");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String prescriptionIdToDelete = parameters.get(CommandParameters.ID);
+
+ if (!isValidPrescriptionParameters(ui, medicines)) {
+ return;
+ }
+
+ int prescriptionId = Integer.parseInt(prescriptionIdToDelete);
+
+ assert prescriptionId <= Prescription.getPrescriptionCount() : "Prescription ID should not exceed max "
+ + "prescription count";
+
+ int stockIdToPrescribe;
+ int prescribeQuantity;
+
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Prescription)) {
+ continue;
+ }
+
+ Prescription prescription = (Prescription) medicine;
+
+ if (prescription.getPrescriptionId() == prescriptionId) {
+ stockIdToPrescribe = prescription.getStockId();
+ prescribeQuantity = prescription.getQuantity();
+
+ if (setStockQuantity(ui, medicines, stockIdToPrescribe, prescribeQuantity)) {
+ return;
+ }
+
+ medicines.remove(prescription);
+ ui.print("Prescription deleted for Prescription ID " + prescriptionId);
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ logger.log(Level.INFO, "Successful deletion of Prescription");
+ return;
+
+ }
+ }
+ }
+
+ /**
+ * Check if parameters values for Prescription are valid and if Prescription ID exist.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of medicines.
+ * @return Boolean Value indicating if parameters values for Prescription are valid and Prescription ID exist.
+ */
+ private boolean isValidPrescriptionParameters(Ui ui, ArrayList medicines) {
+
+ MedicineValidator validator = new PrescriptionValidator();
+ String[] requiredParameters = {CommandParameters.ID};
+ String[] optionalParameters = {};
+
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.DELETE_PRESCRIPTION_COMMAND, true, validator);
+
+ if (isInvalidInput) {
+ logger.log(Level.WARNING, "Invalid parameter or value specified by user");
+ logger.log(Level.INFO, "Unsuccessful deletion of prescription");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Check stock if stock exist. If stock exist, add the quantity to the stock quantity.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of medicines
+ * @param stockIdToPrescribe Stock ID prescribe.
+ * @param prescribedQuantity Quantity prescribed.
+ * @return Boolean value indicating if stock id exist.
+ */
+ private boolean setStockQuantity(Ui ui, ArrayList medicines, int stockIdToPrescribe,
+ int prescribedQuantity) {
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Stock)) {
+ continue;
+ }
+ Stock stock = (Stock) medicine;
+
+ if (stock.getStockId() == stockIdToPrescribe) {
+ if (stock.isDeleted()) {
+ stock.setDeleted(false);
+ }
+
+ int quantityToRestore = stock.getQuantity() + prescribedQuantity;
+
+ if (quantityToRestore > stock.getMaxQuantity()) {
+ ui.print("Unable to delete prescription. Quantity added will exceed maximum quantity.");
+ ui.print("Maximum quantity: " + stock.getMaxQuantity() + " Total Quantity after deletion: "
+ + quantityToRestore);
+ return true;
+ }
+ stock.setQuantity(quantityToRestore);
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/src/main/java/command/prescription/ListPrescriptionCommand.java b/src/main/java/command/prescription/ListPrescriptionCommand.java
new file mode 100644
index 0000000000..5898e9b14c
--- /dev/null
+++ b/src/main/java/command/prescription/ListPrescriptionCommand.java
@@ -0,0 +1,131 @@
+package command.prescription;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Prescription;
+import utilities.comparators.PrescriptionComparator;
+import inventory.Medicine;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.PrescriptionValidator;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+//@@author alvintan01
+
+/**
+ * Helps to process the listprescription command together with filters and sort.
+ */
+public class ListPrescriptionCommand extends Command {
+ private static Logger logger = Logger.getLogger("ListPrescription");
+
+ public ListPrescriptionCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start listing of prescription records");
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String[] requiredParameters = {};
+ String[] optionalParameters = {CommandParameters.ID, CommandParameters.NAME, CommandParameters.QUANTITY,
+ CommandParameters.CUSTOMER_ID, CommandParameters.DATE, CommandParameters.STAFF,
+ CommandParameters.STOCK_ID,
+ CommandParameters.SORT, CommandParameters.REVERSED_SORT};
+
+ MedicineValidator validator = new PrescriptionValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.LIST_PRESCRIPTION_COMMAND, false, validator);
+ if (isInvalidInput) {
+ return;
+ }
+
+ ArrayList filteredPrescriptions = new ArrayList<>();
+
+ assert (filteredPrescriptions != null) : "Array is not initialised";
+
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Prescription) {
+ filteredPrescriptions.add((Prescription) medicine);
+ }
+ }
+ filteredPrescriptions = filterPrescription(filteredPrescriptions);
+
+ ui.printPrescriptions(filteredPrescriptions);
+ logger.log(Level.INFO, "Successful listing of prescription");
+ }
+
+
+ /**
+ * Helps to filter prescription records based on the user's input.
+ *
+ * @param filteredPrescriptions Arraylist of Prescription objects.
+ * @return Arraylist of filtered Prescription objects based on the user's parameters values.
+ */
+ private ArrayList filterPrescription(ArrayList filteredPrescriptions) {
+ for (String parameter : parameters.keySet()) {
+ String parameterValue = parameters.get(parameter);
+ switch (parameter) {
+ case CommandParameters.ID:
+ filteredPrescriptions = (ArrayList) filteredPrescriptions.stream()
+ .filter((d) -> d.getPrescriptionId() == Integer.parseInt(parameterValue))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.NAME:
+ filteredPrescriptions = (ArrayList) filteredPrescriptions.stream()
+ .filter((d) -> d.getMedicineName().toUpperCase().contains(parameterValue.toUpperCase()))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.QUANTITY:
+ filteredPrescriptions = (ArrayList) filteredPrescriptions.stream()
+ .filter((d) -> d.getQuantity() == Integer.parseInt(parameterValue))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.CUSTOMER_ID:
+ filteredPrescriptions = (ArrayList) filteredPrescriptions.stream()
+ .filter((d) -> d.getCustomerId().toUpperCase().contains(parameterValue.toUpperCase()))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.DATE:
+ try {
+ Date date = DateParser.stringToDate(parameterValue);
+ filteredPrescriptions = (ArrayList) filteredPrescriptions.stream()
+ .filter((m) -> m.getDate().equals(date))
+ .collect(Collectors.toList());
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ break;
+ case CommandParameters.STAFF:
+ filteredPrescriptions = (ArrayList) filteredPrescriptions.stream()
+ .filter((d) -> d.getStaff().toUpperCase().contains(parameterValue.toUpperCase()))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.STOCK_ID:
+ filteredPrescriptions = (ArrayList) filteredPrescriptions.stream()
+ .filter((d) -> d.getStockId() == Integer.parseInt(parameterValue))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.SORT:
+ filteredPrescriptions.sort(new PrescriptionComparator(parameterValue.toLowerCase(), false));
+ break;
+ case CommandParameters.REVERSED_SORT:
+ filteredPrescriptions.sort(new PrescriptionComparator(parameterValue.toLowerCase(), true));
+ break;
+ default:
+ return filteredPrescriptions;
+ }
+ }
+ return filteredPrescriptions;
+ }
+}
diff --git a/src/main/java/command/prescription/UpdatePrescriptionCommand.java b/src/main/java/command/prescription/UpdatePrescriptionCommand.java
new file mode 100644
index 0000000000..9335cc3dca
--- /dev/null
+++ b/src/main/java/command/prescription/UpdatePrescriptionCommand.java
@@ -0,0 +1,388 @@
+package command.prescription;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Prescription;
+import inventory.Medicine;
+import inventory.Stock;
+import utilities.parser.MedicineValidator;
+import utilities.parser.PrescriptionManager;
+import utilities.parser.PrescriptionValidator;
+import utilities.parser.StockManager;
+import utilities.parser.StockValidator;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Logger;
+
+//@@author a-tph
+
+/**
+ * Update prescription information based on user input given prescription id.
+ */
+public class UpdatePrescriptionCommand extends Command {
+ private static Logger logger = Logger.getLogger("UpdatePrescription");
+
+ public UpdatePrescriptionCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String[] requiredParameters = {CommandParameters.ID};
+ String[] optionalParameters = {CommandParameters.NAME, CommandParameters.QUANTITY,
+ CommandParameters.CUSTOMER_ID, CommandParameters.STAFF, CommandParameters.DATE};
+
+ MedicineValidator validator = new PrescriptionValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.UPDATE_PRESCRIPTION_COMMAND, true, validator);
+ if (isInvalidInput) {
+ return;
+ }
+
+ Prescription prescription = PrescriptionManager.extractPrescriptionObject(parameters, medicines);
+ assert (prescription != null) : "Prescription object should not be null";
+
+ boolean hasNameParam = validator.hasNameParamChecker(parameters, prescription.getMedicineName());
+ Date date = PrescriptionManager.getUpdatedDate(parameters, prescription.getDate());
+ String customerId = PrescriptionManager.getUpdatedCustomerId(parameters, prescription.getCustomerId());
+ String staffName = PrescriptionManager.getUpdatedStaff(parameters, prescription.getStaff());
+ boolean hasQuantityParam = validator.hasQuantityParamChecker(parameters, prescription.getQuantity());
+
+ if (hasQuantityParam) {
+ boolean isZero = Integer.parseInt(parameters.get(CommandParameters.QUANTITY)) == 0;
+ if (isZero) {
+ ui.print("Action aborted! Please use the delete command to remove the prescription.");
+ return;
+ }
+ }
+ boolean isSuccessfulUpdate = false;
+
+ if (hasNameParam && hasQuantityParam) {
+ isSuccessfulUpdate = processGivenNameAndQuantity(ui, medicines, prescription, customerId, date, staffName);
+ } else if (hasNameParam && !hasQuantityParam) {
+ isSuccessfulUpdate = processGivenName(ui, medicines, prescription, customerId, date, staffName);
+ } else if (!hasNameParam && hasQuantityParam) {
+ isSuccessfulUpdate = processGivenQuantity(ui, medicines, prescription, customerId, date, staffName);
+ } else {
+ isSuccessfulUpdate = processOtherFields(ui, medicines, prescription, customerId, date, staffName);
+ }
+
+ if (!isSuccessfulUpdate) {
+ return;
+ }
+
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ }
+
+ /**
+ * Processes name and quantity field provided by user for updating prescription information.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param prescription The associated prescription object.
+ * @param customerId CustomerId of customers.
+ * @param date Date of prescription.
+ * @param staffName Staff responsible for the prescription of medication.
+ * @return Boolean value true if update is successful.
+ */
+ private boolean processGivenNameAndQuantity(Ui ui, ArrayList medicines, Prescription prescription,
+ String customerId, Date date, String staffName) {
+ StockValidator stockValidator = new StockValidator();
+ String currentName = prescription.getMedicineName();
+ int currentStockId = prescription.getStockId();
+ String updatedName = parameters.get(CommandParameters.NAME);
+
+ Stock targetRestoreStock = StockManager.extractStockObject(medicines, currentName, currentStockId);
+ if (targetRestoreStock == null) {
+ ui.print("Medicine not found in stock");
+ return false;
+ }
+
+ int restoreStockQuantity = targetRestoreStock.getQuantity();
+ int restoredQuantity = prescription.getQuantity();
+ int totalQuantity = restoredQuantity + restoreStockQuantity;
+ int restoreMaxQuantity = targetRestoreStock.getMaxQuantity();
+ boolean isValidRestore = stockValidator.quantityValidityChecker(ui, totalQuantity, restoreMaxQuantity);
+ if (!isValidRestore) {
+ ui.print("Restoring of medication aborted!");
+ return false;
+ }
+
+ ArrayList targetPrescriptionStocks = StockManager.getUnexpiredFilteredStocksByName(medicines,
+ updatedName);
+ if (targetPrescriptionStocks.isEmpty()) {
+ ui.print("Action aborted! Either medication not found or stock has expired.");
+ return false;
+ }
+
+ String updatedQuantity = parameters.get(CommandParameters.QUANTITY);
+ int prescriptionQuantity = Integer.parseInt(updatedQuantity);
+ int availableQuantity = StockManager.getTotalStockQuantity(medicines, updatedName);
+ boolean isValidPrescription = stockValidator.quantityValidityChecker(ui, prescriptionQuantity,
+ availableQuantity);
+ if (!isValidPrescription) {
+ ui.print("Prescription of medication aborted!");
+ return false;
+ }
+
+ // Guarantee is be able to restore & prescribe
+ PrescriptionManager.restoreStock(targetRestoreStock, totalQuantity);
+ ArrayList updatedPrescriptions = PrescriptionManager.prescribeStock(medicines,
+ targetPrescriptionStocks, prescriptionQuantity, customerId, date, staffName);
+
+ // Add to prescription
+ for (Prescription updatedPrescription : updatedPrescriptions) {
+ medicines.add(updatedPrescription);
+ }
+ medicines.remove(prescription);
+
+ ui.print("Restored " + restoredQuantity + " " + targetRestoreStock.getMedicineName());
+ ui.print("Updated prescription information!");
+ ui.printPrescriptions(updatedPrescriptions);
+ return true;
+ }
+
+ /**
+ * Processes name field provided by user for updating prescription information.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param prescription The associated prescription object.
+ * @param customerId CustomerId of customers.
+ * @param date Date of prescription.
+ * @param staffName Staff responsible for the prescription of medication.
+ * @return Boolean value true if update is successful.
+ */
+ private boolean processGivenName(Ui ui, ArrayList medicines, Prescription prescription, String customerId,
+ Date date, String staffName) {
+ StockValidator stockValidator = new StockValidator();
+ String currentName = prescription.getMedicineName();
+ int currentStockId = prescription.getStockId();
+ String updatedName = parameters.get(CommandParameters.NAME);
+ Stock targetRestoreStock = StockManager.extractStockObject(medicines, currentName, currentStockId);
+ if (targetRestoreStock == null) {
+ ui.print("Medicine not found in stock");
+ return false;
+ }
+ int restoreStockQuantity = targetRestoreStock.getQuantity();
+ int restoredQuantity = prescription.getQuantity();
+ int totalQuantity = restoredQuantity + restoreStockQuantity;
+ int restoreMaxQuantity = targetRestoreStock.getMaxQuantity();
+ boolean isValidRestore = stockValidator.quantityValidityChecker(ui, totalQuantity, restoreMaxQuantity);
+ if (!isValidRestore) {
+ ui.print("Restoring of medication aborted!");
+ return false;
+ }
+
+ ArrayList targetPrescriptionStocks = StockManager.getUnexpiredFilteredStocksByName(medicines,
+ updatedName);
+ if (targetPrescriptionStocks.isEmpty()) {
+ ui.print("Action aborted! Either medication not found or stock has expired.");
+ return false;
+ }
+ int availableQuantity = StockManager.getTotalStockQuantity(medicines, updatedName);
+ boolean isValidPrescription = stockValidator.quantityValidityChecker(ui, restoredQuantity, availableQuantity);
+ if (!isValidPrescription) {
+ ui.print("Prescription of medication aborted!");
+ return false;
+ }
+
+ // Guarantee to be able to restore & prescribe
+ PrescriptionManager.restoreStock(targetRestoreStock, totalQuantity);
+ ArrayList updatedPrescriptions = PrescriptionManager.prescribeStock(medicines,
+ targetPrescriptionStocks, restoredQuantity, customerId, date, staffName);
+
+ // Add to prescription
+ for (Prescription updatedPrescription : updatedPrescriptions) {
+ medicines.add(updatedPrescription);
+ }
+ medicines.remove(prescription);
+ ui.print("Restored " + restoredQuantity + " " + targetRestoreStock.getMedicineName());
+ ui.print("Updated prescription information!");
+ ui.printPrescriptions(updatedPrescriptions);
+ return true;
+ }
+
+ /**
+ * Processes quantity field provided by user for updating prescription information.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param prescription The associated prescription object.
+ * @param customerId CustomerId of customers.
+ * @param date Date of prescription.
+ * @param staffName Staff responsible for the prescription of medication.
+ * @return Boolean value true if update is successful.
+ */
+ private boolean processGivenQuantity(Ui ui, ArrayList medicines, Prescription prescription,
+ String customerId, Date date, String staffName) {
+ int currentQuantity = prescription.getQuantity();
+ int updatedQuantity = Integer.parseInt(parameters.get(CommandParameters.QUANTITY));
+ boolean isSuccessful = false;
+ if (updatedQuantity < currentQuantity) {
+ isSuccessful = processRestoration(ui, medicines, prescription, customerId, date, staffName);
+ } else if (updatedQuantity > currentQuantity) {
+ isSuccessful = processPrescription(ui, medicines, prescription, customerId, date, staffName);
+ }
+ if (!isSuccessful) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Process prescription of medication for a prescription record.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param prescription The associated prescription object.
+ * @param customerId CustomerId of customers.
+ * @param date Date of prescription.
+ * @param staffName Staff responsible for the prescription of medication.
+ * @return Boolean value true if prescription is successful.
+ */
+ private boolean processPrescription(Ui ui, ArrayList medicines, Prescription prescription,
+ String customerId, Date date, String staffName) {
+ StockValidator stockValidator = new StockValidator();
+ String currentName = prescription.getMedicineName();
+ int currentQuantity = prescription.getQuantity();
+ int stockId = prescription.getStockId();
+ int updatedQuantity = Integer.parseInt(parameters.get(CommandParameters.QUANTITY));
+
+ ArrayList targetPrescriptionStocks = StockManager.getUnexpiredFilteredStocksByName(medicines,
+ currentName);
+ if (targetPrescriptionStocks.isEmpty()) {
+ ui.print("Action aborted! Either medication not found or stock has expired.");
+ return false;
+ }
+
+ int prescribedQuantity = updatedQuantity - currentQuantity;
+ int stockQuantity = StockManager.getTotalStockQuantity(medicines, currentName);
+ boolean isValidPrescription = stockValidator.quantityValidityChecker(ui, prescribedQuantity, stockQuantity);
+ if (!isValidPrescription) {
+ ui.print("Prescription of medication aborted!");
+ return false;
+ }
+
+ // guarantee can prescribe
+ ArrayList updatedPrescriptions = PrescriptionManager.prescribeStock(medicines,
+ targetPrescriptionStocks, prescribedQuantity, customerId, date, staffName);
+
+ medicines.remove(prescription);
+ for (Prescription updatedPrescription : updatedPrescriptions) {
+ if (updatedPrescription.getStockId() == stockId) {
+ int newQuantity = currentQuantity + updatedPrescription.getQuantity();
+ updatedPrescription.setQuantity(newQuantity);
+ break;
+ }
+ }
+
+ // Add to prescription
+ for (Prescription updatedPrescription : updatedPrescriptions) {
+ medicines.add(updatedPrescription);
+ }
+ ui.print("Updated prescription information!");
+ ui.printPrescriptions(updatedPrescriptions);
+ return true;
+ }
+
+ /**
+ * Process restoration for a prescription record.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param prescription The associated prescription object.
+ * @param customerId CustomerId of customers.
+ * @param date Date of prescription.
+ * @param staffName Staff responsible for the prescription of medication.
+ * @return Boolean value true if restoration is successful.
+ */
+ private boolean processRestoration(Ui ui, ArrayList medicines, Prescription prescription,
+ String customerId, Date date, String staffName) {
+ StockValidator stockValidator = new StockValidator();
+ String currentName = prescription.getMedicineName();
+ int currentStockId = prescription.getStockId();
+ int currentQuantity = prescription.getQuantity();
+ int updatedQuantity = Integer.parseInt(parameters.get(CommandParameters.QUANTITY));
+ Stock stock = StockManager.extractStockObject(medicines, currentName, currentStockId);
+ if (stock == null) {
+ ui.print("Medicine not found in stock");
+ return false;
+ }
+
+ int restoreQuantity = currentQuantity - updatedQuantity;
+ int stockQuantity = stock.getQuantity();
+ int stockMaxQuantity = stock.getMaxQuantity();
+ int totalQuantity = stockQuantity + restoreQuantity;
+ boolean isValidRestore = stockValidator.quantityValidityChecker(ui, totalQuantity, stockMaxQuantity);
+ if (!isValidRestore) {
+ ui.print("Restoring of medication aborted!");
+ return false;
+ }
+
+ // guarantee can restore
+ int stockId = prescription.getStockId();
+ PrescriptionManager.restoreStock(stock, totalQuantity);
+
+ medicines.remove(prescription);
+ Prescription newPrescription = new Prescription(currentName, updatedQuantity, customerId, date, staffName,
+ stockId);
+ medicines.add(newPrescription);
+
+ ArrayList updatedPrescriptions = new ArrayList<>();
+ updatedPrescriptions.add(newPrescription);
+ ui.print("Restored " + restoreQuantity + " " + stock.getMedicineName());
+ ui.print("Updated prescription information!");
+ ui.printPrescriptions(updatedPrescriptions);
+ return true;
+ }
+
+ /**
+ * Processes other fields provided by user for updating prescription information.
+ * The other field are the customerId, date and staffName.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param prescription The associated prescription object.
+ * @param customerId CustomerId of customers.
+ * @param date Date of prescription.
+ * @param staffName Staff responsible for the prescription of medication.
+ * @return Boolean value true if update is successful.
+ */
+ private boolean processOtherFields(Ui ui, ArrayList medicines, Prescription prescription,
+ String customerId, Date date, String staffName) {
+ if (prescription == null) {
+ return false;
+ }
+ Prescription updatedPrescription = null;
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Prescription)) {
+ continue;
+ }
+ Prescription targetPrescription = (Prescription) medicine;
+ boolean isSamePrescriptionId = targetPrescription.getPrescriptionId() == prescription.getPrescriptionId();
+ if (isSamePrescriptionId) {
+ ((Prescription) medicine).setCustomerId(customerId);
+ ((Prescription) medicine).setDate(date);
+ ((Prescription) medicine).setStaff(staffName);
+ updatedPrescription = (Prescription) medicine;
+ break;
+ }
+ }
+ ArrayList updatedPrescriptions = new ArrayList<>();
+ updatedPrescriptions.add(updatedPrescription);
+ ui.print("Updated prescription information!");
+ ui.printPrescriptions(updatedPrescriptions);
+ return true;
+ }
+
+}
diff --git a/src/main/java/command/stock/AddStockCommand.java b/src/main/java/command/stock/AddStockCommand.java
new file mode 100644
index 0000000000..dbd601c0cb
--- /dev/null
+++ b/src/main/java/command/stock/AddStockCommand.java
@@ -0,0 +1,297 @@
+package command.stock;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Stock;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.StockManager;
+import utilities.parser.StockValidator;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author deonchung
+
+/**
+ * Add medication based on user input.
+ * User input include name, price, quantity, expiry date, description and maximum quantity of medication.
+ */
+public class AddStockCommand extends Command {
+ private static Logger logger = Logger.getLogger("AddCommand");
+
+ public AddStockCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start addition of stock");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+ StockValidator stockValidator = new StockValidator();
+ ArrayList filteredStocks = new ArrayList<>();
+
+ String[] optionalParameters = {};
+ String nameToAdd = parameters.get(CommandParameters.NAME);
+ boolean nameExist = false;
+
+ if (parameters.containsKey(CommandParameters.NAME)) {
+ nameToAdd = parameters.get(CommandParameters.NAME);
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Stock && medicine.getMedicineName().equalsIgnoreCase(nameToAdd)
+ && !((Stock) medicine).isDeleted()) {
+ filteredStocks.add((Stock) medicine);
+ nameExist = true;
+ }
+ }
+ }
+
+ if (nameExist) {
+ String[] requiredParameters = {CommandParameters.NAME, CommandParameters.QUANTITY,
+ CommandParameters.EXPIRY_DATE};
+
+ if (!checkValidParametersAndValues(ui, parameters, medicines, requiredParameters,
+ optionalParameters)) {
+ return;
+ }
+
+ String expiryDate = parameters.get(CommandParameters.EXPIRY_DATE);
+ Date formatExpiryDate = checkExpiryDate(ui, expiryDate);
+
+ if (formatExpiryDate == null) { //if medication has expired
+ return;
+ }
+
+ String quantityToAdd = parameters.get(CommandParameters.QUANTITY);
+
+ int totalStock = StockManager.getTotalStockQuantity(medicines, nameToAdd);
+ assert totalStock > 0 : "Total Stock should be more than 0";
+
+ if (isExpiryExist(ui, stockValidator, filteredStocks, quantityToAdd, formatExpiryDate, totalStock)) {
+ return;
+ }
+
+ String[] requiredParams = {CommandParameters.NAME, CommandParameters.PRICE,
+ CommandParameters.QUANTITY, CommandParameters.EXPIRY_DATE};
+
+ if (!checkValidParametersAndValues(ui, parameters, medicines, requiredParams,
+ optionalParameters)) {
+ return;
+ }
+
+ if (addSameMedicine(ui, medicines, nameToAdd, stockValidator, filteredStocks, quantityToAdd,
+ formatExpiryDate, totalStock)) {
+ return;
+ }
+ } else {
+ String[] requiredParameters = {CommandParameters.NAME, CommandParameters.PRICE,
+ CommandParameters.QUANTITY, CommandParameters.EXPIRY_DATE,
+ CommandParameters.DESCRIPTION, CommandParameters.MAX_QUANTITY};
+
+ if (!checkValidParametersAndValues(ui, parameters, medicines, requiredParameters,
+ optionalParameters)) {
+ return;
+ }
+
+ String priceToAdd = parameters.get(CommandParameters.PRICE);
+ String quantityToAdd = parameters.get(CommandParameters.QUANTITY);
+ String descriptionToAdd = parameters.get(CommandParameters.DESCRIPTION);
+ String maxQuantityToAdd = parameters.get(CommandParameters.MAX_QUANTITY);
+ String expiryDate = parameters.get(CommandParameters.EXPIRY_DATE);
+
+ Date formatExpiryDate = checkExpiryDate(ui, expiryDate);
+ if (formatExpiryDate == null) { //if medication has expired
+ return;
+ }
+
+ int maxQuantity = Integer.parseInt(maxQuantityToAdd);
+ int quantity = Integer.parseInt(quantityToAdd);
+ double price = Double.parseDouble(priceToAdd);
+
+ if (isValidQuantity(ui, stockValidator, maxQuantity, quantity)) {
+ return;
+ }
+
+ addMedicine(ui, medicines, nameToAdd, descriptionToAdd, price, quantity, formatExpiryDate, maxQuantity);
+ }
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ }
+
+ /**
+ * Check if medication had expired.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param expiryDate Expiry Date of medication to add.
+ * @return Expiry Date of medication if medication has not expired. Null if medication has expired.
+ */
+ private Date checkExpiryDate(Ui ui, String expiryDate) {
+ Date formatExpiryDate = null;
+ try {
+ formatExpiryDate = DateParser.stringToDate(expiryDate);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ Date todayDate = new Date();
+ String todayDateString = DateParser.dateToString(todayDate);
+
+ Date formatTodayDate = null;
+ try {
+ formatTodayDate = DateParser.stringToDate(todayDateString);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ if (formatExpiryDate.before(formatTodayDate)) {
+ ui.print("Unable to add medicine. Medicine has expired.");
+ return null;
+ }
+ return formatExpiryDate;
+ }
+
+ /**
+ * Check if same expiry for the same medication name exist.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param stockValidator Reference to StockValidator object.
+ * @param filteredStocks List of medication with the same medication name as user input.
+ * @param quantityToAdd Quantity of medication to add.
+ * @param formatExpiry Formatted Expiry Date of medication to add.
+ * @param totalStock Total Quantity of the same stock.
+ * @return Boolean Value indicating if same medication exists.
+ */
+ private boolean isExpiryExist(Ui ui, StockValidator stockValidator, ArrayList filteredStocks,
+ String quantityToAdd, Date formatExpiry, int totalStock) {
+ for (Stock stock : filteredStocks) {
+ int quantity = Integer.parseInt(quantityToAdd);
+
+ if (isValidQuantity(ui, stockValidator, stock.getMaxQuantity(), totalStock + quantity)) {
+ return true;
+ }
+
+ if (formatExpiry.equals(stock.getExpiry())) {
+ quantity += stock.getQuantity();
+ stock.setQuantity(quantity);
+ ui.print("Same Medication and Expiry Date exist. Using existing price,"
+ + " description and maximum quantity. Updating existing quantity.");
+ ui.printStock(stock);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds the medication to same stock if same name exist.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines List of all medicines.
+ * @param nameToAdd Name of medication to add.
+ * @param stockValidator Reference to StockValidator object.
+ * @param filteredStocks List of medication with the same medication name as user input.
+ * @param quantityToAdd Quantity of medication to add.
+ * @param formatExpiry Formatted Expiry Date of medication to add.
+ * @param totalStock Total Quantity of the same stock.
+ * @return Boolean Value indicating if the same medication name exist.
+ */
+ private boolean addSameMedicine(Ui ui, ArrayList medicines, String nameToAdd,
+ StockValidator stockValidator,
+ ArrayList filteredStocks, String quantityToAdd, Date formatExpiry,
+ int totalStock) {
+ for (Stock stock : filteredStocks) {
+
+ int quantity = Integer.parseInt(quantityToAdd);
+ int existingMaxQuantity = stock.getMaxQuantity();
+
+ if (isValidQuantity(ui, stockValidator, existingMaxQuantity, totalStock + quantity)) {
+ return true;
+ }
+
+ String existingDescription = stock.getDescription();
+ String priceToAdd = parameters.get(CommandParameters.PRICE);
+ double price = Double.parseDouble(priceToAdd);
+ ui.print("Medicine exists. Using existing description and maximum quantity.");
+ addMedicine(ui, medicines, nameToAdd, existingDescription, price,
+ quantity, formatExpiry, existingMaxQuantity);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if quantity added is less than the maximum quantity of stock.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param stockValidator Reference to StockValidator object.
+ * @param maxQuantity Maximum quantity of medication.
+ * @param quantity Quantity of medication to add.
+ * @return Boolean Value indicating if quantity added is less than maximum quantity.
+ */
+ private boolean isValidQuantity(Ui ui, StockValidator stockValidator, int maxQuantity, int quantity) {
+ boolean isValidQuantity = stockValidator.quantityValidityChecker(ui, quantity, maxQuantity);
+
+ if (!isValidQuantity) {
+ logger.log(Level.WARNING, "Invalid Quantity is specified by user");
+ logger.log(Level.INFO, "Unsuccessful addition of stock");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if input contains Invalid Parameters and Invalid Parameter Values.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param parameters The parameter that is not found.
+ * @param medicines List of all medicines.
+ * @param requiredParameters The required parameters to check.
+ * @param optionalParameters The optional parameters to check.
+ * @return Boolean value indicating if parameter and parameter values are valid.
+ */
+ private boolean checkValidParametersAndValues(Ui ui, LinkedHashMap parameters,
+ ArrayList medicines, String[] requiredParameters,
+ String[] optionalParameters) {
+ MedicineValidator validator = new StockValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.ADD_STOCK_COMMAND, false, validator);
+ if (isInvalidInput) {
+ logger.log(Level.INFO, "Unsuccessful addition of stock");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Add medication based on user input.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines List of all medicines.
+ * @param name Name of medication to add.
+ * @param description Description of medication to add.
+ * @param price Price of medication to add.
+ * @param quantity Quantity of medication to add.
+ * @param expiryDate Expiry Date of medication to add.
+ * @param maxQuantity Maximum Quantity of medication to add.
+ */
+ private void addMedicine(Ui ui, ArrayList medicines, String name, String description,
+ double price, int quantity, Date expiryDate, int maxQuantity) {
+
+ Stock stock = new Stock(name, price, quantity, expiryDate, description, maxQuantity);
+ medicines.add(stock);
+ ui.print("Medication added: " + name);
+ ui.printStock(stock);
+ logger.log(Level.INFO, "Successful addition of stock");
+ }
+
+}
diff --git a/src/main/java/command/stock/DeleteStockCommand.java b/src/main/java/command/stock/DeleteStockCommand.java
new file mode 100644
index 0000000000..5876e22e39
--- /dev/null
+++ b/src/main/java/command/stock/DeleteStockCommand.java
@@ -0,0 +1,145 @@
+package command.stock;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Stock;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.StockValidator;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author RemusTeo
+
+/**
+ * Delete medication based on user input given stock id.
+ */
+public class DeleteStockCommand extends Command {
+ private static Logger logger = Logger.getLogger("DeleteStock");
+
+ public DeleteStockCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start deletion of stock");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+
+ String[] requiredParameters = {};
+ String[] optionalParameters = {CommandParameters.ID, CommandParameters.EXPIRING};
+
+ MedicineValidator validator = new StockValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.DELETE_STOCK_COMMAND, true, validator);
+ if (isInvalidInput) {
+ logger.log(Level.INFO, "Unsuccessful deletion of stock");
+ return;
+ }
+
+ boolean hasStockId = parameters.containsKey(CommandParameters.ID);
+ boolean hasExpiryDate = parameters.containsKey(CommandParameters.EXPIRING);
+
+ // Both fields should not be provided for deletion of stock.
+ if (hasStockId && hasExpiryDate) {
+ ui.print("Deleted aborted! Please provide only one parameter");
+ return;
+ }
+
+ if (hasStockId && !hasExpiryDate) {
+ deleteStockById(ui, medicines);
+ } else if (!hasStockId && hasExpiryDate) {
+ deleteStockByExpiry(ui, medicines);
+ }
+
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ logger.log(Level.INFO, "Successful deletion of stock");
+ }
+
+ /**
+ * Deletion of stock given an id.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ */
+ private void deleteStockById(Ui ui, ArrayList medicines) {
+ String stockIdToDelete = parameters.get(CommandParameters.ID);
+ int stockId = Integer.parseInt(stockIdToDelete);
+
+ assert stockId > 0 : "Stock Id should be more than 0";
+ assert stockId <= Stock.getStockCount() : "Stock Id should not exceed max stock count";
+
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Stock)) {
+ continue;
+ }
+ Stock stock = (Stock) medicine;
+ if (stock.getStockId() == stockId) {
+ stock.setQuantity(0);
+ stock.setDeleted(true);
+ logger.log(Level.INFO, "Stock id found and deleted");
+ break;
+ }
+ }
+ ui.print("Deleted row with Stock Id: " + stockId);
+ }
+
+ //@@author a-tph
+
+ /**
+ * Deletion of expired stocks given a date.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ */
+ private void deleteStockByExpiry(Ui ui, ArrayList medicines) {
+ String dateString = parameters.get(CommandParameters.EXPIRING);
+ Date date = null;
+ try {
+ date = DateParser.stringToDate(dateString);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+
+ int rowsDeleted = 0;
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Stock)) {
+ continue;
+ }
+
+ Stock stock = (Stock) medicine;
+ Date stockExpiryDate = stock.getExpiry();
+ if (stock.isDeleted()) {
+ continue;
+ }
+
+ if (stockExpiryDate.before(date) || stockExpiryDate.equals(date)) {
+ stock.setQuantity(0);
+ stock.setDeleted(true);
+ rowsDeleted++;
+ }
+ }
+
+ assert rowsDeleted >= 0 : "Rows deleted cannot be negative";
+ if (rowsDeleted > 0) {
+ logger.log(Level.INFO, "Expired stock found: deleted " + rowsDeleted);
+ ui.print("Deleted expired medications! Rows deleted: " + rowsDeleted);
+ } else {
+ logger.log(Level.INFO, "No expired stocks found");
+ ui.print("Delete aborted! Unable to find expired medications!");
+ }
+ }
+}
diff --git a/src/main/java/command/stock/ListStockCommand.java b/src/main/java/command/stock/ListStockCommand.java
new file mode 100644
index 0000000000..a7dca43275
--- /dev/null
+++ b/src/main/java/command/stock/ListStockCommand.java
@@ -0,0 +1,163 @@
+package command.stock;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Stock;
+import utilities.comparators.StockComparator;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.StockManager;
+import utilities.parser.StockValidator;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+//@@author jiangweichen835
+
+/**
+ * Helps to process the liststock command together with filters and sort.
+ */
+public class ListStockCommand extends Command {
+ private static Logger logger = Logger.getLogger("ListStock");
+
+ public ListStockCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start listing of available stock");
+
+ Ui ui = Ui.getInstance();
+
+ String[] requiredParameter = {};
+ String[] optionalParameters = {CommandParameters.ID, CommandParameters.NAME, CommandParameters.PRICE,
+ CommandParameters.QUANTITY, CommandParameters.EXPIRY_DATE, CommandParameters.DESCRIPTION,
+ CommandParameters.MAX_QUANTITY, CommandParameters.SORT, CommandParameters.REVERSED_SORT,
+ CommandParameters.EXPIRING, CommandParameters.LOW};
+
+ ArrayList medicines = Medicine.getInstance();
+ if (!checkValidParameterValues(ui, medicines, requiredParameter, optionalParameters)) {
+ return;
+ }
+
+ ArrayList filteredStocks = new ArrayList<>();
+
+ assert (filteredStocks != null) : "Array is not initialised";
+
+ for (Medicine medicine : medicines) {
+ if (medicine instanceof Stock) { // Ensure that it is a medicine object
+ Stock stock = (Stock) medicine;
+ if (!stock.isDeleted()) {
+ filteredStocks.add(stock);
+ }
+ }
+ }
+ filteredStocks = filterStocks(filteredStocks, medicines);
+ ui.printStocks(filteredStocks, medicines);
+ logger.log(Level.INFO, "Successful listing of stock");
+ }
+
+ /**
+ * Helps to filter stocks based on the user's input.
+ *
+ * @param filteredStocks Arraylist of Stock objects.
+ * @param medicines Arraylist of Medicines objects.
+ * @return Arraylist of filtered Stock objects based on the user's parameters values.
+ */
+ private ArrayList filterStocks(ArrayList filteredStocks, ArrayList medicines) {
+ for (String parameter : parameters.keySet()) {
+ String parameterValue = parameters.get(parameter);
+ switch (parameter) {
+ case CommandParameters.ID:
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ m.getStockId() == Integer.parseInt(parameterValue)).collect(Collectors.toList());
+ break;
+ case CommandParameters.NAME:
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ (m.getMedicineName().toUpperCase()).contains(parameterValue.toUpperCase()))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.PRICE:
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ m.getPrice() == Double.parseDouble(parameterValue)).collect(Collectors.toList());
+ break;
+ case CommandParameters.LOW:
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ StockManager.getTotalStockQuantity(medicines, m.getMedicineName())
+ <= Integer.parseInt(parameterValue)).collect(Collectors.toList());
+ break;
+ case CommandParameters.QUANTITY:
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ m.getQuantity() == Integer.parseInt(parameterValue)).collect(Collectors.toList());
+ break;
+ case CommandParameters.EXPIRING:
+ try {
+ Date expiryDate = DateParser.stringToDate(parameterValue);
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ m.getExpiry().before(expiryDate) || m.getExpiry().equals(expiryDate))
+ .collect(Collectors.toList());
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ break;
+ case CommandParameters.EXPIRY_DATE:
+ try {
+ Date expiryDate = DateParser.stringToDate(parameterValue);
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ m.getExpiry().equals(expiryDate)).collect(Collectors.toList());
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ break;
+ case CommandParameters.DESCRIPTION:
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ (m.getDescription().toUpperCase()).contains(parameterValue.toUpperCase()))
+ .collect(Collectors.toList());
+ break;
+ case CommandParameters.MAX_QUANTITY:
+ filteredStocks = (ArrayList) filteredStocks.stream().filter((m) ->
+ m.getMaxQuantity() == Integer.parseInt(parameterValue)).collect(Collectors.toList());
+ break;
+ case CommandParameters.SORT:
+ filteredStocks.sort(new StockComparator(parameterValue.toLowerCase(), false));
+ break;
+ case CommandParameters.REVERSED_SORT:
+ filteredStocks.sort(new StockComparator(parameterValue.toLowerCase(), true));
+ break;
+ default:
+ return filteredStocks;
+ }
+ }
+ return filteredStocks;
+ }
+
+ /**
+ * Checks if user input are valid.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines List of all medicines.
+ * @param requiredParameters The required parameters to check.
+ * @param optionalParameters The optional parameters to check.
+ * @return Boolean value indicating if parameter and parameter values are valid.
+ */
+ private boolean checkValidParameterValues(Ui ui, ArrayList medicines, String[] requiredParameters,
+ String[] optionalParameters) {
+ MedicineValidator validator = new StockValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.LIST_STOCK_COMMAND, false, validator);
+ if (isInvalidInput) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/command/stock/UpdateStockCommand.java b/src/main/java/command/stock/UpdateStockCommand.java
new file mode 100644
index 0000000000..624609a667
--- /dev/null
+++ b/src/main/java/command/stock/UpdateStockCommand.java
@@ -0,0 +1,300 @@
+package command.stock;
+
+import command.Command;
+import command.CommandParameters;
+import command.CommandSyntax;
+import inventory.Medicine;
+import inventory.Stock;
+import utilities.parser.DateParser;
+import utilities.parser.MedicineValidator;
+import utilities.parser.StockManager;
+import utilities.parser.StockValidator;
+import utilities.storage.Storage;
+import utilities.ui.Ui;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//@@author a-tph
+
+/**
+ * Update medication information based on user input given stock id.
+ */
+public class UpdateStockCommand extends Command {
+ private static Logger logger = Logger.getLogger("UpdateStock");
+
+ public UpdateStockCommand(LinkedHashMap parameters) {
+ this.parameters = parameters;
+ }
+
+ @Override
+ public void execute() {
+ logger.log(Level.INFO, "Start of UpdateStock command execution.");
+
+ Ui ui = Ui.getInstance();
+ ArrayList medicines = Medicine.getInstance();
+ String[] requiredParameters = {CommandParameters.ID};
+ String[] optionalParameters = {CommandParameters.PRICE, CommandParameters.QUANTITY,
+ CommandParameters.EXPIRY_DATE, CommandParameters.DESCRIPTION, CommandParameters.NAME,
+ CommandParameters.MAX_QUANTITY};
+
+ MedicineValidator validator = new StockValidator();
+ boolean isInvalidInput = validator.containsInvalidParametersAndValues(ui, medicines, parameters,
+ requiredParameters, optionalParameters, CommandSyntax.UPDATE_STOCK_COMMAND, true, validator);
+ if (isInvalidInput) {
+ return;
+ }
+
+ Stock stock = StockManager.extractStockObject(parameters, medicines);
+ boolean isValidQuantityValues = processQuantityValues(ui, medicines, stock);
+ if (!isValidQuantityValues) {
+ return;
+ }
+ boolean isValidExpDate = processDateInput(ui, medicines, stock);
+ if (!isValidExpDate) {
+ return;
+ }
+
+ ArrayList oldFilteredStocks = StockManager.getFilteredStocksByName(medicines, stock.getMedicineName());
+ if (parameters.containsKey(CommandParameters.NAME)) {
+ addNewRowForUpdates(oldFilteredStocks, medicines);
+ stock = getNewStock(medicines, stock);
+ }
+ ArrayList filteredStocks = StockManager.getFilteredStocksByName(medicines, stock.getMedicineName());
+
+ // Default value for updating all affected rows
+ boolean isAffectedCommand = checkAffectedCommand();
+ if (!isAffectedCommand) {
+ filteredStocks.clear();
+ filteredStocks.add(stock);
+ }
+
+ int rowsAffected = filteredStocks.size();
+ setUpdatesByStockId(filteredStocks, stock);
+ ui.print("Updated! Number of rows affected: " + rowsAffected);
+ printUpdatedStockId(ui, filteredStocks, oldFilteredStocks);
+
+ ui.printStocks(filteredStocks, medicines);
+ Storage storage = Storage.getInstance();
+ storage.saveData(medicines);
+ logger.log(Level.INFO, "End of UpdateStock command execution.");
+ }
+
+ /**
+ * Prints the change of stock id for affected records.
+ *
+ * @param ui Reference to the UI object passed by Main to print messages.
+ * @param filteredStocks Filtered stocks of the updated records.
+ * @param oldFilteredStocks Filtered stocks of the old records.
+ */
+ private void printUpdatedStockId(Ui ui, ArrayList filteredStocks, ArrayList oldFilteredStocks) {
+ if (parameters.containsKey(CommandParameters.NAME)) {
+ ui.print("Stock Id changed from:");
+ for (int i = 0; i < filteredStocks.size(); i++) {
+ ui.print(oldFilteredStocks.get(i).getStockId() + " -> " + filteredStocks.get(i).getStockId());
+ }
+ }
+ }
+
+ /**
+ * Checks if the command triggers multiple row updates.
+ *
+ * @return Boolean true if the command triggers multiple row updates.
+ */
+ private boolean checkAffectedCommand() {
+ String[] affectedCommands = {CommandParameters.NAME, CommandParameters.DESCRIPTION,
+ CommandParameters.MAX_QUANTITY};
+ boolean isAffectedCommand = false;
+ for (String affectedCommand : affectedCommands) {
+ if (parameters.containsKey(affectedCommand)) {
+ isAffectedCommand = true;
+ break;
+ }
+ }
+ return isAffectedCommand;
+ }
+
+ /**
+ * Retrieves the updated stock object.
+ *
+ * @param medicines Arraylist of all medicines.
+ * @param stock Stock object of the given stock id.
+ * @return The updated stock object.
+ */
+ private Stock getNewStock(ArrayList medicines, Stock stock) {
+ Stock newStock = null;
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Stock)) {
+ continue;
+ }
+ if (((Stock) medicine).isDeleted()) {
+ continue;
+ }
+ boolean isSameName = medicine.getMedicineName().equalsIgnoreCase(stock.getMedicineName());
+ boolean isSameExpDate = ((Stock) medicine).getExpiry().equals(stock.getExpiry());
+ if (isSameName && isSameExpDate) {
+ String newStockId = String.valueOf(((Stock) medicine).getStockId());
+ parameters.put(CommandParameters.ID, newStockId);
+ newStock = (Stock) medicine;
+ break;
+ }
+ }
+ return newStock;
+ }
+
+ /**
+ * Add new rows when medicine name gets updated.
+ *
+ * @param filteredStocks Arraylist of filtered medicine stocks.
+ * @param medicines Arraylist of all medicines.
+ */
+ private void addNewRowForUpdates(ArrayList filteredStocks, ArrayList medicines) {
+ // Initialise new stock to get a new Stock Id
+ for (Stock stock : filteredStocks) {
+ String name = stock.getMedicineName();
+ double price = stock.getPrice();
+ int quantity = stock.getQuantity();
+ Date expiryDate = stock.getExpiry();
+ String description = stock.getDescription();
+ int maxQuantity = stock.getMaxQuantity();
+ Stock newStock = new Stock(name, price, quantity, expiryDate, description, maxQuantity);
+ medicines.add(newStock);
+ }
+
+ for (Stock stock : filteredStocks) {
+ for (Medicine medicine : medicines) {
+ if (!(medicine instanceof Stock)) {
+ continue;
+ }
+ int stockId = ((Stock) medicine).getStockId();
+ if (stockId == stock.getStockId()) {
+ ((Stock) medicine).setDeleted(true);
+ medicine.setQuantity(0);
+ }
+ }
+ }
+ }
+
+ /**
+ * Process valid date input to be updated given a stock id.
+ *
+ * @param ui Reference to the UI object passed by Main to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param stock Stock object of the given stock id.
+ * @return Boolean value indicating if quantity values are valid.
+ */
+ private boolean processDateInput(Ui ui, ArrayList medicines, Stock stock) {
+ logger.log(Level.INFO, "Processing date input for update stock...");
+ boolean hasExpiryDate = parameters.containsKey(CommandParameters.EXPIRY_DATE);
+ if (!hasExpiryDate) {
+ return true;
+ }
+
+ Date expiryDate = null;
+ try {
+ expiryDate = DateParser.stringToDate(parameters.get(CommandParameters.EXPIRY_DATE));
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ StockValidator stockValidator = new StockValidator();
+ String name = stock.getMedicineName();
+ logger.log(Level.INFO, "End processing date input for update stock.");
+ return stockValidator.dateValidityChecker(ui, medicines, expiryDate, name);
+ }
+
+ /**
+ * Process quantity values to be updated given a stock id.
+ *
+ * @param ui Reference to the UI object passed by Main to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param stock Stock object of the given stock id.
+ * @return Boolean value indicating if quantity values are valid.
+ */
+ private boolean processQuantityValues(Ui ui, ArrayList medicines, Stock stock) {
+ logger.log(Level.INFO, "Processing quantity values for update stock...");
+ String name = stock.getMedicineName();
+ int quantity = 0;
+ int maxQuantity = 0;
+ int totalStockQuantity = 0;
+ int initialQuantity = 0;
+ int updatedQuantity = 0;
+
+ boolean hasQuantity = parameters.containsKey(CommandParameters.QUANTITY);
+ boolean hasMaxQuantity = parameters.containsKey(CommandParameters.MAX_QUANTITY);
+
+ // initialise quantity and max quantity based on the different combinations of user inputs
+ if (hasQuantity && hasMaxQuantity) {
+ totalStockQuantity = StockManager.getTotalStockQuantity(medicines, name);
+ initialQuantity = stock.getQuantity();
+ updatedQuantity = Integer.parseInt(parameters.get(CommandParameters.QUANTITY));
+ quantity = totalStockQuantity - initialQuantity + updatedQuantity;
+ maxQuantity = Integer.parseInt(parameters.get(CommandParameters.MAX_QUANTITY));
+ }
+
+ if (hasQuantity && !hasMaxQuantity) {
+ totalStockQuantity = StockManager.getTotalStockQuantity(medicines, name);
+ initialQuantity = stock.getQuantity();
+ updatedQuantity = Integer.parseInt(parameters.get(CommandParameters.QUANTITY));
+ quantity = totalStockQuantity - initialQuantity + updatedQuantity;
+ maxQuantity = StockManager.getMaxStockQuantity(medicines, name);
+ }
+
+ if (!hasQuantity && hasMaxQuantity) {
+ quantity = StockManager.getTotalStockQuantity(medicines, name);
+ maxQuantity = Integer.parseInt(parameters.get(CommandParameters.MAX_QUANTITY));
+ }
+ StockValidator stockValidator = new StockValidator();
+ logger.log(Level.INFO, "End processing quantity values for update stock.");
+ return stockValidator.quantityValidityChecker(ui, quantity, maxQuantity);
+ }
+
+ /**
+ * Update values provided by user for a given stock id.
+ *
+ * @param filteredStocks Arraylist of filtered medicine stocks.
+ * @param stock Stock object of the given stock id.
+ */
+ private void setUpdatesByStockId(ArrayList filteredStocks, Stock stock) {
+ logger.log(Level.INFO, "Attempt to update stock information.");
+ for (String parameter : parameters.keySet()) {
+ String parameterValue = parameters.get(parameter);
+ switch (parameter) {
+ case CommandParameters.NAME:
+ for (Stock targetStock : filteredStocks) {
+ targetStock.setMedicineName(parameterValue);
+ }
+ break;
+ case CommandParameters.PRICE:
+ stock.setPrice(Double.parseDouble(parameterValue));
+ break;
+ case CommandParameters.QUANTITY:
+ stock.setQuantity(Integer.parseInt(parameterValue));
+ break;
+ case CommandParameters.EXPIRY_DATE:
+ try {
+ stock.setExpiry(DateParser.stringToDate(parameterValue));
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ break;
+ case CommandParameters.DESCRIPTION:
+ for (Stock targetStock : filteredStocks) {
+ targetStock.setDescription(parameterValue);
+ }
+ break;
+ case CommandParameters.MAX_QUANTITY:
+ for (Stock targetStock : filteredStocks) {
+ targetStock.setMaxQuantity(Integer.parseInt(parameterValue));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ logger.log(Level.INFO, "Updated stock information with given user input");
+ }
+}
diff --git a/src/main/java/errors/InvalidCommandException.java b/src/main/java/errors/InvalidCommandException.java
new file mode 100644
index 0000000000..148585d64e
--- /dev/null
+++ b/src/main/java/errors/InvalidCommandException.java
@@ -0,0 +1,9 @@
+package errors;
+
+//@@author alvintan01
+/**
+ * Represents the InvalidCommandException thrown when a command is not found in command.CommandList.
+ */
+
+public class InvalidCommandException extends Exception {
+}
diff --git a/src/main/java/errors/InvalidDataException.java b/src/main/java/errors/InvalidDataException.java
new file mode 100644
index 0000000000..2635587996
--- /dev/null
+++ b/src/main/java/errors/InvalidDataException.java
@@ -0,0 +1,11 @@
+package errors;
+
+//@@author RemusTeo
+/**
+ * Represents the InvalidDataException thrown when data is corrupted or missing during loading from file.
+ */
+public class InvalidDataException extends Exception {
+ public InvalidDataException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/inventory/Medicine.java b/src/main/java/inventory/Medicine.java
new file mode 100644
index 0000000000..d753160ef1
--- /dev/null
+++ b/src/main/java/inventory/Medicine.java
@@ -0,0 +1,50 @@
+package inventory;
+
+import java.util.ArrayList;
+
+/**
+ * Represents the generic stock for the application. It contains the medicine name and quantity.
+ * It is inherited by Prescription, Medicine and Order objects.
+ */
+public abstract class Medicine {
+ protected String medicineName;
+ protected int quantity;
+ private static ArrayList medicines = null;
+
+ /**
+ * Helps to create the medicine arraylist or returns the arraylist if it exists.
+ *
+ * @return The medicine's arraylist.
+ */
+ public static ArrayList getInstance() {
+ if (medicines == null) {
+ medicines = new ArrayList<>();
+ }
+ return medicines;
+ }
+
+ public Medicine(String medicineName, int quantity) {
+ this.medicineName = medicineName;
+ this.quantity = quantity;
+ }
+
+ public String getMedicineName() {
+ return medicineName;
+ }
+
+ public void setMedicineName(String medicineName) {
+ this.medicineName = medicineName;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ public abstract String toFileFormat();
+
+ public abstract String toArchiveFormat();
+}
diff --git a/src/main/java/inventory/Order.java b/src/main/java/inventory/Order.java
new file mode 100644
index 0000000000..8d6f391783
--- /dev/null
+++ b/src/main/java/inventory/Order.java
@@ -0,0 +1,91 @@
+package inventory;
+
+import utilities.parser.DateParser;
+
+import java.util.Date;
+
+/**
+ * Represents an Order. An Order is represented by order_id, medicine name, quantity, date and isDelivered.
+ */
+public class Order extends Medicine {
+ public static final String ID = "ID";
+ public static final String NAME = "NAME";
+ public static final String QUANTITY = "QUANTITY";
+ public static final String DATE = "DATE";
+ public static final String STATUS = "STATUS";
+
+ // Used for sorting
+ public static final String ID_LOWERCASE = "id";
+ public static final String NAME_LOWERCASE = "name";
+ public static final String QUANTITY_LOWERCASE = "quantity";
+ public static final String DATE_LOWERCASE = "date";
+ public static final String STATUS_LOWERCASE = "status";
+
+ public static final String[] COLUMNS = {ID, NAME, QUANTITY, DATE, STATUS};
+
+ private static int orderCount = 0;
+ protected int orderId;
+ protected Date date;
+ protected boolean isDelivered;
+
+ public Order(String medicineName, int quantity, Date date) {
+ super(medicineName, quantity);
+ orderCount++;
+ this.orderId = orderCount;
+ this.date = date;
+ this.isDelivered = false;
+ }
+
+ public static int getOrderCount() {
+ return orderCount;
+ }
+
+ public static void setOrderCount(int orderCount) {
+ Order.orderCount = orderCount;
+ }
+
+ public int getOrderId() {
+ return orderId;
+ }
+
+ public void setOrderId(int orderId) {
+ this.orderId = orderId;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public boolean isDelivered() {
+ return isDelivered;
+ }
+
+ public void setDelivered() {
+ isDelivered = true;
+ }
+
+ public String getStatus() {
+ if (isDelivered) {
+ return "DELIVERED";
+ } else {
+ return "PENDING";
+ }
+ }
+
+ public String toFileFormat() {
+ String fileFormat = getOrderId() + "|" + getMedicineName().toUpperCase() + "|" + getQuantity() + "|"
+ + DateParser.dateToString(getDate()) + "|" + getStatus();
+ return fileFormat;
+ }
+
+ public String toArchiveFormat() {
+ String archiveFormat = "[ORDER ID: " + getOrderId() + "] " + getQuantity() + " "
+ + getMedicineName().toUpperCase() + " WAS ORDERED ON " + DateParser.dateToString(getDate())
+ + ". STATUS: " + getStatus();
+ return archiveFormat;
+ }
+}
diff --git a/src/main/java/inventory/Prescription.java b/src/main/java/inventory/Prescription.java
new file mode 100644
index 0000000000..a76724c1bc
--- /dev/null
+++ b/src/main/java/inventory/Prescription.java
@@ -0,0 +1,111 @@
+package inventory;
+
+import utilities.parser.DateParser;
+
+import java.util.Date;
+
+/**
+ * Represents a Dispensed object. A Dispensed object is represented by medicine name, quantity, customer's NRIC,
+ * date and staff name.
+ */
+public class Prescription extends Medicine {
+ public static final String ID = "ID";
+ public static final String NAME = "NAME";
+ public static final String QUANTITY = "QUANTITY";
+ public static final String CUSTOMER_ID = "CUSTOMER_ID";
+ public static final String DATE = "DATE";
+ public static final String STAFF = "STAFF";
+ public static final String STOCK_ID = "STOCK_ID";
+
+ // Used for sorting
+ public static final String ID_LOWERCASE = "id";
+ public static final String NAME_LOWERCASE = "name";
+ public static final String QUANTITY_LOWERCASE = "quantity";
+ public static final String CUSTOMER_ID_LOWERCASE = "customer_id";
+ public static final String DATE_LOWERCASE = "date";
+ public static final String STAFF_LOWERCASE = "staff";
+ public static final String STOCK_ID_LOWERCASE = "stock_id";
+
+ public static final String[] COLUMNS = {ID, NAME, QUANTITY, CUSTOMER_ID, DATE, STAFF, STOCK_ID};
+
+ private static int prescriptionCount = 0;
+ protected int prescriptionId;
+ protected String customerId;
+ protected Date date;
+ protected String staff;
+ protected int stockId;
+
+ public Prescription(String medicineName, int quantity, String customerId, Date date, String staff, int stockId) {
+ super(medicineName, quantity);
+ prescriptionCount++;
+ this.prescriptionId = prescriptionCount;
+ this.customerId = customerId;
+ this.date = date;
+ this.staff = staff;
+ this.stockId = stockId;
+ }
+
+ public static int getPrescriptionCount() {
+ return prescriptionCount;
+ }
+
+ public static void setPrescriptionCount(int prescriptionCount) {
+ Prescription.prescriptionCount = prescriptionCount;
+ }
+
+ public int getPrescriptionId() {
+ return prescriptionId;
+ }
+
+ public void setPrescriptionId(int prescriptionId) {
+ this.prescriptionId = prescriptionId;
+ }
+
+ public String getCustomerId() {
+ return customerId;
+ }
+
+ public void setCustomerId(String customerId) {
+ this.customerId = customerId;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public String getStaff() {
+ return staff;
+ }
+
+ public void setStaff(String staff) {
+ this.staff = staff;
+ }
+
+ public int getStockId() {
+ return stockId;
+ }
+
+ public void setStockId(int stockId) {
+ this.stockId = stockId;
+ }
+
+ public String toFileFormat() {
+ String fileFormat = getPrescriptionId() + "|" + getMedicineName().toUpperCase() + "|" + getQuantity() + "|"
+ + getCustomerId().toUpperCase() + "|" + DateParser.dateToString(getDate()) + "|"
+ + getStaff().toUpperCase() + "|" + getStockId();
+ return fileFormat;
+ }
+
+ public String toArchiveFormat() {
+ String archiveFormat = "[PRESCRIPTION ID: " + getPrescriptionId() + "] " + getQuantity() + " "
+ + getMedicineName().toUpperCase() + " [STOCK ID: " + getStockId() + "] WAS PRESCRIBED BY "
+ + getStaff().toUpperCase() + " TO " + getCustomerId().toUpperCase() + " ON "
+ + DateParser.dateToString(getDate());
+ return archiveFormat;
+ }
+
+}
diff --git a/src/main/java/inventory/Stock.java b/src/main/java/inventory/Stock.java
new file mode 100644
index 0000000000..51de2aa156
--- /dev/null
+++ b/src/main/java/inventory/Stock.java
@@ -0,0 +1,117 @@
+package inventory;
+
+import utilities.parser.DateParser;
+
+import java.util.Date;
+
+/**
+ * Represents a Medicine object. A Medicine object is represented by stock_id, name, price, quantity, expiry,
+ * description and max quantity.
+ */
+public class Stock extends Medicine {
+ public static final String ID = "ID";
+ public static final String NAME = "NAME";
+ public static final String PRICE = "PRICE";
+ public static final String QUANTITY = "QUANTITY";
+ public static final String EXPIRY_DATE = "EXPIRY_DATE";
+ public static final String DESCRIPTION = "DESCRIPTION";
+ public static final String MAX_QUANTITY = "MAX_QUANTITY";
+
+ // Used for sorting
+ public static final String ID_LOWERCASE = "id";
+ public static final String NAME_LOWERCASE = "name";
+ public static final String PRICE_LOWERCASE = "price";
+ public static final String QUANTITY_LOWERCASE = "quantity";
+ public static final String EXPIRY_DATE_LOWERCASE = "expiry";
+ public static final String DESCRIPTION_LOWERCASE = "description";
+ public static final String MAX_QUANTITY_LOWERCASE = "max_quantity";
+
+ public static final String[] COLUMNS = {ID, NAME, PRICE, QUANTITY, EXPIRY_DATE, DESCRIPTION, MAX_QUANTITY};
+
+ private static int stockCount = 0;
+ protected int stockId;
+ protected double price;
+ protected Date expiry;
+ protected String description;
+ protected int maxQuantity;
+ protected boolean isDeleted = false;
+
+ public Stock(String name, double price, int quantity, Date expiry, String description, int maxQuantity) {
+ super(name, quantity);
+ stockCount++;
+ this.stockId = stockCount;
+ this.price = price;
+ this.expiry = expiry;
+ this.description = description;
+ this.maxQuantity = maxQuantity;
+ }
+
+ public static int getStockCount() {
+ return stockCount;
+ }
+
+ public static void setStockCount(int stockCount) {
+ Stock.stockCount = stockCount;
+ }
+
+ public int getStockId() {
+ return stockId;
+ }
+
+ public void setStockId(int stockId) {
+ this.stockId = stockId;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+
+ public void setPrice(double price) {
+ this.price = price;
+ }
+
+ public Date getExpiry() {
+ return expiry;
+ }
+
+ public void setExpiry(Date expiry) {
+ this.expiry = expiry;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public int getMaxQuantity() {
+ return maxQuantity;
+ }
+
+ public void setMaxQuantity(int maxQuantity) {
+ this.maxQuantity = maxQuantity;
+ }
+
+ public boolean isDeleted() {
+ return isDeleted;
+ }
+
+ public void setDeleted(boolean deleted) {
+ isDeleted = deleted;
+ }
+
+ public String toFileFormat() {
+ String fileFormat = getStockId() + "|" + getMedicineName().toUpperCase() + "|" + getPrice() + "|"
+ + getQuantity() + "|" + DateParser.dateToString(getExpiry()) + "|" + getDescription().toUpperCase()
+ + "|" + getMaxQuantity() + "|" + isDeleted();
+ return fileFormat;
+ }
+
+ // Dummy method since Stock does not use archive.
+ public String toArchiveFormat() {
+ String archiveFormat = "";
+ return archiveFormat;
+ }
+}
diff --git a/src/main/java/utilities/comparators/OrderComparator.java b/src/main/java/utilities/comparators/OrderComparator.java
new file mode 100644
index 0000000000..da53a9a5a0
--- /dev/null
+++ b/src/main/java/utilities/comparators/OrderComparator.java
@@ -0,0 +1,52 @@
+package utilities.comparators;
+
+import command.CommandParameters;
+import inventory.Order;
+
+import java.util.Comparator;
+
+//@@author alvintan01
+
+/**
+ * Helps to sort the order based on the column provided.
+ */
+public class OrderComparator implements Comparator {
+ private String column;
+ private Boolean isReversed;
+
+ public OrderComparator(String column, Boolean isReversed) {
+ this.column = column;
+ this.isReversed = isReversed;
+ }
+
+ @Override
+ public int compare(Order order1, Order order2) {
+ Order order;
+
+ if (isReversed) { // If the user chooses to sort in reverse order
+ order = order2;
+ order2 = order1;
+ order1 = order;
+ }
+
+ switch (column) {
+ case Order.ID_LOWERCASE:
+ case CommandParameters.ID:
+ return Integer.compare(order1.getOrderId(), order2.getOrderId());
+ case Order.NAME_LOWERCASE:
+ case CommandParameters.NAME:
+ return order1.getMedicineName().compareTo(order2.getMedicineName());
+ case Order.QUANTITY_LOWERCASE:
+ case CommandParameters.QUANTITY:
+ return Integer.compare(order1.getQuantity(), order2.getQuantity());
+ case Order.DATE_LOWERCASE:
+ case CommandParameters.DATE:
+ return order1.getDate().compareTo(order2.getDate());
+ case Order.STATUS_LOWERCASE:
+ case CommandParameters.STATUS:
+ return order1.getStatus().compareTo(order2.getStatus());
+ default:
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/utilities/comparators/PrescriptionComparator.java b/src/main/java/utilities/comparators/PrescriptionComparator.java
new file mode 100644
index 0000000000..88c9d7d6b2
--- /dev/null
+++ b/src/main/java/utilities/comparators/PrescriptionComparator.java
@@ -0,0 +1,58 @@
+package utilities.comparators;
+
+import command.CommandParameters;
+import inventory.Prescription;
+
+import java.util.Comparator;
+
+//@@author alvintan01
+
+/**
+ * Helps to sort the medicines based on the column provided.
+ */
+public class PrescriptionComparator implements Comparator {
+ private String column;
+ private Boolean isReversed;
+
+ public PrescriptionComparator(String column, Boolean isReversed) {
+ this.column = column;
+ this.isReversed = isReversed;
+ }
+
+ @Override
+ public int compare(Prescription prescription1, Prescription prescription2) {
+ Prescription prescription;
+
+ if (isReversed) { // If the user chooses to sort in reverse order
+ prescription = prescription2;
+ prescription2 = prescription1;
+ prescription1 = prescription;
+ }
+
+ switch (column) {
+ case Prescription.ID_LOWERCASE:
+ case CommandParameters.ID:
+ return Integer.compare(prescription1.getPrescriptionId(), prescription2.getPrescriptionId());
+ case Prescription.NAME_LOWERCASE:
+ case CommandParameters.NAME:
+ return prescription1.getMedicineName().compareTo(prescription2.getMedicineName());
+ case Prescription.QUANTITY_LOWERCASE:
+ case CommandParameters.QUANTITY:
+ return Integer.compare(prescription1.getQuantity(), prescription2.getQuantity());
+ case Prescription.CUSTOMER_ID_LOWERCASE:
+ case CommandParameters.CUSTOMER_ID:
+ return prescription1.getCustomerId().compareTo(prescription2.getCustomerId());
+ case Prescription.DATE_LOWERCASE:
+ case CommandParameters.DATE:
+ return prescription1.getDate().compareTo(prescription2.getDate());
+ case Prescription.STAFF_LOWERCASE:
+ case CommandParameters.STAFF:
+ return prescription1.getStaff().compareTo(prescription2.getStaff());
+ case Prescription.STOCK_ID_LOWERCASE:
+ case CommandParameters.STOCK_ID:
+ return Integer.compare(prescription1.getStockId(), prescription2.getStockId());
+ default:
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/utilities/comparators/StockComparator.java b/src/main/java/utilities/comparators/StockComparator.java
new file mode 100644
index 0000000000..c2adc4404f
--- /dev/null
+++ b/src/main/java/utilities/comparators/StockComparator.java
@@ -0,0 +1,57 @@
+package utilities.comparators;
+
+import command.CommandParameters;
+import inventory.Stock;
+
+import java.util.Comparator;
+
+//@@author alvintan01
+
+/**
+ * Helps to sort the medicines based on the column provided.
+ */
+public class StockComparator implements Comparator {
+ private String column;
+ private Boolean isReversed;
+
+ public StockComparator(String column, Boolean isReversed) {
+ this.column = column;
+ this.isReversed = isReversed;
+ }
+
+ @Override
+ public int compare(Stock stock1, Stock stock2) {
+ Stock stock;
+ if (isReversed) { // If the user chooses to sort in reverse order
+ stock = stock2;
+ stock2 = stock1;
+ stock1 = stock;
+ }
+
+ switch (column) {
+ case Stock.ID_LOWERCASE:
+ case CommandParameters.ID:
+ return Integer.compare(stock1.getStockId(), stock2.getStockId());
+ case Stock.NAME_LOWERCASE:
+ case CommandParameters.NAME:
+ return stock1.getMedicineName().compareTo(stock2.getMedicineName());
+ case Stock.PRICE_LOWERCASE:
+ case CommandParameters.PRICE:
+ return Double.compare(stock1.getPrice(), stock2.getPrice());
+ case Stock.QUANTITY_LOWERCASE:
+ case CommandParameters.QUANTITY:
+ return Integer.compare(stock1.getQuantity(), stock2.getQuantity());
+ case Stock.EXPIRY_DATE_LOWERCASE:
+ case CommandParameters.EXPIRY_DATE:
+ return stock1.getExpiry().compareTo(stock2.getExpiry());
+ case Stock.DESCRIPTION_LOWERCASE:
+ case CommandParameters.DESCRIPTION:
+ return stock1.getDescription().compareTo(stock2.getDescription());
+ case Stock.MAX_QUANTITY_LOWERCASE:
+ case CommandParameters.MAX_QUANTITY:
+ return Integer.compare(stock1.getMaxQuantity(), stock2.getMaxQuantity());
+ default:
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/utilities/parser/CommandParser.java b/src/main/java/utilities/parser/CommandParser.java
new file mode 100644
index 0000000000..bf666bde6a
--- /dev/null
+++ b/src/main/java/utilities/parser/CommandParser.java
@@ -0,0 +1,217 @@
+package utilities.parser;
+
+import command.Command;
+import command.ExitCommand;
+import command.HelpCommand;
+import command.PurgeCommand;
+import command.order.ReceiveOrderCommand;
+import command.prescription.AddPrescriptionCommand;
+import command.prescription.ArchivePrescriptionCommand;
+import command.prescription.DeletePrescriptionCommand;
+import command.prescription.ListPrescriptionCommand;
+import command.prescription.UpdatePrescriptionCommand;
+import command.stock.AddStockCommand;
+import command.stock.DeleteStockCommand;
+import command.stock.ListStockCommand;
+import command.stock.UpdateStockCommand;
+import command.order.AddOrderCommand;
+import command.order.ArchiveOrderCommand;
+import command.order.DeleteOrderCommand;
+import command.order.ListOrderCommand;
+import command.order.UpdateOrderCommand;
+import errors.InvalidCommandException;
+import utilities.ui.Ui;
+
+import java.util.LinkedHashMap;
+
+import static command.CommandList.ADD;
+import static command.CommandList.ADD_PRESCRIPTION;
+import static command.CommandList.ADD_ORDER;
+import static command.CommandList.ADD_STOCK;
+import static command.CommandList.ARCHIVE;
+import static command.CommandList.ARCHIVE_PRESCRIPTION;
+import static command.CommandList.ARCHIVE_ORDER;
+import static command.CommandList.DELETE;
+import static command.CommandList.DELETE_PRESCRIPTION;
+import static command.CommandList.DELETE_STOCK;
+import static command.CommandList.DELETE_ORDER;
+import static command.CommandList.EXIT;
+import static command.CommandList.HELP;
+import static command.CommandList.LIST;
+import static command.CommandList.LIST_PRESCRIPTION;
+import static command.CommandList.LIST_STOCK;
+import static command.CommandList.LIST_ORDER;
+import static command.CommandList.PURGE;
+import static command.CommandList.RECEIVE;
+import static command.CommandList.RECEIVE_ORDER;
+import static command.CommandList.UPDATE;
+import static command.CommandList.UPDATE_PRESCRIPTION;
+import static command.CommandList.UPDATE_STOCK;
+import static command.CommandList.UPDATE_ORDER;
+import static utilities.parser.Mode.PRESCRIPTION;
+import static utilities.parser.Mode.ORDER;
+import static utilities.parser.Mode.STOCK;
+
+//@@author alvintan01
+
+/**
+ * Helps to parse the commands given by the user as well as extract the parameters provided.
+ */
+public class CommandParser {
+ public CommandParser() {
+ }
+
+ private static final String DELIMITER = "/";
+ private static final String SPACE_DELIMITER = "\\s+";
+
+ /**
+ * Processes the user input into a Command Object.
+ *
+ * @param command Input provided by user.
+ * @param parametersString String parameter entered by user.
+ * @param mode The current mode of the program.
+ * @return A Command object.
+ * @throws InvalidCommandException If a command does not exist.
+ */
+ public Command processCommand(String command, String parametersString, Mode mode) throws InvalidCommandException {
+ // Append user's command with mode
+ if (command.equals(ADD) || command.equals(LIST) || command.equals(UPDATE)
+ || command.equals(DELETE) || command.equals(ARCHIVE) || command.equals(RECEIVE)) {
+ command = command + mode.name().toLowerCase();
+ }
+
+ LinkedHashMap parameters = parseParameters(parametersString);
+
+ switch (command) {
+ case ADD_PRESCRIPTION:
+ return new AddPrescriptionCommand(parameters);
+ case ADD_STOCK:
+ return new AddStockCommand(parameters);
+ case ADD_ORDER:
+ return new AddOrderCommand(parameters);
+ case ARCHIVE_ORDER:
+ return new ArchiveOrderCommand(parameters);
+ case ARCHIVE_PRESCRIPTION:
+ return new ArchivePrescriptionCommand(parameters);
+ case DELETE_PRESCRIPTION:
+ return new DeletePrescriptionCommand(parameters);
+ case DELETE_STOCK:
+ return new DeleteStockCommand(parameters);
+ case DELETE_ORDER:
+ return new DeleteOrderCommand(parameters);
+ case EXIT:
+ return new ExitCommand();
+ case HELP:
+ return new HelpCommand();
+ case LIST_PRESCRIPTION:
+ return new ListPrescriptionCommand(parameters);
+ case LIST_STOCK:
+ return new ListStockCommand(parameters);
+ case LIST_ORDER:
+ return new ListOrderCommand(parameters);
+ case PURGE:
+ return new PurgeCommand();
+ case RECEIVE_ORDER:
+ return new ReceiveOrderCommand(parameters);
+ case UPDATE_STOCK:
+ return new UpdateStockCommand(parameters);
+ case UPDATE_PRESCRIPTION:
+ return new UpdatePrescriptionCommand(parameters);
+ case UPDATE_ORDER:
+ return new UpdateOrderCommand(parameters);
+ default:
+ throw new InvalidCommandException();
+ }
+ }
+
+ /**
+ * Splits the user input into command and command parameters.
+ *
+ * @param userInput String input from user.
+ * @return Array of string with size 2 with index 0 representing the command and index 1 representing the
+ * command parameters.
+ */
+ public String[] parseCommand(String userInput) {
+ // Splits user input by spaces
+ String[] userInputSplit = userInput.trim().split(SPACE_DELIMITER, 2);
+
+ assert (userInputSplit.length <= 2) : "Command extraction failed! More than 2 values were returned!";
+
+ String command = userInputSplit[0].toLowerCase();
+ String commandParameters = "";
+ if (userInputSplit.length > 1) { // Ensure command parameter exists
+ commandParameters = userInputSplit[1].toUpperCase();
+ }
+ return new String[]{command, commandParameters};
+ }
+
+ /**
+ * Returns all the parameters entered as a LinkedHashMap.
+ *
+ * @param parameterString String of parameters.
+ * @return LinkedHashMap with parameter as key and parameter contents as value.
+ */
+ public LinkedHashMap parseParameters(String parameterString) {
+ LinkedHashMap parameters = new LinkedHashMap<>();
+
+ if (parameterString.equals("")) { // Ensure parameter string is not empty
+ return parameters;
+ }
+
+ String[] parameterSplit = parameterString.split(SPACE_DELIMITER); // Split by space
+
+ String commandParameter = "";
+ StringBuilder parameterContents = new StringBuilder();
+
+ for (String s : parameterSplit) {
+ if (s.contains(DELIMITER)) {
+ if (!commandParameter.equals("")) { // Ensure it is not the first iteration
+ // Add to linkedhashmap before resetting values
+ parameters.put(commandParameter, parameterContents.toString());
+ }
+
+ parameterContents = new StringBuilder(); // Reset the values
+ String[] commandSplit = s.split(DELIMITER);
+
+ if (commandSplit.length != 0) { // Ensure '/' exists
+ commandParameter = commandSplit[0].toLowerCase();
+ }
+
+ if (commandSplit.length > 1) {
+ parameterContents = new StringBuilder(commandSplit[1]);
+ }
+ } else { // Add the rest of the string
+ parameterContents.append(" ").append(s);
+ }
+ }
+ parameters.put(commandParameter, parameterContents.toString()); // Add to linkedhashmap for the last parameter
+ return parameters;
+ }
+
+ /**
+ * Helps to set the mode of the program.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param command Command entered by the user.
+ * @param mode Current mode of the program.
+ * @return New mode requested by the user.
+ */
+ public Mode changeMode(Ui ui, String command, Mode mode) {
+ Mode newMode = mode;
+ if (command.equalsIgnoreCase(STOCK.name()) && !mode.name().equalsIgnoreCase(STOCK.name())) {
+ newMode = STOCK;
+ ui.print("Mode has changed to STOCK.");
+ } else if (command.equalsIgnoreCase(Mode.PRESCRIPTION.name())
+ && !mode.name().equalsIgnoreCase(PRESCRIPTION.name())) {
+ newMode = Mode.PRESCRIPTION;
+ ui.print("Mode has changed to PRESCRIPTION.");
+ } else if (command.equalsIgnoreCase(ORDER.name()) && !mode.name().equalsIgnoreCase(ORDER.name())) {
+ newMode = ORDER;
+ ui.print("Mode has changed to ORDER.");
+ } else {
+ ui.print("Already in " + mode.name() + " mode!");
+ }
+ return newMode;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/utilities/parser/DateParser.java b/src/main/java/utilities/parser/DateParser.java
new file mode 100644
index 0000000000..3a7f61cfdd
--- /dev/null
+++ b/src/main/java/utilities/parser/DateParser.java
@@ -0,0 +1,61 @@
+package utilities.parser;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.Calendar;
+import java.util.Date;
+
+//@@author alvintan01
+
+/**
+ * Contains the parser for date objects.
+ */
+public class DateParser {
+ public static final String INPUT_DATE_FORMAT = "d-M-yyyy";
+ public static final String OUTPUT_DATE_FORMAT = "dd-MM-yyyy";
+
+ /**
+ * Helps to parse a string to a LocalDate object.
+ *
+ * @param date String date to be converted.
+ * @return LocalDate object representing date.
+ * @throws ParseException If date is invalid.
+ */
+ public static Date stringToDate(String date) throws ParseException {
+ try {
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(INPUT_DATE_FORMAT);
+ dateTimeFormatter.parse(date); // To check if date was in valid format
+ } catch (DateTimeParseException e) {
+ throw new ParseException("Unknown date", 0);
+ }
+ return new SimpleDateFormat(INPUT_DATE_FORMAT).parse(date);
+ }
+
+ /**
+ * Helps to parse a LocalDate object to string.
+ *
+ * @param date Date object to be converted to string.
+ * @return String value of date.
+ */
+ public static String dateToString(Date date) {
+ return new SimpleDateFormat(OUTPUT_DATE_FORMAT).format(date);
+ }
+
+ /**
+ * Helps to remove time from date object.
+ *
+ * @param date Date object which time will be removed.
+ * @return Date object without time.
+ */
+ public static Date removeTime(Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ return cal.getTime();
+ }
+}
diff --git a/src/main/java/utilities/parser/FileParser.java b/src/main/java/utilities/parser/FileParser.java
new file mode 100644
index 0000000000..026c7260f0
--- /dev/null
+++ b/src/main/java/utilities/parser/FileParser.java
@@ -0,0 +1,418 @@
+package utilities.parser;
+
+import errors.InvalidDataException;
+
+import java.text.ParseException;
+import java.util.Date;
+import java.util.HashSet;
+
+//@@author RemusTeo
+
+/**
+ * FileParser class handles all validation of input from data/stock.txt, data/order.txt, data/prescription.txt
+ */
+public class FileParser {
+ private static HashSet stockIds = new HashSet<>();
+ private static HashSet orderIds = new HashSet<>();
+ private static HashSet prescriptionIds = new HashSet<>();
+
+ /**
+ * Perform validation of Stock Id during parsing from file.
+ *
+ * @param splitStockDetails Stock details array fields split by delimiter '|'.
+ * @param stockRow Stock row identifier for use in error message.
+ * @return Stock Id of integer data type for creation of Stock object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static int parseStockId(String[] splitStockDetails, int stockRow) throws InvalidDataException {
+ try {
+ int stockId = Integer.parseInt(splitStockDetails[0]);
+ if (stockId <= 0) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK ID [data/stock.txt]");
+ }
+ if (stockIds.contains(stockId)) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK ID [data/stock.txt]");
+ }
+ stockIds.add(stockId);
+ return stockId;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK ID [data/stock.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Stock name during parsing from file.
+ *
+ * @param splitStockDetails Stock details array fields split by delimiter '|'.
+ * @param stockRow Stock row identifier for use in error message.
+ * @return Stock name of String data type for creation of Stock object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static String parseStockName(String[] splitStockDetails, int stockRow) throws InvalidDataException {
+ String stockName = splitStockDetails[1];
+ if (stockName.equals("")) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK MEDICINE NAME [data/stock.txt]");
+ }
+ return stockName;
+ }
+
+ /**
+ * Perform validation of Stock price during parsing from file.
+ *
+ * @param splitStockDetails Stock details array fields split by delimiter '|'.
+ * @param stockRow Stock row identifier for use in error message.
+ * @return Stock price of double data type for creation of Stock object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static Double parseStockPrice(String[] splitStockDetails, int stockRow) throws InvalidDataException {
+ try {
+ double stockPrice = Double.parseDouble(splitStockDetails[2]);
+ if (stockPrice < 0) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK PRICE [data/stock.txt]");
+ }
+ return stockPrice;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK PRICE [data/stock.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Stock quantity during parsing from file.
+ *
+ * @param splitStockDetails Stock details array fields split by delimiter '|'.
+ * @param stockRow Stock row identifier for use in error message.
+ * @return Stock quantity of integer data type for creation of Stock object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static int parseStockQuantity(String[] splitStockDetails, int stockRow) throws InvalidDataException {
+ try {
+ int stockQuantity = Integer.parseInt(splitStockDetails[3]);
+ if (stockQuantity < 0) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK QUANTITY [data/stock.txt]");
+ }
+ return stockQuantity;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK QUANTITY [data/stock.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Stock expiry date during parsing from file.
+ *
+ * @param splitStockDetails Stock details array fields split by delimiter '|'.
+ * @param stockRow Stock row identifier for use in error message.
+ * @return Stock expiry date of Date data type for creation of Stock object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static Date parseStockExpiry(String[] splitStockDetails, int stockRow) throws InvalidDataException {
+ try {
+ String dateExpiryStr = splitStockDetails[4];
+ Date stockExpiry = DateParser.stringToDate(dateExpiryStr);
+ return stockExpiry;
+ } catch (ParseException e) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK EXPIRY DATE [data/stock.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Stock description during parsing from file.
+ *
+ * @param splitStockDetails Stock details array fields split by delimiter '|'.
+ * @param stockRow Stock row identifier for use in error message.
+ * @return Stock description of String data type for creation of Stock object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static String parseStockDescription(String[] splitStockDetails, int stockRow) throws InvalidDataException {
+ String stockDescription = splitStockDetails[5];
+ if (stockDescription.equals("")) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK DESCRIPTION [data/stock.txt]");
+ }
+ return stockDescription;
+ }
+
+ /**
+ * Perform validation of Stock max quantity during parsing from file.
+ *
+ * @param splitStockDetails Stock details array fields split by delimiter '|'.
+ * @param stockRow Stock row identifier for use in error message.
+ * @return Stock max quantity of integer data type for creation of Stock object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static int parseStockMaxQuantity(String[] splitStockDetails, int stockRow) throws InvalidDataException {
+ try {
+ int stockMaxQuantity = Integer.parseInt(splitStockDetails[6]);
+ if (stockMaxQuantity < 0) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK MAX QUANTITY [data/stock.txt]");
+ }
+ return stockMaxQuantity;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK MAX QUANTITY [data/stock.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Stock isDeleted field during parsing from file.
+ *
+ * @param splitStockDetails Stock details array fields split by delimiter '|'.
+ * @param stockRow Stock row identifier for use in error message.
+ * @return Stock isDeleted of boolean data type for creation of Stock object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static boolean parseStockIsDeleted(String[] splitStockDetails, int stockRow) throws InvalidDataException {
+ String isDeleted = splitStockDetails[7];
+ if (isDeleted.equalsIgnoreCase("TRUE") || isDeleted.equalsIgnoreCase("FALSE")) {
+ boolean stockIsDeleted = Boolean.parseBoolean(splitStockDetails[7]);
+ return stockIsDeleted;
+ } else {
+ throw new InvalidDataException("[ROW: " + stockRow + "] INVALID STOCK ISDELETED [data/stock.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Order Id during parsing from file.
+ *
+ * @param splitOrderDetails Order details array fields split by delimiter '|'.
+ * @param orderRow Order row identifier for use in error message.
+ * @return Order Id of integer data type for creation of Order object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static int parseOrderId(String[] splitOrderDetails, int orderRow) throws InvalidDataException {
+ try {
+ int orderId = Integer.parseInt(splitOrderDetails[0]);
+ if (orderId <= 0) {
+ throw new InvalidDataException("[ROW: " + orderRow + "] INVALID ORDER ID [data/order.txt]");
+ }
+ if (orderIds.contains(orderId)) {
+ throw new InvalidDataException("[ROW: " + orderRow + "] INVALID ORDER ID [data/order.txt]");
+ }
+ orderIds.add(orderId);
+ return orderId;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + orderRow + "] INVALID ORDER ID [data/order.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Order medication name during parsing from file.
+ *
+ * @param splitOrderDetails Order details array fields split by delimiter '|'.
+ * @param orderRow Order row identifier for use in error message.
+ * @return Order medication name of String data type for creation of Order object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static String parseOrderName(String[] splitOrderDetails, int orderRow) throws InvalidDataException {
+ String orderName = splitOrderDetails[1];
+ if (orderName.equals("")) {
+ throw new InvalidDataException("[ROW: " + orderRow + "] INVALID ORDER MEDICINE NAME [data/order.txt]");
+ }
+ return orderName;
+ }
+
+ /**
+ * Perform validation of Order quantity during parsing from file.
+ *
+ * @param splitOrderDetails Order details array fields split by delimiter '|'.
+ * @param orderRow Order row identifier for use in error message.
+ * @return Order quantity of integer data type for creation of Order object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static int parseOrderQuantity(String[] splitOrderDetails, int orderRow) throws InvalidDataException {
+ try {
+ int orderQuantity = Integer.parseInt(splitOrderDetails[2]);
+ if (orderQuantity <= 0) {
+ throw new InvalidDataException("[ROW: " + orderRow + "] INVALID ORDER QUANTITY [data/order.txt]");
+ }
+ return orderQuantity;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + orderRow + "] INVALID ORDER QUANTITY [data/order.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Order date during parsing from file.
+ *
+ * @param splitOrderDetails Order details array fields split by delimiter '|'.
+ * @param orderRow Order row identifier for use in error message.
+ * @return Order date of Date data type for creation of Order object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static Date parseOrderDate(String[] splitOrderDetails, int orderRow) throws InvalidDataException {
+ try {
+ String orderDateStr = splitOrderDetails[3];
+ Date orderDate = DateParser.stringToDate(orderDateStr);
+ return orderDate;
+ } catch (ParseException e) {
+ throw new InvalidDataException("[ROW: " + orderRow + "] INVALID ORDER DATE [data/order.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Order status during parsing from file.
+ *
+ * @param splitOrderDetails Order details array fields split by delimiter '|'.
+ * @param orderRow Order row identifier for use in error message.
+ * @return Order status of boolean data type for creation of Order object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static boolean parseOrderStatus(String[] splitOrderDetails, int orderRow) throws InvalidDataException {
+ String orderStatusStr = splitOrderDetails[4];
+ boolean orderStatus;
+ if (orderStatusStr.equalsIgnoreCase("DELIVERED")) {
+ orderStatus = true;
+ return orderStatus;
+ } else if (orderStatusStr.equalsIgnoreCase("PENDING")) {
+ orderStatus = false;
+ return orderStatus;
+ } else {
+ throw new InvalidDataException("[ROW: " + orderRow + "] INVALID ORDER STATUS [data/order.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Prescription Id during parsing from file.
+ *
+ * @param splitPrescriptionDetails Prescription details array fields split by delimiter '|'.
+ * @param prescriptionRow Prescription row identifier for use in error message.
+ * @return Prescription Id of integer data type for creation of Prescription object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static int parsePrescriptionId(String[] splitPrescriptionDetails, int prescriptionRow)
+ throws InvalidDataException {
+ try {
+ int prescriptionId = Integer.parseInt(splitPrescriptionDetails[0]);
+ if (prescriptionId <= 0) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION "
+ + "ID [data/prescription.txt]");
+ }
+ if (prescriptionIds.contains(prescriptionId)) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION "
+ + "ID [data/prescription.txt]");
+ }
+ prescriptionIds.add(prescriptionId);
+ return prescriptionId;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION "
+ + "ID [data/prescription.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Prescription medication name during parsing from file.
+ *
+ * @param splitPrescriptionDetails Prescription details array fields split by delimiter '|'.
+ * @param prescriptionRow Prescription row identifier for use in error message.
+ * @return Prescription medication name of String data type for creation of Prescription object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static String parsePrescriptionName(String[] splitPrescriptionDetails, int prescriptionRow)
+ throws InvalidDataException {
+ String prescriptionName = splitPrescriptionDetails[1];
+ if (prescriptionName.equals("")) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIBED MEDICATION NAME "
+ + "[data/prescription.txt]");
+ }
+ return prescriptionName;
+ }
+
+ /**
+ * Perform validation of Prescription quantity during parsing from file.
+ *
+ * @param splitPrescriptionDetails Prescription details array fields split by delimiter '|'.
+ * @param prescriptionRow Prescription row identifier for use in error message.
+ * @return Prescription quantity of integer data type for creation of Prescription object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static int parsePrescriptionQuantity(String[] splitPrescriptionDetails, int prescriptionRow) throws
+ InvalidDataException {
+ try {
+ int prescriptionQuantity = Integer.parseInt(splitPrescriptionDetails[2]);
+ if (prescriptionQuantity <= 0) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION QUANTITY"
+ + " [data/prescription.txt]");
+ }
+ return prescriptionQuantity;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION "
+ + "QUANTITY [data/prescription.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Prescription customer id during parsing from file.
+ *
+ * @param splitPrescriptionDetails Prescription details array fields split by delimiter '|'.
+ * @param prescriptionRow Prescription row identifier for use in error message.
+ * @return Prescription customer id of String data type for creation of Prescription object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static String parsePrescriptionCustomerId(String[] splitPrescriptionDetails, int prescriptionRow) throws
+ InvalidDataException {
+ String prescriptionCustomerId = splitPrescriptionDetails[3];
+ if (prescriptionCustomerId.equals("")) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION CUSTOMER ID "
+ + "[data/prescription.txt]");
+ }
+ return prescriptionCustomerId;
+ }
+
+ /**
+ * Perform validation of Prescription date during parsing from file.
+ *
+ * @param splitPrescriptionDetails Prescription details array fields split by delimiter '|'.
+ * @param prescriptionRow Prescription row identifier for use in error message.
+ * @return Prescription date of Date data type for creation of Prescription object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static Date parsePrescriptionDate(String[] splitPrescriptionDetails, int prescriptionRow)
+ throws InvalidDataException {
+ try {
+ String prescriptionDateStr = splitPrescriptionDetails[4];
+ Date prescriptionDate = DateParser.stringToDate(prescriptionDateStr);
+ return prescriptionDate;
+ } catch (ParseException e) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION DATE "
+ + "[data/prescription.txt]");
+ }
+ }
+
+ /**
+ * Perform validation of Prescription staff name during parsing from file.
+ *
+ * @param splitPrescriptionDetails Prescription details array fields split by delimiter '|'.
+ * @param prescriptionRow Prescription row identifier for use in error message.
+ * @return Prescription staff name of String data type for creation of Prescription object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static String parsePrescriptionStaff(String[] splitPrescriptionDetails, int prescriptionRow) throws
+ InvalidDataException {
+ String prescriptionStaff = splitPrescriptionDetails[5];
+ if (prescriptionStaff.equals("")) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION STAFF NAME "
+ + "[data/prescription.txt]");
+ }
+ return prescriptionStaff;
+ }
+
+ /**
+ * Perform validation of Prescription stock id during parsing from file.
+ *
+ * @param splitPrescriptionDetails Prescription details array fields split by delimiter '|'.
+ * @param prescriptionRow Prescription row identifier for use in error message.
+ * @return Prescription stock id of integer data type for creation of Prescription object.
+ * @throws InvalidDataException Invalid data will trigger exception.
+ */
+ public static int parsePrescriptionStockId(String[] splitPrescriptionDetails, int prescriptionRow)
+ throws InvalidDataException {
+ try {
+ int prescriptionStockId = Integer.parseInt(splitPrescriptionDetails[6]);
+ if (prescriptionStockId <= 0) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION STOCK ID "
+ + "[data/prescription.txt]");
+ }
+ return prescriptionStockId;
+ } catch (NumberFormatException e) {
+ throw new InvalidDataException("[ROW: " + prescriptionRow + "] INVALID PRESCRIPTION STOCK ID "
+ + "[data/prescription.txt]");
+ }
+ }
+}
diff --git a/src/main/java/utilities/parser/MedicineValidator.java b/src/main/java/utilities/parser/MedicineValidator.java
new file mode 100644
index 0000000000..9a89b38532
--- /dev/null
+++ b/src/main/java/utilities/parser/MedicineValidator.java
@@ -0,0 +1,242 @@
+package utilities.parser;
+
+import command.CommandParameters;
+import inventory.Medicine;
+import utilities.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Contains all the methods to validate if a Medicine's input parameters are valid.
+ */
+public abstract class MedicineValidator {
+ private static Logger logger = Logger.getLogger("MedicineValidator");
+
+ public MedicineValidator() {
+ }
+
+ public abstract boolean containsInvalidParameterValues(Ui ui, LinkedHashMap parameters,
+ ArrayList medicines, String commandSyntax,
+ ArrayList invalidParameters);
+
+ public abstract boolean isValidColumn(Ui ui, String columnName);
+
+ /**
+ * Helps to check if the parameters and values required are provided by the user.
+ *
+ * @param ui Reference to the UI object to print messages.
+ * @param medicines Arraylist of all medicines.
+ * @param parameters Parameters entered in by the user.
+ * @param requiredParameters Parameters required by the command.
+ * @param optionalParameters Parameters that are optional.
+ * @param commandSyntax The command's valid syntax.
+ * @param requiresOptionalParameters Boolean value of whether command required optional parameters.
+ * @param validator Validator object used for validation checks.
+ * @return A boolean value indicating if the parameters and values required are entered by the user.
+ */
+ public boolean containsInvalidParametersAndValues(Ui ui, ArrayList medicines,
+ LinkedHashMap