fix error in gitignore
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.core.errors import ApiError
|
||||
from apps.processing.models import StepExecution
|
||||
|
||||
|
||||
class ProcessingService:
|
||||
"""Step execution state machine. Transitions are validated server-side."""
|
||||
|
||||
_STARTABLE = {"pending", "ready", "rework_required"}
|
||||
_PAUSABLE = {"in_progress"}
|
||||
_RESUMABLE = {"paused"}
|
||||
_COMPLETABLE = {"in_progress"}
|
||||
_REJECTABLE = {"in_progress", "waiting"}
|
||||
|
||||
@transaction.atomic
|
||||
def start(self, execution, user) -> StepExecution:
|
||||
execution = self._locked(execution)
|
||||
if execution.state not in self._STARTABLE:
|
||||
raise ApiError("INVALID_STEP_TRANSITION", f"Cannot start from state '{execution.state}'.")
|
||||
execution.state = StepExecution.State.IN_PROGRESS
|
||||
execution.started_at = timezone.now()
|
||||
execution.assigned_to = user
|
||||
execution.save()
|
||||
return execution
|
||||
|
||||
@transaction.atomic
|
||||
def pause(self, execution) -> StepExecution:
|
||||
execution = self._locked(execution)
|
||||
if execution.state not in self._PAUSABLE:
|
||||
raise ApiError("INVALID_STEP_TRANSITION", f"Cannot pause from state '{execution.state}'.")
|
||||
execution.state = StepExecution.State.PAUSED
|
||||
execution.save()
|
||||
return execution
|
||||
|
||||
@transaction.atomic
|
||||
def resume(self, execution) -> StepExecution:
|
||||
execution = self._locked(execution)
|
||||
if execution.state not in self._RESUMABLE:
|
||||
raise ApiError("INVALID_STEP_TRANSITION", f"Cannot resume from state '{execution.state}'.")
|
||||
execution.state = StepExecution.State.IN_PROGRESS
|
||||
execution.save()
|
||||
return execution
|
||||
|
||||
@transaction.atomic
|
||||
def complete(self, execution, measurements=None, notes="") -> StepExecution:
|
||||
execution = self._locked(execution)
|
||||
if execution.state not in self._COMPLETABLE:
|
||||
raise ApiError("INVALID_STEP_TRANSITION", f"Cannot complete from state '{execution.state}'.")
|
||||
execution.state = StepExecution.State.COMPLETED
|
||||
execution.completed_at = timezone.now()
|
||||
if measurements is not None:
|
||||
execution.measurements = measurements
|
||||
if notes:
|
||||
execution.notes = notes
|
||||
execution.save()
|
||||
return execution
|
||||
|
||||
@transaction.atomic
|
||||
def reject(self, execution, notes="") -> StepExecution:
|
||||
execution = self._locked(execution)
|
||||
if execution.state not in self._REJECTABLE:
|
||||
raise ApiError("INVALID_STEP_TRANSITION", f"Cannot reject from state '{execution.state}'.")
|
||||
execution.state = StepExecution.State.REJECTED
|
||||
execution.notes = notes or execution.notes
|
||||
execution.save()
|
||||
return execution
|
||||
|
||||
@transaction.atomic
|
||||
def rework(self, execution, target_step) -> StepExecution:
|
||||
"""Create a new execution on `target_step`; preserve history via parent link."""
|
||||
execution = self._locked(execution)
|
||||
if execution.state != StepExecution.State.COMPLETED:
|
||||
raise ApiError("INVALID_STEP_TRANSITION", "Only a completed step can trigger rework.")
|
||||
execution.state = StepExecution.State.REWORK_REQUIRED
|
||||
execution.save()
|
||||
latest = (
|
||||
StepExecution.objects.filter(order=execution.order, step=target_step)
|
||||
.order_by("-attempt")
|
||||
.first()
|
||||
)
|
||||
attempt = (latest.attempt if latest else 0) + 1
|
||||
return StepExecution.objects.create(
|
||||
order=execution.order,
|
||||
step=target_step,
|
||||
state=StepExecution.State.READY,
|
||||
attempt=attempt,
|
||||
parent=execution,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _locked(execution) -> StepExecution:
|
||||
return StepExecution.objects.select_for_update().get(pk=execution.pk)
|
||||
Reference in New Issue
Block a user