Files
task_flow/app/domain/tasks.py

61 lines
1.4 KiB
Python

from __future__ import annotations
from datetime import datetime, UTC
from app.storage.models import StoredTask
class InvalidTransitionError(Exception):
"""Raised when task workflow transition is invalid."""
def start_task(task: StoredTask) -> StoredTask:
"""
Transition task from backlog → in_progress.
Rules:
- Idempotent: if already started, do not change started_at
- Cannot start a task that is already done
"""
# already done → invalid
if task.done_at is not None:
raise InvalidTransitionError("invalid_transaction")
# already started → idempotent (no change)
if task.started_at is not None:
return task
return StoredTask(
id=task.id,
title=task.title,
created_at=task.created_at,
started_at=datetime.now(UTC),
done_at=task.done_at,
)
def complete_task(task: StoredTask) -> StoredTask:
"""
Transition task from in_progress → done.
Rules:
- Allowed only if task is started
- Idempotent: if already done, do not change done_at
"""
# not started → invalid
if task.started_at is None:
raise InvalidTransitionError("invalid_transaction")
# already done → idempotent
if task.done_at is not None:
return task
return StoredTask(
id=task.id,
title=task.title,
created_at=task.created_at,
started_at=task.started_at,
done_at=datetime.now(UTC),
)