PROJECT: Concierge™


Overview

Concierge™ is a desktop application simulating a hotel management system used by hotel owners and receptionists. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.

Summary of contributions

  • Code contributed: [Code Contributed]

  • Major enhancement: Implemented the entire service architecture and command

    • What it does: The service command allows for the integration of all the hotel’s goods and services into Concierge™. Users will be able to use Concierge™ to charge and keep track of the expenditure of all guests on the hotel’s goods and services.

    • Justification: A hotel often provides many different kinds of goods and services, such as room service, restaurants, minibar, swimming pool, etc. Since all of these goods and services belong to the hotel, there should be a centralised system to keep track of all the expenditure on the hotel’s goods and services, such that the expenses can be compiled and presented to the guest conveniently during checkout.

    • Highlights: This functionality required the implementation of several different classes to serve as the architecture. Firstly, Expenses and Expense were required to hold the information regarding the Room’s total expenditure and each individual expenditure respectively. Secondly, a `Menu of ExpenseType objects were required to serve as the main reference of all the items that are sold in the hotel. This serves as the catalogue for the hotel. Finally, a Money class was created to handle monetary values. In addition, the information in all of these classes need to be stored in XML, and therefore implementing this required significant effort to convert each class into an XmlAdaptedClass and to handle all the possible errors that can be introduced by modifying the values in the XML. Testing also required significant effort in adding several new test files and implementing several new utility methods, besides writing tests for all the classes mentioned above.

  • Minor enhancement: added a GUI panel that displays the expenditure details of every room.

  • Other contributions:

    • Refactoring:

      • Replaced all instances and variants of "Address Book" with "Concierge".

    • Documentation:

      • Modified the existing Model UML diagram with our architecture: #247

      • Updated user stories in developer guide, made basic changes to the website: #45

    • Community:

      • PRs reviewed (with non-trivial review comments): #90, #169

      • Reported bugs and suggestions for other teams in the class (examples: 1, 2, 3, 4, 5, 6, 7, )

    • Tools:

      • Integrated Travis CI to the project.

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.

  • Links to relevant sections in User Guide (for viewing on Github)

Provide Room Service: service icon key

Charges a room service to a room
Format: service r/ROOM_NUMBER no/ITEM_NUMBER [c/COST]

ITEM_NUMBER refers to the number in the menu given to each type of service offered by the hotel. The default Menu that comes with Concierge™ consists of the following items:

  • RS01 — Room service: Red wine — $50.00

  • RS02 — Room service: Beef steak — $70.00

  • RS03 — Room service: Thai massage — $100.00

  • MB01 — Minibar: Coca cola — $3.00

  • MB02 — Minibar: Sprite — $3.00

  • MB03 — Minibar: Tiger beer — $6.00

  • MB04 — Minibar: Mineral water — $3.00

  • SP01 — Swimming pool: Entry — $5.00

  • XX01 — Adjustment: Discount — $0.00

  • XX02 — Adjustment: Typo — $0.00

icon important

  • The cost can be specified if the guest is to be charged an amount that is different from the cost in the menu. Note that the cost has to follow a strict format such as 100.00, i.e. with two decimal places. The dollar part of the cost should also not exceed Integer.MAX_VALUE.

  • Only occupied rooms (i.e. rooms with checked-in guests) can have expenses charged to it.

  • Items in the Menu may be modified, added, or removed through concierge.xml. Only item numbers from the Menu (case-sensitive) may be used in the service command. Future versions will allow displaying of the Menu on the main app.

Negative values can be used in service command. This can be used in cases such as when a guest uses a voucher, hence allowing the total expenses to be reduced. Negative values can also be charged if the user wants to remove or edit an existing expense. The two expense types, XX01 and XX02, were thus created for the purpose of adjustments.

Examples:

  • service r/085 no/RS01
    Adds an expenditure of the item RS01 to the room’s expenses.

  • service r/096 no/RS03 c/12.34
    Adds an expenditure of the item RS03 to the room’s expenses and charge $12.34 for it.

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.

Expense, Expenses and ExpenseType

In Concierge, users will be given the feature of tracking the expenditure of each individual guest, in order to facilitate checkout charges. Hence, the three classes, Expenses, Expense and ExpenseType have been created for this purpose. In addition, the hotel also has a Menu of goods and services available.

Current Implementation

ExpenseType objects are essentially immutable objects that represent a single item or service being sold at the hotel. An ExpenseType object contains information about its menu number, usual price, and description. The main purpose of this class is for convenience; users may charge a customer by simply providing the menu number of the item and the cost and description of the item will be able to be referenced. ExpenseType information is stored in a Menu object, which is then stored on the hard disk, since users should have the ability to modify the menu manually. The Menu object is internally represented with a HashMap<String, ExpenseType>, with the menu number as keys and the ExpenseType objects as values.

  • Alternative 1: Use a List<ExpenseType> to store the menu. While there may be negligible differences for a small menu, searching for an ExpenseType object still takes linear time and there may be significant performance drops for a large menu.

An Expense object contains information about one individual expenditure by a guest. An Expense object encapsulates the cost, ExpenseType of the item bought, and the date and time of expenditure.

The Expenses object is essentially a List<Expense>. Every room contains an Expenses object, to represent the collection of all the expenses of the guests in the room.

  • Alternative 1: Use a List<Expense> object: Defining the Expenses class allows us to restrict access to the collection, and only allow certain methods such as adding an Expense or displaying on screen.

  • Alternative 2: Use a Set<Expense> object: Having the expenses ordered (e.g. chronologically) will be useful for generating a nice view of all the expenses incurred.

Here is a simple UML describing the roles of these classes.

expense uml

Design Considerations

Aspect: Immutability of Menu

While it is conceivable that the items sold may change from time to time, for various reasons such as unpopularity or seasonal products, giving users the ability to add and remove items from the menu may result in more problems than benefits. We expect that alterations to the menu will not be performed frequently, and that the majority of our users, receptionists, will not be required to add and remove items to the menu. The menu also does not have to be altered during operational hours. Hence, by making Menu immutable, we eliminate the possibility of making accidental or unwarranted changes to the menu. The only method to modify Menu would thus be through the XML file, which we believe is suitable for these purposes.

Aspect: Immutability of ExpenseType

The ExpenseType object is meant to hold the default values of the name and price of each item. In other words, since an Expense object references an ExpenseType object, the Expense object is allowed to have a cost that is different from the cost in the corresponding ExpenseType object, to account for cases such as the guest having a personalised discount due to the usage of vouchers or certain credit cards. Thus, ExpenseType does not need to be modified by users in the application. Nonetheless, it is still possible to modify the default information through editing the XML file.

Aspect: Assignment of the Expenses object
  • Alternative 1 (current choice): Assign expenses to each Room.

    • Pros: Suitable for current architecture. Each Booking only has one Guest, and each Guest will only stay in one Room. Makes more sense to assign to Room such that it represents the expenditure of the entire Room and not one Guest, since the occupants of the Room can only contribute to one single Expenses object. Room is a more natural choice over Booking as Booking is meant to encapsulate booking information such as timing and Room. Not much difference in implementation no matter which one of the three classes it is assigned to.

    • Cons: May be confusing to implement. Need to ensure that there are no expenses for rooms that have no guests.

  • Alternative 2: Assign expenses to each Guest.

    • Pros: Can track expenses of each Guest, can find out who are the heavy spenders. Can use this information for promotional activities such as vouchers or membership.

    • Cons: Not all guests that will stay in the hotel are registered in the guest list, since each Booking only requires the name of one Guest, regardless of the Room. Will require a major refactoring of the add command. Complications may also arise if a Guest has multiple bookings simultaneously and there is a need to track the Expenses over different rooms.

  • Alternative 3: Assign expenses to each Booking.

    • Pros: Can allow tracking of the booker’s expenditure, less confusing to implement than Room, can allow for expenses to be recorded before the guest checks in.

    • Cons: May violate SRP, since Booking should ideally only deal with booking information.

Money

Current Implementation

Money is a class used to store monetary values. This class was created to enforce the restriction that monetary values should always have at most two decimal places, which could be inconvenient if using Java data types such as double or BigDecimal. Money objects can be created by the user through the service command (details in the next section).

The Money class contains two main attributes, dollars and cents, both of which are int`s, since it is unlikely that the cost of any one item will exceed `Integer.MAX_VALUE dollars.

The main method of creating Money objects is through the service command, with the Money class parsing a string to convert into a Money object. The method isValidMoneyFormat() handles the checking of the string format, and the list of requirements are as follows:

  • Can be negative.

  • Format of the string should be {1 to 10 digits}.{2 digits}, e.g. 12.34. 123, .50, 12.9, 12345612345.00 are not allowed.

  • The dollars section can be 0 but cannot have leading 0, i.e. 0.12 is allowed but 01.23 is not allowed.

  • The dollars section should not exceed Integer.MAX_VALUE.

  • Cannot have characters that are not digits or . or -.

Design Considerations

Aspect: Immutability of Money

Money does not have to be mutable. Adjustment of Expenses are to be done through the service command. Money is simply a data type, much like Double and Integer.

ServiceCommand

Current Implementation

The service command is used for charging expenses to rooms. This functionality is the main reason that the classes Expenses, Expense, ExpenseType, Menu and Money were implemented. The format for the service command is as such:

service r/ROOM_NUMBER no/ITEM_NUMBER [c/COST]

The cost is made optional for the convenience of the user. We expect that most of the time, the cost of items are more or less fixed. Instead of having the user type in the same cost all of the time, the field is made optional. This functionality is enabled by the use of ExpenseType and Menu, which stores the default cost of items. If the cost is not specified, the default cost of the item will be used.

As in AddressBook4, the ConciergeParser (aka AddressBookParser) will parse the user input and create a ServiceCommandParser object to parse a service command. The ServiceCommandParser is responsible for checking that the RoomNumber and cost (a Money object) are in the correct format. Note that the item number is not checked here, since the Menu object of Concierge has to be available in order to check that the given item number is a valid item. Hence, any string will be accepted by the parser. Since ServiceCommand has access to the Model and thus the Menu, the checking is given to ServiceCommand instead. A successful parse will then return a ServiceCommand(RoomNumber roomNumber, String itemNumber, Optional<Money> itemCost) object.

The following flowchart describes what happens when the execute method of a ServiceCommand is called.

ServiceCommand flowchart

The model.addExpense() method call was not illustrated in detail in the flowchart, thus it is illustrated in this sequence diagram.

AddExpenseSequenceDiagram

Design Considerations

Aspect: Deleting and editing Expenses
  • Alternative 1 (current choice): Use service to edit `Expense`s.

    • Pros: Simply keying in `Expense`s with negative values is easy to implement, and does not stray far from real-life implementations, e.g. receipts often contain cost subtractions for discounts and promotions.

    • Cons: May not be elegant, Expenses may become cluttered if there’s too many corrections.

  • Alternative 2: Create new commands to edit and delete `Expense`s.

    • Pros: The Expenses will contain all the `Expense`s at their correct prices.

    • Cons: More effort to implement, difficult to implement, e.g. may need to implement listing out all Expense`s of a `Room with the list command in order to select the Expense to delete or edit. Information on discounts and corrections will also be lost.