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
-
Project Management:
-
Assists in approving, reviewing and merging pull requests.
-
-
Major enhancement: added
modifyPay
andmodifyAllPay
command-
What it does: allows the user to modify the salary and bonus of the employees. Additionally, the
modifyAllPay
command enhance the functionality ofmodifyPay
command by enabling the user to modify the salary and bonus of every employees shown in the list. -
Justification: This feature improves the product significantly because the user can indicate the changes to be made to the employee(s) salary based on values or percentage, and to the bonus based on months of salary.
-
Highlights: These commands enhance the users experience in dealing with payroll due to the functionality to modify the salary and bonus just by indicating the value or percentage for salary, and number of months for bonus without having to calculate themselves which reduce chances for human error.
-
-
Code contributed: [Reposense Dashboard]
-
Other contributions:
-
Test Case:
-
Documentation:
-
Community:
-
Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
Modify the Salary and/or Bonus of an employee : modifyPay
Modify the Salary and/or Bonus of the employee identified by the index.
Format: modifyPay INDEX [s/SALARY] [b/BONUS]
or mp INDEX [s/SALARY] [b/BONUS]
At least one of either Salary or Bonus must be included Bonus will be replaced by new values with every modification |
Examples:
-
modifyPay 1 s/300
Modify the Salary of employee with index '1' with 300 increment -
modifyPay 2 b/2
Modify the Bonus of employee with index '2' to 2 months of the salary -
modifyPay 3 s/%5 b/1
Modify the Salary of employee with index '3' by 5% increment and Bonus to 1 month of salary
Modification to Salary and/or Bonus that causes negative values will be rejected Modification to Salary that goes higher than 999999.99 will be rejected since Salary can only hold a maximum of 6 whole numbers and 2 decimal places. |
Modify the Salary and/or Bonus all listed employee(s) : modifyAllPay
Modify the Salary and/or Bonus of all the employee(s) shown on the display list.
Format: modifyAllPay [s/SALARY] [b/BONUS]
or map [s/SALARY] [b/BONUS]
At least one of either Salary or Bonus must be included Bonus will be replaced by new values with every modification |
Examples:
-
modifyAllPay s/300
Modify the Salary of all the listed employee(s) by increment of 300 -
modifyAllPay b/2
Modify the Bonus of all the listed employee(s) to 1 month of their salary -
modifyAllPay s/%5 b/1
Modify the Salary of all the listed employee(s) by 5% increment and Bonus to 1 month of salary
Modification to Salary and/or Bonus that causes negative values to any employee(s) on the list will be rejected Modification to Salary that goes higher than 999999.99 will be rejected since Salary can only hold a maximum of 6 whole numbers and 2 decimal places. |
Employees' income report generation feature [Upcoming in 2.0]
This feature will generate an employee payout report to show the break down of the Salary and Bonus in term of Base Salary, Bonus, Overtime Pay and CPF Contribution. [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. |
Modify Pay Feature
The command modifyPay
allows the user to modify the salary and bonus of the employee based on the input.
Current Implementation
The implementation of this command consist of two phases.
Phase 1
The modifyPay
function is first supported by ModifyPayCommandParser
which implements the Parser
interface. The interface parse the arguments parameter, which was inputted by the users to form the ModifyPayCommand
object. The arguments will also have their validity checked by the method, isValidSalary
and isValidBonus
, within respective Classes before being parse into the salary and bonus column which will return an error message when the arguments did not meet the requirements.
Code Snippet of ModifyPayCommandParser
that show the parsing of input and the checking validity of the inputs:
public class ModifyPayCommandParser implements Parser<ModifyPayCommand> {
private static final double BONUS_UPPER_LIMIT = 24.0;
public ModifyPayCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_SALARY, PREFIX_BONUS);
Index index;
try {
index = ParserUtil.parseIndex(argMultimap.getPreamble());
} catch (ParseException pe) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ModifyPayCommand.MESSAGE_USAGE), pe);
}
if (!didPrefixAppearOnlyOnce(args)) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ModifyPayCommand.MESSAGE_USAGE));
}
ModSalaryDescriptor modSalaryDescriptor = new ModSalaryDescriptor();
if (argMultimap.getValue(PREFIX_SALARY).isPresent()) {
modSalaryDescriptor.setSalary(ParserUtil.parseSalary(argMultimap.getValue(PREFIX_SALARY).get()));
}
if (argMultimap.getValue(PREFIX_BONUS).isPresent()) {
Bonus bonusInput = ParserUtil.parseBonus(argMultimap.getValue(PREFIX_BONUS).get());
double bonus = Double.parseDouble(argMultimap.getValue(PREFIX_BONUS).get());
if (bonus > BONUS_UPPER_LIMIT) {
throw new ParseException(Bonus.MESSAGE_BONUS_CONSTRAINTS);
}
modSalaryDescriptor.setBonus(bonusInput);
}
if (!modSalaryDescriptor.isAnyFieldEdited()) {
throw new ParseException(ModifyPayCommand.MESSAGE_NOT_MODIFIED);
}
return new ModifyPayCommand(index, modSalaryDescriptor);
}
private boolean didPrefixAppearOnlyOnce(String argument) {
String salaryPrefix = " " + PREFIX_SALARY.toString();
String bonusPrefix = " " + PREFIX_BONUS.toString();
return argument.indexOf(salaryPrefix) == argument.lastIndexOf(salaryPrefix)
&& argument.indexOf(bonusPrefix) == argument.lastIndexOf(bonusPrefix);
}
}
Code snippet of Salary
public static final String MESSAGE_SALARY_CONSTRAINTS =
"Salary should only contain numbers, and it should not be blank. Only a maximum of 6 whole numbers and "
+ "2 decimal place are allowed. (Max Salary store value is 999999.99)\n";
public static final String SALARY_VALIDATION_REGEX = "[%]?[-]?[0-9]{1,6}([.][0-9]{1,2})?";
public final String value;
/**
* Constructs a {@code salary}.
*
* @param salary A valid salary.
*/
public Salary(String salary) {
requireNonNull(salary);
checkArgument(isValidSalary(salary), MESSAGE_SALARY_CONSTRAINTS);
value = salary;
}
/**
* Returns true if a given string is a valid salary.
*/
public static boolean isValidSalary(String test) {
return test.matches(SALARY_VALIDATION_REGEX);
}
Code snippet of Bonus
public static final String MESSAGE_BONUS_CONSTRAINTS =
"Bonus should only contain positive numbers and maximum of 2 decimal places from 0 to 24,"
+ " and it should not be blank";
public static final String BONUS_VALIDATION_REGEX = "(([0-9]{1,7}([.][0-9]{1,2})?)|(1[0-9]{7}([.][0-9]{1,2})?)"
+ "|(2[0-3]([0-9]{1,6})([.][0-9]{1,2})?))";
public final String value;
public Bonus(String bonus) {
requireNonNull(bonus);
checkArgument(isValidBonus(bonus), MESSAGE_BONUS_CONSTRAINTS);
value = bonus;
}
/**
* Returns true if a given string is a valid bonus.
*/
public static boolean isValidBonus(String test) {
return test.matches(BONUS_VALIDATION_REGEX);
}
Phase 2
The ModifyPayCommand
is being executed in this phase. createModifiedPerson
method calls for the edited value from ModifyPayCommandParser
to check if there are values being inputted by the users. When it is found to be a null values, createModifiedPerson
will take back the original value.
Code snippet of ModifyPayCommand
which execute the createModifiedPerson
method:
private static Person createModifiedPerson(Person personToEdit,
ModSalaryDescriptor modSalaryDescriptor) throws ParseException {
assert personToEdit != null;
EmployeeId updatedEmployeeId = personToEdit.getEmployeeId();
Name updatedName = personToEdit.getName();
DateOfBirth updatedDateOfBirth = personToEdit.getDateOfBirth();
Phone updatedPhone = personToEdit.getPhone();
Email updatedEmail = personToEdit.getEmail();
Department updatedDepartment = personToEdit.getDepartment();
Position updatedPosition = personToEdit.getPosition();
Address updatedAddress = personToEdit.getAddress();
Salary updatedSalary = ParserUtil.parseSalary(typeOfSalaryMod(personToEdit, modSalaryDescriptor));
Bonus updatedBonus = ParserUtil.parseBonus(modifyBonusMonth(personToEdit, modSalaryDescriptor, updatedSalary));
Set<Tag> updatedTags = personToEdit.getTags();
return new Person(updatedEmployeeId, updatedName, updatedDateOfBirth, updatedPhone, updatedEmail,
updatedDepartment, updatedPosition, updatedAddress, updatedSalary, updatedBonus, updatedTags);
}
The result of ModifyPayCommand
is encapsulated as a CommandResult
object which is
passed back into the UI to reflect the newly modified Salary/Bonus.
The sequence diagram below illustrates the operation of modifyPay
command:
Employee’s Pay Report: payReport
[Upcoming in 2.0]
Generate a report to show the break down of employee’s pay such as base Salary, Bonus, Overtime Pay and CPF Contribution. [Upcoming in 2.0]
Design Considerations
Aspect implementation of modifyPay
command:
-
Alternative 1(current choice): A separate command to handle modification of payroll.
-
Pros: Reduce the risk of accidental editing of sensitive information
-
Cons: Additional method and prefixes are required to execute the function
-
-
Alternative 2: One command to handle all the modifications
-
Pros: Lesser Class to handle different fields
-
Cons: User may accidentally touch on sensitive data and ended up editing them
-