State-Based Workflow Reference

API, schema and command reference for the state-based (workflow_kind='state_based') workflow engine. Part of the Workflow series. Entry point: State-Based Workflows.

Table of Contents

  1. Choices
  2. Model Field Reference
  3. Service Reference
  4. Validation Rules S1–S20
  5. design_data JSON Schema
  6. URLs and Views
  7. WorkflowMixin Reference
  8. History Context
  9. Management Commands
  10. Settings and Migrations
  11. Error Types
  12. See Also
  13. A Note on Testing

Choices

All defined in enezaworkflowengine/models/choices.py.

WorkflowExecutionType — choices.py:5

Value Label Meaning in a state-based graph
start Start Exactly one entry node (S2).
approval Approval Approval-engine only; invalid in a state graph (S1).
condition condition Approval-engine only; invalid in a state graph (S1).
end End Terminal sink; at least one required (S3).
state State A user-moveable state carrying a state_code and assignees.
fork Fork Splits a branch into parallel children.
join Join Waits for a fork scope and auto-continues.

WorkflowKind — choices.py:14

Value Label Engine
approval Approval workflow_template_validator + step_dispatcher (default).
state_based State Based state_template_validator + services/state_workflow.py.

StateLifecycle — choices.py:18

Used by both WorkflowInstance.state_status and WorkflowBranch.status.

Value Label
active Active
completed Completed
cancelled Cancelled

WorkflowActionType — choices.py:23

creation, assignment, approval, precondition, notification, status_change, resubmission, completion. State-based history uses creation, assignment, status_change, completion and notification.

Backward-compatibility alias: WorflowActionType = WorkflowActionType (choices.py:34).

Model Field Reference

WorkflowTemplate — models/workflowtemplate.py:15

Field Type Default Verbose name Notes
name CharField(255) — Workflow Template Name
description TextField — Workflow Template Description blank=True.
workflowname CharField(100), get_getworkflow_names_choices().choices — Workflow Name Registry key for state choices.
workflow_kind CharField(20), WorkflowKind.choices approval Workflow Kind Selects engine + validator.
state_choices_path CharField(255) '' State Choices Path blank=True; per-template override.
is_active BooleanField False Is Active Only one active version per workflowname.
workflowmodule CharField(100), Modules.choices GL (Modules.GENERAL_LEDGER) Workflow Module
design_data JSONField {} Designer Data Layout snapshot.
version PositiveIntegerField 1 Version Unique with workflowname.
is_latest BooleanField, indexed True Is Latest Version Only one latest per workflowname.
cloned_from self-FK, SET_NULL None Cloned From related_name='branches'.

StepTemplate — workflowtemplate.py:83

Field Type Default Verbose name Notes
workflowtemplate FK, PROTECT — Workflow Template related_name='steps'.
order PositiveIntegerField — Order Model ordering = ['order'].
name CharField(255) — Step Name
step_type CharField(50), WorkflowExecutionType.choices None Step Type null=True, blank=True.
condition_expression FK SavedQuery, PROTECT None Condition Expression Approval/condition nodes; state transition guards live on StateTransition.
if_true / if_false self-FK, PROTECT None If True/False Go To Approval-engine only.
next_step self-FK, PROTECT None Next Step Approval-engine only.
approval_threshold CharField(50), ApprovalThreshold.choices None Approval Threshold Approval steps and state stages; blank state value means single.
state_assignment_template_code CharField(100) '' State Assignment Email Template Code Per-state Email Studio override.
notify_originator_on_assignment BooleanField False Notify Originator on State Assignment Adds the initiator as a state assignment recipient.
orig_notification_subject CharField(200) None Originator Notification Subject
originator_notification_message TextField None Originator Notification Message
app_notification_subject CharField(200) None Approver Notification Subject
approver_notification_message TextField None Approver Notification Message
notification_recipient CharField(50), NotificationRecipient.choices None Notification Recipient
condition_failure_behavior CharField(50), ConditionFailureBehavior.choices fail_closed Condition Failure Behavior
state_code CharField(100) '' State Code blank=True; state nodes only.
matched_join self-FK, SET_NULL None Matched Join related_name='matched_fork'.
assignee_users M2M User — Assignee Users blank=True.
assignee_groups M2M Group — Assignee Groups blank=True.

StateTransition — workflowtemplate.py:127

Field Type Default Verbose name Notes
workflowtemplate FK, CASCADE — Workflow Template related_name='state_transitions'.
source_state FK StepTemplate, CASCADE — Source State related_name='outgoing_transitions'.
target_state FK StepTemplate, CASCADE — Target State related_name='incoming_transitions'.
label CharField(150) '' Transition Label blank=True; overrides the display name.
order PositiveIntegerField 0 Order ordering = ['order', 'id'].
condition_expression FK SavedQuery, PROTECT None Transition Condition State guard or automatic route.
condition_mode CharField(20), TransitionConditionMode.choices manual Condition Mode
condition_result CharField(10), ConditionResult.choices '' Condition Result true/false on condition-node edges.
comment_required BooleanField False Comment Required

Unique together: (workflowtemplate, source_state, target_state).

WorkflowInstance — workflowtemplate.py:165

Field Type Default Verbose name Notes
template FK, PROTECT — Workflow Template related_name='instances'.
content_type FK ContentType, PROTECT — Content Type With object_id forms document.
object_id TextField None — Stored as str(pk).
initiated_by FK User, PROTECT None Initiated By Notification recipient.
current_step FK StepTemplate, PROTECT None Current Step Primary active state.
current_step_order PositiveIntegerField 1 Current Step Order Approval engine.
status CharField(30), ApprovalStatus.choices draft Status
state_status CharField(20), StateLifecycle.choices None State Status Authoritative for state-based.
is_active / is_completed BooleanField True / False Is Active / Is Completed
submitted_at / completed_at DateTimeField None Submitted At / Completed At
context JSONField {} Context entity_id, document_id, amounts.

WorkflowBranch — models/workflowinstance.py:70

Field Type Default Verbose name Notes
workflow_instance FK, CASCADE — Workflow Instance related_name='branches'.
current_state FK StepTemplate, PROTECT None Current State related_name='branches_here'.
parent_branch self-FK, SET_NULL None Parent Branch related_name='child_branches'.
fork_scope UUIDField, indexed None Fork Scope Shared by sibling branches.
fork_node FK StepTemplate, SET_NULL None Fork Node related_name='spawned_branches'.
join_node FK StepTemplate, SET_NULL None Join Node related_name='consumed_branches'.
status CharField(20), StateLifecycle.choices active Branch Status
started_at / completed_at DateTimeField — / None Started At / Completed At ordering = ['started_at', 'id'].

WorkflowStepInstance.branch — workflowinstance.py:43

Field Type Default Verbose name
branch FK WorkflowBranch, SET_NULL None Branch

related_name='step_instances'; audit link from the executed step back to its token.

WorkflowApproverAction — workflowinstance.py:141

Field Type Default Notes
step_instance FK, CASCADE — related_name='approver_actions'.
target_state FK StepTemplate, SET_NULL None State-threshold vote target; null for approval steps.
approver FK User, PROTECT — related_name='workflow_approvals'.
action CharField(30) pending pending/approved/rejected/changes_requested/resubmitted.
comment TextField ''
acted_at DateTimeField None
is_available BooleanField True Set False for non-acting assignees.

Unique constraint unique_approver_per_step_instance on (step_instance, approver).

WorkflowTransaction — workflowinstance.py:197

Field Type Default Notes
workflow_instance FK, CASCADE — related_name='transactions'.
step_instance FK, SET_NULL None
action_type CharField(30), WorflowActionType.choices —
actor FK User, SET_NULL None Null when the actor has no PK.
step_name CharField(255) ''
message TextField — Human-readable history line.
metadata JSONField {} See the architecture guide's metadata list.

Service Reference

enezaworkflowengine/services/state_workflow.py

Function Signature Behaviour
get_start_node (template) First step_type='start' step or None.
get_end_node (template) First step_type='end' step ordered by order, id.
get_initial_node (template) Target of START's first outgoing StateTransition, or None.
get_initial_state (template) Backward-compatible alias for get_initial_node.
get_available_transitions (state_template) Ordered list of outgoing StateTransition rows.
state_approval_threshold (step_template) State threshold, defaulting blank to single.
state_required_approvals (step_instance) Required votes from the frozen eligible count.
approved_votes_for_target (step_instance, target_state) Approved vote count for one destination.
transition_display_name (transition) User-facing name; resolves through forks/joins up to depth 3.
get_active_branches (workflow_instance) Active branches ordered by started_at, id.
get_branches_for_user (workflow_instance, user, document=None) Active branches whose current node is a state and where user_can_transition is true.
state_assignees (state_template) set of active users from assignee_users plus active members of assignee_groups; empty set for None.
has_effective_assignees (state_template) bool(state_assignees(...)).
assignee_label (state_template) Sorted display names, or 'nobody'.
user_can_transition (state_template, user, document=None) False for anonymous, empty assignees, or a non-assignee. No permission fallback.
start_state_workflow (workflow_instance) Creates the initial branch; raises StateWorkflowError if START is missing or the initial state has no effective assignees. Returns the WorkflowBranch.
transition_branch (workflow_instance, branch, target_state, user, comment='') Atomic move with locks and validation. Records a per-target state vote; moves only when the threshold is met. Raises WorkflowAlreadyCompletedError / StateWorkflowError. Returns the branch.
cancel_state_workflow (workflow_instance, user=None, reason='') Cancels all active branches and the instance, clears the document state. No-op if already not active. Returns the instance. Not exposed in the UI.
sync_document_state (workflow_instance, final_code=None) Resolves the document state code, queues the write, updates current_step, returns the code or ''.

transition_display_name rules (:94-127): a state is named by its label or node name; a transition into a fork is named after the states the fork activates; a transition into a condition is named after its true/false destinations; a transition into a join is named after the node the join continues to; structural names are never shown. Depth is capped at 3, and duplicate names are collapsed.

enezaworkflowengine/services/state_choices.py — State Choices Resolution

Function Signature Behaviour
resolve_state_choices (state_choices_path) import_string → [(value, label)]; [] on missing path/bad import/no choices.
state_choice_values (state_choices_path) Set of values from resolve_state_choices.
discover_document_state_choices () Scans installed models for a workflowstate field with choices; returns the shared set, or a deterministic single set (sorted label) when several differ, logging a warning.
configured_registry () Reads WorkflowTypeConfig.WORKFLOW_STATE_CHOICES (or a plain dict) via settings.MY_PROJECT_WORKFLOWS_CONFIG. {} when unset/unresolvable.
configured_state_choices_path (workflowname) Registry entry for the name, else ''.
choices_for_workflowname (workflowname) Registry path; if empty and the registry has exactly one entry, that entry is used as a fallback.
explicit_state_choices_path (template) Registry path for template.workflowname, else template.state_choices_path, else ''.
template_state_choices (template) Precedence: registry → state_choices_path → auto-discovery.

Precedence chain, summarised:

flowchart LR
    A["WORKFLOW_STATE_CHOICES<br/>registry entry for workflowname"] -->|found| R["(value, label) list"]
    A -->|not found| B["WorkflowTemplate.state_choices_path"]
    B -->|found| R
    B -->|not found| C["discover_document_state_choices()<br/>any workflowstate field choices"]
    C --> R

Only explicit_state_choices_path is used by the validator for the S7 check (state_template_validator.py:238-244); the designer uses template_state_choices.

enezaworkflowengine/services/workflow_submission.py

Function Signature Behaviour
submit_workflow (document, user, template=None, workflow_name=None) Atomic. Rejects an existing active instance; resolves the active template by workflow_name; requires workflowstate for state-based; creates the instance and starts the state engine. Raises WorkflowSubmissionError.

enezaworkflowengine/services/workflow_versioning.py

Function Signature Behaviour
clone_workflow_template (source_template) Atomic. Creates version = max + 1, is_active=False, is_latest=True; copies kind, state_choices_path, design_data, all steps (with state_code and assignees), remapped FKs and all StateTransition rows. Returns the new template.

enezaworkflowengine/services/workflow_template_validator.py

Function Signature Behaviour
validate_workflow_template (template) Approval rules R1–R21. Returns list[str] of errors.
validate_template (template) Dispatches to validate_state_workflow_template when workflow_kind == 'state_based', else validate_workflow_template.

Validation Rules S1–S20

Source: enezaworkflowengine/services/state_template_validator.py. validate_state_workflow_template returns a list[str]; activation runs it through validate_template and refuses to activate when the list is non-empty.

Rule Line range Requirement Message prefix
S1 175-190 Every node's step_type is one of start/state/condition/fork/join/end, and every transition connects nodes of the same template. S1: Node ... / S1: Transition ...
S2 192-204 Exactly one START node; it has no incoming transitions, no state code and no assignees. S2: ... / S6: / S9: for the code/assignee checks
S3 206-215 At least one END node; END nodes have no outgoing transitions, no state code and no assignees. S3: ...
S4 217-231 START has exactly one outgoing transition and it targets a state or condition. S4: START node ...
S5 233-235 The template has at least one state (or, when there are no nodes at all, :162-163 returns S5). S5: ...
S6 237-266 Every state has a non-empty state_code, unique per template (compared case-insensitively); conditions, forks, joins, START and END have none. S6: State ... / S6: Node ...
S7 238-259 When the template declares state choices (via explicit_state_choices_path), every state code belongs to them; an unresolvable path is itself an error. S7: ...
S8 268-271 Every non-END state/join has at least one outgoing transition. S8: Node ...
S9 299-322 A fork has ≥ 2 outgoing transitions targeting states, conditions or forks, no assignees, and a matched_join pointing at a join of the template. S9: Fork ...
S10 340-359 A join has ≥ 2 incoming transitions, is matched by a fork, has exactly one outgoing transition, and does not continue into another join. S10: Join ...
S11 324-338, 361-369 Matching is bijective: a join is matched by at most one fork and every fork's join is a join of this template. S11: ...
S12 371-443 Fork scopes are properly nested or disjoint; no edge crosses scopes except into the matching join or an END; entering a scope is only allowed via the fork node itself. S12: ...
S13 445-457 Every branch leaving a fork can reach its matching join or an END node. S13: Branch from fork ...
S14 458-462 The matching join is reachable from at least one branch of its fork. S14: Join ...
S15 464-470 Every node is reachable from START; no orphan fork/join. S15: ...
S16 273-297 Every state has at least one effective assignee (active user, or group with active members); conditions, forks and joins have none. A state with only inactive users or empty groups is an error. S16: ...
S17 453-483 Transition guards remain state-only; condition-node edges are unconditional and carry a true/false result. S17: ...
S18 282-322 A condition node has a query, no assignees, no state code, and exactly one true plus one false outgoing transition. S18: ...
S19 324-339 condition_result is set on condition edges and blank on every other edge; condition targets are state/condition/fork/join/end. S19: ...
S20 422-451 A majority/all state has at least one manual transition and no automatic transition that would bypass voting. S20: ...

Notes:

  • S6 also tightens S2/S3: a START or END node carrying a state code is reported under S6.
  • S9 also covers START/END assignees: any of them having assignees is reported under S9.
  • S16 is evaluated with state_assignees(), so "listed but inactive" does not satisfy it.
  • Rule numbers in the reference docstring (:13-49) are authoritative; a few checks are physically grouped by node kind rather than by rule number.

design_data JSON Schema

WorkflowTemplate.design_data stores the last designer snapshot. The save view writes exactly what the designer sent; the load view enriches it before returning it.

Stored shape

json
{
  "nodes": [
    {
      "id": "step-1",
      "type": "state",
      "x": 360,
      "y": 60,
      "name": "Reported",
      "zIndex": 1,
      "stateCode": "reported",
      "approvalThreshold": "majority",
      "stateAssignmentTemplateCode": "STATE_ASSIGNED",
      "notifyOriginatorOnAssignment": true,
      "assigneeUserIds": [1, 2],
      "assigneeGroupIds": [3]
    }
  ],
  "connections": [
    {
      "id": "conn-1",
      "source": "step-1",
      "target": "step-2",
      "type": "transition",
      "label": "Triage"
    },
    {
      "id": "conn-2",
      "source": "condition-1",
      "target": "step-3",
      "type": "true",
      "conditionResult": "true"
    }
  ]
}

nodes[] keys

Key Type Present on Meaning
id string all Designer id, step-<n> when rebuilt from the DB.
type string all One of state, condition, fork, join, start, end.
x, y number all Canvas position. Fallback layout uses x=360, y=60 + idx*170.
name string all Node display name.
zIndex number all Stacking order, idx + 1.
stateCode string state The state code; empty string when unset.
approvalThreshold string state single, majority, or all; blank loads as single.
stateAssignmentTemplateCode string state Per-state assignment Email Studio code.
notifyOriginatorOnAssignment bool state Also notify the workflow originator.
conditionExpressionId string condition SavedQuery PK.
assigneeUserIds int[] state, join User PKs (returns [] when none).
assigneeGroupIds int[] state, join Group PKs.

connections[] keys

Key Type Meaning
id string conn-<n>.
source string Source node id.
target string Target node id.
type string transition, or true/false for edges leaving a condition node.
label string Transition label; truncated to 150 chars on save.
conditionExpressionId string Optional state-transition guard.
conditionMode string manual or automatic for state transitions.
conditionResult string true/false for condition-node edges.
commentRequired bool Transition comment requirement.

Loader enrichment

WorkflowDesignerLoadView (views/worflow_design.py:484-492) adds:

Key Source
workflow_kind WorkflowTemplate.workflow_kind
state_choices template_state_choices(template)
state_choices_path explicit_state_choices_path(template)
version WorkflowTemplate.version
is_latest WorkflowTemplate.is_latest
is_active WorkflowTemplate.is_active
template_id str(WorkflowTemplate.id)
cloned_from_version cloned_from.version, only when cloned_from is set

The stored snapshot is bypassed when _design_data_matches_steps finds it stale (worflow_design.py:281-316); see the architecture guide's Designer Load/Save Pipeline.

URLs and Views

Registered in enezaworkflowengine/urls.py (namespaced enezaworkflowengine).

Name Path View Methods
workflow_state_transition_picker workflow/<uuid:instance_id>/transition/<uuid:branch_id>/ (urls.py:79) StateWorkflowTransitionPickerView (views/workflow_api.py:973) GET
workflow_state_transition workflow/<uuid:instance_id>/transition/<uuid:branch_id>/move/ (urls.py:80) StateWorkflowTransitionView (views/workflow_api.py:1021) POST

Also relevant: workflow_history_ui (workflow/<uuid:instance_id>/history/ui/), used by the View History menu item.

workflow_state_transition_picker (GET)

  • Unauthenticated → JSON {'error': 'Authentication required'}, status 401.
  • Unknown instance/branch → 404 (get_object_or_404).
  • Optional query parameter list_url is passed through to the template.
  • Renders workflow_instance/partials/state_transition_form.html with:
  • workflow_instance, branch, current_state
  • transitions (raw StateTransition rows)
  • transition_options — [{'id': target.id, 'name': transition_display_name(t), 'is_end': <bool>}]
  • list_url, can_transition (user_can_transition(current_state, request.user, document))
  • The form posts target_state, comment and list_url to workflow_state_transition.

workflow_state_transition (POST)

Request fields: target_state (UUID, required), comment (optional), list_url (optional). The view is csrf_exempt at the dispatch level; the picker's form still includes {% csrf_token %}.

Success responses by request shape:

Condition Response
X-Requested-With: XMLHttpRequest JsonResponse({'success': True, 'workflow_instance_id', 'status', 'message', 'list_url'})
HX-Request header Empty 200 with HX-Reswap: none and HX-Trigger = {"workflowResult": {"title": "Success", "message", "variant": "success", "list_url"}}
Otherwise eneza_workflow_engine/workflow_result.html with message, list_url, title, variant

Error handling:

  • Missing/invalid target_state → JSON 400.
  • WorkflowTransitionError subclass → status e.http_status; JSON {'error': str(e)} or an HTMX HX-Trigger payload with variant: "error" when HX-Request is set.
  • Any other exception → JSON {'error': 'An unexpected error occurred'}, status 500 (logged with traceback).

WorkflowMixin Reference

Source: enezaframework/views/mixins.py.

Member Line Behaviour
workflow_template_name :979 Class attribute the child view must set.
has_workflow_state_field() :1087-1103 True when self.model has a workflowstate field.
get_workflow_kind() :1105-1115 workflow_kind of the active template, or None.
get_document_workflow_state() :1117-1126 Raw object.workflowstate or ''.
get_transitionable_branches() :1128-1148 get_branches_for_user(instance, request.user, self.object); [] when anonymous or no active instance.
can_submit_to_workflow() :1221-1266 State-based gate at :1229-1241.
get_workflow_menu_items() :1268-1381 State branch at :1342-1381.

State-based can_submit_to_workflow gate — :1229-1241

Returns (False, reason) in order when: the model lacks workflowstate; workflow_template_name is unset; no active template resolves; an active instance already exists; workflowstate is non-empty. Returns (True, '') otherwise. Note that the approval-engine draft-status requirement does not apply.

State-based get_workflow_menu_items — :1342-1381

  1. Always appends View History → workflow_history_ui.
  2. When workflow_instance.state_status == 'active', iterates get_transitionable_branches() and appends one item per branch: - name: Move to -> <transition_display_name(t)> when the state has exactly one allowed transition, otherwise Move to -> .... - url: workflow_state_transition_picker with (instance.id, branch.id). - method: GET, modal: True, hx_vals: {"list_url": "<app_name>:<list_view_name>"}.
  3. Returns after the state branch; the approval action items are not produced for state-based documents.

History Context

WorkflowHistoryMainView (views/workflow_api.py:665-705) adds to the template context:

Key Type Value
is_state_based bool template.workflow_kind == WorkflowKind.STATE_BASED
active_branches list get_active_branches(instance); each branch is annotated with effective_assignees (sorted active users) and assigned_groups.
state_summary str Sorted, comma-joined unique names of the active branches' current states.
state_status_display str instance.get_state_status_display() or ''.

history_shell.html renders state_summary (falling back to state_status_display, then status_display) and, when is_state_based and active_branches, lists every active branch with its effective_assignees (workflow_instance/partials/history_shell.html:10-50).

Management Commands

All under enezaworkflowengine/management/commands/.

create_sample_state_workflow

Builds a ready-to-edit state-based template with a Fork/Join (START → reported → triage → assessment → fork → investigation/containment → join → notification → remediation → validation → closed/cancelled → END).

Argument Default Meaning
--workflowname IncidentWorkflow Workflow name for the sample.
--reset off Delete all existing versions of the name (globally unique) first.
--entity first Entity Entity by id, slug, name or company code.
--activate off Validate and activate the created template.
--assignee first active superuser Repeatable username assigned to every state.
text
python manage.py create_sample_state_workflow
python manage.py create_sample_state_workflow --workflowname IncidentWorkflow --reset
python manage.py create_sample_state_workflow --entity ACME --activate --assignee admin

assign_state_users

Adds (or replaces) users/groups on every state of a template. The quickest way to make a workflow testable.

Argument Default Meaning
--workflowname required Target workflow name.
--username — Repeatable username.
--group — Repeatable group name.
--version active, else latest Target one template version.
--replace off Replace assignees instead of adding.
text
python manage.py assign_state_users --workflowname IncidentWorkflow --username admin
python manage.py assign_state_users --workflowname IncidentWorkflow --group Managers --replace

check_workflow_state_choices

Reports how the designer resolves state choices: the settings path, the registry, models with a workflowstate field, the discovery result, and per-template registry_path / explicit_path / choices.

Argument Default Meaning
--workflowname all Limit the report to one name.
--json off Emit the report as JSON.
text
python manage.py check_workflow_state_choices --workflowname IncidentWorkflow
python manage.py check_workflow_state_choices --json

workflow_instance_status

Prints instances with their kind, state_status, document workflowstate, every branch (id, status, state, fork_scope), the resolved assignees and — with --user — whether that user can move each state. Warns when an active instance has no active branches.

Argument Default Meaning
--workflowname all Filter by template.workflowname.
--user — Username to test user_can_transition against.
--limit 20 Maximum instances.
text
python manage.py workflow_instance_status --workflowname IncidentWorkflow --user admin

workflow_task_status

Shows recent django_tasks DBTaskResult rows (workflow tasks only unless --all), including status, queue, args and the last traceback line for failures, plus a status count.

Argument Default Meaning
--limit 25 Maximum rows.
--all off Include every module, not just workflow.
text
python manage.py workflow_task_status --all --limit 50

delete_workflow_template

Deletes a template (all versions by default) and everything attached to it in the correct order: instances (cascading to branches/steps/transactions) → transitions → steps → template. PROTECT FKs make a plain delete fail when runtime data exists.

Argument Default Meaning
--workflowname required Target workflow name.
--template-version all Delete only this version.
--keep-instances off Do not delete instances; fails if any reference the template.
--yes off Skip the interactive confirmation.
text
python manage.py delete_workflow_template --workflowname IncidentWorkflow --yes

Settings and Migrations

Settings

Setting Default Effect
WORKFLOW_STATE_ASYNC unset (False) False: apply_document_state runs inline. True: enqueued to the database task backend on commit; requires python manage.py db_worker. Read in tasks/workflow_tasks.py:728.
MY_PROJECT_WORKFLOWS_CONFIG framework.workflowconfig.WorkflowTypeConfig (framework/settings.py:32) Dotted path to the project config class holding WORKFLOW_STATE_CHOICES (and the type registry).
MY_PROJECT_WORKFLOWS_NAME framework.config.workflownames (framework/settings.py:31) Dotted path to the workflowname choices class.

Migrations

Migration Adds
enezaworkflowengine/migrations/0004_state_based_workflow.py State workflow models/fields (kind, branches, state fields).
enezaworkflowengine/migrations/0005_state_choices_and_start_end.py state_choices_path and the START/END additions.
frameworkapp/migrations/0012_incidentreport.py The IncidentReport test document.
frameworkapp/migrations/0013_incidentreport_workflowstate_choices.py IncidentReport.workflowstate choices.

Error Types

Class Module code http_status Raised when
WorkflowTransitionError services/workflow_errors.py:1 TRANSITION_ERROR 500 Base class; __init__(message, step_instance_id=None, event=None, original=None).
StateWorkflowError services/state_workflow.py:40 STATE_WORKFLOW_ERROR 400 Invalid branch state, disallowed edge, non-assignee, bad target type, missing START/initial assignees.
WorkflowAlreadyCompletedError services/workflow_errors.py:57 WORKFLOW_COMPLETED 409 Transition attempted on a non-active instance.
WorkflowSubmissionError services/workflow_submission.py:33 — (plain Exception) — Already-active instance, no active template, missing workflowstate/Approvalstatus.

Approval-engine siblings (StepHandlerNotFoundError, ConditionEvaluationError, ApproverAssignmentError, StepLockedError, WorkflowNotActiveError) share the same base class and are not raised by the state engine.

See Also

A Note on Testing

Per project rules, the developer or agent does not run or claim test results. The user is solely responsible for all testing and validation of the output described in this guide.