Developer Guide
Table of Contents
- Table of Contents
- Acknowledgements
- Setting up, getting started
- Design
-
Implementation
- Book Management
- Toggling between vendor and guest list
- Checking in a Guest
- Checking in a returning Guest
- Editing a Guest
- Editing a Vendor
- Charging a guest
- Checking out a Guest
- Filter feature
- Deleting a Guest
- Deleting a Vendor
- Clear all Guest
- Clear all Vendors
- Invoice Generation
- [Proposed] Undo/redo feature
- Documentation, logging, testing, configuration, dev-ops
- Appendix A: Requirements
-
Appendix B: Instructions for manual testing
- Launch and shutdown
- Check in a guest
- Editing a guest
- Charging a guest for services
- Checking out a guest
- Viewing invoice generated
- Return check in
- Filter guest
- Show all guests
- Delete guest
- Clear guest
- Adding a vendor
- Editing a vendor
- Filter vendor
- Show all vendors
- Deleting a vendor
- Clear vendor
- Saving data
- Appendix C: Effort
Acknowledgements
This project is a brown-field team project based on the AddressBook-Level 3 (AB3) project.
Credits:
- iText7 Event Handlers
- Java DateTime Format
- Rounding to 2 decimal places by Bharat Sinha
- Create borderless cells in iText7 by Samuel HuylebroeckAdd
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml
files used to create diagrams in this document can be found in
the diagrams folder. Refer to the PlantUML
Tutorial at se-edu/guides to learn how to create and edit
diagrams.
Architecture
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
has two classes
called Main
and MainApp
. It
is responsible for,
- At app launch: Initializes the components in the correct sequence, and connects them up with each other.
- At shut down: Shuts down the components and invokes cleanup methods where necessary.
Commons
represents a collection of classes used by multiple other components.
The rest of the App consists of four components.
-
UI
: The UI of the App. -
Logic
: The command executor. -
Model
: Holds the data of the App in memory. -
Storage
: Reads data from, and writes data to, the hard disk.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command deletevendor vid/123
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using
the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component
through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the
implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
UI component
The API of this component is specified
in Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, GuestListPanel
, VendorListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures
the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that
are in the src/main/resources/view
folder. For example, the layout of
the MainWindow
is specified
in MainWindow.fxml
The UI
component,
- executes user commands using the
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysGuest
andVendor
object residing in theModel
.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
How the Logic
component works:
- When
Logic
is called upon to execute a command, it uses thePocketHotelParser
class to parse the user command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,CheckInNewGuestCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to check in a guest). - The result of the command execution is encapsulated as a
CommandResult
object which is returned back fromLogic
.
The Sequence Diagram below illustrates the interactions within the Logic
component for
the execute("deletevendor vid/123")
API call.
DeleteVendorCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
- When called upon to parse a user command, the
PocketHotelParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,CheckInNewGuestCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,CheckInNewGuestCommand
) which thePocketHotelParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,CheckInNewGuestCommandParser
,DeleteVendorCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores the vendorbook and guestbook data i.e., all
Vendor
andGuest
objects. - stores the currently ‘selected’
Guest
orVendor
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Guest>
orObservableList<Vendor>
that can be ‘observed’ e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
Tag
list in the GuestBook
, which Guest
references. This allows GuestBook
to only require one Tag
object per unique tag, instead of each Guest
needing their own Tag
objects.Storage component
API : Storage.java
The Storage
component,
- can save both vendor book data, guest book data, archive data, and user preference data in json format, and read them back into corresponding objects.
- inherits from
GuestBookStorage
,VendorBookStorage
,ArchiveStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the seedu.addressbook.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Book Management
PH allows the user to manage vendors and guests.
As mentioned in the Model
section earlier, there are three different types of lists:
- GuestBook (Management of guests)
- VendorBook (Management of vendors)
- Archive (Management of archived guests; currently not exposed to the user)
All the lists are managed by the ModelManager
which supports some common operations across them, with certain
variations depending on which list we are currently executing the operation on.
Some common operations include:
-
addvendor
for vendors andcheckin
for guests - creates the entity and adds to the respective books. -
editvendor
for vendors andeditguest
for guests - edits the entity and updates the book accordingly. -
deletevendor
for vendors anddeleteguest
for guests - removes the existing entity from the respective book. -
listvendor
for vendors andlistguest
for guest - renders all the entities of the respective book. -
clearvendor
for vendors andclearguest
for guest - removes all the entities from the respective book.
By segregating the model into its respective books/lists, we felt that this embraced OOP concepts, as it reduces coupling and increases cohesion.
The following class diagram shows the general structure of a GuestBook
. The same concepts were applied when building
the VendorBook
and Archive
.
The GuestBook
implements the ReadOnlyGuestBook
interface. The getGuestList()
method returns an ObservableList
of
guests. ObservableList
makes use of the Observer pattern, as it notifies the ModelManager
of any changes that occur
in the guest list, and reflect those changes onto the GUI.
Toggling between vendor and guest list
Other than toggling between the two lists via the GUI. The user can make use of the commands listguest
and listvendor
to toggle between the two. After certain commands like filterguest
and filtervendor
, the list also
gets toggled automatically for the user. The toggling is executed depending on the state of the CommandResult
, after
executing the user command.
MainWindow
has a function toggleTab()
that reads in the state of the CommandResult
and renders the correct list
accordingly.
The following activity diagram illustrates what happens to the MainWindow
of the UI component when a user inputs a
command.
Checking in a Guest
Implementation
The implementation of the checkin
command was mostly based off the original AB3 implementation, with changes made to
support the Archive
and with curated fields tied to a guest. The checkin
command makes use of the filtered guest
list to search for the guest to be checked in to see whether they are a duplicate guess and Archive
class to determine
if the user is trying to check in a guest that has been archived, which are both not allowed. This is done through the
implementation of Model
called ModelManager
. The operation
ModelManager#getFilteredGuestList()
gets the last shown list of guests in the UI, after which a search is done to see
if the list contains the guest to check in. If the guest is not found, the details of the guest will be added. If the
guest is found, which means that there is a duplicate guest, the operation will not be allowed. In the event that the
guest cannot be found in the last shown list, the operation
ModelManager#getArchivedGuest(PassportNumber passportNumber)
checks if the user is trying to check in a guest that has
been archived, which is not allowed.
The checkin
command is facilitated by the CheckInNewGuestCommandParser
and CheckInNewGuestCommand
of PH. The
following sequence diagram shows how the checkin
operation works:
The following activity diagram shows what happens when a user executes a checkin command.
Checking in a returning Guest
Implementation
The implementation of the returncheckin
command was mostly based off the original AB3 implementation, with changes
made to support the Archive
and with curated fields tied to a guest. The returncheckin
command makes use of the
filtered guest list to search for the guest to be checked in to see whether they are a duplicate guess, which is not
allowed, and Archive
class to determine if the user is trying to check in a guest that has been archived. This is done
through the implementation of Model
called ModelManager
. The operation
ModelManager#getFilteredGuestList()
gets the last shown list of guests in the UI, after which a search is done to see
if the list contains the guest to edit. If the guest is not found, the details of the guest will be added. If the guest
is found, which means that there is a duplicate guest, the operation will not be allowed. In the event that the guest
canno bet found in the last shown list, the operation
ModelManager#getArchivedGuest(PassportNumber passportNumber)
checks if the user is trying to check in a guest that has
been archived, which is the purpose of this command.
The returncheckin
command is facilitated by the CheckInReturningGuestCommandParser
and
CheckInReturningGuestCommand
of PH. The following sequence diagram shows how the checkin
operation works:
The following activity diagram shows what happens when a user executes a checkin command.
Editing a Guest
Implementation
The implementation of the editguest
command was largely based off the original AB3 implementation, with changes made
to support the Archive
and edit by the guest details instead of index in list. The editguest
command makes use of
the filtered guest list to search for the guest to be edited and Archive
class to determine if the user is trying to
edit a guest that has been archived, which is not allowed.
This is done through the implementation of Model
called ModelManager
. The operation
ModelManager#getFilteredGuestList()
gets the last shown list of guests in the UI, after which a search is done to see
if the list contains the guest to edit. If the guest is found, the details of the guest will be edited.
In the event that the guest cannot found in the last shown list, the operation
ModelManager#getArchivedGuest(PassportNumber passportNumber)
checks if the user is trying to edit a guest that has
been archived, which is not allowed.
It is worth noting that the passport number of a guest cannot be edited.
Editing a Vendor
Implementation
The implementation of the editvendor
command was largely based off the original AB3 implementation, with changes made
to edit a different model, Vendor
and edit by the vendor details instead of index in list.
The difference between the Guest and Vendor model is that Vendors cannot be archived. Therefore, the implementation of
the editvendor
command is the same as the editguest
command, but only the VendorBook
(the GuestBook
equivalent for vendors) has to be searched.
Charging a guest
Implementation
The implementation of the chargeguest
is a new command implemented for the invoice to work nicely together.
The chargeguest
would identity the guest by their passport number and vendor by their vendor id.
The service provided by the vendor would be charged to the assigned guest with the important information such as
ServiceName, Quantity, Cost, CompanyName.
The chargeguest
command would increment the quantity for duplicate items.
The chargeguest
command is facilitated by the ChargeGuestCommandParser
and ChargeGuestCommand
of PH. The
following sequence diagram shows how the chargeguest
operation works:
Checking out a Guest
Implementation
The implementation of the checkout
command builds upon the original AB3 implementation of ‘delete’, with changes made
to delete the guest from the model by the guest details instead of index in list. The ‘checkout’ command first generate
an invoice for the guest if vendor services were engaged during his/her stay. After which, the guest is deleted from the
model, and then archived.
The checkout
command makes use of the filtered guest list to search for the guest to be checked out and Archive
class to archive the guest.
This is done through the implementation of Model
called ModelManager
. The operation
ModelManager#getFilteredGuestList()
gets the last shown list of guests in the UI, after which a search is done to see
if the list contains the guest to check out.
If the guest is found, a check is done to see if the guest engaged any vendor services (by seeing if he/she has any chargeables). As mentioned earlier, the invoice is generated only if the guest has chargeables.
Once the invoice (if any) is generated, the chargeables (if any) of the guest will be cleared using the operation
Guest#clearChargeables()
.
The guest is then deleted from the model using ModelManager#deleteGuest(Guest guest)
and added to the archive using
ModelManager#addArchivedGuest(Guest guest)
.
Filter feature
Implementation
The filter feature makes use of the Model#updateFilteredGuestList
and Model#updateFilteredVendorList
operations,
where each function takes in a Predicate<Guest>
and Predicate<Vendor>
respectively. To avoid repetition, we will
cover how the
filterguest
command is implemented. The filtervendor
command follows the exact same logic with its own unique
fields.
The filterguest
command is facilitated by the FilterGuestCommandParser
and FilterGuestCommand
of PH. The
following sequence diagram shows how the filterguest
operation works:
FilterGuestCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Given above is an example of a user filtering guests by a tag, deluxe. The end result is a filtered list of guests with
the tag, deluxe. The execution of the above example follows the same flow as all the other commands. One important to
take note is that, the FilterGuestCommandParser
returns a GuestPredicate
. This GuestPredicate
implements Predicate<Guest>
, and the instance instantiated by the
parser is what gets passed into Model#updateFilteredGuestList
to achieve the end result. filtervendor
makes use of a
class VendorPredicate
that follows the same idea.
The following activity diagram shows what happens when a user executes a filterguest
command, filtervendor
follows
the same flow.
Deleting a Guest
Implementation
The implementation of the deleteguest
command was largely based off the original AB3 implementation, with changes made
to support the Archive
and delete by the guest details instead of index in list. The deleteguest
command makes use
of the GuestBook
and Archive
class to search for the guest to be deleted.
This is done through the implementation of Model
called ModelManager
. The operations
ModelManager#getGuest(PassportNumber passportNumber)
andModelManager#getArchivedGuest(PassportNumber passportNumber)
are used to check if the guests details can be found in Pocket Hotel (Either in the archive or currently checked in). If
the guest details is found in either locations, it would be deleted.
Deleting a Vendor
Implementation
The implementation of the deletevendor
command was largely based off the original AB3 implementation, with changes
made to delete a different model, Vendor
and delete by the vendor details instead of index in list.
The difference between the Guest and Vendor model is that Vendors cannot be archived. Therefore, the implementation of
the deletevendor
command is the same as the deleteguest
command, but only the VendorBook
(the GuestBook
equivalent for vendors) has to be searched.
Clear all Guest
Implementation
The implementation of the clearguest
command was largely based off the original AB3 implementation.
The clearguest
command makes use
of the GuestBook
and removes all guest on the list.
Clear all Vendors
Implementation
The implementation of the clearvendor
command was largely based off the original AB3 implementation.
The clearvendor
command makes use
of the VendorBook
and removes all Vendors on the list.
Invoice Generation
Implementation
Invoices in Pocket Hotel was created using the iText7 Core library, which provides an API to create PDF documents in Java.
The implementation of invoice generation can be found in the Invoice
class which contains almost all the code for
generating invoices. The Invoice
class is meant to be used as a static method and should not be instantiated. It has
only one method that has the public access modifier is the static method Invoice#generatePdfInvoice
The other static methods are private helper functions to perform the generation of the PDF.
An invoice has 5 components:
- Invoice header
- Billing details: Includes the guest name and their allocated room number
- The invoice table: Contain services the guest used during their stay as well as the total cost. Each row contains, the item number (row number), the name of the vendor, their vendor ID, service type, quantity and cost per unit, as well as line cost (quantity multiplied by cost per unit) are included
- A short note of thanks
- Page number
Given below is the sequence diagram of how the invoice is created by Invoice#generatePdfInvoice
.
Referring back to the components that we have to include in the invoice. The InvoiceNewPageHandler
would add
the invoice header and the page number. The addGuestBillingDetailsToPdf
adds the billing details, addInvoiceTableToPdf
adds the invoice table and addThankYouParagraphToPdf
adds a short note of thanks.
[Proposed] Undo/redo feature
Proposed Implementation
The proposed undo/redo mechanism is facilitated by VersionedAddressBook
. It extends AddressBook
with an undo/redo
history, stored internally as an addressBookStateList
and currentStatePointer
. Additionally, it implements the
following operations:
-
VersionedAddressBook#commit()
— Saves the current address book state in its history. -
VersionedAddressBook#undo()
— Restores the previous address book state from its history. -
VersionedAddressBook#redo()
— Restores a previously undone address book state from its history.
These operations are exposed in the Model
interface as Model#commitAddressBook()
, Model#undoAddressBook()
and Model#redoAddressBook()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedAddressBook
will be initialized with the
initial address book state, and the currentStatePointer
pointing to that single address book state.
Step 2. The user executes delete 5
command to delete the 5th person in the address book. The delete
command
calls Model#commitAddressBook()
, causing the modified state of the address book after the delete 5
command executes
to be saved in the addressBookStateList
, and the currentStatePointer
is shifted to the newly inserted address book
state.
Step 3. The user executes add n/David …
to add a new person. The add
command also calls Model#commitAddressBook()
, causing another modified address book state to be saved into the addressBookStateList
.
Model#commitAddressBook()
, so the address book state will not be saved into the addressBookStateList
.
Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing
the undo
command. The undo
command will call Model#undoAddressBook()
, which will shift the currentStatePointer
once to the left, pointing it to the previous address book state, and restores the address book to that state.
currentStatePointer
is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The undo
command uses Model#canUndoAddressBook()
to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.
The following sequence diagram shows how the undo operation works:
UndoCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
The redo
command does the opposite — it calls Model#redoAddressBook()
, which shifts the currentStatePointer
once
to the right, pointing to the previously undone state, and restores the address book to that state.
currentStatePointer
is at index addressBookStateList.size() - 1
, pointing to the latest address book state, then there are no undone AddressBook states to restore. The redo
command uses Model#canRedoAddressBook()
to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
Step 5. The user then decides to execute the command list
. Commands that do not modify the address book, such
as list
, will usually not call Model#commitAddressBook()
, Model#undoAddressBook()
or Model#redoAddressBook()
.
Thus, the addressBookStateList
remains unchanged.
Step 6. The user executes clear
, which calls Model#commitAddressBook()
. Since the currentStatePointer
is not
pointing at the end of the addressBookStateList
, all address book states after the currentStatePointer
will be
purged. Reason: It no longer makes sense to redo the add n/David …
command. This is the behavior that most modern
desktop applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
Design considerations:
Aspect: How undo & redo executes:
-
Alternative 1 (current choice): Saves the entire address book.
- Pros: Easy to implement.
- Cons: May have performance issues in terms of memory usage.
-
Alternative 2: Individual command knows how to undo/redo by itself.
- Pros: Will use less memory (e.g. for
delete
, just save the person being deleted). - Cons: We must ensure that the implementation of each individual command are correct.
- Pros: Will use less memory (e.g. for
Documentation, logging, testing, configuration, dev-ops
Appendix A: Requirements
Product scope
Target user profile: Front-desk receptionists at small-scale hotels
- has a need to manage a significant number of contacts (both vendors and guests)
- prefers to have everything centralized in one application
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
- tired of using pen and paper to keep track of contacts
Value proposition: Automate front-desk operations, elevating guest experience and lightens the front desk’s workload.
User stories
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * |
user | add details of vendors | look up vendors that suit the guest’s needs and phone them. |
* * * |
user | edit contact details of vendors and guests | have the most updated information. |
* * * |
user | delete guests/vendors | keep track of only guests checked into the hotel and vendors working with hotel. |
* * * |
user | see help instructions | get help on how to use the app |
* * * |
user | save the details I enter | |
* * * |
user | check in new guests | manage all guests currently checked into the hotel. |
* * * |
user | have a faster check in for returning guests | reduce the average check-in time at the front desk |
* * * |
user | check out my guests | archive them and generate an invoice form for them. |
* * |
new user | generate an invoice form | charge the guest for their stay. |
* * |
user | charge my guests for vendors hired | generate an invoice form for them when they check out. |
* * |
new user | clear all current data | get rid of sample data |
* * |
potential user | see app populated with sample data | easily learn and get a feel for the app |
* * |
user | filter guests and vendors | look at them in more manageable lists. |
* * |
user | add tags to vendors/guests | easily categorize and filter them |
* |
expert user | personalize my GUI to my liking | optimise the layout to cater to my needs |
* |
CLI user | add aliases to my commands | execute commands quickly with shorter syntax |
* |
new user | learn how to use the app (Tutorial) | get more familiar with the features they offer and how I can use it better |
Use cases
(For all use cases below, the System is the PH
and the Actor is the user
, unless specified otherwise)
Navigation
UC01 - Viewing the Vendor List
MSS:
1. User requests to go the vendor list.
2. Pocket Hotel switches to the vendor list, where user can see all the vendors working with the hotel.
Use case ends.
UC02 - Viewing the Guest List
MSS:
1. User requests to go the guest list.
2. Pocket Hotel switches to the guest list, where user can see all guests currently checked into the hotel.
Use case ends.
Utility
UC03 - Viewing the help tab
MSS:
1. User requests to go to the help tab.
2. Pocket Hotel opens the help window directing the user to a guide on how to use the application.
Use case ends.
UC04 - Exiting Pocket Hotel
MSS:
1. User requests to exit the app.
2. Pocket Hotel closes the application window.
Use case ends.
UC05 - Saving your data
MSS:
1. User executes a valid action.
2. Pocket Hotel's data gets modified accordingly, and replaces the existing local save-file.
3. Pocket Hotel shows a success message to user indicating action has been executed successfully.
Use case ends.
Extensions:
1a. Action carried out by user is invalid.
1a1. Pocket Hotel shows an error message.
Use case ends.
2a. Unable to overwrite save file.
2a1. Pocket Hotel shows an error message.
Use case ends.
Managing Guests
UC06 - Checking in new guests
Preconditions: Guest must not already be currently checked into the hotel.
Guarantees: Guest list gets updated with the new guest checked in.
MSS:
1. User requests to check in a new guest.
2. Pocket Hotel adds the requested guest.
3. Pocket Hotel shows a success message to user indicating guest has been successfully checked in.
Use case ends.
Extensions:
1a. Guest is already checked in.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Guest is a returning guest.
1b1. Pocket Hotel shows an error message.
Use case ends.
1c. Given fields such as passport number, name, etc. is invalid.
1c1. Pocket Hotel shows an error message.
Use case ends.
UC07 - Checking in returning guests
Preconditions: Guest must not already be currently checked into the hotel and must be a returning guest.
Guarantees: Guest list gets updated with the returning guest checked in.
MSS:
1. User requests to check in the returning guest.
2. Pocket Hotel adds the requested guest.
3. Pocket Hotel shows a success message to user indicating guest has been successfully checked in.
Use case ends.
Extensions:
1a. Guest is already checked in.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Guest is not a returning guest.
1b1. Pocket Hotel shows an error message.
Use case ends.
1c. Given fields such as passport number or room number is invalid.
1c1. Pocket Hotel shows an error message.
Use case ends.
UC08 - Editing guests
Preconditions: Guest must exist and be currently checked into the hotel.
Guarantees: Guest list gets updated with the guest edited.
MSS:
1. User requests to edit a guest.
2. Pocket Hotel updates the guest with its new details.
3. Pocket Hotel shows a success message to user indicating guest has been successfully edited.
Use case ends.
Extensions:
1a. Guest with given passport number is not checked in.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Given fields such as room number, name, etc. is invalid.
1b1. Pocket Hotel shows an error message.
Use case ends.
1c. No field is given to edit.
1c1. Pocket Hotel shows an error message.
Use case ends.
UC09 - Deleting guests
Preconditions: Guest must exist and be currently checked into the hotel.
Guarantees: Guest list gets updated with the guest removed.
MSS:
1. User requests to delete a guest.
2. Pocket Hotel deletes the guest.
3. Pocket Hotel shows a success message to user indicating guest has been successfully deleted.
Use case ends.
Extensions:
1a. Guest is not checked in.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Given identifier, passport number is invalid.
1b1. Pocket Hotel shows an error message.
Use case ends.
UC10 - Checking out guests
Preconditions: Guest must exist and be currently checked into the hotel.
Guarantees: Guest list gets updated with the guest archived and invoice form generated.
MSS:
1. User requests to check out a guest.
2. Pocket Hotel archives the guest and generates the invoice form.
3. Pocket Hotel shows a success message to user indicating guest has been successfully checked out.
Use case ends.
Extensions:
1a. Guest is not checked in.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Given identifier, passport number is invalid.
1b1. Pocket Hotel shows an error message.
Use case ends.
UC11 - Clearing guests
Preconditions: None.
Guarantees: Guest list gets cleared.
MSS:
1. User requests to clear all guest data.
2. Pocket Hotel clears all guest data.
3. Pocket Hotel shows a success message to user indicating all guest data has been successfully cleared.
Use case ends.
UC12 - Filtering guests
Preconditions: Only guest fields are given for the filter.
Guarantees: Guest list gets filtered to user's specifications.
MSS:
1. User requests to filter guests.
2. Pocket Hotel filters the guests, and only shows those that fit the user's specifications.
3. Pocket Hotel shows a success message to user with the number of guests that have been filtered.
Use case ends.
Extensions:
1a. No fields are given to filter.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Fields given do not follow correct syntax.
1b1. Pocket Hotel shows an error message.
Use case ends.
UC13 - Charging guests
Preconditions: Guest must exist and be currently checked into the hotel.
Guarantees: Pocket Hotel keeps track of the vendors hired by the guest.
MSS:
1. User requests to charge a guest.
2. Pocket Hotel keeps track of the vendor hired by the guest.
3. Pocket Hotel shows a success message to user indicating the guest has been successfully charged.
Use case ends.
Extensions:
1a. Guest is not checked in.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Vendor hired does not exist.
1b1. Pocket Hotel shows an error message.
Use case ends.
Managing Vendors
UC14 - Adding vendors
Preconditions: Vendors must not already exist in the app.
Guarantees: Vendor list gets updated with the new vendor added.
MSS:
1. User requests to add a new vendor.
2. Pocket Hotel adds the requested vendor.
3. Pocket Hotel shows a success message to user indicating the vendor has been successfully added.
Use case ends.
Extensions:
1a. Vendor already exists.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Given operating hour start time is after the end time.
1b1. Pocket Hotel shows an error message.
Use case ends.
1c. Given fields such as vendor id, name, etc. is invalid.
1c1. Pocket Hotel shows an error message.
Use case ends.
UC15 - Editing vendors
Preconditions: Vendor must exist in the app.
Guarantees: Vendor list gets updated with the vendor edited.
MSS:
1. User requests to edit a vendor.
2. Pocket Hotel updates the vendor with its new details.
3. Pocket Hotel shows a success message to user indicating vendor has been successfully edited.
Use case ends.
Extensions:
1a. Vendor with given vendor id does not exist.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Given fields such as email, name, etc. is invalid.
1b1. Pocket Hotel shows an error message.
Use case ends.
1c. No field is given to edit.
1c1. Pocket Hotel shows an error message.
Use case ends.
UC16 - Deleting vendors
Preconditions: Vendor must exist in the app.
Guarantees: Vendor list gets updated with the vendor removed.
MSS:
1. User requests to delete a vendor.
2. Pocket Hotel deletes the vendor.
3. Pocket Hotel shows a success message to user indicating vendor has been successfully deleted.
Use case ends.
Extensions:
1a. Vendor with given vendor id does not exist.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Given identifier, vendor id is invalid.
1b1. Pocket Hotel shows an error message.
Use case ends.
UC17 - Clearing vendors
Preconditions: None.
Guarantees: Vendor list gets cleared.
MSS:
1. User requests to clear all vendor data.
2. Pocket Hotel clears all vendor data.
3. Pocket Hotel shows a success message to user indicating all vendor data has been successfully cleared.
Use case ends.
UC18 - Filtering vendors
Preconditions: Only vendor fields are given for the filter.
Guarantees: Vendor list gets filtered to user's specifications.
MSS:
1. User requests to filter vendors.
2. Pocket Hotel filters the vendors, and only shows those that fit the user's specifications.
3. Pocket Hotel shows a success message to user with the number of vendors that have been filtered.
Use case ends.
Extensions:
1a. No fields are given to filter.
1a1. Pocket Hotel shows an error message.
Use case ends.
1b. Fields given do not follow correct syntax.
1b1. Pocket Hotel shows an error message.
Use case ends.
Non-Functional Requirements
- Should work on any Mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 contacts without a noticeable sluggishness in performance for typical usage.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
- PH should retain all functionalities even without a connection to the internet.
- PH is meant to be used by single user at any given time.
- PH should be user-friendly for any receptionist who can use a computer, and does not require any technical knowledge or previous experience of CLI apps.
- PH should not crash on any incorrect user input, this should be handled safely with exceptions. Ideally, rendering a useful error message to the user. {More to be added}
Glossary
- PH: Acronym for Pocket Hotel
- Mainstream OS: Windows, Linux, Unix, OS-X
- Private contact detail: A contact detail that is not meant to be shared with others
- Guest: A person staying in Pocket Hotel
- Staff: An employee of Pocket Hotel
- OOP: Object-oriented programming. A programming paradigm that relies on the idea of designing data around objects and classes.
- GUI: Graphical user interface
- AB3: Address Book 3
Appendix B: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
Perform one of the steps (Option 2 recommended for mac) -
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
Run
java -jar PH.jar
in the directory that you placed your jar
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
Check in a guest
-
Check in a new guest to PH
-
Test case:
checkin n/Bobby pn/S1234 e/bobby@email.com r/23 t/VIP t/Deluxe Room
Expected: A guest card will be created with the passport number S1234 with name “Bobby”, email “bobby@gmail.com”, room number “23”, and tags “VIP” and “Deluxe Room” -
Test case:
checkin n/bobby
Expected: Invalid command format error
-
Editing a guest
-
Editing a guest while all guests are being shown
-
Prerequisites: List all guests using the ‘listguest’ command. Alternatively, click on the “Guests” tab to view the list of guests.
-
Test case:
editguest pn/S1234 n/Alexander Poon
Expected: The guest card of the guest identified by passport number S1234 should be updated to reflect the new name, “Alexander Poon”. The result display shows the details of the guest that has just been edited. -
Test case:
editguest pn/
Expected: No guest is edited. Error details shown in the result display. -
Other incorrect editguest commands to try:
editguest pn/S1234
,editguest n/Bernice Yu
.
Expected: Similar to previous.
-
Charging a guest for services
-
Charges a guest a service
-
Test case:
chargeguest pn/S123 vid/001
Expected: Service from vendor with vid001
has been billed to guest with passport numberS123
. -
Test case:
chargeguest
Expected: No transaction occurs and invalid command format will be shown in the result display. -
Test case:
chargeguest pn/S123
Expected: No transaction occurs and invalid command format will be shown in the result display. -
Test case:
chargeguest vid/001
Expected: No transaction occurs and invalid command format will be shown in the result display. -
Test case:
chargeguest pn/A999 vid/001
which passport number does not exist
Expected: No transaction occurs andGuest with this passport number does not exist
will be shown in the result display. -
Test case:
chargeguest pn/S123 vid/99999
which vendor id does not exist
Expected: No transaction occurs andVendor with this vendorId does not exist
will be shown in the result display.
-
Checking out a guest
-
Checking out a guest while all guests are being shown
-
Prerequisites: List all guests using the ‘listguest’ command. Alternatively, click on the “Guests” tab to view the list of guests.
-
Test case:
checkout pn/S1234
Expected: The guest card of the guest identified by passport number S1234 should no longer be visible in the guests list. The result display shows the details of the guest that has just been checked out. An invoice is generated for the guest as well. -
Test case:
checkout pn/
Expected: No guest is checked out. Error details shown in the result display. -
Other incorrect editguest commands to try:
checkout pn/A123
,editguest pn/@@@@@
. Expected: Similar to previous.
-
Viewing invoice generated
-
Upon performing the
checkout
command in the previous section, a PDF invoice of all the guests expenses will be generated.- Test case: From previous step
Expected: Check directory which contains jar file for PDF namedS1234 <CURRENT_TIME>
, PDF should contain base price of hotel stay and the 2 charges by vendor 001
- Test case: From previous step
Return check in
-
Return check in for guests whose details have been previously entered into the hotel
- Test case:
returncheckin pn/S1234 r/411
Expected: Checked in guest.
- Test case:
Filter guest
-
Filter guests with fields
- Test case:
filter guest n/Ale
, filters all guest that name starts with “Ale” Expected: Message sayingX guest listed
- Test case:
Show all guests
-
Removes filters and switches to the guest list
-
Test case:
-
Perform filter guest example above
-
Click on vendor list
-
listguest
Expected: List will switch to guest and remove filters
-
-
Delete guest
-
Deletes guest based on its passport number.
-
Test case:
deleteguest pn/S1234
Expected: Message notifying that guest is deleted -
Test case (Deleting an archived guest):
-
checkin n/Bobby pn/S1234 e/bobby@email.com r/23 t/VIP t/Deluxe Room
-
checkout pn/1234
-
deleteguest pn/1234
Expected: Message notifying that guest is deleted
-
-
Clear guest
-
Deletes all guests from PH, even archived ones
-
Test case:
-
checkin n/Bobby pn/S1234 e/bobby@email.com r/23 t/VIP t/Deluxe Room
-
checkout pn/1234
-
clearguest
-
returncheckin pn/S1234 r/111
Expected: All guests from guest list will be cleared,returncheckin
command will throw an error as guest cannot be found in archive
-
-
Adding a vendor
-
Add vendor to list of vendors
-
Test case:
-
addvendor vid/123 n/Wang's Satay e/satayMan@email.com p/84711231 a/Geylang Street 31 sn/Satay c/5 oh/15 0800-2000
Expected: Adds vendor with vendor ID 123, called Wang’s Satay with email address satayMan@email.com, phone number 84711231, address Geylang Street 31 , service name “Satay”, and operating hours Monday and Friday 0800-2000.
-
-
Editing a vendor
-
Editing a vendor while all vendors are being shown
-
Prerequisites: List all vendors using the ‘listvendor’ command. Alternatively, click on the “Vendors” tab to view the list of vendors.
-
Test case:
editvendor vid/001 n/Jeremy Western Delivery
Expected: The vendor card of the vendor identified by vendor id 001 should be updated to reflect the new name, “ Jeremy Western Delivery”. The result display shows the details of the vendor that has just been edited. -
Test case:
editvendor vid/
Expected: No vendor is edited. Error details shown in the result display. -
Other incorrect editvendor commands to try:
editvendor vid/001
,editvendor n/Bing Massage Parlour
.
Expected: Similar to previous.
-
Filter vendor
-
Filters vendors according to filter
-
Test case:
filtervendor oh/5 0800
Expected: Filters vendors that are open at 0800 and displays to the GUI -
Test case:
filtervendor oh/5 0800-1300
Expected: Filters all vendors that operate anywhere between 0800 and 1300 on a Friday and displays them to the GUI -
Test case:
filtervendor sn/Food
Expected: Filters all vendors that have a service name field of food.
-
Show all vendors
-
Removes filters and switches to the vendor list
-
Test case:
-
Perform filter vendor example above
-
Click on guest list
-
listvendor
Expected: List will switch to vendor and removes filters
-
-
Deleting a vendor
-
Deletes a vendor based on its vendor ID
- Test case:
deletevendor vid/123
Expected: Deletes vendor with vid 123 from PH
- Test case:
Clear vendor
-
Deletes all vendors from PH.
- Test case:
clearvendor
Expected: Deletes all vendors from PH, vendor list will be empty.
- Test case:
Saving data
-
Dealing with missing/corrupted data files
i. Test case: go to
data\addressbook.json
and corrupt the file. On bootup of the program, there should be a notification in the command box saying “File corrupted! Restored a new file.” and the program will delete and load a fresh new file.ii. Rename
data\addressbook.json
to something else likedata\addressbook.json
would cause the addressbook to be not found and load the sample contacts into the addressbook.
Appendix C: Effort
Challenges faced
Prior to the 1.3b iteration, PH was aimed at managing Guests and Staff. However, upon meeting with our CS2101 lecturer, we realised that our use cases were ill-defined and we had failed to adequately address the needs of our target audience. Coming up with meaningful use cases for that iteration was difficult and our team gathered to brainstorm ideas on what core features we should include and who our target audience should really be. We eventually came to a consensus that our application would be front desk oriented and ended up redesigning the entire workflow of the application. Instead of managing Guests and Staff, our app would now manage guests and external vendors, with a focus on streamlining all guest-related processes such as check in, checkout, charging guests etc. That was one of the longest meetings spanning over 5 hours as we cleared out most of the edge case scenarios and came up with features that would be useful to the application.
With 5 days left to the submission deadline, we set out to achieve what most groups would take 4 weeks to do. We had to
make significant changes to refactor the original codebase. Our original commands such as edit
, add
(which was
converted to checkin
and returncheckin
) and delete
had to be duplicated for both guests and vendors, which greatly
increased the workload for implementation and testing. Additionally, we made changes to the original Model
by
introducing an Archive
, which would be used to store checked out guests and implemented several new features that were
dissimilar to any of those in AB3, such as invoice generation for guests who engaged vendor services during their
stay. We also have more json files to manage such as guests.json
, vendors.json
and archive.json
, which increased
the amount of testing and implementation required.
In particular, with the additional feature of generating invoices, we have a new workflow to allow this functionality with the added logic for charging guests and checking out a guest for a smoother process. The parsing of the information and generation of the layout was also tricky.
Two major entities are involved: Guest
and Vendor
:
The two classes have some fields in common but are different from one another. For example, Vendors have operating hours
while Guests have a list of things that they are charged for.
The difference in workflow also greatly increases the workload of implementation and testing for both the Guest and Vendors due to the separate command logic and storage required to handle them.
Achievements
We managed to revamp our existing v1.3 iteration to a whole new PH in v1.3b iteration within a week with all the new features added such as filter, archive, invoice, chargeable, and returning guest check in.
Our team managed to deliver a convincing pitch and demo of our product and both our CS2101 lecturer and CS2103T tutor were impressed with our work.