infrasynth-backend-kit/infrasynth/workflows/models.py
2026-08-28 14:38:47 -05:00

141 lines
4.6 KiB
Python

from django.conf import settings
from django.db import models
from infrasynth.shared.enums import ApprovalStrategy
class Workflow(models.Model):
slug = models.SlugField(max_length=100, unique=True)
name = models.CharField(max_length=200)
description = models.TextField(blank=True)
is_active = models.BooleanField(default=True)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="+",
)
class Meta:
db_table = "workflows_definition"
def __str__(self):
return self.name
class WorkflowNode(models.Model):
class NodeType(models.TextChoices):
START = "start", "Start"
INTERMEDIATE = "intermediate", "Intermediate"
END = "end", "End"
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, related_name="nodes")
name = models.CharField(max_length=200)
node_type = models.CharField(max_length=20, choices=NodeType.choices, default=NodeType.INTERMEDIATE)
min_approvals = models.PositiveSmallIntegerField(default=1)
approval_strategy = models.CharField(
max_length=20,
choices=ApprovalStrategy.choices,
default=ApprovalStrategy.ALL,
)
position_x = models.IntegerField(default=0)
position_y = models.IntegerField(default=0)
class Meta:
db_table = "workflows_node"
unique_together = [("workflow", "name")]
def __str__(self):
return f"{self.workflow.slug}:{self.name}"
class Transition(models.Model):
from_node = models.ForeignKey(WorkflowNode, on_delete=models.CASCADE, related_name="outgoing_transitions")
to_node = models.ForeignKey(WorkflowNode, on_delete=models.CASCADE, related_name="incoming_transitions")
condition_slug = models.CharField(max_length=100, blank=True)
is_default = models.BooleanField(default=False)
class Meta:
db_table = "workflows_transition"
unique_together = [("from_node", "condition_slug")]
def __str__(self):
return f"{self.from_node} \u2192 {self.to_node}"
class WorkflowInstance(models.Model):
class Status(models.TextChoices):
IN_PROGRESS = "in_progress", "In Progress"
COMPLETED = "completed", "Completed"
CANCELLED = "cancelled", "Cancelled"
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, related_name="instances")
current_node = models.ForeignKey(
WorkflowNode,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="+",
)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="+",
)
status = models.CharField(max_length=20, choices=Status.choices, default=Status.IN_PROGRESS)
started_at = models.DateTimeField(auto_now_add=True)
completed_at = models.DateTimeField(null=True, blank=True)
metadata = models.JSONField(default=dict)
class Meta:
db_table = "workflows_instance"
def __str__(self):
return f"{self.workflow.slug}#{self.pk}"
class NodeAssignment(models.Model):
instance = models.ForeignKey(WorkflowInstance, on_delete=models.CASCADE, related_name="assignments")
node = models.ForeignKey(WorkflowNode, on_delete=models.CASCADE, related_name="assignments")
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="+")
visit_number = models.IntegerField(default=1)
is_required = models.BooleanField(default=True)
has_processed = models.BooleanField(default=False)
decision = models.CharField(max_length=50, null=True, blank=True)
comments = models.TextField(blank=True)
submitted_data = models.JSONField(default=dict, null=True, blank=True)
processed_at = models.DateTimeField(null=True, blank=True)
class Meta:
db_table = "workflows_node_assignment"
def __str__(self):
return f"{self.instance}#{self.node.name}@{self.user}"
class WorkflowObserver(models.Model):
instance = models.ForeignKey(WorkflowInstance, on_delete=models.CASCADE, related_name="observers")
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="+")
class Meta:
db_table = "workflows_observer"
unique_together = [("instance", "user")]
def __str__(self):
return f"{self.instance}\u2192{self.user}"
class WorkflowAwareModel(models.Model):
workflow_instance = models.ForeignKey(
WorkflowInstance,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="+",
)
class Meta:
abstract = True