Files
TimeTracker/app/models/time_entry_template.py
Dries Peeters b1973ca49a feat: Add Quick Wins feature set - activity tracking, templates, and user preferences
This commit introduces several high-impact features to improve user experience
and productivity:

New Features:
- Activity Logging: Comprehensive audit trail tracking user actions across the
  system with Activity model, including IP address and user agent tracking
- Time Entry Templates: Reusable templates for frequently logged activities with
  usage tracking and quick-start functionality
- Saved Filters: Save and reuse common search/filter combinations across
  different views (projects, tasks, reports)
- User Preferences: Enhanced user settings including email notifications,
  timezone, date/time formats, week start day, and theme preferences
- Excel Export: Generate formatted Excel exports for time entries and reports
  with styling and proper formatting
- Email Notifications: Complete email system for task assignments, overdue
  invoices, comments, and weekly summaries with HTML templates
- Scheduled Tasks: Background task scheduler for periodic operations

Models Added:
- Activity: Tracks all user actions with detailed context and metadata
- TimeEntryTemplate: Stores reusable time entry configurations
- SavedFilter: Manages user-saved filter configurations

Routes Added:
- user.py: User profile and settings management
- saved_filters.py: CRUD operations for saved filters
- time_entry_templates.py: Template management endpoints

UI Enhancements:
- Bulk actions widget component
- Keyboard shortcuts help modal with advanced shortcuts
- Save filter widget component
- Email notification templates
- User profile and settings pages
- Saved filters management interface
- Time entry templates interface

Database Changes:
- Migration 022: Creates activities and time_entry_templates tables
- Adds user preference columns (notifications, timezone, date/time formats)
- Proper indexes for query optimization

Backend Updates:
- Enhanced keyboard shortcuts system (commands.js, keyboard-shortcuts-advanced.js)
- Updated projects, reports, and tasks routes with activity logging
- Safe database commit utilities integration
- Event tracking for analytics

Dependencies:
- Added openpyxl for Excel generation
- Added Flask-Mail dependencies
- Updated requirements.txt

All new features include proper error handling, activity logging integration,
and maintain existing functionality while adding new capabilities.
2025-10-23 09:05:07 +02:00

89 lines
3.6 KiB
Python

from datetime import datetime
from app import db
class TimeEntryTemplate(db.Model):
"""Quick-start templates for common time entries
Allows users to create reusable templates for frequently
logged activities, saving time and ensuring consistency.
"""
__tablename__ = 'time_entry_templates'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)
name = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=True)
# Default values for time entries
project_id = db.Column(db.Integer, db.ForeignKey('projects.id'), nullable=True, index=True)
task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'), nullable=True, index=True)
default_duration_minutes = db.Column(db.Integer, nullable=True) # Optional default duration
default_notes = db.Column(db.Text, nullable=True)
tags = db.Column(db.String(500), nullable=True) # Comma-separated tags
billable = db.Column(db.Boolean, default=True, nullable=False)
# Metadata
usage_count = db.Column(db.Integer, default=0, nullable=False) # Track how often used
last_used_at = db.Column(db.DateTime, nullable=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
# Relationships
user = db.relationship('User', backref='time_entry_templates')
project = db.relationship('Project', backref='time_entry_templates')
task = db.relationship('Task', backref='time_entry_templates')
def __repr__(self):
return f'<TimeEntryTemplate {self.name}>'
@property
def default_duration(self):
"""Get duration in hours"""
if self.default_duration_minutes is None:
return None
return self.default_duration_minutes / 60.0
@default_duration.setter
def default_duration(self, hours):
"""Set duration from hours"""
if hours is None:
self.default_duration_minutes = None
else:
self.default_duration_minutes = int(hours * 60)
def record_usage(self):
"""Record that this template was used"""
self.usage_count += 1
self.last_used_at = datetime.utcnow()
def increment_usage(self):
"""Increment usage count and update last used timestamp"""
self.usage_count += 1
self.last_used_at = datetime.utcnow()
db.session.commit()
def to_dict(self):
"""Convert to dictionary for API responses"""
return {
'id': self.id,
'user_id': self.user_id,
'name': self.name,
'description': self.description,
'project_id': self.project_id,
'project_name': self.project.name if self.project else None,
'task_id': self.task_id,
'task_name': self.task.name if self.task else None,
'default_duration': self.default_duration, # In hours for API
'default_duration_minutes': self.default_duration_minutes, # Keep for compatibility
'default_notes': self.default_notes,
'tags': self.tags,
'billable': self.billable,
'usage_count': self.usage_count,
'last_used_at': self.last_used_at.isoformat() if self.last_used_at else None,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
}