Files
leocrm/app/plugins/builtins/tasks/models.py
T

107 lines
4.5 KiB
Python
Raw Normal View History

"""Task model for the Tasks plugin."""
from __future__ import annotations
import uuid
from datetime import datetime
from typing import Any
from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, Text
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.dialects.postgresql import UUID as PGUUID
from sqlalchemy.orm import Mapped, mapped_column
from app.core.db import Base, TenantMixin
from app.models.owned_mixin import OwnedMixin
class Task(Base, TenantMixin, OwnedMixin):
"""Task entity — free activities (calls, notes, visits) linked to entities.
Supports polymorphic assignment (user/agent/group), polymorphic entity
links (contact/company/...), subtasks, dependencies, goals/milestones and
agent subtasks. Legacy ``contact_id`` and ``assigned_to`` columns are kept
for backward compatibility and mirrored into the polymorphic fields.
"""
__tablename__ = "tasks"
__table_args__ = (
Index("ix_tasks_tenant_deleted", "tenant_id", "deleted_at"),
Index("ix_tasks_tenant_status", "tenant_id", "status"),
Index("ix_tasks_tenant_assigned", "tenant_id", "assigned_to"),
Index("ix_tasks_tenant_due", "tenant_id", "due_date"),
Index("ix_tasks_contact", "contact_id"),
Index("ix_tasks_tenant_entity", "tenant_id", "entity_type", "entity_id"),
Index("ix_tasks_tenant_assignee", "tenant_id", "assignee_type", "assignee_id"),
Index("ix_tasks_tenant_parent", "tenant_id", "parent_task_id"),
Index("ix_tasks_tenant_type", "tenant_id", "task_type"),
)
id: Mapped[uuid.UUID] = mapped_column(
PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
)
title: Mapped[str] = mapped_column(String(255), nullable=False)
description: Mapped[str | None] = mapped_column(Text, nullable=True)
status: Mapped[str] = mapped_column(
String(20), nullable=False, default="open"
) # open, in_progress, review, blocked, done, cancelled
priority: Mapped[str] = mapped_column(
String(10), nullable=False, default="medium"
) # low, medium, high, urgent
due_date: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
assigned_to: Mapped[uuid.UUID | None] = mapped_column(
PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True
)
contact_id: Mapped[uuid.UUID | None] = mapped_column(
PGUUID(as_uuid=True), ForeignKey("contacts.id", ondelete="SET NULL"), nullable=True
)
created_by: Mapped[uuid.UUID | None] = mapped_column(
PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True
)
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
# ── F.14 Unified Task System ────────────────────────────────────────────
# Polymorphic assignee (user/agent/group)
assignee_type: Mapped[str] = mapped_column(
String(20), nullable=False, default="user"
) # user, agent, group
assignee_id: Mapped[uuid.UUID | None] = mapped_column(
PGUUID(as_uuid=True), nullable=True
)
# Polymorphic entity link (contact/company/...)
entity_type: Mapped[str | None] = mapped_column(String(80), nullable=True)
entity_id: Mapped[uuid.UUID | None] = mapped_column(PGUUID(as_uuid=True), nullable=True)
# Polymorphic creator (user/agent/workflow/system)
creator_type: Mapped[str] = mapped_column(
String(20), nullable=False, default="user"
) # user, agent, workflow, system
creator_id: Mapped[uuid.UUID | None] = mapped_column(
PGUUID(as_uuid=True), nullable=True
)
# Subtasks (self-reference)
parent_task_id: Mapped[uuid.UUID | None] = mapped_column(
PGUUID(as_uuid=True),
ForeignKey("tasks.id", ondelete="CASCADE"),
nullable=True,
)
# Task dependencies (blocked-by task IDs)
depends_on: Mapped[list[Any]] = mapped_column(JSONB, nullable=False, default=list)
# Task type
task_type: Mapped[str] = mapped_column(
String(30), nullable=False, default="todo"
) # todo, approval, follow_up, review, goal, milestone, agent_subtask
# Goal / Milestone support
success_criteria: Mapped[dict[str, Any] | None] = mapped_column(JSONB, nullable=True)
target_date: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
progress: Mapped[int] = mapped_column(Integer, nullable=False, default=0) # 0-100