Merged PR 965: UserStory EMP009 Generate Payslips

Related work items: #954
This commit is contained in:
2026-04-14 17:32:19 +05:30
15 changed files with 218 additions and 11 deletions
@@ -37,24 +37,32 @@ std::pair<Enums::EmployeeType, std::vector<std::shared_ptr<const Employee>>> Zen
return m_employeeManagementService->searchEmployee(name); 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) 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); 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() void ZenvyController::loadStates()
{ {
m_employeeManagementService->loadEmployees(); m_employeeManagementService->loadEmployees();
m_payslipManagementService->loadPayrolls(); m_payslipManagementService->loadPayrolls();
m_payslipManagementService->loadPayslips();
} }
void ZenvyController::persistStates() void ZenvyController::persistStates()
{ {
m_employeeManagementService->saveEmployees(); m_employeeManagementService->saveEmployees();
m_payslipManagementService->savePayrolls(); m_payslipManagementService->savePayrolls();
m_payslipManagementService->savePayslips();
} }
@@ -59,6 +59,7 @@ public:
//Payslip management //Payslip management
void updateSalary(const std::string&, double, double, double, double, double); void updateSalary(const std::string&, double, double, double, double, double);
void generatePayslips();
//File Management //File Management
void loadStates(); void loadStates();
@@ -31,3 +31,8 @@ payrollMap& DataStore::getPayrolls()
{ {
return m_payrolls; return m_payrolls;
} }
payslipMap& DataStore::getPayslips()
{
return m_payslips;
}
@@ -19,9 +19,11 @@
#include "Announcement.h" #include "Announcement.h"
#include "Faq.h" #include "Faq.h"
#include "Payroll.h" #include "Payroll.h"
#include "Payslip.h"
using employeeMap = std::map<std::string, std::shared_ptr<Employee>>; using employeeMap = std::map<std::string, std::shared_ptr<Employee>>;
using payrollMap = std::map<std::string, std::shared_ptr<Payroll>>; 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>>; using logMap = std::map<util::Timestamp, std::shared_ptr<Log>>;
class DataStore class DataStore
@@ -30,6 +32,7 @@ private:
std::shared_ptr<Employee> m_authenticatedEmployee; std::shared_ptr<Employee> m_authenticatedEmployee;
employeeMap m_employees; employeeMap m_employees;
payrollMap m_payrolls; payrollMap m_payrolls;
payslipMap m_payslips;
logMap m_logs; logMap m_logs;
DataStore() = default; DataStore() = default;
public: public:
@@ -40,6 +43,7 @@ public:
DataStore& operator=(DataStore&&) = delete; DataStore& operator=(DataStore&&) = delete;
employeeMap& getEmployees(); employeeMap& getEmployees();
payrollMap& getPayrolls(); payrollMap& getPayrolls();
payslipMap& getPayslips();
logMap& getLogs(); logMap& getLogs();
std::shared_ptr<Employee>& getAuthenticatedEmployee(); std::shared_ptr<Employee>& getAuthenticatedEmployee();
void setAuthenticatedEmployee(std::shared_ptr < Employee>); void setAuthenticatedEmployee(std::shared_ptr < Employee>);
@@ -143,7 +143,7 @@ void Employee::addPayslip(std::shared_ptr<Payslip> payslip)
{ {
if (payslip) if (payslip)
{ {
m_payslips[payslip->getPayslipId()] = payslip; m_payslips[payslip->getId()] = payslip;
} }
} }
+1 -1
View File
@@ -52,7 +52,7 @@ public:
void setFoodAllowance(double); void setFoodAllowance(double);
void setEmployeePFContribution(double); void setEmployeePFContribution(double);
void setEmployerPFContribution(double); void setEmployerPFContribution(double);
virtual std::string serialize() const; std::string serialize() const;
static std::shared_ptr<Payroll> deserialize(const std::string&); static std::shared_ptr<Payroll> deserialize(const std::string&);
static std::string getHeaders(); static std::string getHeaders();
}; };
+73 -2
View File
@@ -1,8 +1,27 @@
#include <sstream>
#include "Payslip.h" #include "Payslip.h"
#include "StringHelper.h"
#include "Factory.h"
int Payslip::m_uid = 0; 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; return m_id;
} }
@@ -20,4 +39,56 @@ void Payslip::setPayslipId(const std::string& id)
void Payslip::setSalary(double salary) void Payslip::setSalary(double salary)
{ {
m_salary = 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";
}
+16 -3
View File
@@ -1,17 +1,30 @@
#pragma once #pragma once
#include <memory>
#include <string> #include <string>
#include "Timestamp.h"
class Payslip class Payslip
{ {
private: private:
static int m_uid; static int m_uid;
std::string m_id; std::string m_id;
std::string m_employeeId;
double m_salary; double m_salary;
util::Timestamp m_timestamp;
public: public:
Payslip() : m_id("PS" + std::to_string(++m_uid)), m_salary(0.0) {} Payslip() : m_id("PS" + std::to_string(++m_uid)), m_employeeId(""), m_salary(0.0) {}
Payslip(const double salary) : m_id("PS" + std::to_string(++m_uid)), m_salary(salary) {} Payslip(const double salary, const std::string& employeeId) : m_id("PS" + std::to_string(++m_uid)), m_employeeId(employeeId), m_salary(salary) {}
const std::string& getPayslipId() const; Payslip(const std::string& id,
const std::string& employeeId,
double salary,
util::Timestamp timestamp);
const std::string& getId() const;
double getSalary() const; double getSalary() const;
void setPayslipId(const std::string& id); void setPayslipId(const std::string& id);
void setSalary(double salary); 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* EMPLOYEES_FILE = "files/Employee.csv";
constexpr const char* GENERAL_EMPLOYEES_FILE = "files/GeneralEmployee.csv"; constexpr const char* GENERAL_EMPLOYEES_FILE = "files/GeneralEmployee.csv";
constexpr const char* PAYROLL_FILE = "files/Payroll.csv"; constexpr const char* PAYROLL_FILE = "files/Payroll.csv";
constexpr const char* PAYSLIP_FILE = "files/Payslip.csv";
} }
} }
@@ -1,9 +1,11 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm>
#include "PayslipManagementService.h" #include "PayslipManagementService.h"
#include "ApplicationConfig.h" #include "ApplicationConfig.h"
#include "AuthorizationHelper.h" #include "AuthorizationHelper.h"
#include "Enums.h" #include "Enums.h"
#include "FileManager.h" #include "FileManager.h"
#include "Factory.h"
void PayslipManagementService::updateSalary(const std::string& employeeId, double basicSalary, double houseRentAllowance, double foodAllowance, double employeePFContribution, double employerPFContribution) 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() void PayslipManagementService::loadPayrolls()
{ {
FileManager<Payroll> payrollFileManager(Config::File::PAYROLL_FILE); FileManager<Payroll> payrollFileManager(Config::File::PAYROLL_FILE);
@@ -47,4 +85,29 @@ void PayslipManagementService::savePayrolls()
FileManager<Payroll> payrollFileManager(Config::File::PAYROLL_FILE); FileManager<Payroll> payrollFileManager(Config::File::PAYROLL_FILE);
auto& payrolls = m_dataStore.getPayrolls(); auto& payrolls = m_dataStore.getPayrolls();
payrollFileManager.save(payrolls); 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: public:
PayslipManagementService() : m_dataStore(DataStore::getInstance()) {}; PayslipManagementService() : m_dataStore(DataStore::getInstance()) {};
void updateSalary(const std::string&, double, double, double, double, double); void updateSalary(const std::string&, double, double, double, double, double);
void generatePayslips();
void loadPayrolls(); void loadPayrolls();
void savePayrolls(); void savePayrolls();
void loadPayslips();
void savePayslips();
}; };
@@ -50,6 +50,27 @@ int util::Timestamp::getDateAsInt() const
return year * 10000 + month * 100 + day; 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) double util::Timestamp::getDurationInMinutes(const Timestamp& startTimestamp, const Timestamp& endTimestamp)
{ {
return getDurationInSeconds(startTimestamp, endTimestamp) / 60.0; return getDurationInSeconds(startTimestamp, endTimestamp) / 60.0;
@@ -17,6 +17,9 @@ namespace util
static double getDurationInMinutes(const Timestamp&, const Timestamp&); static double getDurationInMinutes(const Timestamp&, const Timestamp&);
static double getDurationInSeconds(const Timestamp&, const Timestamp&); static double getDurationInSeconds(const Timestamp&, const Timestamp&);
int getDateAsInt() const; 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; bool operator<(const Timestamp&) const;
bool operator>=(const Timestamp&) const; bool operator>=(const Timestamp&) const;
@@ -3,6 +3,7 @@
#include "InputHelper.h" #include "InputHelper.h"
#include "OutputHelper.h" #include "OutputHelper.h"
#include "MenuHelper.h" #include "MenuHelper.h"
#include "Timestamp.h"
void FinanceExecutiveMenu::run() void FinanceExecutiveMenu::run()
{ {
@@ -13,7 +14,7 @@ void FinanceExecutiveMenu::run()
{ {
int choice; int choice;
util::clear(); 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); util::read(choice);
if (!handleOperation(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) bool FinanceExecutiveMenu::handleOperation(int choice)
{ {
switch (choice) switch (choice)
@@ -61,6 +71,9 @@ bool FinanceExecutiveMenu::handleOperation(int choice)
case 5: case 5:
searchEmployee(m_zenvyController); searchEmployee(m_zenvyController);
break; break;
case 9:
generatePayslips();
break;
case 10: case 10:
updatePayroll(); updatePayroll();
break; break;
@@ -14,5 +14,6 @@ public:
void run(); void run();
bool handleOperation(int); bool handleOperation(int);
void updatePayroll(); void updatePayroll();
void generatePayslips();
}; };