query("SELECT * FROM users WHERE role = 'admin' LIMIT 1")->fetch(PDO::FETCH_ASSOC); } return $user; } function get_current_company_id() { $user = getCurrentAppUser(); return $user ? $user['company_id'] : null; } function get_company_onboarding_status($company_id) { $stmt = db()->prepare("SELECT onboarding_complete FROM companies WHERE id = ?"); $stmt->execute([$company_id]); $result = $stmt->fetch(PDO::FETCH_ASSOC); return $result ? (bool)$result['onboarding_complete'] : false; } function logActivity($job_id, $event_type, $field_name = null, $old_value = null, $new_value = null) { $user = getCurrentAppUser(); if (!$user) { return; } // Don't log if no user context $stmt = db()->prepare("INSERT INTO activity_logs (job_id, company_id, user_id, user_name, event_type, field_name, old_value, new_value) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([ $job_id, $user['company_id'], $user['id'], $user['name'], $event_type, $field_name, $old_value, $new_value ]); } function getJobStatuses($company_id) { $stmt = db()->prepare("SELECT * FROM job_statuses WHERE company_id = ?"); $stmt->execute([$company_id]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function getClients($company_id) { $stmt = db()->prepare("SELECT * FROM clients WHERE company_id = ? AND is_active = 1"); $stmt->execute([$company_id]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function getCompanyRequiredFolders($company_id) { $stmt = db()->prepare("SELECT * FROM job_folders WHERE company_id = ? AND is_required = TRUE ORDER BY name ASC"); $stmt->execute([$company_id]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } // New functions for File & Folder Manager /** * Ensures all required folders for a company are created for a specific job. * This should be called when a new job is created or when new required folders are added globally. */ function ensureRequiredJobFoldersExist($job_id, $company_id) { $pdo = db(); $required_folders = getCompanyRequiredFolders($company_id); $insert_stmt = $pdo->prepare( "INSERT IGNORE INTO job_job_folders (job_id, company_id, folder_id, name, is_custom) VALUES (?, ?, ?, ?, ?)" ); foreach ($required_folders as $rf) { // Check if this required folder already exists for this job $check_stmt = $pdo->prepare( "SELECT COUNT(*) FROM job_job_folders WHERE job_id = ? AND company_id = ? AND folder_id = ? AND is_custom = FALSE" ); $check_stmt->execute([$job_id, $company_id, $rf['id']]); if ($check_stmt->fetchColumn() == 0) { $insert_stmt->execute([$job_id, $company_id, $rf['id'], $rf['name'], FALSE]); } } } function getJobFolders($job_id, $company_id) { $stmt = db()->prepare("SELECT jjf.*, COUNT(jf.id) as file_count FROM job_job_folders jjf LEFT JOIN job_files jf ON jjf.id = jf.job_job_folder_id WHERE jjf.job_id = ? AND jjf.company_id = ? GROUP BY jjf.id ORDER BY jjf.is_custom ASC, jjf.name ASC"); $stmt->execute([$job_id, $company_id]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function getFilesInJobFolder($job_job_folder_id, $company_id) { $stmt = db()->prepare("SELECT * FROM job_files WHERE job_job_folder_id = ? AND company_id = ? ORDER BY filename ASC"); $stmt->execute([$job_job_folder_id, $company_id]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function createJobFolder($job_id, $company_id, $folder_name, $is_custom = TRUE, $folder_id = null) { $pdo = db(); // Check for duplicate folder name for this job $check_stmt = $pdo->prepare("SELECT COUNT(*) FROM job_job_folders WHERE job_id = ? AND company_id = ? AND name = ?"); $check_stmt->execute([$job_id, $company_id, $folder_name]); if ($check_stmt->fetchColumn() > 0) { return ['success' => FALSE, 'message' => 'Folder with this name already exists for this job.']; } $stmt = $pdo->prepare("INSERT INTO job_job_folders (job_id, company_id, folder_id, name, is_custom) VALUES (?, ?, ?, ?, ?)"); $success = $stmt->execute([$job_id, $company_id, $folder_id, $folder_name, $is_custom]); return ['success' => $success, 'id' => $pdo->lastInsertId()]; } function deleteJobFolder($job_job_folder_id, $job_id, $company_id) { $pdo = db(); $pdo->beginTransaction(); try { // Check if the folder is custom and empty $folder_info_stmt = $pdo->prepare("SELECT is_custom FROM job_job_folders WHERE id = ? AND job_id = ? AND company_id = ?"); $folder_info_stmt->execute([$job_job_folder_id, $job_id, $company_id]); $folder = $folder_info_stmt->fetch(PDO::FETCH_ASSOC); if (!$folder) { $pdo->rollBack(); return ['success' => FALSE, 'message' => 'Folder not found.']; } if (!$folder['is_custom']) { $pdo->rollBack(); return ['success' => FALSE, 'message' => 'Required folders cannot be deleted.']; } $file_count_stmt = $pdo->prepare("SELECT COUNT(*) FROM job_files WHERE job_job_folder_id = ? AND company_id = ?"); $file_count_stmt->execute([$job_job_folder_id, $company_id]); if ($file_count_stmt->fetchColumn() > 0) { $pdo->rollBack(); return ['success' => FALSE, 'message' => 'This folder must be empty before it can be deleted.']; } // Delete the folder entry from the database $delete_stmt = $pdo->prepare("DELETE FROM job_job_folders WHERE id = ? AND job_id = ? AND company_id = ?"); $success = $delete_stmt->execute([$job_job_folder_id, $job_id, $company_id]); if ($success) { logActivity($job_id, 'folder_deleted', 'folder', $folder_info_stmt->fetchColumn(3), null); // Log the name of the deleted folder $pdo->commit(); return ['success' => TRUE]; } else { $pdo->rollBack(); return ['success' => FALSE, 'message' => 'Failed to delete folder.']; } } catch (PDOException $e) { $pdo->rollBack(); return ['success' => FALSE, 'message' => 'Database error: ' . $e->getMessage()]; } } function addJobFile($job_id, $job_job_folder_id, $company_id, $user_id, $filename, $filepath, $mimetype, $size) { $pdo = db(); $stmt = $pdo->prepare("INSERT INTO job_files (job_id, job_job_folder_id, company_id, user_id, filename, filepath, mimetype, size) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); $success = $stmt->execute([$job_id, $job_job_folder_id, $company_id, $user_id, $filename, $filepath, $mimetype, $size]); if ($success) { logActivity($job_id, 'file_uploaded', 'file', null, $filename); // Log the uploaded file } return ['success' => $success, 'id' => $pdo->lastInsertId()]; } function deleteJobFile($file_id, $job_id, $company_id) { $pdo = db(); $pdo->beginTransaction(); try { // Get file information to delete from file system $file_info_stmt = $pdo->prepare("SELECT filename, filepath FROM job_files WHERE id = ? AND job_id = ? AND company_id = ?"); $file_info_stmt->execute([$file_id, $job_id, $company_id]); $file = $file_info_stmt->fetch(PDO::FETCH_ASSOC); if (!$file) { $pdo->rollBack(); return ['success' => FALSE, 'message' => 'File not found.']; } // Delete file from filesystem if (file_exists($file['filepath'])) { unlink($file['filepath']); } // Delete from database $delete_stmt = $pdo->prepare("DELETE FROM job_files WHERE id = ? AND job_id = ? AND company_id = ?"); $success = $delete_stmt->execute([$file_id, $job_id, $company_id]); if ($success) { logActivity($job_id, 'file_deleted', 'file', $file['filename'], null); // Log the deleted file $pdo->commit(); return ['success' => TRUE]; } else { $pdo->rollBack(); return ['success' => FALSE, 'message' => 'Failed to delete file from database.']; } } catch (PDOException $e) { $pdo->rollBack(); return ['success' => FALSE, 'message' => 'Database error: ' . $e->getMessage()]; } }