Overview
Centralised Human Resource System (CHRS) is an application for managing employees within the company. The application is created to assist the Human Resource Department of the company to better manage the employees' information. CHRS is capable of checking work schedule, creating recruitment posts, checking of expenses claims and storage of various information of each employee such as salary, department, position, etc.
Summary of contributions
-
Major enhancement: Added
filter
and enhancedfind
command-
What it does: The
filter
command allows user to filter out employees of a certain department, rank/position or both and thefind
command allows user to search for a specific employee via their name or employee ID. -
Justification: This feature improves the product significantly as the user is able to search for the required employee’s details quickly.
-
Highlights: This enhancement enhances the user experience as the user can now search for an employee’s details without having the need to go through the whole list of employees. This feature required in-depth analysis of possible design alternatives and in-depth understanding of the HR needs when searching. The implementation of this feature was challenging as it required enhancement to existing commands and understanding of predicates.
-
-
Minor enhancements:
-
Added sorting to PersonList, ExpensesList and ScheduleList to ensure that the lists stay sorted in ascending order. (Pull request: #219)
-
Enhanced
add
andedit
commands to reject having employees with duplication in these fields:EmployeeId
OREmail
ORPhone
ORName
andDateOfBirth
. Should any attempt of duplication occur, the application will display the employee being duplicated and reject the command. (Pull requests: #124, #134, #136, #219)
-
-
Code contributed: [Reposense Dashboard]
-
Other contributions:
-
Project management:
-
Managed releases
v1.1
-v1.4
(5 releases) on GitHub-
Managed .jar file release and description of each release
-
-
Managed the approval of pull requests
-
Set up issue tracker, milestones and labels
-
Ensures that the team is on track and is able to complete each milestone’s requirements
-
-
Enhancements to existing features:
-
Added
EmployeeId
,DateOfBirth
,Department
,Rank/Position
,Salary
andBonus
fields (Pull request: #18)
-
-
Test Cases:
-
Documentation:
-
Updated About Us to include team members' images, roles and responsibilities alongside GitHub and Portfolio links (Pull requests: #1, #3, #8, #41, #127)
-
Updated Developer Guide on
filter
feature alongside model component, user stories, use cases and instructions for manual testing (Pull requests: #11, #13, #14, #15, #97, #109, #235, #240) -
Updated User Guide to ensure
add
,edit
,find
andfilter
commands alongside the fields added by me are up to date (Pull requests: #95, #156, #167, #172, #183)
-
Community:
-
Tools:
-
Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
Add employee’s data : add
Adds employee’s data to the database
Format: add id/EMPLOYEEID n/NAME dob/DATE_OF_BIRTH p/PHONE_NUMBER e/EMAIL d/DEPARTMENT r/RANK_POSITION a/ADDRESS s/SALARY t/[TAGS]…
Examples:
-
add id/000001 n/John Doe dob/13/12/2000 p/98765432 e/johnd@example.com d/IT r/Assistant a/John street, block 123, #01-01 s/3000.00 t/FlyKite
Adds an employee with the fields listed above -
add id/888888 n/Betsy dob/23/05/1987 p/95544332 e/betsy@example.com d/Account r/Manager a/Betsy street, block 3, #11-01 s/5000.00
Adds an employee with the fields listed above
Any usage of add command that will result in duplicated employeeId or phone number or email will be rejected. Additionally, duplicated name alongside date of birth will also be rejected.
|
Edit an existing employee’s data : edit
Edit an existing employee’s data in CHRS.
Format: edit INDEX [n/NAME] [p/PHONE_NUMBER] [a/ADDRESS] [e/EMAIL] [d/DEPARTMENT] [r/RANK_POSITION]
Include at least one field alongside the INDEX. The existing values of the employee will be updated to the input values. |
Examples:
-
edit 1 p/98765432 d/HR r/Manager
Edits employee at index 1 to have the new input of phone, department and rank/position
Any usage of edit command that will result in duplicated phone number or email will be rejected. Additionally, usage of this command to edit an employee’s name to be the same as another employee who has the same date of birth will be rejected.
|
Locating persons by name or employee ID : find
Find the employee’s name that contains the input or find the employee id that matches the input. The expenses and schedule list will also be updated accordingly to show only the matched employee(s)' expenses and schedule.
Format: find [NAME] [EMPLOYEEID]
Include only one of the fields, either Name or Employee Id. The NAME parameter is case-insensitive, i.e. The command find john will find the instances of JoHn, joHN, etc.
|
Examples:
-
find John
Find all instances of John, and his associated expenses and schedule -
find 000001
Find the employee with employee ID000001
, and his/her associated expenses and schedule
Any usage of find command will be rejected if it contains special characters or alphanumeric input. It accepts only either alphabets or numbers in a single input, not both.
|
Filter and list of specific employee’s data : filter
Filters out the employees whose department and/or rank/position contains the keyword(s) input from the user and list them in ascending or descending name order. The expenses and schedule list will also be updated accordingly to show only the matched employees' expenses and schedule.
Format: filter SORT_ORDER [d/DEPARTMENT] [r/POSITION]
The SORT_ORDER parameter should either be asc for ascending or dsc for descending. The SORT_ORDER parameter is case-insensitive. Include either department or rank/position or both, at least one of the field must be included alongside the sort order. The keywords are delimited by a space, i.e filter asc d/human resource would mean the keywords are "human" and "resource". The keywords matching is case-insensitive. |
Examples:
-
filter asc d/Human Resource r/Manager
List all employees whose department contains the keyword of either human or resource and rank/position contains the keyword of manager in ascending name order. Expenses and schedule list will also be updated to show only matched employee(s)' expenses and schedule(s). -
filter dsc d/Finance
List all employees whose department contains the keyword of finance in descending name order. Expenses and schedule list will also be updated to show only matched employee(s)' expenses and schedule(s).
Any usage of filter command that results in the same prefix appearing more than once will be rejected. Example: filter asc d/Human d/Finance will be rejected.
|
Keyword suggestion and auto complete feature [Upcoming in 2.0]
This feature will suggest keywords when filtering or finding employee and the keyword will be auto-completed by pressing TAB
key. [Upcoming in 2.0]
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
Filter Feature
The command filter
allows the user to filter employees based on their respective department and/or position within the company.
Current Implementation
The implementation of this command is separated into two phases.
Phase 1
The filter
command’s mechanism is facilitated by FilterCommandParser
.
The FilterCommandParser
implements the Parser
interface, parses the arguments parameter, which is the input from the user, and creates a new FilterCommand
object.
Apart from parsing the input, the FilterCommandParser
also checks whether the input complies with the required format.
The checking of input compliance is assisted by a helper method, didPrefixesAppearOnlyOnce
, which checks whether the department prefix and/or position prefix appears only once.
If the input does not comply with the required format, an error message will be shown to the user. |
Code snippet of the parse
method within FilterCommandParser
showing the checks for input compliance:
public FilterCommand parse(String args) throws ParseException {
...
...
ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_DEPARTMENT, PREFIX_POSITION);
if (trimmedArgs.isEmpty() || (!argMultimap.getValue(PREFIX_DEPARTMENT).isPresent()
&& !argMultimap.getValue(PREFIX_POSITION).isPresent()) || !didPrefixesAppearOnlyOnce(trimmedArgs)
|| !ACCEPTED_ORDERS.contains(sortOrder)) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
}
...
...
}
Code snippet of the helper method didPrefixesAppearOnlyOnce
:
public boolean didPrefixesAppearOnlyOnce(String argument) {
String departmentPrefix = " " + PREFIX_DEPARTMENT.toString();
String positionPrefix = " " + PREFIX_POSITION.toString();
return argument.indexOf(departmentPrefix) == argument.lastIndexOf(departmentPrefix)
&& argument.indexOf(positionPrefix) == argument.lastIndexOf(positionPrefix);
}
If the input complies with the required format, further checks will be performed on the keywords to ensure that the keywords are valid.
This keywords checking is completed by the processDepartmentKeywords
and processPositionKeywords
methods that are both within the FilterCommandParser
class.
This guide will focus on explaining how processDepartmentKeywords
work instead of both as the methods processDepartmentKeywords
and processPositionKeywords
are similar.
Code snippet of the parse
method in FilterCommandParser
calling processDepartmentKeywords
method:
public FilterCommand parse(String args) throws ParseException {
...
...
if (!argMultimap.getValue(PREFIX_DEPARTMENT).isPresent()) {
filterCommand.setIsDepartmentPrefixPresent(false);
} else if (argMultimap.getValue(PREFIX_DEPARTMENT).isPresent()
&& !processDepartmentKeywords(argMultimap, filterCommand)) {
throw new ParseException(Department.MESSAGE_DEPARTMENT_KEYWORD_CONSTRAINTS);
}
...
...
}
Code snippet of processDepartmentKeywords
helper method:
public boolean processDepartmentKeywords(ArgumentMultimap argMultimap, FilterCommand command) {
String trimmedDepartment = (argMultimap.getValue(PREFIX_DEPARTMENT).get().trim());
String[] departmentKeywords = trimmedDepartment.split("\\s+");
return validityCheckForDepartments(command, departmentKeywords);
}
The processDepartmentKeywords
is further assisted by the validityCheckForDepartments
method which calls another method areDepartmentKeywordsValid
to check whether the given keywords comply with the DEPARTMENT_KEYWORD_VALIDATION_REGEX
.
If the keywords from the user are all valid, the departmentPredicate will be created and passed to the FilterCommand
object through a setter.
The DEPARTMENT_KEYWORD_VALIDATION_REGEX is a regular expression that accepts only spaces and case-insensitive alphabets.
It only allows 1 to 30 characters per keyword.
|
Code snippet of validityCheckForDepartments
and areDepartmentKeywordsValid
methods in FilterCommandParser
class:
public boolean validityCheckForDepartments(FilterCommand command, String[] keywords) {
if (!areDepartmentKeywordsValid(keywords)) {
return false;
}
command.setIsDepartmentPrefixPresent(true);
command.setDepartmentPredicate(new DepartmentContainsKeywordsPredicate(Arrays.asList(keywords)));
return true;
}
public boolean areDepartmentKeywordsValid(String[] keywords) {
for (String keyword: keywords) {
if (!keyword.matches(DEPARTMENT_KEYWORD_VALIDATION_REGEX)) {
return false;
}
}
return true;
}
Phase 2
The FilterCommand
is being executed in this phase.
FilterCommand
first checks which prefix(es) is(are) present prior to calling the updateFilteredPersonList
method, which updates filteredPersonList
with the employees of the relevant department(s) and/or position(s) that matches the keyword(s) input from the user.
Additionally, the methods updateFilteredExpensesList
and updateFilteredScheduleList
will also be called to update the filteredExpensesList
and filteredScheduleList
respectively to show only the matched employees' expenses and schedules.
If the keywords input from the user results in 0 person found. The CLI will show the user a list of currently available department(s) and/or position(s) in the PersonList.
The listing of available department(s) and/or position(s) depends on the presence of the prefix. Example: If filter asc d/hello results in 0 person found, the CLI will list all the currently available department(s) in CHRS.
|
Code snippet of FilterCommand
that checks which prefix is present prior to updating filteredPersonList
, filteredExpensesList
and filteredScheduleList
:
public class FilterCommand extends Command {
...
...
@Override
public CommandResult execute(Model model, CommandHistory history) {
requireNonNull(model);
String allAvailableDepartments = listAvailableDepartments(model);
String allAvailablePositions = listAvailablePositions(model);
if (isDepartmentPrefixPresent && !isPositionPrefixPresent) {
model.updateFilteredPersonList(departmentPredicate, sortOrder);
} else if (isPositionPrefixPresent && !isDepartmentPrefixPresent) {
model.updateFilteredPersonList(positionPredicate, sortOrder);
} else if (isDepartmentPrefixPresent && isPositionPrefixPresent) {
model.updateFilteredPersonList(departmentPredicate.and(positionPredicate), sortOrder);
}
EmployeeIdExpensesContainsKeywordsPredicate expensesPredicate = generateEmployeeIdExpensesPredicate(model);
EmployeeIdScheduleContainsKeywordsPredicate schedulePredicate = generateEmployeeIdSchedulePredicate(model);
model.updateFilteredExpensesList(expensesPredicate);
model.updateFilteredScheduleList(schedulePredicate);
return new CommandResult(feedbackToUser(model, allAvailableDepartments, allAvailablePositions));
}
...
...
}
The result of the execution of FilterCommand
is then encapsulated as a CommandResult
object which is returned to the LogicManager
.
During the execution of FilterCommand
, the filteredPersonList
, filteredExpensesList
and filteredScheduleList
will be updated accordingly to display only employees, that belongs to the department(s)
and/or hold the specified position(s) as specified by the user input.
The sequence diagram below illustrates the operation of filter
command:
Design Considerations
Aspect: Implementation of filter
command
-
Alternative 1 (current choice): One command to handle filtering by department(s) and/or position(s)
-
Pros: Does not require several command and parser files to handle filtering of different fields
-
Cons: Additional methods required to check for presence of prefix and input validity
-
-
Alternative 2: Separate commands for filtering department and position, one for department and one for position
-
Pros: Easy to implement as it follows the existing
find
command -
Cons: More commands to create and implementation can get quite complicated when filter requires both fields
-
Future improvements: Keyword suggestion and auto complete feature [Upcoming in 2.0]
This feature will suggest keywords when filtering or finding employee and the keyword will be auto-completed by pressing TAB
key. [Upcoming in 2.0]