Automated Action 2519513d99 Implement comprehensive due date CRUD operations and filtering
- Add enhanced due date filtering to get_todos function with support for "today", "this_week", "next_week"
- Add overdue filtering parameter with timezone-aware comparisons
- Add sorting by due_date with null values at end
- Add get_overdue_todos function for retrieving overdue todos
- Add get_todos_due_soon function for todos due within next N days (default 7)
- Add get_todos_by_date_range function for custom date range filtering
- Create comprehensive date utilities in app/utils/date_utils.py with timezone support
- Add project_id and tag_ids support to TodoCreate and TodoUpdate schemas
- Include efficient database indexing for due_date queries
- Use SQLAlchemy timezone-aware datetime filtering throughout
- Add proper overdue detection logic with timezone handling
2025-06-19 13:20:58 +00:00

70 lines
2.3 KiB
Python

from sqlalchemy import Column, Integer, String, Boolean, DateTime, Enum, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
import enum
from datetime import datetime, timezone
from typing import Optional
from app.db.base import Base
class Priority(str, enum.Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
class Todo(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(200), nullable=False)
description = Column(String(500), nullable=True)
completed = Column(Boolean, default=False)
priority = Column(Enum(Priority), default=Priority.MEDIUM)
project_id = Column(Integer, ForeignKey("projects.id"), nullable=True)
category_id = Column(Integer, ForeignKey("categories.id"), nullable=True)
parent_id = Column(Integer, ForeignKey("todos.id"), nullable=True)
due_date = Column(DateTime(timezone=True), nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# Relationship to project
project = relationship("Project", back_populates="todos")
# Relationship to category
category = relationship("Category", back_populates="todos")
# Self-referential relationship for subtasks
parent = relationship("Todo", remote_side=[id], back_populates="children")
children = relationship(
"Todo", back_populates="parent", cascade="all, delete-orphan"
)
@property
def is_subtask(self) -> bool:
"""Check if this todo is a subtask of another todo."""
return self.parent_id is not None
@property
def is_overdue(self) -> bool:
"""Check if this todo is overdue."""
if self.due_date is None or self.completed:
return False
return datetime.now(timezone.utc) > self.due_date
@property
def days_until_due(self) -> Optional[int]:
"""Calculate the number of days until the due date.
Returns:
int: Number of days until due (negative if overdue)
None: If no due date is set
"""
if self.due_date is None:
return None
now = datetime.now(timezone.utc)
delta = (self.due_date - now).days
return delta