Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions app-backend/src/controllers/payroll.controller.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
/**
* @file controllers/payroll.controller.js
* @description Payroll endpoint handlers for SecureShift.
*
* Endpoints
* GET /api/v1/payroll – Generate / retrieve payroll summaries
* POST /api/v1/payroll/approve – Approve one or more PENDING payroll records
* POST /api/v1/payroll/process – Process one or more APPROVED payroll records
* GET /api/v1/payroll/export – Export payroll data as CSV or PDF
*
* POST /api/v1/payroll/attendance – Record attendance (admin / guard)
* GET /api/v1/payroll/attendance/:shiftId – Get attendance for a shift
*/

import mongoose from 'mongoose';

Check failure on line 15 in app-backend/src/controllers/payroll.controller.js

View workflow job for this annotation

GitHub Actions / lint

'mongoose' is defined but never used. Allowed unused vars must match /^_/u
import Payroll from '../models/Payroll.js';

Check failure on line 16 in app-backend/src/controllers/payroll.controller.js

View workflow job for this annotation

GitHub Actions / lint

'Payroll' is defined but never used. Allowed unused vars must match /^_/u
import ShiftAttendance from '../models/ShiftAttendance.js';

Check failure on line 17 in app-backend/src/controllers/payroll.controller.js

View workflow job for this annotation

GitHub Actions / lint

'ShiftAttendance' is defined but never used. Allowed unused vars must match /^_/u
import Shift from '../models/Shift.js';

Check failure on line 18 in app-backend/src/controllers/payroll.controller.js

View workflow job for this annotation

GitHub Actions / lint

'Shift' is defined but never used. Allowed unused vars must match /^_/u
import User from '../models/User.js';

Check failure on line 19 in app-backend/src/controllers/payroll.controller.js

View workflow job for this annotation

GitHub Actions / lint

'User' is defined but never used. Allowed unused vars must match /^_/u
import { ACTIONS } from '../middleware/logger.js';
import {
approvePayrollRecords,
Expand All @@ -6,6 +25,10 @@
getPayrollRecords,
processPayrollRecords,
} from '../services/payroll.service.js';
import {
sendPayrollApproved,

Check failure on line 29 in app-backend/src/controllers/payroll.controller.js

View workflow job for this annotation

GitHub Actions / lint

'sendPayrollApproved' is defined but never used. Allowed unused vars must match /^_/u
sendPayrollProcessed,

Check failure on line 30 in app-backend/src/controllers/payroll.controller.js

View workflow job for this annotation

GitHub Actions / lint

'sendPayrollProcessed' is defined but never used. Allowed unused vars must match /^_/u
} from '../utils/sendEmail.js';

const sendError = (res, error, fallbackMessage) => {
return res.status(error.statusCode || 500).json({
Expand Down
67 changes: 67 additions & 0 deletions app-backend/src/utils/sendEmail.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,73 @@
}
};

/**
* Notify a guard that their payroll has been APPROVED.
* In dev mode (EMAIL_ENABLED=false) prints to terminal.
*/
export const sendPayrollApproved = async (email, guardName, grossPay, periodType, startDate, endDate) => {
if (!EMAIL_ENABLED) {

Check failure on line 151 in app-backend/src/utils/sendEmail.js

View workflow job for this annotation

GitHub Actions / lint

'EMAIL_ENABLED' is not defined
console.log('');
console.log('┌─────────────────────────────────────────┐');
console.log(`│ 💰 Payroll APPROVED for ${guardName.substring(0, 15).padEnd(15)} │`);
console.log(`│ Period : ${String(periodType).padEnd(30)}│`);
console.log(`│ From : ${String(startDate).padEnd(30)}│`);
console.log(`│ To : ${String(endDate).padEnd(30)}│`);
console.log(`│ Gross : $${String(grossPay.toFixed(2)).padEnd(29)}│`);
console.log('└─────────────────────────────────────────┘');
console.log('');
return;
}

const mailOptions = {
from: `"SecureShift" <${process.env.SMTP_USER}>`,
to: email,
subject: 'Your SecureShift Payroll Has Been Approved',
text: `Hi ${guardName},\n\nYour payroll for the period ${startDate} to ${endDate} has been approved.\n\nGross Pay: $${grossPay.toFixed(2)}\n\nIt will be processed shortly.\n\nBest regards,\nSecureShift Team`,
};

try {
await transporter.sendMail(mailOptions);
console.log(`✅ Payroll approval email sent to ${email}`);
} catch (err) {
console.error('❌ Failed to send payroll approval email:', err.message);
}
};

/**
* Notify a guard that their payroll has been PROCESSED (payment on the way).
* In dev mode (EMAIL_ENABLED=false) prints to terminal.
*/
export const sendPayrollProcessed = async (email, guardName, grossPay, periodType, startDate, endDate) => {
if (!EMAIL_ENABLED) {

Check failure on line 184 in app-backend/src/utils/sendEmail.js

View workflow job for this annotation

GitHub Actions / lint

'EMAIL_ENABLED' is not defined
console.log('');
console.log('┌─────────────────────────────────────────┐');
console.log(`│ ✅ Payroll PROCESSED for ${guardName.substring(0, 14).padEnd(14)} │`);
console.log(`│ Period : ${String(periodType).padEnd(30)}│`);
console.log(`│ From : ${String(startDate).padEnd(30)}│`);
console.log(`│ To : ${String(endDate).padEnd(30)}│`);
console.log(`│ Gross : $${String(grossPay.toFixed(2)).padEnd(29)}│`);
console.log('│ Payment is on its way! │');
console.log('└─────────────────────────────────────────┘');
console.log('');
return;
}

const mailOptions = {
from: `"SecureShift" <${process.env.SMTP_USER}>`,
to: email,
subject: 'Your SecureShift Payroll Has Been Processed',
text: `Hi ${guardName},\n\nGreat news! Your payroll for the period ${startDate} to ${endDate} has been processed.\n\nGross Pay: $${grossPay.toFixed(2)}\n\nPayment is on its way.\n\nBest regards,\nSecureShift Team`,
};

try {
await transporter.sendMail(mailOptions);
console.log(`✅ Payroll processed email sent to ${email}`);
} catch (err) {
console.error('❌ Failed to send payroll processed email:', err.message);
}
};

export const sendEmployerCredentials = async (email, tempPassword, contactPerson, companyName) => {
transporter = createTransporter();

Expand Down
Loading