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
6 changes: 5 additions & 1 deletion app-backend/src/controllers/shift.controller.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import mongoose from 'mongoose';
import Shift from '../models/Shift.js';
import ShiftAttendance from '../models/ShiftAttendance.js';

import { ACTIONS } from "../middleware/logger.js";

Expand Down Expand Up @@ -408,7 +409,7 @@ export const completeShift = async (req, res) => {
const { id } = req.params;
if (!mongoose.isValidObjectId(id)) return res.status(400).json({ message: 'Invalid id' });

const shift = await Shift.findById(id);
const shift = await Shift.findById(id).populate('attendance');
if (!shift) return res.status(404).json({ message: 'Shift not found' });

const isOwner = String(shift.createdBy) === String(req.user._id);
Expand All @@ -418,6 +419,9 @@ export const completeShift = async (req, res) => {
if (!shift.assignedGuard) return res.status(400).json({ message: 'No guard assigned' });
if (shift.status === 'completed') return res.status(400).json({ message: 'Already completed' });

if (!shift.hasCheckedIn) return res.status(400).json({ message: 'Guard has not checked in' });
if (!shift.hasCheckedOut) return res.status(400).json({ message: 'Guard has not checked out' });

shift.status = 'completed';
await shift.save();
await req.audit.log(req.user._id, ACTIONS.SHIFT_COMPLETED, {
Expand Down
18 changes: 18 additions & 0 deletions app-backend/src/models/Shift.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,24 @@ shiftSchema
this.acceptedBy = v;
});

// Virtual for attendance record
shiftSchema
.virtual('attendance', {
ref: 'ShiftAttendance',
localField: '_id',
foreignField: 'shiftId',
justOne: true,
});

// Virtuals for check-in/out status
shiftSchema.virtual('hasCheckedIn').get(function () {
return this.attendance?.checkInTime != null;
});

shiftSchema.virtual('hasCheckedOut').get(function () {
return this.attendance?.checkOutTime != null;
});

// Ensure virtuals in responses
shiftSchema.set('toJSON', { virtuals: true });
shiftSchema.set('toObject', { virtuals: true });
Expand Down
3 changes: 3 additions & 0 deletions app-backend/src/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import adminRoutes from './admin.routes.js';
import availabilityRoutes from './availability.routes.js';
import rbacRoutes from './rbac.routes.js';
import branchRoutes from './branch.routes.js'
import shiftAttendanceRoutes from './shiftattendance.routes.js';

import payrollRoutes from './payroll.routes.js';
import documentRoutes from './document.routes.js';
const router = express.Router();
Expand All @@ -22,6 +24,7 @@ router.use('/availability', availabilityRoutes);
router.use('/users', userRoutes);
router.use('/rbac', rbacRoutes);
router.use('/branch', branchRoutes);
router.use('/attendance', shiftAttendanceRoutes);
router.use('/payroll', payrollRoutes);

export default router;
Loading