mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-01-06 03:30:25 -06:00
Store user avatars in persistent /data volume instead of application directory to ensure profile pictures survive container rebuilds and version updates. Changes: - Update avatar upload folder from app/static/uploads/avatars to /data/uploads/avatars using existing app_data volume mount - Modify get_avatar_upload_folder() in auth routes to use persistent location with UPLOAD_FOLDER config - Update User.get_avatar_path() to reference new storage location - Add migration script to safely move existing avatars to new location - Preserve backward compatibility - no database changes required Benefits: - Profile pictures now persist between Docker image updates - Consistent with company logo storage pattern (/data/uploads) - Better user experience - avatars not lost during upgrades - Production-ready data/code separation - All persistent uploads consolidated in app_data volume Migration: For existing installations with user avatars, run: docker-compose run --rm app python /app/docker/migrate-avatar-storage.py New installations work automatically with no action required. Documentation: - docs/AVATAR_STORAGE_MIGRATION.md - Full migration guide - docs/AVATAR_PERSISTENCE_SUMMARY.md - Quick reference - docs/TEST_AVATAR_PERSISTENCE.md - Testing guide - AVATAR_PERSISTENCE_CHANGELOG.md - Detailed changelog Files modified: - app/routes/auth.py - app/models/user.py Files added: - docker/migrate-avatar-storage.py - docs/AVATAR_STORAGE_MIGRATION.md - docs/AVATAR_PERSISTENCE_SUMMARY.md - docs/TEST_AVATAR_PERSISTENCE.md - AVATAR_PERSISTENCE_CHANGELOG.md Tested: ✓ No linter errors, backward compatible, volume mount verified
7.1 KiB
7.1 KiB
Extra Goods Feature
Overview
The Extra Goods feature allows you to add physical products, services, materials, licenses, and other billable items to both projects and invoices. This extends the time-tracking functionality to support full product and service billing.
Features
Core Functionality
- Add extra goods to projects: Track products and services associated with a project
- Add extra goods to invoices: Include products and services directly on invoices
- Multiple categories: Organize goods as products, services, materials, licenses, or other
- Flexible pricing: Set quantity and unit price with automatic total calculation
- SKU/Product codes: Track items with unique identifiers
- Billable/Non-billable: Mark items as billable or non-billable
- Multi-currency support: Each good can have its own currency code
Integration
- Invoice generation: Automatically include project extra goods when generating invoices from time entries
- Cost tracking: Extra goods work alongside project costs for comprehensive billing
- Reporting: Goods are included in project totals and invoice calculations
Data Model
ExtraGood Model
class ExtraGood(db.Model):
id = db.Column(db.Integer, primary_key=True)
# Links (can be associated with project, invoice, or both)
project_id = db.Column(db.Integer, nullable=True)
invoice_id = db.Column(db.Integer, nullable=True)
# Good details
name = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=True)
category = db.Column(db.String(50), nullable=False)
# Pricing
quantity = db.Column(db.Numeric(10, 2), nullable=False, default=1)
unit_price = db.Column(db.Numeric(10, 2), nullable=False)
total_amount = db.Column(db.Numeric(10, 2), nullable=False)
currency_code = db.Column(db.String(3), nullable=False, default='EUR')
# Billing
billable = db.Column(db.Boolean, default=True, nullable=False)
sku = db.Column(db.String(100), nullable=True)
# Metadata
created_by = db.Column(db.Integer, nullable=False)
created_at = db.Column(db.DateTime, nullable=False)
updated_at = db.Column(db.DateTime, nullable=False)
Categories
- product: Physical or digital products
- service: Additional services beyond time-tracked work
- material: Materials and supplies used in the project
- license: Software licenses, permits, or other licenses
- other: Any other type of good or service
Usage
Adding Extra Goods to a Project
- Navigate to the project view page
- Click "Add Extra Good" or navigate to
/projects/<id>/goods/add - Fill in the form:
- Name (required)
- Description (optional)
- Category (required)
- SKU/Product Code (optional)
- Quantity (required, default: 1)
- Unit Price (required)
- Currency (default: EUR)
- Billable checkbox (default: checked)
- Click "Add Good"
Adding Extra Goods to an Invoice
Method 1: Direct Addition
- Navigate to invoice edit page
- In the "Extra Goods" section, click "Add Good"
- Fill in the good details inline:
- Name
- Description
- Category
- Quantity
- Unit Price
- SKU (optional)
- Click "Save Changes"
Method 2: Generate from Project
- Navigate to invoice edit page
- Click "Generate from Time/Costs/Goods"
- Select extra goods from the project
- Click "Add Selected to Invoice"
- Project goods will be copied to the invoice
Managing Extra Goods
Editing
- For project goods: Navigate to
/projects/<id>/goods/<good_id>/edit - For invoice goods: Edit directly in the invoice edit form
Deleting
- Project goods can only be deleted if not yet added to an invoice
- Invoice goods are deleted when you remove them from the invoice edit form
Viewing
- Project goods list:
/projects/<id>/goods - Invoice goods: Displayed on invoice view and edit pages
API Endpoints
Project Extra Goods
GET /projects/<id>/goods- List all goods for a projectPOST /projects/<id>/goods/add- Add a new good to a projectGET /projects/<id>/goods/<good_id>/edit- Edit formPOST /projects/<id>/goods/<good_id>/edit- Update a goodPOST /projects/<id>/goods/<good_id>/delete- Delete a goodGET /api/projects/<id>/goods- JSON API for project goods
Invoice Extra Goods
Extra goods for invoices are managed through the invoice edit form:
GET /invoices/<id>/edit- Shows invoice with extra goodsPOST /invoices/<id>/edit- Updates invoice including extra goods
Database Migration
The extra goods feature requires database migration 021_add_extra_goods_table.py.
To apply the migration:
# Using Alembic
alembic upgrade head
# Or using Flask-Migrate
flask db upgrade
Calculations
Invoice Totals
When calculating invoice totals, extra goods are included:
items_total = sum(item.total_amount for item in invoice.items)
goods_total = sum(good.total_amount for good in invoice.extra_goods)
subtotal = items_total + goods_total
tax_amount = subtotal * (tax_rate / 100)
total_amount = subtotal + tax_amount
Project Value
Extra goods contribute to the total project value:
total_value = (billable_hours * hourly_rate) + billable_costs + billable_extra_goods
Best Practices
- Use SKU codes: For recurring products, use SKU codes for easy identification
- Categorize correctly: Choose the appropriate category for easier reporting
- Set billable flag: Mark non-billable items appropriately to exclude from client billing
- Link to projects first: Add goods to projects, then include them in invoices for better tracking
- Update totals: The system automatically updates totals, but verify before sending invoices
Permissions
- Admin users: Full access to create, edit, and delete extra goods
- Regular users: Can add goods they created; cannot delete goods added to invoices
Reporting and Analytics
Extra goods data is available for:
- Project cost tracking and budgeting
- Invoice generation and billing
- Category-based analysis
- Client billing summaries
Troubleshooting
Common Issues
Good won't delete from project
- Check if the good has been added to an invoice
- Goods added to invoices cannot be deleted from projects
Total amount incorrect
- The system auto-calculates
total_amount = quantity * unit_price - If you need to override, modify quantity or unit price
Good not appearing on invoice
- Ensure the good is marked as billable
- Check that
invoice_idis not already set to another invoice - Verify the good belongs to the project linked to the invoice
Future Enhancements
Potential future improvements:
- Inventory tracking integration
- Automated pricing from product catalog
- Volume discounts
- Tax rules per product category
- Multi-unit conversions
Support
For issues or questions about the extra goods feature:
- Check the application logs for error details
- Verify database migration is applied
- Review the model tests in
tests/test_extra_good_model.py - Check the route implementations in
app/routes/invoices.pyandapp/routes/projects.py