mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
from dataclasses import dataclass
|
|
from datetime import datetime, timezone
|
|
from enum import Enum
|
|
from typing import Optional
|
|
from uuid import UUID, uuid4
|
|
|
|
from domain.tasks.subtasks import SubTaskStatus
|
|
|
|
|
|
class TaskStatus(str, Enum):
|
|
WAITING = "waiting"
|
|
IN_PROGRESS = "in progress"
|
|
COMPLETE = "complete"
|
|
FAILED = "failed"
|
|
|
|
|
|
class Source(str, Enum):
|
|
PORTFOLIO = "portfolio_id"
|
|
HUBSPOT_DEAL = "hubspot_deal_id"
|
|
|
|
|
|
@dataclass
|
|
class Task:
|
|
id: UUID
|
|
task_source: str
|
|
status: TaskStatus = TaskStatus.WAITING
|
|
service: Optional[str] = None
|
|
source: Optional[Source] = None
|
|
source_id: Optional[str] = None
|
|
job_started: Optional[datetime] = None
|
|
job_completed: Optional[datetime] = None
|
|
|
|
@classmethod
|
|
def create(
|
|
cls,
|
|
*,
|
|
task_source: str,
|
|
service: Optional[str] = None,
|
|
source: Optional[Source] = None,
|
|
source_id: Optional[str] = None,
|
|
) -> "Task":
|
|
if not task_source.strip():
|
|
raise ValueError("task_source must be non-empty")
|
|
return cls(
|
|
id=uuid4(),
|
|
task_source=task_source,
|
|
service=service,
|
|
source=source,
|
|
source_id=source_id,
|
|
status=TaskStatus.WAITING,
|
|
job_started=datetime.now(timezone.utc),
|
|
)
|
|
|
|
def start(self) -> None:
|
|
if self.status not in (TaskStatus.WAITING, TaskStatus.IN_PROGRESS):
|
|
raise ValueError(f"cannot start task in status {self.status}")
|
|
if self.job_started is None:
|
|
self.job_started = datetime.now(timezone.utc)
|
|
self.status = TaskStatus.IN_PROGRESS
|
|
|
|
def complete(self) -> None:
|
|
self.status = TaskStatus.COMPLETE
|
|
self.job_completed = datetime.now(timezone.utc)
|
|
|
|
def fail(self) -> None:
|
|
self.status = TaskStatus.FAILED
|
|
self.job_completed = datetime.now(timezone.utc)
|
|
|
|
def recalculate_from_subtasks(self, statuses: list[SubTaskStatus]) -> None:
|
|
"""Recompute Task.status from its SubTasks' statuses.
|
|
|
|
Rule (preserved from legacy _update_task_progress):
|
|
- any FAILED → FAILED
|
|
- all COMPLETE → COMPLETE
|
|
- any IN_PROGRESS → IN_PROGRESS
|
|
- otherwise → WAITING
|
|
|
|
Empty list is a no-op (newly-created task with no subtasks).
|
|
"""
|
|
if not statuses:
|
|
return
|
|
now = datetime.now(timezone.utc)
|
|
if SubTaskStatus.FAILED in statuses:
|
|
self.status = TaskStatus.FAILED
|
|
self.job_completed = now
|
|
elif all(s is SubTaskStatus.COMPLETE for s in statuses):
|
|
self.status = TaskStatus.COMPLETE
|
|
self.job_completed = now
|
|
elif SubTaskStatus.IN_PROGRESS in statuses:
|
|
self.status = TaskStatus.IN_PROGRESS
|
|
self.job_completed = None
|
|
else:
|
|
self.status = TaskStatus.WAITING
|
|
self.job_completed = None
|