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);
}
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;
}
}
+1 -1
View File
@@ -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();
};
+72 -1
View File
@@ -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;
}
@@ -21,3 +40,55 @@ 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";
}
+16 -3
View File
@@ -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);
@@ -48,3 +86,28 @@ void PayslipManagementService::savePayrolls()
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();
};