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
andsell
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
andsell
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
andsell
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
andsell
commands and their related tests. -
As
buy
andsell
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:
-
The supplier has not been entered in the supplier list
-
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:
-
The good being sold does not exist in the inventory
-
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. |
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:
-
Update the quantity in the inventory, subject to their respective validity checks.
-
Create a transaction record of itself to be added to the transaction history.
-
Commit the mutated model to facilitate proper functioning of
undo
andredo
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:
-
Model#setGood()
-
Model#addTransaction()
-
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:
-
Purchase from a supplier that is not in the supplier list
-
Purchase a good that the supplier does not offer.
-
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:
-
The
SUPPLIER_DISPLAYED_INDEX
must be within the length of list of suppliers returned byModel#getFilteredSupplierList()
. -
Get the offers of the supplier through
Supplier#getOffers()
. Iterate through theSet<Offer>
of the selected supplier to find existence of anOffer
withGOODNAME
. -
Reuse the inbuilt quantity validation in the
Good
constructor to test if the resulting inventory quantity is valid. AGood
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 theSUPPLIER_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:
-
Sell a good they do not currently have in inventory.
-
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:
-
The
GOOD_DISPLAYED_INDEX
must be within the length of list of Goods returned byModel#getFilteredGoodList()
. -
Reuse the inbuilt quantity validation in the
Good
constructor to test if the resulting inventory quantity is valid. AGood
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 theGOOD_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.
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:
-
Make any expiry event generate it’s respective transaction record in the transaction history.
-
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 insertingQUANTITY
ofEXPIRY_DATE
into the list and sorting it. -
Selling
QUANTITY
of a good would correspond to removing the firstQUANTITY
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 to999,999
quantity, and there will be 1Date
for each good stored.
-
-
PROJECT: PowerPointLabs
{Optionally, you may include other projects in your portfolio.}