Asunto en internos funcionando

This commit is contained in:
2026-03-24 08:01:57 -06:00
parent daf3a524c7
commit 08816ab73a
7 changed files with 660 additions and 240 deletions

View File

@@ -8,6 +8,7 @@ from sqlalchemy import String, ForeignKey, Text, Table, Column
from sqlalchemy.orm import Mapped, mapped_column, relationship
from typing import Optional, List
from datetime import datetime
import enum
import uuid
from app.core.database import Base, GUID
@@ -16,6 +17,13 @@ from sqlalchemy import Enum as SAEnum
from sqlalchemy.dialects.postgresql import ENUM as PG_ENUM
class IssueStatus(str, enum.Enum):
OPEN = "OPEN"
IN_PROGRESS = "IN_PROGRESS"
RESOLVED = "RESOLVED"
CLOSED = "CLOSED"
# Tabla de relación N:M entre TicketIssue y User (usuarios etiquetados)
ticket_issue_tagged_users = Table(
"ticket_issue_tagged_users",
@@ -38,37 +46,23 @@ ticket_issue_tagged_users = Table(
class TicketIssue(Base):
"""
Asunto de escalación de un ticket.
Solo puede crearlo:
- El usuario que creó el ticket (created_by del Ticket)
- El CLIENT_ADMIN del mismo tenant
"""
__tablename__ = "ticket_issues"
# Multi-tenancy — siempre filtrar por esto
tenant_id: Mapped[uuid.UUID] = mapped_column(
GUID(),
ForeignKey("tenants.id", ondelete="CASCADE"),
nullable=False,
)
# Relación con el ticket padre
ticket_id: Mapped[uuid.UUID] = mapped_column(
GUID(),
ForeignKey("tickets.id", ondelete="CASCADE"),
nullable=False,
)
# Quién lo creó
created_by: Mapped[uuid.UUID] = mapped_column(
GUID(),
ForeignKey("users.id"),
nullable=False,
)
# Contenido
content: Mapped[str] = mapped_column(Text, nullable=False)
priority: Mapped[TicketPriority] = mapped_column(
@@ -80,23 +74,24 @@ class TicketIssue(Base):
nullable=False,
)
# Adjunto opcional (reutiliza file_handler igual que TicketAttachment)
status: Mapped[IssueStatus] = mapped_column(
SAEnum(IssueStatus, name="issue_status_enum", native_enum=False).with_variant(
PG_ENUM(IssueStatus, name="issue_status_enum", create_type=True),
"postgresql",
),
default=IssueStatus.OPEN,
nullable=False,
)
attachment_path: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
attachment_filename: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
attachment_mime_type: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
# Relationships
ticket: Mapped["Ticket"] = relationship("Ticket", back_populates="issues")
created_by_user: Mapped["User"] = relationship(
"User",
foreign_keys=[created_by],
)
created_by_user: Mapped["User"] = relationship("User", foreign_keys=[created_by])
tagged_users: Mapped[List["User"]] = relationship(
"User",
secondary=ticket_issue_tagged_users,
"User", secondary=ticket_issue_tagged_users,
)
def __repr__(self) -> str:
return f"<TicketIssue(id={self.id}, ticket={self.ticket_id}, priority={self.priority})>"
return f"<TicketIssue(id={self.id}, ticket={self.ticket_id}, status={self.status})>"