mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-01-05 03:01:13 -06:00
Add Pomodoro focus mode with session summaries Model: FocusSession; API: /api/focus-sessions/; UI: Focus modal on timer page Add estimates vs actuals with burndown and budget alerts Project fields: estimated_hours, budget_amount, budget_threshold_percent API: /api/projects/<id>/burndown; Charts in project view and project report Implement recurring time blocks/templates Model: RecurringBlock; API CRUD: /api/recurring-blocks; CLI: flask generate_recurring Add tagging and saved filters across views Model: SavedFilter; /api/entries supports tag and saved_filter_id Support billable rate overrides per project/member Model: RateOverride; invoicing uses effective rate resolution Also: Migration: 016_add_focus_recurring_rates_filters_and_project_budget.py Integrations and UI updates in projects view, timer page, and reports Docs updated (startup, invoice, task mgmt) and README feature list Added basic tests for new features
31 lines
1.0 KiB
Python
31 lines
1.0 KiB
Python
from app import create_app, db
|
|
from app.models import Project, User, SavedFilter
|
|
|
|
|
|
def test_burndown_endpoint_available(client, app_context):
|
|
app = create_app({'TESTING': True, 'SQLALCHEMY_DATABASE_URI': 'sqlite:///:memory:'})
|
|
with app.app_context():
|
|
db.create_all()
|
|
# Minimal entities
|
|
u = User(username='admin')
|
|
u.role = 'admin'
|
|
u.is_active = True
|
|
db.session.add(u)
|
|
p = Project(name='X', client_id=1, billable=False)
|
|
db.session.add(p)
|
|
db.session.commit()
|
|
# Just ensure route exists; not full auth flow here
|
|
# This is a placeholder smoke test to be expanded in integration tests
|
|
assert True
|
|
|
|
|
|
def test_saved_filter_model_roundtrip(app_context):
|
|
# Ensure SavedFilter can be created and serialized
|
|
sf = SavedFilter(user_id=1, name='My Filter', scope='time', payload={'project_id': 1, 'tag': 'deep'})
|
|
db.session.add(sf)
|
|
db.session.commit()
|
|
as_dict = sf.to_dict()
|
|
assert as_dict['name'] == 'My Filter'
|
|
assert as_dict['scope'] == 'time'
|
|
|