diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 11c47bf5ab..2f0bf5ef93 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -13,7 +13,7 @@ - [Transaction and TransactionManager](#transaction-and-transactionmanager) - [StringMatcher](#stringmatcher) - [Order](#order) - - [Visualizer](#Visualizer ) + - [Visualizer](#visualizer) - [Parser](#parser) - [DateTime](#datetime) - [TimeStampIO](#timestampio) @@ -161,6 +161,8 @@ The usage of TreeSet is to facilitate storing multiple batches of items with different expiry dates and quantities, and to be able to extract items with the soonest expiry date when taking out of storage. + + ### Order Orders are from the perspective of the Inventory, so purchases is items being @@ -179,11 +181,61 @@ and analyze their inventory data through visual representation. ![](diagrams/Visualizer-ClassDiagram.png) + + ### Parser -Deals with parsing of user inputs to corresponding commands, and also handles -the execution of those commands. Private helper methods throw PillException, -but they are all caught within Parser itself, and do not propagate out of Parser. +The Parser class is responsible for interpreting and executing user commands +within the application. It translates raw user input into actionable commands, +checks for common errors, and ensures the commands are executed in a controlled +and predictable way. The class contains several helper methods that assist in +interpreting specific command formats, while the main parseCommand method +coordinates this process. + +#### Responsibilities +- Input Parsing: Parser takes a single line of user input, splits it into its + component parts (command and arguments), and identifies which command the + user intended to execute. +- Command Dispatching: Based on the parsed command, Parser creates the + appropriate command object (e.g., AddCommand, DeleteCommand, EditCommand) and + invokes its execute method. +- Error Handling: All exceptions related to parsing and validation (encapsulated + in PillException) are handled directly within Parser. This ensures that any + invalid input or command errors are handled without propagating out. + +#### Key Functionalities + +1. Command Recognition: + The first word of each input string determines the command type. For example, + “add” initiates the AddCommand, while “delete” initiates the DeleteCommand. + Commands can also support optional flags and arguments, parsed from the + remaining components of the input. + +2. Argument and Flag Parsing: + After identifying the command, Parser extracts and verifies additional + arguments, flags, and parameters. Specific commands (e.g., stock-check, + expiring) have strict requirements on the number and format of arguments, which + are validated before command execution. + +3. Command Execution: + For each recognized command, the corresponding command object is created and + its execute method is invoked with any necessary arguments. All command objects + receive items and storage as parameters, enabling them to interact with the + application’s data layer. + +4. Exception Management: + Each helper method that parses specific commands may throw a PillException + for invalid arguments, unsupported commands, or unexpected input formats. + These exceptions are caught within the parseCommand method, allowing Parser + to handle error messages consistently across the application. + +#### Assumptions + +Parser expects commands to follow a specific format. For instance, commands +like `add` require additional arguments, while commands like `list` and `exit` +require none. Only recognized commands will proceed to execution; any unrecognized +command results in a PillException. + ### Exceptions @@ -194,6 +246,7 @@ getMessage(), ensuring consistent error descriptions across the application. Most importantly, this keeps code of thrown exceptions readable. Example usage: + ``` } catch (NumberFormatException e) { throw new PillException(ExceptionMessages.INVALID_INDEX); @@ -212,7 +265,9 @@ handle logging across the entire application. PillLogger implements the singleto logger instance, which manages log creation, configuration, and output redirection. #### Key Components -- File Output Configuration: The log level for file output is set by the `fileHandler.setLevel()` call, using `Level.ALL` to + +- File Output Configuration: The log level for file output is set by the `fileHandler.setLevel()` call, using + `Level.ALL` to capture all events during execution. The log file, named according to the `FILE_NAME` attribute, is created in the directory specified by `PATH`. @@ -221,12 +276,15 @@ logger instance, which manages log creation, configuration, and output redirecti debugging. #### Resilience and Error Handling + In the event of a failure in log file creation, PillLogger logs the error to the console and allows the application to continue running. This design ensures the application’s functionality is not hindered by logging setup issues. #### API Access + PillLogger exposes a single public method, `getLogger()`, which provides application-wide access to the singleton Logger -instance. Classes within the application use `getLogger()` to record events, without needing to set up or manage their own +instance. Classes within the application use `getLogger()` to record events, without needing to set up or manage their +own loggers. @@ -262,24 +320,46 @@ complexity. ## Non-Functional Requirements -* Technical Requirements: Any mainstream OS, i.e. Windows, macOS or Linux, with Java 11 installed. Instructions for downloading Java 11 can be found [here](https://www.oracle.com/sg/java/technologies/javase/jdk11-archive-downloads.html). -* Project Scope Constraints: The application should only be used for tracking. It is not meant to be involved in any form of monetary transaction. +* Technical Requirements: Any *mainstream OS* with Java 17 or above installed. + Instructions for downloading Java 17 can be found + [here](https://www.oracle.com/sg/java/technologies/javase/jdk17-archive-downloads.html). +* Project Scope Constraints: The application should only be used for tracking. It is not meant to be involved in any + form of monetary transaction. * Project Scope Constraints: Data storage is only to be performed locally. -* Quality Requirements: The application should be able to be used effectively by a novice with little experience with CLIs. +* Quality Requirements: The application should be able to be used effectively by a novice with little experience with + CLIs. ## Glossary -[ADD GLOSSARY HERE] +- **Mainstream OS**: Windows, Linux, Unix, MacOS +- **CLI (Command-Line Interface)**: A text-based user interface used to interact with software by typing commands. +- **UI (User Interface)**: The components and layout of a software application + with which users interact, including visual elements like buttons, screens, + and command prompts that facilitate user interaction with the program. +- **I/O (Input/Output)**: The communication between a program and the external + environment, such as receiving data from the user (input) or displaying results + to the user (output). +- **JUnit**: A testing framework for Java that allows developers to write and run + repeatable automated tests. +- **Gradle**: A build automation tool for Java (and other languages) used to compile, test, and package applications. +- **Text UI Testing**: A form of testing where interactions with a command-line + interface are tested by simulating user input and validating the application’s text output. +- **Pharmaceutical Inventory**: Refers to the stock of medicines and other medical + supplies maintained by a pharmacy or healthcare facility for dispensing and logistics. +- **Expiry Date**: The date after which a pharmaceutical product is no longer considered safe or effective for use. +- **Restocking**: The process of replenishing inventory to ensure sufficient supply. ## Instructions for Testing ### Manual Testing -View the [User Guide](UserGuide.md) for the full list of UI commands and their related use case and expected outcomes. +View the [User Guide](UserGuide.md) for the full list of UI commands and +their related use case and expected outcomes. ### JUnit Testing -JUnit tests are written in the [test directory](../src/test/java/seedu/pill/) and serve to test key methods part of the application. +JUnit tests are written in the [test directory](../src/test/java/seedu/pill/) +and serve to test key methods part of the application. ### Text UI Testing @@ -287,18 +367,21 @@ Files relating to Text UI Testing can be found [here](../text-ui-test/). To run the Text UI tests, navigate to the `text-ui-test` directory in the terminal. -When running tests on a Windows system, run the following command from the specified directory: +When running tests on a Windows system, run the following command from the +specified directory: ``` ./runtest.bat ``` When running tests on a UNIX-based system, run the following command from the specified directory: + ``` ./runtest.sh ``` Outcomes of these tests are listed in the below code segment. + ``` // Successfully passed all tests All tests passed! diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 1bcfeeef5c..32f554ba74 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -3,7 +3,11 @@ **Version 2.0** 1. [Introduction](#introduction) -2. [Features](#features) +2. [Important Note](#important-note) + - [Case Sensitivity](#case-sensitivity) + - [No special characters](#no-special-characters) + - [Expiry Date](#expiry-date) +3. [Features](#features) - **General Commands** - [Viewing Help: `help`](#viewing-help-help) - [Listing All Items: `list`](#listing-all-items-list) @@ -35,10 +39,6 @@ - [Fulfill Order: `fulfill-order`](#fulfill-order-fulfill-order) - [Viewing Transactions: `transactions`](#view-transactions-transactions) - [Viewing Transaction History: `transaction-history`](#view-transactions-within-a-set-time-period-transaction-history) -3. [Important Note](#important-note) - - [Case Sensitivity](#case-sensitivity) - - [No special characters](#no-special-characters) - - [Expiry Date](#expiry-date) ## Introduction @@ -55,6 +55,39 @@ Key features: PILL is designed for users who prefer keyboard-based interactions over GUI applications, offering faster data entry and retrieval through CLI commands. + + +--- + +## Important Usage Notes + +### Case Sensitivity + +Our application is **case-sensitive**. This means that item names must match exactly as they were entered. For example: + +- `add Panadol` and `add PANADOL` will be treated as two different items. +- Similarly, commands such as `edit`, `delete` will only work if the case of the item name matches exactly as stored in the inventory. + +Ensure you use the correct capitalization when interacting with items in the inventory. + +### Order of arguments + +Our commands **do not** allow arguments in any order. Please read the documentation for the +order in which arguments should follow a command. + +### No special characters + +Our application **does not support special characters** for any input. + +Preferably, please keep to **lowercase, alphanumeric characters** for command inputs. + +### Expiry Date + +Under most commands, items with the same name but different expiry dates are treated as **different items**. Be very careful when reading command instructions: +- **Include the expiry date** with the item name for commands where it is required to ensure the correct item entry is processed. +- Always double-check the item's expiry date before executing commands like `delete` or `edit` to avoid unintentional modifications or deletions. + + ## Features @@ -89,8 +122,6 @@ Added the following item to the inventory: Aspirin: 100 in stock, expiring: 2024-05-24 ``` - - --- ### Listing All Items: `list` @@ -120,12 +151,13 @@ Listing all items: ### Deleting Existing Item: `delete` -The `delete` command is used to remove an existing item entry from the inventory. The behavior of this command depends on whether the item has an associated expiry date. +The `delete` command is used to remove an existing item entry from the inventory. The behavior of this +command depends on whether the item has an associated expiry date. **Format**: `delete NAME (EXPIRY_DATE)` - `NAME`: The name of the item you wish to delete. -- `EXPIRY_DATE`: An optional parameter in the `YYYY-MM-DD` format that must be provided if the item you want to delete has an expiry date. +- `EXPIRY_DATE`: An optional parameter in the `YYYY-MM-DD` format that **must** be provided if the item you want to delete has an expiry date. **Command Behavior**: @@ -212,7 +244,7 @@ Listing all items: **Notes**: -- The `find` command is not **case sensitive**. This means that `find PANADOL` and `find panadol` will yield the same results. +- The `find` command is **not** case-sensitive. This means that `find PANADOL` and `find panadol` will yield the same results. - Use `find` to quickly locate items, especially when you only remember part of the name. --- @@ -456,11 +488,11 @@ Completes an order by adding/removing items from the inventory. The action taken depends on the order type (purchase/dispense) and the items in the order. -**Format**: `fulfill-order ORDER_ID` +**Format**: `fulfill-order ORDER_UUID` **Sample Output**: -`> fulfill-order 1` +`> fulfill-order cec43f38-5c63-40b6-8964-00f8b4225c17` ``` Added the following item to the inventory: @@ -503,29 +535,3 @@ The system automatically saves any changes to the inventory to the hard disk aft Inventory data is stored in a `.txt` file (in `csv` format). Users can edit this file manually if necessary. - ---- - -## Important Note - -### Case Sensitivity - -Our application is **case sensitive**. This means that item names must match exactly as they were entered. For example: - -- `add Panadol` and `add PANADOL` will be treated as two different items. -- Similarly, commands such as `edit`, `delete` will only work if the case of the item name matches exactly as stored in the inventory. - -Ensure you use the correct capitalization when interacting with items in the inventory. - - -### No special characters - -Our application **does not support special characters** for any input. - -Preferably, please keep to **lowercase, alphanumeric characters** for command inputs. - -### Expiry Date - -Under most commands, items with the same name but different expiry dates are treated as **different items**. Be very careful when reading command instructions: -- **Include the expiry date** with the item name for commands where it is required to ensure the correct item entry is processed. -- Always double-check the item's expiry date before executing commands like `delete` or `edit` to avoid unintentional modifications or deletions. \ No newline at end of file diff --git a/docs/diagrams/Item-ClassDiagram.png b/docs/diagrams/Item-ClassDiagram.png index a82a6aaa2e..0813ded498 100644 Binary files a/docs/diagrams/Item-ClassDiagram.png and b/docs/diagrams/Item-ClassDiagram.png differ diff --git a/docs/diagrams/Item-ClassDiagram.puml b/docs/diagrams/Item-ClassDiagram.puml index 3bb76f4905..0384191a78 100644 --- a/docs/diagrams/Item-ClassDiagram.puml +++ b/docs/diagrams/Item-ClassDiagram.puml @@ -1,8 +1,9 @@ @startuml skinparam classAttributeIconSize 0 +hide circles -interface Comparable +interface Comparable << interface >> Comparable <|-[dashed]- Item class Item { diff --git a/docs/diagrams/ItemMap-ClassDiagram.png b/docs/diagrams/ItemMap-ClassDiagram.png index 8d53869c14..d0562c3834 100644 Binary files a/docs/diagrams/ItemMap-ClassDiagram.png and b/docs/diagrams/ItemMap-ClassDiagram.png differ diff --git a/docs/diagrams/ItemMap-ClassDiagram.puml b/docs/diagrams/ItemMap-ClassDiagram.puml index 9d58614eba..d8465acdf6 100644 --- a/docs/diagrams/ItemMap-ClassDiagram.puml +++ b/docs/diagrams/ItemMap-ClassDiagram.puml @@ -1,6 +1,7 @@ @startuml skinparam classAttributeIconSize 0 +hide circles class ItemMap { + addItem(newItem: Item) @@ -15,11 +16,12 @@ class ItemMap { ItemMap "1" *-- "1" Map : contains > -interface Map { +interface Map << interface >> { itemName: String item: TreeSet } note right of Map : Maps key(itemName) to value(item)\nHas any amount of key-value pairs +note bottom of Map : Stored as a Map, intialised as a LinkedHashMap @enduml \ No newline at end of file diff --git a/src/main/java/seedu/pill/command/HelpCommand.java b/src/main/java/seedu/pill/command/HelpCommand.java index 4d4e77eaf4..a074dabc21 100644 --- a/src/main/java/seedu/pill/command/HelpCommand.java +++ b/src/main/java/seedu/pill/command/HelpCommand.java @@ -513,14 +513,26 @@ private void showOrderHelp() { System.out.println("order: Creates a new purchase or dispense order."); if (verbose) { - System.out.println("Usage: order [item2 quantity2 ...] [-n \"notes\"]"); + System.out.println("Usage:"); + System.out.println("order "); + System.out.println(" "); + System.out.println("[item2 quantity2]"); + System.out.println("..."); + System.out.println("[-n \"notes\"]"); + System.out.println(); System.out.println(" - Type of order: 'purchase' or 'dispense'"); System.out.println(" - Name of item to order"); System.out.println(" - Quantity of the item"); System.out.println(" -n - Optional notes about the order"); System.out.println("\nExamples:"); - System.out.println(" order purchase Aspirin 100 Bandages 50 -n \"Monthly stock replenishment\""); - System.out.println(" order dispense Paracetamol 20 -n \"Emergency room request\""); + System.out.println(" order purchase 2"); + System.out.println(" Aspirin 100"); + System.out.println(" Bandages 50"); + System.out.println(" -n \"Monthly stock replenishment\""); + System.out.println(); + System.out.println(" order dispense 1"); + System.out.println(" Paracetamol 20"); + System.out.println(" -n \"Emergency room request\""); } } @@ -532,8 +544,8 @@ private void showFulfillOrderHelp() { System.out.println("fulfill-order: Processes and completes a pending order."); if (verbose) { - System.out.println("Usage: fulfill-order "); - System.out.println(" - The unique identifier of the order to fulfill"); + System.out.println("Usage: fulfill-order "); + System.out.println(" - The unique identifier of the order to fulfill"); System.out.println("\nExample:"); System.out.println(" fulfill-order 123e4567-e89b-12d3-a456-556642440000"); System.out.println("\nNote: This will create the necessary transactions and update inventory levels"); diff --git a/src/main/java/seedu/pill/util/Parser.java b/src/main/java/seedu/pill/util/Parser.java index 6c6aeb94e7..3d2ab8e70a 100644 --- a/src/main/java/seedu/pill/util/Parser.java +++ b/src/main/java/seedu/pill/util/Parser.java @@ -33,6 +33,7 @@ import java.time.LocalDateTime; import java.time.format.DateTimeParseException; import java.util.Arrays; +import java.util.List; import java.util.Optional; public class Parser { @@ -175,10 +176,10 @@ public void parseCommand(String input) { /** * Parses the arguments provided to create a {@link FulfillCommand} instance, which is used to fulfill an order. * - * @param arguments The command input containing the order index to be fulfilled. + * @param arguments The command input containing the order UUID to be fulfilled. * @return A {@link FulfillCommand} instance that contains the order and transaction manager. * @throws PillException if the input contains too many arguments, is empty, cannot be parsed as a number, - * or if the specified order index is invalid. + * or if the specified order UUID is invalid. * */ private FulfillCommand parseFulfillCommand(String arguments) throws PillException { @@ -186,14 +187,20 @@ private FulfillCommand parseFulfillCommand(String arguments) throws PillExceptio if (commandArguments.length > 1) { throw new PillException(ExceptionMessages.TOO_MANY_ARGUMENTS); } - if (commandArguments.length == 0) { + if (commandArguments.length == 0 || arguments.isEmpty()) { throw new PillException(ExceptionMessages.INVALID_FULFILL_COMMAND); } try { - Order order = transactionManager.getOrders().get(Integer.parseInt(commandArguments[0]) - 1); + List orders = transactionManager.getOrders(); + String orderToFetch = commandArguments[0]; + Order order = orders.stream() + .filter(orderInfo -> orderInfo.getId().toString().equals(orderToFetch)) + .findFirst() + .orElse(null); + if (order == null) { + throw new PillException(ExceptionMessages.INVALID_ORDER); + } return new FulfillCommand(order, transactionManager); - } catch (NumberFormatException e) { - throw new PillException(ExceptionMessages.INVALID_INDEX); } catch (IndexOutOfBoundsException e) { throw new PillException(ExceptionMessages.INVALID_ORDER); } diff --git a/src/main/java/seedu/pill/util/TransactionManager.java b/src/main/java/seedu/pill/util/TransactionManager.java index 4c1e517fbd..1c022a3cc5 100644 --- a/src/main/java/seedu/pill/util/TransactionManager.java +++ b/src/main/java/seedu/pill/util/TransactionManager.java @@ -201,12 +201,16 @@ public void listTransactions() { */ public void listOrders() { List orders = getOrders(); - IntStream.rangeClosed(1, orders.size()) - .forEach(i -> { - System.out.print(i + ". "); - orders.get(i - 1).listItems(); - System.out.println(); - }); + if (orders.isEmpty()) { + System.out.println("No orders recorded..."); + } else { + IntStream.rangeClosed(1, orders.size()) + .forEach(i -> { + System.out.print(i + ". "); + orders.get(i - 1).listItems(); + System.out.println(); + }); + } } /** diff --git a/src/main/java/seedu/pill/util/OrderItem.java b/unused/OrderItem.java similarity index 97% rename from src/main/java/seedu/pill/util/OrderItem.java rename to unused/OrderItem.java index 06d0f48a5f..af9a8b8385 100644 --- a/src/main/java/seedu/pill/util/OrderItem.java +++ b/unused/OrderItem.java @@ -1,3 +1,8 @@ +//@@author philip1304-unused +/* + * We ended up using regular Items in another ItemMap, rather than using a + * different type of item. + */ package seedu.pill.util; import java.time.LocalDate; diff --git a/src/test/java/seedu/pill/util/OrderItemTest.java b/unused/OrderItemTest.java similarity index 99% rename from src/test/java/seedu/pill/util/OrderItemTest.java rename to unused/OrderItemTest.java index c80b708060..9f49ce7135 100644 --- a/src/test/java/seedu/pill/util/OrderItemTest.java +++ b/unused/OrderItemTest.java @@ -1,3 +1,5 @@ +//@@author philip1304-unused +// Same reason given in OrderItem.java package seedu.pill.util; import org.junit.jupiter.api.Test; diff --git a/src/main/java/seedu/pill/util/TimestampIO.java b/unused/TimestampIO.java similarity index 88% rename from src/main/java/seedu/pill/util/TimestampIO.java rename to unused/TimestampIO.java index d01e936b49..a8d9eed243 100644 --- a/src/main/java/seedu/pill/util/TimestampIO.java +++ b/unused/TimestampIO.java @@ -1,3 +1,8 @@ +//@@author philip1304-unused +/* + * We did not get around to integrating timestamps since we had too many bugs + * in our code and many other features that needed integrating at the same time. + */ package seedu.pill.util; import java.time.LocalDateTime; diff --git a/src/test/java/seedu/pill/util/TimestampIOTest.java b/unused/TimestampIOTest.java similarity index 97% rename from src/test/java/seedu/pill/util/TimestampIOTest.java rename to unused/TimestampIOTest.java index 7e5ad7360f..203c8f0e83 100644 --- a/src/test/java/seedu/pill/util/TimestampIOTest.java +++ b/unused/TimestampIOTest.java @@ -1,3 +1,5 @@ +//@@author philip1304-unused +// Same reason given in TimestampIO.java package seedu.pill.util; import org.junit.jupiter.api.AfterEach;