diff --git a/.gitignore b/.gitignore
index 284c4ca7cd9..8bb5051a94a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
/.gradle/
/build/
src/main/resources/docs/
+bin/
# IDEA files
/.idea/
diff --git a/README.md b/README.md
index 13f5c77403f..21ccac543d3 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,21 @@
-[](https://github.com/se-edu/addressbook-level3/actions)
+[](https://github.com/AY2324S2-CS2103T-T17-4/tp/actions)
+[](https://codecov.io/gh/AY2324S2-CS2103T-T17-4/tp)

-* This is **a sample project for Software Engineering (SE) students**.
- Example usages:
- * as a starting point of a course project (as opposed to writing everything from scratch)
- * as a case study
-* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details.
- * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big.
- * It comes with a **reasonable level of user and developer documentation**.
-* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...).
-* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**.
-* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info.
+This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+
+# FnBuddy
+FnBuddy is an innovative employee contact management application designed specifically for restaurant managers.
+It offers a user-friendly interface (both CLI and GUI) that allows you to effortlessly create, manage,
+and maintain contact records for all your part-time employees. With FnBuddy, you can store essential information such as
+contact details, banking information, and work schedules, ensuring efficient communication and accurate payroll
+calculations.
+
+Example usages:
+ * As a restaurant manager, I can store the contact and banking details of my part-time employees for easy referral when I want to contact them or transfer their salary.
+ * As a restaurant manager, I can remove the details of my part-time employees so that I can free up space in my address book.
+ * As a restaurant manager, I can view the contacts of all my part-time employees so that I can have an overview of all contacts in my address book.
+ * As a restaurant manager, I can use the application to store the accumulated work hours of my part-time employee for later use of salary calculation.
+
+For the detailed documentation of this project, see the **[FnBuddy Product Website](https://ay2324s2-cs2103t-t17-4.github.io/tp/)**.
diff --git a/build.gradle b/build.gradle
index a2951cc709e..f8832c5f749 100644
--- a/build.gradle
+++ b/build.gradle
@@ -25,6 +25,10 @@ test {
finalizedBy jacocoTestReport
}
+run {
+ enableAssertions = true
+}
+
task coverage(type: JacocoReport) {
sourceDirectories.from files(sourceSets.main.allSource.srcDirs)
classDirectories.from files(sourceSets.main.output)
@@ -66,7 +70,7 @@ dependencies {
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'fnbuddy.jar'
}
defaultTasks 'clean', 'test'
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..ec2f3f01702 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -9,51 +9,53 @@ You can reach us at the email `seer[at]comp.nus.edu.sg`
## Project team
-### John Doe
+### Chua Joon Peng, Gabriel
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[homepage](https://www.linkedin.com/in/gabriel-chua-087543229/)]
+[[github](https://github.com/1rbg)]
+[[portfolio](team/gabrielchua.md)]
-* Role: Project Advisor
+* Role: Developer
+* Responsibilities: Documentation + UI
-### Jane Doe
+### Teo Hao Wei
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/h4ow3i)]
+[[portfolio](team/teohaowei.md)]
-* Role: Team Lead
-* Responsibilities: UI
+* Role: Developer
+* Responsibilities: Code Quality
-### Johnny Doe
+### Hue Koh
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/huekoh)]
+[[portfolio](team/huekoh.md)]
* Role: Developer
-* Responsibilities: Data
+* Responsibilities: Task Scheduling + UI
-### Jean Doe
+### Martin Ng Jinn Kai
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/martinng01)]
+[[portfolio](team/martinng.md)]
* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Responsibilities: Testing
-### James Doe
+### Jin Xunze
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/jxunze)]
+[[portfolio](team/jinxunze.md)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities: Integration
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 1b56bb5d31b..a2e6a80fff2 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -2,28 +2,57 @@
layout: page
title: Developer Guide
---
+
* Table of Contents
-{:toc}
+ * [Acknowledgements](#acknowledgements)
+ * [Setting up, getting started](#setting-up-getting-started)
+ * [Design](#design)
+ * [Architecture](#architecture)
+ * [UI component](#ui-component)
+ * [Logic component](#logic-component)
+ * [Model component](#model-component)
+ * [Storage component](#storage-component)
+ * [Common classes](#common-classes)
+ * [Implementation](#implementation)
+ * [\[Implemented\] Schedule feature](#implemented-schedule-feature)
+ * [Proposed Implementation](#proposed-implementation)
+ * [\[Implemented\] Contact archiving](#implemented-contact-archiving)
+ * [Proposed Implementation](#proposed-implementation)
+ * [\[Proposed\] Undo/redo feature](#proposed-undoredo-feature)
+ * [Proposed Implementation](#proposed-implementation)
+ * [Design considerations:](#design-considerations)
+ * [Documentation, logging, testing, configuration, dev-ops](#documentation-logging-testing-configuration-dev-ops)
+ * [Appendix: Requirements](#appendix-requirements)
+ * [Product scope](#product-scope)
+ * [User stories](#user-stories)
+ * [Use cases](#use-cases)
+ * [Non-Functional Requirements](#non-functional-requirements)
+ * [Glossary](#glossary)
+ * [Appendix: Instructions for manual testing](#appendix-instructions-for-manual-testing)
+ * [Launch and shutdown](#launch-and-shutdown)
+ * [Deleting a person](#deleting-a-person)
--------------------------------------------------------------------------------------------------------------------
-## **Acknowledgements**
+## Acknowledgements
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+* Calendar for Schedule feature adapted from: https://gist.github.com/Da9el00/f4340927b8ba6941eb7562a3306e93b6
--------------------------------------------------------------------------------------------------------------------
-## **Setting up, getting started**
+## Setting up, getting started
Refer to the guide [_Setting up and getting started_](SettingUp.md).
--------------------------------------------------------------------------------------------------------------------
-## **Design**
+## Design
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document `docs/diagrams` folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
+:bulb: **Tip:** The `.puml` files used to create diagrams in this document `docs/diagrams` folder. Refer to the [
+_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create
+and edit diagrams.
### Architecture
@@ -36,7 +65,11 @@ Given below is a quick overview of main components and how they interact with ea
**Main components of the architecture**
-**`Main`** (consisting of classes [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down.
+**`Main`** (consisting of
+classes [`Main`](https://github.com/AY2324S2-CS2103T-T17-4/tp/tree/master/src/main/java/seedu/address/Main.java)
+and [`MainApp`](https://github.com/AY2324S2-CS2103T-T17-4/tp/tree/master/src/main/java/seedu/address/MainApp.java)) is
+in charge of the app launch and shut down.
+
* At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
* At shut down, it shuts down the other components and invokes cleanup methods where necessary.
@@ -51,16 +84,21 @@ The bulk of the app's work is done by the following four components:
**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 `delete 1`.
+The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues
+the command `delete 98765432`.
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 API `interface` mentioned in the previous point.
+* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding
+ API `interface` 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.
+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.
@@ -68,13 +106,21 @@ The sections below give more details of each component.
### UI component
-The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java)
+The **API** of this component is specified
+in [`Ui.java`](https://github.com/AY2324S2-CS2103T-T17-4/tp/tree/master/src/main/java/seedu/address/ui/Ui.java)

-The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `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 consists of a `MainWindow` that is made up of parts
+e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `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`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml)
+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`](https://github.com/AY2324S2-CS2103T-T17-4/tp/tree/master/src/main/java/seedu/address/ui/MainWindow.java)
+is specified
+in [`MainWindow.fxml`](https://github.com/AY2324S2-CS2103T-T17-4/tp/tree/master/src/main/resources/view/MainWindow.fxml)
The `UI` component,
@@ -85,25 +131,29 @@ The `UI` component,
### Logic component
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+The **API** of this component is specified in [`Logic.java`](https://github.com/AY2324S2-CS2103T-T17-4/tp/tree/master/src/main/java/seedu/address/logic/Logic.java)
Here's a (partial) class diagram of the `Logic` component:
-The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example.
+The sequence diagram below illustrates the interactions within the `Logic` component, taking
+`execute("delete 98765432")` API call as an example.
-
+
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
How the `Logic` component works:
-1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command.
-1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`.
+1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates
+ a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command.
+1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which
+ is executed by the `LogicManager`.
1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
- Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve.
+ Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take
+ several interactions (between the command object and the `Model`) to achieve.
1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
@@ -111,11 +161,18 @@ Here are the other classes in `Logic` (omitted from the class diagram above) tha
How the parsing works:
-* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object.
-* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
+
+* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a
+ placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse
+ the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as
+ a `Command` object.
+* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser`
+ interface so that they can be treated similarly where possible e.g, during testing.
### Model component
-**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
+
+**API
+** : [`Model.java`](https://github.com/AY2324S2-CS2103T-T17-4/tp/tree/master/src/main/java/seedu/address/model/Model.java)
@@ -123,9 +180,14 @@ How the parsing works:
The `Model` component,
* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
-* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` 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 a `ReadOnlyUserPref` 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)
+* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which
+ is exposed to outsiders as an unmodifiable `ObservableList` 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
+ a `ReadOnlyUserPref` objects.
+* stores a `Schedule` object that represents the employees' work schedule.
+* 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)
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
@@ -133,17 +195,21 @@ The `Model` component,
-
### Storage component
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
+**API
+** : [`Storage.java`](https://github.com/AY2324S2-CS2103T-T17-4/tp/tree/master/src/main/java/seedu/address/storage/Storage.java)
The `Storage` component,
-* can save both address book data and user preference data in JSON format, and read them back into corresponding objects.
-* inherits from both `AddressBookStorage` and `UserPrefStorage`, 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 the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
+
+* can save both address book data and user preference data in JSON format, and read them back into corresponding
+ objects.
+* inherits from all of `AddressBookStorage`, `UserPrefStorage` and `ScheduleStorage`, 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 the `Storage` component's job is to save/retrieve objects
+ that belong to the `Model`)
### Common classes
@@ -151,33 +217,102 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa
--------------------------------------------------------------------------------------------------------------------
-## **Implementation**
+## Implementation
This section describes some noteworthy details on how certain features are implemented.
+### \[Implemented\] Schedule feature
+#### Proposed Implementation
+
+The current implementation of the schedule feature is facilitated by the `Schedule` interface. It contains a
+`Set`, which contains the `ScheduleDate` objects that represent the dates in the schedule and hold a
+list of who is working on that particular date.
+
+Given below is an example usage scenario and how the schedule mechanism behaves at each step.
+
+Step 1. The user launches the application for the first time. A concrete class implementing `Schedule` will be
+initialised with an empty set of `ScheduleDate` objects. The `ModelManager` is then initialised with the `Schedule`.
+
+Step 2. The user executes `schedule 98765432 2024-04-15` command to add a schedule entry for the person with phone
+number `98765432` on the date `2024-04-15`. The old `Schedule` object is then updated in the `Model` through the calling
+of `Model#addPersonToSchedule()`, which creates a new `ScheduleDate` object that corresponds to the date
+`2024-04-15`, and adds the person with phone number `98765432` to the list of people working on that date. The UI
+changes screen to show the updated schedule.
+
+
+
+Step 3. The user decides that he would like to add another person on the same date. The user executes `schedule
+92345678 2024-04-15` command to add a schedule entry for the person with phone number `92345678` on the date
+`2024-04-15`. The old `Schedule` object is then updated in the `Model` through the calling of
+`Model#addPersonToSchedule()`, which uses the existing `ScheduleDate` object associated with `2024-04-15` that
+corresponds to the date `2024-04-15`, and adds the person with phone number `98765432` to the list of people working
+on that date. The UI changes screen to show the updated schedule.
+
+Step 4. The user decides that he would like to remove the schedule entry. The user executes `unschedule 98765432
+2024-04-15` command to remove the schedule entry for the person with phone number `98765432` on the date
+`2024-04-15`. The `unschedule` command removes a person with phone number `98765432` from the existing
+`ScheduleDate` with date `2024-04-15`. The UI changes screen to show the updated schedule.
+
+### \[Implemented\] Contact archiving
+#### Proposed Implementation
+
+The current implementation of contact archiving (and by virtue un-archiving) is facilitated by the `ArchiveCommand`
+and `UnarchiveCommand`. It extends `Command` and is responsible for updating the `Person` object's `Archive` field.
+
+Given below is an example usage scenario and how the archive/unarchive mechanism behaves at each step.
+
+Step 1. The user launches the application. Existing contacts in storage are loaded into the `AddressBook`, the `ModelManager`
+is then initialised with the `AddressBook`. The `Person` objects in the `AddressBook` that have `ArchiveStatus` field set to 'false'
+are filtered by `ModelManager` into the `ObservableList` to be displayed in the UI.
+
+Step 2. The user executes `archive 98765432` command to archive the person in the address book. The `archive` command
+creates a new `Person` object that corresponds to all of the selected `Person` object's fields, except for the
+`ArchiveStatus` field which it intialises as 'true'. The old `Person` object is then updated in the `AddressBook` through
+the calling of `Model#archivePerson()`. The UI updates the `ObservableList` to reflect the changes made.
+
+
+
+Step 3. The user decides that he would like to view the archived contact. The user executes `list archive` command to
+view all archived contacts. The `list archive` command filters the `Person` objects in the `AddressBook` that have
+`ArchiveStatus` field set to 'true' into the `ObservableList` to be displayed in the UI.
+
+Step 4. The employee of the archived contact decides to return to the company. The user executes `unarchive 98765432`
+command to unarchive the person in the address book. The `unarchive` command creates a new `Person` object that
+corresponds to all of the selected `Person` object's fields, except for the `ArchiveStatus` field which it intialises
+as 'false'. The old `Person` object is then updated in the `AddressBook` through the calling of `Model#archivePerson()`.
+
### \[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:
+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.
+* `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.
+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 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 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`.
+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`.

@@ -185,7 +320,9 @@ Step 3. The user executes `add n/David …` to add a new person. The `add` co
-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.
+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.

@@ -206,17 +343,23 @@ Similarly, how an undo operation goes through the `Model` component is shown bel

-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.
+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.
:information_source: **Note:** If the `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 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.
+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.

@@ -229,24 +372,19 @@ The following activity diagram summarizes what happens when a user executes a ne
**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.
+ * 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 `delete`, just save the person being deleted).
+ * Cons: We must ensure that the implementation of each individual command are correct.
_{more aspects and alternatives to be added}_
-### \[Proposed\] Data archiving
-
-_{Explain here how the data archiving feature will be implemented}_
-
-
--------------------------------------------------------------------------------------------------------------------
-## **Documentation, logging, testing, configuration, dev-ops**
+## Documentation, logging, testing, configuration, dev-ops
* [Documentation guide](Documentation.md)
* [Testing guide](Testing.md)
@@ -256,81 +394,155 @@ _{Explain here how the data archiving feature will be implemented}_
--------------------------------------------------------------------------------------------------------------------
-## **Appendix: Requirements**
+## Appendix: Requirements
### Product scope
**Target user profile**:
-* has a need to manage a significant number of contacts
+* has a need to manage a significant number of employee contacts and banking details
+* has a need to track employee worked hours
+* has a need to tabulate payroll for employees with different pay rates
* prefer desktop apps over other types
* can type fast
* prefers typing to mouse interactions
* is reasonably comfortable using CLI apps
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
-
+**Value proposition**: manage employee salary disbursement faster than a typical exel sheet with manual calculations.
### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| Priority | As a … | I want to … | So that I can… |
-| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- |
-| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
+| Priority | As a … | I want to … | So that I can… |
+|----------|----------------------------------------------------------------|----------------------------------------------------|-----------------------------------------------------------------------|
+| `* *` | new user | see a tutorial and usage instructions | familiarise with FnBuddy' features |
+| `* * *` | user | add an employee contact with banking details | quickly access the employee's banking details for salary disbursement |
+| `* * *` | user | delete an employee contact | remove entries that I no longer need |
+| `* * *` | user | view all employee contacts | |
+| `* *` | user | track an employee's weekly worked hours | access it for employee salary calculation |
+| `* *` | user handling employees with a variety of employment contracts | tag an employee contact with their employment type | retrieve the salary rate of the employee |
+| `* *` | user with human error tendencies | retrieve an employee's calculated pay | avoid paying out an incorrect salary amount |
+| `* *` | user | edit an employee contact details | keep the employee's details up to date |
+| `* *` | user | schedule my employee shifts | plan workload more easily |
+| `*` | user with many employees | sort employees contacts by name | locate the employee contact easily |
+| `*` | user with potential returning employees | archive an employee contact | reopen the employee's details when they return easily |
+| `*` | user with forgetfulness | search for contacts by keyword | find contacts without needing to provide their full name |
+| `*` | user with many employees | filter employee contacts by tag(s) | identify which employee(s) are of that employment type |
*{More to be added}*
### Use cases
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+(For all use cases below, the **System** is the `FnBuddy` and the **Actor** is the `user`, unless specified otherwise)
+
+**Use case: Add an employee**
+
+**MSS**
+
+1. User requests to add employee contact
+2. FnBuddy requests contact information of employee
+3. User provides required information
+4. FnBuddy adds the employee contact
+
+ Use case ends.
+
+**Extensions**
+
+* 3a. The given contact information is invalid.
+
+ * 3a1. FnBuddy shows an error message.
-**Use case: Delete a person**
+ Use case resumes at step 2.
+
+**Use case: Delete an employee**
**MSS**
-1. User requests to list persons
-2. AddressBook shows a list of persons
-3. User requests to delete a specific person in the list
-4. AddressBook deletes the person
+1. User requests to delete an employee contact
+2. FnBuddy requests employee contact
+3. User provides required information
+4. FnBuddy deletes the employee contact
Use case ends.
**Extensions**
-* 2a. The list is empty.
+* 2a. The contact book is empty.
+ * 2a1. FnBuddy shows an error message.
+
+ Use case ends
- Use case ends.
-* 3a. The given index is invalid.
+* 3a. The given contact information is invalid.
- * 3a1. AddressBook shows an error message.
+ * 3a1. FnBuddy shows an error message.
Use case resumes at step 2.
-*{More to be added}*
+**Use case: List all employee contacts**
-### Non-Functional Requirements
+**MSS**
+
+1. User requests to list all employee contacts
+2. FnBuddy lists all employee contacts
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The contact book is empty.
+ * 2a1. FnBuddy shows an error message.
+
+ Use case ends
+
+**Use case: Track employee's work hours**
+
+**MSS**
+
+1. User requests to add employee's work hours
+2. FnBuddy requests employee contact and work hours
+3. User provides required information
+4. FnBuddy tracks the employee's work hours
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The contact book is empty.
+ * 2a1. FnBuddy shows an error message.
+
+ Use case ends
+
+
+* 3a. The given contact information or working hours is invalid.
+
+ * 3a1. FnBuddy shows an error message.
+
+ Use case resumes at step 2.
-1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
-2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
-3. 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.
*{More to be added}*
+### Non-Functional Requirements
+
+1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
+2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
+3. 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.
+4. The app should be highly reliable, minimizing downtime and ensuring continuous availability during operational hours.
+5. It should have built-in mechanisms for data backup and recovery to prevent loss of employee contact information.
+
### Glossary
* **Mainstream OS**: Windows, Linux, Unix, MacOS
* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **Worked hours**: The number of hours an employee has spent working in a month
+* **Bank Details**: Account number for salary disbursement, 7-11 digits in length.
--------------------------------------------------------------------------------------------------------------------
-## **Appendix: Instructions for manual testing**
+## Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
@@ -343,15 +555,16 @@ testers are expected to do more *exploratory* testing.
1. Initial launch
- 1. Download the jar file and copy into an empty folder
+ 1. Download the jar file and copy into an empty folder
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+ 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be
+ optimum.
1. Saving window preferences
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+ 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
- 1. Re-launch the app by double-clicking the jar file.
+ 1. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
1. _{ more test cases … }_
@@ -360,23 +573,15 @@ testers are expected to do more *exploratory* testing.
1. Deleting a person while all persons are being shown
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+ 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
- 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.
+ 1. Test case: `delete 1`
+ Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message.
+ Timestamp in the status bar is updated.
- 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+ 1. Test case: `delete 0`
+ Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
-
-1. _{ more test cases … }_
+ 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
+ Expected: Similar to previous.
-### Saving data
-
-1. Dealing with missing/corrupted data files
-
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
-
-1. _{ more test cases … }_
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 7abd1984218..90caab92ace 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,198 +1,547 @@
----
-layout: page
-title: User Guide
----
+# FnBuddy User Guide
+
+Welcome to the FnBuddy User Guide! This comprehensive guide is designed to help you navigate and utilise the FnBuddy part-time employee contact management application with ease.
+Whether you need to create, update, schedule or retrieve the payroll of your employees, or simply wish to navigate the application seamlessly, this guide will equip you with the knowledge to do so effectively.
+
+Our guide assumes that you are a restaurant manager with a basic understanding of using software applications, and are familiar with common restaurant operations and terminology.
+
+## Table of Contents
+
+- [FnBuddy User Guide](#fnbuddy-user-guide)
+ - [Table of Contents](#table-of-contents)
+ - [Introduction to FnBuddy](#introduction-to-fnbuddy)
+ - [Quick Start](#quick-start)
+ - [GUI Components](#gui-components)
+ - [Pages](#pages)
+ - [Command Type](#command-type)
+ - [Features](#features)
+ - [Notes about the command format](#notes-about-the-command-format)
+ - [Adding a person `add`](#adding-a-person-add)
+ - [Listing contacts `list`](#listing-contacts-list)
+ - [Deleting a person `delete`](#deleting-a-person-delete)
+ - [Editing a person `edit`](#editing-a-person-edit)
+ - [Locating a person by name `find`](#locating-a-person-by-name-find)
+ - [Clear all contacts `clear`](#clear-all-contacts-clear)
+ - [Exiting the program `exit`](#exiting-the-program-exit)
+ - [Archiving the person `archive`](#archiving-the-person-archive)
+ - [Unarchive the person `unarchive`](#unarchive-the-person-unarchive)
+ - [Retrieving payroll `payroll`](#retrieving-payroll-payroll)
+ - [Schedule employees `schedule`](#schedule-employees-schedule)
+ - [Unschedule employees `unschedule`](#unschedule-employees-unschedule)
+ - [Saving the data](#saving-the-data)
+ - [Modifying saved data](#modifying-saved-data)
+ - [Known Issues](#known-issues)
+ - [Planned Enhancements](#planned-enhancements)
+ - [Adding a `view` feature](#adding-a-view-feature)
+ - [Enhancements to Archive Feature](#enhancements-to-archive-feature)
+ - [More Informative List Command Feedback](#more-informative-list-command-feedback)
+ - [Enhancements to Scheduling and Payroll Feature](#enhancements-to-scheduling-and-payroll-feature)
+ - [Separating Multiple Tags](#separating-multiple-tags)
+ - [Glossary](#glossary)
+ - [FAQ](#faq)
+ - [Command summary](#command-summary)
+
+Click on any item in the table of contents to instantly navigate to that specific section.
+
+
+
+## Introduction to FnBuddy
+
+Whether you're a seasoned restaurant manager or new to the role, FnBuddy will serve as your trusted companion, empowering you to streamline your operations and enhance your team management capabilities. FnBuddy manage contacts optimised for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). So if you're a fast typer, FnBuddy is just the application for you!
+
+Features that FnBuddy offers with your needs in mind include:
+- **contact creation and management** such as editing and archiving
+- **scheduling** of part-time employee contacts on specified dates
+- **payroll retrieval** that calculates the total payroll for all employees who worked within a specified date range (currently dependent on their scheduled hours).
+
+
+
+## Quick Start
+
+1. Ensure you have [Java 11](#faq) or above installed on your Computer.
+2. Download the latest fnbuddy.jar from [here](https://github.com/AY2324S2-CS2103T-T17-4/tp/releases/latest/).
+3. Move the fnbuddy.jar file to the directory you intend to designate as the home folder for your FnBuddy.
+4. Open the terminal on your Operating System.
+ - For Windows, press `Win + R`, type `cmd`, and press Enter.
+ - For macOS, press `Cmd + Space`, type `Terminal`, and press Enter.
+ - For Linux, press `Ctrl + Alt + T`.
+5. You should see a terminal window similar to the one below open. (The terminal window will look different depending on your Operating System.)
+
+ |  |
+ |--------------------------------------------------|
+ | *Example of a terminal window on a MacOS system* |
+6. Type `cd` followed by the path to the folder you copied the fnbuddy.jar file to.
+ - Windows Example: `cd C:\Users\JohnDoe\Desktop\FnBuddy`.
+ - MacOS Example: `cd /Users/JohnDoe/Desktop/FnBuddy`.
+ - Linux Example: `cd /home/JohnDoe/Desktop/FnBuddy`.
+7. Type `java -jar fnbuddy.jar` to run the application.
+8. An application similar to the one below should appear in a few seconds. For a more detailed explanation of the Graphical User Interface (GUI) and
+ its components, refer to the [GUI Components](#gui-components). Note how the app contains some sample data. The list of contacts displayed at startup is the main list of unarchived contacts. More details in the [Features](#features) section below.
+
+ |  |
+ |------------------------|
+ | *FnBuddy GUI* |
+
+9. Type the command in the command box and press Enter to execute it. e.g., typing `help` and pressing Enter will open the help window.
+
+Some example commands you can try:
+
+- `add -fn Javier -ln Tan -p 98749874 -s m -pr 10.5 -a 123 Street -b posb 420053040` : Adds a contact named Javier Tan to FnBuddy.
+- `list all` : Lists all contacts.
+- `list main` : Lists all un-archived contacts.
+- `list archive` : Lists all archived contacts.
+- `archive 98749874` : Archives the contact associated with the phone number 98749874.
+- `delete 98749874` : Deletes the contact associated with the phone number 98749874 from FnBuddy.
+- `edit 98749874 -a NUS` : Edits the address of the contact associated with phone number 98749874 to NUS.
+- `find james` : Searches the address book for a person whose name matches “james”.
+- `clear` : Deletes all contacts.
+- `exit` : Exits the app.
+
+Refer to the [Features](#features) section below for details of each command.
+
+
+
+## GUI Components
+|  |
+|----------------------------------------|
+| *Labelled UI Components* |
+The names of the UI components have been labelled in the image above. The components are as follows:
+1. **Command Box** - This is where you can type commands to interact with the application.
+2. **Feedback Panel** - This panel displays feedback messages to the user. These feedback messages can be success
+ messages, error messages, or help with commands.
+3. **Navigation Buttons** - These buttons allow you to navigate between the different pages of the application. The
+ buttons are labelled "CONTACTS" and "SCHEDULE".
+4. **Results Panel** - This panel displays the currently selected page, based on the last command or button clicked. The
+ results panel will display the contacts, schedule, or payroll based on the page selected.
+5. **Menu Bar** - The menu bar contains the "File" and "Help" menus. The "File" menu contains the "Exit" option, which
+ allows you to exit the application. The "Help" menu contains the "Help" option, which provides a link to this
+ user guide for the application.
+
+
+
+## Pages
+There are 3 main pages in the application:
+1. **Main Page** - This page shows all the contacts in the application. You can view the details of each contact by clicking on the contact.
+
+ |  |
+ |------------------------------|
+ | *FnBuddy Main Page* |
+
+
+
+2. **Payroll Page** - This page shows the payroll of all employees for the given date range in the payroll command.
+
+ |  |
+ |-----------------------------------------------------------------|
+ | *FnBuddy Payroll Page* |
+3. **Schedule Page** - This page shows the schedule of all employees for the next four weeks (including the current
+ week).
+
+ |  |
+ |----------------------------------------------------|
+ | *FnBuddy Schedule Page* |
+
+### Command Type
+With the 3 different pages, different types of commands can also be used to navigate the application. These types are as follows:
+1. **Main Page Commands** - These commands when used will navigate to the main page of the application.
+2. **Payroll Page Commands** - These commands when used will navigate to the payroll page of the application.
+3. **Schedule Page Commands** - These commands when used will navigate to the schedule page of the application.
+
+
-AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps.
-
-* Table of Contents
-{:toc}
+## Features
---------------------------------------------------------------------------------------------------------------------
+### Notes about the command format
-## Quick start
+- Words in UPPER_CASE are the parameters to be supplied by the user. e.g., in `add -fn FIRST_NAME -ln LAST_NAME`, FIRST_NAME and LAST_NAME are parameters which can be used as `add -fn Javier -ln Tan`.
+- Items in square brackets are optional. e.g., `-fn FIRST_NAME -ln LAST_NAME [-t TAG]` can be used as `-fn Javier -ln Tan -t/waiter` or as `-fn Javier -ln Tan`.
+- Items with `…` after them can be used multiple times, including zero times. e.g., `[-t TAG]…` can be used as `-t cook -t waiter -t dishwasher`, etc.
+- Parameters can be in any order. e.g., if the command specifies `-fn FIRST_NAME -ln LAST_NAME`, `-ln LAST_NAME -fn FIRST_NAME` is also acceptable.
+- Extraneous parameters for commands that do not take in parameters (such as help, exit, and clear) will be ignored. e.g., if the command specifies `help 123`, it will be interpreted as `help`.
+- If you are using a PDF version of this document, be careful when copying and pasting commands that span multiple lines, as space characters surrounding line-breaks may be omitted when copied over to the application.
+- There should be spaces between the flags and the parameters. e.g., `add -fn Javier -ln Tan` is correct, while `add -fn Javier-ln Tan` is incorrect. However, extra spaces are allowed. e.g., `add -fn Javier -ln Tan` is also correct.
+- The types of commands are divided into 3 categories: Main Page Commands, Payroll Page Commands, and Schedule Page
+ Commands. For more details, refer to the [Pages](#Pages) section below.
+- If you key in any command that is not recognised by the application, the feedback panel will display an error message
+ indicating that the command is not recognised.
+- If you key in any command that is recognised by the application but has incorrect parameters, the feedback panel will
+ display an error message indicating that the command has incorrect parameters. Just follow the correct format and
+ try again!
-1. Ensure you have Java `11` or above installed in your Computer.
+***
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+### Adding a person `add`
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+Adds a person’s contact to FnBuddy.
-1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
- A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- 
+Format: `add -fn FIRST_NAME -ln LAST_NAME -p PHONE_NUMBER -s SEX -pr PAY_RATE -a ADDRESS [-b BANK_DETAILS] [-t TAG]…`
-1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
- Some example commands you can try:
+Command Type: [Main Page Command](#command-type)
- * `list` : Lists all contacts.
+Example:
- * `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book.
+- `add -fn John -ln Doe -p 91860934 -s m -pr 20.50 -a 123 Main St, City`
+- `add -fn Jane -ln Smith -p 98765432 -s f -pr 25.50 -a 432 Orchard Road -b posb 123456789 -t waiter -t bartender`
- * `delete 3` : Deletes the 3rd contact shown in the current list.
+Note: All contacts added are compressed to only show `FIRST_NAME`, `LAST_NAME` and `PHONE_NUMBER` by default. To view all the contact's information, simply click on the GUI contact to expand it.
- * `clear` : Deletes all contacts.
+***
- * `exit` : Exits the app.
+
-1. Refer to the [Features](#features) below for details of each command.
+### Listing contacts `list`
---------------------------------------------------------------------------------------------------------------------
+Shows a list of contacts in FnBuddy depending on which you'd like to view. On launch of the application, the default list shows all un-archived contacts only.
-## Features
+Format: `list LIST_TYPE`
-
+Command Type: [Main Page Command](#command-type)
-**:information_source: Notes about the command format:**
+Example:
-* Words in `UPPER_CASE` are the parameters to be supplied by the user.
- e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`.
+- `list all` shows all contacts in FnBuddy.
-* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`.
+|  |
+|------------------------------------------------------------------|
+| _Example result panel display for a successful list all command_ |
-* Items with `…` after them can be used multiple times including zero times.
- e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc.
+- `list main` shows all un-archived contacts in FnBuddy.
-* Parameters can be in any order.
- e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable.
+|  |
+|-------------------------------------------------------------------|
+| _Example result panel display for a successful list main command_ |
-* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
- e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+- `list archive` shows all archived contacts in FnBuddy.
-* If you are using a PDF version of this document, be careful when copying and pasting commands that span multiple lines as space characters surrounding line-breaks may be omitted when copied over to the application.
-
+|  |
+|----------------------------------------------------------------------|
+| _Example result panel display for a successful list archive command_ |
-### Viewing help : `help`
+Note: If unexpected extraneous parameters are added such as `list main 123`, the command will default to `list all`. (eg. you are currently viewing `list all` and want to switch to `list archive`, but typed `list archivee` instead, there will be no visible change on the GUI as it has defaulted to `list all`.)
-Shows a message explaning how to access the help page.
+Note: We understand that the current feedback messages for the list command may not be sufficient to inform you which list you are currently viewing. As we continue to strive and improve your experience with us in upcoming versions, we seek your understanding on this for FnBuddy's current version and have addressed some possible scenarios in the [FAQ](#FAQ) section.
-
+### Deleting a person `delete`
-Format: `help`
+Deletes the specified person from FnBuddy.
+Format: `delete PHONE_NUMBER`
-### Adding a person: `add`
+Command Type: [Main Page Command](#command-type)
-Adds a person to the address book.
+Example:
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+- `delete 91860934` deletes the person with the number 91860934 from FnBuddy.
-
:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
+***
-Examples:
-* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01`
-* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal`
+### Editing a person `edit`
-### Listing all persons : `list`
+Edits an existing person in FnBuddy.
-Shows a list of all persons in the address book.
+Format: `edit PHONE_NUMBER [-fn FIRST_NAME] [-ln LAST_NAME] [-p PHONE_NUMBER] [-s SEX] [-pr PAY_RATE] [-a ADDRESS] [-b BANK_DETAILS] [-t TAG]…`
-Format: `list`
+Command Type: [Main Page Command](#command-type)
-### Editing a person : `edit`
+Example:
-Edits an existing person in the address book.
+- `edit 91860934 -a Room 504, Marina Bay Sands -pr 25` Edits the address of the person with the phone number 91860934 to Room 504 Marina Bay Sands, and their pay rate to 25 dollars per hour, respectively.
+- `edit 98765432 -t ` Clears all existing tags from the person with the phone number 98765432. Take note to put an additional space after the `-t` flag to clear all tags.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+Note: You can only edit contacts that are currently visible in the panel. If you are unable to find the contact you
+wish to edit, use the `find` command to locate the contact first, or use the `list all` command to view all contacts
+before editing that particular contact.
-* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …
-* At least one of the optional fields must be provided.
-* Existing values will be updated to the input values.
-* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative.
-* You can remove all the person’s tags by typing `t/` without
- specifying any tags after it.
+***
-Examples:
-* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively.
-* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags.
+
-### Locating persons by name: `find`
+### Locating a person by name `find`
-Finds persons whose names contain any of the given keywords.
+Finds persons whose names match completely any of the given keywords. The search is case-insensitive.
Format: `find KEYWORD [MORE_KEYWORDS]`
-* The search is case-insensitive. e.g `hans` will match `Hans`
-* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`
-* Only the name is searched.
-* Only full words will be matched e.g. `Han` will not match `Hans`
-* Persons matching at least one keyword will be returned (i.e. `OR` search).
- e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`
+Command Type: [Main Page Command](#command-type)
-Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- 
+Example:
-### Deleting a person : `delete`
+- `find tan` returns all contacts with names matching `tan`.
-Deletes the specified person from the address book.
+|  |
+|--------------------------------------------------------------|
+| *Example result panel display for a successful find command* |
-Format: `delete INDEX`
+***
-* Deletes the person at the specified `INDEX`.
-* The index refers to the index number shown in the displayed person list.
-* The index **must be a positive integer** 1, 2, 3, …
+### Clear all contacts `clear`
-Examples:
-* `list` followed by `delete 2` deletes the 2nd person in the address book.
-* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command.
+Delete all employee contacts.
-### Clearing all entries : `clear`
+Format: `clear`
-Clears all entries from the address book.
+Command Type: [Main Page Command](#command-type)
-Format: `clear`
+**WARNING!** This action is permanent and non-reversible! Make sure that you want to clear FnBuddy before you execute the command.
+
+***
-### Exiting the program : `exit`
+### Exiting the program `exit`
Exits the program.
Format: `exit`
+***
+
+### Archiving the person `archive`
+
+Archives the person's contact so that it is hidden from the main list of contacts.
+
+Format: `archive PHONE_NUMBER`
+
+Command Type: [Main Page Command](#command-type)
+
+Example:
+
+- `archive 91860934` archives the person with the number 91860934 from FnBuddy's main list of contacts.
+
+***
+
+### Unarchive the person `unarchive`
+
+Unarchive the person's contact so that it is shown in the main list of contacts.
+
+Format: `unarchive PHONE_NUMBER`
+
+Command Type: [Main Page Command](#command-type)
+
+Example:
+
+- `unarchive 91860934` un-archives the person with the number 91860934 from FnBuddy's main list of contacts.
+
+***
+
+
+
+### Retrieving payroll `payroll`
+
+Retrieve employee's payroll for a given start and end date
+
+Format: `payroll -sd START_DATE -ed END_DATE` where `START_DATE` and `END_DATE` are in the format `YYYY-MM-DD`.
+
+Command Type: [Payroll Command](#command-type)
+
+Example:
+
+- `payroll -sd 2024-04-01 -ed 2024-04-30` calculates the payroll of all employees that have worked within 1st April 2024 and 30th April 2024.
+
+|  |
+|-----------------------------------------------------------------|
+| *Example result panel display for a successful payroll command* |
+
+Note: Employee's payroll is calculated by multiplying 8 to their respective `PAY_RATE`. We are assuming each shift is 8 hours.
+
+***
+
+
+
+### Schedule employees `schedule`
+
+Adds a person in FnBuddy to the schedule on a specified date.
+
+Format: `schedule PHONE_NUMBER DATE` where `DATE` is in the format `YYYY-MM-DD`.
+
+Command Type: [Schedule Command](#command-type)
+
+Example:
+- `schedule 91860934 2024-04-01` Adds the person with the phone number 91860934 to the schedule on 1st April 2024.
+
+|  |
+|----------------------------------------------------------------------|
+| *Example result panel display for a successful schedule command* |
+
+Note: If you add a duplicate entry in the schedule for the same date, the feedback message will not prompt this.
+However, the schedule will not be updated with the new entry.
+
+***
+
+
+
+### Unschedule employees `unschedule`
+
+Removes a person in FnBuddy from the schedule on a specified date.
+
+Format: `unschedule PHONE_NUMBER DATE` where `DATE` is in the format `YYYY-MM-DD`.
+
+Command Type: [Schedule Command](#command-type)
+
+Example:
+- `unschedule 91860934 2024-04-01` Removes the person with the phone number 91860934 from the schedule on 1st April 2024.
+
+|  |
+|--------------------------------------------------------------------|
+| *Example result panel display for a successful unschedule command* |
+
+***
+
+
+
### Saving the data
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+FnBuddy data is stored in the hard disk automatically after any command that changes the data. Rest assured, there is no need to save manually.
+
+#### Modifying saved data
+
+⚠️ **For advanced users only!**
+
+You may edit the JSON files directly in the data folder if you wish to make changes to the data without using the app. However,
+if the JSON files are no longer in the correct format, the app may not be able to read the data correctly and may crash or have unexpected behaviour.
+
+If you still wish to edit the JSON files, for the schedule.json file, note that there are additional constraints you must follow aside from the format:
+
+- The contact in the schedule must exist in the main list of contacts i.e. you should not add a new contact that does not exist, in the schedule.json file.
+- There should not be duplicate entries for the same contact on the same date.
+- There should not be duplicate entries for the same date.
+
+
+
+## Known Issues
+
+1. When using multiple screens, if you move the application to a secondary screen and later switch to using only the primary screen, the GUI will open off-screen. The remedy is to delete the `preferences.json` file created by the application before running the application again.
+ a. Alternatively, for Windows users, you can press Shift and right-click the program icon on the taskbar, Select Move, and use your left or right arrow keys to move the window until the window appears.
+2. The same feedback message 'listed all employees' produced by the application when the list commands (`list all`, `list main`, `list archive`) are inputted is used. The current universal feedback message does not provide the user with enough information about which list they are viewing.
+ There is currently no remedy for this flaw, and it is set to be a future enhancement.
+3. The `schedule` and `payroll` feature currently lets you schedule and calculate payroll for employees who are not in the main list of contacts. There is no current remedy for this flaw apart from you as a user being mindful of not scheduling an archived contact.
+4. The `payroll` feature currently calculates the payroll based on the pay rate of each employee and assumes that each shift is 8 hours. This may not be accurate for all employees, especially if they work different hours or have different pay rates.
+5. The `payroll` feature currently accepts invalid date ranges, such as end dates that are before the start date. This may lead to incorrect payroll calculations. There is no current remedy for this flaw apart from you as a user being mindful of the date ranges you input.
+
+
+
+## Planned Enhancements
+
+### Adding a `view` feature
+
+- In order to cater to the user's preference of a command line interface, we will be adding a `view` feature that will
+ allow users to view all the details of a contact without having to click on the contact card in the GUI, which is the
+ current only way to access all the details of a contact.
+
+### Enhancements to Archive Feature
+
+- Making the archive status of each person visible to the user on each contact card. This is to improve the usability of the archive feature and
+ add more differentiation to archived and unarchived contacts, which is currently only differentiated by which list (list main OR list archive) they are viewing.
+
+### More Informative List Command Feedback
-### Editing the data file
+- To provide more informative feedback to the user when they use the list command, we will be updating the feedback messages to display the list type that the user is currently viewing. This will help the user to know which list they are currently viewing, as the current feedback message is the same for all list commands.
-AddressBook data are saved automatically as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+### Stricter Validations for Schedule and Payroll Features
-
:exclamation: **Caution:**
-If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it.
-Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside of the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
-
+- To prevent users from scheduling or calculating payroll for contacts that are supposed to be archived, we will be adding validation checks to ensure that only contacts in the main list can be scheduled or used for payroll calculations.
+- To ensure that only valid date ranges are used for payroll calculations, we will be adding validation checks to ensure that the start date is before the end date.
-### Archiving data files `[coming in v2.0]`
+### Enhanced Flexibility for Schedule Feature
-_Details coming soon ..._
+- Currently, the application calendar only allows users to view the next real time four weeks, without the option to toggle to the previous or next months. We will be adding the ability to toggle between months to
+allow users to view and schedule employees for any date in the future. This will also allow users more flexibility with the scheduling feature.
---------------------------------------------------------------------------------------------------------------------
+- In order to cater to employees having differing shift hours, we will be adding the ability to input and modify the number of hours worked by each employee during a shift. This will allow for more accurate payroll calculations and better tracking of employee work hours as compared to the current restricted 8 hours per shift assumption.
+
+### Separating Multiple Tags
+
+- Currently, when multiple tags are added to a contact, they are displayed as a single string. We will be improving the tag interface to allow for better visualisation of tags in the future.
+
+
+
+## Glossary
+
+- **CLI** - Command Line Interface
+ - A text-based interface used to interact with software applications. In the context of this application, the
+ CLI is used to input commands to manage employee contacts. You can type commands into the command box as shown
+ below.
+
+ |  |
+ |--------------------------------------|
+ | *Command Box used to input commands* |
+
+
+
+- **GUI** - Graphical User Interface
+ - A visual interface that allows users to interact with software applications using graphical elements such as
+ windows, buttons, and icons. In the context of this application, the GUI provides a visual representation of
+ the employee contacts and allows users to interact with the application using buttons and text fields. However,
+ our GUI is not as feature-rich as traditional GUI applications and is designed to be used in conjunction with
+ the CLI to provide the full functionality of the application.
+
+ |  |
+ |-------------------------------------------------------|
+ | _How the app displays information in the FnBuddy GUI_ |
+
+- **FnBuddy** - The name of the application
+- **Employee** - A person who works part-time at a restaurant
+- **Contact** - A record of an employee in FnBuddy
+- **Payroll** - The total amount of money paid to employees for their work
+
+
## FAQ
-**Q**: How do I transfer my data to another Computer?
-**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous AddressBook home folder.
+- **Q: What is Java 11?**
+ - A: Java 11 is a release of the [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) programming language and runtime environment. In the context of FnBuddy,
+ Java 11 is required to be able to run the fnbuddy.jar program that launches the application. For installation
+ instructions, refer to this [guide](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-microsoft-windows-platforms.html#GUID-A7E27B90-A28D-4237-9383-A58B416071CA)
+ to install the Java Development Kit (JDK) for Java 11.
+
+- **Q: How is FnBuddy’s data stored?**
+ - A: FnBuddy stores its data in local files on your computer (JSON format).
+
+- **Q: I prefer clicking buttons to navigate applications. Will FnBuddy be upgrading its GUI to be friendlier to such users?**
+
+ - A: As FnBuddy is purposefully targeted towards users who prefer typing, there are currently no plans to add features that support GUI interactions to replace the command-line style of the app.
+
+- **Q: Is there any quick referral in the app itself for commands that I forget?**
+
+ - A: Click on the help button at the top left of the application’s window for a commands list dropdown.
+
+- **Q: Can I list down an employee with more than 2 names?**
+
+ - A: As FnBuddy only supports the `FIRST_NAME` `LAST_NAME` format, the best solution currently is to list the middle name with either the first or the last. Example: Chua Xun Hao can be saved as `-fn Xun Hao -ln Chua`.
+
+- **Q: My employee uses a foreign phone number, how can that be reflected in the app?**
+
+ - A: FnBuddy does not currently support phone number region differentiation and only supports 8-digit inputs after the `-p` flag. In future updates, we will add contact regions as a feature.
+
+- **Q: Do I need to provide all the details of an employee when creating the contact?**
+ - A: No, optional details do not need to be added and can be edited into the contact later on if required. Refer to the add contact feature to view which details are compulsory and optional.
---------------------------------------------------------------------------------------------------------------------
+- **Q: Can I modify the hours worked of my staff?**
+ - A: Currently, the hours worked by an employee are calculated based on the schedule. In future updates, we will
+ add a feature to allow users to modify the hours worked by an employee, you can see more in [Planned
+ Enhancements](#Planned-Enhancements).
-## Known issues
+- **Q: I have an archived contact, but I can't find it in the main list. How do I unarchive it?**
+ - A: Use the `list archive` command to view all archived contacts. From there, you can unarchive the contact by using the `unarchive` command. You may also use the `list all` command to view all contacts, including archived ones.
-1. **When using multiple screens**, if you move the application to a secondary screen, and later switch to using only the primary screen, the GUI will open off-screen. The remedy is to delete the `preferences.json` file created by the application before running the application again.
+- **Q: I have a contact for John Doe in the main list, and a contact for another John Doe in the archive list. How do I differentiate between the two?**
+ - A: Currently, the only way to differentiate between the two contacts is by viewing the list they are in, as well as clicking on them to expand their details card. We are planning to add a feature that will display the archive status of each contact on the contact card to make it easier to differentiate between archived and unarchived contacts in future versions.
---------------------------------------------------------------------------------------------------------------------
+
## Command summary
-Action | Format, Examples
---------|------------------
-**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…` e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague`
-**Clear** | `clear`
-**Delete** | `delete INDEX` e.g., `delete 3`
-**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…` e.g.,`edit 2 n/James Lee e/jameslee@example.com`
-**Find** | `find KEYWORD [MORE_KEYWORDS]` e.g., `find James Jake`
-**List** | `list`
-**Help** | `help`
+Here's the updated table with the new features added:
+
+| Command | Description | Format | Examples |
+|-------------------------------|------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Adding a person** | Adds a person's contact to FnBuddy. | `add -fn FIRST_NAME -ln LAST_NAME -p PHONE_NUMBER -s SEX -pr PAY_RATE -a ADDRESS [-b BANK_DETAILS] [-t TAG]...` | `add -fn John -ln Doe -p 91860934 -s m -pr 20.50 -a 123 Main St City` `add -fn Jane -ln Smith -p 98765432 -s f -pr 25.50 -a 432 Orchard Road -b posb 123456789 -t waiter -t bartender` |
+| **Listing all persons** | Shows a list of all persons in FnBuddy. | `list LIST_TYPE` | 1. `list all` 2. `list archive` 3. `list main` |
+| **Deleting a person** | Deletes the specified person from FnBuddy. | `delete PHONE_NUMBER` | `delete 91860934` |
+| **Editing a person** | Edits an existing person in FnBuddy. | `edit PHONE_NUMBER [-fn FIRST_NAME] [-ln LAST_NAME] [-p PHONE_NUMBER] [-s SEX] [-pr PAY_RATE] [-a ADDRESS] [-b BANK_DETAILS] [-t TAG]...` | `edit 91860934 -a Room 504 Marina Bay Sands -pr 25` `edit 98765432 -t ` |
+| **Locating a person by name** | Finds persons whose names match any of the given keywords. | `find KEYWORD [MORE_KEYWORDS]` | `find john tan` |
+| **Clear all contacts** | Delete all employee contacts. | `clear` | - |
+| **Exiting the program** | Exits the program. | `exit` | - |
+| **Archiving a person** | Archives the person's contact so that it is hidden from the main list of contacts. | `archive PHONE_NUMBER` | `archive 91860934` |
+| **Un-archiving a person** | Un-archives the person's contact so that it is shown in the main list of contacts. | `unarchive PHONE_NUMBER` | `unarchive 91860934` |
+| **Retrieving payroll** | Retrieve employee's payroll for a given start and end date. | `payroll -sd START_DATE -ed END_DATE` | `payroll -sd 2024-04-01 -ed 2024-04-30` |
+| **Schedule employees** | Adds a person in FnBuddy to the schedule on a specified date. | `schedule PHONE_NUMBER DATE` | `schedule 91860934 2024-04-01` |
+| **Unschedule employees** | Removes a person in FnBuddy from the schedule on a specified date. | `unschedule PHONE_NUMBER DATE` | `unschedule 91860934 2024-04-01` |
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..e63849675e9 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "FnBuddy"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2324S2-CS2103T-T17-4/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index 48b6cc4333c..2f575d2f0a0 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -8,10 +8,10 @@ Participant ":Logic" as logic LOGIC_COLOR
Participant ":Model" as model MODEL_COLOR
Participant ":Storage" as storage STORAGE_COLOR
-user -[USER_COLOR]> ui : "delete 1"
+user -[USER_COLOR]> ui : "delete 98765432"
activate ui UI_COLOR
-ui -[UI_COLOR]> logic : execute("delete 1")
+ui -[UI_COLOR]> logic : execute("delete 98765432")
activate logic LOGIC_COLOR
logic -[LOGIC_COLOR]> model : deletePerson(p)
diff --git a/docs/diagrams/ArchiveSequenceDiagram.puml b/docs/diagrams/ArchiveSequenceDiagram.puml
new file mode 100644
index 00000000000..d5acf341921
--- /dev/null
+++ b/docs/diagrams/ArchiveSequenceDiagram.puml
@@ -0,0 +1,86 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":ArchiveCommandParser" as ArchiveCommandParser LOGIC_COLOR
+participant "a:ArchiveCommand" as ArchiveCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+participant "p1:Person" as Person1 MODEL_COLOR
+participant "p2:Person" as Person2 MODEL_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("archive 98765432")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("archive 98765432")
+activate AddressBookParser
+
+create ArchiveCommandParser
+AddressBookParser -> ArchiveCommandParser
+activate ArchiveCommandParser
+
+ArchiveCommandParser --> AddressBookParser
+deactivate ArchiveCommandParser
+
+AddressBookParser -> ArchiveCommandParser : parse("98765432")
+activate ArchiveCommandParser
+
+create ArchiveCommand
+ArchiveCommandParser -> ArchiveCommand
+activate ArchiveCommand
+
+ArchiveCommand --> ArchiveCommandParser :
+deactivate ArchiveCommand
+
+ArchiveCommandParser --> AddressBookParser : a
+deactivate ArchiveCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+ArchiveCommandParser -[hidden]-> AddressBookParser
+destroy ArchiveCommandParser
+
+AddressBookParser --> LogicManager : a
+deactivate AddressBookParser
+
+LogicManager -> ArchiveCommand : execute(m)
+activate ArchiveCommand
+
+create Person1
+ArchiveCommand -> Person1
+activate Person1
+
+Person1 --> ArchiveCommand
+deactivate Person1
+
+create Person2
+ArchiveCommand -> Person2 : createArchivedPerson("p1:Person")
+activate Person2
+
+Person2 --> ArchiveCommand
+deactivate Person2
+
+ArchiveCommand -> Model : archivePerson("p1:Person", "p2:Person")
+activate Model
+
+Model --> ArchiveCommand
+deactivate Model
+
+create CommandResult
+ArchiveCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ArchiveCommand
+deactivate CommandResult
+
+ArchiveCommand --> LogicManager : r
+deactivate ArchiveCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 598474a5c82..bc85397f0e1 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -14,8 +14,22 @@ UniquePersonList -right-> Person
Person -up-> "*" Tag
-Person *--> Name
+Person *--> FirstName
+Person *--> LastName
+Person *--> Sex
+Person *--> PayRate
+Person *--> BankDetails
Person *--> Phone
-Person *--> Email
Person *--> Address
+Person *--> HoursWorked
+Person *--> ArchiveStatus
+
+FirstName -[hidden]right-> LastName
+LastName -[hidden]right-> Phone
+Phone -[hidden]right-> Sex
+Sex -[hidden]right-> PayRate
+PayRate -[hidden]right-> Address
+Address -[hidden]right-> BankDetails
+BankDetails -[hidden]right-> HoursWorked
+HoursWorked -[hidden]right-> ArchiveStatus
@enduml
diff --git a/docs/diagrams/ComponentManagers.puml b/docs/diagrams/ComponentManagers.puml
index 564dd1ae32f..d39564f7d88 100644
--- a/docs/diagrams/ComponentManagers.puml
+++ b/docs/diagrams/ComponentManagers.puml
@@ -4,6 +4,11 @@ skinparam arrowThickness 1.1
skinparam arrowColor LOGIC_COLOR_T4
skinparam classBackgroundColor LOGIC_COLOR
+package Ui as UiPackage {
+Class "<>\nUi" as Ui
+Class UiManager
+}
+
package Logic as LogicPackage {
Class "<>\nLogic" as Logic
Class LogicManager
@@ -19,13 +24,12 @@ Class "<>\nStorage" as Storage
Class StorageManager
}
-Class HiddenOutside #FFFFFF
-HiddenOutside ..> Logic
-
LogicManager .up.|> Logic
ModelManager .up.|> Model
StorageManager .up.|> Storage
+UiManager .up.|> Ui
LogicManager --> Model
LogicManager --> Storage
+UiManager ..> Logic
@enduml
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 5241e79d7da..ddb849c0d6d 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -14,10 +14,10 @@ box Model MODEL_COLOR_T1
participant "m:Model" as Model MODEL_COLOR
end box
-[-> LogicManager : execute("delete 1")
+[-> LogicManager : execute("delete 98765432")
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand("delete 1")
+LogicManager -> AddressBookParser : parseCommand("delete 98765432")
activate AddressBookParser
create DeleteCommandParser
@@ -27,7 +27,7 @@ activate DeleteCommandParser
DeleteCommandParser --> AddressBookParser
deactivate DeleteCommandParser
-AddressBookParser -> DeleteCommandParser : parse("1")
+AddressBookParser -> DeleteCommandParser : parse("98765432")
activate DeleteCommandParser
create DeleteCommand
@@ -49,7 +49,7 @@ deactivate AddressBookParser
LogicManager -> DeleteCommand : execute(m)
activate DeleteCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteCommand -> Model : deletePerson(98765432)
activate Model
Model --> DeleteCommand
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 0de5673070d..99445db4bb9 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -8,17 +8,25 @@ Package Model as ModelPackage <>{
Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook
Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs
Class "<>\nModel" as Model
+Class "<>\nSchedule" as Schedule
Class AddressBook
Class ModelManager
Class UserPrefs
+Class ScheduleManager
Class UniquePersonList
Class Person
Class Address
-Class Email
-Class Name
+Class FirstName
+Class LastName
+Class BankDetails
+Class PayRate
+Class Sex
Class Phone
+Class HoursWorked
Class Tag
+Class PayrollWrapper
+Class ArchiveStatus
Class I #FFFFFF
}
@@ -27,28 +35,42 @@ Class HiddenOutside #FFFFFF
HiddenOutside ..> Model
AddressBook .up.|> ReadOnlyAddressBook
-
ModelManager .up.|> Model
Model .right.> ReadOnlyUserPrefs
Model .left.> ReadOnlyAddressBook
+Model .right.> Schedule
ModelManager -left-> "1" AddressBook
ModelManager -right-> "1" UserPrefs
+PayrollWrapper -down-> "1" Person
+ScheduleManager .up.|> Schedule
+ModelManager -down-> "1" ScheduleManager
UserPrefs .up.|> ReadOnlyUserPrefs
AddressBook *--> "1" UniquePersonList
UniquePersonList --> "~* all" Person
-Person *--> Name
+Person *--> FirstName
+Person *--> LastName
Person *--> Phone
-Person *--> Email
+Person *--> BankDetails
+Person *--> PayRate
+Person *--> Sex
Person *--> Address
+Person *--> HoursWorked
+Person *--> ArchiveStatus
Person *--> "*" Tag
Person -[hidden]up--> I
-UniquePersonList -[hidden]right-> I
+UniquePersonList -[hidden]left-> I
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
+FirstName -[hidden]right-> LastName
+LastName -[hidden]right-> Phone
+Phone -[hidden]right-> Sex
+Sex -[hidden]right-> PayRate
+PayRate -[hidden]right-> Address
+Address -[hidden]right-> BankDetails
+BankDetails -[hidden]right-> HoursWorked
+HoursWorked -[hidden]right-> ArchiveStatus
ModelManager --> "~* filtered" Person
+ModelManager --> "~* filtered" PayrollWrapper
@enduml
diff --git a/docs/diagrams/ScheduleSequenceDiagram.puml b/docs/diagrams/ScheduleSequenceDiagram.puml
new file mode 100644
index 00000000000..6ccedb8e374
--- /dev/null
+++ b/docs/diagrams/ScheduleSequenceDiagram.puml
@@ -0,0 +1,76 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":ScheduleCommandParser" as ScheduleCommandParser LOGIC_COLOR
+participant "a:ScheduleCommand" as ScheduleCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("schedule 98765432 2024-04-15")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("schedule 98765432 2024-04-15")
+activate AddressBookParser
+
+create ScheduleCommandParser
+AddressBookParser -> ScheduleCommandParser
+activate ScheduleCommandParser
+
+ScheduleCommandParser --> AddressBookParser
+deactivate ScheduleCommandParser
+
+AddressBookParser -> ScheduleCommandParser : parse("98765432 2024-04-15")
+activate ScheduleCommandParser
+
+create ScheduleCommand
+ScheduleCommandParser -> ScheduleCommand
+activate ScheduleCommand
+
+ScheduleCommand --> ScheduleCommandParser :
+deactivate ScheduleCommand
+
+ScheduleCommandParser --> AddressBookParser : a
+deactivate ScheduleCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+ScheduleCommandParser -[hidden]-> AddressBookParser
+destroy ScheduleCommandParser
+
+AddressBookParser --> LogicManager : a
+deactivate AddressBookParser
+
+LogicManager -> ScheduleCommand : execute(m)
+activate ScheduleCommand
+
+ScheduleCommand -> Model : getPersonByPhoneNumber("98765432")
+activate Model
+
+Model --> ScheduleCommand : p1
+deactivate Model
+
+ScheduleCommand -> Model : addPersonToSchedule(p1, "2024-04-15")
+activate Model
+
+Model --> ScheduleCommand
+deactivate Model
+
+create CommandResult
+ScheduleCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ScheduleCommand
+deactivate CommandResult
+
+ScheduleCommand --> LogicManager : r
+deactivate ScheduleCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index a821e06458c..7c34701758d 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -22,14 +22,22 @@ Class JsonAdaptedPerson
Class JsonAdaptedTag
}
+package "Schedule Storage" #F4F6F6{
+Class "<>\nScheduleStorage" as ScheduleStorage
+Class JsonScheduleStorage
+Class JsonSerializableSchedule
+Class JsonAdaptedScheduleDate
+}
+
}
Class HiddenOutside #FFFFFF
HiddenOutside ..> Storage
StorageManager .up.|> Storage
-StorageManager -up-> "1" UserPrefsStorage
-StorageManager -up-> "1" AddressBookStorage
+StorageManager -down-> "1" UserPrefsStorage
+StorageManager -down-> "1" AddressBookStorage
+StorageManager -down-> "1" ScheduleStorage
Storage -left-|> UserPrefsStorage
Storage -right-|> AddressBookStorage
@@ -40,4 +48,9 @@ JsonAddressBookStorage ..> JsonSerializableAddressBook
JsonSerializableAddressBook --> "*" JsonAdaptedPerson
JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonScheduleStorage .up.|> ScheduleStorage
+JsonScheduleStorage ..> JsonSerializableSchedule
+JsonSerializableSchedule --> "*" JsonAdaptedScheduleDate
+JsonAdaptedScheduleDate --> "*" JsonAdaptedPerson
+
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..f3133d44f28 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -15,6 +15,9 @@ Class PersonListPanel
Class PersonCard
Class StatusBarFooter
Class CommandBox
+Class Calendar
+Class PayrollListPanel
+Class PayrollCard
}
package Model <> {
@@ -32,22 +35,29 @@ UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
MainWindow *-down-> "1" CommandBox
MainWindow *-down-> "1" ResultDisplay
-MainWindow *-down-> "1" PersonListPanel
+MainWindow *-down-> "0..1" PersonListPanel
+MainWindow *-down-> "0..1" PayrollListPanel
+MainWindow *-down-> "0..1" Calendar
MainWindow *-down-> "1" StatusBarFooter
MainWindow --> "0..1" HelpWindow
PersonListPanel -down-> "*" PersonCard
+PayrollListPanel -down-> "*" PayrollCard
MainWindow -left-|> UiPart
ResultDisplay --|> UiPart
CommandBox --|> UiPart
PersonListPanel --|> UiPart
+PayrollCard --|> UiPart
+PayrollListPanel --|> UiPart
PersonCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
PersonCard ..> Model
+PayrollCard ..> Model
+Calendar ..> Model
UiManager -right-> Logic
MainWindow -left-> Logic
diff --git a/docs/images/1rbg.png b/docs/images/1rbg.png
new file mode 100644
index 00000000000..88deafeb620
Binary files /dev/null and b/docs/images/1rbg.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 37ad06a2803..121220ed723 100644
Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/ArchiveSequenceDiagram.png b/docs/images/ArchiveSequenceDiagram.png
new file mode 100644
index 00000000000..b3fdd9f70b6
Binary files /dev/null and b/docs/images/ArchiveSequenceDiagram.png differ
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
index 02a42e35e76..406e0d2ffbd 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/CommandBox.png b/docs/images/CommandBox.png
new file mode 100644
index 00000000000..08a45c71d2c
Binary files /dev/null and b/docs/images/CommandBox.png differ
diff --git a/docs/images/ComponentManagers.png b/docs/images/ComponentManagers.png
index ae52a35718a..8a99dc1bf63 100644
Binary files a/docs/images/ComponentManagers.png and b/docs/images/ComponentManagers.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index ac2ae217c51..fa4ebd13ca8 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/Find_UI.png b/docs/images/Find_UI.png
new file mode 100644
index 00000000000..31239e90aa6
Binary files /dev/null and b/docs/images/Find_UI.png differ
diff --git a/docs/images/LabelledUi.png b/docs/images/LabelledUi.png
new file mode 100644
index 00000000000..ded70e751f4
Binary files /dev/null and b/docs/images/LabelledUi.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index a19fb1b4ac8..705a348706e 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/PayrollPageSuccess.png b/docs/images/PayrollPageSuccess.png
new file mode 100644
index 00000000000..5aa7cf86eb3
Binary files /dev/null and b/docs/images/PayrollPageSuccess.png differ
diff --git a/docs/images/Sample_UI.jpg b/docs/images/Sample_UI.jpg
new file mode 100644
index 00000000000..c1d31359f70
Binary files /dev/null and b/docs/images/Sample_UI.jpg differ
diff --git a/docs/images/SchedulePage.png b/docs/images/SchedulePage.png
new file mode 100644
index 00000000000..15a56e7258f
Binary files /dev/null and b/docs/images/SchedulePage.png differ
diff --git a/docs/images/SchedulePageSuccess.png b/docs/images/SchedulePageSuccess.png
new file mode 100644
index 00000000000..c763a1615b6
Binary files /dev/null and b/docs/images/SchedulePageSuccess.png differ
diff --git a/docs/images/ScheduleSequenceDiagram.png b/docs/images/ScheduleSequenceDiagram.png
new file mode 100644
index 00000000000..01692558abe
Binary files /dev/null and b/docs/images/ScheduleSequenceDiagram.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 18fa4d0d51f..56db17a6d05 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/Terminal.png b/docs/images/Terminal.png
new file mode 100644
index 00000000000..988f7709564
Binary files /dev/null and b/docs/images/Terminal.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..072c1778c1a 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 11f06d68671..d04d152ae97 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/UnschedulePageSuccess.png b/docs/images/UnschedulePageSuccess.png
new file mode 100644
index 00000000000..fd553c93267
Binary files /dev/null and b/docs/images/UnschedulePageSuccess.png differ
diff --git a/docs/images/h4ow3i.png b/docs/images/h4ow3i.png
new file mode 100644
index 00000000000..a498a8d29a8
Binary files /dev/null and b/docs/images/h4ow3i.png differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
index b1f70470137..d70de5b5fbf 100644
Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ
diff --git a/docs/images/huekoh.png b/docs/images/huekoh.png
new file mode 100644
index 00000000000..8015e66dd16
Binary files /dev/null and b/docs/images/huekoh.png differ
diff --git a/docs/images/jxunze.png b/docs/images/jxunze.png
new file mode 100644
index 00000000000..9ce12b6122c
Binary files /dev/null and b/docs/images/jxunze.png differ
diff --git a/docs/images/listall_screenshot.png b/docs/images/listall_screenshot.png
new file mode 100644
index 00000000000..53bf4c062cb
Binary files /dev/null and b/docs/images/listall_screenshot.png differ
diff --git a/docs/images/listarchive_screenshot.png b/docs/images/listarchive_screenshot.png
new file mode 100644
index 00000000000..3969ebfc6cb
Binary files /dev/null and b/docs/images/listarchive_screenshot.png differ
diff --git a/docs/images/listmain_screenshot.png b/docs/images/listmain_screenshot.png
new file mode 100644
index 00000000000..d3d2cf83769
Binary files /dev/null and b/docs/images/listmain_screenshot.png differ
diff --git a/docs/images/martinng01.png b/docs/images/martinng01.png
new file mode 100644
index 00000000000..7a1be811774
Binary files /dev/null and b/docs/images/martinng01.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..0d3d0d04f3e 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,17 +1,24 @@
---
layout: page
-title: AddressBook Level-3
+title: FnBuddy
---
-[](https://github.com/se-edu/addressbook-level3/actions)
-[](https://codecov.io/gh/se-edu/addressbook-level3)
+[](https://github.com/AY2324S2-CS2103T-T17-4/tp/actions)
+[](https://codecov.io/gh/AY2324S2-CS2103T-T17-4/tp)
+

-**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+**FnBuddy is an innovative employee contact management application designed specifically for restaurant managers.**
+It offers a user-friendly interface (both CLI and GUI) that allows you to effortlessly create, manage,
+and maintain contact records for all your part-time employees. With FnBuddy, you can store essential information such as
+contact details, banking information, and work schedules, ensuring efficient communication and accurate payroll
+calculations.
-* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
-* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
+* If you are interested in using FnBuddy, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.
+ html#quick-start).
+* If you are interested about developing FnBuddy, the [**Developer Guide**](DeveloperGuide.html) is a good place to
+ start.
**Acknowledgements**
diff --git a/docs/team/gabrielchua.md b/docs/team/gabrielchua.md
new file mode 100644
index 00000000000..3a224b92e12
--- /dev/null
+++ b/docs/team/gabrielchua.md
@@ -0,0 +1,46 @@
+---
+layout: page
+title: Gabriel Chua's Project Portfolio Page
+---
+
+### Project: AddressBook Level 3
+
+AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. 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.
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added the ability to undo/redo previous commands.
+ * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.
+ * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.
+ * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.
+ * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
+
+* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
+
+* **Code contributed**: [RepoSense link]()
+
+* **Project management**:
+ * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
+
+* **Enhancements to existing features**:
+ * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
+ * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]())
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `delete` and `find` [\#72]()
+ * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
+ * Developer Guide:
+ * Added implementation details of the `delete` feature.
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
+ * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
+ * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
+ * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
+
+* **Tools**:
+ * Integrated a third party library (Natty) to the project ([\#42]())
+ * Integrated a new Github plugin (CircleCI) to the team repo
+
+* _{you can add/remove categories in the list above}_
diff --git a/docs/team/huekoh.md b/docs/team/huekoh.md
new file mode 100644
index 00000000000..92ef34a6ee1
--- /dev/null
+++ b/docs/team/huekoh.md
@@ -0,0 +1,46 @@
+---
+layout: page
+title: Hue Koh's Project Portfolio Page
+---
+
+### Project: FnBuddy
+
+AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. 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.
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added the ability to undo/redo previous commands.
+ * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.
+ * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.
+ * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.
+ * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
+
+* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
+
+* **Code contributed**: [RepoSense link]()
+
+* **Project management**:
+ * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
+
+* **Enhancements to existing features**:
+ * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
+ * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]())
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `delete` and `find` [\#72]()
+ * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
+ * Developer Guide:
+ * Added implementation details of the `delete` feature.
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
+ * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
+ * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
+ * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
+
+* **Tools**:
+ * Integrated a third party library (Natty) to the project ([\#42]())
+ * Integrated a new Github plugin (CircleCI) to the team repo
+
+* _{you can add/remove categories in the list above}_
diff --git a/docs/team/johndoe.md b/docs/team/jinxunze.md
similarity index 98%
rename from docs/team/johndoe.md
rename to docs/team/jinxunze.md
index 773a07794e2..be38dc7f9d8 100644
--- a/docs/team/johndoe.md
+++ b/docs/team/jinxunze.md
@@ -1,6 +1,6 @@
---
layout: page
-title: John Doe's Project Portfolio Page
+title: Jin Xunze's Project Portfolio Page
---
### Project: AddressBook Level 3
diff --git a/docs/team/martinng.md b/docs/team/martinng.md
new file mode 100644
index 00000000000..23b06ff28ad
--- /dev/null
+++ b/docs/team/martinng.md
@@ -0,0 +1,53 @@
+---
+layout: page
+title: Martin Ng's Project Portfolio Page
+---
+
+### Project: AddressBook Level 3
+
+AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. 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.
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added the ability to undo/redo previous commands.
+ * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed
+ by using the redo command.
+ * Justification: This feature improves the product significantly because a user can make mistakes in commands and
+ the app should provide a convenient way to rectify them.
+ * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth
+ analysis of design alternatives. The implementation too was challenging as it required changes to existing
+ commands.
+ * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in
+ the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
+
+* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
+
+* **Code contributed**: [RepoSense link]()
+
+* **Project management**:
+ * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
+
+* **Enhancements to existing features**:
+ * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
+ * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull
+ requests [\#36](), [\#38]())
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `delete` and `find` [\#72]()
+ * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
+ * Developer Guide:
+ * Added implementation details of the `delete` feature.
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
+ * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
+ * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
+ * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
+
+* **Tools**:
+ * Integrated a third party library (Natty) to the project ([\#42]())
+ * Integrated a new Github plugin (CircleCI) to the team repo
+
+* _{you can add/remove categories in the list above}_
diff --git a/docs/team/teohaowei.md b/docs/team/teohaowei.md
new file mode 100644
index 00000000000..cd8a27774ff
--- /dev/null
+++ b/docs/team/teohaowei.md
@@ -0,0 +1,46 @@
+---
+layout: page
+title: Teo Hao Wei's Project Portfolio Page
+---
+
+### Project: FnBuddy
+
+AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. 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.
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added the ability to undo/redo previous commands.
+ * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.
+ * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.
+ * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.
+ * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
+
+* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
+
+* **Code contributed**: [RepoSense link]()
+
+* **Project management**:
+ * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
+
+* **Enhancements to existing features**:
+ * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
+ * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]())
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `delete` and `find` [\#72]()
+ * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
+ * Developer Guide:
+ * Added implementation details of the `delete` feature.
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
+ * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
+ * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
+ * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
+
+* **Tools**:
+ * Integrated a third party library (Natty) to the project ([\#42]())
+ * Integrated a new Github plugin (CircleCI) to the team repo
+
+* _{you can add/remove categories in the list above}_
diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/seedu/address/Main.java
index ec1b7958746..f14473af111 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/seedu/address/Main.java
@@ -7,17 +7,17 @@
/**
* The main entry point to the application.
- *
+ *
* This is a workaround for the following error when MainApp is made the
* entry point of the application:
- *
- * Error: JavaFX runtime components are missing, and are required to run this application
- *
+ *
+ * Error: JavaFX runtime components are missing, and are required to run this application
+ *
* The reason is that MainApp extends Application. In that case, the
* LauncherHelper will check for the javafx.graphics module to be present
* as a named module. We don't use JavaFX via the module system so it can't
* find the javafx.graphics module, and so the launch is aborted.
- *
+ *
* By having a separate main class (Main) that doesn't extend Application
* to be the entry point of the application, we avoid this issue.
*/
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java
index 3d6bd06d5af..c3f7a40444c 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/address/MainApp.java
@@ -21,10 +21,14 @@
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleManager;
import seedu.address.model.util.SampleDataUtil;
import seedu.address.storage.AddressBookStorage;
import seedu.address.storage.JsonAddressBookStorage;
+import seedu.address.storage.JsonScheduleStorage;
import seedu.address.storage.JsonUserPrefsStorage;
+import seedu.address.storage.ScheduleStorage;
import seedu.address.storage.Storage;
import seedu.address.storage.StorageManager;
import seedu.address.storage.UserPrefsStorage;
@@ -36,7 +40,7 @@
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 2, true);
+ public static final Version VERSION = new Version(1, 2, 1, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -48,7 +52,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing FnBuddy ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -58,7 +62,8 @@ public void init() throws Exception {
UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath());
UserPrefs userPrefs = initPrefs(userPrefsStorage);
AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath());
- storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ ScheduleStorage scheduleStorage = new JsonScheduleStorage(userPrefs.getScheduleFilePath());
+ storage = new StorageManager(addressBookStorage, userPrefsStorage, scheduleStorage);
model = initModelManager(storage, userPrefs);
@@ -76,21 +81,35 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
logger.info("Using data file : " + storage.getAddressBookFilePath());
Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ ReadOnlyAddressBook abInitialData;
try {
addressBookOptional = storage.readAddressBook();
if (!addressBookOptional.isPresent()) {
logger.info("Creating a new data file " + storage.getAddressBookFilePath()
- + " populated with a sample AddressBook.");
+ + " populated with a sample AddressBook.");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ abInitialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
} catch (DataLoadingException e) {
logger.warning("Data file at " + storage.getAddressBookFilePath() + " could not be loaded."
+ " Will be starting with an empty AddressBook.");
- initialData = new AddressBook();
+ abInitialData = new AddressBook();
+ }
+ Optional scheduleOptional;
+ Schedule scheduleInitialData;
+ try {
+ scheduleOptional = storage.readSchedule();
+ if (!scheduleOptional.isPresent()) {
+ logger.info("Creating a new data file " + storage.getScheduleFilePath()
+ + " populated with a sample Schedule.");
+ }
+ scheduleInitialData = scheduleOptional.orElseGet(SampleDataUtil::getSampleSchedule);
+ } catch (DataLoadingException e) {
+ logger.warning("Data file at " + storage.getScheduleFilePath() + " could not be loaded."
+ + " Will be starting with an empty Schedule.");
+ scheduleInitialData = new ScheduleManager();
}
- return new ModelManager(initialData, userPrefs);
+ return new ModelManager(abInitialData, userPrefs, scheduleInitialData);
}
private void initLogging(Config config) {
@@ -123,7 +142,7 @@ protected Config initConfig(Path configFilePath) {
initializedConfig = configOptional.orElse(new Config());
} catch (DataLoadingException e) {
logger.warning("Config file at " + configFilePathUsed + " could not be loaded."
- + " Using default config properties.");
+ + " Using default config properties.");
initializedConfig = new Config();
}
@@ -154,7 +173,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
initializedPrefs = prefsOptional.orElse(new UserPrefs());
} catch (DataLoadingException e) {
logger.warning("Preference file at " + prefsFilePath + " could not be loaded."
- + " Using default preferences.");
+ + " Using default preferences.");
initializedPrefs = new UserPrefs();
}
@@ -176,7 +195,7 @@ public void start(Stage primaryStage) {
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping FnBuddy ] =============================");
try {
storage.saveUserPrefs(model.getUserPrefs());
} catch (IOException e) {
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/address/commons/core/GuiSettings.java
index a97a86ee8d7..56286d22adf 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/address/commons/core/GuiSettings.java
@@ -12,8 +12,8 @@
*/
public class GuiSettings implements Serializable {
- private static final double DEFAULT_HEIGHT = 600;
- private static final double DEFAULT_WIDTH = 740;
+ private static final double DEFAULT_HEIGHT = 420;
+ private static final double DEFAULT_WIDTH = 650;
private final double windowWidth;
private final double windowHeight;
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/address/commons/core/LogsCenter.java
index 8cf8e15a0f0..60bf6145139 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/address/commons/core/LogsCenter.java
@@ -102,5 +102,4 @@ private static void setBaseLogger() {
}
}
-
}
diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/address/commons/util/JsonUtil.java
index 100cb16c395..927723785a5 100644
--- a/src/main/java/seedu/address/commons/util/JsonUtil.java
+++ b/src/main/java/seedu/address/commons/util/JsonUtil.java
@@ -31,20 +31,19 @@ public class JsonUtil {
private static final Logger logger = LogsCenter.getLogger(JsonUtil.class);
private static ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules()
- .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
- .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
- .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
- .registerModule(new SimpleModule("SimpleModule")
- .addSerializer(Level.class, new ToStringSerializer())
- .addDeserializer(Level.class, new LevelDeserializer(Level.class)));
+ .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
+ .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
+ .registerModule(new SimpleModule("SimpleModule")
+ .addSerializer(Level.class, new ToStringSerializer())
+ .addDeserializer(Level.class, new LevelDeserializer(Level.class)));
static void serializeObjectToJsonFile(Path jsonFile, T objectToSerialize) throws IOException {
FileUtil.writeToFile(jsonFile, toJsonString(objectToSerialize));
}
- static T deserializeObjectFromJsonFile(Path jsonFile, Class classOfObjectToDeserialize)
- throws IOException {
+ static T deserializeObjectFromJsonFile(Path jsonFile, Class classOfObjectToDeserialize) throws IOException {
return fromJsonString(FileUtil.readFromFile(jsonFile), classOfObjectToDeserialize);
}
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
index 92cd8fa605a..aee05ca26a6 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/address/logic/Logic.java
@@ -1,6 +1,7 @@
package seedu.address.logic;
import java.nio.file.Path;
+import java.util.Set;
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
@@ -8,7 +9,9 @@
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.person.PayrollWrapper;
import seedu.address.model.person.Person;
+import seedu.address.model.schedule.ScheduleDate;
/**
* API of the Logic component
@@ -30,9 +33,17 @@ public interface Logic {
*/
ReadOnlyAddressBook getAddressBook();
+ Set getScheduleDates();
+
/** Returns an unmodifiable view of the filtered list of persons */
ObservableList getFilteredPersonList();
+ /** Returns an unmodifiable view of the list of payrolls */
+ ObservableList getPayrollList();
+
+ /** Returns an unmodifiable view of the list of unarchived persons */
+ ObservableList getFilteredUnarchivedPersonList();
+
/**
* Returns the user prefs' address book file path.
*/
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
index 5aa3b91c7d0..044b033b995 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/address/logic/LogicManager.java
@@ -3,6 +3,7 @@
import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.nio.file.Path;
+import java.util.Set;
import java.util.logging.Logger;
import javafx.collections.ObservableList;
@@ -15,7 +16,9 @@
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.person.PayrollWrapper;
import seedu.address.model.person.Person;
+import seedu.address.model.schedule.ScheduleDate;
import seedu.address.storage.Storage;
/**
@@ -52,6 +55,7 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
try {
storage.saveAddressBook(model.getAddressBook());
+ storage.saveSchedule(model.getSchedule());
} catch (AccessDeniedException e) {
throw new CommandException(String.format(FILE_OPS_PERMISSION_ERROR_FORMAT, e.getMessage()), e);
} catch (IOException ioe) {
@@ -66,11 +70,26 @@ public ReadOnlyAddressBook getAddressBook() {
return model.getAddressBook();
}
+ @Override
+ public Set getScheduleDates() {
+ return model.getScheduleDates();
+ }
+
+ @Override
+ public ObservableList getPayrollList() {
+ return model.getPayrollList();
+ }
+
@Override
public ObservableList getFilteredPersonList() {
return model.getFilteredPersonList();
}
+ @Override
+ public ObservableList getFilteredUnarchivedPersonList() {
+ return model.getFilteredUnarchivedPersonList();
+ }
+
@Override
public Path getAddressBookFilePath() {
return model.getAddressBookFilePath();
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java
index ecd32c31b53..3e590de9c4f 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/seedu/address/logic/Messages.java
@@ -14,10 +14,11 @@ public class Messages {
public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
- public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
+ public static final String MESSAGE_PERSON_NOT_FOUND = "The person does not exist in the address book";
+ public static final String MESSAGE_PERSON_NOT_ARCHIVED = "The person does not exist in the archives";
public static final String MESSAGE_DUPLICATE_FIELDS =
- "Multiple values specified for the following single-valued field(s): ";
+ "Multiple values specified for the following single-valued field(s): ";
/**
* Returns an error message indicating the duplicate prefixes.
@@ -39,10 +40,14 @@ public static String format(Person person) {
builder.append(person.getName())
.append("; Phone: ")
.append(person.getPhone())
- .append("; Email: ")
- .append(person.getEmail())
+ .append("; Sex: ")
+ .append(person.getSex())
+ .append("; Pay Rate: ")
+ .append(person.getPayRate())
.append("; Address: ")
.append(person.getAddress())
+ .append("; Bank Details: ")
+ .append(person.getBankDetails())
.append("; Tags: ");
person.getTags().forEach(builder::append);
return builder.toString();
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 5d7185a9680..fb5c067abee 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -2,9 +2,12 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_BANKDETAILS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FIRSTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PAYRATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import seedu.address.commons.util.ToStringBuilder;
@@ -13,6 +16,7 @@
import seedu.address.model.Model;
import seedu.address.model.person.Person;
+
/**
* Adds a person to the address book.
*/
@@ -21,23 +25,28 @@ public class AddCommand extends Command {
public static final String COMMAND_WORD = "add";
public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. "
- + "Parameters: "
- + PREFIX_NAME + "NAME "
- + PREFIX_PHONE + "PHONE "
- + PREFIX_EMAIL + "EMAIL "
- + PREFIX_ADDRESS + "ADDRESS "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " "
- + PREFIX_NAME + "John Doe "
- + PREFIX_PHONE + "98765432 "
- + PREFIX_EMAIL + "johnd@example.com "
- + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
- + PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
+ + "Parameters: "
+ + PREFIX_FIRSTNAME + "FIRST NAME "
+ + PREFIX_LASTNAME + "LAST NAME "
+ + PREFIX_PHONE + "PHONE "
+ + PREFIX_SEX + "SEX "
+ + PREFIX_PAYRATE + "PAY RATE "
+ + PREFIX_ADDRESS + "ADDRESS "
+ + PREFIX_BANKDETAILS + "BANK DETAILS "
+ + PREFIX_TAG + "TAG\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_FIRSTNAME + "John "
+ + PREFIX_LASTNAME + "Doe "
+ + PREFIX_PHONE + "98765432 "
+ + PREFIX_SEX + "m "
+ + PREFIX_PAYRATE + "14 "
+ + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
+ + PREFIX_BANKDETAILS + "posb 123456789 "
+ + PREFIX_TAG + "owesMoney";
public static final String MESSAGE_SUCCESS = "New person added: %1$s";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
-
+ public static final String MESSAGE_DUPLICATE_PERSON = "This phone number already exists in the address book. "
+ + "Every contact must have a unique phone number.";
private final Person toAdd;
/**
@@ -78,7 +87,7 @@ public boolean equals(Object other) {
@Override
public String toString() {
return new ToStringBuilder(this)
- .add("toAdd", toAdd)
- .toString();
+ .add("toAdd", toAdd)
+ .toString();
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ArchiveCommand.java b/src/main/java/seedu/address/logic/commands/ArchiveCommand.java
new file mode 100644
index 00000000000..625da906b57
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ArchiveCommand.java
@@ -0,0 +1,113 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.commands.AddCommand.MESSAGE_DUPLICATE_PERSON;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS;
+
+import java.util.List;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.ArchiveStatus;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+
+/**
+ * Archives an employee from the contact book into the archive book.
+ */
+public class ArchiveCommand extends Command {
+
+ public static final String COMMAND_WORD = "archive";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Archives a contact. \n"
+ + "Parameters: archive [EXISTING PHONE NUMBER] \n"
+ + "Example: " + COMMAND_WORD + " 98765432";
+
+ public static final String MESSAGE_ARCHIVE_PERSON_SUCCESS = "Archived Person: %1$s";
+
+ private final Phone targetPhone;
+
+ public ArchiveCommand(Phone targetPhone) {
+ this.targetPhone = targetPhone;
+ }
+
+ /**
+ * Creates an archived person based on the person to archive.
+ *
+ * @param personToArchive Person to archive.
+ * @return Archived person.
+ */
+ private static Person createArchivedPerson(Person personToArchive) {
+ assert personToArchive != null;
+
+ ArchiveStatus updatedArchiveStatus = new ArchiveStatus(true);
+
+ return new Person(personToArchive.getFirstName(), personToArchive.getLastName(), personToArchive.getPhone(),
+ personToArchive.getSex(), personToArchive.getPayRate(), personToArchive.getAddress(),
+ personToArchive.getBankDetails(), personToArchive.getWorkHours(), personToArchive.getTags(),
+ updatedArchiveStatus);
+ }
+
+ /**
+ * Archives a person from the contact book.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return A command result that indicates the person has been archived.
+ * @throws CommandException If the person does not exist in the contact book.
+ */
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredUnarchivedPersonList();
+ boolean exists = false;
+ Person personToArchive = null;
+ for (Person person : lastShownList) {
+ if (person.getPhone().equals(targetPhone)) {
+ exists = true;
+ personToArchive = person;
+ break;
+ }
+ }
+ if (!exists) {
+ throw new CommandException(Messages.MESSAGE_PERSON_NOT_FOUND);
+ }
+
+ Person archivedPerson = createArchivedPerson(personToArchive);
+
+ if (!personToArchive.isSamePerson(archivedPerson) && model.hasPerson(archivedPerson)) {
+ throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ }
+
+ model.archivePerson(personToArchive, archivedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS);
+ return new CommandResult(String.format(MESSAGE_ARCHIVE_PERSON_SUCCESS, Messages.format(personToArchive)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ArchiveCommand)) {
+ return false;
+ }
+
+ // state check
+ ArchiveCommand e = (ArchiveCommand) other;
+ return targetPhone.equals(e.targetPhone);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("targetPhone", targetPhone)
+ .toString();
+ }
+
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
index 9c86b1fa6e4..453ad5973d3 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java
@@ -4,6 +4,7 @@
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
+import seedu.address.model.schedule.ScheduleManager;
/**
* Clears the address book.
@@ -18,6 +19,7 @@ public class ClearCommand extends Command {
public CommandResult execute(Model model) {
requireNonNull(model);
model.setAddressBook(new AddressBook());
+ model.setSchedule(new ScheduleManager());
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java
index 249b6072d0d..412fec0a704 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/address/logic/commands/CommandResult.java
@@ -19,13 +19,34 @@ public class CommandResult {
/** The application should exit. */
private final boolean exit;
+ /** The application should show contacts. */
+ private final boolean showContacts;
+
+ /** The application should show schedule. */
+ private final boolean showSchedule;
+
+ /** The application should show payroll. */
+ private final boolean showPayroll;
+
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
- public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit,
+ boolean showContacts, boolean showSchedule, boolean showPayroll) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
+ this.showContacts = showContacts;
+ this.showSchedule = showSchedule;
+ this.showPayroll = showPayroll;
+ }
+
+ /**
+ * Constructs a {@code CommandResult} with the specified {@code feedbackToUser},
+ * {@code showHelp} and {@code exit} fields, and other fields set to their default value.
+ */
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
+ this(feedbackToUser, showHelp, exit, false, false, false);
}
/**
@@ -33,7 +54,7 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser) {
- this(feedbackToUser, false, false);
+ this(feedbackToUser, false, false, true, false, false);
}
public String getFeedbackToUser() {
@@ -48,6 +69,18 @@ public boolean isExit() {
return exit;
}
+ public boolean isShowContacts() {
+ return showContacts;
+ }
+
+ public boolean isShowSchedule() {
+ return showSchedule;
+ }
+
+ public boolean isShowPayroll() {
+ return showPayroll;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -62,12 +95,14 @@ public boolean equals(Object other) {
CommandResult otherCommandResult = (CommandResult) other;
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
&& showHelp == otherCommandResult.showHelp
- && exit == otherCommandResult.exit;
+ && exit == otherCommandResult.exit
+ && showContacts == otherCommandResult.showContacts
+ && showSchedule == otherCommandResult.showSchedule;
}
@Override
public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit);
+ return Objects.hash(feedbackToUser, showHelp, exit, showContacts, showSchedule, showPayroll);
}
@Override
@@ -76,6 +111,8 @@ public String toString() {
.add("feedbackToUser", feedbackToUser)
.add("showHelp", showHelp)
.add("exit", exit)
+ .add("showContacts", showContacts)
+ .add("showSchedule", showSchedule)
.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 1135ac19b74..734180ec06b 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -4,12 +4,12 @@
import java.util.List;
-import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
/**
* Deletes a person identified using it's displayed index from the address book.
@@ -19,28 +19,34 @@ public class DeleteCommand extends Command {
public static final String COMMAND_WORD = "delete";
public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Deletes the person identified by the index number used in the displayed person list.\n"
- + "Parameters: INDEX (must be a positive integer)\n"
- + "Example: " + COMMAND_WORD + " 1";
+ + ": Deletes the person identified by the phone number.\n"
+ + "Parameters: PHONE NUMBER\n"
+ + "Example: " + COMMAND_WORD + " 89348843";
public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
- private final Index targetIndex;
+ private final Phone targetPhone;
- public DeleteCommand(Index targetIndex) {
- this.targetIndex = targetIndex;
+ public DeleteCommand(Phone targetPhone) {
+ this.targetPhone = targetPhone;
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List lastShownList = model.getFilteredPersonList();
-
- if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ boolean exists = false;
+ Person personToDelete = null;
+ for (Person person : lastShownList) {
+ if (person.getPhone().equals(targetPhone)) {
+ exists = true;
+ personToDelete = person;
+ break;
+ }
+ }
+ if (!exists) {
+ throw new CommandException(Messages.MESSAGE_PERSON_NOT_FOUND);
}
-
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
model.deletePerson(personToDelete);
return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, Messages.format(personToDelete)));
}
@@ -57,13 +63,13 @@ public boolean equals(Object other) {
}
DeleteCommand otherDeleteCommand = (DeleteCommand) other;
- return targetIndex.equals(otherDeleteCommand.targetIndex);
+ return targetPhone.equals(otherDeleteCommand.targetPhone);
}
@Override
public String toString() {
return new ToStringBuilder(this)
- .add("targetIndex", targetIndex)
+ .add("targetPhone", targetPhone.toString())
.toString();
}
}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 4b581c7331e..98778da3385 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -2,11 +2,13 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_BANKDETAILS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FIRSTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PAYRATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
import java.util.Collections;
import java.util.HashSet;
@@ -15,68 +17,104 @@
import java.util.Optional;
import java.util.Set;
-import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.CollectionUtil;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.ArchiveStatus;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
+import seedu.address.model.person.WorkHours;
import seedu.address.model.tag.Tag;
/**
* Edits the details of an existing person in the address book.
*/
public class EditCommand extends Command {
-
public static final String COMMAND_WORD = "edit";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the displayed person list. "
- + "Existing values will be overwritten by the input values.\n"
- + "Parameters: INDEX (must be a positive integer) "
- + "[" + PREFIX_NAME + "NAME] "
- + "[" + PREFIX_PHONE + "PHONE] "
- + "[" + PREFIX_EMAIL + "EMAIL] "
- + "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " 1 "
- + PREFIX_PHONE + "91234567 "
- + PREFIX_EMAIL + "johndoe@example.com";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person"
+ + " identified "
+ + "by the phone number. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: Phone number"
+ + "[" + PREFIX_PHONE + "PHONE] "
+ + "[" + PREFIX_ADDRESS + "ADDRESS] "
+ + "[" + PREFIX_TAG + "TAG] "
+ + "[" + PREFIX_FIRSTNAME + "FIRST NAME] "
+ + "[" + PREFIX_LASTNAME + "LAST NAME] "
+ + "[" + PREFIX_PAYRATE + "PAY RATE] "
+ + "[" + PREFIX_BANKDETAILS + "BANK DETAILS] "
+ + "[" + PREFIX_SEX + "SEX] "
+ + "Example: " + COMMAND_WORD + " 85789476 "
+ + PREFIX_PHONE + "91234567 ";
public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
+ public static final String MESSAGE_DUPLICATE_PERSON = "This phone number already exists in the address book. "
+ + "Every contact must have a unique phone number.";
- private final Index index;
+ private final Phone number;
private final EditPersonDescriptor editPersonDescriptor;
/**
- * @param index of the person in the filtered person list to edit
+ * @param phoneNumber of the person in the filtered person list to edit
* @param editPersonDescriptor details to edit the person with
*/
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
- requireNonNull(index);
+ public EditCommand(Phone phoneNumber, EditPersonDescriptor editPersonDescriptor) {
+ requireNonNull(phoneNumber);
requireNonNull(editPersonDescriptor);
- this.index = index;
+ this.number = phoneNumber;
this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
}
+ /**
+ * Creates and returns a {@code Person} with the details of {@code personToEdit}
+ * edited with {@code editPersonDescriptor}.
+ */
+ private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
+ assert personToEdit != null;
+ Name updatedFirstName = editPersonDescriptor.getFirstName().orElse(personToEdit.getFirstName());
+ Name updatedLastName = editPersonDescriptor.getLastName().orElse(personToEdit.getLastName());
+ Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
+ Sex updatedSex = editPersonDescriptor.getSex().orElse(personToEdit.getSex());
+ PayRate updatedPayRate = editPersonDescriptor.getPayRate()
+ .orElse(personToEdit.getPayRate());
+ Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
+ BankDetails updatedBankDetails = editPersonDescriptor.getBankDetails().orElse(personToEdit.getBankDetails());
+ WorkHours updatedWorkHours = editPersonDescriptor.getHoursWorked().orElse(personToEdit.getWorkHours());
+ Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
+ ArchiveStatus archiveStatus = personToEdit.getArchiveStatus();
+
+ return new Person(updatedFirstName, updatedLastName, updatedPhone, updatedSex, updatedPayRate,
+ updatedAddress, updatedBankDetails, updatedWorkHours, updatedTags, archiveStatus);
+ }
+
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List lastShownList = model.getFilteredPersonList();
- if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ boolean exists = false;
+ Person personToEdit = null;
+ for (Person person : lastShownList) {
+ if (person.getPhone().equals(number)) {
+ exists = true;
+ personToEdit = person;
+ break;
+ }
+ }
+ if (!exists) {
+ throw new CommandException(Messages.MESSAGE_PERSON_NOT_FOUND);
}
- Person personToEdit = lastShownList.get(index.getZeroBased());
Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
@@ -84,26 +122,9 @@ public CommandResult execute(Model model) throws CommandException {
}
model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson)));
}
- /**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
- */
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
-
- Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName());
- Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
- Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
- Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
- }
-
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -116,16 +137,16 @@ public boolean equals(Object other) {
}
EditCommand otherEditCommand = (EditCommand) other;
- return index.equals(otherEditCommand.index)
- && editPersonDescriptor.equals(otherEditCommand.editPersonDescriptor);
+ return number.equals(otherEditCommand.number)
+ && editPersonDescriptor.equals(otherEditCommand.editPersonDescriptor);
}
@Override
public String toString() {
return new ToStringBuilder(this)
- .add("index", index)
- .add("editPersonDescriptor", editPersonDescriptor)
- .toString();
+ .add("index", number)
+ .add("editPersonDescriptor", editPersonDescriptor)
+ .toString();
}
/**
@@ -133,71 +154,105 @@ public String toString() {
* corresponding field value of the person.
*/
public static class EditPersonDescriptor {
- private Name name;
+ private Name firstName;
+ private Name lastName;
private Phone phone;
- private Email email;
private Address address;
private Set tags;
+ private Sex sex;
+ private PayRate payRate;
+ private BankDetails bankDetails;
+ private WorkHours hoursWorked;
- public EditPersonDescriptor() {}
+ public EditPersonDescriptor() {
+ }
/**
* Copy constructor.
* A defensive copy of {@code tags} is used internally.
*/
public EditPersonDescriptor(EditPersonDescriptor toCopy) {
- setName(toCopy.name);
+ setFirstName(toCopy.firstName);
+ setLastName(toCopy.lastName);
setPhone(toCopy.phone);
- setEmail(toCopy.email);
- setAddress(toCopy.address);
setTags(toCopy.tags);
+ setPayRate(toCopy.payRate);
+ setSex(toCopy.sex);
+ setAddress(toCopy.address);
+ setBankDetails(toCopy.bankDetails);
+ setHoursWorked(toCopy.hoursWorked);
}
/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
+ return CollectionUtil.isAnyNonNull(firstName, lastName, phone, address, tags, sex, payRate,
+ bankDetails);
}
- public void setName(Name name) {
- this.name = name;
+ public Optional getFirstName() {
+ return Optional.ofNullable(firstName);
}
- public Optional getName() {
- return Optional.ofNullable(name);
+ public void setFirstName(Name name) {
+ this.firstName = name;
}
- public void setPhone(Phone phone) {
- this.phone = phone;
+ public Optional getLastName() {
+ return Optional.ofNullable(lastName);
+ }
+
+ public void setLastName(Name name) {
+ this.lastName = name;
}
public Optional getPhone() {
return Optional.ofNullable(phone);
}
- public void setEmail(Email email) {
- this.email = email;
+ public void setPhone(Phone phone) {
+ this.phone = phone;
}
- public Optional getEmail() {
- return Optional.ofNullable(email);
+ public Optional getSex() {
+ return Optional.ofNullable(sex);
}
- public void setAddress(Address address) {
- this.address = address;
+ public void setSex(Sex sex) {
+ this.sex = sex;
+ }
+
+ public Optional getBankDetails() {
+ return Optional.ofNullable(bankDetails);
+ }
+
+ public void setBankDetails(BankDetails bankDetails) {
+ this.bankDetails = bankDetails;
+ }
+
+ public Optional getPayRate() {
+ return Optional.ofNullable(payRate);
+ }
+
+ public void setPayRate(PayRate payRate) {
+ this.payRate = payRate;
}
public Optional getAddress() {
return Optional.ofNullable(address);
}
- /**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
- */
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+
+ public Optional getHoursWorked() {
+ return Optional.ofNullable(hoursWorked);
+ }
+
+ public void setHoursWorked(WorkHours hoursWorked) {
+ this.hoursWorked = hoursWorked;
}
/**
@@ -206,7 +261,15 @@ public void setTags(Set tags) {
* Returns {@code Optional#empty()} if {@code tags} is null.
*/
public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ return tags != null ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ }
+
+ /**
+ * Sets {@code tags} to this object's {@code tags}.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public void setTags(Set tags) {
+ this.tags = tags != null ? new HashSet<>(tags) : null;
}
@Override
@@ -221,22 +284,30 @@ public boolean equals(Object other) {
}
EditPersonDescriptor otherEditPersonDescriptor = (EditPersonDescriptor) other;
- return Objects.equals(name, otherEditPersonDescriptor.name)
- && Objects.equals(phone, otherEditPersonDescriptor.phone)
- && Objects.equals(email, otherEditPersonDescriptor.email)
- && Objects.equals(address, otherEditPersonDescriptor.address)
- && Objects.equals(tags, otherEditPersonDescriptor.tags);
+ return Objects.equals(firstName, otherEditPersonDescriptor.firstName)
+ && Objects.equals(lastName, otherEditPersonDescriptor.lastName)
+ && Objects.equals(phone, otherEditPersonDescriptor.phone)
+ && Objects.equals(tags, otherEditPersonDescriptor.tags)
+ && Objects.equals(sex, otherEditPersonDescriptor.sex)
+ && Objects.equals(payRate, otherEditPersonDescriptor.payRate)
+ && Objects.equals(address, otherEditPersonDescriptor.address)
+ && Objects.equals(bankDetails, otherEditPersonDescriptor.bankDetails)
+ && Objects.equals(hoursWorked, otherEditPersonDescriptor.hoursWorked);
}
@Override
public String toString() {
return new ToStringBuilder(this)
- .add("name", name)
- .add("phone", phone)
- .add("email", email)
- .add("address", address)
- .add("tags", tags)
- .toString();
+ .add("firstName", firstName)
+ .add("lastName", lastName)
+ .add("phone", phone)
+ .add("sex", sex)
+ .add("payRate", payRate)
+ .add("address", address)
+ .add("bankDetails", bankDetails)
+ .add("hoursWorked", hoursWorked)
+ .add("tags", tags)
+ .toString();
}
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
index 3dd85a8ba90..8ace7068750 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -13,7 +13,7 @@ public class ExitCommand extends Command {
@Override
public CommandResult execute(Model model) {
- return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true, false, false, false);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index 72b9eddd3a7..051b1aa9700 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -15,10 +15,10 @@ public class FindCommand extends Command {
public static final String COMMAND_WORD = "find";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
- + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
- + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons with names which match any of "
+ + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ + "Example: " + COMMAND_WORD + " alice bob charlie";
private final NameContainsKeywordsPredicate predicate;
@@ -31,7 +31,7 @@ public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(predicate);
return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
}
@Override
@@ -52,7 +52,7 @@ public boolean equals(Object other) {
@Override
public String toString() {
return new ToStringBuilder(this)
- .add("predicate", predicate)
- .toString();
+ .add("predicate", predicate)
+ .toString();
}
}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
index bf824f91bd0..f4996722342 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java
@@ -16,6 +16,6 @@ public class HelpCommand extends Command {
@Override
public CommandResult execute(Model model) {
- return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
+ return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false, false, false);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/HoursCommand.java b/src/main/java/seedu/address/logic/commands/HoursCommand.java
new file mode 100644
index 00000000000..a871b2048f0
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/HoursCommand.java
@@ -0,0 +1,77 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.person.WorkHours;
+
+/**
+ * Adds work hours to a person in the address book.
+ */
+public class HoursCommand extends Command {
+
+ public static final String COMMAND_WORD = "hours";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds work hours to a person in the address book. "
+ + "Parameters: \n"
+ + "Example: " + COMMAND_WORD + " 98765432 5";
+
+ public static final String MESSAGE_SUCCESS = "%1$s has worked %2$d hours this week";
+ public static final String MESSAGE_PERSON_NOT_FOUND = "The person with phone number: %1$s does not exist";
+
+ private final Phone phoneNumber;
+ private final WorkHours hoursWorked;
+
+ /**
+ * Creates an HoursCommand to add work hours to the person with the specified phone number.
+ */
+ public HoursCommand(Phone phoneNumber, WorkHours hoursWorked) {
+ requireNonNull(phoneNumber);
+ this.phoneNumber = phoneNumber;
+ this.hoursWorked = hoursWorked;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ Person personToUpdate = model.getPersonByPhoneNumber(phoneNumber);
+ if (personToUpdate == null) {
+ throw new CommandException(String.format(MESSAGE_PERSON_NOT_FOUND, phoneNumber));
+ }
+
+ personToUpdate.setHoursWorked(hoursWorked);
+ model.updatePerson(personToUpdate);
+
+ return new CommandResult(String.format(MESSAGE_SUCCESS, personToUpdate.getName(),
+ hoursWorked.getHoursWorked()));
+
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof HoursCommand)) {
+ return false;
+ }
+
+ HoursCommand otherCommand = (HoursCommand) other;
+ return phoneNumber.equals(otherCommand.phoneNumber)
+ && hoursWorked == otherCommand.hoursWorked;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("phoneNumber", phoneNumber)
+ .add("hoursWorked", hoursWorked)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
index 84be6ad2596..2f690173c62 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -1,7 +1,9 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_ARCHIVED_PERSONS;
import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS;
import seedu.address.model.Model;
@@ -12,13 +14,34 @@ public class ListCommand extends Command {
public static final String COMMAND_WORD = "list";
- public static final String MESSAGE_SUCCESS = "Listed all persons";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": List all persons in either the archived or"
+ + " unarchived list.\n"
+ + "Example: " + COMMAND_WORD + " archive \n"
+ + "Example: " + COMMAND_WORD + " main \n"
+ + "Example: " + COMMAND_WORD + " all \n";
+ public static final String MESSAGE_SUCCESS = "Listed all employees";
+ private final String keyword;
+ public ListCommand(String keyword) {
+ this.keyword = keyword;
+ }
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
+ switch (keyword) {
+ case "archive":
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_ARCHIVED_PERSONS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ case "main":
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ case "all":
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ default:
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ return new CommandResult(MESSAGE_USAGE);
+ }
}
}
diff --git a/src/main/java/seedu/address/logic/commands/PayrollCommand.java b/src/main/java/seedu/address/logic/commands/PayrollCommand.java
new file mode 100644
index 00000000000..2079c4d3440
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/PayrollCommand.java
@@ -0,0 +1,49 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ENDDATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STARTDATE;
+
+import java.time.LocalDate;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+
+/**
+ * Generates a payroll for a time period.
+ */
+public class PayrollCommand extends Command {
+ public static final String COMMAND_WORD = "payroll";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Generates a payroll for a time period.\n"
+ + "Parameters: "
+ + PREFIX_STARTDATE + "START DATE "
+ + PREFIX_ENDDATE + "END DATE\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_STARTDATE + "2021-01-01 "
+ + PREFIX_ENDDATE + "2021-01-31";
+
+ public static final String MESSAGE_SUCCESS = "Payroll generated for %1$s to %2$s";
+ public static final String MESSAGE_FAILURE = "Payroll generation failed";
+ private final LocalDate startDate;
+ private final LocalDate endDate;
+
+ /**
+ * Creates a PayrollCommand to generate a payroll for the specified time period.
+ */
+ public PayrollCommand(LocalDate startDate, LocalDate endDate) {
+ this.startDate = startDate;
+ this.endDate = endDate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ try {
+ model.generatePayroll(startDate, endDate);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, startDate, endDate), false, false,
+ false, false, true);
+ } catch (Exception e) {
+ return new CommandResult(MESSAGE_FAILURE);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ScheduleCommand.java b/src/main/java/seedu/address/logic/commands/ScheduleCommand.java
new file mode 100644
index 00000000000..988d48d2831
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ScheduleCommand.java
@@ -0,0 +1,77 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.time.LocalDate;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+
+/**
+ * Adds a person to the address book.
+ */
+public class ScheduleCommand extends Command {
+
+ public static final String COMMAND_WORD = "schedule";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the schedule.\n"
+ + "Parameters: "
+ + "PHONE "
+ + "DATE in the format yyyy-mm-dd\n"
+ + "Example: " + COMMAND_WORD + " "
+ + "91234567 "
+ + "2021-01-01";
+
+ public static final String MESSAGE_SUCCESS = "Schedule: %1$s added on %2$s";
+ private final Phone phoneNumber;
+ private final LocalDate date;
+
+ /**
+ * Creates a ScheduleCommand to add the specified {@code Person} to the schedule on the specified {@code LocalDate}.
+ */
+ public ScheduleCommand(Phone phoneNumber, LocalDate date) {
+ requireAllNonNull(phoneNumber, date);
+ this.phoneNumber = phoneNumber;
+ this.date = date;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ Person person = model.getPersonByPhoneNumber(phoneNumber);
+ if (person == null) {
+ throw new CommandException(Messages.MESSAGE_PERSON_NOT_FOUND);
+ }
+ model.addPersonToSchedule(person, date);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, person.getName().value, date), false, false,
+ false, true, false);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ScheduleCommand)) {
+ return false;
+ }
+
+ ScheduleCommand otherScheduleCommand = (ScheduleCommand) other;
+ return phoneNumber.equals(otherScheduleCommand.phoneNumber) && date.equals(otherScheduleCommand.date);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("phoneNumber", phoneNumber)
+ .add("date", date)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/UnarchiveCommand.java b/src/main/java/seedu/address/logic/commands/UnarchiveCommand.java
new file mode 100644
index 00000000000..acec974e39e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/UnarchiveCommand.java
@@ -0,0 +1,115 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.commands.AddCommand.MESSAGE_DUPLICATE_PERSON;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_ARCHIVED_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS;
+
+import java.util.List;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.ArchiveStatus;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+
+/**
+ * Archives an employee from the contact book into the archive book.
+ */
+public class UnarchiveCommand extends Command {
+
+ public static final String COMMAND_WORD = "unarchive";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Archives a contact. \n"
+ + "Parameters: unarchive [EXISTING PHONE NUMBER] \n"
+ + "Example: " + COMMAND_WORD + " 98765432";
+
+ public static final String MESSAGE_ARCHIVE_PERSON_SUCCESS = "Un-archived Person: %1$s";
+
+ private final Phone targetPhone;
+
+ public UnarchiveCommand(Phone targetPhone) {
+ this.targetPhone = targetPhone;
+ }
+
+ /**
+ * Creates an archived person based on the person to archive.
+ *
+ * @param personToUnarchive Person to archive.
+ * @return Archived person.
+ */
+ private static Person createUnarchivedPerson(Person personToUnarchive) {
+ assert personToUnarchive != null;
+
+ ArchiveStatus updatedArchiveStatus = new ArchiveStatus(false);
+
+ return new Person(personToUnarchive.getFirstName(), personToUnarchive.getLastName(),
+ personToUnarchive.getPhone(), personToUnarchive.getSex(), personToUnarchive.getPayRate(),
+ personToUnarchive.getAddress(), personToUnarchive.getBankDetails(), personToUnarchive.getWorkHours(),
+ personToUnarchive.getTags(), updatedArchiveStatus);
+ }
+
+ /**
+ * Archives a person from the contact book.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return A command result that indicates the person has been archived.
+ * @throws CommandException If the person does not exist in the contact book.
+ */
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_ARCHIVED_PERSONS);
+ List archiveList = model.getFilteredPersonList();
+ boolean exists = false;
+ Person personToUnarchive = null;
+ for (Person person : archiveList) {
+ if (person.getPhone().equals(targetPhone)) {
+ exists = true;
+ personToUnarchive = person;
+ break;
+ }
+ }
+ if (!exists) {
+ throw new CommandException(Messages.MESSAGE_PERSON_NOT_ARCHIVED);
+ }
+
+ Person unarchivedPerson = createUnarchivedPerson(personToUnarchive);
+
+ if (!personToUnarchive.isSamePerson(unarchivedPerson) && model.hasPerson(unarchivedPerson)) {
+ throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ }
+
+ model.unarchivePerson(personToUnarchive, unarchivedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS);
+ return new CommandResult(String.format(MESSAGE_ARCHIVE_PERSON_SUCCESS, Messages.format(personToUnarchive)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof UnarchiveCommand)) {
+ return false;
+ }
+
+ // state check
+ UnarchiveCommand e = (UnarchiveCommand) other;
+ return targetPhone.equals(e.targetPhone);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("targetPhone", targetPhone)
+ .toString();
+ }
+
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/UnscheduleCommand.java b/src/main/java/seedu/address/logic/commands/UnscheduleCommand.java
new file mode 100644
index 00000000000..b68d947c202
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/UnscheduleCommand.java
@@ -0,0 +1,74 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.time.LocalDate;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+
+/**
+ * Removes a person from the schedule.
+ */
+public class UnscheduleCommand extends Command {
+
+ public static final String COMMAND_WORD = "unschedule";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Removes a person from the schedule.\n"
+ + "Parameters: "
+ + "PHONE "
+ + "DATE in the format yyyy-mm-dd\n"
+ + "Example: " + COMMAND_WORD + " "
+ + "91234567 "
+ + "2021-01-01";
+
+ public static final String MESSAGE_SUCCESS = "Schedule: %1$s removed from %2$s";
+ private final Phone phoneNumber;
+ private final LocalDate date;
+
+ /**
+ * Creates an UnscheduleCommand to remove the specified {@code Person} from the schedule on the specified
+ * {@code LocalDate}.
+ */
+ public UnscheduleCommand(Phone phoneNumber, LocalDate date) {
+ requireAllNonNull(phoneNumber, date);
+ this.phoneNumber = phoneNumber;
+ this.date = date;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ Person person = model.getPersonByPhoneNumber(phoneNumber);
+ model.removePersonFromSchedule(person, date);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, person.getName().value, date), false, false,
+ false, true, false);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof UnscheduleCommand)) {
+ return false;
+ }
+
+ UnscheduleCommand otherUnscheduleCommand = (UnscheduleCommand) other;
+ return phoneNumber.equals(otherUnscheduleCommand.phoneNumber) && date.equals(otherUnscheduleCommand.date);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("phoneNumber", phoneNumber)
+ .add("date", date)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 4ff1a97ed77..d0d32b14546 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -2,21 +2,28 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_BANKDETAILS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FIRSTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PAYRATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.ParserUtil.arePrefixesPresent;
import java.util.Set;
-import java.util.stream.Stream;
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.ArchiveStatus;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
+import seedu.address.model.person.WorkHours;
import seedu.address.model.tag.Tag;
/**
@@ -27,35 +34,39 @@ public class AddCommandParser implements Parser {
/**
* Parses the given {@code String} of arguments in the context of the AddCommand
* and returns an AddCommand object for execution.
+ *
* @throws ParseException if the user input does not conform the expected format
*/
public AddCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, PREFIX_FIRSTNAME, PREFIX_LASTNAME, PREFIX_PHONE,
+ PREFIX_SEX, PREFIX_PAYRATE, PREFIX_ADDRESS, PREFIX_BANKDETAILS,
+ PREFIX_TAG);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
+ if (!arePrefixesPresent(argMultimap, PREFIX_FIRSTNAME, PREFIX_LASTNAME,
+ PREFIX_PHONE, PREFIX_SEX, PREFIX_PAYRATE, PREFIX_ADDRESS)
+ || !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
- Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_FIRSTNAME, PREFIX_LASTNAME, PREFIX_PHONE,
+ PREFIX_SEX, PREFIX_PAYRATE,
+ PREFIX_ADDRESS, PREFIX_BANKDETAILS);
+ Name firstName = ParserUtil.parseName(argMultimap.getValue(PREFIX_FIRSTNAME).get());
+ Name lastName = ParserUtil.parseName(argMultimap.getValue(PREFIX_LASTNAME).get());
Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
- Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
- Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
+ Sex sex = ParserUtil.parseSex(argMultimap.getValue(PREFIX_SEX).get());
+ PayRate payRate =
+ ParserUtil.parsePayRate(argMultimap.getValue(PREFIX_PAYRATE).get());
+ Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).orElse(""));
+ BankDetails bankDetails =
+ ParserUtil.parseBankDetails(argMultimap.getValue(PREFIX_BANKDETAILS).orElse(""));
Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
- Person person = new Person(name, phone, email, address, tagList);
+ Person person = new Person(firstName, lastName, phone, sex, payRate, address,
+ bankDetails, new WorkHours(), tagList, new ArchiveStatus(false));
return new AddCommand(person);
}
- /**
- * Returns true if none of the prefixes contains empty {@code Optional} values in the given
- * {@code ArgumentMultimap}.
- */
- private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
- return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
- }
-
}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
index 3149ee07e0b..a7f268050d7 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
@@ -9,6 +9,7 @@
import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.ArchiveCommand;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.DeleteCommand;
@@ -16,7 +17,12 @@
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
+import seedu.address.logic.commands.HoursCommand;
import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.PayrollCommand;
+import seedu.address.logic.commands.ScheduleCommand;
+import seedu.address.logic.commands.UnarchiveCommand;
+import seedu.address.logic.commands.UnscheduleCommand;
import seedu.address.logic.parser.exceptions.ParseException;
/**
@@ -38,7 +44,7 @@ public class AddressBookParser {
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput) throws ParseException {
- final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
+ final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput);
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}
@@ -69,7 +75,7 @@ public Command parseCommand(String userInput) throws ParseException {
return new FindCommandParser().parse(arguments);
case ListCommand.COMMAND_WORD:
- return new ListCommand();
+ return new ListCommandParser().parse(arguments);
case ExitCommand.COMMAND_WORD:
return new ExitCommand();
@@ -77,10 +83,27 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case HoursCommand.COMMAND_WORD:
+ return new HoursCommandParser().parse(arguments);
+
+ case ScheduleCommand.COMMAND_WORD:
+ return new ScheduleCommandParser().parse(arguments);
+
+ case UnscheduleCommand.COMMAND_WORD:
+ return new UnscheduleCommandParser().parse(arguments);
+
+ case ArchiveCommand.COMMAND_WORD:
+ return new ArchiveCommandParser().parse(arguments);
+
+ case UnarchiveCommand.COMMAND_WORD:
+ return new UnarchiveCommandParser().parse(arguments);
+
+ case PayrollCommand.COMMAND_WORD:
+ return new PayrollCommandParser().parse(arguments);
+
default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/ArchiveCommandParser.java b/src/main/java/seedu/address/logic/parser/ArchiveCommandParser.java
new file mode 100644
index 00000000000..1e6bd025ba9
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ArchiveCommandParser.java
@@ -0,0 +1,28 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.ArchiveCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Phone;
+
+/**
+ * Parses input arguments and creates a new ArchiveCommand object
+ */
+public class ArchiveCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ArchiveCommand
+ * and returns an ArchiveCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ArchiveCommand parse(String args) throws ParseException {
+ try {
+ Phone number = ParserUtil.parsePhone(args);
+ return new ArchiveCommand(number);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ArchiveCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
index 5c9aebfa488..3be8e89059d 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
@@ -7,11 +7,11 @@
/**
* Tokenizes arguments string of the form: {@code preamble value value ...}
- * e.g. {@code some preamble text t/ 11.00 t/12.00 k/ m/ July} where prefixes are {@code t/ k/ m/}.
+ * e.g. {@code some preamble text t/ 11.00 t/12.00 k/ m/ July} where prefixes are {@code t/ k/ m/}.
* 1. An argument's value can be an empty string e.g. the value of {@code k/} in the above example.
* 2. Leading and trailing whitespaces of an argument value will be discarded.
* 3. An argument may be repeated and all its values will be accumulated e.g. the value of {@code t/}
- * in the above example.
+ * in the above example.
*/
public class ArgumentTokenizer {
@@ -21,7 +21,7 @@ public class ArgumentTokenizer {
*
* @param argsString Arguments string of the form: {@code preamble value value ...}
* @param prefixes Prefixes to tokenize the arguments string with
- * @return ArgumentMultimap object that maps prefixes to their arguments
+ * @return ArgumentMultimap object that maps prefixes to their arguments
*/
public static ArgumentMultimap tokenize(String argsString, Prefix... prefixes) {
List positions = findAllPrefixPositions(argsString, prefixes);
@@ -33,7 +33,7 @@ public static ArgumentMultimap tokenize(String argsString, Prefix... prefixes) {
*
* @param argsString Arguments string of the form: {@code preamble value value ...}
* @param prefixes Prefixes to find in the arguments string
- * @return List of zero-based prefix positions in the given arguments string
+ * @return List of zero-based prefix positions in the given arguments string
*/
private static List findAllPrefixPositions(String argsString, Prefix... prefixes) {
return Arrays.stream(prefixes)
@@ -62,7 +62,7 @@ private static List findPrefixPositions(String argsString, Prefi
* {@code argsString} starting from index {@code fromIndex}. An occurrence
* is valid if there is a whitespace before {@code prefix}. Returns -1 if no
* such occurrence can be found.
- *
+ *
* E.g if {@code argsString} = "e/hip/900", {@code prefix} = "p/" and
* {@code fromIndex} = 0, this method returns -1 as there are no valid
* occurrences of "p/" with whitespace before it. However, if
@@ -82,7 +82,7 @@ private static int findPrefixPosition(String argsString, String prefix, int from
*
* @param argsString Arguments string of the form: {@code preamble value value ...}
* @param prefixPositions Zero-based positions of all prefixes in {@code argsString}
- * @return ArgumentMultimap object that maps prefixes to their arguments
+ * @return ArgumentMultimap object that maps prefixes to their arguments
*/
private static ArgumentMultimap extractArguments(String argsString, List prefixPositions) {
@@ -114,8 +114,8 @@ private static ArgumentMultimap extractArguments(String argsString, List {
*/
public DeleteCommand parse(String args) throws ParseException {
try {
- Index index = ParserUtil.parseIndex(args);
- return new DeleteCommand(index);
+ Phone number = ParserUtil.parsePhone(args);
+ return new DeleteCommand(number);
} catch (ParseException pe) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 46b3309a78b..90dbc1da2aa 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -3,9 +3,12 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_BANKDETAILS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FIRSTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PAYRATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import java.util.Collection;
@@ -13,10 +16,9 @@
import java.util.Optional;
import java.util.Set;
-import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Phone;
import seedu.address.model.tag.Tag;
/**
@@ -27,44 +29,58 @@ public class EditCommandParser implements Parser {
/**
* Parses the given {@code String} of arguments in the context of the EditCommand
* and returns an EditCommand object for execution.
+ *
* @throws ParseException if the user input does not conform the expected format
*/
public EditCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, PREFIX_FIRSTNAME, PREFIX_LASTNAME, PREFIX_PHONE,
+ PREFIX_ADDRESS, PREFIX_TAG, PREFIX_SEX, PREFIX_PAYRATE, PREFIX_BANKDETAILS);
- Index index;
+ Phone number;
try {
- index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ number = ParserUtil.parsePhone(argMultimap.getPreamble());
} catch (ParseException pe) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_FIRSTNAME, PREFIX_LASTNAME, PREFIX_PHONE, PREFIX_SEX,
+ PREFIX_PAYRATE, PREFIX_BANKDETAILS, PREFIX_ADDRESS);
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
+ EditCommand.EditPersonDescriptor editPersonDescriptor = new EditCommand.EditPersonDescriptor();
- if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
+ if (argMultimap.getValue(PREFIX_FIRSTNAME).isPresent()) {
+ editPersonDescriptor.setFirstName(ParserUtil.parseName(argMultimap.getValue(PREFIX_FIRSTNAME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_LASTNAME).isPresent()) {
+ editPersonDescriptor.setLastName(ParserUtil.parseName(argMultimap.getValue(PREFIX_LASTNAME).get()));
}
if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
}
- if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
- }
if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
}
+ if (argMultimap.getValue(PREFIX_SEX).isPresent()) {
+ editPersonDescriptor.setSex(ParserUtil.parseSex(argMultimap.getValue(PREFIX_SEX).get()));
+ }
+ if (argMultimap.getValue(PREFIX_PAYRATE).isPresent()) {
+ editPersonDescriptor.setPayRate(ParserUtil
+ .parsePayRate(argMultimap.getValue(PREFIX_PAYRATE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_BANKDETAILS).isPresent()) {
+ editPersonDescriptor.setBankDetails(ParserUtil
+ .parseBankDetails(argMultimap.getValue(PREFIX_BANKDETAILS).get()));
+ }
parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
if (!editPersonDescriptor.isAnyFieldEdited()) {
throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
}
- return new EditCommand(index, editPersonDescriptor);
+ return new EditCommand(number, editPersonDescriptor);
}
/**
diff --git a/src/main/java/seedu/address/logic/parser/HoursCommandParser.java b/src/main/java/seedu/address/logic/parser/HoursCommandParser.java
new file mode 100644
index 00000000000..e590d57580d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/HoursCommandParser.java
@@ -0,0 +1,31 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.HoursCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Phone;
+import seedu.address.model.person.WorkHours;
+
+/**
+ * Parses input arguments and creates a new HoursCommand object
+ */
+public class HoursCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the HoursCommand
+ * and returns a HoursCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public HoursCommand parse(String args) throws ParseException {
+ String[] tokens = args.trim().split("\\s+");
+ if (tokens.length != 2) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HoursCommand.MESSAGE_USAGE));
+ }
+ Phone phoneNumber = ParserUtil.parsePhone(tokens[0]);
+ WorkHours hoursWorked;
+ hoursWorked = ParserUtil.parseWorkHours(tokens[1]);
+ return new HoursCommand(phoneNumber, hoursWorked);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ListCommandParser.java b/src/main/java/seedu/address/logic/parser/ListCommandParser.java
new file mode 100644
index 00000000000..159515f1df1
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ListCommandParser.java
@@ -0,0 +1,30 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new ListCommand object
+ */
+public class ListCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the ListCommand
+ * and returns a ListCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ListCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListCommand.MESSAGE_USAGE));
+ }
+
+ String keyword = args.trim();
+
+ return new ListCommand(keyword);
+ }
+
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..4d139365a82 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -2,17 +2,22 @@
import static java.util.Objects.requireNonNull;
+import java.time.LocalDate;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
+import java.util.stream.Stream;
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
+import seedu.address.model.person.WorkHours;
import seedu.address.model.tag.Tag;
/**
@@ -25,6 +30,7 @@ public class ParserUtil {
/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
* trimmed.
+ *
* @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
*/
public static Index parseIndex(String oneBasedIndex) throws ParseException {
@@ -65,6 +71,41 @@ public static Phone parsePhone(String phone) throws ParseException {
return new Phone(trimmedPhone);
}
+ /**
+ * Parses a {@code String sex} into a {@code Sex}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code sex} is invalid.
+ */
+ public static Sex parseSex(String sex) throws ParseException {
+ requireNonNull(sex);
+ String trimmedSex = sex.trim();
+ if (!Sex.isValidSex(trimmedSex)) {
+ throw new ParseException(Sex.MESSAGE_CONSTRAINTS);
+ }
+ return new Sex(trimmedSex);
+ }
+
+ /**
+ * Parses a {@code String employmentType} into a {@code EmploymentType}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code employmentType} is invalid.
+ */
+ public static PayRate parsePayRate(String payRate) throws ParseException {
+ requireNonNull(payRate);
+ String trimmedPayRate = payRate.trim();
+ try {
+ double rate = Double.parseDouble(trimmedPayRate);
+ if (rate <= 0) {
+ throw new ParseException("Pay rate cannot be zero or negative");
+ }
+ return new PayRate(rate);
+ } catch (NumberFormatException e) {
+ throw new ParseException(PayRate.MESSAGE_CONSTRAINTS);
+ }
+ }
+
/**
* Parses a {@code String address} into an {@code Address}.
* Leading and trailing whitespaces will be trimmed.
@@ -81,18 +122,18 @@ public static Address parseAddress(String address) throws ParseException {
}
/**
- * Parses a {@code String email} into an {@code Email}.
+ * Parses a {@code String bankDetails} into an {@code BankDetails}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code email} is invalid.
+ * @throws ParseException if the given {@code bankDetails} is invalid.
*/
- public static Email parseEmail(String email) throws ParseException {
- requireNonNull(email);
- String trimmedEmail = email.trim();
- if (!Email.isValidEmail(trimmedEmail)) {
- throw new ParseException(Email.MESSAGE_CONSTRAINTS);
+ public static BankDetails parseBankDetails(String bankDetails) throws ParseException {
+ requireNonNull(bankDetails);
+ String trimmedBankDetails = bankDetails.trim();
+ if (!BankDetails.isValidBankAccount(trimmedBankDetails)) {
+ throw new ParseException(BankDetails.MESSAGE_CONSTRAINTS);
}
- return new Email(trimmedEmail);
+ return new BankDetails(trimmedBankDetails);
}
/**
@@ -121,4 +162,50 @@ public static Set parseTags(Collection tags) throws ParseException
}
return tagSet;
}
+
+ /**
+ * Parses a string representation of work hours into a WorkHours object.
+ *
+ * @param workHours A string representing the number of work hours.
+ * @return A WorkHours object representing the parsed work hours.
+ * @throws ParseException if the work hours string is invalid or cannot be parsed.
+ */
+ public static WorkHours parseWorkHours(String workHours) throws ParseException {
+ requireNonNull(workHours);
+ String trimmedWorkHours = workHours.trim();
+ try {
+ int hours = Integer.parseInt(trimmedWorkHours);
+ if (hours < 0) {
+ throw new ParseException("Work hours cannot be negative");
+ }
+ return new WorkHours(hours);
+ } catch (NumberFormatException e) {
+ throw new ParseException(WorkHours.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Parses a string representation of a date into a LocalDate object.
+ *
+ * @param date A string representing a date.
+ * @return A LocalDate object representing the parsed date.
+ * @throws ParseException if the date string is invalid or cannot be parsed.
+ */
+ public static LocalDate parseDate(String date) throws ParseException {
+ requireNonNull(date);
+ String trimmedDate = date.trim();
+ try {
+ return LocalDate.parse(trimmedDate);
+ } catch (Exception e) {
+ throw new ParseException("Invalid date format. Please enter a date in the format yyyy-mm-dd");
+ }
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ public static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
}
diff --git a/src/main/java/seedu/address/logic/parser/PayrollCommandParser.java b/src/main/java/seedu/address/logic/parser/PayrollCommandParser.java
new file mode 100644
index 00000000000..6f075720c7f
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/PayrollCommandParser.java
@@ -0,0 +1,39 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ENDDATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STARTDATE;
+import static seedu.address.logic.parser.ParserUtil.arePrefixesPresent;
+
+import java.time.LocalDate;
+
+import seedu.address.logic.commands.PayrollCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new PayrollCommand object
+ */
+public class PayrollCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the PayrollCommand
+ * and returns a PayrollCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public PayrollCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_STARTDATE, PREFIX_ENDDATE);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_STARTDATE, PREFIX_ENDDATE);
+ if (!arePrefixesPresent(argMultimap, PREFIX_STARTDATE, PREFIX_ENDDATE)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, PayrollCommand.MESSAGE_USAGE));
+ }
+ LocalDate startDate = ParserUtil.parseDate(argMultimap.getValue(PREFIX_STARTDATE).get());
+ LocalDate endDate = ParserUtil.parseDate(argMultimap.getValue(PREFIX_ENDDATE).get());
+ if (startDate.isAfter(endDate)) {
+ throw new ParseException("Start date cannot be after end date");
+ }
+ return new PayrollCommand(startDate, endDate);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ScheduleCommandParser.java b/src/main/java/seedu/address/logic/parser/ScheduleCommandParser.java
new file mode 100644
index 00000000000..6f3cacc29e8
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ScheduleCommandParser.java
@@ -0,0 +1,31 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.time.LocalDate;
+
+import seedu.address.logic.commands.ScheduleCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Phone;
+
+/**
+ * Parses input arguments and creates a new ScheduleCommand object
+ */
+public class ScheduleCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ScheduleCommand
+ * and returns a ScheduleCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ScheduleCommand parse(String args) throws ParseException {
+ String[] tokens = args.trim().split("\\s+");
+ if (tokens.length != 2) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ScheduleCommand.MESSAGE_USAGE));
+ }
+ Phone phoneNumber = ParserUtil.parsePhone(tokens[0]);
+ LocalDate date = ParserUtil.parseDate(tokens[1]);
+ return new ScheduleCommand(phoneNumber, date);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/UnarchiveCommandParser.java b/src/main/java/seedu/address/logic/parser/UnarchiveCommandParser.java
new file mode 100644
index 00000000000..1f5b3a9b0de
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/UnarchiveCommandParser.java
@@ -0,0 +1,29 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.UnarchiveCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Phone;
+
+/**
+ * Parses input arguments and creates a new ArchiveCommand object
+ */
+public class UnarchiveCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ArchiveCommand
+ * and returns an ArchiveCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public UnarchiveCommand parse(String args) throws ParseException {
+ try {
+ Phone number = ParserUtil.parsePhone(args);
+ return new UnarchiveCommand(number);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnarchiveCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/UnscheduleCommandParser.java b/src/main/java/seedu/address/logic/parser/UnscheduleCommandParser.java
new file mode 100644
index 00000000000..e282ca1b5ce
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/UnscheduleCommandParser.java
@@ -0,0 +1,31 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.time.LocalDate;
+
+import seedu.address.logic.commands.UnscheduleCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Phone;
+
+/**
+ * Parses input arguments and creates a new UnscheduleCommand object
+ */
+public class UnscheduleCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ScheduleCommand
+ * and returns a ScheduleCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public UnscheduleCommand parse(String args) throws ParseException {
+ String[] tokens = args.trim().split("\\s+");
+ if (tokens.length != 2) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnscheduleCommand.MESSAGE_USAGE));
+ }
+ Phone phoneNumber = ParserUtil.parsePhone(tokens[0]);
+ LocalDate date = ParserUtil.parseDate(tokens[1]);
+ return new UnscheduleCommand(phoneNumber, date);
+ }
+}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
index 73397161e84..9ac783de663 100644
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ b/src/main/java/seedu/address/model/AddressBook.java
@@ -8,6 +8,8 @@
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.person.Person;
import seedu.address.model.person.UniquePersonList;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleManager;
/**
* Wraps all data at the address-book level
@@ -16,6 +18,7 @@
public class AddressBook implements ReadOnlyAddressBook {
private final UniquePersonList persons;
+ private final Schedule schedule;
/*
* The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
@@ -26,6 +29,7 @@ public class AddressBook implements ReadOnlyAddressBook {
*/
{
persons = new UniquePersonList();
+ schedule = new ScheduleManager();
}
public AddressBook() {}
@@ -94,6 +98,14 @@ public void removePerson(Person key) {
persons.remove(key);
}
+ public void archivePerson(Person target, Person archivedPerson) {
+ persons.archive(target, archivedPerson);
+ }
+
+ public void unarchivePerson(Person target, Person unarchivedPerson) {
+ persons.unarchive(target, unarchivedPerson);
+ }
+
//// util methods
@Override
@@ -108,6 +120,10 @@ public ObservableList getPersonList() {
return persons.asUnmodifiableObservableList();
}
+ public Schedule getSchedule() {
+ return schedule;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index d54df471c1f..ee7e8c3c09f 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -1,11 +1,17 @@
package seedu.address.model;
import java.nio.file.Path;
+import java.time.LocalDate;
+import java.util.Set;
import java.util.function.Predicate;
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
+import seedu.address.model.person.PayrollWrapper;
import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleDate;
/**
* The API of the Model component.
@@ -14,6 +20,12 @@ public interface Model {
/** {@code Predicate} that always evaluate to true */
Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
+ /** {@code Predicate} that evaluates to true when the person is not archived */
+ Predicate PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS = person -> !person.getArchiveStatus().getArchiveStatus();
+
+ /** {@code Predicate} that evaluates to true when the person is archived */
+ Predicate PREDICATE_SHOW_ALL_ARCHIVED_PERSONS = person -> person.getArchiveStatus().getArchiveStatus();
+
/**
* Replaces user prefs data with the data in {@code userPrefs}.
*/
@@ -52,6 +64,29 @@ public interface Model {
/** Returns the AddressBook */
ReadOnlyAddressBook getAddressBook();
+ /**
+ * Replaces schedule data with the data in {@code schedule}.
+ */
+ void setSchedule(Schedule schedule);
+
+ /** Returns the Schedule */
+ Schedule getSchedule();
+
+ /**
+ * Returns the schedule dates.
+ */
+ Set getScheduleDates();
+
+ /**
+ * Adds {@code person} on {@code date} to the {@code Schedule} in the model.
+ */
+ void addPersonToSchedule(Person person, LocalDate date);
+
+ /**
+ * Removes {@code person} on {@code date} from the {@code Schedule} in the model.
+ */
+ void removePersonFromSchedule(Person person, LocalDate date);
+
/**
* Returns true if a person with the same identity as {@code person} exists in the address book.
*/
@@ -79,9 +114,42 @@ public interface Model {
/** Returns an unmodifiable view of the filtered person list */
ObservableList getFilteredPersonList();
+ /** Returns an unmodifiable view of the filtered un-archived person list */
+ ObservableList getFilteredUnarchivedPersonList();
+
+ /** Returns an unmodifiable view of the filtered archived person list */
+ ObservableList getFilteredArchivedPersonList();
+
/**
* Updates the filter of the filtered person list to filter by the given {@code predicate}.
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredPersonList(Predicate predicate);
+
+ /**
+ * Returns a person with the given phone number.
+ * Returns {@code null} if no person with the given phone number is found.
+ */
+ Person getPersonByPhoneNumber(Phone phoneNumber);
+
+ /**
+ * Updates the details of the specified person in the address book with the details of the updated person.
+ * @param personToUpdate The person to be updated.
+ */
+ void updatePerson(Person personToUpdate);
+
+ void archivePerson(Person personToArchive, Person archivedPerson);
+
+ void unarchivePerson(Person personToUnarchive, Person unarchivedPerson);
+ /**
+ * Generates the payroll for the specified period.
+ * @param startDate The start date of the period.
+ * @param endDate The end date of the period.
+ */
+ void generatePayroll(LocalDate startDate, LocalDate endDate);
+
+ /**
+ * Returns the payroll list.
+ */
+ ObservableList getPayrollList();
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 57bc563fde6..32190fc8aa6 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -4,14 +4,25 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
import java.nio.file.Path;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.function.Predicate;
import java.util.logging.Logger;
+import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
+import seedu.address.model.person.PayrollWrapper;
import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleDate;
+import seedu.address.model.schedule.ScheduleManager;
/**
* Represents the in-memory model of the address book data.
@@ -21,23 +32,29 @@ public class ModelManager implements Model {
private final AddressBook addressBook;
private final UserPrefs userPrefs;
+ private final Schedule schedule;
private final FilteredList filteredPersons;
+ private final ObservableList payrolls;
+
/**
* Initializes a ModelManager with the given addressBook and userPrefs.
*/
- public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
- requireAllNonNull(addressBook, userPrefs);
+ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs, Schedule schedule) {
+ requireAllNonNull(addressBook, userPrefs, schedule);
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
+ logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs
+ + " and schedule " + schedule);
this.addressBook = new AddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
+ this.schedule = schedule;
filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ payrolls = FXCollections.observableArrayList();
}
public ModelManager() {
- this(new AddressBook(), new UserPrefs());
+ this(new AddressBook(), new UserPrefs(), new ScheduleManager());
}
//=========== UserPrefs ==================================================================================
@@ -101,16 +118,73 @@ public void deletePerson(Person target) {
@Override
public void addPerson(Person person) {
addressBook.addPerson(person);
- updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ updateFilteredPersonList(PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS);
}
@Override
public void setPerson(Person target, Person editedPerson) {
requireAllNonNull(target, editedPerson);
-
addressBook.setPerson(target, editedPerson);
}
+ @Override
+ public void archivePerson(Person target, Person archivedPerson) {
+ addressBook.archivePerson(target, archivedPerson);
+ }
+
+ @Override
+ public void unarchivePerson(Person target, Person unarchivedPerson) {
+ addressBook.unarchivePerson(target, unarchivedPerson);
+ }
+
+ //=========== Schedule ===================================================================================
+
+ @Override
+ public void setSchedule(Schedule schedule) {
+ this.schedule.resetData(schedule);
+ }
+
+ @Override
+ public Schedule getSchedule() {
+ return schedule;
+ }
+
+ @Override
+ public Set getScheduleDates() {
+ return schedule.getScheduleDates();
+ }
+
+ @Override
+ public void addPersonToSchedule(Person person, LocalDate date) {
+ requireAllNonNull(person, date);
+ schedule.addPerson(person, date);
+ }
+
+ @Override
+ public void removePersonFromSchedule(Person person, LocalDate date) {
+ requireAllNonNull(person, date);
+ schedule.deletePerson(person, date);
+ }
+
+ //=========== Payroll ===================================================================================
+
+ @Override
+ public void generatePayroll(LocalDate startDate, LocalDate endDate) {
+ requireAllNonNull(startDate, endDate);
+ payrolls.clear();
+ List newPayrolls = new ArrayList<>();
+ Map hoursWorked = schedule.getHoursWorked(startDate, endDate);
+ for (Map.Entry entry : hoursWorked.entrySet()) {
+ newPayrolls.add(new PayrollWrapper(entry.getKey(), entry.getValue()));
+ }
+ payrolls.setAll(newPayrolls);
+ }
+
+ @Override
+ public ObservableList getPayrollList() {
+ return payrolls;
+ }
+
//=========== Filtered Person List Accessors =============================================================
/**
@@ -122,6 +196,26 @@ public ObservableList getFilteredPersonList() {
return filteredPersons;
}
+ /**
+ * Returns an unmodifiable view of the list of unarchived {@code Person} backed by the internal list of
+ * {@code addressBook}
+ */
+ @Override
+ public ObservableList getFilteredUnarchivedPersonList() {
+ this.updateFilteredPersonList(PREDICATE_SHOW_ALL_UNARCHIVED_PERSONS);
+ return filteredPersons;
+ }
+
+ /**
+ * Returns an unmodifiable view of the list of archived {@code Person} backed by the internal list of
+ * {@code addressBook}
+ */
+ @Override
+ public ObservableList getFilteredArchivedPersonList() {
+ this.updateFilteredPersonList(PREDICATE_SHOW_ALL_ARCHIVED_PERSONS);
+ return filteredPersons;
+ }
+
@Override
public void updateFilteredPersonList(Predicate predicate) {
requireNonNull(predicate);
@@ -145,4 +239,21 @@ public boolean equals(Object other) {
&& filteredPersons.equals(otherModelManager.filteredPersons);
}
+ @Override
+ public Person getPersonByPhoneNumber(Phone phoneNumber) {
+ requireNonNull(phoneNumber);
+ for (Person person : addressBook.getPersonList()) {
+ if (person.getPhone().equals(phoneNumber)) {
+ return person;
+ }
+ }
+ return null; // Return null if the person is not found
+ }
+
+ @Override
+ public void updatePerson(Person personToUpdate) {
+ requireNonNull(personToUpdate);
+ addressBook.setPerson(personToUpdate, personToUpdate);
+ }
+
}
diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
index befd58a4c73..2de0639c53c 100644
--- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
+++ b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
@@ -13,4 +13,7 @@ public interface ReadOnlyUserPrefs {
Path getAddressBookFilePath();
+ Path getScheduleFilePath();
+
+ Path getArchiveBookFilePath();
}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java
index 6be655fb4c7..6153b5fe72d 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/seedu/address/model/UserPrefs.java
@@ -14,7 +14,9 @@
public class UserPrefs implements ReadOnlyUserPrefs {
private GuiSettings guiSettings = new GuiSettings();
- private Path addressBookFilePath = Paths.get("data" , "addressbook.json");
+ private Path addressBookFilePath = Paths.get("data", "addressbook.json");
+ private Path scheduleFilePath = Paths.get("data", "schedule.json");
+ private Path archiveBookFilePath = Paths.get("data", "archivebook.json");
/**
* Creates a {@code UserPrefs} with default values.
@@ -36,6 +38,7 @@ public void resetData(ReadOnlyUserPrefs newUserPrefs) {
requireNonNull(newUserPrefs);
setGuiSettings(newUserPrefs.getGuiSettings());
setAddressBookFilePath(newUserPrefs.getAddressBookFilePath());
+ setScheduleFilePath(newUserPrefs.getScheduleFilePath());
}
public GuiSettings getGuiSettings() {
@@ -51,11 +54,24 @@ public Path getAddressBookFilePath() {
return addressBookFilePath;
}
+ public Path getArchiveBookFilePath() {
+ return archiveBookFilePath;
+ }
+
public void setAddressBookFilePath(Path addressBookFilePath) {
requireNonNull(addressBookFilePath);
this.addressBookFilePath = addressBookFilePath;
}
+ public Path getScheduleFilePath() {
+ return scheduleFilePath;
+ }
+
+ public void setScheduleFilePath(Path scheduleFilePath) {
+ requireNonNull(scheduleFilePath);
+ this.scheduleFilePath = scheduleFilePath;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -80,8 +96,8 @@ public int hashCode() {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("Gui Settings : " + guiSettings);
- sb.append("\nLocal data file location : " + addressBookFilePath);
+ sb.append("Gui Settings : ").append(guiSettings);
+ sb.append("\nLocal data file location : ").append(addressBookFilePath);
return sb.toString();
}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
index 469a2cc9a1e..14e31e0986f 100644
--- a/src/main/java/seedu/address/model/person/Address.java
+++ b/src/main/java/seedu/address/model/person/Address.java
@@ -9,13 +9,13 @@
*/
public class Address {
- public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
+ public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values";
/*
* The first character of the address must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
- public static final String VALIDATION_REGEX = "[^\\s].*";
+ public static final String VALIDATION_REGEX = "^.+$";
public final String value;
diff --git a/src/main/java/seedu/address/model/person/ArchiveStatus.java b/src/main/java/seedu/address/model/person/ArchiveStatus.java
new file mode 100644
index 00000000000..dab00d1ba88
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/ArchiveStatus.java
@@ -0,0 +1,48 @@
+package seedu.address.model.person;
+
+/**
+ * Represents the archive status of a person in the contact book.
+ */
+public class ArchiveStatus {
+
+ public static final String MESSAGE_CONSTRAINTS = "Archive status can only be '0' for not archived or "
+ + "'1' for archived.";
+ private boolean isArchived;
+
+ /**
+ * Constructor for ArchiveStatus that initializes the archive status to not archived.
+ */
+ public ArchiveStatus(boolean isArchived) {
+ this.isArchived = isArchived;
+ }
+
+ public boolean getArchiveStatus() {
+ return isArchived;
+ }
+
+ /**
+ * Sets the archive status of a person to be archived.
+ */
+ public void setArchiveStatusTrue() {
+ this.isArchived = true;
+ }
+
+ /**
+ * Sets the archive status of a person to be not archived.
+ */
+ public void setArchiveStatusFalse() {
+ this.isArchived = false;
+ }
+
+ @Override
+ public String toString() {
+ return isArchived ? "Archived" : "Not Archived";
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ArchiveStatus // instanceof handles nulls
+ && isArchived == ((ArchiveStatus) other).isArchived); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/BankDetails.java b/src/main/java/seedu/address/model/person/BankDetails.java
new file mode 100644
index 00000000000..2bb1f58f813
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/BankDetails.java
@@ -0,0 +1,73 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Person's bank details in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidBankAccount(String)}
+ */
+public class BankDetails {
+
+ public static final String MESSAGE_CONSTRAINTS = "Bank details should be in this format: "
+ + " \n"
+ + "Accepted banks and corresponding digit length: OCBC {7}, POSB {9}, UOB {10}, DBS {10}, "
+ + "Standard Chartered {10}, HSBC {any length}, Others {any length}\n"
+ + "Examples: -b posb 1234567890/ -b hsbc 172002492/ -b other maybank 712834957521";
+ public static final String DBS_UOB_STANDARD_REGEX = "(?:dbs|uob|standard chartered)\\s+\\d{10}";
+ public static final String POSB_REGEX = "posb\\s+\\d{9}";
+ public static final String OCBC_REGEX = "ocbc\\s+\\d{7}";
+ public static final String HSBC_REGEX = "hsbc\\s+\\d+";
+ public static final String OTHERS_REGEX = "other\\s+\\w+\\s+\\d+";
+
+ public static final String BLANK_REGEX = "\\s*";
+
+ public static final String VALIDATION_REGEX = DBS_UOB_STANDARD_REGEX + "|"
+ + POSB_REGEX + "|" + OCBC_REGEX + "|" + HSBC_REGEX + "|" + OTHERS_REGEX + "|" + BLANK_REGEX;
+
+ public final String value;
+
+ /**
+ * Constructs an {@code BankDetails}.
+ *
+ * @param bankDetails A valid bank account.
+ */
+ public BankDetails(String bankDetails) {
+ requireNonNull(bankDetails);
+ checkArgument(isValidBankAccount(bankDetails), MESSAGE_CONSTRAINTS);
+ value = bankDetails;
+ }
+
+ /**
+ * Returns true if a given string is a valid bank account.
+ */
+ public static boolean isValidBankAccount(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof BankDetails)) {
+ return false;
+ }
+
+ BankDetails otherBankDetails = (BankDetails) other;
+ return value.equals(otherBankDetails.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java
index 173f15b9b00..d94cb50bde0 100644
--- a/src/main/java/seedu/address/model/person/Name.java
+++ b/src/main/java/seedu/address/model/person/Name.java
@@ -10,15 +10,15 @@
public class Name {
public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
+ "Names should only contain alphanumeric characters and spaces, and it should not be blank";
/*
* The first character of the address must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+ public static final String VALIDATION_REGEX = "^(?! )[a-zA-Z0-9 ]*$";
- public final String fullName;
+ public final String value;
/**
* Constructs a {@code Name}.
@@ -28,7 +28,7 @@ public class Name {
public Name(String name) {
requireNonNull(name);
checkArgument(isValidName(name), MESSAGE_CONSTRAINTS);
- fullName = name;
+ value = name;
}
/**
@@ -41,7 +41,7 @@ public static boolean isValidName(String test) {
@Override
public String toString() {
- return fullName;
+ return value;
}
@Override
@@ -56,12 +56,12 @@ public boolean equals(Object other) {
}
Name otherName = (Name) other;
- return fullName.equals(otherName.fullName);
+ return value.equals(otherName.value);
}
@Override
public int hashCode() {
- return fullName.hashCode();
+ return value.hashCode();
}
}
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
index 62d19be2977..8a187bd5a66 100644
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
@@ -19,7 +19,7 @@ public NameContainsKeywordsPredicate(List keywords) {
@Override
public boolean test(Person person) {
return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
+ .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().value, keyword));
}
@Override
diff --git a/src/main/java/seedu/address/model/person/PayRate.java b/src/main/java/seedu/address/model/person/PayRate.java
new file mode 100644
index 00000000000..0ce40aa6143
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PayRate.java
@@ -0,0 +1,88 @@
+package seedu.address.model.person;
+
+import java.util.Objects;
+
+/**
+ * Represents a person's pay rate in the contact book
+ * A pay rate is represented as a floating-point number.
+ *
+ * Pay rates should only contain numeric values.
+ *
+ * Guarantees: immutable
+ */
+public class PayRate {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Pay rate should only contain numbers";
+
+ public final double value;
+
+ /**
+ * Constructs a {@code PayRate} with the specified pay rate value.
+ *
+ * @param payRate The pay rate value.
+ */
+ public PayRate(double payRate) {
+ this.value = payRate;
+ }
+
+ public double getPayRate() {
+ return value;
+ }
+
+ /**
+ * Returns a string representation of the pay rate.
+ *
+ * @return A string representing the pay rate.
+ */
+ @Override
+ public String toString() {
+ return "Pay Rate: $ " + value;
+ }
+
+ /**
+ * Checks if the given pay rate string is valid.
+ *
+ * @param payRate The pay rate string to be checked for validity.
+ * @return {@code true} if the pay rate string is valid, {@code false} otherwise.
+ */
+ public static boolean isValidPayRate(String payRate) {
+ if (payRate == null) {
+ return false;
+ }
+ try {
+ double rate = Double.parseDouble(payRate);
+ return rate > 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks if this pay rate is equal to another object.
+ *
+ * @param other The object to compare with.
+ * @return {@code true} if the objects are equal, {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof PayRate)) {
+ return false;
+ }
+ PayRate otherPayRate = (PayRate) other;
+ return value == otherPayRate.value;
+ }
+
+ /**
+ * Returns the hash code of the pay rate.
+ *
+ * @return The hash code of the pay rate.
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(value);
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/PayrollWrapper.java b/src/main/java/seedu/address/model/person/PayrollWrapper.java
new file mode 100644
index 00000000000..657c8e542ab
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PayrollWrapper.java
@@ -0,0 +1,56 @@
+package seedu.address.model.person;
+
+/**
+ * Represents a Person's payroll in the address book.
+ */
+public class PayrollWrapper {
+ private final Person person;
+ private double hoursWorked = 0;
+
+
+ /**
+ * Creates a PayrollWrapper with the given {@code Person} and hours worked.
+ */
+ public PayrollWrapper(Person person, double hoursWorked) {
+ this.person = person;
+ this.hoursWorked = hoursWorked;
+ }
+
+ public String getName() {
+ return person.getName().toString();
+ }
+
+ public double getHoursWorked() {
+ return hoursWorked;
+ }
+
+ public double getPay() {
+ return hoursWorked * person.getPayRate().value;
+ }
+
+ public Person getPerson() {
+ return person;
+ }
+
+ @Override
+ public int hashCode() {
+ return person.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof PayrollWrapper)) {
+ return false;
+ }
+ PayrollWrapper otherPayrollWrapper = (PayrollWrapper) other;
+ return otherPayrollWrapper.person.equals(this.person);
+ }
+
+ @Override
+ public String toString() {
+ return person.toString() + " Hours Worked: " + hoursWorked;
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
index abe8c46b535..eeee94ddd1d 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/seedu/address/model/person/Person.java
@@ -17,42 +17,82 @@
public class Person {
// Identity fields
- private final Name name;
+ private final Name firstName;
+ private final Name lastName;
private final Phone phone;
- private final Email email;
// Data fields
+ private final Sex sex;
+ private final PayRate payRate;
private final Address address;
+ private final BankDetails bankDetails;
private final Set tags = new HashSet<>();
+ private WorkHours hoursWorked;
+ private ArchiveStatus archiveStatus;
/**
* Every field must be present and not null.
*/
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
- this.name = name;
+ public Person(Name firstName, Name lastName, Phone phone, Sex sex,
+ PayRate payRate, Address address,
+ BankDetails bankDetails, WorkHours hoursWorked, Set tags, ArchiveStatus archiveStatus) {
+ requireAllNonNull(firstName, lastName, phone, address, bankDetails, tags);
+ this.firstName = firstName;
+ this.lastName = lastName;
this.phone = phone;
- this.email = email;
+ this.sex = sex;
+ this.payRate = payRate;
this.address = address;
+ this.bankDetails = bankDetails;
this.tags.addAll(tags);
+ this.hoursWorked = hoursWorked;
+ this.archiveStatus = archiveStatus;
}
public Name getName() {
- return name;
+ return new Name(firstName + " " + lastName);
+ }
+
+ public Name getFirstName() {
+ return firstName;
+ }
+
+ public Name getLastName() {
+ return lastName;
}
public Phone getPhone() {
return phone;
}
- public Email getEmail() {
- return email;
+ public Sex getSex() {
+ return sex;
+ }
+
+ public PayRate getPayRate() {
+ return payRate;
}
public Address getAddress() {
return address;
}
+ public BankDetails getBankDetails() {
+ return bankDetails;
+ }
+
+ public WorkHours getWorkHours() {
+ return hoursWorked;
+ }
+
+ public ArchiveStatus getArchiveStatus() {
+ return archiveStatus;
+ }
+
+ public void setHoursWorked(WorkHours hoursWorked) {
+ this.hoursWorked = hoursWorked;
+ }
+
/**
* Returns an immutable tag set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
@@ -71,7 +111,7 @@ public boolean isSamePerson(Person otherPerson) {
}
return otherPerson != null
- && otherPerson.getName().equals(getName());
+ && otherPerson.phone.equals(phone);
}
/**
@@ -90,28 +130,36 @@ public boolean equals(Object other) {
}
Person otherPerson = (Person) other;
- return name.equals(otherPerson.name)
- && phone.equals(otherPerson.phone)
- && email.equals(otherPerson.email)
- && address.equals(otherPerson.address)
- && tags.equals(otherPerson.tags);
+ return getName().equals(otherPerson.getName())
+ && phone.equals(otherPerson.phone)
+ && sex.equals(otherPerson.sex)
+ && payRate.equals(otherPerson.payRate)
+ && address.equals(otherPerson.address)
+ && bankDetails.equals(otherPerson.bankDetails)
+ && tags.equals(otherPerson.tags)
+ && archiveStatus.equals(otherPerson.archiveStatus);
}
@Override
public int hashCode() {
// use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
+ return Objects.hash(firstName, lastName, phone, sex, payRate, address, bankDetails,
+ tags);
}
@Override
public String toString() {
return new ToStringBuilder(this)
- .add("name", name)
- .add("phone", phone)
- .add("email", email)
- .add("address", address)
- .add("tags", tags)
- .toString();
+ .add("firstName", firstName)
+ .add("lastName", lastName)
+ .add("phone", phone)
+ .add("sex", sex)
+ .add("payRate", payRate)
+ .add("address", address)
+ .add("bankDetails", bankDetails)
+ .add("tags", tags)
+ .add("archiveStatus", archiveStatus)
+ .toString();
}
}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java
index d733f63d739..8da75dd199e 100644
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ b/src/main/java/seedu/address/model/person/Phone.java
@@ -11,8 +11,8 @@ public class Phone {
public static final String MESSAGE_CONSTRAINTS =
- "Phone numbers should only contain numbers, and it should be at least 3 digits long";
- public static final String VALIDATION_REGEX = "\\d{3,}";
+ "Phone numbers should only contain numbers, and it should be only 8 digits long";
+ public static final String VALIDATION_REGEX = "^\\d{8}$";
public final String value;
/**
diff --git a/src/main/java/seedu/address/model/person/Sex.java b/src/main/java/seedu/address/model/person/Sex.java
new file mode 100644
index 00000000000..dec82d7c61b
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Sex.java
@@ -0,0 +1,61 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Person's sex in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidSex(String)}
+ */
+public class Sex {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Sex should only be either 'm' or 'f'.";
+ public static final String VALIDATION_REGEX = "^[mf]$";
+ public final String value;
+
+
+ /**
+ * Constructs an {@code Sex}.
+ *
+ * @param sex A valid sex.
+ */
+ public Sex(String sex) {
+ requireNonNull(sex);
+ checkArgument(isValidSex(sex), MESSAGE_CONSTRAINTS);
+ value = sex;
+ }
+
+ /**
+ * Returns true if a given string is a valid sex.
+ */
+ public static boolean isValidSex(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Sex)) {
+ return false;
+ }
+
+ Sex otherSex = (Sex) other;
+ return value.equals(otherSex.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
index cc0a68d79f9..4cad0fbe65e 100644
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ b/src/main/java/seedu/address/model/person/UniquePersonList.java
@@ -79,6 +79,44 @@ public void remove(Person toRemove) {
}
}
+ /**
+ * Archives the equivalent person from the list.
+ * The person must exist in the list.
+ */
+ public void archive(Person target, Person archivedPerson) {
+ requireAllNonNull(target);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new PersonNotFoundException();
+ }
+
+ if (!target.isSamePerson(archivedPerson) && contains(archivedPerson)) {
+ throw new DuplicatePersonException();
+ }
+
+ internalList.set(index, archivedPerson);
+ }
+
+ /**
+ * Unarchives the equivalent person from the list.
+ * The person must exist in the list.
+ */
+ public void unarchive(Person target, Person unarchivedPerson) {
+ requireAllNonNull(target);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new PersonNotFoundException();
+ }
+
+ if (!target.isSamePerson(unarchivedPerson) && contains(unarchivedPerson)) {
+ throw new DuplicatePersonException();
+ }
+
+ internalList.set(index, unarchivedPerson);
+ }
+
public void setPersons(UniquePersonList replacement) {
requireNonNull(replacement);
internalList.setAll(replacement.internalList);
@@ -104,6 +142,32 @@ public ObservableList asUnmodifiableObservableList() {
return internalUnmodifiableList;
}
+ /**
+ * Returns an ObservableList of unarchived persons.
+ */
+ public ObservableList getUnarchivedPersonList() {
+ ObservableList unarchivedPersons = FXCollections.observableArrayList();
+ for (Person person : internalList) {
+ if (!person.getArchiveStatus().getArchiveStatus()) {
+ unarchivedPersons.add(person);
+ }
+ }
+ return FXCollections.unmodifiableObservableList(unarchivedPersons);
+ }
+
+ /**
+ * Returns an ObservableList of archived persons.
+ */
+ public ObservableList getArchivedPersonList() {
+ ObservableList archivedPersons = FXCollections.observableArrayList();
+ for (Person person : internalList) {
+ if (person.getArchiveStatus().getArchiveStatus()) {
+ archivedPersons.add(person);
+ }
+ }
+ return FXCollections.unmodifiableObservableList(archivedPersons);
+ }
+
@Override
public Iterator iterator() {
return internalList.iterator();
diff --git a/src/main/java/seedu/address/model/person/WorkHours.java b/src/main/java/seedu/address/model/person/WorkHours.java
new file mode 100644
index 00000000000..3f22ae38334
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/WorkHours.java
@@ -0,0 +1,54 @@
+package seedu.address.model.person;
+
+import java.util.Objects;
+
+/**
+ * Represents the work hours of a person.
+ */
+public class WorkHours {
+ public static final String MESSAGE_CONSTRAINTS = "Hours clocked can only contain numbers.";
+ public final int hoursWorked;
+
+ /**
+ * Constructs a {@code WorkHours} object with zero hours worked.
+ */
+ public WorkHours() {
+ this.hoursWorked = 0;
+ }
+
+ public WorkHours(int hoursWorked) {
+ this.hoursWorked = hoursWorked;
+ }
+
+
+ /**
+ * Returns the number of hours worked.
+ *
+ * @return The number of hours worked.
+ */
+ public int getHoursWorked() {
+ return hoursWorked;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ WorkHours workHours = (WorkHours) o;
+ return hoursWorked == workHours.hoursWorked;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(hoursWorked);
+ }
+
+ @Override
+ public String toString() {
+ return hoursWorked + " hours clocked";
+ }
+}
diff --git a/src/main/java/seedu/address/model/schedule/Schedule.java b/src/main/java/seedu/address/model/schedule/Schedule.java
new file mode 100644
index 00000000000..01d5c0bc94c
--- /dev/null
+++ b/src/main/java/seedu/address/model/schedule/Schedule.java
@@ -0,0 +1,43 @@
+package seedu.address.model.schedule;
+
+import java.time.LocalDate;
+import java.util.Map;
+import java.util.Set;
+
+import seedu.address.model.person.Person;
+
+/**
+ * Represents a Schedule that maps lists of Persons to dates.
+ */
+public interface Schedule {
+ /**
+ * Returns the schedule as a Map.
+ */
+ Set getScheduleDates();
+
+ /**
+ * Adds a Person to the schedule on the given date.
+ */
+ void addPerson(Person person, LocalDate date);
+
+ /**
+ * Deletes a Person from the schedule on the given date.
+ */
+ void deletePerson(Person person, LocalDate date);
+
+ /**
+ * Adds a ScheduleDate to the schedule.
+ */
+ void addScheduleDate(ScheduleDate scheduleDate);
+
+ /**
+ * Resets the existing data of this {@code Schedule} with {@code newData}.
+ */
+ void resetData(Schedule newData);
+
+
+ /**
+ * Returns the number of hours worked by each person in the schedule between the given dates.
+ */
+ Map getHoursWorked(LocalDate startDate, LocalDate endDate);
+}
diff --git a/src/main/java/seedu/address/model/schedule/ScheduleDate.java b/src/main/java/seedu/address/model/schedule/ScheduleDate.java
new file mode 100644
index 00000000000..45e4fdb1cbf
--- /dev/null
+++ b/src/main/java/seedu/address/model/schedule/ScheduleDate.java
@@ -0,0 +1,71 @@
+package seedu.address.model.schedule;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+
+import seedu.address.model.person.Person;
+
+/**
+ * Represents a date in the schedule.
+ */
+public class ScheduleDate {
+ private final LocalDate date;
+ private final List persons;
+
+ /**
+ * Constructs a {@code ScheduleDate} with the given {@code LocalDate}.
+ */
+ public ScheduleDate(LocalDate date) {
+ this.date = date;
+ this.persons = new ArrayList<>();
+ }
+
+ /**
+ * Constructs a {@code ScheduleDate} with the given {@code LocalDate} and {@code List}.
+ */
+ public LocalDate getDate() {
+ return date;
+ }
+
+ /**
+ * Returns the list of people working on this date.
+ */
+ public List getPersons() {
+ return persons;
+ }
+
+ /**
+ * Adds someone working on this date.
+ */
+ public void addPerson(Person person) {
+ persons.add(person);
+ }
+
+ /**
+ * Removes someone working on this date.
+ */
+ public void removePerson(Person person) {
+ persons.remove(person);
+ }
+
+ /**
+ * Returns true if the person is working on this date.
+ */
+ public boolean hasPerson(Person person) {
+ return persons.contains(person);
+ }
+
+ @Override
+ public int hashCode() {
+ return date.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ScheduleDate // instanceof handles nulls
+ && date.equals(((ScheduleDate) other).date)) // state check
+ && persons.equals(((ScheduleDate) other).persons);
+ }
+}
diff --git a/src/main/java/seedu/address/model/schedule/ScheduleManager.java b/src/main/java/seedu/address/model/schedule/ScheduleManager.java
new file mode 100644
index 00000000000..6b51c8b357c
--- /dev/null
+++ b/src/main/java/seedu/address/model/schedule/ScheduleManager.java
@@ -0,0 +1,111 @@
+package seedu.address.model.schedule;
+
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import seedu.address.model.person.Person;
+
+/**
+ * Represents a Schedule that maps lists of Persons to dates.
+ */
+public class ScheduleManager implements Schedule {
+ // The schedule is a set of ScheduleDates.
+ private final Set schedule;
+
+ /**
+ * Creates a MonthSchedule with an empty schedule.
+ */
+ public ScheduleManager() {
+ this.schedule = new HashSet<>();
+ }
+
+ @Override
+ public Set getScheduleDates() {
+ return schedule;
+ }
+
+ @Override
+ public void addPerson(Person person, LocalDate date) {
+ for (ScheduleDate scheduleDate : schedule) {
+ if (scheduleDate.getDate().equals(date)) {
+ if (!scheduleDate.hasPerson(person)) {
+ scheduleDate.addPerson(person);
+ }
+ return;
+ }
+ }
+ ScheduleDate newScheduleDate = new ScheduleDate(date);
+ newScheduleDate.addPerson(person);
+ schedule.add(newScheduleDate);
+ }
+
+ /**
+ * Adds a ScheduleDate to the schedule.
+ * Used only by JsonAdaptedSchedule to convert JSON data to a Schedule,
+ * so there is no need to check for duplicates.
+ * @param scheduleDate the ScheduleDate to add
+ */
+ @Override
+ public void addScheduleDate(ScheduleDate scheduleDate) {
+ schedule.add(scheduleDate);
+ }
+
+ @Override
+ public void deletePerson(Person person, LocalDate date) {
+ for (ScheduleDate scheduleDate : schedule) {
+ if (scheduleDate.getDate().equals(date)) {
+ if (scheduleDate.hasPerson(person)) {
+ scheduleDate.removePerson(person);
+ }
+ return;
+ }
+ }
+ }
+
+ @Override
+ public Map getHoursWorked(LocalDate startDate, LocalDate endDate) {
+ Map hoursWorked = new HashMap<>();
+ for (ScheduleDate scheduleDate : schedule) {
+ if (isAfterOrEqual(scheduleDate.getDate(), startDate) && isBeforeOrEqual(scheduleDate.getDate(), endDate)) {
+ for (Person person : scheduleDate.getPersons()) {
+ if (!hoursWorked.containsKey(person)) {
+ hoursWorked.put(person, 0.0);
+ }
+ hoursWorked.put(person, hoursWorked.get(person) + 8.0);
+ }
+ }
+ }
+ return hoursWorked;
+ }
+
+ @Override
+ public void resetData(Schedule newData) {
+ schedule.clear();
+ if (newData != null) {
+ schedule.addAll(newData.getScheduleDates());
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ScheduleManager // instanceof handles nulls
+ && schedule.equals(((ScheduleManager) other).schedule));
+ }
+ private boolean isAfterOrEqual(LocalDate date1, LocalDate date2) {
+ if (date1 == null || date2 == null) {
+ return false;
+ }
+ return date1.isAfter(date2) || date1.isEqual(date2);
+ }
+
+ private boolean isBeforeOrEqual(LocalDate date1, LocalDate date2) {
+ if (date1 == null || date2 == null) {
+ return false;
+ }
+ return date1.isBefore(date2) || date1.isEqual(date2);
+ }
+}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..91c3ce80afb 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -1,5 +1,6 @@
package seedu.address.model.util;
+import java.time.LocalDate;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
@@ -7,10 +8,16 @@
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.ArchiveStatus;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
+import seedu.address.model.person.WorkHours;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleManager;
import seedu.address.model.tag.Tag;
/**
@@ -19,24 +26,72 @@
public class SampleDataUtil {
public static Person[] getSamplePersons() {
return new Person[] {
- new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
+ new Person(
+ new Name("Alex"),
+ new Name("Yeoh"),
+ new Phone("87438807"),
+ new Sex("m"),
+ new PayRate(14.5),
new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
- new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
+ new BankDetails("dbs 1234567890"),
+ new WorkHours(),
+ getTagSet("friends"),
+ new ArchiveStatus(false)),
+ new Person(
+ new Name("Bernice"),
+ new Name("Yu"),
+ new Phone("99272758"),
+ new Sex("f"),
+ new PayRate(16),
new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- getTagSet("colleagues", "friends")),
- new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
+ new BankDetails("ocbc 1234567"),
+ new WorkHours(),
+ getTagSet("colleagues", "friends"),
+ new ArchiveStatus(false)),
+ new Person(
+ new Name("Charlotte"),
+ new Name("Oliveiro"),
+ new Phone("93210283"),
+ new Sex("f"),
+ new PayRate(20),
new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
- new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
+ new BankDetails("hsbc 0987654321"),
+ new WorkHours(),
+ getTagSet("neighbours"),
+ new ArchiveStatus(false)),
+ new Person(
+ new Name("David"),
+ new Name("Li"),
+ new Phone("91031282"),
+ new Sex("m"),
+ new PayRate(18.5),
new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
- new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
+ new BankDetails("uob 8888777700"),
+ new WorkHours(),
+ getTagSet("family"),
+ new ArchiveStatus(false)),
+ new Person(
+ new Name("Irfan"),
+ new Name("Ibrahim"),
+ new Phone("92492021"),
+ new Sex("m"),
+ new PayRate(16.5),
new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
- new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
+ new BankDetails("posb 369369369"),
+ new WorkHours(),
+ getTagSet("classmates"),
+ new ArchiveStatus(false)),
+ new Person(
+ new Name("Roy"),
+ new Name("Balakrishnan"),
+ new Phone("92624417"),
+ new Sex("m"),
+ new PayRate(10),
new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
+ new BankDetails("ocbc 7654321"),
+ new WorkHours(),
+ getTagSet("colleagues"),
+ new ArchiveStatus(false))
};
}
@@ -48,13 +103,24 @@ public static ReadOnlyAddressBook getSampleAddressBook() {
return sampleAb;
}
+ public static Schedule getSampleSchedule() {
+ Schedule sampleSchedule = new ScheduleManager();
+ LocalDate date = LocalDate.now();
+ int count = 0;
+ for (Person samplePerson : getSamplePersons()) {
+ if (count % 3 == 0) {
+ date = date.plusDays(1);
+ }
+ sampleSchedule.addPerson(samplePerson, date);
+ }
+ return sampleSchedule;
+ }
+
/**
* Returns a tag set containing the list of strings given.
*/
public static Set getTagSet(String... strings) {
- return Arrays.stream(strings)
- .map(Tag::new)
- .collect(Collectors.toSet());
+ return Arrays.stream(strings).map(Tag::new).collect(Collectors.toSet());
}
}
diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java
index f2e015105ae..490685ad07b 100644
--- a/src/main/java/seedu/address/storage/AddressBookStorage.java
+++ b/src/main/java/seedu/address/storage/AddressBookStorage.java
@@ -41,5 +41,4 @@ public interface AddressBookStorage {
* @see #saveAddressBook(ReadOnlyAddressBook)
*/
void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException;
-
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
index bd1ca0f56c8..b0034ab4cca 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
@@ -11,10 +11,14 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.ArchiveStatus;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
+import seedu.address.model.person.WorkHours;
import seedu.address.model.tag.Tag;
/**
@@ -24,39 +28,61 @@ class JsonAdaptedPerson {
public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
- private final String name;
+ private final String firstName;
+ private final String lastName;
private final String phone;
- private final String email;
+ private final String sex;
+ private final double payRate;
private final String address;
+ private final String bankDetails;
private final List tags = new ArrayList<>();
+ private final int workHours;
+ private final boolean archiveStatus;
/**
* Constructs a {@code JsonAdaptedPerson} with the given person details.
*/
@JsonCreator
- public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tags") List tags) {
- this.name = name;
+ public JsonAdaptedPerson(@JsonProperty("firstName") String firstName,
+ @JsonProperty("lastName") String lastName,
+ @JsonProperty("phone") String phone,
+ @JsonProperty("sex") String sex,
+ @JsonProperty("payRate") double payRate,
+ @JsonProperty("address") String address,
+ @JsonProperty("bankDetails") String bankDetails,
+ @JsonProperty("workHours") int workHours,
+ @JsonProperty("tags") List tags,
+ @JsonProperty("archiveStatus") boolean archiveStatus) {
+ this.firstName = firstName;
+ this.lastName = lastName;
this.phone = phone;
- this.email = email;
+ this.sex = sex;
+ this.payRate = payRate;
this.address = address;
+ this.bankDetails = bankDetails;
+ this.workHours = workHours;
if (tags != null) {
this.tags.addAll(tags);
}
+ this.archiveStatus = archiveStatus;
}
/**
* Converts a given {@code Person} into this class for Jackson use.
*/
public JsonAdaptedPerson(Person source) {
- name = source.getName().fullName;
+ firstName = source.getFirstName().value;
+ lastName = source.getLastName().value;
phone = source.getPhone().value;
- email = source.getEmail().value;
+ sex = source.getSex().value;
+ payRate = source.getPayRate().getPayRate();
address = source.getAddress().value;
+ bankDetails = source.getBankDetails().value;
+ workHours = source.getWorkHours().getHoursWorked();
+ archiveStatus = source.getArchiveStatus().getArchiveStatus();
tags.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList()));
}
/**
@@ -70,13 +96,21 @@ public Person toModelType() throws IllegalValueException {
personTags.add(tag.toModelType());
}
- if (name == null) {
+ if (firstName == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
}
- if (!Name.isValidName(name)) {
+ if (!Name.isValidName(firstName)) {
throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
}
- final Name modelName = new Name(name);
+ final Name modelFirstName = new Name(firstName);
+
+ if (lastName == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
+ }
+ if (!Name.isValidName(lastName)) {
+ throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
+ }
+ final Name modelLastName = new Name(lastName);
if (phone == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()));
@@ -86,13 +120,15 @@ public Person toModelType() throws IllegalValueException {
}
final Phone modelPhone = new Phone(phone);
- if (email == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
+ if (sex == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Sex.class.getSimpleName()));
}
- if (!Email.isValidEmail(email)) {
- throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
+ if (!Sex.isValidSex(sex)) {
+ throw new IllegalValueException(Sex.MESSAGE_CONSTRAINTS);
}
- final Email modelEmail = new Email(email);
+ final Sex modelSex = new Sex(sex);
+
+ final PayRate modelPayRate = new PayRate(payRate);
if (address == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()));
@@ -102,8 +138,24 @@ public Person toModelType() throws IllegalValueException {
}
final Address modelAddress = new Address(address);
+ if (bankDetails == null) {
+ throw new IllegalValueException(
+ String.format(MISSING_FIELD_MESSAGE_FORMAT, BankDetails.class.getSimpleName()));
+ }
+ if (!BankDetails.isValidBankAccount(bankDetails)) {
+ throw new IllegalValueException(BankDetails.MESSAGE_CONSTRAINTS);
+ }
+ final BankDetails modelBankDetails = new BankDetails(bankDetails);
+
+ final WorkHours modelWorkHours = new WorkHours(workHours);
+
final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
+
+ final ArchiveStatus modelArchiveStatus = new ArchiveStatus(archiveStatus);
+
+ return new Person(modelFirstName, modelLastName, modelPhone, modelSex, modelPayRate,
+ modelAddress,
+ modelBankDetails, modelWorkHours, modelTags, modelArchiveStatus);
}
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedScheduleDate.java b/src/main/java/seedu/address/storage/JsonAdaptedScheduleDate.java
new file mode 100644
index 00000000000..97ef3047aeb
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedScheduleDate.java
@@ -0,0 +1,62 @@
+package seedu.address.storage;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.person.Person;
+import seedu.address.model.schedule.ScheduleDate;
+
+/**
+ * Jackson-friendly version of {@link ScheduleDate}.
+ */
+class JsonAdaptedScheduleDate {
+ private final String date;
+ private final List persons = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedScheduleDate} with the given person details.
+ */
+ @JsonCreator
+ public JsonAdaptedScheduleDate(@JsonProperty("date") String date,
+ @JsonProperty("persons") List persons) {
+ this.date = date;
+ if (persons != null) {
+ this.persons.addAll(persons);
+ }
+ }
+
+ /**
+ * Converts a given {@code ScheduleDate} into this class for Jackson use.
+ */
+ public JsonAdaptedScheduleDate(ScheduleDate source) {
+ date = source.getDate().toString();
+ persons.addAll(source.getPersons().stream()
+ .map(JsonAdaptedPerson::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted person object into the model's {@code ScheduleDate} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted person.
+ */
+ public ScheduleDate toModelType() throws IllegalValueException {
+ final List persons = new ArrayList<>();
+ for (JsonAdaptedPerson person : this.persons) {
+ persons.add(person.toModelType());
+ }
+ final LocalDate modelDate = LocalDate.parse(date);
+ ScheduleDate scheduleDate = new ScheduleDate(modelDate);
+ for (Person person : persons) {
+ scheduleDate.addPerson(person);
+ }
+ return scheduleDate;
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
index 41e06f264e1..2a33c759770 100644
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ b/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
@@ -31,6 +31,10 @@ public Path getAddressBookFilePath() {
return filePath;
}
+ public Path getArchiveBookFilePath() {
+ return filePath;
+ }
+
@Override
public Optional readAddressBook() throws DataLoadingException {
return readAddressBook(filePath);
diff --git a/src/main/java/seedu/address/storage/JsonScheduleStorage.java b/src/main/java/seedu/address/storage/JsonScheduleStorage.java
new file mode 100644
index 00000000000..c3c8373b676
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonScheduleStorage.java
@@ -0,0 +1,80 @@
+package seedu.address.storage;
+
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.commons.exceptions.DataLoadingException;
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.commons.util.FileUtil;
+import seedu.address.commons.util.JsonUtil;
+import seedu.address.model.schedule.Schedule;
+
+/**
+ * A class to access AddressBook data stored as a json file on the hard disk.
+ */
+public class JsonScheduleStorage implements ScheduleStorage {
+
+ private static final Logger logger = LogsCenter.getLogger(JsonScheduleStorage.class);
+
+ private Path filePath;
+
+ public JsonScheduleStorage(Path filePath) {
+ this.filePath = filePath;
+ }
+
+ public Path getScheduleFilePath() {
+ return filePath;
+ }
+
+ @Override
+ public Optional readSchedule() throws DataLoadingException {
+ return readSchedule(filePath);
+ }
+
+ /**
+ * Similar to {@link #readSchedule()}.
+ *
+ * @param filePath location of the data. Cannot be null.
+ * @throws DataLoadingException if loading the data from storage failed.
+ */
+ public Optional readSchedule(Path filePath) throws DataLoadingException {
+ requireNonNull(filePath);
+
+ Optional jsonSchedule = JsonUtil.readJsonFile(
+ filePath, JsonSerializableSchedule.class);
+ if (!jsonSchedule.isPresent()) {
+ return Optional.empty();
+ }
+
+ try {
+ return Optional.of(jsonSchedule.get().toModelType());
+ } catch (IllegalValueException ive) {
+ logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
+ throw new DataLoadingException(ive);
+ }
+ }
+
+ @Override
+ public void saveSchedule(Schedule schedule) throws IOException {
+ saveSchedule(schedule, filePath);
+ }
+
+ /**
+ * Similar to {@link #saveSchedule(Schedule)}.
+ *
+ * @param filePath location of the data. Cannot be null.
+ */
+ public void saveSchedule(Schedule schedule, Path filePath) throws IOException {
+ requireNonNull(schedule);
+ requireNonNull(filePath);
+
+ FileUtil.createIfMissing(filePath);
+ JsonUtil.saveJsonFile(new JsonSerializableSchedule(schedule), filePath);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableSchedule.java b/src/main/java/seedu/address/storage/JsonSerializableSchedule.java
new file mode 100644
index 00000000000..a1d792997ec
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonSerializableSchedule.java
@@ -0,0 +1,56 @@
+package seedu.address.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleDate;
+import seedu.address.model.schedule.ScheduleManager;
+
+/**
+ * An Immutable Schedule that is serializable to JSON format.
+ */
+@JsonRootName(value = "schedule")
+class JsonSerializableSchedule {
+
+ private final List scheduleDates = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonSerializableAddressBook} with the given persons.
+ */
+ @JsonCreator
+ public JsonSerializableSchedule(@JsonProperty("scheduleDates") List scheduleDates) {
+ this.scheduleDates.addAll(scheduleDates);
+ }
+
+ /**
+ * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
+ *
+ * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}.
+ */
+ public JsonSerializableSchedule(Schedule source) {
+ scheduleDates.addAll(source.getScheduleDates().stream()
+ .map(JsonAdaptedScheduleDate::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this address book into the model's {@code AddressBook} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated.
+ */
+ public Schedule toModelType() throws IllegalValueException {
+ Schedule schedule = new ScheduleManager();
+ for (JsonAdaptedScheduleDate jsonAdaptedScheduleDate : scheduleDates) {
+ ScheduleDate scheduleDate = jsonAdaptedScheduleDate.toModelType();
+ schedule.addScheduleDate(scheduleDate);
+ }
+ return schedule;
+ }
+}
diff --git a/src/main/java/seedu/address/storage/ScheduleStorage.java b/src/main/java/seedu/address/storage/ScheduleStorage.java
new file mode 100644
index 00000000000..5044b75bf41
--- /dev/null
+++ b/src/main/java/seedu/address/storage/ScheduleStorage.java
@@ -0,0 +1,45 @@
+package seedu.address.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.address.commons.exceptions.DataLoadingException;
+import seedu.address.model.schedule.Schedule;
+
+/**
+ * Represents a storage for {@link seedu.address.model.schedule.Schedule}.
+ */
+public interface ScheduleStorage {
+
+ /**
+ * Returns the file path of the data file.
+ */
+ Path getScheduleFilePath();
+
+ /**
+ * Returns Schedule data as a {@link Schedule}.
+ * Returns {@code Optional.empty()} if storage file is not found.
+ *
+ * @throws DataLoadingException if loading the data from storage failed.
+ */
+ Optional readSchedule() throws DataLoadingException;
+
+ /**
+ * @see #getScheduleFilePath()
+ */
+ Optional readSchedule(Path filePath) throws DataLoadingException;
+
+ /**
+ * Saves the given {@link Schedule} to the storage.
+ * @param schedule cannot be null.
+ * @throws IOException if there was any problem writing to the file.
+ */
+ void saveSchedule(Schedule schedule) throws IOException;
+
+ /**
+ * @see #saveSchedule(Schedule)
+ */
+ void saveSchedule(Schedule schedule, Path filePath) throws IOException;
+
+}
diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java
index 9fba0c7a1d6..0fdcd896ca5 100644
--- a/src/main/java/seedu/address/storage/Storage.java
+++ b/src/main/java/seedu/address/storage/Storage.java
@@ -8,11 +8,12 @@
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
+import seedu.address.model.schedule.Schedule;
/**
* API of the Storage component
*/
-public interface Storage extends AddressBookStorage, UserPrefsStorage {
+public interface Storage extends AddressBookStorage, UserPrefsStorage, ScheduleStorage {
@Override
Optional readUserPrefs() throws DataLoadingException;
@@ -29,4 +30,12 @@ public interface Storage extends AddressBookStorage, UserPrefsStorage {
@Override
void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
+ @Override
+ Path getScheduleFilePath();
+
+ @Override
+ Optional readSchedule() throws DataLoadingException;
+
+ @Override
+ void saveSchedule(Schedule schedule) throws IOException;
}
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java
index 8b84a9024d5..9e39b0604a0 100644
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ b/src/main/java/seedu/address/storage/StorageManager.java
@@ -10,6 +10,7 @@
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
+import seedu.address.model.schedule.Schedule;
/**
* Manages storage of AddressBook data in local storage.
@@ -19,13 +20,17 @@ public class StorageManager implements Storage {
private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
private AddressBookStorage addressBookStorage;
private UserPrefsStorage userPrefsStorage;
+ private ScheduleStorage scheduleStorage;
/**
- * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}.
+ * Creates a {@code StorageManager} with the given {@code AddressBookStorage}, {@code UserPrefStorage},
+ * and {@code ScheduleStorage}.
*/
- public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) {
+ public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage,
+ ScheduleStorage scheduleStorage) {
this.addressBookStorage = addressBookStorage;
this.userPrefsStorage = userPrefsStorage;
+ this.scheduleStorage = scheduleStorage;
}
// ================ UserPrefs methods ==============================
@@ -45,7 +50,6 @@ public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
userPrefsStorage.saveUserPrefs(userPrefs);
}
-
// ================ AddressBook methods ==============================
@Override
@@ -75,4 +79,32 @@ public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) thro
addressBookStorage.saveAddressBook(addressBook, filePath);
}
+ // ================ Schedule methods ==============================
+ @Override
+ public Path getScheduleFilePath() {
+ return scheduleStorage.getScheduleFilePath();
+ }
+
+ @Override
+ public Optional readSchedule() throws DataLoadingException {
+ return readSchedule(scheduleStorage.getScheduleFilePath());
+ }
+
+ @Override
+ public Optional readSchedule(Path filePath) throws DataLoadingException {
+ logger.fine("Attempting to read data from file: " + filePath);
+ return scheduleStorage.readSchedule(filePath);
+ }
+
+ @Override
+ public void saveSchedule(Schedule schedule) throws IOException {
+ saveSchedule(schedule, scheduleStorage.getScheduleFilePath());
+ }
+
+ @Override
+ public void saveSchedule(Schedule schedule, Path filePath) throws IOException {
+ logger.fine("Attempting to write to data file: " + filePath);
+ scheduleStorage.saveSchedule(schedule, filePath);
+ }
+
}
diff --git a/src/main/java/seedu/address/ui/Calendar.java b/src/main/java/seedu/address/ui/Calendar.java
new file mode 100644
index 00000000000..455d98b26b8
--- /dev/null
+++ b/src/main/java/seedu/address/ui/Calendar.java
@@ -0,0 +1,156 @@
+/*
+ * Adapted from Da9el00's Calendar.fxml
+ * https://gist.github.com/Da9el00/f4340927b8ba6941eb7562a3306e93b6
+ */
+
+package seedu.address.ui;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.format.TextStyle;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javafx.fxml.FXML;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.scene.text.Text;
+import seedu.address.model.person.Person;
+import seedu.address.model.schedule.ScheduleDate;
+
+/**
+ * A graphic calendar that displays the schedule of a given month.
+ */
+public class Calendar extends UiPart {
+ private static final String FXML = "Calendar.fxml";
+
+ // Number of weeks to display in the calendar
+ private static int numberOfWeeks = 4;
+
+ private final LocalDate today;
+ private final Set scheduleDates;
+
+ @FXML
+ private FlowPane calendar;
+
+ /**
+ * Creates a calendar with the given schedule dates.
+ * @param scheduleDates Schedule dates to display in the calendar.
+ */
+ public Calendar(Set scheduleDates) {
+ super(FXML);
+ today = LocalDate.now();
+ this.scheduleDates = scheduleDates;
+ drawCalendar();
+ }
+
+ /**
+ * Creates a calendar with the given schedule dates and today's date.
+ */
+ private void drawCalendar() {
+ double calendarWidth = calendar.getPrefWidth();
+ assert(calendarWidth >= 0);
+ double calendarHeight = calendar.getPrefHeight();
+ assert(calendarHeight >= 0);
+ double strokeWidth = 1;
+ double spacingH = calendar.getHgap();
+ assert(spacingH >= 0);
+ double spacingV = calendar.getVgap();
+ assert(spacingV >= 0);
+
+ // List of activities for a given month
+ Map scheduleDateMap = createCalendarMap();
+
+ Month month = today.getMonth();
+ int day = today.getDayOfMonth() - today.getDayOfWeek().getValue();
+ if (day <= 0) {
+ month = today.getMonth().minus(1);
+ day = month.maxLength() + day;
+ }
+ int currentMonthMaxDay = month.maxLength();
+
+ for (int i = 0; i < numberOfWeeks; i++) {
+ for (int j = 0; j < 7; j++) {
+ StackPane stackPane = new StackPane();
+ Rectangle rectangle = new Rectangle();
+ rectangle.setFill(Color.TRANSPARENT);
+ rectangle.setStroke(Color.BLACK);
+ rectangle.setStrokeWidth(strokeWidth);
+ double rectangleWidth = (calendarWidth / 7) - strokeWidth - spacingH;
+ rectangle.setWidth(rectangleWidth);
+ double rectangleHeight = (calendarHeight / numberOfWeeks) - strokeWidth - spacingV;
+ rectangle.setHeight(rectangleHeight);
+ stackPane.getChildren().add(rectangle);
+ String dayMonth = day + " " + month.getDisplayName(TextStyle.FULL, Locale.ENGLISH);
+ ScheduleDate scheduleDate = scheduleDateMap.get(LocalDate.of(today.getYear(), month, day));
+ Text date = new Text(dayMonth);
+ double textTranslationY = -(rectangleHeight / 2) * 0.75;
+ date.setTranslateY(textTranslationY);
+ stackPane.getChildren().add(date);
+ if (scheduleDate != null) {
+ createCalendarActivity(scheduleDate, rectangleHeight, rectangleWidth, stackPane);
+ }
+ if (today.getDayOfMonth() == day && today.getMonth() == month) {
+ rectangle.setStroke(Color.BLUE);
+ }
+ calendar.getChildren().add(stackPane);
+ day++;
+ if (day > currentMonthMaxDay) {
+ day = 1;
+ month = month.plus(1);
+ currentMonthMaxDay = month.maxLength();
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a calendar activity for a given date.
+ * @param scheduleDate Schedule date to create the calendar activity for.
+ * @param rectangleHeight Height of the rectangle.
+ * @param rectangleWidth Width of the rectangle.
+ * @param stackPane Stack pane to add the calendar activity to.
+ */
+ private void createCalendarActivity(ScheduleDate scheduleDate, double rectangleHeight, double rectangleWidth,
+ StackPane stackPane) {
+ VBox calendarActivityBox = new VBox();
+ List persons = scheduleDate.getPersons();
+ List personNames = persons.stream()
+ .map(Person::getName)
+ .map(x -> x.value)
+ .collect(Collectors.toList());
+ for (int k = 0; k < persons.size(); k++) {
+ Text text = new Text(personNames.get(k));
+ calendarActivityBox.getChildren().add(text);
+ }
+ calendarActivityBox.setTranslateY((rectangleHeight / 2) * 0.20);
+ calendarActivityBox.setMaxWidth(rectangleWidth * 0.8);
+ calendarActivityBox.setMaxHeight(rectangleHeight * 0.65);
+ stackPane.getChildren().add(calendarActivityBox);
+ }
+
+ /**
+ * Creates a map of schedule dates with the date as the key.
+ * @return Map of schedule dates with the date as the key.
+ */
+ private Map createCalendarMap() {
+ return scheduleDates.stream().collect(
+ Collectors.toMap(ScheduleDate::getDate, x -> x));
+ }
+
+ /**
+ * Sets the number of weeks to display in the calendar.
+ * @param numberOfWeeks Number of weeks to display in the calendar.
+ */
+ public static void setNumberOfWeeks(int numberOfWeeks) {
+ assert(numberOfWeeks > 0);
+ Calendar.numberOfWeeks = numberOfWeeks;
+ }
+}
diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/address/ui/CommandBox.java
index 9e75478664b..48b7afe84d7 100644
--- a/src/main/java/seedu/address/ui/CommandBox.java
+++ b/src/main/java/seedu/address/ui/CommandBox.java
@@ -37,7 +37,7 @@ public CommandBox(CommandExecutor commandExecutor) {
@FXML
private void handleCommandEntered() {
String commandText = commandTextField.getText();
- if (commandText.equals("")) {
+ if ("".equals(commandText)) {
return;
}
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/address/ui/HelpWindow.java
index 3f16b2fcf26..5ac8b37310d 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/seedu/address/ui/HelpWindow.java
@@ -15,7 +15,7 @@
*/
public class HelpWindow extends UiPart {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
+ public static final String USERGUIDE_URL = "https://ay2324s2-cs2103t-t17-4.github.io/tp/UserGuide.html";
public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
index 79e74ef37c0..03425d42f78 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/address/ui/MainWindow.java
@@ -9,6 +9,7 @@
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
+import javafx.scene.text.Text;
import javafx.stage.Stage;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
@@ -41,6 +42,9 @@ public class MainWindow extends UiPart {
@FXML
private MenuItem helpMenuItem;
+ @FXML
+ private MenuItem showContactsMenuItem;
+
@FXML
private StackPane personListPanelPlaceholder;
@@ -50,6 +54,12 @@ public class MainWindow extends UiPart {
@FXML
private StackPane statusbarPlaceholder;
+ @FXML
+ private StackPane showContactsButton;
+
+ @FXML
+ private StackPane showScheduleButton;
+
/**
* Creates a {@code MainWindow} with the given {@code Stage} and {@code Logic}.
*/
@@ -110,9 +120,8 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
* Fills up all the placeholders of this window.
*/
void fillInnerParts() {
- personListPanel = new PersonListPanel(logic.getFilteredPersonList());
+ personListPanel = new PersonListPanel(logic.getFilteredUnarchivedPersonList());
personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
-
resultDisplay = new ResultDisplay();
resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
@@ -121,6 +130,10 @@ void fillInnerParts() {
CommandBox commandBox = new CommandBox(this::executeCommand);
commandBoxPlaceholder.getChildren().add(commandBox.getRoot());
+ Text contactsButtonText = new Text("CONTACTS");
+ showContactsButton.getChildren().add(contactsButtonText);
+ Text scheduleButtonText = new Text("SCHEDULE");
+ showScheduleButton.getChildren().add(scheduleButtonText);
}
/**
@@ -163,6 +176,24 @@ private void handleExit() {
primaryStage.hide();
}
+ @FXML
+ private void handleShowContacts() {
+ personListPanel = new PersonListPanel(logic.getFilteredPersonList());
+ personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ }
+
+ @FXML
+ private void handleShowPayroll() {
+ PayrollListPanel payrollListPanel = new PayrollListPanel(logic.getPayrollList());
+ personListPanelPlaceholder.getChildren().add(payrollListPanel.getRoot());
+ }
+
+ @FXML
+ private void handleShowCalendar() {
+ Calendar calendar = new Calendar(logic.getScheduleDates());
+ personListPanelPlaceholder.getChildren().add(calendar.getRoot());
+ }
+
public PersonListPanel getPersonListPanel() {
return personListPanel;
}
@@ -186,6 +217,18 @@ private CommandResult executeCommand(String commandText) throws CommandException
handleExit();
}
+ if (commandResult.isShowContacts()) {
+ handleShowContacts();
+ }
+
+ if (commandResult.isShowSchedule()) {
+ handleShowCalendar();
+ }
+
+ if (commandResult.isShowPayroll()) {
+ handleShowPayroll();
+ }
+
return commandResult;
} catch (CommandException | ParseException e) {
logger.info("An error occurred while executing command: " + commandText);
diff --git a/src/main/java/seedu/address/ui/PayrollCard.java b/src/main/java/seedu/address/ui/PayrollCard.java
new file mode 100644
index 00000000000..3d227ff49cf
--- /dev/null
+++ b/src/main/java/seedu/address/ui/PayrollCard.java
@@ -0,0 +1,57 @@
+package seedu.address.ui;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+import seedu.address.model.person.PayrollWrapper;
+
+
+/**
+ * An UI component that displays information of a {@code Person}.
+ */
+public class PayrollCard extends UiPart {
+
+ private static final String FXML = "PayrollListCard.fxml";
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final PayrollWrapper payroll;
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private VBox vBox;
+ @FXML
+ private Label name;
+ @FXML
+ private Label id;
+ @FXML
+ private FlowPane tags;
+ @FXML
+ private Label phone;
+
+
+ /**
+ * Creates a {@code PersonCode} with the given {@code Person} and index to display.
+ */
+ public PayrollCard(PayrollWrapper payroll, int displayedIndex) {
+ super(FXML);
+ this.payroll = payroll;
+ id.setText(displayedIndex + ". ");
+ name.setText(payroll.getPerson().getName().value);
+ phone.setText(payroll.getPerson().getPhone().value);
+ Label bankDetails = new Label(payroll.getPerson().getBankDetails().value);
+ Label hoursWorked = new Label(payroll.getHoursWorked() + " hours");
+ Label pay = new Label("$" + payroll.getPay());
+ vBox.getChildren().addAll(bankDetails, hoursWorked, pay);
+ }
+}
diff --git a/src/main/java/seedu/address/ui/PayrollListPanel.java b/src/main/java/seedu/address/ui/PayrollListPanel.java
new file mode 100644
index 00000000000..3b8048a979f
--- /dev/null
+++ b/src/main/java/seedu/address/ui/PayrollListPanel.java
@@ -0,0 +1,40 @@
+package seedu.address.ui;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.address.model.person.PayrollWrapper;
+
+/**
+ * Panel containing the list of payrolls.
+ */
+public class PayrollListPanel extends UiPart {
+ private static final String FXML = "PayrollListPanel.fxml";
+
+ @FXML
+ private ListView payrollListView;
+
+ /**
+ * Creates a {@code PayrollListPanel} with the given {@code ObservableList}.
+ */
+ public PayrollListPanel(ObservableList payrollList) {
+ super(FXML);
+ payrollListView.setItems(payrollList);
+ payrollListView.setCellFactory(listView -> new PayrollListViewCell());
+ }
+
+ class PayrollListViewCell extends ListCell {
+ @Override
+ protected void updateItem(PayrollWrapper payroll, boolean empty) {
+ super.updateItem(payroll, empty);
+ if (empty || payroll == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new PayrollCard(payroll, getIndex() + 1).getRoot());
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
index 094c42cda82..27428e8ec43 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/seedu/address/ui/PersonCard.java
@@ -7,8 +7,10 @@
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
import seedu.address.model.person.Person;
+
/**
* An UI component that displays information of a {@code Person}.
*/
@@ -29,31 +31,48 @@ public class PersonCard extends UiPart {
@FXML
private HBox cardPane;
@FXML
+ private VBox vBox;
+ @FXML
private Label name;
@FXML
private Label id;
@FXML
- private Label phone;
- @FXML
- private Label address;
- @FXML
- private Label email;
- @FXML
private FlowPane tags;
+ @FXML
+ private Label phone;
/**
* Creates a {@code PersonCode} with the given {@code Person} and index to display.
*/
- public PersonCard(Person person, int displayedIndex) {
+ public PersonCard(Person person, int displayedIndex, boolean isFullView) {
super(FXML);
this.person = person;
id.setText(displayedIndex + ". ");
- name.setText(person.getName().fullName);
+ name.setText(person.getName().value);
phone.setText(person.getPhone().value);
- address.setText(person.getAddress().value);
- email.setText(person.getEmail().value);
person.getTags().stream()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+ .sorted(Comparator.comparing(tag -> tag.tagName))
+ .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+
+ if (isFullView) {
+ Label sex = new Label(getFullSexString(person.getSex().value));
+ Label payRate = new Label(person.getPayRate().toString());
+ Label address = new Label(person.getAddress().value);
+ Label bankDetails = new Label(person.getBankDetails().value);
+ // Label hoursWorked = new Label(person.getWorkHours().toString());
+ vBox.getChildren().addAll(new Label[]{sex, payRate, address, bankDetails});
+ }
+ }
+
+ /**
+ * Returns the full sex string based on the short form string returned from Sex.
+ */
+ private String getFullSexString(String shortFormString) {
+ if (shortFormString.equals("m")) {
+ return "Male";
+ } else if (shortFormString.equals("f")) {
+ return "Female";
+ }
+ return "Invalid Sex"; // should not reach here
}
}
diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java
index f4c501a897b..308c76d5e4b 100644
--- a/src/main/java/seedu/address/ui/PersonListPanel.java
+++ b/src/main/java/seedu/address/ui/PersonListPanel.java
@@ -1,13 +1,10 @@
package seedu.address.ui;
-import java.util.logging.Logger;
-
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.Region;
-import seedu.address.commons.core.LogsCenter;
import seedu.address.model.person.Person;
/**
@@ -15,7 +12,8 @@
*/
public class PersonListPanel extends UiPart {
private static final String FXML = "PersonListPanel.fxml";
- private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
+ private int selectedIndex = -1;
+ private boolean isFullView = false;
@FXML
private ListView personListView;
@@ -27,6 +25,16 @@ public PersonListPanel(ObservableList personList) {
super(FXML);
personListView.setItems(personList);
personListView.setCellFactory(listView -> new PersonListViewCell());
+ personListView.setOnMousePressed(event -> {
+ // If the same person is selected, toggle between full view and normal view
+ if (selectedIndex == personListView.getSelectionModel().getSelectedIndex()) {
+ isFullView = !isFullView;
+ } else {
+ isFullView = true;
+ }
+ selectedIndex = personListView.getSelectionModel().getSelectedIndex();
+ personListView.refresh();
+ });
}
/**
@@ -41,7 +49,8 @@ protected void updateItem(Person person, boolean empty) {
setGraphic(null);
setText(null);
} else {
- setGraphic(new PersonCard(person, getIndex() + 1).getRoot());
+ setGraphic(new PersonCard(person, getIndex() + 1,
+ getIndex() == selectedIndex && isFullView).getRoot());
}
}
}
diff --git a/src/main/resources/view/Calendar.fxml b/src/main/resources/view/Calendar.fxml
new file mode 100644
index 00000000000..82cc61ccbcb
--- /dev/null
+++ b/src/main/resources/view/Calendar.fxml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/CommandBox.fxml b/src/main/resources/view/CommandBox.fxml
index 124283a392e..aaeb1ff9174 100644
--- a/src/main/resources/view/CommandBox.fxml
+++ b/src/main/resources/view/CommandBox.fxml
@@ -3,7 +3,6 @@
-
-
+
+
-
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 7778f666a0a..2f09aa15ce0 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -1,60 +1,68 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PayrollListCard.fxml b/src/main/resources/view/PayrollListCard.fxml
new file mode 100644
index 00000000000..8988e70d8f6
--- /dev/null
+++ b/src/main/resources/view/PayrollListCard.fxml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PayrollListPanel.fxml b/src/main/resources/view/PayrollListPanel.fxml
new file mode 100644
index 00000000000..b63c5e0923f
--- /dev/null
+++ b/src/main/resources/view/PayrollListPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
index f5e812e25e6..961ade74dd0 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PersonListCard.fxml
@@ -7,30 +7,32 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/PersonListPanel.fxml
index a1bb6bbace8..fd4589a3cc0 100644
--- a/src/main/resources/view/PersonListPanel.fxml
+++ b/src/main/resources/view/PersonListPanel.fxml
@@ -3,6 +3,6 @@
-
+
diff --git a/src/main/resources/view/ResultDisplay.fxml b/src/main/resources/view/ResultDisplay.fxml
index 01b691792a9..3b16e31a628 100644
--- a/src/main/resources/view/ResultDisplay.fxml
+++ b/src/main/resources/view/ResultDisplay.fxml
@@ -3,7 +3,6 @@
-
-
+
+
diff --git a/src/test/data/JsonScheduleStorageTest/invalidDateSchedule.json b/src/test/data/JsonScheduleStorageTest/invalidDateSchedule.json
new file mode 100644
index 00000000000..ae02e276fc3
--- /dev/null
+++ b/src/test/data/JsonScheduleStorageTest/invalidDateSchedule.json
@@ -0,0 +1,22 @@
+{
+ "scheduleDates": [
+ {
+ "date": "2024-04-012",
+ "persons": [
+ {
+ "firstName": "Benson",
+ "lastName": "Meier",
+ "phone": "98765432",
+ "sex": "m",
+ "payRate": 14.5,
+ "address": "311, Clementi Ave 2, #02-25",
+ "bankDetails": "ocbc 1234567",
+ "tags": [
+ "owesMoney",
+ "friends"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/test/data/JsonScheduleStorageTest/notJsonFormatSchedule.json b/src/test/data/JsonScheduleStorageTest/notJsonFormatSchedule.json
new file mode 100644
index 00000000000..a1097343b5d
--- /dev/null
+++ b/src/test/data/JsonScheduleStorageTest/notJsonFormatSchedule.json
@@ -0,0 +1 @@
+not json format!
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
index a7427fe7aa2..790027a514c 100644
--- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
@@ -1,14 +1,28 @@
-{
- "persons": [ {
- "name": "Alice Pauline",
- "phone": "94351253",
- "email": "alice@example.com",
- "address": "123, Jurong West Ave 6, #08-111",
- "tags": [ "friends" ]
- }, {
- "name": "Alice Pauline",
- "phone": "94351253",
- "email": "pauline@example.com",
- "address": "4th street"
- } ]
+ {
+ "persons": [
+ {
+ "firstName": "Alice",
+ "lastName": "Pauline",
+ "sex": "f",
+ "payRate": 14.5,
+ "phone": "94351253",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "bankDetails": "dbs 1234567890",
+ "tags": [
+ "friends"
+ ]
+ },
+ {
+ "firstName": "Alice",
+ "lastName": "Pauline",
+ "sex": "f",
+ "payRate": 14.5,
+ "phone": "94351253",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "bankDetails": "dbs 1234567890",
+ "tags": [
+ "friends"
+ ]
+ }
+ ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
index ad3f135ae42..3150826f7f7 100644
--- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
@@ -1,8 +1,16 @@
{
- "persons": [ {
- "name": "Hans Muster",
- "phone": "9482424",
- "email": "invalid@email!3e",
- "address": "4th street"
- } ]
+ "persons": [
+ {
+ "firstName": "Alice",
+ "lastName": "Pauline",
+ "sex": "invalidsex",
+ "payRate": 14.5,
+ "phone": "94351253",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "bankDetails": "dbs 1234567890",
+ "tags": [
+ "friends"
+ ]
+ }
+ ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
index 72262099d35..6c6bca0cce6 100644
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
@@ -1,46 +1,82 @@
{
"_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
- "persons" : [ {
- "name" : "Alice Pauline",
- "phone" : "94351253",
- "email" : "alice@example.com",
- "address" : "123, Jurong West Ave 6, #08-111",
- "tags" : [ "friends" ]
- }, {
- "name" : "Benson Meier",
- "phone" : "98765432",
- "email" : "johnd@example.com",
- "address" : "311, Clementi Ave 2, #02-25",
- "tags" : [ "owesMoney", "friends" ]
- }, {
- "name" : "Carl Kurz",
- "phone" : "95352563",
- "email" : "heinz@example.com",
- "address" : "wall street",
- "tags" : [ ]
- }, {
- "name" : "Daniel Meier",
- "phone" : "87652533",
- "email" : "cornelia@example.com",
- "address" : "10th street",
- "tags" : [ "friends" ]
- }, {
- "name" : "Elle Meyer",
- "phone" : "9482224",
- "email" : "werner@example.com",
- "address" : "michegan ave",
- "tags" : [ ]
- }, {
- "name" : "Fiona Kunz",
- "phone" : "9482427",
- "email" : "lydia@example.com",
- "address" : "little tokyo",
- "tags" : [ ]
- }, {
- "name" : "George Best",
- "phone" : "9482442",
- "email" : "anna@example.com",
- "address" : "4th street",
- "tags" : [ ]
- } ]
+ "persons": [
+ {
+ "firstName": "Alice",
+ "lastName": "Pauline",
+ "sex": "f",
+ "payRate": 14.5,
+ "phone": "94351253",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "bankDetails": "dbs 1234567890",
+ "tags": [
+ "friends"
+ ]
+ },
+ {
+ "firstName": "Benson",
+ "lastName": "Meier",
+ "phone": "98765432",
+ "sex": "m",
+ "payRate": 14.5,
+ "address": "311, Clementi Ave 2, #02-25",
+ "bankDetails": "ocbc 1234567",
+ "tags": [
+ "owesMoney",
+ "friends"
+ ]
+ },
+ {
+ "firstName": "Carl",
+ "lastName": "Kurz",
+ "sex": "m",
+ "payRate": 14.5,
+ "phone": "95352563",
+ "address": "wall street",
+ "bankDetails": "hsbc 0987654321",
+ "tags": []
+ },
+ {
+ "firstName": "Daniel",
+ "lastName": "Meier",
+ "phone": "87652533",
+ "sex": "m",
+ "payRate": 14.5,
+ "address": "10th street",
+ "bankDetails": "uob 8888777700",
+ "tags": [
+ "friends"
+ ]
+ },
+ {
+ "firstName": "Elle",
+ "lastName": "Meyer",
+ "phone": "94823224",
+ "sex": "f",
+ "payRate": 14.5,
+ "bankDetails": "posb 369369369",
+ "address": "michegan ave",
+ "tags": []
+ },
+ {
+ "firstName": "Fiona",
+ "lastName": "Kunz",
+ "phone": "94823427",
+ "sex": "f",
+ "payRate": 14.5,
+ "address": "little tokyo",
+ "bankDetails": "ocbc 7654321",
+ "tags": []
+ },
+ {
+ "firstName": "George",
+ "lastName": "Best",
+ "phone": "93482442",
+ "sex": "m",
+ "payRate": 14.5,
+ "bankDetails": "other maybank 5554443332",
+ "address": "4th street",
+ "tags": []
+ }
+ ]
}
diff --git a/src/test/data/JsonSerializableScheduleTest/invalidDateSchedule.json b/src/test/data/JsonSerializableScheduleTest/invalidDateSchedule.json
new file mode 100644
index 00000000000..0830e3c783c
--- /dev/null
+++ b/src/test/data/JsonSerializableScheduleTest/invalidDateSchedule.json
@@ -0,0 +1,16 @@
+{
+ "scheduleDates" : [ {
+ "date" : "2024-04-06f",
+ "persons" : [ {
+ "firstName" : "Roy",
+ "lastName" : "Balakrishnan",
+ "phone" : "92624417",
+ "sex" : "m",
+ "payRate" : 10.0,
+ "address" : "Blk 45 Aljunied Street 85, #11-31",
+ "bankDetails" : "5501089550",
+ "workHours" : 0,
+ "tags" : [ "colleagues" ]
+ } ]
+ } ]
+}
diff --git a/src/test/data/JsonSerializableScheduleTest/invalidPersonSchedule.json b/src/test/data/JsonSerializableScheduleTest/invalidPersonSchedule.json
new file mode 100644
index 00000000000..30f4df34d18
--- /dev/null
+++ b/src/test/data/JsonSerializableScheduleTest/invalidPersonSchedule.json
@@ -0,0 +1,16 @@
+{
+ "scheduleDates" : [ {
+ "date" : "2024-04-06",
+ "persons" : [ {
+ "firstName" : "Roy",
+ "lastName" : "Balakrishnan",
+ "phone" : "92624417",
+ "sex" : "invalid",
+ "payRate" : 10.0,
+ "address" : "Blk 45 Aljunied Street 85, #11-31",
+ "bankDetails" : "5501089550",
+ "workHours" : 0,
+ "tags" : [ "colleagues" ]
+ } ]
+ } ]
+}
diff --git a/src/test/data/JsonSerializableScheduleTest/typicalSchedule.json b/src/test/data/JsonSerializableScheduleTest/typicalSchedule.json
new file mode 100644
index 00000000000..53af6702b20
--- /dev/null
+++ b/src/test/data/JsonSerializableScheduleTest/typicalSchedule.json
@@ -0,0 +1,52 @@
+{
+ "scheduleDates": [
+ {
+ "date": "2024-03-31",
+ "persons": [
+ {
+ "firstName": "Alice",
+ "lastName": "Pauline",
+ "sex": "f",
+ "payRate": 14.5,
+ "phone": "94351253",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "bankDetails": "dbs 1234567890",
+ "tags": [
+ "friends"
+ ]
+ },
+ {
+ "firstName": "Benson",
+ "lastName": "Meier",
+ "phone": "98765432",
+ "sex": "m",
+ "payRate": 14.5,
+ "address": "311, Clementi Ave 2, #02-25",
+ "bankDetails": "ocbc 1234567",
+ "tags": [
+ "owesMoney",
+ "friends"
+ ]
+ }
+ ]
+ },
+ {
+ "date": "2024-04-01",
+ "persons": [
+ {
+ "firstName": "Benson",
+ "lastName": "Meier",
+ "phone": "98765432",
+ "sex": "m",
+ "payRate": 14.5,
+ "address": "311, Clementi Ave 2, #02-25",
+ "bankDetails": "ocbc 1234567",
+ "tags": [
+ "owesMoney",
+ "friends"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java
index baf8ce336a2..610563c58e8 100644
--- a/src/test/java/seedu/address/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/address/logic/LogicManagerTest.java
@@ -1,12 +1,14 @@
package seedu.address.logic;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.BANKDETAILS_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.FIRSTNAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.LASTNAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.PAYRATE_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.SEX_DESC_AMY;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.AMY;
@@ -28,7 +30,9 @@
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.Person;
+import seedu.address.model.schedule.ScheduleManager;
import seedu.address.storage.JsonAddressBookStorage;
+import seedu.address.storage.JsonScheduleStorage;
import seedu.address.storage.JsonUserPrefsStorage;
import seedu.address.storage.StorageManager;
import seedu.address.testutil.PersonBuilder;
@@ -46,9 +50,10 @@ public class LogicManagerTest {
@BeforeEach
public void setUp() {
JsonAddressBookStorage addressBookStorage =
- new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json"));
+ new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json"));
JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json"));
- StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ JsonScheduleStorage scheduleStorage = new JsonScheduleStorage(temporaryFolder.resolve("schedule.json"));
+ StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage, scheduleStorage);
logic = new LogicManager(model, storage);
}
@@ -60,26 +65,26 @@ public void execute_invalidCommandFormat_throwsParseException() {
@Test
public void execute_commandExecutionError_throwsCommandException() {
- String deleteCommand = "delete 9";
- assertCommandException(deleteCommand, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ String deleteCommand = "delete 12345678";
+ assertCommandException(deleteCommand, Messages.MESSAGE_PERSON_NOT_FOUND);
}
@Test
public void execute_validCommand_success() throws Exception {
- String listCommand = ListCommand.COMMAND_WORD;
+ String listCommand = ListCommand.COMMAND_WORD + " archive";
assertCommandSuccess(listCommand, ListCommand.MESSAGE_SUCCESS, model);
}
@Test
public void execute_storageThrowsIoException_throwsCommandException() {
assertCommandFailureForExceptionFromStorage(DUMMY_IO_EXCEPTION, String.format(
- LogicManager.FILE_OPS_ERROR_FORMAT, DUMMY_IO_EXCEPTION.getMessage()));
+ LogicManager.FILE_OPS_ERROR_FORMAT, DUMMY_IO_EXCEPTION.getMessage()));
}
@Test
public void execute_storageThrowsAdException_throwsCommandException() {
assertCommandFailureForExceptionFromStorage(DUMMY_AD_EXCEPTION, String.format(
- LogicManager.FILE_OPS_PERMISSION_ERROR_FORMAT, DUMMY_AD_EXCEPTION.getMessage()));
+ LogicManager.FILE_OPS_PERMISSION_ERROR_FORMAT, DUMMY_AD_EXCEPTION.getMessage()));
}
@Test
@@ -92,10 +97,11 @@ public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException
* - no exceptions are thrown
* - the feedback message is equal to {@code expectedMessage}
* - the internal model manager state is the same as that in {@code expectedModel}
+ *
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandSuccess(String inputCommand, String expectedMessage,
- Model expectedModel) throws CommandException, ParseException {
+ Model expectedModel) throws CommandException, ParseException {
CommandResult result = logic.execute(inputCommand);
assertEquals(expectedMessage, result.getFeedbackToUser());
assertEquals(expectedModel, model);
@@ -103,6 +109,7 @@ private void assertCommandSuccess(String inputCommand, String expectedMessage,
/**
* Executes the command, confirms that a ParseException is thrown and that the result message is correct.
+ *
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertParseException(String inputCommand, String expectedMessage) {
@@ -111,6 +118,7 @@ private void assertParseException(String inputCommand, String expectedMessage) {
/**
* Executes the command, confirms that a CommandException is thrown and that the result message is correct.
+ *
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandException(String inputCommand, String expectedMessage) {
@@ -119,11 +127,12 @@ private void assertCommandException(String inputCommand, String expectedMessage)
/**
* Executes the command, confirms that the exception is thrown and that the result message is correct.
+ *
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandFailure(String inputCommand, Class extends Throwable> expectedException,
- String expectedMessage) {
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ String expectedMessage) {
+ Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs(), new ScheduleManager());
assertCommandFailure(inputCommand, expectedException, expectedMessage, expectedModel);
}
@@ -132,10 +141,11 @@ private void assertCommandFailure(String inputCommand, Class extends Throwable
* - the {@code expectedException} is thrown
* - the resulting error message is equal to {@code expectedMessage}
* - the internal model manager state is the same as that in {@code expectedModel}
+ *
* @see #assertCommandSuccess(String, String, Model)
*/
private void assertCommandFailure(String inputCommand, Class extends Throwable> expectedException,
- String expectedMessage, Model expectedModel) {
+ String expectedMessage, Model expectedModel) {
assertThrows(expectedException, expectedMessage, () -> logic.execute(inputCommand));
assertEquals(expectedModel, model);
}
@@ -143,7 +153,7 @@ private void assertCommandFailure(String inputCommand, Class extends Throwable
/**
* Tests the Logic component's handling of an {@code IOException} thrown by the Storage component.
*
- * @param e the exception to be thrown by the Storage component
+ * @param e the exception to be thrown by the Storage component
* @param expectedMessage the message expected inside exception thrown by the Logic component
*/
private void assertCommandFailureForExceptionFromStorage(IOException e, String expectedMessage) {
@@ -152,22 +162,24 @@ private void assertCommandFailureForExceptionFromStorage(IOException e, String e
// Inject LogicManager with an AddressBookStorage that throws the IOException e when saving
JsonAddressBookStorage addressBookStorage = new JsonAddressBookStorage(prefPath) {
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath)
- throws IOException {
+ public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
throw e;
}
};
JsonUserPrefsStorage userPrefsStorage =
- new JsonUserPrefsStorage(temporaryFolder.resolve("ExceptionUserPrefs.json"));
- StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ new JsonUserPrefsStorage(temporaryFolder.resolve("ExceptionUserPrefs.json"));
+
+ JsonScheduleStorage scheduleStorage = new JsonScheduleStorage(temporaryFolder.resolve("schedule.json"));
+ StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage, scheduleStorage);
logic = new LogicManager(model, storage);
// Triggers the saveAddressBook method by executing an add command
- String addCommand = AddCommand.COMMAND_WORD + NAME_DESC_AMY + PHONE_DESC_AMY
- + EMAIL_DESC_AMY + ADDRESS_DESC_AMY;
- Person expectedPerson = new PersonBuilder(AMY).withTags().build();
+ String addCommand =
+ AddCommand.COMMAND_WORD + FIRSTNAME_DESC_AMY + LASTNAME_DESC_AMY + PHONE_DESC_AMY
+ + SEX_DESC_AMY + PAYRATE_DESC_AMY + BANKDETAILS_DESC_AMY + ADDRESS_DESC_AMY;
+ Person expectedPerson = new PersonBuilder(AMY).withTags().withArchiveStatus(false).build();
ModelManager expectedModel = new ModelManager();
expectedModel.addPerson(expectedPerson);
assertCommandFailure(addCommand, CommandException.class, expectedMessage, expectedModel);
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
index 162a0c86031..1d326ab3146 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
@@ -12,6 +12,7 @@
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.Person;
+import seedu.address.model.schedule.ScheduleManager;
import seedu.address.testutil.PersonBuilder;
/**
@@ -23,14 +24,14 @@ public class AddCommandIntegrationTest {
@BeforeEach
public void setUp() {
- model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ model = new ModelManager(getTypicalAddressBook(), new UserPrefs(), new ScheduleManager());
}
@Test
public void execute_newPerson_success() {
Person validPerson = new PersonBuilder().build();
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs(), new ScheduleManager());
expectedModel.addPerson(validPerson);
assertCommandSuccess(new AddCommand(validPerson), model,
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
index 90e8253f48e..3e4797e5a92 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
@@ -8,8 +8,10 @@
import static seedu.address.testutil.TypicalPersons.ALICE;
import java.nio.file.Path;
+import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Set;
import java.util.function.Predicate;
import org.junit.jupiter.api.Test;
@@ -22,7 +24,11 @@
import seedu.address.model.Model;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.ReadOnlyUserPrefs;
+import seedu.address.model.person.PayrollWrapper;
import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleDate;
import seedu.address.testutil.PersonBuilder;
public class AddCommandTest {
@@ -40,7 +46,7 @@ public void execute_personAcceptedByModel_addSuccessful() throws Exception {
CommandResult commandResult = new AddCommand(validPerson).execute(modelStub);
assertEquals(String.format(AddCommand.MESSAGE_SUCCESS, Messages.format(validPerson)),
- commandResult.getFeedbackToUser());
+ commandResult.getFeedbackToUser());
assertEquals(Arrays.asList(validPerson), modelStub.personsAdded);
}
@@ -55,8 +61,8 @@ public void execute_duplicatePerson_throwsCommandException() {
@Test
public void equals() {
- Person alice = new PersonBuilder().withName("Alice").build();
- Person bob = new PersonBuilder().withName("Bob").build();
+ Person alice = new PersonBuilder().withFirstName("Alice").withLastName("Ng").build();
+ Person bob = new PersonBuilder().withFirstName("Bob").withLastName("Tan").build();
AddCommand addAliceCommand = new AddCommand(alice);
AddCommand addBobCommand = new AddCommand(bob);
@@ -89,15 +95,29 @@ public void toStringMethod() {
*/
private class ModelStub implements Model {
@Override
- public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
+ public void updatePerson(Person personToUpdate) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void archivePerson(Person personToArchive, Person archivedPerson) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public Person getPersonByPhoneNumber(Phone phoneNumber) {
+ throw new AssertionError("This method should not be called.");
+ }
@Override
public ReadOnlyUserPrefs getUserPrefs() {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public GuiSettings getGuiSettings() {
throw new AssertionError("This method should not be called.");
@@ -124,12 +144,12 @@ public void addPerson(Person person) {
}
@Override
- public void setAddressBook(ReadOnlyAddressBook newData) {
+ public ReadOnlyAddressBook getAddressBook() {
throw new AssertionError("This method should not be called.");
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
+ public void setAddressBook(ReadOnlyAddressBook newData) {
throw new AssertionError("This method should not be called.");
}
@@ -148,15 +168,67 @@ public void setPerson(Person target, Person editedPerson) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void unarchivePerson(Person personToUnarchive, Person unarchivedPerson) {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public ObservableList getFilteredPersonList() {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public ObservableList getFilteredArchivedPersonList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getFilteredUnarchivedPersonList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void updateFilteredPersonList(Predicate predicate) {
throw new AssertionError("This method should not be called.");
}
+
+ @Override
+ public void setSchedule(Schedule schedule) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public Schedule getSchedule() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public Set getScheduleDates() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void addPersonToSchedule(Person person, LocalDate date) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void removePersonFromSchedule(Person person, LocalDate date) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void generatePayroll(LocalDate startDate, LocalDate endDate) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ /**
+ * Returns the payroll list.
+ */
+ public ObservableList getPayrollList() {
+ throw new AssertionError("This method should not be called.");
+ }
}
/**
diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
index 80d9110c03a..a96d12038d5 100644
--- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
@@ -9,6 +9,7 @@
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
+import seedu.address.model.schedule.ScheduleManager;
public class ClearCommandTest {
@@ -22,8 +23,8 @@ public void execute_emptyAddressBook_success() {
@Test
public void execute_nonEmptyAddressBook_success() {
- Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs(), new ScheduleManager());
+ Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs(), new ScheduleManager());
expectedModel.setAddressBook(new AddressBook());
assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel);
diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
index 7b8c7cd4546..e7c1f81b30f 100644
--- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java
+++ b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
@@ -14,7 +14,9 @@ public void equals() {
// same values -> returns true
assertTrue(commandResult.equals(new CommandResult("feedback")));
- assertTrue(commandResult.equals(new CommandResult("feedback", false, false)));
+
+ // different page -> returns false
+ assertFalse(commandResult.equals(new CommandResult("feedback", false, false)));
// same object -> returns true
assertTrue(commandResult.equals(commandResult));
@@ -57,7 +59,8 @@ public void toStringMethod() {
CommandResult commandResult = new CommandResult("feedback");
String expected = CommandResult.class.getCanonicalName() + "{feedbackToUser="
+ commandResult.getFeedbackToUser() + ", showHelp=" + commandResult.isShowHelp()
- + ", exit=" + commandResult.isExit() + "}";
+ + ", exit=" + commandResult.isExit() + ", showContacts=" + commandResult.isShowContacts()
+ + ", showSchedule=" + commandResult.isShowSchedule() + "}";
assertEquals(expected, commandResult.toString());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
index 643a1d08069..815e62712a6 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -3,9 +3,12 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_BANKDETAILS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FIRSTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PAYRATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.testutil.Assert.assertThrows;
@@ -26,47 +29,68 @@
*/
public class CommandTestUtil {
- public static final String VALID_NAME_AMY = "Amy Bee";
- public static final String VALID_NAME_BOB = "Bob Choo";
+ public static final String VALID_FIRSTNAME_AMY = "Amy";
+ public static final String VALID_LASTNAME_AMY = "Bee";
+ public static final String VALID_FIRSTNAME_BOB = "Bob";
+ public static final String VALID_LASTNAME_BOB = "Choo";
public static final String VALID_PHONE_AMY = "11111111";
public static final String VALID_PHONE_BOB = "22222222";
- public static final String VALID_EMAIL_AMY = "amy@example.com";
- public static final String VALID_EMAIL_BOB = "bob@example.com";
+ public static final String VALID_SEX_AMY = "f";
+ public static final String VALID_SEX_BOB = "m";
+ public static final double VALID_PAYRATE_AMY = 14.0;
+ public static final double VALID_PAYRATE_BOB = 18.5;
public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1";
public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3";
- public static final String VALID_TAG_HUSBAND = "husband";
- public static final String VALID_TAG_FRIEND = "friend";
-
- public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
- public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
+ public static final String VALID_BANKDETAILS_AMY = "ocbc 8374219";
+ public static final String VALID_BANKDETAILS_BOB = "dbs 7777222201";
+ public static final String VALID_TAG_WAITER = "waiter";
+ public static final String VALID_TAG_COOK = "cook";
+ public static final int VALID_WORK_HOURS_AMY = 10;
+ public static final int VALID_WORK_HOURS_BOB = 20;
+
+ public static final String FIRSTNAME_DESC_AMY = " " + PREFIX_FIRSTNAME + VALID_FIRSTNAME_AMY;
+ public static final String LASTNAME_DESC_AMY = " " + PREFIX_LASTNAME + VALID_LASTNAME_AMY;
+ public static final String FIRSTNAME_DESC_BOB = " " + PREFIX_FIRSTNAME + VALID_FIRSTNAME_BOB;
+ public static final String LASTNAME_DESC_BOB = " " + PREFIX_LASTNAME + VALID_LASTNAME_BOB;
public static final String PHONE_DESC_AMY = " " + PREFIX_PHONE + VALID_PHONE_AMY;
public static final String PHONE_DESC_BOB = " " + PREFIX_PHONE + VALID_PHONE_BOB;
- public static final String EMAIL_DESC_AMY = " " + PREFIX_EMAIL + VALID_EMAIL_AMY;
- public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB;
+ public static final String SEX_DESC_AMY = " " + PREFIX_SEX + VALID_SEX_AMY;
+ public static final String SEX_DESC_BOB = " " + PREFIX_SEX + VALID_SEX_BOB;
+ public static final String PAYRATE_DESC_AMY = " " + PREFIX_PAYRATE + VALID_PAYRATE_AMY;
+ public static final String PAYRATE_DESC_BOB = " " + PREFIX_PAYRATE + VALID_PAYRATE_BOB;
public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY;
public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB;
- public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
- public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
+ public static final String BANKDETAILS_DESC_AMY = " " + PREFIX_BANKDETAILS + VALID_BANKDETAILS_AMY;
+ public static final String BANKDETAILS_DESC_BOB = " " + PREFIX_BANKDETAILS + VALID_BANKDETAILS_BOB;
+
+ public static final String TAG_DESC_COOK = " " + PREFIX_TAG + VALID_TAG_COOK;
+ public static final String TAG_DESC_WAITER = " " + PREFIX_TAG + VALID_TAG_WAITER;
- public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names
+ public static final String INVALID_FIRSTNAME_DESC = " " + PREFIX_FIRSTNAME + "James&"; // '&' not allowed in
+ public static final String INVALID_LASTNAME_DESC = " " + PREFIX_LASTNAME + "Char.les"; // '&' not allowed in
+ public static final String INVALID_SEX_DESC = " " + PREFIX_SEX + "u"; // 'u' is not an allowed sex
+ public static final String INVALID_PAYRATE_DESC = " " + PREFIX_PAYRATE + "ut"; //'ut' is not an allowed payrate
public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones
- public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol
- public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses
+ public static final String INVALID_BANKDETAILS_DESC = " " + PREFIX_BANKDETAILS
+ + "3213*421321"; // '*' not allowed in bank details
public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags
+ public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses
+
public static final String PREAMBLE_WHITESPACE = "\t \r \n";
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";
+
public static final EditCommand.EditPersonDescriptor DESC_AMY;
public static final EditCommand.EditPersonDescriptor DESC_BOB;
static {
- DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
- .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_FRIEND).build();
- DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ DESC_AMY = new EditPersonDescriptorBuilder().withFirstName(VALID_FIRSTNAME_AMY)
+ .withPhone(VALID_PHONE_AMY)
+ .withTags(VALID_TAG_COOK).build();
+ DESC_BOB = new EditPersonDescriptorBuilder().withFirstName(VALID_LASTNAME_BOB)
+ .withPhone(VALID_PHONE_BOB)
+ .withTags(VALID_TAG_WAITER, VALID_TAG_COOK).build();
}
/**
@@ -75,7 +99,7 @@ public class CommandTestUtil {
* - the {@code actualModel} matches {@code expectedModel}
*/
public static void assertCommandSuccess(Command command, Model actualModel, CommandResult expectedCommandResult,
- Model expectedModel) {
+ Model expectedModel) {
try {
CommandResult result = command.execute(actualModel);
assertEquals(expectedCommandResult, result);
@@ -90,7 +114,7 @@ public static void assertCommandSuccess(Command command, Model actualModel, Comm
* that takes a string {@code expectedMessage}.
*/
public static void assertCommandSuccess(Command command, Model actualModel, String expectedMessage,
- Model expectedModel) {
+ Model expectedModel) {
CommandResult expectedCommandResult = new CommandResult(expectedMessage);
assertCommandSuccess(command, actualModel, expectedCommandResult, expectedModel);
}
@@ -111,6 +135,7 @@ public static void assertCommandFailure(Command command, Model actualModel, Stri
assertEquals(expectedAddressBook, actualModel.getAddressBook());
assertEquals(expectedFilteredList, actualModel.getFilteredPersonList());
}
+
/**
* Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the
* {@code model}'s address book.
@@ -119,7 +144,7 @@ public static void showPersonAtIndex(Model model, Index targetIndex) {
assertTrue(targetIndex.getZeroBased() < model.getFilteredPersonList().size());
Person person = model.getFilteredPersonList().get(targetIndex.getZeroBased());
- final String[] splitName = person.getName().fullName.split("\\s+");
+ final String[] splitName = person.getName().value.split("\\s+");
model.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0])));
assertEquals(1, model.getFilteredPersonList().size());
diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
index b6f332eabca..7604c61c17a 100644
--- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
@@ -7,17 +7,17 @@
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.index.Index;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.schedule.ScheduleManager;
/**
* Contains integration tests (interaction with the Model) and unit tests for
@@ -25,41 +25,41 @@
*/
public class DeleteCommandTest {
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs(), new ScheduleManager());
@Test
- public void execute_validIndexUnfilteredList_success() {
+ public void execute_validPhoneUnfilteredList_success() {
Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+ Phone phoneToDelete = personToDelete.getPhone();
+ DeleteCommand deleteCommand = new DeleteCommand(phoneToDelete);
String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
Messages.format(personToDelete));
- ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs(), new ScheduleManager());
expectedModel.deletePerson(personToDelete);
assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
}
@Test
- public void execute_invalidIndexUnfilteredList_throwsCommandException() {
- Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
- DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+ public void execute_invalidPhoneUnfilteredList_throwsCommandException() {
+ DeleteCommand deleteCommand = new DeleteCommand(new Phone("12345678"));
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(deleteCommand, model, Messages.MESSAGE_PERSON_NOT_FOUND);
}
@Test
- public void execute_validIndexFilteredList_success() {
+ public void execute_validPhoneFilteredList_success() {
showPersonAtIndex(model, INDEX_FIRST_PERSON);
Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+ DeleteCommand deleteCommand = new DeleteCommand(personToDelete.getPhone());
String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
Messages.format(personToDelete));
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs(), new ScheduleManager());
expectedModel.deletePerson(personToDelete);
showNoPerson(expectedModel);
@@ -67,28 +67,24 @@ public void execute_validIndexFilteredList_success() {
}
@Test
- public void execute_invalidIndexFilteredList_throwsCommandException() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
-
- Index outOfBoundIndex = INDEX_SECOND_PERSON;
- // ensures that outOfBoundIndex is still in bounds of address book list
- assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
-
- DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+ public void execute_invalidPhoneFilteredList_throwsCommandException() {
+ DeleteCommand deleteCommand = new DeleteCommand(new Phone("12345678"));
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(deleteCommand, model, Messages.MESSAGE_PERSON_NOT_FOUND);
}
@Test
public void equals() {
- DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_PERSON);
- DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_PERSON);
+ Phone firstPhone = new Phone("12345678");
+ Phone secondPhone = new Phone("87654321");
+ DeleteCommand deleteFirstCommand = new DeleteCommand(firstPhone);
+ DeleteCommand deleteSecondCommand = new DeleteCommand(secondPhone);
// same object -> returns true
assertTrue(deleteFirstCommand.equals(deleteFirstCommand));
// same values -> returns true
- DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_PERSON);
+ DeleteCommand deleteFirstCommandCopy = new DeleteCommand(firstPhone);
assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy));
// different types -> returns false
@@ -103,9 +99,9 @@ public void equals() {
@Test
public void toStringMethod() {
- Index targetIndex = Index.fromOneBased(1);
- DeleteCommand deleteCommand = new DeleteCommand(targetIndex);
- String expected = DeleteCommand.class.getCanonicalName() + "{targetIndex=" + targetIndex + "}";
+ Phone phone = new Phone("12345678");
+ DeleteCommand deleteCommand = new DeleteCommand(phone);
+ String expected = DeleteCommand.class.getCanonicalName() + "{targetPhone=" + phone.toString() + "}";
assertEquals(expected, deleteCommand.toString());
}
diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
index 469dd97daa7..24ef45a5ed0 100644
--- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
@@ -5,9 +5,10 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_FIRSTNAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_LASTNAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_WAITER;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
@@ -25,6 +26,8 @@
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.schedule.ScheduleManager;
import seedu.address.testutil.EditPersonDescriptorBuilder;
import seedu.address.testutil.PersonBuilder;
@@ -33,17 +36,23 @@
*/
public class EditCommandTest {
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs(), new ScheduleManager());
+ private Phone indexFirstPhone = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()).getPhone();
+ private Phone indexSecondPhone = model.getFilteredPersonList().get(INDEX_SECOND_PERSON.getZeroBased()).getPhone();
+ private Phone indexLastPhone = model.getFilteredPersonList().get(model.getFilteredPersonList().size() - 1)
+ .getPhone();
@Test
public void execute_allFieldsSpecifiedUnfilteredList_success() {
Person editedPerson = new PersonBuilder().build();
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(editedPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor);
+ EditCommand editCommand = new EditCommand(indexFirstPhone, descriptor);
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
+ String expectedMessage = String.format(
+ EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs(),
+ new ScheduleManager());
expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
@@ -55,16 +64,22 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() {
Person lastPerson = model.getFilteredPersonList().get(indexLastPerson.getZeroBased());
PersonBuilder personInList = new PersonBuilder(lastPerson);
- Person editedPerson = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withTags(VALID_TAG_HUSBAND).build();
-
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_HUSBAND).build();
- EditCommand editCommand = new EditCommand(indexLastPerson, descriptor);
-
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
-
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ Person editedPerson = personInList.withFirstName(VALID_FIRSTNAME_BOB)
+ .withLastName(VALID_LASTNAME_BOB)
+ .withPhone(VALID_PHONE_BOB)
+ .withTags(VALID_TAG_WAITER).build();
+
+ EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withFirstName(VALID_FIRSTNAME_BOB)
+ .withLastName(VALID_LASTNAME_BOB)
+ .withPhone(VALID_PHONE_BOB)
+ .withTags(VALID_TAG_WAITER).build();
+ EditCommand editCommand = new EditCommand(indexLastPhone, descriptor);
+
+ String expectedMessage = String.format(
+ EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
+
+ Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs(),
+ new ScheduleManager());
expectedModel.setPerson(lastPerson, editedPerson);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
@@ -72,29 +87,14 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() {
@Test
public void execute_noFieldSpecifiedUnfilteredList_success() {
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor());
+ EditCommand editCommand = new EditCommand(indexFirstPhone, new EditPersonDescriptor());
Person editedPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
-
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
-
- assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
- }
-
- @Test
- public void execute_filteredList_success() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
-
- Person personInFilteredList = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- Person editedPerson = new PersonBuilder(personInFilteredList).withName(VALID_NAME_BOB).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
- new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
+ String expectedMessage = String.format(
+ EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
-
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs(),
+ new ScheduleManager());
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@@ -103,7 +103,7 @@ public void execute_filteredList_success() {
public void execute_duplicatePersonUnfilteredList_failure() {
Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(firstPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor);
+ EditCommand editCommand = new EditCommand(indexSecondPhone, descriptor);
assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
}
@@ -114,7 +114,7 @@ public void execute_duplicatePersonFilteredList_failure() {
// edit person in filtered list into a duplicate in address book
Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased());
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
+ EditCommand editCommand = new EditCommand(indexFirstPhone,
new EditPersonDescriptorBuilder(personInList).build());
assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
@@ -122,11 +122,13 @@ public void execute_duplicatePersonFilteredList_failure() {
@Test
public void execute_invalidPersonIndexUnfilteredList_failure() {
- Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build();
- EditCommand editCommand = new EditCommand(outOfBoundIndex, descriptor);
+ Phone phoneNumberNotInBook = new Phone("12345678");
+ EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withFirstName(VALID_FIRSTNAME_BOB)
+ .withLastName(VALID_LASTNAME_BOB)
+ .build();
+ EditCommand editCommand = new EditCommand(phoneNumberNotInBook, descriptor);
- assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(editCommand, model, Messages.MESSAGE_PERSON_NOT_FOUND);
}
/**
@@ -136,23 +138,23 @@ public void execute_invalidPersonIndexUnfilteredList_failure() {
@Test
public void execute_invalidPersonIndexFilteredList_failure() {
showPersonAtIndex(model, INDEX_FIRST_PERSON);
- Index outOfBoundIndex = INDEX_SECOND_PERSON;
// ensures that outOfBoundIndex is still in bounds of address book list
- assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
-
- EditCommand editCommand = new EditCommand(outOfBoundIndex,
- new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
+ assertTrue(INDEX_SECOND_PERSON.getZeroBased() < model.getAddressBook().getPersonList().size());
+ EditCommand editCommand = new EditCommand(indexSecondPhone,
+ new EditPersonDescriptorBuilder().withFirstName(VALID_FIRSTNAME_BOB)
+ .withLastName(VALID_LASTNAME_BOB)
+ .build());
- assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(editCommand, model, Messages.MESSAGE_PERSON_NOT_FOUND);
}
@Test
public void equals() {
- final EditCommand standardCommand = new EditCommand(INDEX_FIRST_PERSON, DESC_AMY);
+ final EditCommand standardCommand = new EditCommand(indexFirstPhone, DESC_AMY);
// same values -> returns true
EditPersonDescriptor copyDescriptor = new EditPersonDescriptor(DESC_AMY);
- EditCommand commandWithSameValues = new EditCommand(INDEX_FIRST_PERSON, copyDescriptor);
+ EditCommand commandWithSameValues = new EditCommand(indexFirstPhone, copyDescriptor);
assertTrue(standardCommand.equals(commandWithSameValues));
// same object -> returns true
@@ -165,19 +167,19 @@ public void equals() {
assertFalse(standardCommand.equals(new ClearCommand()));
// different index -> returns false
- assertFalse(standardCommand.equals(new EditCommand(INDEX_SECOND_PERSON, DESC_AMY)));
+ assertFalse(standardCommand.equals(new EditCommand(indexSecondPhone, DESC_AMY)));
// different descriptor -> returns false
- assertFalse(standardCommand.equals(new EditCommand(INDEX_FIRST_PERSON, DESC_BOB)));
+ assertFalse(standardCommand.equals(new EditCommand(indexSecondPhone, DESC_BOB)));
}
@Test
public void toStringMethod() {
Index index = Index.fromOneBased(1);
EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- EditCommand editCommand = new EditCommand(index, editPersonDescriptor);
- String expected = EditCommand.class.getCanonicalName() + "{index=" + index + ", editPersonDescriptor="
- + editPersonDescriptor + "}";
+ EditCommand editCommand = new EditCommand(indexFirstPhone, editPersonDescriptor);
+ String expected = EditCommand.class.getCanonicalName() + "{index=" + indexFirstPhone
+ + ", editPersonDescriptor=" + editPersonDescriptor + "}";
assertEquals(expected, editCommand.toString());
}
diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
index b17c1f3d5c2..f91ff6da335 100644
--- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
@@ -6,10 +6,10 @@
import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_FIRSTNAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_LASTNAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_WAITER;
import org.junit.jupiter.api.Test;
@@ -37,34 +37,35 @@ public void equals() {
assertFalse(DESC_AMY.equals(DESC_BOB));
// different name -> returns false
- EditPersonDescriptor editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withName(VALID_NAME_BOB).build();
+ EditPersonDescriptor editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withFirstName(VALID_FIRSTNAME_BOB)
+ .withLastName(VALID_LASTNAME_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
// different phone -> returns false
editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withPhone(VALID_PHONE_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
- // different email -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withEmail(VALID_EMAIL_BOB).build();
- assertFalse(DESC_AMY.equals(editedAmy));
-
// different address -> returns false
editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withAddress(VALID_ADDRESS_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
// different tags -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_HUSBAND).build();
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_WAITER).build();
assertFalse(DESC_AMY.equals(editedAmy));
}
@Test
public void toStringMethod() {
EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- String expected = EditPersonDescriptor.class.getCanonicalName() + "{name="
- + editPersonDescriptor.getName().orElse(null) + ", phone="
- + editPersonDescriptor.getPhone().orElse(null) + ", email="
- + editPersonDescriptor.getEmail().orElse(null) + ", address="
- + editPersonDescriptor.getAddress().orElse(null) + ", tags="
+ String expected = EditPersonDescriptor.class.getCanonicalName() + "{firstName="
+ + editPersonDescriptor.getFirstName().orElse(null) + ", lastName="
+ + editPersonDescriptor.getLastName().orElse(null) + ", phone="
+ + editPersonDescriptor.getPhone().orElse(null) + ", sex="
+ + editPersonDescriptor.getSex().orElse(null) + ", payRate="
+ + editPersonDescriptor.getPayRate().orElse(null) + ", address="
+ + editPersonDescriptor.getAddress().orElse(null) + ", bankDetails="
+ + editPersonDescriptor.getBankDetails().orElse(null) + ", hoursWorked="
+ + editPersonDescriptor.getHoursWorked().orElse(null) + ", tags="
+ editPersonDescriptor.getTags().orElse(null) + "}";
assertEquals(expected, editPersonDescriptor.toString());
}
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
index b8b7dbba91a..0191c76aed9 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
@@ -19,13 +19,14 @@
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.schedule.ScheduleManager;
/**
* Contains integration tests (interaction with the Model) for {@code FindCommand}.
*/
public class FindCommandTest {
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs(), new ScheduleManager());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs(), new ScheduleManager());
@Test
public void equals() {
diff --git a/src/test/java/seedu/address/logic/commands/ListCommandTest.java b/src/test/java/seedu/address/logic/commands/ListCommandTest.java
index 435ff1f7275..a9035788d83 100644
--- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ListCommandTest.java
@@ -11,6 +11,7 @@
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
+import seedu.address.model.schedule.ScheduleManager;
/**
* Contains integration tests (interaction with the Model) and unit tests for ListCommand.
@@ -22,18 +23,18 @@ public class ListCommandTest {
@BeforeEach
public void setUp() {
- model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ model = new ModelManager(getTypicalAddressBook(), new UserPrefs(), new ScheduleManager());
+ expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs(), new ScheduleManager());
}
@Test
public void execute_listIsNotFiltered_showsSameList() {
- assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel);
+ assertCommandSuccess(new ListCommand("all"), model, ListCommand.MESSAGE_SUCCESS, expectedModel);
}
@Test
public void execute_listIsFiltered_showsEverything() {
showPersonAtIndex(model, INDEX_FIRST_PERSON);
- assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel);
+ assertCommandSuccess(new ListCommand("main"), model, ListCommand.MESSAGE_SUCCESS, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/ScheduleCommandTest.java b/src/test/java/seedu/address/logic/commands/ScheduleCommandTest.java
new file mode 100644
index 00000000000..2cb5a6fdd37
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/ScheduleCommandTest.java
@@ -0,0 +1,296 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import java.nio.file.Path;
+import java.time.LocalDate;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+
+import org.junit.jupiter.api.Test;
+
+import javafx.collections.ObservableList;
+import seedu.address.commons.core.GuiSettings;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyUserPrefs;
+import seedu.address.model.person.PayrollWrapper;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleDate;
+import seedu.address.testutil.PersonBuilder;
+
+public class ScheduleCommandTest {
+
+ @Test
+ public void constructor_nullPerson_throwsNullPointerException() {
+ Phone phoneNumber = new Phone("92345678");
+ LocalDate date = LocalDate.now();
+ assertThrows(NullPointerException.class, () -> new ScheduleCommand(null, null));
+ assertThrows(NullPointerException.class, () -> new ScheduleCommand(null, date));
+ assertThrows(NullPointerException.class, () -> new ScheduleCommand(phoneNumber, null));
+ }
+
+ @Test
+ public void execute_personNotFound_throwsCommandException() {
+ Person person = new PersonBuilder().build();
+ ModelStubWithGetPersonByPhoneNumber modelStub = new ModelStubWithGetPersonByPhoneNumber(person);
+ Phone phoneNumber = new Phone("92315678");
+ LocalDate date = LocalDate.now();
+
+ assertThrows(CommandException.class, () -> new ScheduleCommand(phoneNumber, date).execute(modelStub));
+ }
+
+ @Test
+ public void equals() {
+ Phone phoneNumber1 = new Phone("92345678");
+ Phone phoneNumber2 = new Phone("91345678");
+ LocalDate date = LocalDate.now();
+ ScheduleCommand scheduleCommand1 = new ScheduleCommand(phoneNumber1, date);
+ ScheduleCommand scheduleCommand2 = new ScheduleCommand(phoneNumber2, date);
+
+ // same object -> returns true
+ assertTrue(scheduleCommand1.equals(scheduleCommand1));
+
+ // same values -> returns true
+ ScheduleCommand scheduleCommand1Copy = new ScheduleCommand(phoneNumber1, date);
+ assertTrue(scheduleCommand1.equals(scheduleCommand1Copy));
+
+ // different types -> returns false
+ assertFalse(scheduleCommand1.equals(1));
+
+ // null -> returns false
+ assertFalse(scheduleCommand1.equals(null));
+
+ // different person -> returns false
+ assertFalse(scheduleCommand1.equals(scheduleCommand2));
+ }
+
+ @Test
+ public void toStringMethod() {
+ Phone phoneNumber = new Phone("92345678");
+ LocalDate date = LocalDate.now();
+ ScheduleCommand scheduleCommand = new ScheduleCommand(phoneNumber, date);
+
+ String expected = ScheduleCommand.class.getCanonicalName() + "{phoneNumber=92345678, date=" + date + "}";
+ assertEquals(expected, scheduleCommand.toString());
+ }
+
+ /**
+ * A default model stub that have all of the methods failing.
+ */
+ private class ModelStub implements Model {
+ @Override
+ public void updatePerson(Person personToUpdate) {
+ throw new AssertionError("This method should not be called.");
+ }
+ @Override
+ public Person getPersonByPhoneNumber(Phone phoneNumber) {
+ throw new AssertionError("This method should not be called.");
+ }
+ @Override
+ public ReadOnlyUserPrefs getUserPrefs() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public GuiSettings getGuiSettings() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setGuiSettings(GuiSettings guiSettings) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public Path getAddressBookFilePath() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setAddressBookFilePath(Path addressBookFilePath) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void addPerson(Person person) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ReadOnlyAddressBook getAddressBook() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setAddressBook(ReadOnlyAddressBook newData) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public boolean hasPerson(Person person) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void deletePerson(Person target) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setPerson(Person target, Person editedPerson) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getFilteredPersonList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getFilteredUnarchivedPersonList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getFilteredArchivedPersonList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void updateFilteredPersonList(Predicate predicate) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setSchedule(Schedule schedule) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public Schedule getSchedule() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public Set getScheduleDates() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void addPersonToSchedule(Person person, LocalDate date) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void removePersonFromSchedule(Person person, LocalDate date) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void archivePerson(Person personToArchive, Person archivedPerson) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void unarchivePerson(Person personToUnarchive, Person unarchivedPerson) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void generatePayroll(LocalDate startDate, LocalDate endDate) {
+ throw new AssertionError("This method should not be called.");
+ };
+
+ @Override
+ public ObservableList getPayrollList() {
+ throw new AssertionError("This method should not be called.");
+ };
+ }
+
+ private class ModelStubWithGetPersonByPhoneNumber extends ModelStub {
+ private final Person person;
+
+ ModelStubWithGetPersonByPhoneNumber(Person person) {
+ requireNonNull(person);
+ this.person = person;
+ }
+
+ @Override
+ public Person getPersonByPhoneNumber(Phone phoneNumber) {
+ if (!person.getPhone().equals(phoneNumber)) {
+ return null;
+ }
+ return person;
+ }
+ }
+
+ private class ModelStubWithScheduleDate extends ModelStub {
+ private final Set scheduleDates = new HashSet<>();
+
+ ModelStubWithScheduleDate(Person person, LocalDate date) {
+ requireNonNull(person);
+ ScheduleDate scheduleDate = new ScheduleDate(date);
+ scheduleDates.add(scheduleDate);
+ }
+
+ @Override
+ public void addPersonToSchedule(Person person, LocalDate date) {
+ requireNonNull(person);
+ ScheduleDate scheduleDate = new ScheduleDate(date);
+ scheduleDates.add(scheduleDate);
+ }
+
+ @Override
+ public Set getScheduleDates() {
+ return scheduleDates;
+ }
+ }
+
+ /**
+ * A Model stub that always accept the person being added to the schedule.
+ */
+ private class ModelStubAcceptingScheduleUpdate extends ModelStub {
+ final Set scheduleDates = new HashSet<>();
+ final Person person;
+
+ ModelStubAcceptingScheduleUpdate(Person person) {
+ requireNonNull(person);
+ this.person = person;
+ }
+
+ @Override
+ public void addPersonToSchedule(Person person, LocalDate date) {
+ requireNonNull(person);
+ ScheduleDate scheduleDate = new ScheduleDate(date);
+ scheduleDates.add(scheduleDate);
+ }
+
+ @Override
+ public Set getScheduleDates() {
+ return scheduleDates;
+ }
+
+ @Override
+ public Person getPersonByPhoneNumber(Phone phoneNumber) {
+ if (!person.getPhone().equals(phoneNumber)) {
+ return null;
+ }
+ return person;
+ }
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
index 5bc11d3cdaa..2037f88d6ea 100644
--- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
@@ -3,194 +3,237 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.BANKDETAILS_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.BANKDETAILS_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.FIRSTNAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.FIRSTNAME_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_FIRSTNAME_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_LASTNAME_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_PAYRATE_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_SEX_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.LASTNAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.LASTNAME_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.PAYRATE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.PAYRATE_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.SEX_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.SEX_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_COOK;
+import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_WAITER;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_FIRSTNAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_LASTNAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PAYRATE_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SEX_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_COOK;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_WAITER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_BANKDETAILS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FIRSTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PAYRATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
import static seedu.address.testutil.TypicalPersons.AMY;
import static seedu.address.testutil.TypicalPersons.BOB;
+//import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import org.junit.jupiter.api.Test;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.AddCommand;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
import seedu.address.model.tag.Tag;
import seedu.address.testutil.PersonBuilder;
+
public class AddCommandParserTest {
private AddCommandParser parser = new AddCommandParser();
@Test
public void parse_allFieldsPresent_success() {
- Person expectedPerson = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND).build();
+ Person expectedPerson = new PersonBuilder(BOB).withTags(VALID_TAG_COOK).build();
// whitespace only preamble
- assertParseSuccess(parser, PREAMBLE_WHITESPACE + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
+ assertParseSuccess(parser, PREAMBLE_WHITESPACE + FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + SEX_DESC_BOB + PAYRATE_DESC_BOB + BANKDETAILS_DESC_BOB + ADDRESS_DESC_BOB + TAG_DESC_COOK,
+ new AddCommand(expectedPerson));
// multiple tags - all accepted
- Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND)
- .build();
+ Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_COOK, VALID_TAG_WAITER)
+ .build();
assertParseSuccess(parser,
- NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
- new AddCommand(expectedPersonMultipleTags));
+ FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB + SEX_DESC_BOB
+ + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB
+ + BANKDETAILS_DESC_BOB + TAG_DESC_WAITER + TAG_DESC_COOK,
+ new AddCommand(expectedPersonMultipleTags));
}
@Test
public void parse_repeatedNonTagValue_failure() {
- String validExpectedPersonString = NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND;
+ String validExpectedPersonString = FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB
+ + PHONE_DESC_BOB + SEX_DESC_BOB + PAYRATE_DESC_BOB
+ + ADDRESS_DESC_BOB + BANKDETAILS_DESC_BOB + TAG_DESC_COOK;
+
+ // multiple first names
+ assertParseFailure(parser, FIRSTNAME_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_FIRSTNAME));
- // multiple names
- assertParseFailure(parser, NAME_DESC_AMY + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME));
+ // multiple last names
+ assertParseFailure(parser, LASTNAME_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_LASTNAME));
// multiple phones
assertParseFailure(parser, PHONE_DESC_AMY + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
- // multiple emails
- assertParseFailure(parser, EMAIL_DESC_AMY + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_EMAIL));
+ // multiple sexes
+ assertParseFailure(parser, SEX_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_SEX));
+
+ // multiple employment types
+ assertParseFailure(parser, PAYRATE_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PAYRATE));
// multiple addresses
assertParseFailure(parser, ADDRESS_DESC_AMY + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
+
+ // multiple bank details
+ assertParseFailure(parser, BANKDETAILS_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_BANKDETAILS));
// multiple fields repeated
assertParseFailure(parser,
- validExpectedPersonString + PHONE_DESC_AMY + EMAIL_DESC_AMY + NAME_DESC_AMY + ADDRESS_DESC_AMY
- + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME, PREFIX_ADDRESS, PREFIX_EMAIL, PREFIX_PHONE));
+ validExpectedPersonString + PHONE_DESC_AMY + FIRSTNAME_DESC_AMY + ADDRESS_DESC_AMY,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_FIRSTNAME,
+ PREFIX_ADDRESS, PREFIX_PHONE));
// invalid value followed by valid value
- // invalid name
- assertParseFailure(parser, INVALID_NAME_DESC + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME));
+ // invalid first name
+ assertParseFailure(parser, INVALID_FIRSTNAME_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_FIRSTNAME));
- // invalid email
- assertParseFailure(parser, INVALID_EMAIL_DESC + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_EMAIL));
+ // invalid last name
+ assertParseFailure(parser, INVALID_LASTNAME_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_LASTNAME));
// invalid phone
assertParseFailure(parser, INVALID_PHONE_DESC + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
-
- // invalid address
- assertParseFailure(parser, INVALID_ADDRESS_DESC + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
// valid value followed by invalid value
- // invalid name
- assertParseFailure(parser, validExpectedPersonString + INVALID_NAME_DESC,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME));
-
- // invalid email
- assertParseFailure(parser, validExpectedPersonString + INVALID_EMAIL_DESC,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_EMAIL));
-
// invalid phone
assertParseFailure(parser, validExpectedPersonString + INVALID_PHONE_DESC,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
-
- // invalid address
- assertParseFailure(parser, validExpectedPersonString + INVALID_ADDRESS_DESC,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
}
@Test
public void parse_optionalFieldsMissing_success() {
// zero tags
Person expectedPerson = new PersonBuilder(AMY).withTags().build();
- assertParseSuccess(parser, NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY + ADDRESS_DESC_AMY,
- new AddCommand(expectedPerson));
+ assertParseSuccess(parser,
+ FIRSTNAME_DESC_AMY + LASTNAME_DESC_AMY + PHONE_DESC_AMY
+ + SEX_DESC_AMY + ADDRESS_DESC_AMY + BANKDETAILS_DESC_AMY
+ + PAYRATE_DESC_AMY, new AddCommand(expectedPerson));
}
@Test
public void parse_compulsoryFieldMissing_failure() {
String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE);
- // missing name prefix
- assertParseFailure(parser, VALID_NAME_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
+ // missing firstname prefix
+ assertParseFailure(parser, VALID_FIRSTNAME_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + SEX_DESC_BOB + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB,
+ expectedMessage);
+
+ // missing lastname prefix
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + VALID_LASTNAME_BOB + PHONE_DESC_BOB
+ + SEX_DESC_BOB + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB,
+ expectedMessage);
// missing phone prefix
- assertParseFailure(parser, NAME_DESC_BOB + VALID_PHONE_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + VALID_PHONE_BOB
+ + SEX_DESC_BOB + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB,
+ expectedMessage);
- // missing email prefix
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + VALID_EMAIL_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
+ // missing sex prefix
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + VALID_SEX_BOB + PAYRATE_DESC_BOB,
+ expectedMessage);
+
+ // missing employment type prefix
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + SEX_DESC_BOB + VALID_PAYRATE_BOB,
+ expectedMessage);
// missing address prefix
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + VALID_ADDRESS_BOB,
- expectedMessage);
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + VALID_ADDRESS_BOB,
+ expectedMessage);
// all prefixes missing
- assertParseFailure(parser, VALID_NAME_BOB + VALID_PHONE_BOB + VALID_EMAIL_BOB + VALID_ADDRESS_BOB,
- expectedMessage);
+ assertParseFailure(parser, VALID_FIRSTNAME_BOB + VALID_LASTNAME_BOB + VALID_PHONE_BOB
+ + VALID_SEX_BOB + VALID_PAYRATE_BOB,
+ expectedMessage);
}
@Test
public void parse_invalidValue_failure() {
// invalid name
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Name.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, INVALID_FIRSTNAME_DESC + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + SEX_DESC_BOB + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_WAITER + TAG_DESC_COOK, Name.MESSAGE_CONSTRAINTS);
+
+ // invalid name
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + INVALID_LASTNAME_DESC + PHONE_DESC_BOB
+ + SEX_DESC_BOB + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_WAITER + TAG_DESC_COOK, Name.MESSAGE_CONSTRAINTS);
// invalid phone
- assertParseFailure(parser, NAME_DESC_BOB + INVALID_PHONE_DESC + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Phone.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + INVALID_PHONE_DESC
+ + SEX_DESC_BOB + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_WAITER + TAG_DESC_COOK, Phone.MESSAGE_CONSTRAINTS);
- // invalid email
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS);
+ // invalid sex
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + INVALID_SEX_DESC + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_WAITER + TAG_DESC_COOK, Sex.MESSAGE_CONSTRAINTS);
- // invalid address
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS);
+ // invalid employment type
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + SEX_DESC_BOB + INVALID_PAYRATE_DESC + ADDRESS_DESC_BOB
+ + TAG_DESC_WAITER + TAG_DESC_COOK, PayRate.MESSAGE_CONSTRAINTS);
// invalid tag
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + SEX_DESC_BOB + PAYRATE_DESC_BOB + ADDRESS_DESC_BOB
+ + INVALID_TAG_DESC + VALID_TAG_COOK, Tag.MESSAGE_CONSTRAINTS);
// two invalid values, only first invalid value reported
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC,
- Name.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, INVALID_FIRSTNAME_DESC + LASTNAME_DESC_BOB + PHONE_DESC_BOB
+ + SEX_DESC_BOB + INVALID_PAYRATE_DESC + ADDRESS_DESC_BOB,
+ Name.MESSAGE_CONSTRAINTS);
// non-empty preamble
- assertParseFailure(parser, PREAMBLE_NON_EMPTY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, PREAMBLE_NON_EMPTY + FIRSTNAME_DESC_BOB + LASTNAME_DESC_BOB
+ + PHONE_DESC_BOB + SEX_DESC_BOB + PAYRATE_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_WAITER + TAG_DESC_COOK,
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
}
diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
index 5a1ab3dbc0c..cc5af8598f4 100644
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
@@ -5,7 +5,6 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
import java.util.Arrays;
import java.util.List;
@@ -25,6 +24,7 @@
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.NameContainsKeywordsPredicate;
import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
import seedu.address.testutil.EditPersonDescriptorBuilder;
import seedu.address.testutil.PersonBuilder;
import seedu.address.testutil.PersonUtil;
@@ -49,8 +49,8 @@ public void parseCommand_clear() throws Exception {
@Test
public void parseCommand_delete() throws Exception {
DeleteCommand command = (DeleteCommand) parser.parseCommand(
- DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
- assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
+ DeleteCommand.COMMAND_WORD + " " + PersonBuilder.DEFAULT_PHONE);
+ assertEquals(new DeleteCommand(new Phone(PersonBuilder.DEFAULT_PHONE)), command);
}
@Test
@@ -58,8 +58,8 @@ public void parseCommand_edit() throws Exception {
Person person = new PersonBuilder().build();
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build();
EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " "
- + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
- assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command);
+ + PersonBuilder.DEFAULT_PHONE + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
+ assertEquals(new EditCommand(new Phone(PersonBuilder.DEFAULT_PHONE), descriptor), command);
}
@Test
@@ -72,7 +72,7 @@ public void parseCommand_exit() throws Exception {
public void parseCommand_find() throws Exception {
List keywords = Arrays.asList("foo", "bar", "baz");
FindCommand command = (FindCommand) parser.parseCommand(
- FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
+ FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
}
@@ -84,8 +84,9 @@ public void parseCommand_help() throws Exception {
@Test
public void parseCommand_list() throws Exception {
- assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand);
- assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " all") instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " main") instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " archive") instanceof ListCommand);
}
@Test
diff --git a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
index 6a40e14a649..e8450d93a84 100644
--- a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
@@ -1,13 +1,14 @@
package seedu.address.logic.parser;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
import org.junit.jupiter.api.Test;
import seedu.address.logic.commands.DeleteCommand;
+import seedu.address.model.person.Phone;
/**
* As we are only doing white-box testing, our test cases do not cover path variations
@@ -22,11 +23,11 @@ public class DeleteCommandParserTest {
@Test
public void parse_validArgs_returnsDeleteCommand() {
- assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_PERSON));
+ assertParseSuccess(parser, VALID_PHONE_AMY, new DeleteCommand(new Phone(VALID_PHONE_AMY)));
}
@Test
public void parse_invalidArgs_throwsParseException() {
- assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "abc", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
}
}
diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
index cc7175172d4..86bce457517 100644
--- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
@@ -3,45 +3,46 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.FIRSTNAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_BANKDETAILS_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_FIRSTNAME_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_LASTNAME_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_PAYRATE_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_SEX_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.LASTNAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.PAYRATE_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_COOK;
+import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_WAITER;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_FIRSTNAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_LASTNAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PAYRATE_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_COOK;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_WAITER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON;
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.index.Index;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
import seedu.address.model.tag.Tag;
import seedu.address.testutil.EditPersonDescriptorBuilder;
@@ -52,15 +53,15 @@ public class EditCommandParserTest {
private static final String MESSAGE_INVALID_FORMAT =
String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE);
- private EditCommandParser parser = new EditCommandParser();
+ private final EditCommandParser parser = new EditCommandParser();
@Test
public void parse_missingParts_failure() {
// no index specified
- assertParseFailure(parser, VALID_NAME_AMY, MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, VALID_FIRSTNAME_AMY, MESSAGE_INVALID_FORMAT);
// no field specified
- assertParseFailure(parser, "1", EditCommand.MESSAGE_NOT_EDITED);
+ assertParseFailure(parser, VALID_PHONE_AMY, EditCommand.MESSAGE_NOT_EDITED);
// no index and no field specified
assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT);
@@ -68,63 +69,70 @@ public void parse_missingParts_failure() {
@Test
public void parse_invalidPreamble_failure() {
- // negative index
- assertParseFailure(parser, "-5" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT);
-
- // zero index
- assertParseFailure(parser, "0" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT);
+ // invalid number
+ assertParseFailure(parser, "0" + FIRSTNAME_DESC_AMY, MESSAGE_INVALID_FORMAT);
// invalid arguments being parsed as preamble
- assertParseFailure(parser, "1 some random string", MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, VALID_PHONE_AMY + "some random string", MESSAGE_INVALID_FORMAT);
// invalid prefix being parsed as preamble
- assertParseFailure(parser, "1 i/ string", MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, VALID_PHONE_AMY + "i/ string", MESSAGE_INVALID_FORMAT);
}
@Test
public void parse_invalidValue_failure() {
- assertParseFailure(parser, "1" + INVALID_NAME_DESC, Name.MESSAGE_CONSTRAINTS); // invalid name
- assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone
- assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email
- assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address
- assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag
-
- // invalid phone followed by valid email
- assertParseFailure(parser, "1" + INVALID_PHONE_DESC + EMAIL_DESC_AMY, Phone.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_FIRSTNAME_DESC,
+ Name.MESSAGE_CONSTRAINTS); // invalid name
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_LASTNAME_DESC,
+ Name.MESSAGE_CONSTRAINTS); // invalid name
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_PHONE_DESC,
+ Phone.MESSAGE_CONSTRAINTS); // invalid phone
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_ADDRESS_DESC,
+ Address.MESSAGE_CONSTRAINTS); // invalid address
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_TAG_DESC,
+ Tag.MESSAGE_CONSTRAINTS); // invalid tag
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_BANKDETAILS_DESC,
+ BankDetails.MESSAGE_CONSTRAINTS); // invalid bank details
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_SEX_DESC,
+ Sex.MESSAGE_CONSTRAINTS); // invalid sex
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_PAYRATE_DESC,
+ PayRate.MESSAGE_CONSTRAINTS); // invalid employment type
// while parsing {@code PREFIX_TAG} alone will reset the tags of the {@code Person} being edited,
// parsing it together with a valid tag results in error
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_DESC_HUSBAND + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_EMPTY + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_EMPTY + TAG_DESC_FRIEND + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
-
+ assertParseFailure(parser, VALID_PHONE_AMY + TAG_DESC_COOK + TAG_DESC_WAITER + TAG_EMPTY,
+ Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, VALID_PHONE_AMY + TAG_DESC_COOK + TAG_EMPTY + TAG_DESC_WAITER,
+ Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, VALID_PHONE_AMY + TAG_EMPTY + TAG_DESC_COOK + TAG_DESC_WAITER,
+ Tag.MESSAGE_CONSTRAINTS);
// multiple invalid values, but only the first invalid value is captured
- assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC + VALID_ADDRESS_AMY + VALID_PHONE_AMY,
- Name.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, VALID_PHONE_AMY + INVALID_FIRSTNAME_DESC + INVALID_PAYRATE_DESC
+ + VALID_PHONE_AMY, Name.MESSAGE_CONSTRAINTS);
}
@Test
public void parse_allFieldsSpecified_success() {
- Index targetIndex = INDEX_SECOND_PERSON;
- String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + TAG_DESC_HUSBAND
- + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + NAME_DESC_AMY + TAG_DESC_FRIEND;
+ Phone targetPhone = new Phone(VALID_PHONE_AMY);
+ String userInput = VALID_PHONE_AMY + PHONE_DESC_AMY + TAG_DESC_WAITER
+ + ADDRESS_DESC_AMY + FIRSTNAME_DESC_AMY + TAG_DESC_COOK + LASTNAME_DESC_AMY;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
- .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
- EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
+ EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withFirstName(VALID_FIRSTNAME_AMY)
+ .withLastName(VALID_LASTNAME_AMY).withPhone(VALID_PHONE_AMY)
+ .withAddress(VALID_ADDRESS_AMY).withTags(VALID_TAG_WAITER, VALID_TAG_COOK).build();
+ EditCommand expectedCommand = new EditCommand(targetPhone, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
@Test
public void parse_someFieldsSpecified_success() {
- Index targetIndex = INDEX_FIRST_PERSON;
- String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + EMAIL_DESC_AMY;
+ Phone targetPhone = new Phone(VALID_PHONE_BOB);
+ String userInput = VALID_PHONE_BOB + PHONE_DESC_BOB + PAYRATE_DESC_BOB;
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_AMY).build();
- EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
+ .withPayRate(VALID_PAYRATE_BOB).build();
+ EditCommand expectedCommand = new EditCommand(targetPhone, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
@@ -132,34 +140,28 @@ public void parse_someFieldsSpecified_success() {
@Test
public void parse_oneFieldSpecified_success() {
// name
- Index targetIndex = INDEX_THIRD_PERSON;
- String userInput = targetIndex.getOneBased() + NAME_DESC_AMY;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY).build();
- EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
- assertParseSuccess(parser, userInput, expectedCommand);
-
- // phone
- userInput = targetIndex.getOneBased() + PHONE_DESC_AMY;
- descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_AMY).build();
- expectedCommand = new EditCommand(targetIndex, descriptor);
- assertParseSuccess(parser, userInput, expectedCommand);
-
- // email
- userInput = targetIndex.getOneBased() + EMAIL_DESC_AMY;
- descriptor = new EditPersonDescriptorBuilder().withEmail(VALID_EMAIL_AMY).build();
- expectedCommand = new EditCommand(targetIndex, descriptor);
+ Phone targetPhone = new Phone(VALID_PHONE_AMY);
+ String userInput = VALID_PHONE_AMY + FIRSTNAME_DESC_AMY;
+ EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withFirstName(VALID_FIRSTNAME_AMY).build();
+ EditCommand expectedCommand = new EditCommand(targetPhone, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
// address
- userInput = targetIndex.getOneBased() + ADDRESS_DESC_AMY;
+ userInput = VALID_PHONE_AMY + ADDRESS_DESC_AMY;
descriptor = new EditPersonDescriptorBuilder().withAddress(VALID_ADDRESS_AMY).build();
- expectedCommand = new EditCommand(targetIndex, descriptor);
+ expectedCommand = new EditCommand(targetPhone, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
// tags
- userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND;
- descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_FRIEND).build();
- expectedCommand = new EditCommand(targetIndex, descriptor);
+ userInput = VALID_PHONE_AMY + TAG_DESC_COOK;
+ descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_COOK).build();
+ expectedCommand = new EditCommand(targetPhone, descriptor);
+ assertParseSuccess(parser, userInput, expectedCommand);
+
+ // phone
+ userInput = VALID_PHONE_AMY + PHONE_DESC_AMY;
+ descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_AMY).build();
+ expectedCommand = new EditCommand(targetPhone, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
@@ -169,39 +171,39 @@ public void parse_multipleRepeatedFields_failure() {
// AddCommandParserTest#parse_repeatedNonTagValue_failure()
// valid followed by invalid
- Index targetIndex = INDEX_FIRST_PERSON;
- String userInput = targetIndex.getOneBased() + INVALID_PHONE_DESC + PHONE_DESC_BOB;
+ Phone targetPhone = new Phone(VALID_PHONE_AMY);
+ String userInput = targetPhone + INVALID_PHONE_DESC + PHONE_DESC_BOB;
assertParseFailure(parser, userInput, Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
// invalid followed by valid
- userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + INVALID_PHONE_DESC;
+ userInput = targetPhone + PHONE_DESC_BOB + INVALID_PHONE_DESC;
assertParseFailure(parser, userInput, Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
// mulltiple valid fields repeated
- userInput = targetIndex.getOneBased() + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY
- + TAG_DESC_FRIEND + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY + TAG_DESC_FRIEND
- + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB + TAG_DESC_HUSBAND;
+ userInput = targetPhone + PHONE_DESC_AMY + ADDRESS_DESC_AMY
+ + TAG_DESC_COOK + PHONE_DESC_AMY + ADDRESS_DESC_AMY + TAG_DESC_COOK
+ + PHONE_DESC_BOB + ADDRESS_DESC_BOB + TAG_DESC_WAITER;
assertParseFailure(parser, userInput,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_ADDRESS));
// multiple invalid values
- userInput = targetIndex.getOneBased() + INVALID_PHONE_DESC + INVALID_ADDRESS_DESC + INVALID_EMAIL_DESC
- + INVALID_PHONE_DESC + INVALID_ADDRESS_DESC + INVALID_EMAIL_DESC;
+ userInput = targetPhone + INVALID_PHONE_DESC + INVALID_ADDRESS_DESC
+ + INVALID_PHONE_DESC + INVALID_ADDRESS_DESC;
assertParseFailure(parser, userInput,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_ADDRESS));
}
@Test
public void parse_resetTags_success() {
- Index targetIndex = INDEX_THIRD_PERSON;
- String userInput = targetIndex.getOneBased() + TAG_EMPTY;
+ Phone targetPhone = new Phone(VALID_PHONE_AMY);
+ String userInput = targetPhone + TAG_EMPTY;
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags().build();
- EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
+ EditCommand expectedCommand = new EditCommand(targetPhone, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
index 4256788b1a7..84331d2e323 100644
--- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
+++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
@@ -15,7 +15,6 @@
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
import seedu.address.model.tag.Tag;
@@ -23,14 +22,15 @@
public class ParserUtilTest {
private static final String INVALID_NAME = "R@chel";
private static final String INVALID_PHONE = "+651234";
- private static final String INVALID_ADDRESS = " ";
- private static final String INVALID_EMAIL = "example.com";
+ private static final String INVALID_SEX = "x";
+ private static final String INVALID_PAYRATE = "invalid";
private static final String INVALID_TAG = "#friend";
private static final String VALID_NAME = "Rachel Walker";
- private static final String VALID_PHONE = "123456";
+ private static final String VALID_PHONE = "93213213";
private static final String VALID_ADDRESS = "123 Main Street #0505";
- private static final String VALID_EMAIL = "rachel@example.com";
+ private static final String VALID_SEX = "f";
+ private static final String VALID_EMPLOYMENTTYPE = "ft";
private static final String VALID_TAG_1 = "friend";
private static final String VALID_TAG_2 = "neighbour";
@@ -103,49 +103,41 @@ public void parsePhone_validValueWithWhitespace_returnsTrimmedPhone() throws Exc
}
@Test
- public void parseAddress_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseAddress((String) null));
+ public void parseSex_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseSex((String) null));
}
@Test
- public void parseAddress_invalidValue_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseAddress(INVALID_ADDRESS));
+ public void parseSex_invalidValue_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseSex(INVALID_SEX));
}
@Test
- public void parseAddress_validValueWithoutWhitespace_returnsAddress() throws Exception {
- Address expectedAddress = new Address(VALID_ADDRESS);
- assertEquals(expectedAddress, ParserUtil.parseAddress(VALID_ADDRESS));
+ public void parsePayRate_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parsePayRate((String) null));
}
@Test
- public void parseAddress_validValueWithWhitespace_returnsTrimmedAddress() throws Exception {
- String addressWithWhitespace = WHITESPACE + VALID_ADDRESS + WHITESPACE;
- Address expectedAddress = new Address(VALID_ADDRESS);
- assertEquals(expectedAddress, ParserUtil.parseAddress(addressWithWhitespace));
+ public void parsePayRate_invalidValue_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parsePayRate(INVALID_PAYRATE));
}
@Test
- public void parseEmail_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseEmail((String) null));
- }
-
- @Test
- public void parseEmail_invalidValue_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseEmail(INVALID_EMAIL));
+ public void parseAddress_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseAddress((String) null));
}
@Test
- public void parseEmail_validValueWithoutWhitespace_returnsEmail() throws Exception {
- Email expectedEmail = new Email(VALID_EMAIL);
- assertEquals(expectedEmail, ParserUtil.parseEmail(VALID_EMAIL));
+ public void parseAddress_validValueWithoutWhitespace_returnsAddress() throws Exception {
+ Address expectedAddress = new Address(VALID_ADDRESS);
+ assertEquals(expectedAddress, ParserUtil.parseAddress(VALID_ADDRESS));
}
@Test
- public void parseEmail_validValueWithWhitespace_returnsTrimmedEmail() throws Exception {
- String emailWithWhitespace = WHITESPACE + VALID_EMAIL + WHITESPACE;
- Email expectedEmail = new Email(VALID_EMAIL);
- assertEquals(expectedEmail, ParserUtil.parseEmail(emailWithWhitespace));
+ public void parseAddress_validValueWithWhitespace_returnsTrimmedAddress() throws Exception {
+ String addressWithWhitespace = WHITESPACE + VALID_ADDRESS + WHITESPACE;
+ Address expectedAddress = new Address(VALID_ADDRESS);
+ assertEquals(expectedAddress, ParserUtil.parseAddress(addressWithWhitespace));
}
@Test
diff --git a/src/test/java/seedu/address/logic/parser/ScheduleCommandParserTest.java b/src/test/java/seedu/address/logic/parser/ScheduleCommandParserTest.java
new file mode 100644
index 00000000000..927ebf4c14d
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/ScheduleCommandParserTest.java
@@ -0,0 +1,36 @@
+package seedu.address.logic.parser;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.time.LocalDate;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.ScheduleCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Phone;
+
+public class ScheduleCommandParserTest {
+
+ private final ScheduleCommandParser parser = new ScheduleCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsScheduleCommand() throws ParseException {
+ String args = "12345678 2022-12-31";
+ ScheduleCommand expectedCommand = new ScheduleCommand(new Phone("12345678"), LocalDate.parse("2022-12-31"));
+ assertEquals(expectedCommand, parser.parse(args));
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ String args = "12345678";
+ assertThrows(ParseException.class, () -> parser.parse(args));
+ }
+
+ @Test
+ public void parse_invalidDate_throwsParseException() {
+ String args = "12345678 invalidDate";
+ assertThrows(ParseException.class, () -> parser.parse(args));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/UnscheduleCommandParserTest.java b/src/test/java/seedu/address/logic/parser/UnscheduleCommandParserTest.java
new file mode 100644
index 00000000000..fe3fc85c506
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/UnscheduleCommandParserTest.java
@@ -0,0 +1,37 @@
+package seedu.address.logic.parser;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.time.LocalDate;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.ScheduleCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Phone;
+
+
+public class UnscheduleCommandParserTest {
+
+ private final ScheduleCommandParser parser = new ScheduleCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsScheduleCommand() throws ParseException {
+ String args = "12345678 2022-12-31";
+ ScheduleCommand expectedCommand = new ScheduleCommand(new Phone("12345678"), LocalDate.parse("2022-12-31"));
+ assertEquals(expectedCommand, parser.parse(args));
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ String args = "12345678";
+ assertThrows(ParseException.class, () -> parser.parse(args));
+ }
+
+ @Test
+ public void parse_invalidDate_throwsParseException() {
+ String args = "12345678 invalidDate";
+ assertThrows(ParseException.class, () -> parser.parse(args));
+ }
+}
diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/seedu/address/model/AddressBookTest.java
index 68c8c5ba4d5..f44734ceecb 100644
--- a/src/test/java/seedu/address/model/AddressBookTest.java
+++ b/src/test/java/seedu/address/model/AddressBookTest.java
@@ -4,7 +4,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_WAITER;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.ALICE;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
@@ -46,7 +46,7 @@ public void resetData_withValidReadOnlyAddressBook_replacesData() {
@Test
public void resetData_withDuplicatePersons_throwsDuplicatePersonException() {
// Two persons with the same identity fields
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
+ Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_WAITER)
.build();
List newPersons = Arrays.asList(ALICE, editedAlice);
AddressBookStub newData = new AddressBookStub(newPersons);
@@ -73,7 +73,7 @@ public void hasPerson_personInAddressBook_returnsTrue() {
@Test
public void hasPerson_personWithSameIdentityFieldsInAddressBook_returnsTrue() {
addressBook.addPerson(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
+ Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_WAITER)
.build();
assertTrue(addressBook.hasPerson(editedAlice));
}
diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java
index 2cf1418d116..7c34a137a31 100644
--- a/src/test/java/seedu/address/model/ModelManagerTest.java
+++ b/src/test/java/seedu/address/model/ModelManagerTest.java
@@ -16,6 +16,8 @@
import seedu.address.commons.core.GuiSettings;
import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleManager;
import seedu.address.testutil.AddressBookBuilder;
public class ModelManagerTest {
@@ -26,6 +28,7 @@ public class ModelManagerTest {
public void constructor() {
assertEquals(new UserPrefs(), modelManager.getUserPrefs());
assertEquals(new GuiSettings(), modelManager.getGuiSettings());
+ assertEquals(new ScheduleManager(), modelManager.getSchedule());
assertEquals(new AddressBook(), new AddressBook(modelManager.getAddressBook()));
}
@@ -98,10 +101,11 @@ public void equals() {
AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build();
AddressBook differentAddressBook = new AddressBook();
UserPrefs userPrefs = new UserPrefs();
+ Schedule schedule = new ScheduleManager();
// same values -> returns true
- modelManager = new ModelManager(addressBook, userPrefs);
- ModelManager modelManagerCopy = new ModelManager(addressBook, userPrefs);
+ modelManager = new ModelManager(addressBook, userPrefs, schedule);
+ ModelManager modelManagerCopy = new ModelManager(addressBook, userPrefs, schedule);
assertTrue(modelManager.equals(modelManagerCopy));
// same object -> returns true
@@ -114,12 +118,12 @@ public void equals() {
assertFalse(modelManager.equals(5));
// different addressBook -> returns false
- assertFalse(modelManager.equals(new ModelManager(differentAddressBook, userPrefs)));
+ assertFalse(modelManager.equals(new ModelManager(differentAddressBook, userPrefs, schedule)));
// different filteredList -> returns false
- String[] keywords = ALICE.getName().fullName.split("\\s+");
+ String[] keywords = ALICE.getName().value.split("\\s+");
modelManager.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(keywords)));
- assertFalse(modelManager.equals(new ModelManager(addressBook, userPrefs)));
+ assertFalse(modelManager.equals(new ModelManager(addressBook, userPrefs, schedule)));
// resets modelManager to initial state for upcoming tests
modelManager.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
@@ -127,6 +131,6 @@ public void equals() {
// different userPrefs -> returns false
UserPrefs differentUserPrefs = new UserPrefs();
differentUserPrefs.setAddressBookFilePath(Paths.get("differentFilePath"));
- assertFalse(modelManager.equals(new ModelManager(addressBook, differentUserPrefs)));
+ assertFalse(modelManager.equals(new ModelManager(addressBook, differentUserPrefs, schedule)));
}
}
diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/seedu/address/model/person/AddressTest.java
index 314885eca26..e334b8664bc 100644
--- a/src/test/java/seedu/address/model/person/AddressTest.java
+++ b/src/test/java/seedu/address/model/person/AddressTest.java
@@ -13,21 +13,11 @@ public void constructor_null_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> new Address(null));
}
- @Test
- public void constructor_invalidAddress_throwsIllegalArgumentException() {
- String invalidAddress = "";
- assertThrows(IllegalArgumentException.class, () -> new Address(invalidAddress));
- }
-
@Test
public void isValidAddress() {
// null address
assertThrows(NullPointerException.class, () -> Address.isValidAddress(null));
- // invalid addresses
- assertFalse(Address.isValidAddress("")); // empty string
- assertFalse(Address.isValidAddress(" ")); // spaces only
-
// valid addresses
assertTrue(Address.isValidAddress("Blk 456, Den Road, #01-355"));
assertTrue(Address.isValidAddress("-")); // one character
diff --git a/src/test/java/seedu/address/model/person/BankDetailsTest.java b/src/test/java/seedu/address/model/person/BankDetailsTest.java
new file mode 100644
index 00000000000..b1616f4c032
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/BankDetailsTest.java
@@ -0,0 +1,61 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class BankDetailsTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new BankDetails(null));
+ }
+
+ @Test
+ public void constructor_invalidBankDetails_throwsIllegalArgumentException() {
+ String invalidBankDetails = "32132-423421";
+ assertThrows(IllegalArgumentException.class, () -> new BankDetails(invalidBankDetails));
+ }
+
+ @Test
+ public void isValidBankDetails() {
+ // null BankDetails number
+ assertThrows(NullPointerException.class, () -> BankDetails.isValidBankAccount(null));
+
+ // invalid BankDetails numbers
+ assertFalse(BankDetails.isValidBankAccount("mt"));
+ assertFalse(BankDetails.isValidBankAccount("1231-421321"));
+ assertFalse(BankDetails.isValidBankAccount("1234567890"));
+
+ // valid BankDetails numbers
+ assertTrue(BankDetails.isValidBankAccount("posb 123456789"));
+ assertTrue(BankDetails.isValidBankAccount("ocbc 1234567"));
+ assertTrue(BankDetails.isValidBankAccount("dbs 1234567890"));
+ assertTrue(BankDetails.isValidBankAccount("uob 1234567890"));
+ assertTrue(BankDetails.isValidBankAccount("standard chartered 1234567890"));
+ assertTrue(BankDetails.isValidBankAccount("hsbc 12345678901234"));
+ assertTrue(BankDetails.isValidBankAccount("other maybank 1234567890123"));
+ }
+
+ @Test
+ public void equals() {
+ BankDetails bankDetails = new BankDetails("posb 123123123");
+
+ // same values -> returns true
+ assertTrue(bankDetails.equals(new BankDetails("posb 123123123")));
+
+ // same object -> returns true
+ assertTrue(bankDetails.equals(bankDetails));
+
+ // null -> returns false
+ assertFalse(bankDetails.equals(null));
+
+ // different types -> returns false
+ assertFalse(bankDetails.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(bankDetails.equals(new BankDetails("uob 3987398782")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/EmailTest.java b/src/test/java/seedu/address/model/person/EmailTest.java
deleted file mode 100644
index f08cdff0a64..00000000000
--- a/src/test/java/seedu/address/model/person/EmailTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
-
-import org.junit.jupiter.api.Test;
-
-public class EmailTest {
-
- @Test
- public void constructor_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new Email(null));
- }
-
- @Test
- public void constructor_invalidEmail_throwsIllegalArgumentException() {
- String invalidEmail = "";
- assertThrows(IllegalArgumentException.class, () -> new Email(invalidEmail));
- }
-
- @Test
- public void isValidEmail() {
- // null email
- assertThrows(NullPointerException.class, () -> Email.isValidEmail(null));
-
- // blank email
- assertFalse(Email.isValidEmail("")); // empty string
- assertFalse(Email.isValidEmail(" ")); // spaces only
-
- // missing parts
- assertFalse(Email.isValidEmail("@example.com")); // missing local part
- assertFalse(Email.isValidEmail("peterjackexample.com")); // missing '@' symbol
- assertFalse(Email.isValidEmail("peterjack@")); // missing domain name
-
- // invalid parts
- assertFalse(Email.isValidEmail("peterjack@-")); // invalid domain name
- assertFalse(Email.isValidEmail("peterjack@exam_ple.com")); // underscore in domain name
- assertFalse(Email.isValidEmail("peter jack@example.com")); // spaces in local part
- assertFalse(Email.isValidEmail("peterjack@exam ple.com")); // spaces in domain name
- assertFalse(Email.isValidEmail(" peterjack@example.com")); // leading space
- assertFalse(Email.isValidEmail("peterjack@example.com ")); // trailing space
- assertFalse(Email.isValidEmail("peterjack@@example.com")); // double '@' symbol
- assertFalse(Email.isValidEmail("peter@jack@example.com")); // '@' symbol in local part
- assertFalse(Email.isValidEmail("-peterjack@example.com")); // local part starts with a hyphen
- assertFalse(Email.isValidEmail("peterjack-@example.com")); // local part ends with a hyphen
- assertFalse(Email.isValidEmail("peter..jack@example.com")); // local part has two consecutive periods
- assertFalse(Email.isValidEmail("peterjack@example@com")); // '@' symbol in domain name
- assertFalse(Email.isValidEmail("peterjack@.example.com")); // domain name starts with a period
- assertFalse(Email.isValidEmail("peterjack@example.com.")); // domain name ends with a period
- assertFalse(Email.isValidEmail("peterjack@-example.com")); // domain name starts with a hyphen
- assertFalse(Email.isValidEmail("peterjack@example.com-")); // domain name ends with a hyphen
- assertFalse(Email.isValidEmail("peterjack@example.c")); // top level domain has less than two chars
-
- // valid email
- assertTrue(Email.isValidEmail("PeterJack_1190@example.com")); // underscore in local part
- assertTrue(Email.isValidEmail("PeterJack.1190@example.com")); // period in local part
- assertTrue(Email.isValidEmail("PeterJack+1190@example.com")); // '+' symbol in local part
- assertTrue(Email.isValidEmail("PeterJack-1190@example.com")); // hyphen in local part
- assertTrue(Email.isValidEmail("a@bc")); // minimal
- assertTrue(Email.isValidEmail("test@localhost")); // alphabets only
- assertTrue(Email.isValidEmail("123@145")); // numeric local part and domain name
- assertTrue(Email.isValidEmail("a1+be.d@example1.com")); // mixture of alphanumeric and special characters
- assertTrue(Email.isValidEmail("peter_jack@very-very-very-long-example.com")); // long domain name
- assertTrue(Email.isValidEmail("if.you.dream.it_you.can.do.it@example.com")); // long local part
- assertTrue(Email.isValidEmail("e1234567@u.nus.edu")); // more than one period in domain
- }
-
- @Test
- public void equals() {
- Email email = new Email("valid@email");
-
- // same values -> returns true
- assertTrue(email.equals(new Email("valid@email")));
-
- // same object -> returns true
- assertTrue(email.equals(email));
-
- // null -> returns false
- assertFalse(email.equals(null));
-
- // different types -> returns false
- assertFalse(email.equals(5.0f));
-
- // different values -> returns false
- assertFalse(email.equals(new Email("other.valid@email")));
- }
-}
diff --git a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
index 6b3fd90ade7..81ad791496f 100644
--- a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
+++ b/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
@@ -43,35 +43,35 @@ public void equals() {
public void test_nameContainsKeywords_returnsTrue() {
// One keyword
NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Alice"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new PersonBuilder().withFirstName("Alice").withLastName("Bob").build()));
// Multiple keywords
predicate = new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new PersonBuilder().withFirstName("Alice").withLastName("Bob").build()));
// Only one matching keyword
predicate = new NameContainsKeywordsPredicate(Arrays.asList("Bob", "Carol"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Carol").build()));
+ assertTrue(predicate.test(new PersonBuilder().withFirstName("Alice").withLastName("Carol").build()));
// Mixed-case keywords
predicate = new NameContainsKeywordsPredicate(Arrays.asList("aLIce", "bOB"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new PersonBuilder().withFirstName("Alice").withLastName("Bob").build()));
}
@Test
public void test_nameDoesNotContainKeywords_returnsFalse() {
// Zero keywords
NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.emptyList());
- assertFalse(predicate.test(new PersonBuilder().withName("Alice").build()));
+ assertFalse(predicate.test(new PersonBuilder().withFirstName("Alice").withLastName("Bob").build()));
// Non-matching keyword
predicate = new NameContainsKeywordsPredicate(Arrays.asList("Carol"));
- assertFalse(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertFalse(predicate.test(new PersonBuilder().withFirstName("Alice").withLastName("Bob").build()));
- // Keywords match phone, email and address, but does not match name
- predicate = new NameContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com", "Main", "Street"));
- assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
- .withEmail("alice@email.com").withAddress("Main Street").build()));
+ // Keywords match phone and address, but does not match name
+ predicate = new NameContainsKeywordsPredicate(Arrays.asList("12345", "Main", "Street"));
+ assertFalse(predicate.test(new PersonBuilder().withFirstName("Alice").withLastName("Bob").withPhone("93232321")
+ .withAddress("Main Street").build()));
}
@Test
diff --git a/src/test/java/seedu/address/model/person/NameTest.java b/src/test/java/seedu/address/model/person/NameTest.java
index 94e3dd726bd..13f63f38742 100644
--- a/src/test/java/seedu/address/model/person/NameTest.java
+++ b/src/test/java/seedu/address/model/person/NameTest.java
@@ -15,7 +15,7 @@ public void constructor_null_throwsNullPointerException() {
@Test
public void constructor_invalidName_throwsIllegalArgumentException() {
- String invalidName = "";
+ String invalidName = "g*3";
assertThrows(IllegalArgumentException.class, () -> new Name(invalidName));
}
@@ -25,12 +25,12 @@ public void isValidName() {
assertThrows(NullPointerException.class, () -> Name.isValidName(null));
// invalid name
- assertFalse(Name.isValidName("")); // empty string
assertFalse(Name.isValidName(" ")); // spaces only
assertFalse(Name.isValidName("^")); // only non-alphanumeric characters
assertFalse(Name.isValidName("peter*")); // contains non-alphanumeric characters
// valid name
+ assertTrue(Name.isValidName("")); // empty string
assertTrue(Name.isValidName("peter jack")); // alphabets only
assertTrue(Name.isValidName("12345")); // numbers only
assertTrue(Name.isValidName("peter the 2nd")); // alphanumeric characters
diff --git a/src/test/java/seedu/address/model/person/PayRateTest.java b/src/test/java/seedu/address/model/person/PayRateTest.java
new file mode 100644
index 00000000000..f5380d20a01
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PayRateTest.java
@@ -0,0 +1,42 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class PayRateTest {
+
+ @Test
+ public void isValidPayRate() {
+
+ // invalid pay rates
+ assertFalse(PayRate.isValidPayRate("")); // empty string
+ assertFalse(PayRate.isValidPayRate(" ")); // spaces only
+ assertFalse(PayRate.isValidPayRate("abc")); // non-numeric string
+ assertFalse(PayRate.isValidPayRate("-5.0")); // negative pay rate
+
+ // valid pay rates
+ assertTrue(PayRate.isValidPayRate("5.0"));
+ assertTrue(PayRate.isValidPayRate("10.5"));
+ assertTrue(PayRate.isValidPayRate("100.75"));
+ }
+
+
+ @Test
+ public void equals() {
+ PayRate payRate = new PayRate(15);
+
+ // same values -> returns true
+ assertTrue(payRate.equals(new PayRate(15)));
+
+ // same object -> returns true
+ assertTrue(payRate.equals(payRate));
+
+ // different types -> returns false
+ assertFalse(payRate.equals("abc"));
+
+ // different values -> returns false
+ assertFalse(payRate.equals(new PayRate(14)));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java
index 31a10d156c9..28926e95450 100644
--- a/src/test/java/seedu/address/model/person/PersonTest.java
+++ b/src/test/java/seedu/address/model/person/PersonTest.java
@@ -4,10 +4,12 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_FIRSTNAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_FIRSTNAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_LASTNAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_LASTNAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_WAITER;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.ALICE;
import static seedu.address.testutil.TypicalPersons.BOB;
@@ -32,23 +34,18 @@ public void isSamePerson() {
// null -> returns false
assertFalse(ALICE.isSamePerson(null));
- // same name, all other attributes different -> returns true
- Person editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
- .withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND).build();
- assertTrue(ALICE.isSamePerson(editedAlice));
-
- // different name, all other attributes same -> returns false
- editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build();
+ // same name, all other attributes different -> returns false
+ Person editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB)
+ .withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_WAITER).build();
assertFalse(ALICE.isSamePerson(editedAlice));
- // name differs in case, all other attributes same -> returns false
- Person editedBob = new PersonBuilder(BOB).withName(VALID_NAME_BOB.toLowerCase()).build();
- assertFalse(BOB.isSamePerson(editedBob));
+ // different first name, same phone number -> returns true
+ Person editedBob = new PersonBuilder(BOB).withFirstName(VALID_FIRSTNAME_AMY).build();
+ assertTrue(BOB.isSamePerson(editedBob));
- // name has trailing spaces, all other attributes same -> returns false
- String nameWithTrailingSpaces = VALID_NAME_BOB + " ";
- editedBob = new PersonBuilder(BOB).withName(nameWithTrailingSpaces).build();
- assertFalse(BOB.isSamePerson(editedBob));
+ // different first name, same phone number -> returns true
+ editedBob = new PersonBuilder(BOB).withFirstName(VALID_FIRSTNAME_BOB).withLastName(VALID_LASTNAME_AMY).build();
+ assertTrue(BOB.isSamePerson(editedBob));
}
@Test
@@ -69,16 +66,16 @@ public void equals() {
// different person -> returns false
assertFalse(ALICE.equals(BOB));
- // different name -> returns false
- Person editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build();
+ // different first name -> returns false
+ Person editedAlice = new PersonBuilder(ALICE).withFirstName(VALID_FIRSTNAME_BOB).build();
assertFalse(ALICE.equals(editedAlice));
- // different phone -> returns false
- editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).build();
+ // different last name -> returns false
+ editedAlice = new PersonBuilder(ALICE).withLastName(VALID_LASTNAME_BOB).build();
assertFalse(ALICE.equals(editedAlice));
- // different email -> returns false
- editedAlice = new PersonBuilder(ALICE).withEmail(VALID_EMAIL_BOB).build();
+ // different phone -> returns false
+ editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).build();
assertFalse(ALICE.equals(editedAlice));
// different address -> returns false
@@ -86,14 +83,22 @@ public void equals() {
assertFalse(ALICE.equals(editedAlice));
// different tags -> returns false
- editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build();
+ editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_WAITER).build();
assertFalse(ALICE.equals(editedAlice));
}
@Test
public void toStringMethod() {
- String expected = Person.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone()
- + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + "}";
+ String expected =
+ Person.class.getCanonicalName() + "{firstName=" + ALICE.getFirstName()
+ + ", lastName=" + ALICE.getLastName()
+ + ", phone=" + ALICE.getPhone()
+ + ", sex=" + ALICE.getSex()
+ + ", payRate=" + ALICE.getPayRate()
+ + ", address=" + ALICE.getAddress()
+ + ", bankDetails=" + ALICE.getBankDetails()
+ + ", tags=" + ALICE.getTags()
+ + ", archiveStatus=" + ALICE.getArchiveStatus() + "}";
assertEquals(expected, ALICE.toString());
}
}
diff --git a/src/test/java/seedu/address/model/person/PhoneTest.java b/src/test/java/seedu/address/model/person/PhoneTest.java
index deaaa5ba190..34f30ecdc42 100644
--- a/src/test/java/seedu/address/model/person/PhoneTest.java
+++ b/src/test/java/seedu/address/model/person/PhoneTest.java
@@ -33,17 +33,15 @@ public void isValidPhone() {
assertFalse(Phone.isValidPhone("9312 1534")); // spaces within digits
// valid phone numbers
- assertTrue(Phone.isValidPhone("911")); // exactly 3 numbers
assertTrue(Phone.isValidPhone("93121534"));
- assertTrue(Phone.isValidPhone("124293842033123")); // long phone numbers
}
@Test
public void equals() {
- Phone phone = new Phone("999");
+ Phone phone = new Phone("99943213");
// same values -> returns true
- assertTrue(phone.equals(new Phone("999")));
+ assertTrue(phone.equals(new Phone("99943213")));
// same object -> returns true
assertTrue(phone.equals(phone));
@@ -55,6 +53,6 @@ public void equals() {
assertFalse(phone.equals(5.0f));
// different values -> returns false
- assertFalse(phone.equals(new Phone("995")));
+ assertFalse(phone.equals(new Phone("99943233")));
}
}
diff --git a/src/test/java/seedu/address/model/person/SexTest.java b/src/test/java/seedu/address/model/person/SexTest.java
new file mode 100644
index 00000000000..896e02063b5
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/SexTest.java
@@ -0,0 +1,57 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class SexTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Sex(null));
+ }
+
+ @Test
+ public void constructor_invalidSex_throwsIllegalArgumentException() {
+ String invalidSex = "";
+ assertThrows(IllegalArgumentException.class, () -> new Sex(invalidSex));
+ }
+
+ @Test
+ public void isValidSex() {
+ // null Sex number
+ assertThrows(NullPointerException.class, () -> Sex.isValidSex(null));
+
+ // invalid Sex numbers
+ assertFalse(Sex.isValidSex("")); // empty string
+ assertFalse(Sex.isValidSex(" ")); // spaces only
+ assertFalse(Sex.isValidSex("mf"));
+ assertFalse(Sex.isValidSex("3")); // numeric
+
+ // valid Sex numbers
+ assertTrue(Sex.isValidSex("f"));
+ assertTrue(Sex.isValidSex("m"));
+ }
+
+ @Test
+ public void equals() {
+ Sex sex = new Sex("f");
+
+ // same values -> returns true
+ assertTrue(sex.equals(new Sex("f")));
+
+ // same object -> returns true
+ assertTrue(sex.equals(sex));
+
+ // null -> returns false
+ assertFalse(sex.equals(null));
+
+ // different types -> returns false
+ assertFalse(sex.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(sex.equals(new Sex("m")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/UniquePersonListTest.java b/src/test/java/seedu/address/model/person/UniquePersonListTest.java
index 17ae501df08..706ea59e8e8 100644
--- a/src/test/java/seedu/address/model/person/UniquePersonListTest.java
+++ b/src/test/java/seedu/address/model/person/UniquePersonListTest.java
@@ -4,7 +4,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_WAITER;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.ALICE;
import static seedu.address.testutil.TypicalPersons.BOB;
@@ -42,7 +42,7 @@ public void contains_personInList_returnsTrue() {
@Test
public void contains_personWithSameIdentityFieldsInList_returnsTrue() {
uniquePersonList.add(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
+ Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_WAITER)
.build();
assertTrue(uniquePersonList.contains(editedAlice));
}
@@ -85,7 +85,7 @@ public void setPerson_editedPersonIsSamePerson_success() {
@Test
public void setPerson_editedPersonHasSameIdentity_success() {
uniquePersonList.add(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
+ Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_WAITER)
.build();
uniquePersonList.setPerson(ALICE, editedAlice);
UniquePersonList expectedUniquePersonList = new UniquePersonList();
diff --git a/src/test/java/seedu/address/model/schedule/ScheduleDateTest.java b/src/test/java/seedu/address/model/schedule/ScheduleDateTest.java
new file mode 100644
index 00000000000..49be08a4af1
--- /dev/null
+++ b/src/test/java/seedu/address/model/schedule/ScheduleDateTest.java
@@ -0,0 +1,69 @@
+package seedu.address.model.schedule;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.time.LocalDate;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.person.Person;
+import seedu.address.testutil.PersonBuilder;
+
+public class ScheduleDateTest {
+
+ @Test
+ public void constructor_validDate_success() {
+ LocalDate date = LocalDate.now();
+ ScheduleDate scheduleDate = new ScheduleDate(date);
+ assertEquals(date, scheduleDate.getDate());
+ assertTrue(scheduleDate.getPersons().isEmpty());
+ }
+
+ @Test
+ public void addPerson_validPerson_success() {
+ LocalDate date = LocalDate.now();
+ ScheduleDate scheduleDate = new ScheduleDate(date);
+ Person person = new PersonBuilder().build();
+ scheduleDate.addPerson(person);
+ assertTrue(scheduleDate.hasPerson(person));
+ assertEquals(1, scheduleDate.getPersons().size());
+ assertEquals(person, scheduleDate.getPersons().get(0));
+ }
+
+ @Test
+ public void removePerson_validPerson_success() {
+ LocalDate date = LocalDate.now();
+ ScheduleDate scheduleDate = new ScheduleDate(date);
+ Person person = new PersonBuilder().build();
+ scheduleDate.addPerson(person);
+ scheduleDate.removePerson(person);
+ assertFalse(scheduleDate.hasPerson(person));
+ assertTrue(scheduleDate.getPersons().isEmpty());
+ }
+
+ @Test
+ public void equals_sameObject_true() {
+ LocalDate date = LocalDate.now();
+ ScheduleDate scheduleDate = new ScheduleDate(date);
+ assertTrue(scheduleDate.equals(scheduleDate));
+ }
+
+ @Test
+ public void equals_sameValues_true() {
+ LocalDate date = LocalDate.now();
+ ScheduleDate scheduleDate1 = new ScheduleDate(date);
+ ScheduleDate scheduleDate2 = new ScheduleDate(date);
+ assertTrue(scheduleDate1.equals(scheduleDate2));
+ }
+
+ @Test
+ public void equals_differentValues_false() {
+ LocalDate date1 = LocalDate.now();
+ LocalDate date2 = LocalDate.now().plusDays(1);
+ ScheduleDate scheduleDate1 = new ScheduleDate(date1);
+ ScheduleDate scheduleDate2 = new ScheduleDate(date2);
+ assertFalse(scheduleDate1.equals(scheduleDate2));
+ }
+}
diff --git a/src/test/java/seedu/address/model/schedule/ScheduleManagerTest.java b/src/test/java/seedu/address/model/schedule/ScheduleManagerTest.java
new file mode 100644
index 00000000000..1fb33aef9c7
--- /dev/null
+++ b/src/test/java/seedu/address/model/schedule/ScheduleManagerTest.java
@@ -0,0 +1,86 @@
+package seedu.address.model.schedule;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.time.LocalDate;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.person.Person;
+import seedu.address.testutil.PersonBuilder;
+
+
+public class ScheduleManagerTest {
+ private ScheduleManager scheduleManager;
+
+ @BeforeEach
+ public void setUp() {
+ scheduleManager = new ScheduleManager();
+ }
+
+ @Test
+ public void addPerson_validPersonAndDate_personAddedToSchedule() {
+ Person person = new PersonBuilder().build();
+ LocalDate date = LocalDate.now();
+
+ scheduleManager.addPerson(person, date);
+
+ assertTrue(scheduleManager.getScheduleDates().stream()
+ .anyMatch(scheduleDate -> scheduleDate.getDate().equals(date)
+ && scheduleDate.hasPerson(person)));
+ }
+
+ @Test
+ public void addPerson_existingPersonAndDate_personNotAddedToSchedule() {
+ Person person = new PersonBuilder().build();
+ LocalDate date = LocalDate.now();
+
+ scheduleManager.addPerson(person, date);
+ scheduleManager.addPerson(person, date);
+
+ assertEquals(1, scheduleManager.getScheduleDates().stream()
+ .filter(scheduleDate -> scheduleDate.getDate().equals(date)
+ && scheduleDate.hasPerson(person))
+ .count());
+ }
+
+ @Test
+ public void deletePerson_existingPersonAndDate_personRemovedFromSchedule() {
+ Person person = new PersonBuilder().build();
+ LocalDate date = LocalDate.now();
+
+ scheduleManager.addPerson(person, date);
+ scheduleManager.deletePerson(person, date);
+
+ assertFalse(scheduleManager.getScheduleDates().stream()
+ .anyMatch(scheduleDate -> scheduleDate.getDate().equals(date)
+ && scheduleDate.hasPerson(person)));
+ }
+
+ @Test
+ public void resetData_nullData_scheduleCleared() {
+ Person person = new PersonBuilder().build();
+ LocalDate date = LocalDate.now();
+
+ scheduleManager.addPerson(person, date);
+ scheduleManager.resetData(null);
+
+ assertTrue(scheduleManager.getScheduleDates().isEmpty());
+ }
+
+ @Test
+ public void resetData_nonNullData_scheduleUpdated() {
+ Person person = new PersonBuilder().build();
+ LocalDate date = LocalDate.now();
+ ScheduleManager newData = new ScheduleManager();
+ newData.addPerson(person, date);
+
+ scheduleManager.addPerson(person, date);
+ scheduleManager.resetData(newData);
+
+ assertEquals(newData.getScheduleDates(), scheduleManager.getScheduleDates());
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
index 83b11331cdb..dd5792be452 100644
--- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
+++ b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
@@ -13,24 +13,35 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
public class JsonAdaptedPersonTest {
- private static final String INVALID_NAME = "R@chel";
+ private static final String INVALID_FIRSTNAME = "R@chel";
+ private static final String INVALID_LASTNAME = "T4.n";
private static final String INVALID_PHONE = "+651234";
+ private static final String INVALID_SEX = "h";
+ private static final String INVALID_PAYRATE = "abc";
private static final String INVALID_ADDRESS = " ";
- private static final String INVALID_EMAIL = "example.com";
+
+ private static final String INVALID_BANK_DETAILS = "057-3213-4123";
private static final String INVALID_TAG = "#friend";
- private static final String VALID_NAME = BENSON.getName().toString();
+ private static final String VALID_FIRSTNAME = BENSON.getFirstName().toString();
+ private static final String VALID_LASTNAME = BENSON.getLastName().toString();
private static final String VALID_PHONE = BENSON.getPhone().toString();
- private static final String VALID_EMAIL = BENSON.getEmail().toString();
+ private static final String VALID_SEX = BENSON.getSex().toString();
+ private static final double VALID_PAYRATE = BENSON.getPayRate().getPayRate();
private static final String VALID_ADDRESS = BENSON.getAddress().toString();
+ private static final String VALID_BANK_DETAILS = BENSON.getBankDetails().toString();
+ private static final int VALID_WORK_HOURS = BENSON.getWorkHours().getHoursWorked();
private static final List VALID_TAGS = BENSON.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList());
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList());
+
+ private static final boolean VALID_ARCHIVE_STATUS = BENSON.getArchiveStatus().getArchiveStatus();
@Test
public void toModelType_validPersonDetails_returnsPerson() throws Exception {
@@ -39,16 +50,35 @@ public void toModelType_validPersonDetails_returnsPerson() throws Exception {
}
@Test
- public void toModelType_invalidName_throwsIllegalValueException() {
+ public void toModelType_invalidFirstName_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(INVALID_FIRSTNAME, VALID_LASTNAME, VALID_PHONE, VALID_SEX, VALID_PAYRATE,
+ VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS, VALID_ARCHIVE_STATUS);
String expectedMessage = Name.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
- public void toModelType_nullName_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ public void toModelType_invalidLastName_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_FIRSTNAME, INVALID_LASTNAME, VALID_PHONE, VALID_SEX, VALID_PAYRATE,
+ VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS, VALID_ARCHIVE_STATUS);
+ String expectedMessage = Name.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullFirstName_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_LASTNAME, VALID_PHONE, VALID_SEX,
+ VALID_PAYRATE, VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS, VALID_ARCHIVE_STATUS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullLastName_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_FIRSTNAME, null, VALID_PHONE, VALID_SEX,
+ VALID_PAYRATE, VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS, VALID_ARCHIVE_STATUS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@@ -56,45 +86,62 @@ public void toModelType_nullName_throwsIllegalValueException() {
@Test
public void toModelType_invalidPhone_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(VALID_FIRSTNAME, VALID_LASTNAME, INVALID_PHONE, VALID_SEX, VALID_PAYRATE,
+ VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS, VALID_ARCHIVE_STATUS);
String expectedMessage = Phone.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_FIRSTNAME, VALID_LASTNAME, null,
+ VALID_SEX, VALID_PAYRATE, VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS,
+ VALID_ARCHIVE_STATUS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
- public void toModelType_invalidEmail_throwsIllegalValueException() {
+ public void toModelType_invalidSex_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
- String expectedMessage = Email.MESSAGE_CONSTRAINTS;
+ new JsonAdaptedPerson(VALID_FIRSTNAME, VALID_LASTNAME, VALID_PHONE, INVALID_SEX, VALID_PAYRATE,
+ VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS, VALID_ARCHIVE_STATUS);
+ String expectedMessage = Sex.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullSex_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_FIRSTNAME, VALID_LASTNAME,
+ VALID_PHONE, null, VALID_PAYRATE, VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS,
+ VALID_TAGS, VALID_ARCHIVE_STATUS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Sex.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
- public void toModelType_nullEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS);
- String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName());
+ public void toModelType_nullAddress_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_FIRSTNAME, VALID_LASTNAME, VALID_PHONE,
+ VALID_SEX, VALID_PAYRATE, null, VALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS,
+ VALID_ARCHIVE_STATUS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
- public void toModelType_invalidAddress_throwsIllegalValueException() {
+ public void toModelType_invalidBankDetails_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS);
- String expectedMessage = Address.MESSAGE_CONSTRAINTS;
+ new JsonAdaptedPerson(VALID_FIRSTNAME, VALID_LASTNAME, VALID_PHONE, VALID_SEX,
+ VALID_PAYRATE, VALID_ADDRESS, INVALID_BANK_DETAILS, VALID_WORK_HOURS, VALID_TAGS, VALID_ARCHIVE_STATUS);
+ String expectedMessage = BankDetails.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
- public void toModelType_nullAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS);
- String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName());
+ public void toModelType_nullBankDetails_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_FIRSTNAME, VALID_LASTNAME, VALID_PHONE,
+ VALID_SEX, VALID_PAYRATE, VALID_ADDRESS, null, VALID_WORK_HOURS, VALID_TAGS, VALID_ARCHIVE_STATUS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, BankDetails.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@@ -103,7 +150,8 @@ public void toModelType_invalidTags_throwsIllegalValueException() {
List invalidTags = new ArrayList<>(VALID_TAGS);
invalidTags.add(new JsonAdaptedTag(INVALID_TAG));
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags);
+ new JsonAdaptedPerson(VALID_FIRSTNAME, VALID_LASTNAME, VALID_PHONE, VALID_SEX, VALID_PAYRATE,
+ VALID_ADDRESS, VALID_BANK_DETAILS, VALID_WORK_HOURS, invalidTags, VALID_ARCHIVE_STATUS);
assertThrows(IllegalValueException.class, person::toModelType);
}
diff --git a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java b/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
index 4e5ce9200c8..feaac2ee042 100644
--- a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
+++ b/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
@@ -11,6 +11,7 @@
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -30,7 +31,7 @@ public void readAddressBook_nullFilePath_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> readAddressBook(null));
}
- private java.util.Optional readAddressBook(String filePath) throws Exception {
+ private Optional readAddressBook(String filePath) throws Exception {
return new JsonAddressBookStorage(Paths.get(filePath)).readAddressBook(addToTestDataPathIfNotNull(filePath));
}
diff --git a/src/test/java/seedu/address/storage/JsonScheduleStorageTest.java b/src/test/java/seedu/address/storage/JsonScheduleStorageTest.java
new file mode 100644
index 00000000000..81d5453c78f
--- /dev/null
+++ b/src/test/java/seedu/address/storage/JsonScheduleStorageTest.java
@@ -0,0 +1,108 @@
+package seedu.address.storage;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.HOON;
+import static seedu.address.testutil.TypicalPersons.IDA;
+import static seedu.address.testutil.TypicalSchedule.getTypicalSchedule;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDate;
+import java.time.format.DateTimeParseException;
+import java.util.Optional;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import seedu.address.commons.exceptions.DataLoadingException;
+import seedu.address.model.schedule.Schedule;
+import seedu.address.model.schedule.ScheduleManager;
+
+public class JsonScheduleStorageTest {
+ private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonScheduleStorageTest");
+
+ @TempDir
+ public Path testFolder;
+
+ @Test
+ public void readSchedule_nullFilePath_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> readSchedule(null));
+ }
+
+ private Optional readSchedule(String filePath) throws Exception {
+ return new JsonScheduleStorage(Paths.get(filePath)).readSchedule(addToTestDataPathIfNotNull(filePath));
+ }
+
+ private Path addToTestDataPathIfNotNull(String prefsFileInTestDataFolder) {
+ return prefsFileInTestDataFolder != null
+ ? TEST_DATA_FOLDER.resolve(prefsFileInTestDataFolder)
+ : null;
+ }
+
+ @Test
+ public void read_missingFile_emptyResult() throws Exception {
+ assertFalse(readSchedule("NonExistentFile.json").isPresent());
+ }
+
+ @Test
+ public void read_notJsonFormat_exceptionThrown() {
+ assertThrows(DataLoadingException.class, () -> readSchedule("notJsonFormatSchedule.json"));
+ }
+
+ @Test
+ public void readSchedule_invalidDateSchedule_throwDataLoadingException() {
+ assertThrows(DateTimeParseException.class, () -> readSchedule("invalidDateSchedule.json"));
+ }
+
+ @Test
+ public void readAndSaveSchedule_allInOrder_success() throws Exception {
+ LocalDate april1 = LocalDate.parse("2024-04-01");
+ Path filePath = testFolder.resolve("TempAddressBook.json");
+ Schedule original = getTypicalSchedule();
+ JsonScheduleStorage jsonScheduleStorage = new JsonScheduleStorage(filePath);
+
+ // Save in new file and read back
+ jsonScheduleStorage.saveSchedule(original, filePath);
+ Schedule readBack = jsonScheduleStorage.readSchedule(filePath).get();
+ assertEquals(original, readBack);
+
+ // Modify data, overwrite exiting file, and read back
+ original.addPerson(HOON, april1);
+ original.deletePerson(ALICE, april1.minusDays(1));
+ jsonScheduleStorage.saveSchedule(original, filePath);
+ readBack = jsonScheduleStorage.readSchedule(filePath).get();
+ assertEquals(original, readBack);
+
+ // Save and read without specifying file path
+ original.addPerson(IDA, april1);
+ jsonScheduleStorage.saveSchedule(original); // file path not specified
+ readBack = jsonScheduleStorage.readSchedule().get(); // file path not specified
+ assertEquals(original, readBack);
+ }
+
+ @Test
+ public void saveSchedule_nullSchedule_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> saveSchedule(null, "SomeFile.json"));
+ }
+
+ /**
+ * Saves {@code addressBook} at the specified {@code filePath}.
+ */
+ private void saveSchedule(Schedule schedule, String filePath) {
+ try {
+ new JsonScheduleStorage(Paths.get(filePath))
+ .saveSchedule(schedule, addToTestDataPathIfNotNull(filePath));
+ } catch (IOException ioe) {
+ throw new AssertionError("There should not be an error writing to the file.", ioe);
+ }
+ }
+
+ @Test
+ public void saveSchedule_nullFilePath_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> saveSchedule(new ScheduleManager(), null));
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonSerializableScheduleTest.java b/src/test/java/seedu/address/storage/JsonSerializableScheduleTest.java
new file mode 100644
index 00000000000..7c35c3ddf64
--- /dev/null
+++ b/src/test/java/seedu/address/storage/JsonSerializableScheduleTest.java
@@ -0,0 +1,33 @@
+package seedu.address.storage;
+
+import static seedu.address.testutil.Assert.assertThrows;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.commons.util.JsonUtil;
+
+public class JsonSerializableScheduleTest {
+
+ private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializableScheduleTest");
+ private static final Path INVALID_DATE_SCHEDULE_FILE = TEST_DATA_FOLDER.resolve("invalidDateSchedule.json");
+ private static final Path INVALID_PERSON_SCHEDULE_FILE = TEST_DATA_FOLDER.resolve("invalidDateSchedule.json");
+
+ @Test
+ public void toModelType_invalidDateFile_throwsIllegalValueException() throws Exception {
+ JsonSerializableSchedule dataFromFile = JsonUtil.readJsonFile(INVALID_DATE_SCHEDULE_FILE,
+ JsonSerializableSchedule.class).get();
+ assertThrows(IllegalValueException.class, dataFromFile::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception {
+ JsonSerializableSchedule dataFromFile = JsonUtil.readJsonFile(INVALID_PERSON_SCHEDULE_FILE,
+ JsonSerializableSchedule.class).get();
+ assertThrows(IllegalValueException.class, dataFromFile::toModelType);
+ }
+
+}
diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/seedu/address/storage/StorageManagerTest.java
index 99a16548970..af8cce47c0b 100644
--- a/src/test/java/seedu/address/storage/StorageManagerTest.java
+++ b/src/test/java/seedu/address/storage/StorageManagerTest.java
@@ -26,7 +26,8 @@ public class StorageManagerTest {
public void setUp() {
JsonAddressBookStorage addressBookStorage = new JsonAddressBookStorage(getTempFilePath("ab"));
JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(getTempFilePath("prefs"));
- storageManager = new StorageManager(addressBookStorage, userPrefsStorage);
+ JsonScheduleStorage scheduleStorage = new JsonScheduleStorage(getTempFilePath("sched"));
+ storageManager = new StorageManager(addressBookStorage, userPrefsStorage, scheduleStorage);
}
private Path getTempFilePath(String fileName) {
diff --git a/src/test/java/seedu/address/testutil/Assert.java b/src/test/java/seedu/address/testutil/Assert.java
index 9863093bd6e..4120ae7bd69 100644
--- a/src/test/java/seedu/address/testutil/Assert.java
+++ b/src/test/java/seedu/address/testutil/Assert.java
@@ -27,7 +27,7 @@ public static void assertThrows(Class extends Throwable> expectedType, Executa
* @see #assertThrows(Class, Executable)
*/
public static void assertThrows(Class extends Throwable> expectedType, String expectedMessage,
- Executable executable) {
+ Executable executable) {
Throwable thrownException = Assertions.assertThrows(expectedType, executable);
Assertions.assertEquals(expectedMessage, thrownException.getMessage());
}
diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
index 4584bd5044e..dcced54d93c 100644
--- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
+++ b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
@@ -6,10 +6,12 @@
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
import seedu.address.model.tag.Tag;
/**
@@ -32,21 +34,34 @@ public EditPersonDescriptorBuilder(EditPersonDescriptor descriptor) {
*/
public EditPersonDescriptorBuilder(Person person) {
descriptor = new EditPersonDescriptor();
- descriptor.setName(person.getName());
+ descriptor.setFirstName(person.getFirstName());
+ descriptor.setLastName(person.getLastName());
descriptor.setPhone(person.getPhone());
- descriptor.setEmail(person.getEmail());
+ descriptor.setSex(person.getSex());
+ descriptor.setPayRate(person.getPayRate());
descriptor.setAddress(person.getAddress());
descriptor.setTags(person.getTags());
+ descriptor.setBankDetails(person.getBankDetails());
}
/**
- * Sets the {@code Name} of the {@code EditPersonDescriptor} that we are building.
+ * Sets the {@code FirstName} of the {@code EditPersonDescriptor} that we are building.
*/
- public EditPersonDescriptorBuilder withName(String name) {
- descriptor.setName(new Name(name));
+ public EditPersonDescriptorBuilder withFirstName(String name) {
+ descriptor.setFirstName(new Name(name));
return this;
}
+ /**
+ * Sets the {@code LastName} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withLastName(String name) {
+ descriptor.setLastName(new Name(name));
+ return this;
+ }
+
+
+
/**
* Sets the {@code Phone} of the {@code EditPersonDescriptor} that we are building.
*/
@@ -56,10 +71,26 @@ public EditPersonDescriptorBuilder withPhone(String phone) {
}
/**
- * Sets the {@code Email} of the {@code EditPersonDescriptor} that we are building.
+ * Sets the {@code Sex} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withSex(String sex) {
+ descriptor.setSex(new Sex(sex));
+ return this;
+ }
+
+ /**
+ * Sets the {@code EmploymentType} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withPayRate(double payRate) {
+ descriptor.setPayRate(new PayRate(payRate));
+ return this;
+ }
+
+ /**
+ * Sets the {@code BankDetails} of the {@code EditPersonDescriptor} that we are building.
*/
- public EditPersonDescriptorBuilder withEmail(String email) {
- descriptor.setEmail(new Email(email));
+ public EditPersonDescriptorBuilder withBankDetails(String bankDetails) {
+ descriptor.setBankDetails(new BankDetails(bankDetails));
return this;
}
diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java
index 6be381d39ba..ecda3a6e0a5 100644
--- a/src/test/java/seedu/address/testutil/PersonBuilder.java
+++ b/src/test/java/seedu/address/testutil/PersonBuilder.java
@@ -4,10 +4,14 @@
import java.util.Set;
import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
+import seedu.address.model.person.ArchiveStatus;
+import seedu.address.model.person.BankDetails;
import seedu.address.model.person.Name;
+import seedu.address.model.person.PayRate;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Sex;
+import seedu.address.model.person.WorkHours;
import seedu.address.model.tag.Tag;
import seedu.address.model.util.SampleDataUtil;
@@ -16,51 +20,79 @@
*/
public class PersonBuilder {
- public static final String DEFAULT_NAME = "Amy Bee";
+ public static final String DEFAULT_FIRSTNAME = "Amy";
+ public static final String DEFAULT_LASTNAME = "Bee";
public static final String DEFAULT_PHONE = "85355255";
- public static final String DEFAULT_EMAIL = "amy@gmail.com";
+ public static final String DEFAULT_SEX = "f";
+ public static final double DEFAULT_PAY_RATE = 15;
public static final String DEFAULT_ADDRESS = "123, Jurong West Ave 6, #08-111";
+ public static final String DEFAULT_BANK_ADDRESS = "ocbc 8374219";
+ public static final int DEFAULT_WORK_HOURS = 0;
+ public static final boolean DEFAULT_ARCHIVE_STATUS = false;
- private Name name;
+ private Name firstName;
+ private Name lastName;
private Phone phone;
- private Email email;
+ private Sex sex;
+ private PayRate payRate;
private Address address;
+ private BankDetails bankDetails;
+ private WorkHours hoursWorked;
private Set tags;
+ private ArchiveStatus archiveStatus;
/**
* Creates a {@code PersonBuilder} with the default details.
*/
public PersonBuilder() {
- name = new Name(DEFAULT_NAME);
+ firstName = new Name(DEFAULT_FIRSTNAME);
+ lastName = new Name(DEFAULT_LASTNAME);
phone = new Phone(DEFAULT_PHONE);
- email = new Email(DEFAULT_EMAIL);
+ sex = new Sex(DEFAULT_SEX);
+ payRate = new PayRate(DEFAULT_PAY_RATE);
address = new Address(DEFAULT_ADDRESS);
+ bankDetails = new BankDetails(DEFAULT_BANK_ADDRESS);
+ hoursWorked = new WorkHours(DEFAULT_WORK_HOURS);
tags = new HashSet<>();
+ archiveStatus = new ArchiveStatus(DEFAULT_ARCHIVE_STATUS);
}
/**
* Initializes the PersonBuilder with the data of {@code personToCopy}.
*/
public PersonBuilder(Person personToCopy) {
- name = personToCopy.getName();
+ firstName = personToCopy.getFirstName();
+ lastName = personToCopy.getLastName();
phone = personToCopy.getPhone();
- email = personToCopy.getEmail();
address = personToCopy.getAddress();
+ sex = personToCopy.getSex();
+ payRate = personToCopy.getPayRate();
+ bankDetails = personToCopy.getBankDetails();
tags = new HashSet<>(personToCopy.getTags());
+ archiveStatus = personToCopy.getArchiveStatus();
}
+
/**
- * Sets the {@code Name} of the {@code Person} that we are building.
+ * Sets the {@code firstName} of the {@code Person} that we are building.
*/
- public PersonBuilder withName(String name) {
- this.name = new Name(name);
+ public PersonBuilder withFirstName(String name) {
+ this.firstName = new Name(name);
+ return this;
+ }
+
+ /**
+ * Sets the {@code lastName} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withLastName(String name) {
+ this.lastName = new Name(name);
return this;
}
/**
* Parses the {@code tags} into a {@code Set} and set it to the {@code Person} that we are building.
*/
- public PersonBuilder withTags(String ... tags) {
+ public PersonBuilder withTags(String... tags) {
this.tags = SampleDataUtil.getTagSet(tags);
return this;
}
@@ -82,15 +114,51 @@ public PersonBuilder withPhone(String phone) {
}
/**
- * Sets the {@code Email} of the {@code Person} that we are building.
+ * Sets the {@code Sex} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withSex(String sex) {
+ this.sex = new Sex(sex);
+ return this;
+ }
+
+ /**
+ * Sets the {@code EmploymentType} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withPayRate(double payRate) {
+ this.payRate = new PayRate(payRate);
+ return this;
+ }
+
+ /**
+ * Sets the {@code BankDetails} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withBankDetails(String bankDetails) {
+ this.bankDetails = new BankDetails(bankDetails);
+ return this;
+ }
+
+ /**
+ * Sets the {@code WorkHours} of the {@code Person} that we are building.
*/
- public PersonBuilder withEmail(String email) {
- this.email = new Email(email);
+ public PersonBuilder withWorkedHours(int hoursWorked) {
+ this.hoursWorked = new WorkHours(hoursWorked);
return this;
}
+ /**
+ * Sets the {@code ArchiveStatus} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withArchiveStatus(boolean archiveStatus) {
+ this.archiveStatus = new ArchiveStatus(archiveStatus);
+ return this;
+ }
+
+ /**
+ * Builds the person object.
+ */
public Person build() {
- return new Person(name, phone, email, address, tags);
+ return new Person(firstName, lastName, phone, sex, payRate, address, bankDetails, hoursWorked,
+ tags, archiveStatus);
}
}
diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java
index 90849945183..0bd8c108ca1 100644
--- a/src/test/java/seedu/address/testutil/PersonUtil.java
+++ b/src/test/java/seedu/address/testutil/PersonUtil.java
@@ -1,9 +1,12 @@
package seedu.address.testutil;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_BANKDETAILS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FIRSTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTNAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PAYRATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import java.util.Set;
@@ -30,9 +33,14 @@ public static String getAddCommand(Person person) {
*/
public static String getPersonDetails(Person person) {
StringBuilder sb = new StringBuilder();
- sb.append(PREFIX_NAME + person.getName().fullName + " ");
+ sb.append(PREFIX_FIRSTNAME + person.getFirstName().value + " ");
+ sb.append(PREFIX_LASTNAME + person.getLastName().value + " ");
sb.append(PREFIX_PHONE + person.getPhone().value + " ");
- sb.append(PREFIX_EMAIL + person.getEmail().value + " ");
+ sb.append(PREFIX_SEX + person.getSex().value + " ");
+ sb.append(PREFIX_PAYRATE);
+ sb.append(person.getPayRate().value);
+ sb.append(" ");
+ sb.append(PREFIX_BANKDETAILS + person.getBankDetails().value + " ");
sb.append(PREFIX_ADDRESS + person.getAddress().value + " ");
person.getTags().stream().forEach(
s -> sb.append(PREFIX_TAG + s.tagName + " ")
@@ -45,10 +53,17 @@ public static String getPersonDetails(Person person) {
*/
public static String getEditPersonDescriptorDetails(EditPersonDescriptor descriptor) {
StringBuilder sb = new StringBuilder();
- descriptor.getName().ifPresent(name -> sb.append(PREFIX_NAME).append(name.fullName).append(" "));
+ descriptor.getFirstName().ifPresent(name -> sb.append(PREFIX_FIRSTNAME).append(name.value).append(
+ " "));
+ descriptor.getLastName().ifPresent(name -> sb.append(PREFIX_LASTNAME).append(name.value).append(
+ " "));
descriptor.getPhone().ifPresent(phone -> sb.append(PREFIX_PHONE).append(phone.value).append(" "));
- descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" "));
descriptor.getAddress().ifPresent(address -> sb.append(PREFIX_ADDRESS).append(address.value).append(" "));
+ descriptor.getSex().ifPresent(sex -> sb.append(PREFIX_SEX).append(sex.value).append(" "));
+ descriptor.getPayRate().ifPresent(payRate -> sb.append(PREFIX_PAYRATE).append(
+ payRate.value).append(" "));
+ descriptor.getBankDetails().ifPresent(bankDetails -> sb.append(PREFIX_BANKDETAILS).append(bankDetails.value)
+ .append(" "));
if (descriptor.getTags().isPresent()) {
Set tags = descriptor.getTags().get();
if (tags.isEmpty()) {
diff --git a/src/test/java/seedu/address/testutil/ScheduleDateBuilder.java b/src/test/java/seedu/address/testutil/ScheduleDateBuilder.java
new file mode 100644
index 00000000000..c6ebb2234e4
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/ScheduleDateBuilder.java
@@ -0,0 +1,33 @@
+package seedu.address.testutil;
+
+import java.time.LocalDate;
+
+import seedu.address.model.person.Person;
+import seedu.address.model.schedule.ScheduleDate;
+
+/**
+ * A utility class to help with building ScheduleDate objects.
+ */
+public class ScheduleDateBuilder {
+ private ScheduleDate scheduleDate;
+
+ public ScheduleDateBuilder(LocalDate localDate) {
+ scheduleDate = new ScheduleDate(localDate);
+ }
+
+ public ScheduleDateBuilder(ScheduleDate scheduleDate) {
+ this.scheduleDate = scheduleDate;
+ }
+
+ /**
+ * Adds a new {@code Person} to the {@code ScheduleDate} that we are building.
+ */
+ public ScheduleDateBuilder withPerson(Person person) {
+ scheduleDate.addPerson(person);
+ return this;
+ }
+
+ public ScheduleDate build() {
+ return scheduleDate;
+ }
+}
diff --git a/src/test/java/seedu/address/testutil/ScheduleManagerBuilder.java b/src/test/java/seedu/address/testutil/ScheduleManagerBuilder.java
new file mode 100644
index 00000000000..6040f779770
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/ScheduleManagerBuilder.java
@@ -0,0 +1,31 @@
+package seedu.address.testutil;
+
+import seedu.address.model.schedule.ScheduleDate;
+import seedu.address.model.schedule.ScheduleManager;
+
+/**
+ * A utility class to help with building ScheduleManager objects.
+ */
+public class ScheduleManagerBuilder {
+ private ScheduleManager scheduleManager;
+
+ public ScheduleManagerBuilder() {
+ scheduleManager = new ScheduleManager();
+ }
+
+ public ScheduleManagerBuilder(ScheduleManager scheduleManager) {
+ this.scheduleManager = scheduleManager;
+ }
+
+ /**
+ * Adds a new {@code ScheduleDate} to the {@code ScheduleManager} that we are building.
+ */
+ public ScheduleManagerBuilder withScheduleDate(ScheduleDate scheduleDate) {
+ scheduleManager.addScheduleDate(scheduleDate);
+ return this;
+ }
+
+ public ScheduleManager build() {
+ return scheduleManager;
+ }
+}
diff --git a/src/test/java/seedu/address/testutil/TypicalIndexes.java b/src/test/java/seedu/address/testutil/TypicalIndexes.java
index 1e613937657..c675e9e4bc6 100644
--- a/src/test/java/seedu/address/testutil/TypicalIndexes.java
+++ b/src/test/java/seedu/address/testutil/TypicalIndexes.java
@@ -9,4 +9,5 @@ public class TypicalIndexes {
public static final Index INDEX_FIRST_PERSON = Index.fromOneBased(1);
public static final Index INDEX_SECOND_PERSON = Index.fromOneBased(2);
public static final Index INDEX_THIRD_PERSON = Index.fromOneBased(3);
+
}
diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java
index fec76fb7129..0d3b8d69740 100644
--- a/src/test/java/seedu/address/testutil/TypicalPersons.java
+++ b/src/test/java/seedu/address/testutil/TypicalPersons.java
@@ -2,14 +2,22 @@
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_BANKDETAILS_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_BANKDETAILS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_FIRSTNAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_FIRSTNAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_LASTNAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_LASTNAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PAYRATE_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PAYRATE_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SEX_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SEX_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_COOK;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_WAITER;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_WORK_HOURS_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_WORK_HOURS_BOB;
import java.util.ArrayList;
import java.util.Arrays;
@@ -23,41 +31,128 @@
*/
public class TypicalPersons {
- public static final Person ALICE = new PersonBuilder().withName("Alice Pauline")
- .withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
- .withPhone("94351253")
- .withTags("friends").build();
- public static final Person BENSON = new PersonBuilder().withName("Benson Meier")
- .withAddress("311, Clementi Ave 2, #02-25")
- .withEmail("johnd@example.com").withPhone("98765432")
- .withTags("owesMoney", "friends").build();
- public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563")
- .withEmail("heinz@example.com").withAddress("wall street").build();
- public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533")
- .withEmail("cornelia@example.com").withAddress("10th street").withTags("friends").build();
- public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224")
- .withEmail("werner@example.com").withAddress("michegan ave").build();
- public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427")
- .withEmail("lydia@example.com").withAddress("little tokyo").build();
- public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("9482442")
- .withEmail("anna@example.com").withAddress("4th street").build();
+ public static final Person ALICE = new PersonBuilder()
+ .withFirstName("Alice")
+ .withLastName("Pauline")
+ .withSex("f")
+ .withPayRate(14.5)
+ .withAddress("123, Jurong West Ave 6, #08-111")
+ .withPhone("94351253")
+ .withTags("friends")
+ .withBankDetails("dbs 1234567890")
+ .withArchiveStatus(false)
+ .build();
+ public static final Person BENSON = new PersonBuilder()
+ .withFirstName("Benson")
+ .withLastName("Meier")
+ .withSex("m")
+ .withPayRate(14.5)
+ .withAddress("311, Clementi Ave 2, #02-25")
+ .withPhone("98765432")
+ .withTags("owesMoney", "friends")
+ .withBankDetails("ocbc 1234567")
+ .withArchiveStatus(false)
+ .build();
+ public static final Person CARL = new PersonBuilder()
+ .withFirstName("Carl")
+ .withLastName("Kurz")
+ .withPhone("95352563")
+ .withSex("m")
+ .withPayRate(14.5)
+ .withAddress("wall street")
+ .withBankDetails("hsbc 0987654321")
+ .withArchiveStatus(false)
+ .build();
+ public static final Person DANIEL = new PersonBuilder()
+ .withFirstName("Daniel")
+ .withLastName("Meier")
+ .withPhone("87652533")
+ .withSex("m")
+ .withPayRate(14.5)
+ .withAddress("10th street")
+ .withTags("friends")
+ .withBankDetails("uob 8888777700")
+ .withArchiveStatus(false)
+ .build();
+ public static final Person ELLE = new PersonBuilder()
+ .withFirstName("Elle")
+ .withLastName("Meyer")
+ .withPhone("94823224")
+ .withSex("f")
+ .withPayRate(14.5)
+ .withAddress("michegan ave")
+ .withBankDetails("posb 369369369")
+ .withArchiveStatus(false)
+ .build();
+ public static final Person FIONA = new PersonBuilder()
+ .withFirstName("Fiona")
+ .withLastName("Kunz")
+ .withPhone("94823427")
+ .withSex("f")
+ .withPayRate(14.5)
+ .withAddress("little tokyo")
+ .withBankDetails("ocbc 7654321")
+ .withArchiveStatus(false)
+ .build();
+ public static final Person GEORGE = new PersonBuilder()
+ .withFirstName("George")
+ .withLastName("Best")
+ .withPhone("93482442")
+ .withSex("m")
+ .withPayRate(14.5)
+ .withAddress("4th street")
+ .withBankDetails("other maybank 5554443332")
+ .withArchiveStatus(false)
+ .build();
// Manually added
- public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("8482424")
- .withEmail("stefan@example.com").withAddress("little india").build();
- public static final Person IDA = new PersonBuilder().withName("Ida Mueller").withPhone("8482131")
- .withEmail("hans@example.com").withAddress("chicago ave").build();
+ public static final Person HOON = new PersonBuilder()
+ .withFirstName("Hoon")
+ .withLastName("Meier")
+ .withPhone("84832424")
+ .withSex("m")
+ .withPayRate(14.5)
+ .withAddress("little india")
+ .withArchiveStatus(false)
+ .build();
+ public static final Person IDA = new PersonBuilder()
+ .withFirstName("Ida")
+ .withLastName("Mueller")
+ .withPhone("84821331")
+ .withSex("f")
+ .withPayRate(14.5)
+ .withAddress("chicago ave")
+ .withArchiveStatus(false)
+ .build();
// Manually added - Person's details found in {@code CommandTestUtil}
- public static final Person AMY = new PersonBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY)
- .withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY).withTags(VALID_TAG_FRIEND).build();
- public static final Person BOB = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND)
- .build();
+ public static final Person AMY = new PersonBuilder()
+ .withFirstName(VALID_FIRSTNAME_AMY)
+ .withLastName(VALID_LASTNAME_AMY)
+ .withPhone(VALID_PHONE_AMY)
+ .withSex(VALID_SEX_AMY)
+ .withPayRate(VALID_PAYRATE_AMY)
+ .withAddress(VALID_ADDRESS_AMY)
+ .withBankDetails(VALID_BANKDETAILS_AMY).withWorkedHours(VALID_WORK_HOURS_AMY)
+ .withTags(VALID_TAG_COOK)
+ .withArchiveStatus(false)
+ .build();
+ public static final Person BOB = new PersonBuilder()
+ .withFirstName(VALID_FIRSTNAME_BOB)
+ .withLastName(VALID_LASTNAME_BOB)
+ .withPhone(VALID_PHONE_BOB)
+ .withSex(VALID_SEX_BOB)
+ .withPayRate(VALID_PAYRATE_BOB)
+ .withAddress(VALID_ADDRESS_BOB)
+ .withBankDetails(VALID_BANKDETAILS_BOB).withWorkedHours(VALID_WORK_HOURS_BOB)
+ .withTags(VALID_TAG_WAITER, VALID_TAG_COOK)
+ .withArchiveStatus(false)
+ .build();
public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER
- private TypicalPersons() {} // prevents instantiation
+ private TypicalPersons() {
+ } // prevents instantiation
/**
* Returns an {@code AddressBook} with all the typical persons.
diff --git a/src/test/java/seedu/address/testutil/TypicalSchedule.java b/src/test/java/seedu/address/testutil/TypicalSchedule.java
new file mode 100644
index 00000000000..b857e2c5f35
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/TypicalSchedule.java
@@ -0,0 +1,25 @@
+package seedu.address.testutil;
+
+import java.time.LocalDate;
+
+import seedu.address.model.schedule.ScheduleManager;
+
+/**
+ * A utility class containing a list of {@code Person} objects to be used in tests.
+ */
+public class TypicalSchedule {
+ private static final LocalDate april1 = LocalDate.parse("2024-04-01");
+ public static final ScheduleManager SCHEDULE = new ScheduleManagerBuilder()
+ .withScheduleDate(new ScheduleDateBuilder(april1.minusDays(1))
+ .withPerson(TypicalPersons.ALICE)
+ .withPerson(TypicalPersons.BENSON).build())
+ .withScheduleDate(new ScheduleDateBuilder(april1).withPerson(TypicalPersons.BENSON).build())
+ .build();
+
+ private TypicalSchedule() {
+ } // prevents instantiation
+
+ public static ScheduleManager getTypicalSchedule() {
+ return SCHEDULE;
+ }
+}