12 KiB
Project Costs Implementation Summary
Overview
Successfully implemented a comprehensive project costs tracking feature that allows tracking expenses beyond hourly work, including travel, materials, services, equipment, and other project-related costs.
What Was Implemented
1. Database Layer
New Model: ProjectCost (app/models/project_cost.py)
- Complete CRUD model for tracking project expenses
- Support for multiple cost categories
- Billable/non-billable tracking
- Invoice integration with invoiced status tracking
- Currency support (EUR, USD, GBP, CHF)
- Receipt path field for future file upload support
Model Relationships:
- Updated
Projectmodel withcostsrelationship - Updated
Usermodel withproject_costsrelationship - Added properties to
Project:total_costs,total_billable_costs,total_project_value
2. Backend Routes
New Routes in app/routes/projects.py:
GET /projects/<id>/costs- List all costs with filteringGET /projects/<id>/costs/add- Add cost formPOST /projects/<id>/costs/add- Create new costGET /projects/<id>/costs/<cost_id>/edit- Edit cost formPOST /projects/<id>/costs/<cost_id>/edit- Update costPOST /projects/<id>/costs/<cost_id>/delete- Delete costGET /api/projects/<id>/costs- JSON API for costs
Updated Invoice Generation (app/routes/invoices.py):
- Modified
generate_from_time()to include project costs - Automatic marking of costs as invoiced
- Prevention of double-billing invoiced costs
- Support for mixed time entries and costs in invoices
Updated Reports (app/routes/reports.py):
- Project reports now include cost calculations
- Summary totals include costs
- Category breakdown for costs
3. Frontend Templates
New Templates:
templates/projects/add_cost.html- Form for adding coststemplates/projects/edit_cost.html- Form for editing costs
Updated Templates:
templates/projects/view.html- Added costs section with:- Cost summary cards (Total Costs, Billable Costs, Total Project Value)
- Recent costs table (latest 5)
- Add/Edit/Delete actions
- Delete confirmation modal
- Updated statistics to show costs
4. Database Migrations
Three Migration Options Provided:
-
Alembic Migration (
migrations/versions/018_add_project_costs_table.py)- Standard Python-based migration
- Revision: 018, follows existing migration chain
- Includes upgrade and downgrade functions
- Full index and foreign key creation
- Safe table existence checks
-
SQL Migration (
migrations/add_project_costs.sql)- Direct SQL script for PostgreSQL
- Can be run manually
- Includes table comments
-
Python Script (
docker/migrate-add-project-costs.py)- Standalone Python script for Docker environments
- Includes existence checks
- Detailed console output
5. Documentation
PROJECT_COSTS_FEATURE.md- Complete feature documentationPROJECT_COSTS_IMPLEMENTATION_SUMMARY.md- This file
Key Features
Cost Management
✅ Add costs with description, category, amount, and date ✅ Edit costs (permission-based) ✅ Delete costs (only uninvoiced ones) ✅ Six cost categories: Travel, Materials, Services, Equipment, Software, Other ✅ Billable/non-billable status ✅ Multi-currency support (EUR, USD, GBP, CHF) ✅ Optional notes field
Project Integration
✅ Cost summary on project page ✅ Recent costs display ✅ Total project value calculation (hours + costs) ✅ Updated project statistics ✅ Budget tracking maintains separation between hour-based and cost-based
Invoice Integration
✅ Include costs when generating invoices ✅ Automatic cost-to-invoice-item conversion ✅ Invoiced status tracking ✅ Prevention of double-billing ✅ Uninvoiced costs filter
Reporting
✅ Project reports include cost data ✅ Cost breakdown by category ✅ Total project value in reports ✅ Date range filtering for costs
Permissions & Security
✅ Users can add costs to projects they work on ✅ Only cost creators and admins can edit costs ✅ Only cost creators and admins can delete costs ✅ Invoiced costs cannot be deleted ✅ Proper foreign key constraints with cascading
Files Created
Models
app/models/project_cost.py- ProjectCost model
Routes
- Updated
app/routes/projects.py- Cost CRUD routes - Updated
app/routes/invoices.py- Invoice generation with costs - Updated
app/routes/reports.py- Reports with cost calculations
Templates
templates/projects/add_cost.htmltemplates/projects/edit_cost.html- Updated
templates/projects/view.html
Migrations
migrations/versions/018_add_project_costs_table.py- Alembic migration (Revision 018)migrations/add_project_costs.sql- SQL migrationdocker/migrate-add-project-costs.py- Python migration scriptMIGRATION_INSTRUCTIONS.md- Detailed migration instructions
Documentation
PROJECT_COSTS_FEATURE.md- Feature documentationPROJECT_COSTS_IMPLEMENTATION_SUMMARY.md- Implementation summary
Files Modified
Models
app/models/__init__.py- Added ProjectCost importapp/models/project.py- Added costs relationship and propertiesapp/models/user.py- Added project_costs relationship
Routes
app/routes/projects.py- Added cost routesapp/routes/invoices.py- Updated invoice generationapp/routes/reports.py- Updated reports with costs
Templates
templates/projects/view.html- Added costs section
Installation Steps
1. Run Database Migration
Choose one of the following methods:
Option A: Using Alembic (recommended)
alembic upgrade head
Option B: Using SQL directly
psql -U your_user -d timetracker -f migrations/add_project_costs.sql
Option C: Using Python script (Docker)
python docker/migrate-add-project-costs.py
2. Restart Application
# If using Docker
docker-compose restart
# If running directly
# Stop and restart your application server
3. Verify Installation
- Log in to the application
- Navigate to any project
- You should see a new "Project Costs & Expenses" section
- Try adding a cost to verify functionality
Usage Example
Adding a Cost
- Go to a project page
- Click "Add Cost" in the Project Costs & Expenses section
- Fill in:
- Description: "Travel to client site"
- Category: Travel
- Amount: 150.00
- Date: 2024-01-15
- Billable: Yes
- Click "Add Cost"
Including Costs in Invoice
- Create or edit an invoice for the project
- Click "Generate from Time Entries"
- Select time entries AND costs to include
- Click "Generate Items"
- Review the invoice with both hours and costs as line items
Technical Details
Database Schema
CREATE TABLE project_costs (
id SERIAL PRIMARY KEY,
project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
description VARCHAR(500) NOT NULL,
category VARCHAR(50) NOT NULL,
amount NUMERIC(10, 2) NOT NULL,
currency_code VARCHAR(3) NOT NULL DEFAULT 'EUR',
billable BOOLEAN NOT NULL DEFAULT TRUE,
invoiced BOOLEAN NOT NULL DEFAULT FALSE,
invoice_id INTEGER REFERENCES invoices(id) ON DELETE SET NULL,
cost_date DATE NOT NULL,
notes TEXT,
receipt_path VARCHAR(500),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
Key Methods
ProjectCost Model:
get_project_costs(project_id, start_date, end_date, user_id, billable_only)- Query costsget_total_costs(project_id, ...)- Calculate total costsget_uninvoiced_costs(project_id)- Get billable uninvoiced costsget_costs_by_category(project_id, ...)- Group costs by categorymark_as_invoiced(invoice_id)- Mark cost as invoicedto_dict()- Convert to dictionary for API
Project Model:
total_costs- Property for total project coststotal_billable_costs- Property for billable coststotal_project_value- Property for total value (hours + costs)
API Endpoints
Get Project Costs (JSON)
GET /api/projects/<project_id>/costs?start_date=2024-01-01&end_date=2024-12-31
Response:
{
"costs": [...],
"total_costs": 1500.00,
"billable_costs": 1200.00,
"count": 5
}
Design Considerations
Light Look and Feel
Following the TimeTracker design guidelines:
- Clean, modern interface with subtle shadows
- Light color palette with blue accents
- Clear visual hierarchy
- Responsive design for mobile
- Intuitive icons (Font Awesome)
- Consistent with existing UI patterns
Data Integrity
- Foreign key constraints prevent orphaned records
- CASCADE deletion when parent project/user deleted
- SET NULL when invoice deleted (preserve cost history)
- Invoiced costs cannot be deleted
- Transaction-based operations with rollback
Performance
- Indexed columns: project_id, user_id, cost_date, invoice_id
- Efficient queries using SQLAlchemy ORM
- Lazy loading for relationships
- Optimized aggregation queries
Testing Checklist
- Create a cost on a project
- Edit a cost (as creator)
- Delete a cost (uninvoiced)
- Verify costs appear in project statistics
- Include costs in invoice generation
- Verify costs appear in project reports
- Verify invoiced costs cannot be deleted
- Test permission restrictions (non-creator, non-admin)
- Verify total project value calculation
- Test date filtering on costs
Future Enhancements
Potential improvements for future versions:
- Receipt Uploads - File upload for receipts with preview
- Cost Approval Workflow - Multi-level approval for costs
- Cost Budgets - Separate budget tracking for costs
- Advanced Analytics - Charts and visualizations for cost trends
- Recurring Costs - Template for recurring project costs
- Currency Conversion - Automatic conversion with exchange rates
- Cost Export - CSV/PDF export of costs
- Cost Categories Management - Admin panel to manage categories
- Cost Alerts - Notifications for cost thresholds
- Cost Comparison - Compare costs across projects
Support & Troubleshooting
Common Issues
Issue: Migration fails with "table already exists"
- Solution: The table already exists from a previous migration. Skip the migration or check if it was partially applied.
Issue: Costs don't appear in project view
- Solution: Ensure you've restarted the application after applying migrations. Clear browser cache if needed.
Issue: Cannot delete a cost
- Solution: Check if the cost has been invoiced. Invoiced costs cannot be deleted to maintain invoice integrity.
Issue: Costs not showing in reports
- Solution: Verify the date range filter includes the cost dates. Check that the project filter includes the project with costs.
Logs
Check application logs for detailed error messages:
logs/timetracker.log- Application logslogs/timetracker_startup.log- Startup logs
Compatibility
- Database: PostgreSQL 9.6+
- Python: 3.7+
- Flask: Compatible with current TimeTracker version
- SQLAlchemy: Compatible with current TimeTracker version
- Browsers: Modern browsers (Chrome, Firefox, Safari, Edge)
Security Considerations
- All routes require authentication (
@login_required) - Permission checks for edit/delete operations
- SQL injection prevention via SQLAlchemy ORM
- Input validation on all forms
- CSRF protection via Flask forms
- XSS prevention via Jinja2 autoescaping
Performance Impact
- Minimal impact on existing features
- Additional queries only on project/invoice/report pages
- Indexed columns for optimal query performance
- Lazy loading prevents unnecessary data fetching
- Caching opportunities for future optimization
Conclusion
The Project Costs feature is fully implemented and ready for use. It seamlessly integrates with existing TimeTracker functionality while maintaining the clean, light design aesthetic. The feature adds significant value by enabling complete project cost tracking beyond just hourly work.
All database migrations, backend logic, frontend templates, and documentation have been completed. The implementation follows best practices for security, performance, and maintainability.
Questions or Issues?
For any questions about the implementation or issues during deployment, refer to:
PROJECT_COSTS_FEATURE.mdfor user-facing documentation- Code comments in model and route files
- Migration scripts for database details
- This summary for technical overview