Automated Action 7251fea2ba Add due date functionality to Todo model
- Add due_date field as nullable DateTime with timezone support
- Add is_overdue property to check if task is overdue
- Add days_until_due property for time calculations
- Create migration 007 to add due_date column with index
- Maintain backward compatibility with nullable due_date
2025-06-19 13:18:24 +00:00

69 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