PROJECT: Inventory Manager

Overview

InventoryManager is for those who prefer to use a desktop app for managing their inventory. More importantly, InventoryManager is optimized for those who prefer to work with a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, InventoryManager can get your inventory management tasks done faster than traditional GUI apps.

Summary of contributions

  • Major enhancement: added Buy and Sell commands

    • What it does: Allows users to buy and sell batches of goods. The commands orchestrate the interaction between the Inventory, Supplier List, and Transaction History to validate the input and update the model properly, or notify the user otherwise.

    • Justification: This is the main functionality of the Inventory Manager, which is to keep stock, and manage all changes to, all goods currently in inventory. buy and sell commands accomplish exactly that.

    • Highlights: This feature touched upon all aspects of the Model. It required supplier information and inventory status to perform input validation to update the inventory. Then it creates a new transaction history record.

      • Since the buy and sell commands are the main avenue that our program takes input from the user, the required parameters would form the basis of other commands, especially profit analytics and historical analysis extensions. As such, it was a challenge to ensure that it was as extensible as possible because it was expected to change frequently with additional commands.

      • A total of 3 extensions were needed to buy and sell commands and their related tests.

      • As buy and sell commands needed to access all the models of persistent storage, the development of this feature also shaped the storage design and API of the underlying model to facilitate ease of access without violating encapsulation principles.

  • Minor enhancement: Added ability to delete a good entry from inventory.

  • Code contributed: [RepoSense report]

  • Documentation: Excerpts from my documentations is reproduced below.

  • Other contributions:

    • Project management:

      • Updates About Us, Contact Us, ReadMe page ( #45 )

      • Set up Appveyor CI

    • Enhancements to existing features:

      • Refactored ModelStubs used for easier model-related testing.

    • Community:

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

User Guide: Buy Command section

Buying goods from supplier: buy (By Pang Jia Da)

Buys a batch of goods from a supplier in the contact list who stocks that product. The inventory manager cannot buy products in the following cases:

  1. The supplier has not been entered in the supplier list

  2. The supplier has not been registered to the good, as indicated by the "offers" section of each supplier

Format: buy SUPPLIER_DISPLAY_INDEX g/GOOD_NAME q/QUANTITY

Example:

  • buy 1 g/Apple q/4
    Buys 4 apples from supplier at displayed index 1 in the supplier list.

If the good does not exist in the inventory, a new entry for that good will be created.
The maximum quantity of any good in the inventory is 999,999. Users are not allowed to buy quantities of goods that would cause that limit to be exceeded.

User Guide: Sell Command section

Selling goods: sell (By Pang Jia Da)

Sells a particular goods from the inventory.

The inventory manager cannot sell products in the following cases:

  1. The good being sold does not exist in the inventory

  2. The quantity being sold is larger than the amount existing in the inventory

Format: sell GOOD_DISPLAYED_INDEX q/QUANTITY p/PRICE

Example:

  • sell 1 q/4 p/3.5
    Sells 4 units of good at displayed index 1 in the inventory at $3.50 each.

The selling price can be specified to the nearest cent, or 2 decimal places maximum.
When the quantity in inventory reaches 0, the name of the good is not deleted for future reference or restocking. This entry can be deleted using the delete-g command.

User Guide: Delete Good Command section

Delete good entry in inventory: delete-g (By Pang Jia Da)

Deletes an entry for a good in the inventory. The good to be deleted is at the displayed index shown in the middle inventory panel. All of the good’s quantity will be removed in the process.

Format: delete-g INDEX

Example:

  • delete-g 3 The good entry at displayed index 3 will be removed, provided there is an entry at index 3.

No transaction history will be recorded for delete-g. This command is meant to recove goods with no quantity in the inventory when reference to them is no longer required. If there are quantities being transacted, buy and sell should be used instead.

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

UML Diagrams

Developer Guide: Buy and Sell Command

Buy and Sell Commands (By Pang Jia Da)

The buy and sell commands are the main ways a user is expected to interact with the Inventory Manager, and encompasses the bulk of the commands a user is going to enter into Inventory Manager.

Commonalities in Implementation of buy and sell

Both buy and sell commands are required to accomplish 3 things:

  1. Update the quantity in the inventory, subject to their respective validity checks.

  2. Create a transaction record of itself to be added to the transaction history.

  3. Commit the mutated model to facilitate proper functioning of undo and redo commands

The API that Model exposes has been structured to mirror the requirements of the commands. The above 3 requirements can be satisfied by calls to:

  1. Model#setGood()

  2. Model#addTransaction()

  3. Model#commit().

Specifics of buy Command

The two ways buy executes successfully depends on whether the good already exists in the inventory or not.

  • If the good does not already exist, then a new Good entry has to be created with the quantity bought.

  • If it does exist, then the existing good entry has to be retrieved, and the quantity updated.

Developers modifying existing Good related information must be aware that Goods are immutable. In updating only the quantity field, all other fields must be correctly duplicated to the updated Good entry created. Common mistakes are to omit those fields, resulting in loss of persistent Good related information. To make explicit this requirement to future Developers, multiple constructors have been created with their respective purposes documented: Good(), Good.newGoodEntry(), Good.goodWithName().
Buy Command Input Constraints

The following constraints have been put on buy command inputs. Their reasons are discussed in the following section. Users will not be allowed to:

  1. Purchase from a supplier that is not in the supplier list

  2. Purchase a good that the supplier does not offer.

  3. Purchase a quantity of good that would cause the total quantity of any individual good in the inventory to exceed the Good limit.

The maximum Good limit is 999,999.

Developers seeking to modify the buy command must respect the above 3 input validations as they form the basis of future features.

The buy command format is: buy SUPPLIER_DISPLAYED_INDEX g/GOODNAME q/QUANTITY

The current implementation of buy performs validation of the above respectively as follows:

  1. The SUPPLIER_DISPLAYED_INDEX must be within the length of list of suppliers returned by Model#getFilteredSupplierList().

  2. Get the offers of the supplier through Supplier#getOffers(). Iterate through the Set<Offer> of the selected supplier to find existence of an Offer with GOODNAME.

  3. Reuse the inbuilt quantity validation in the Good constructor to test if the resulting inventory quantity is valid. A Good with the new quantity is constructed. If the quantity is invalid, an error is thrown and the relevant feedback to the user returned.

Design Considerations

Aspect: Format of buy command
  • Alternative 1 (current choice): buy SUPPLIER_DISPLAYED_INDEX g/GOODNAME q/QUANTITY.

    • Pros:

      • Users would not have to type out the entire Supplier’s name in full and case sensitive. This increases command input speed and further optimizes usage for fast typists. Wasted time from typos in minimized.

      • Verification that a supplier exists in the supplier list is trivial. The supplier at the given index only needs to be retrieved.

    • Cons:

      • We lose the flexibility of having input parameters being unordered. All inputs with a prefix flag, e.g. g/, can be input in any order, but now the SUPPLIER_DISPLAYED_INDEX has to be the first parameter.

      • Additional cognitive burden on users to remember the buy command format’s first parameter.

  • Alternative 2: buy n/SUPPLIER_NAME g/GOODNAME q/QUANTITY.

    • Pros: Flexibility of having unordered input is maintained.

    • Cons: Testing revealed that command entry was tedious and error prone, especially since supplier names tended to be long and a mix of upper- and lower- case alphabets, reducing user-friendliness.

Aspect: buy Input Constraints:
  • Alternative 1 (current choice): Supplier has to exist in supplier list before purchase.

    • Pros:

      • Supports future data analytics commands. We can save all relevant transaction information with every particular supplier at the point of transaction because the supplier will have to exist in the supplier list. The feasible future features include: cost analysis and ranking of suppliers by certain parameters.

      • Users do not have to enter an additional parameter: purchase price, since this can be extracted from the Supplier’s offer under the hood.

    • Cons: If user has making a new purchase, he or she has to first perform data entry for the supplier and all it’s relevant information before the buy command can be executed.

  • Alternative 2: Supplier would be an optional parameter to the buy command.

    • Pros: Command usage is more fluid and user-friendly.

    • Cons: Cost and supplier related data would be incomplete, reducing comprehensiveness of data analytics commands.

Specifics of sell Command

Sell Command Input Constraints

The following constraints have been put on sell command inputs. Their reasons are discussed in the following section. Users will not be allowed to:

  1. Sell a good they do not currently have in inventory.

  2. Sell a quantity a larger quantity of a good than they currently have in inventory.

The minimum Good limit is 0.

Developers seeking to modify the sell command must respect the above 2 input validations as they form the basis of future features.

The sell command format is: sell GOOD_DISPLAYED_INDEX p/PRICE q/QUANTITY

The current implementation of sell performs validation as follows:

  1. The GOOD_DISPLAYED_INDEX must be within the length of list of Goods returned by Model#getFilteredGoodList().

  2. Reuse the inbuilt quantity validation in the Good constructor to test if the resulting inventory quantity is valid. A Good with the new quantity is constructed. If the quantity is invalid, an error is thrown and the relevant feedback to the user returned.

Design Considerations

Aspect: Format of sell command
  • Alternative 1 (current choice): sell GOOD_DISPLAYED_INDEX p/PRICE q/QUANTITY.

    • Pros:

      • Users would not have to type out the entire Good’s name in full and case sensitive. This increases command input speed and further optimizes usage for fast typists. Wasted time from typos in minimized.

      • Verification that a good exists in the inventory is trivial. The good at the given index only needs to be retrieved.

    • Cons:

      • We lose the flexibility of having input parameters being unordered. All inputs with a prefix flag, e.g. g/, can be input in any order, but now the GOOD_DISPLAYED_INDEX has to be the first parameter.

      • Additional cognitive burden on users to remember the sell command format’s first parameter.

  • Alternative 2: sell g/GOOD_NAME p/PRICE q/QUANTITY.

    • Pros: Flexibility of having unordered input is maintained.

    • Cons: Testing revealed that command entry was tedious and error prone, especially since Good names tended to be long and a mix of upper- and lower- case alphabets, reducing user-friendliness.

Developer Guide: Proposed Automatic Expiry Feature

[Proposed] Automatic Batch Expiry and Warning (By Pang Jia Da)

The primary aim of inventory management is to ensure that there is always sufficient stock of goods. Out-of-stock situations cost the company needless revenue losses.

When stores sell fast moving consumer goods with short shelf lives, this problem becomes hard to solve when every individual batch of purchases have their respective expiry dates.

This feature aims to augment every buy command with it’s respective EXPIRY_DATE. When the expiry date approaches, unsold goods from that batch would automatically be removed from the inventory, the user would be notified of the expiration and warned if that causes the good to fall below it’s stipulated threshold. The command to source for suppliers who sell that good can also be triggered to facilitate restocking of that good.

Proposed Implementation

Proposed Changes to Good class

Inventory Manager v1.4 currently stores the name, current quantity, and threshold quantity of every good in the inventory. An expiryDates field will be added to store all distinct expiry dates, from closest to furthest, and the number of units expiring on that date. Java’s built-in Date class will suffice.

GoodWithExpiryDate

Proposed Changes to buy Command

The buy command will include an expiry date for every purchase goods. A possible format would be: buy SUPPLIER_DISPLAYED_INDEX q/QUANTITY g/GOOD_NAME x/EXPIRY_DATE. This assigns the EXPIRY_DATE to all QUANTITY units of GOOD_NAME bought.

The correct Good entry can be retrieved from the InventoryManager. If there is currently no expiry dates on EXPIRY_DATE, a new Map.entry will be created indicating that QUANTITY many units will expire on EXPIRY_DATE. Else, the current Map.entry will be updated.

Proposed Changes to sell Command

Under this implementation, the sell command must sell goods in a First-In-First-Out (FIFO) manner. When any valid sell command is entered, the earliest expiry dates are removed first. This is accomplished by reducing the values that are mapped to the earliest expiry dates.

Expiry Detection

Upon Inventory Manager Program startup, the expiryDates of all Good s in the inventory is checked with the current System Date. When any expiry date is found to be earlier than the System date, the mapped number of goods will expire and be removed from inventory.

Possible Extensions

Possible extensions of usefulness are listed below:

  1. Make any expiry event generate it’s respective transaction record in the transaction history.

  2. If goods fall below their warning threshold as a result of expiry, have a notification to the user and display the list of suppliers that sell that particular good, sorted by increasing price.

Design Considerations

Aspect: Data Structure for expiryDates
  • Alternative 1 (current choice): Use a TreeMap<Date, Integer>

    • Pros: Memory efficient.

    • Cons:

      • TreeMap navigation is more complex than a linear data structure.

      • Updating is more complex for sell commands, especially if goods with multiple expiry dates are being sold.

  • Alternative 2: Maintain an ordered LinkedList<Date>.

    • Pros: Simple to implement and update.

      • Buying QUANTITY of a good would correspond to inserting QUANTITY of EXPIRY_DATE into the list and sorting it.

      • Selling QUANTITY of a good would correspond to removing the first QUANTITY elements.

      • Finding all expired items can be done be traversing down the list until the first non-expired item is found. Everything traversed has expired.

    • Cons:

      • Extremely memory inefficient, especially since each Good can contain up to 999,999 quantity, and there will be 1 Date for each good stored.

PROJECT: PowerPointLabs


{Optionally, you may include other projects in your portfolio.}