const dayjs = require('dayjs'); const { Document, Employee, Vendor, User, SafetyBadge, GatePass, AlertLog } = require('../models'); const { sendEmail, sendWhatsApp } = require('./notificationService'); async function ensureMandatoryDocuments(employeeId) { const rows = await Document.find({ employee_id: employeeId }, { type: 1, verified_by_hr: 1 }).lean(); const hasAadhar = rows.some((r) => r.type === 'Aadhar'); const hasUan = rows.some((r) => r.type === 'UAN'); const hasEsi = rows.some((r) => r.type === 'ESI'); const hasCompPolicy = rows.some((r) => r.type === 'Compensation_Policy'); const hasPvc = rows.some((r) => r.type === 'PVC'); return hasAadhar && hasUan && (hasEsi || hasCompPolicy) && hasPvc; } async function countVendorWorkers(vendorId) { return Employee.countDocuments({ vendor_id: vendorId, is_active: true, status: { $in: ['Pending', 'HR_Approved', 'Safety_Approved', 'Active'] } }); } async function findVendorContact(vendorId) { return User.findOne({ vendor_id: vendorId, role: 'Vendor', is_active: true }, { email: 1, phone: 1 }).lean(); } async function sendAlert(alertType, table, refId, recipientEmail, recipientPhone, subject, message) { if (!recipientEmail) return; const existing = await AlertLog.findOne({ alert_type: alertType, reference_table: table, reference_id: String(refId), recipient_email: recipientEmail, channel: 'Email' }).lean(); if (!existing) { await sendEmail(recipientEmail, subject, message); await AlertLog.create({ alert_type: alertType, reference_table: table, reference_id: String(refId), recipient_email: recipientEmail, channel: 'Email', message, sent_at: new Date() }); } if (recipientPhone) { const existingWa = await AlertLog.findOne({ alert_type: alertType, reference_table: table, reference_id: String(refId), recipient_email: recipientEmail, channel: 'WhatsApp' }).lean(); if (!existingWa) { await sendWhatsApp(`whatsapp:${recipientPhone}`, message); await AlertLog.create({ alert_type: alertType, reference_table: table, reference_id: String(refId), recipient_email: recipientEmail, channel: 'WhatsApp', message, sent_at: new Date() }); } } } async function processBadgeAlerts(adminUsers) { const today = dayjs().startOf('day'); const maxDate = today.add(30, 'day').endOf('day').toDate(); const badges = await SafetyBadge.find({ expiry_date: { $lte: maxDate } }) .populate({ path: 'employee_id', model: 'Employee', select: 'name vendor_id is_active' }) .lean(); for (const badge of badges) { const employee = badge.employee_id; if (!employee || !employee.is_active) continue; const vendor = await Vendor.findById(employee.vendor_id, { name: 1, is_active: 1 }).lean(); if (!vendor || !vendor.is_active) continue; const daysToExpiry = dayjs(badge.expiry_date).startOf('day').diff(today, 'day'); let alertType; let subject; if (daysToExpiry <= 0) { alertType = 'SAFETY_BADGE_EXPIRED'; subject = `Safety Badge Expired - ${employee.name}`; } else if (daysToExpiry === 7) { alertType = 'SAFETY_BADGE_7_DAYS'; subject = `Safety Badge Expires in 7 Days - ${employee.name}`; } else if (daysToExpiry === 30) { alertType = 'SAFETY_BADGE_30_DAYS'; subject = `Safety Badge Expires in 30 Days - ${employee.name}`; } else { continue; } const message = `${employee.name} (${vendor.name}) safety badge due date: ${dayjs(badge.expiry_date).format('DD/MM/YYYY')}.`; const vendorUser = await findVendorContact(vendor._id); if (vendorUser) { await sendAlert(alertType, 'safety_badges', badge._id, vendorUser.email, vendorUser.phone, subject, message); } for (const adminUser of adminUsers) { await sendAlert(alertType, 'safety_badges', badge._id, adminUser.email, adminUser.phone, subject, message); } } } async function processGatePassAlerts(adminUsers) { const today = dayjs().startOf('day'); const maxDate = today.add(30, 'day').endOf('day').toDate(); const gatePasses = await GatePass.find({ expiry_date: { $lte: maxDate } }) .populate({ path: 'employee_id', model: 'Employee', select: 'name vendor_id is_active' }) .lean(); for (const gatePass of gatePasses) { const employee = gatePass.employee_id; if (!employee || !employee.is_active) continue; const vendor = await Vendor.findById(employee.vendor_id, { name: 1, is_active: 1 }).lean(); if (!vendor || !vendor.is_active) continue; const daysToExpiry = dayjs(gatePass.expiry_date).startOf('day').diff(today, 'day'); let alertType; let subject; if (daysToExpiry <= 0) { alertType = 'GATE_PASS_EXPIRED'; subject = `Gate Pass Expired - ${employee.name}`; } else if (daysToExpiry === 7) { alertType = 'GATE_PASS_7_DAYS'; subject = `Gate Pass Expires in 7 Days - ${employee.name}`; } else if (daysToExpiry === 30) { alertType = 'GATE_PASS_30_DAYS'; subject = `Gate Pass Expires in 30 Days - ${employee.name}`; } else { continue; } const message = `${employee.name} (${vendor.name}) gate pass due date: ${dayjs(gatePass.expiry_date).format('DD/MM/YYYY')}.`; const vendorUser = await findVendorContact(vendor._id); if (vendorUser) { await sendAlert(alertType, 'gate_passes', gatePass._id, vendorUser.email, vendorUser.phone, subject, message); } for (const adminUser of adminUsers) { await sendAlert(alertType, 'gate_passes', gatePass._id, adminUser.email, adminUser.phone, subject, message); } } } async function sendExpiryAlerts() { const adminUsers = await User.find({ role: 'Admin', is_active: true }, { email: 1, phone: 1 }).lean(); await processBadgeAlerts(adminUsers); await processGatePassAlerts(adminUsers); await GatePass.updateMany( { expiry_date: { $lt: dayjs().startOf('day').toDate() }, status: { $ne: 'Expired' } }, { $set: { status: 'Expired' } } ); } module.exports = { ensureMandatoryDocuments, countVendorWorkers, sendExpiryAlerts };