Implement Payslip Generation Feature
<UserStory> EMP009 : Generate Payslips </UserStory> <Changes> - Updated Payslip model to store employee, salary, and date details - Added payslip storage to DataStore and file load/save support - Added logic to generate payslips once per month per employee - Restricted payslip generation to finance role - Linked payslips to employees during load and creation - Added month, year, and day helpers to Timestamp - Added payslip generation option to Finance Executive menu </Changes> <Review> Smitha Mohan </Review>
This commit is contained in:
@@ -37,24 +37,32 @@ std::pair<Enums::EmployeeType, std::vector<std::shared_ptr<const Employee>>> Zen
|
||||
return m_employeeManagementService->searchEmployee(name);
|
||||
}
|
||||
|
||||
std::shared_ptr<const Employee> ZenvyController::getCurrentEmployee()
|
||||
{
|
||||
return m_employeeManagementService->getCurrentEmployee();
|
||||
}
|
||||
|
||||
//Payslip Management
|
||||
void ZenvyController::updateSalary(const std::string& employeeId, double basicSalary, double houseRentAllowance, double foodAllowance, double employeePFContribution, double employerPFContribution)
|
||||
{
|
||||
m_payslipManagementService->updateSalary(employeeId, basicSalary, houseRentAllowance, foodAllowance, employeePFContribution, employerPFContribution);
|
||||
}
|
||||
|
||||
std::shared_ptr<const Employee> ZenvyController::getCurrentEmployee()
|
||||
void ZenvyController::generatePayslips()
|
||||
{
|
||||
return m_employeeManagementService->getCurrentEmployee();
|
||||
m_payslipManagementService->generatePayslips();
|
||||
}
|
||||
|
||||
void ZenvyController::loadStates()
|
||||
{
|
||||
m_employeeManagementService->loadEmployees();
|
||||
m_payslipManagementService->loadPayrolls();
|
||||
m_payslipManagementService->loadPayslips();
|
||||
}
|
||||
|
||||
void ZenvyController::persistStates()
|
||||
{
|
||||
m_employeeManagementService->saveEmployees();
|
||||
m_payslipManagementService->savePayrolls();
|
||||
m_payslipManagementService->savePayslips();
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
|
||||
//Payslip management
|
||||
void updateSalary(const std::string&, double, double, double, double, double);
|
||||
void generatePayslips();
|
||||
|
||||
//File Management
|
||||
void loadStates();
|
||||
|
||||
@@ -31,3 +31,8 @@ payrollMap& DataStore::getPayrolls()
|
||||
{
|
||||
return m_payrolls;
|
||||
}
|
||||
|
||||
payslipMap& DataStore::getPayslips()
|
||||
{
|
||||
return m_payslips;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
#include "Announcement.h"
|
||||
#include "Faq.h"
|
||||
#include "Payroll.h"
|
||||
#include "Payslip.h"
|
||||
|
||||
using employeeMap = std::map<std::string, std::shared_ptr<Employee>>;
|
||||
using payrollMap = std::map<std::string, std::shared_ptr<Payroll>>;
|
||||
using payslipMap = std::map<std::string, std::shared_ptr<Payslip>>;
|
||||
using logMap = std::map<util::Timestamp, std::shared_ptr<Log>>;
|
||||
|
||||
class DataStore
|
||||
@@ -30,6 +32,7 @@ private:
|
||||
std::shared_ptr<Employee> m_authenticatedEmployee;
|
||||
employeeMap m_employees;
|
||||
payrollMap m_payrolls;
|
||||
payslipMap m_payslips;
|
||||
logMap m_logs;
|
||||
DataStore() = default;
|
||||
public:
|
||||
@@ -40,6 +43,7 @@ public:
|
||||
DataStore& operator=(DataStore&&) = delete;
|
||||
employeeMap& getEmployees();
|
||||
payrollMap& getPayrolls();
|
||||
payslipMap& getPayslips();
|
||||
logMap& getLogs();
|
||||
std::shared_ptr<Employee>& getAuthenticatedEmployee();
|
||||
void setAuthenticatedEmployee(std::shared_ptr < Employee>);
|
||||
|
||||
@@ -143,7 +143,7 @@ void Employee::addPayslip(std::shared_ptr<Payslip> payslip)
|
||||
{
|
||||
if (payslip)
|
||||
{
|
||||
m_payslips[payslip->getPayslipId()] = payslip;
|
||||
m_payslips[payslip->getId()] = payslip;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
void setFoodAllowance(double);
|
||||
void setEmployeePFContribution(double);
|
||||
void setEmployerPFContribution(double);
|
||||
virtual std::string serialize() const;
|
||||
std::string serialize() const;
|
||||
static std::shared_ptr<Payroll> deserialize(const std::string&);
|
||||
static std::string getHeaders();
|
||||
};
|
||||
@@ -1,8 +1,27 @@
|
||||
#include <sstream>
|
||||
#include "Payslip.h"
|
||||
#include "StringHelper.h"
|
||||
#include "Factory.h"
|
||||
|
||||
int Payslip::m_uid = 0;
|
||||
|
||||
const std::string& Payslip::getPayslipId() const
|
||||
Payslip::Payslip(const std::string& id,
|
||||
const std::string& employeeId,
|
||||
double salary,
|
||||
util::Timestamp timestamp)
|
||||
: m_id(id),
|
||||
m_employeeId(employeeId),
|
||||
m_salary(salary),
|
||||
m_timestamp(timestamp)
|
||||
{
|
||||
int idNumber = util::extractNumber(m_id);
|
||||
if (idNumber > m_uid)
|
||||
{
|
||||
m_uid = idNumber;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& Payslip::getId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
@@ -20,4 +39,56 @@ void Payslip::setPayslipId(const std::string& id)
|
||||
void Payslip::setSalary(double salary)
|
||||
{
|
||||
m_salary = salary;
|
||||
}
|
||||
}
|
||||
|
||||
const util::Timestamp& Payslip::getTimestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
const std::string& Payslip::getEmployeeId() const
|
||||
{
|
||||
return m_employeeId;
|
||||
}
|
||||
|
||||
std::string Payslip::serialize() const
|
||||
{
|
||||
std::ostringstream serializedPayslip;
|
||||
serializedPayslip << m_id << ','
|
||||
<< m_employeeId << ','
|
||||
<< m_salary << ','
|
||||
<< m_timestamp.toString();
|
||||
return serializedPayslip.str();
|
||||
}
|
||||
|
||||
std::shared_ptr<Payslip> Payslip::deserialize(const std::string& record)
|
||||
{
|
||||
std::string id, employeeId, timestampString;
|
||||
std::string salaryString;
|
||||
std::istringstream serializedPayslip(record);
|
||||
std::getline(serializedPayslip, id, ',');
|
||||
std::getline(serializedPayslip, employeeId, ',');
|
||||
std::getline(serializedPayslip, salaryString, ',');
|
||||
std::getline(serializedPayslip, timestampString, ',');
|
||||
|
||||
try
|
||||
{
|
||||
double salary = std::stod(salaryString);
|
||||
util::Timestamp timestamp = util::Timestamp::fromString(timestampString);
|
||||
return Factory::getObject<Payslip>(
|
||||
id,
|
||||
employeeId,
|
||||
salary,
|
||||
timestamp
|
||||
);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw std::runtime_error("Failed to deserialize Payslip object");
|
||||
}
|
||||
}
|
||||
|
||||
std::string Payslip::getHeaders()
|
||||
{
|
||||
return "PayslipId,EmployeeId,Salary,Timestamp";
|
||||
}
|
||||
|
||||
@@ -1,17 +1,30 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "Timestamp.h"
|
||||
|
||||
class Payslip
|
||||
{
|
||||
private:
|
||||
static int m_uid;
|
||||
std::string m_id;
|
||||
std::string m_employeeId;
|
||||
double m_salary;
|
||||
util::Timestamp m_timestamp;
|
||||
public:
|
||||
Payslip() : m_id("PS" + std::to_string(++m_uid)), m_salary(0.0) {}
|
||||
Payslip(const double salary) : m_id("PS" + std::to_string(++m_uid)), m_salary(salary) {}
|
||||
const std::string& getPayslipId() const;
|
||||
Payslip() : m_id("PS" + std::to_string(++m_uid)), m_employeeId(""), m_salary(0.0) {}
|
||||
Payslip(const double salary, const std::string& employeeId) : m_id("PS" + std::to_string(++m_uid)), m_employeeId(employeeId), m_salary(salary) {}
|
||||
Payslip(const std::string& id,
|
||||
const std::string& employeeId,
|
||||
double salary,
|
||||
util::Timestamp timestamp);
|
||||
const std::string& getId() const;
|
||||
double getSalary() const;
|
||||
void setPayslipId(const std::string& id);
|
||||
void setSalary(double salary);
|
||||
const util::Timestamp& getTimestamp() const;
|
||||
const std::string& getEmployeeId() const;
|
||||
std::string serialize() const;
|
||||
static std::shared_ptr<Payslip> deserialize(const std::string&);
|
||||
static std::string getHeaders();
|
||||
};
|
||||
@@ -36,5 +36,6 @@ namespace Config
|
||||
constexpr const char* EMPLOYEES_FILE = "files/Employee.csv";
|
||||
constexpr const char* GENERAL_EMPLOYEES_FILE = "files/GeneralEmployee.csv";
|
||||
constexpr const char* PAYROLL_FILE = "files/Payroll.csv";
|
||||
constexpr const char* PAYSLIP_FILE = "files/Payslip.csv";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include "PayslipManagementService.h"
|
||||
#include "ApplicationConfig.h"
|
||||
#include "AuthorizationHelper.h"
|
||||
#include "Enums.h"
|
||||
#include "FileManager.h"
|
||||
#include "Factory.h"
|
||||
|
||||
void PayslipManagementService::updateSalary(const std::string& employeeId, double basicSalary, double houseRentAllowance, double foodAllowance, double employeePFContribution, double employerPFContribution)
|
||||
{
|
||||
@@ -24,6 +26,42 @@ void PayslipManagementService::updateSalary(const std::string& employeeId, doubl
|
||||
}
|
||||
}
|
||||
|
||||
void PayslipManagementService::generatePayslips()
|
||||
{
|
||||
util::enforceAuthorization(m_dataStore.getAuthenticatedEmployee()->getEmployeeType(), Enums::EmployeeType::FINANCE);
|
||||
auto& employees = m_dataStore.getEmployees();
|
||||
auto& payslips = m_dataStore.getPayslips();
|
||||
util::Timestamp currentTimestamp;
|
||||
int currentMonth = currentTimestamp.getMonth();
|
||||
int currentYear = currentTimestamp.getYear();
|
||||
for (const auto& employeePair : employees)
|
||||
{
|
||||
auto& employee = employeePair.second;
|
||||
if (employee->getEmployeeType() == Enums::EmployeeType::ADMIN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto& employeePayslips = employee->getEmployeePayslips();
|
||||
auto payslipForTheMonth = std::find_if(employeePayslips.begin(), employeePayslips.end(),
|
||||
[currentMonth, currentYear](const auto& payslipPair)
|
||||
{
|
||||
auto& payslip = payslipPair.second;
|
||||
auto& timestamp = payslip->getTimestamp();
|
||||
return (timestamp.getMonth() == currentMonth && timestamp.getYear() == currentYear);
|
||||
}
|
||||
);
|
||||
if (payslipForTheMonth == employeePayslips.end())
|
||||
{
|
||||
auto payroll = employee->getPayroll();
|
||||
double salary;
|
||||
salary = payroll->getBasicSalary() + payroll->getFoodAllowance() + payroll->getHouseRentAllowance() - payroll->getEmployeePFContribution() - payroll->getEmployerPFContribution();
|
||||
std::shared_ptr<Payslip> payslip = Factory::getObject<Payslip>(salary, employee->getId());
|
||||
employee->addPayslip(payslip);
|
||||
payslips.emplace(payslip->getId(), payslip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PayslipManagementService::loadPayrolls()
|
||||
{
|
||||
FileManager<Payroll> payrollFileManager(Config::File::PAYROLL_FILE);
|
||||
@@ -47,4 +85,29 @@ void PayslipManagementService::savePayrolls()
|
||||
FileManager<Payroll> payrollFileManager(Config::File::PAYROLL_FILE);
|
||||
auto& payrolls = m_dataStore.getPayrolls();
|
||||
payrollFileManager.save(payrolls);
|
||||
}
|
||||
}
|
||||
|
||||
void PayslipManagementService::loadPayslips()
|
||||
{
|
||||
FileManager<Payslip> payslipFileManager(Config::File::PAYSLIP_FILE);
|
||||
auto& payslips = m_dataStore.getPayslips();
|
||||
auto& employees = m_dataStore.getEmployees();
|
||||
auto payslipObjects = payslipFileManager.load();
|
||||
for (const auto& payslipPair : payslipObjects)
|
||||
{
|
||||
auto employeeIterator = employees.find(payslipPair.second->getEmployeeId());
|
||||
if (employeeIterator == employees.end())
|
||||
{
|
||||
throw std::runtime_error("Payslip Object not associated with an existing employee");
|
||||
}
|
||||
employeeIterator->second->addPayslip(payslipPair.second);
|
||||
}
|
||||
payslips.insert(payslipObjects.begin(), payslipObjects.end());
|
||||
}
|
||||
|
||||
void PayslipManagementService::savePayslips()
|
||||
{
|
||||
FileManager<Payslip> payslipFileManager(Config::File::PAYSLIP_FILE);
|
||||
auto& payslips = m_dataStore.getPayslips();
|
||||
payslipFileManager.save(payslips);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ private:
|
||||
public:
|
||||
PayslipManagementService() : m_dataStore(DataStore::getInstance()) {};
|
||||
void updateSalary(const std::string&, double, double, double, double, double);
|
||||
void generatePayslips();
|
||||
void loadPayrolls();
|
||||
void savePayrolls();
|
||||
void loadPayslips();
|
||||
void savePayslips();
|
||||
};
|
||||
|
||||
@@ -50,6 +50,27 @@ int util::Timestamp::getDateAsInt() const
|
||||
return year * 10000 + month * 100 + day;
|
||||
}
|
||||
|
||||
int util::Timestamp::getMonth() const
|
||||
{
|
||||
std::tm timeStruct{};
|
||||
localtime_s(&timeStruct, &m_time);
|
||||
return timeStruct.tm_mon + 1;
|
||||
}
|
||||
|
||||
int util::Timestamp::getYear() const
|
||||
{
|
||||
std::tm timeStruct{};
|
||||
localtime_s(&timeStruct, &m_time);
|
||||
return timeStruct.tm_year + 1900;
|
||||
}
|
||||
|
||||
int util::Timestamp::getDay() const
|
||||
{
|
||||
std::tm timeStruct{};
|
||||
localtime_s(&timeStruct, &m_time);
|
||||
return timeStruct.tm_mday;
|
||||
}
|
||||
|
||||
double util::Timestamp::getDurationInMinutes(const Timestamp& startTimestamp, const Timestamp& endTimestamp)
|
||||
{
|
||||
return getDurationInSeconds(startTimestamp, endTimestamp) / 60.0;
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace util
|
||||
static double getDurationInMinutes(const Timestamp&, const Timestamp&);
|
||||
static double getDurationInSeconds(const Timestamp&, const Timestamp&);
|
||||
int getDateAsInt() const;
|
||||
int getMonth() const;
|
||||
int getYear() const;
|
||||
int getDay() const;
|
||||
bool operator>(const Timestamp&) const;
|
||||
bool operator<(const Timestamp&) const;
|
||||
bool operator>=(const Timestamp&) const;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "InputHelper.h"
|
||||
#include "OutputHelper.h"
|
||||
#include "MenuHelper.h"
|
||||
#include "Timestamp.h"
|
||||
|
||||
void FinanceExecutiveMenu::run()
|
||||
{
|
||||
@@ -13,7 +14,7 @@ void FinanceExecutiveMenu::run()
|
||||
{
|
||||
int choice;
|
||||
util::clear();
|
||||
std::cout << "Finance Executive Menu\n1. Apply Leave\n2. View Payslip\n3. View Payslip History\n4. View Employees\n5. Search Employee\n6. View Notification\n7. View Announcements\n8. Resolve Ticket\n9. Generate Payslip\n10. Update Payroll\n11. Update Profile\n12. View Profile \n13. Logout\nEnter your Choice: ";
|
||||
std::cout << "Finance Executive Menu\n1. Apply Leave\n2. View Payslip\n3. View Payslip History\n4. View Employees\n5. Search Employee\n6. View Notification\n7. View Announcements\n8. Resolve Ticket\n9. Generate Payslips\n10. Update Payroll\n11. Update Profile\n12. View Profile \n13. Logout\nEnter your Choice: ";
|
||||
util::read(choice);
|
||||
if (!handleOperation(choice))
|
||||
{
|
||||
@@ -51,6 +52,15 @@ void FinanceExecutiveMenu::updatePayroll()
|
||||
}
|
||||
}
|
||||
|
||||
void FinanceExecutiveMenu::generatePayslips()
|
||||
{
|
||||
util::Timestamp currentTimestamp;
|
||||
util::clear();
|
||||
m_zenvyController->generatePayslips();
|
||||
std::cout << "Generated payslips for the month of " << currentTimestamp.getMonth() << "-" << currentTimestamp.getYear() << " successfully.";
|
||||
util::pressEnter();
|
||||
}
|
||||
|
||||
bool FinanceExecutiveMenu::handleOperation(int choice)
|
||||
{
|
||||
switch (choice)
|
||||
@@ -61,6 +71,9 @@ bool FinanceExecutiveMenu::handleOperation(int choice)
|
||||
case 5:
|
||||
searchEmployee(m_zenvyController);
|
||||
break;
|
||||
case 9:
|
||||
generatePayslips();
|
||||
break;
|
||||
case 10:
|
||||
updatePayroll();
|
||||
break;
|
||||
|
||||
@@ -14,5 +14,6 @@ public:
|
||||
void run();
|
||||
bool handleOperation(int);
|
||||
void updatePayroll();
|
||||
void generatePayslips();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user