Implement comprehensive project time logging feature
Add complete project management system with role-based access control: **Core Features:** - Project creation and management for Admins/Supervisors - Time tracking with optional project selection and notes - Project-based filtering and reporting in history - Enhanced export functionality with project data - Team-specific project assignments **Database Changes:** - New Project model with full relationships - Enhanced TimeEntry model with project_id and notes - Updated migration scripts with rollback support - Sample project creation for testing **User Interface:** - Project management templates (create, edit, list) - Enhanced time tracking with project dropdown - Project filtering in history page - Updated navigation for role-based access - Modern styling with hover effects and responsive design **API Enhancements:** - Project validation and access control - Updated arrive endpoint with project support - Enhanced export functions with project data - Role-based route protection **Migration Support:** - Comprehensive migration scripts (migrate_projects.py) - Updated main migration script (migrate_db.py) - Detailed migration documentation - Rollback functionality for safe deployment **Role-Based Access:** - Admins: Full project CRUD operations - Supervisors: Project creation and management - Team Leaders: View team hours with projects - Team Members: Select projects when tracking time 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from app import app, db
|
||||
import sqlite3
|
||||
import os
|
||||
from models import User, TimeEntry, WorkConfig, SystemSettings, Team, Role
|
||||
from models import User, TimeEntry, WorkConfig, SystemSettings, Team, Role, Project
|
||||
from werkzeug.security import generate_password_hash
|
||||
from datetime import datetime
|
||||
|
||||
@@ -152,6 +152,40 @@ def migrate_database():
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
|
||||
# Check if the project table exists
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='project'")
|
||||
if not cursor.fetchone():
|
||||
print("Creating project table...")
|
||||
cursor.execute("""
|
||||
CREATE TABLE project (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
code VARCHAR(20) NOT NULL UNIQUE,
|
||||
is_active BOOLEAN DEFAULT 1,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by_id INTEGER NOT NULL,
|
||||
team_id INTEGER,
|
||||
start_date DATE,
|
||||
end_date DATE,
|
||||
FOREIGN KEY (created_by_id) REFERENCES user (id),
|
||||
FOREIGN KEY (team_id) REFERENCES team (id)
|
||||
)
|
||||
""")
|
||||
|
||||
# Add project-related columns to time_entry table
|
||||
cursor.execute("PRAGMA table_info(time_entry)")
|
||||
time_entry_columns = [column[1] for column in cursor.fetchall()]
|
||||
|
||||
if 'project_id' not in time_entry_columns:
|
||||
print("Adding project_id column to time_entry...")
|
||||
cursor.execute("ALTER TABLE time_entry ADD COLUMN project_id INTEGER")
|
||||
|
||||
if 'notes' not in time_entry_columns:
|
||||
print("Adding notes column to time_entry...")
|
||||
cursor.execute("ALTER TABLE time_entry ADD COLUMN notes TEXT")
|
||||
|
||||
# Commit changes and close connection
|
||||
conn.commit()
|
||||
@@ -229,6 +263,44 @@ def migrate_database():
|
||||
print(f"Associated {len(orphan_configs)} existing work configs with admin user")
|
||||
print(f"Marked {len(existing_users)} existing users as verified")
|
||||
print(f"Updated {updated_count} users with default role and 2FA settings")
|
||||
|
||||
# Create sample projects if none exist
|
||||
existing_projects = Project.query.count()
|
||||
if existing_projects == 0 and admin:
|
||||
sample_projects = [
|
||||
{
|
||||
'name': 'General Administration',
|
||||
'code': 'ADMIN001',
|
||||
'description': 'General administrative tasks and meetings',
|
||||
'team_id': None,
|
||||
},
|
||||
{
|
||||
'name': 'Development Project',
|
||||
'code': 'DEV001',
|
||||
'description': 'Software development and maintenance tasks',
|
||||
'team_id': None,
|
||||
},
|
||||
{
|
||||
'name': 'Customer Support',
|
||||
'code': 'SUPPORT001',
|
||||
'description': 'Customer service and technical support activities',
|
||||
'team_id': None,
|
||||
}
|
||||
]
|
||||
|
||||
for proj_data in sample_projects:
|
||||
project = Project(
|
||||
name=proj_data['name'],
|
||||
code=proj_data['code'],
|
||||
description=proj_data['description'],
|
||||
team_id=proj_data['team_id'],
|
||||
created_by_id=admin.id,
|
||||
is_active=True
|
||||
)
|
||||
db.session.add(project)
|
||||
|
||||
db.session.commit()
|
||||
print(f"Created {len(sample_projects)} sample projects")
|
||||
|
||||
def init_system_settings():
|
||||
"""Initialize system settings with default values if they don't exist"""
|
||||
|
||||
Reference in New Issue
Block a user