prepare(" SELECT e.*, u.id as linked_user_id, u.email as user_email, u.last_login_at, u.welcome_email_sent_at FROM employees e LEFT JOIN users u ON e.user_id = u.id WHERE e.id = ? "); $employee->execute([$id]); $employee = $employee->fetch(); if (!$employee) { die("Employee not found."); } // Handle Welcome Email Request if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['send_welcome'])) { require_once __DIR__ . '/mail/MailService.php'; $targetUser = null; if ($employee['linked_user_id']) { $stmt = $db->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$employee['linked_user_id']]); $targetUser = $stmt->fetch(); } else if ($employee['email']) { // Create user if doesn't exist? For now let's assume we invite existing users or those with email $stmt = $db->prepare("SELECT * FROM users WHERE email = ?"); $stmt->execute([$employee['email']]); $targetUser = $stmt->fetch(); } if (!$targetUser && $employee['email']) { // Create user if missing try { $stmt = $db->prepare("INSERT INTO users (tenant_id, name, email, role, require_password_change) VALUES (?, ?, ?, 'staff', 1)"); $stmt->execute([$employee['tenant_id'], $employee['name'], $employee['email']]); $newUserId = $db->lastInsertId(); // Link employee to user $db->prepare("UPDATE employees SET user_id = ? WHERE id = ?")->execute([$newUserId, $id]); // Fetch the new user $stmt = $db->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$newUserId]); $targetUser = $stmt->fetch(); } catch (\Exception $e) { $error_msg = "Could not create user account: " . $e->getMessage(); } } if ($targetUser) { $token = bin2hex(random_bytes(32)); $expires = date('Y-m-d H:i:s', strtotime('+48 hours')); $db->prepare("INSERT INTO password_resets (email, token, expires_at) VALUES (?, ?, ?)") ->execute([$targetUser['email'], $token, $expires]); $setupLink = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]/reset_password.php?token=$token"; $subject = "Welcome to SR&ED Manager - Account Setup"; $html = "

Welcome to SR&ED Manager!

Your account has been created. Click the button below to set your password and get started.

Set Up Account

This link will expire in 48 hours.

"; $text = "Welcome! Set up your account here: $setupLink"; if (MailService::sendMail($targetUser['email'], $subject, $html, $text)) { $db->prepare("UPDATE users SET welcome_email_sent_at = NOW() WHERE id = ?") ->execute([$targetUser['id']]); $success_msg = "Welcome email sent to " . $targetUser['email']; } } } $pageTitle = "Employee Detail: " . htmlspecialchars($employee['name']); include __DIR__ . '/includes/header.php'; // Fetch recent sessions $sessions = []; if ($employee['linked_user_id']) { $sessionStmt = $db->prepare("SELECT * FROM user_sessions WHERE user_id = ? ORDER BY login_at DESC LIMIT 5"); $sessionStmt->execute([$employee['linked_user_id']]); $sessions = $sessionStmt->fetchAll(); } // Fetch recent labour entries $stmt = $db->prepare(" SELECT l.*, p.name as project_name, lt.name as labour_type FROM labour_entries l JOIN projects p ON l.project_id = p.id JOIN labour_types lt ON l.labour_type_id = lt.id WHERE l.employee_id = ? ORDER BY l.entry_date DESC LIMIT 10 "); $stmt->execute([$id]); $labourEntries = $stmt->fetchAll(); // Fetch summary stats $stats = $db->prepare(" SELECT (SELECT SUM(hours) FROM labour_entries WHERE employee_id = ?) as total_hours, (SELECT COUNT(DISTINCT project_id) FROM labour_entries WHERE employee_id = ?) as project_count, (SELECT COUNT(*) FROM attachments a JOIN labour_entries le ON a.entity_id = le.id WHERE a.entity_type = 'labour_entry' AND le.employee_id = ?) as file_count "); $stats->execute([$id, $id, $id]); $stats = $stats->fetch(); // Fetch recent expenses (linked via attachments uploaded by this employee name) $expenseStmt = $db->prepare(" SELECT ex.*, et.name as expense_type, s.name as supplier_name, p.name as project_name FROM expenses ex JOIN expense_types et ON ex.expense_type_id = et.id LEFT JOIN suppliers s ON ex.supplier_id = s.id JOIN projects p ON ex.project_id = p.id JOIN attachments a ON a.entity_id = ex.id AND a.entity_type = 'expense' WHERE a.uploaded_by = ? ORDER BY ex.entry_date DESC LIMIT 10 "); $expenseStmt->execute([$employee['name']]); $expenseEntries = $expenseStmt->fetchAll(); // Fetch recent files (uploaded by this employee or linked to their labour) $fileStmt = $db->prepare(" SELECT a.*, COALESCE(le.entry_date, ex.entry_date) as entry_date, COALESCE(p1.name, p2.name) as project_name FROM attachments a LEFT JOIN labour_entries le ON a.entity_id = le.id AND a.entity_type = 'labour_entry' LEFT JOIN projects p1 ON le.project_id = p1.id LEFT JOIN expenses ex ON a.entity_id = ex.id AND a.entity_type = 'expense' LEFT JOIN projects p2 ON ex.project_id = p2.id WHERE a.uploaded_by = ? OR (a.entity_type = 'labour_entry' AND le.employee_id = ?) ORDER BY a.created_at DESC LIMIT 10 "); $fileStmt->execute([$employee['name'], $id]); $recentFiles = $fileStmt->fetchAll(); function formatBytes($bytes, $precision = 2) { $units = ['B', 'KB', 'MB', 'GB', 'TB']; $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); $bytes /= pow(1024, $pow); return round($bytes, $precision) . ' ' . $units[$pow]; } ?>

• Joined

Add Labour
Total Hours

Across all projects
Projects

Involved in
Files Uploaded

Labour & Expenses
Email

Contact Info
Recent Labour Entries
View All
Date Project Type Hours
No entries found.
Recent Expenses Captured
View All
Date Project Type Amount
No expenses captured by this employee.
$
Recent Files & Attachments
View All Files
Filename Linked To Size Date Action
No files found.
View
Recent Sessions
Login Time IP / Country
No session history found.