From a2a711f887d16d68748aa4ddb5c0ca00ae288901 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 15 Feb 2026 00:18:02 +0000 Subject: [PATCH] added labour --- assets/css/custom.css | 120 +++++++ db/migrations/001_initial_schema.sql | 43 +++ db/migrations/002_labour_module.sql | 74 ++++ index.php | 513 ++++++++++++++++++++------- 4 files changed, 612 insertions(+), 138 deletions(-) create mode 100644 assets/css/custom.css create mode 100644 db/migrations/001_initial_schema.sql create mode 100644 db/migrations/002_labour_module.sql diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..0d3fda7 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,120 @@ +body { + background-color: #f8fafc; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + color: #0f172a; + font-size: 0.875rem; +} + +.navbar { + background-color: #ffffff; + border-bottom: 1px solid #e2e8f0; + padding: 0.75rem 1.5rem; +} + +.navbar-brand { + font-weight: 700; + color: #0f172a; + letter-spacing: -0.025em; +} + +.nav-link { + color: #475569; + font-weight: 500; +} + +.nav-link:hover { + color: #3b82f6; +} + +.dropdown-menu { + border: 1px solid #e2e8f0; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); + border-radius: 0.375rem; + padding: 0.5rem; +} + +.dropdown-item { + border-radius: 0.25rem; + padding: 0.5rem 0.75rem; + color: #475569; +} + +.dropdown-item:hover { + background-color: #f1f5f9; + color: #3b82f6; +} + +.card { + background-color: #ffffff; + border: 1px solid #e2e8f0; + border-radius: 0.375rem; + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); +} + +.card-header { + background-color: #ffffff; + border-bottom: 1px solid #e2e8f0; + padding: 1rem 1.5rem; + font-weight: 600; +} + +.btn-primary { + background-color: #3b82f6; + border-color: #3b82f6; + font-weight: 500; +} + +.btn-primary:hover { + background-color: #2563eb; + border-color: #2563eb; +} + +.table { + margin-bottom: 0; +} + +.table th { + background-color: #f8fafc; + color: #64748b; + text-transform: uppercase; + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.05em; + padding: 0.75rem 1.5rem; + border-top: none; +} + +.table td { + padding: 1rem 1.5rem; + vertical-align: middle; +} + +.status-badge { + padding: 0.25rem 0.5rem; + border-radius: 9999px; + font-size: 0.75rem; + font-weight: 600; +} + +.status-active { background-color: #dcfce7; color: #166534; } +.status-on-hold { background-color: #fef9c3; color: #854d0e; } +.status-completed { background-color: #dbeafe; color: #1e40af; } + +.activity-feed { + list-style: none; + padding: 0; +} + +.activity-item { + padding: 0.75rem 0; + border-bottom: 1px solid #f1f5f9; +} + +.activity-item:last-child { + border-bottom: none; +} + +.activity-time { + font-size: 0.75rem; + color: #94a3b8; +} diff --git a/db/migrations/001_initial_schema.sql b/db/migrations/001_initial_schema.sql new file mode 100644 index 0000000..e92c915 --- /dev/null +++ b/db/migrations/001_initial_schema.sql @@ -0,0 +1,43 @@ +-- Initial Schema for SR&ED Manager +CREATE TABLE IF NOT EXISTS tenants ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + role ENUM('global_admin', 'tenant_admin', 'staff') DEFAULT 'staff', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE SET NULL +); + +CREATE TABLE IF NOT EXISTS projects ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT NOT NULL, + name VARCHAR(255) NOT NULL, + code VARCHAR(50) NOT NULL, + status ENUM('active', 'completed', 'on_hold') DEFAULT 'active', + start_date DATE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS activity_log ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT NOT NULL, + user_id INT, + action VARCHAR(255) NOT NULL, + details TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE +); + +-- Seed Initial Demo Data +INSERT IGNORE INTO tenants (id, name) VALUES (1, 'Acme Research Corp'); +INSERT IGNORE INTO users (id, tenant_id, name, email, role) VALUES (1, 1, 'John Manager', 'john@acme.com', 'tenant_admin'); +INSERT IGNORE INTO projects (tenant_id, name, code, start_date) VALUES (1, 'Project Alpha: Quantum AI', 'PA-001', '2025-01-01'); +INSERT IGNORE INTO activity_log (tenant_id, user_id, action, details) VALUES (1, 1, 'System Setup', 'Initial tenant environment created.'); diff --git a/db/migrations/002_labour_module.sql b/db/migrations/002_labour_module.sql new file mode 100644 index 0000000..fc7ea51 --- /dev/null +++ b/db/migrations/002_labour_module.sql @@ -0,0 +1,74 @@ +-- Migration for Labour Module and Centralized Attachments + +-- Table for Employees +CREATE TABLE IF NOT EXISTS employees ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT NOT NULL, + name VARCHAR(255) NOT NULL, + email VARCHAR(255), + position VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE +); + +-- Table for Labour Types (e.g., Experimental Development, Technical Support) +CREATE TABLE IF NOT EXISTS labour_types ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT NOT NULL, + name VARCHAR(255) NOT NULL, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE +); + +-- Table for Objective Evidence Types (e.g., Logbooks, Test Results, Design Docs) +CREATE TABLE IF NOT EXISTS evidence_types ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT NOT NULL, + name VARCHAR(255) NOT NULL, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE +); + +-- Table for Labour Entries +CREATE TABLE IF NOT EXISTS labour_entries ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT NOT NULL, + project_id INT NOT NULL, + employee_id INT NOT NULL, + entry_date DATE NOT NULL, + hours DECIMAL(10, 2) NOT NULL, + labour_type_id INT, + evidence_type_id INT, + notes TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE, + FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE, + FOREIGN KEY (employee_id) REFERENCES employees(id) ON DELETE CASCADE, + FOREIGN KEY (labour_type_id) REFERENCES labour_types(id) ON DELETE SET NULL, + FOREIGN KEY (evidence_type_id) REFERENCES evidence_types(id) ON DELETE SET NULL +); + +-- Centralized Attachments Table +CREATE TABLE IF NOT EXISTS attachments ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT NOT NULL, + entity_type VARCHAR(50) NOT NULL, -- 'labour_entry', 'project', 'expense', etc. + entity_id INT NOT NULL, + file_name VARCHAR(255) NOT NULL, + file_path VARCHAR(255) NOT NULL, + file_size INT, + mime_type VARCHAR(100), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE +); + +-- Seed some initial settings for the demo tenant +INSERT IGNORE INTO employees (tenant_id, name, position) VALUES (1, 'Alice Smith', 'Lead Researcher'); +INSERT IGNORE INTO employees (tenant_id, name, position) VALUES (1, 'Bob Jones', 'Developer'); + +INSERT IGNORE INTO labour_types (tenant_id, name) VALUES (1, 'Experimental Development'); +INSERT IGNORE INTO labour_types (tenant_id, name) VALUES (1, 'Technical Support'); +INSERT IGNORE INTO labour_types (tenant_id, name) VALUES (1, 'Technical Planning'); + +INSERT IGNORE INTO evidence_types (tenant_id, name) VALUES (1, 'Logbooks'); +INSERT IGNORE INTO evidence_types (tenant_id, name) VALUES (1, 'Test Results'); +INSERT IGNORE INTO evidence_types (tenant_id, name) VALUES (1, 'Design Documents'); +INSERT IGNORE INTO evidence_types (tenant_id, name) VALUES (1, 'Source Code Commits'); diff --git a/index.php b/index.php index 7205f3d..f1183ab 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,387 @@ prepare("INSERT INTO projects (tenant_id, name, code, start_date) VALUES (?, ?, ?, ?)"); + $stmt->execute([$tenant_id, $name, $code, $start_date]); + + // Log Activity + $stmt = db()->prepare("INSERT INTO activity_log (tenant_id, action, details) VALUES (?, ?, ?)"); + $stmt->execute([$tenant_id, 'Project Created', "Added project: $name ($code)"]); + + header("Location: index.php?success=1"); + exit; + } +} + +// Handle Add Labour +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_labour'])) { + $project_id = (int)($_POST['project_id'] ?? 0); + $employee_id = (int)($_POST['employee_id'] ?? 0); + $entry_date = $_POST['entry_date'] ?? date('Y-m-d'); + $hours = (float)($_POST['hours'] ?? 0); + $labour_type_id = (int)($_POST['labour_type_id'] ?? 0); + $evidence_type_id = (int)($_POST['evidence_type_id'] ?? 0); + $notes = $_POST['notes'] ?? ''; + + if ($project_id && $employee_id && $hours > 0) { + $stmt = db()->prepare("INSERT INTO labour_entries (tenant_id, project_id, employee_id, entry_date, hours, labour_type_id, evidence_type_id, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$tenant_id, $project_id, $employee_id, $entry_date, $hours, $labour_type_id, $evidence_type_id, $notes]); + $labour_entry_id = (int)db()->lastInsertId(); + + // Handle File Uploads + if (!empty($_FILES['attachments']['name'][0])) { + foreach ($_FILES['attachments']['tmp_name'] as $key => $tmp_name) { + $file_name = $_FILES['attachments']['name'][$key]; + $file_size = $_FILES['attachments']['size'][$key]; + $mime_type = $_FILES['attachments']['type'][$key]; + $file_ext = pathinfo($file_name, PATHINFO_EXTENSION); + $new_file_name = uniqid() . '.' . $file_ext; + $file_path = 'uploads/' . $new_file_name; + + if (move_uploaded_file($tmp_name, $file_path)) { + $stmt = db()->prepare("INSERT INTO attachments (tenant_id, entity_type, entity_id, file_name, file_path, file_size, mime_type) VALUES (?, 'labour_entry', ?, ?, ?, ?, ?)"); + $stmt->execute([$tenant_id, $labour_entry_id, $file_name, $file_path, $file_size, $mime_type]); + } + } + } + + // Log Activity + $stmt = db()->prepare("INSERT INTO activity_log (tenant_id, action, details) VALUES (?, ?, ?)"); + $stmt->execute([$tenant_id, 'Labour Added', "Logged $hours hours for employee ID $employee_id"]); + + header("Location: index.php?success=labour"); + exit; + } +} + +// Fetch Data +$projects = db()->prepare("SELECT * FROM projects WHERE tenant_id = ? ORDER BY created_at DESC"); +$projects->execute([$tenant_id]); +$projectList = $projects->fetchAll(); + +$employees = db()->prepare("SELECT * FROM employees WHERE tenant_id = ? ORDER BY name"); +$employees->execute([$tenant_id]); +$employeeList = $employees->fetchAll(); + +$labourTypes = db()->prepare("SELECT * FROM labour_types WHERE tenant_id = ? ORDER BY name"); +$labourTypes->execute([$tenant_id]); +$labourTypeList = $labourTypes->fetchAll(); + +$evidenceTypes = db()->prepare("SELECT * FROM evidence_types WHERE tenant_id = ? ORDER BY name"); +$evidenceTypes->execute([$tenant_id]); +$evidenceTypeList = $evidenceTypes->fetchAll(); + +$labourEntries = db()->prepare(" + SELECT le.*, p.name as project_name, e.name as employee_name, lt.name as labour_type, et.name as evidence_type + FROM labour_entries le + JOIN projects p ON le.project_id = p.id + JOIN employees e ON le.employee_id = e.id + LEFT JOIN labour_types lt ON le.labour_type_id = lt.id + LEFT JOIN evidence_types et ON le.evidence_type_id = et.id + WHERE le.tenant_id = ? + ORDER BY le.entry_date DESC, le.created_at DESC +"); +$labourEntries->execute([$tenant_id]); +$labourList = $labourEntries->fetchAll(); + +$activities = db()->prepare("SELECT * FROM activity_log WHERE tenant_id = ? ORDER BY created_at DESC LIMIT 10"); +$activities->execute([$tenant_id]); +$activityList = $activities->fetchAll(); + +$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'SR&ED Project Tracking Software'; ?> - - - New Style - - - - - - - - - - - - - - - - - - - + + + SR&ED Manager - Dashboard + + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ +
- + + +
+
+ +
+ + + + +
+
+ Active Projects + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
Project NameCodeStart DateStatusActions
+ +
No projects found. Start by adding one.
+
+
+ +
+
+ Recent Labour Entries + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
DateEmployeeProjectHoursType / EvidenceActions
h +
+
+
+ +
No labour entries found.
+
+
+
+ + +
+
+
Activity Hub
+
+
    + +
  • +
    +
    +
    +
  • + +
+
+
+
+
+
+ + + + + + + +