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 = "
Your account has been created. Click the button below to set your password and get started.
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]; } ?>= htmlspecialchars($employee['position'] ?? 'Staff') ?> • Joined = $employee['start_date'] ? date('M j, Y', strtotime($employee['start_date'])) : 'N/A' ?>
| Date | Project | Type | Hours |
|---|---|---|---|
| No entries found. | |||
| = date('M j, Y', strtotime($le['entry_date'])) ?> | = htmlspecialchars($le['project_name']) ?> | = htmlspecialchars($le['labour_type']) ?> | = number_format($le['hours'], 1) ?> |
| Date | Project | Type | Amount |
|---|---|---|---|
| No expenses captured by this employee. | |||
| = date('M j, Y', strtotime($ee['entry_date'])) ?> | = htmlspecialchars($ee['project_name']) ?> | = htmlspecialchars($ee['expense_type']) ?> | $= number_format($ee['amount'], 2) ?> |
| Filename | Linked To | Size | Date | Action |
|---|---|---|---|---|
| No files found. | ||||
|
= htmlspecialchars($f['file_name']) ?>
|
= ucfirst($f['entity_type']) ?> | = formatBytes((int)$f['file_size']) ?> | = date('M j, Y', strtotime($f['created_at'])) ?> | View |
| Login Time | IP / Country |
|---|---|
| No session history found. | |
|
= date('M j, H:i', strtotime($s['login_at'])) ?>
= date('Y', strtotime($s['login_at'])) ?>
|
= htmlspecialchars($s['ip_address']) ?>
= htmlspecialchars($s['country'] ?? 'Unknown') ?>
|