From 035c4a7faa1c2923547ef22b1afc38272d56bddd Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:05:54 -0400 Subject: [PATCH 01/24] Add central filing workflow registry --- efile_app/efile/workflow.py | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 efile_app/efile/workflow.py diff --git a/efile_app/efile/workflow.py b/efile_app/efile/workflow.py new file mode 100644 index 0000000..7936262 --- /dev/null +++ b/efile_app/efile/workflow.py @@ -0,0 +1,83 @@ +from dataclasses import dataclass +from typing import Iterable, Optional + +from django.urls import reverse + + +@dataclass(frozen=True) +class WorkflowStep: + """A single screen in the filing workflow.""" + + key: str + label: str + url_name: str + + +FILING_WORKFLOW: tuple[WorkflowStep, ...] = ( + WorkflowStep("options", "Options", "efile_options"), + WorkflowStep("upload_first", "Upload lead document", "upload_first"), + WorkflowStep("case_information", "Case information", "expert_form"), + WorkflowStep("documents", "Documents", "upload"), + WorkflowStep("payment", "Payment", "payment"), + WorkflowStep("review", "Review", "case_review"), + WorkflowStep("confirmation", "Confirmation", "filing_confirmation"), +) + + +def get_workflow_steps() -> Iterable[WorkflowStep]: + return FILING_WORKFLOW + + +def get_step(step_key: str) -> WorkflowStep: + try: + return next(step for step in FILING_WORKFLOW if step.key == step_key) + except StopIteration as exc: + raise KeyError(f"Unknown workflow step: {step_key}") from exc + + +def get_step_index(step_key: str) -> int: + for index, step in enumerate(FILING_WORKFLOW): + if step.key == step_key: + return index + raise KeyError(f"Unknown workflow step: {step_key}") + + +def get_previous_step(step_key: str) -> Optional[WorkflowStep]: + index = get_step_index(step_key) + if index == 0: + return None + return FILING_WORKFLOW[index - 1] + + +def get_next_step(step_key: str) -> Optional[WorkflowStep]: + index = get_step_index(step_key) + try: + return FILING_WORKFLOW[index + 1] + except IndexError: + return None + + +def get_step_url(step_key: str, jurisdiction: str) -> str: + step = get_step(step_key) + return reverse(step.url_name, kwargs={"jurisdiction": jurisdiction}) + + +def get_workflow_context(current_step: str, jurisdiction: str) -> dict: + previous_step = get_previous_step(current_step) + next_step = get_next_step(current_step) + previous_url = None + next_url = None + + if previous_step: + previous_url = get_step_url(previous_step.key, jurisdiction) + if next_step: + next_url = get_step_url(next_step.key, jurisdiction) + + return { + "workflow_steps": get_workflow_steps(), + "workflow_current_step": get_step(current_step), + "workflow_previous_step": previous_step, + "workflow_next_step": next_step, + "workflow_previous_url": previous_url, + "workflow_next_url": next_url, + } From dbfed9161296a7491a323b030316a59d65c8f407 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:06:16 -0400 Subject: [PATCH 02/24] Add workflow context to options page --- efile_app/efile/views/options.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/efile_app/efile/views/options.py b/efile_app/efile/views/options.py index f2c996d..9e4752d 100644 --- a/efile_app/efile/views/options.py +++ b/efile_app/efile/views/options.py @@ -3,6 +3,7 @@ from efile.api.suffolk_api_views import get_tyler_token from ..utils.case_data_utils import get_case_data +from ..workflow import get_workflow_context def efile_options(request, jurisdiction): @@ -17,14 +18,12 @@ def efile_options(request, jurisdiction): if not get_tyler_token(request, jurisdiction): is_logged_in = False - is_logged_in = request.user.is_authenticated - if not get_tyler_token(request, jurisdiction): - is_logged_in = False # Pass case data to template for display context = { "is_logged_in": is_logged_in, "case_data": case_data, "has_case_data": bool(case_data), } + context.update(get_workflow_context("options", jurisdiction)) return render(request, "efile/options.html", context) From 87d01cb9650084ec2bf857475d3db52858b8c67a Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:06:38 -0400 Subject: [PATCH 03/24] Add workflow context to upload-first page --- efile_app/efile/views/upload_first.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/efile_app/efile/views/upload_first.py b/efile_app/efile/views/upload_first.py index 24c5858..e2dc789 100644 --- a/efile_app/efile/views/upload_first.py +++ b/efile_app/efile/views/upload_first.py @@ -12,6 +12,7 @@ get_upload_data, ) from ..utils.django_helpers import flush_cache_stay_logged_in +from ..workflow import get_workflow_context logger = logging.getLogger(__name__) @@ -55,5 +56,6 @@ def efile_upload_first(request, jurisdiction): "name_sought_info": name_sought_info, "case_classification": case_classification, } + context.update(get_workflow_context("upload_first", jurisdiction)) return render(request, "efile/upload_first.html", context) From 7aca5696eeceb7bfb1122dcd0ced50f212404ca5 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:07:01 -0400 Subject: [PATCH 04/24] Add workflow context to case information page --- efile_app/efile/views/expert_form.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/efile_app/efile/views/expert_form.py b/efile_app/efile/views/expert_form.py index 64ecbf5..4a22bf6 100644 --- a/efile_app/efile/views/expert_form.py +++ b/efile_app/efile/views/expert_form.py @@ -5,6 +5,7 @@ from efile.api.suffolk_api_views import get_tyler_token from ..utils.case_data_utils import get_upload_data +from ..workflow import get_workflow_context logger = logging.getLogger(__name__) @@ -59,5 +60,6 @@ def efile_expert_form(request, jurisdiction): "missing_required_fields": not has_all_required, "missing_party_info": has_all_required and not has_party_info, } + context.update(get_workflow_context("case_information", jurisdiction)) return render(request, "efile/expert_form.html", context) From eb1f2092157e98a7c9a848e712d9a478347c2f15 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:07:50 -0400 Subject: [PATCH 05/24] Add workflow context to payment page --- efile_app/efile/views/payment.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/efile_app/efile/views/payment.py b/efile_app/efile/views/payment.py index c6d15d9..1079383 100644 --- a/efile_app/efile/views/payment.py +++ b/efile_app/efile/views/payment.py @@ -7,6 +7,7 @@ from efile.api.suffolk_api_views import get_tyler_token from ..utils.case_data_utils import get_case_data +from ..workflow import get_workflow_context logger = logging.getLogger(__name__) @@ -37,5 +38,6 @@ def efile_payment(request, jurisdiction): "new_toga_url": new_toga_url, "case_data": case_data, } + context.update(get_workflow_context("payment", jurisdiction)) return render(request, "efile/payment.html", context) From c5bd6c6617902d560caf26776b3d759e0ee36c1e Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:10:19 -0400 Subject: [PATCH 06/24] Fix workflow lint imports --- efile_app/efile/workflow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/efile_app/efile/workflow.py b/efile_app/efile/workflow.py index 7936262..f6a5700 100644 --- a/efile_app/efile/workflow.py +++ b/efile_app/efile/workflow.py @@ -1,5 +1,5 @@ +from collections.abc import Iterable from dataclasses import dataclass -from typing import Iterable, Optional from django.urls import reverse @@ -42,14 +42,14 @@ def get_step_index(step_key: str) -> int: raise KeyError(f"Unknown workflow step: {step_key}") -def get_previous_step(step_key: str) -> Optional[WorkflowStep]: +def get_previous_step(step_key: str): index = get_step_index(step_key) if index == 0: return None return FILING_WORKFLOW[index - 1] -def get_next_step(step_key: str) -> Optional[WorkflowStep]: +def get_next_step(step_key: str): index = get_step_index(step_key) try: return FILING_WORKFLOW[index + 1] From 7a4b93ddf9c41e3fdfa23194f9d23048bffff793 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:31:02 -0400 Subject: [PATCH 07/24] Add workflow registry tests --- efile_app/efile/tests/test_workflow.py | 79 ++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 efile_app/efile/tests/test_workflow.py diff --git a/efile_app/efile/tests/test_workflow.py b/efile_app/efile/tests/test_workflow.py new file mode 100644 index 0000000..15f2ea2 --- /dev/null +++ b/efile_app/efile/tests/test_workflow.py @@ -0,0 +1,79 @@ +import pytest +from django.urls import reverse + +from efile.workflow import ( + FILING_WORKFLOW, + get_next_step, + get_previous_step, + get_step, + get_step_url, + get_workflow_context, + get_workflow_steps, +) + + +@pytest.mark.parametrize( + ("step_key", "label"), + [ + ("options", "Options"), + ("upload_first", "Upload lead document"), + ("case_information", "Case information"), + ("documents", "Documents"), + ("payment", "Payment"), + ("review", "Review"), + ("confirmation", "Confirmation"), + ], +) +def test_get_step_returns_registered_step(step_key, label): + step = get_step(step_key) + + assert step.key == step_key + assert step.label == label + + +def test_get_workflow_steps_returns_ordered_workflow(): + assert get_workflow_steps() == FILING_WORKFLOW + assert [step.key for step in get_workflow_steps()] == [ + "options", + "upload_first", + "case_information", + "documents", + "payment", + "review", + "confirmation", + ] + + +def test_get_step_raises_key_error_for_unknown_step(): + with pytest.raises(KeyError): + get_step("unknown") + + +def test_get_previous_step_returns_none_for_first_step(): + assert get_previous_step("options") is None + + +def test_get_previous_step_returns_prior_step(): + assert get_previous_step("case_information").key == "upload_first" + + +def test_get_next_step_returns_following_step(): + assert get_next_step("case_information").key == "documents" + + +def test_get_next_step_returns_none_for_last_step(): + assert get_next_step("confirmation") is None + + +def test_get_step_url_reverses_workflow_route(): + assert get_step_url("payment", "illinois") == reverse("payment", kwargs={"jurisdiction": "illinois"}) + + +def test_get_workflow_context_includes_current_previous_and_next_urls(): + context = get_workflow_context("payment", "illinois") + + assert context["workflow_current_step"].key == "payment" + assert context["workflow_previous_step"].key == "documents" + assert context["workflow_next_step"].key == "review" + assert context["workflow_previous_url"] == reverse("upload", kwargs={"jurisdiction": "illinois"}) + assert context["workflow_next_url"] == reverse("case_review", kwargs={"jurisdiction": "illinois"}) From 99b9ad145cedd5bb787340fff52bd1ae3de29a3b Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:31:14 -0400 Subject: [PATCH 08/24] Address workflow typing review comments --- efile_app/efile/workflow.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/efile_app/efile/workflow.py b/efile_app/efile/workflow.py index f6a5700..00323b3 100644 --- a/efile_app/efile/workflow.py +++ b/efile_app/efile/workflow.py @@ -1,4 +1,3 @@ -from collections.abc import Iterable from dataclasses import dataclass from django.urls import reverse @@ -24,7 +23,7 @@ class WorkflowStep: ) -def get_workflow_steps() -> Iterable[WorkflowStep]: +def get_workflow_steps() -> tuple[WorkflowStep, ...]: return FILING_WORKFLOW @@ -42,14 +41,14 @@ def get_step_index(step_key: str) -> int: raise KeyError(f"Unknown workflow step: {step_key}") -def get_previous_step(step_key: str): +def get_previous_step(step_key: str) -> WorkflowStep | None: index = get_step_index(step_key) if index == 0: return None return FILING_WORKFLOW[index - 1] -def get_next_step(step_key: str): +def get_next_step(step_key: str) -> WorkflowStep | None: index = get_step_index(step_key) try: return FILING_WORKFLOW[index + 1] From 4fc3182ad9b123f4e2026645e2480a06a235a38d Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:31:33 -0400 Subject: [PATCH 09/24] Add workflow context to document upload page --- efile_app/efile/views/upload.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/efile_app/efile/views/upload.py b/efile_app/efile/views/upload.py index 7e51641..ef60440 100644 --- a/efile_app/efile/views/upload.py +++ b/efile_app/efile/views/upload.py @@ -13,6 +13,7 @@ get_petitioner_info, get_upload_data, ) +from ..workflow import get_workflow_context logger = logging.getLogger(__name__) @@ -20,24 +21,19 @@ def efile_upload(request, jurisdiction): """Upload view for document submission and filing creation.""" - # Check if user is authenticated first if not request.user.is_authenticated: return redirect("efile_login", jurisdiction=jurisdiction) - # Get case data from session case_data = get_case_data(request) - # If no case data exists, redirect back to options page if not case_data: messages.error(request, gettext("Please complete the case details first.")) return redirect("efile_options", jurisdiction=jurisdiction) - # Get organized case information petitioner_info = get_petitioner_info(request) name_sought_info = get_name_sought_info(request) case_classification = get_case_classification(request) - # Use friendly names if available, otherwise fallback to raw values friendly_case_type = case_data.get("case_type_name", case_classification["case_type"]) friendly_filing_type = case_data.get("filing_type_name", case_classification["filing_type"]) friendly_court = case_data.get("court_name", case_classification["court"]) @@ -62,5 +58,6 @@ def efile_upload(request, jurisdiction): "filing_type_raw": case_classification["filing_type"], "court_raw": case_classification["court"], } + context.update(get_workflow_context("documents", jurisdiction)) return render(request, "efile/upload.html", context) From 826e12a75cfdf3f4e28378f73987c31a807d38f5 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:31:40 -0400 Subject: [PATCH 10/24] Add workflow context to confirmation page --- efile_app/efile/views/confirmation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/efile_app/efile/views/confirmation.py b/efile_app/efile/views/confirmation.py index 597e27a..a5da143 100644 --- a/efile_app/efile/views/confirmation.py +++ b/efile_app/efile/views/confirmation.py @@ -2,6 +2,8 @@ from efile.api.suffolk_api_views import get_tyler_token +from ..workflow import get_workflow_context + def filing_confirmation(request, jurisdiction): """Confirmation page after successful filing submission.""" @@ -17,5 +19,6 @@ def filing_confirmation(request, jurisdiction): "page_title": "Filing Confirmation", "success_message": "Your filing has been successfully submitted!", } + context.update(get_workflow_context("confirmation", jurisdiction)) return render(request, "efile/confirmation.html", context) From 1ab8d774582651dbe07823b4f042aac1d2e9772b Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:31:56 -0400 Subject: [PATCH 11/24] Add workflow context to review page --- efile_app/efile/views/review.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/efile_app/efile/views/review.py b/efile_app/efile/views/review.py index 1b386e8..d3db397 100644 --- a/efile_app/efile/views/review.py +++ b/efile_app/efile/views/review.py @@ -7,6 +7,7 @@ from efile.api.suffolk_api_views import get_tyler_token from ..utils.case_data_utils import get_case_classification, get_case_data, get_name_sought_info, get_petitioner_info +from ..workflow import get_workflow_context logger = logging.getLogger(__name__) @@ -112,5 +113,6 @@ def case_review(request, jurisdiction): "document_type": friendly_document_type, }, } + context.update(get_workflow_context("review", jurisdiction)) return render(request, "efile/review.html", context) From 303049249b384f8c394e9d5228ae475ae1efbdb1 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:45:44 -0400 Subject: [PATCH 12/24] Document workflow step maintenance --- efile_app/efile/workflow.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/efile_app/efile/workflow.py b/efile_app/efile/workflow.py index 00323b3..d59f61f 100644 --- a/efile_app/efile/workflow.py +++ b/efile_app/efile/workflow.py @@ -1,3 +1,22 @@ +"""Central filing workflow registry. + +Use FILING_WORKFLOW as the single high-level map of the filing flow. + +To add a step: +1. Add the URL route and view. +2. Add a WorkflowStep entry in the desired position below. +3. Add get_workflow_context("step_key", jurisdiction) to that view's context. +4. Update any navigation copy that mentions the surrounding steps. +5. Update efile/tests/test_workflow.py. + +To rearrange steps: +1. Reorder FILING_WORKFLOW. +2. Update affected labels, navigation copy, and workflow tests. + +This registry is intentionally linear for now. Future branching should be added +here after the durable filing draft model exists as the workflow state source. +""" + from dataclasses import dataclass from django.urls import reverse From 8bed869d0db04a001ce1cb1dfce0a21a2dc52238 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:54:42 -0400 Subject: [PATCH 13/24] Use enum keys for workflow steps --- efile_app/efile/workflow.py | 52 +++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/efile_app/efile/workflow.py b/efile_app/efile/workflow.py index d59f61f..d2445d2 100644 --- a/efile_app/efile/workflow.py +++ b/efile_app/efile/workflow.py @@ -3,11 +3,12 @@ Use FILING_WORKFLOW as the single high-level map of the filing flow. To add a step: -1. Add the URL route and view. -2. Add a WorkflowStep entry in the desired position below. -3. Add get_workflow_context("step_key", jurisdiction) to that view's context. -4. Update any navigation copy that mentions the surrounding steps. -5. Update efile/tests/test_workflow.py. +1. Add a WorkflowStepKey member for the new step. +2. Add the URL route and view. +3. Add a WorkflowStep entry in the desired position below. +4. Add get_workflow_context(WorkflowStepKey.YOUR_STEP, jurisdiction) to that view's context. +5. Update any navigation copy that mentions the surrounding steps. +6. Update efile/tests/test_workflow.py. To rearrange steps: 1. Reorder FILING_WORKFLOW. @@ -18,27 +19,40 @@ """ from dataclasses import dataclass +from enum import StrEnum from django.urls import reverse +class WorkflowStepKey(StrEnum): + """Stable identifiers for filing workflow steps.""" + + OPTIONS = "options" + UPLOAD_FIRST = "upload_first" + CASE_INFORMATION = "case_information" + DOCUMENTS = "documents" + PAYMENT = "payment" + REVIEW = "review" + CONFIRMATION = "confirmation" + + @dataclass(frozen=True) class WorkflowStep: """A single screen in the filing workflow.""" - key: str + key: WorkflowStepKey label: str url_name: str FILING_WORKFLOW: tuple[WorkflowStep, ...] = ( - WorkflowStep("options", "Options", "efile_options"), - WorkflowStep("upload_first", "Upload lead document", "upload_first"), - WorkflowStep("case_information", "Case information", "expert_form"), - WorkflowStep("documents", "Documents", "upload"), - WorkflowStep("payment", "Payment", "payment"), - WorkflowStep("review", "Review", "case_review"), - WorkflowStep("confirmation", "Confirmation", "filing_confirmation"), + WorkflowStep(WorkflowStepKey.OPTIONS, "Options", "efile_options"), + WorkflowStep(WorkflowStepKey.UPLOAD_FIRST, "Upload lead document", "upload_first"), + WorkflowStep(WorkflowStepKey.CASE_INFORMATION, "Case information", "expert_form"), + WorkflowStep(WorkflowStepKey.DOCUMENTS, "Documents", "upload"), + WorkflowStep(WorkflowStepKey.PAYMENT, "Payment", "payment"), + WorkflowStep(WorkflowStepKey.REVIEW, "Review", "case_review"), + WorkflowStep(WorkflowStepKey.CONFIRMATION, "Confirmation", "filing_confirmation"), ) @@ -46,28 +60,28 @@ def get_workflow_steps() -> tuple[WorkflowStep, ...]: return FILING_WORKFLOW -def get_step(step_key: str) -> WorkflowStep: +def get_step(step_key: WorkflowStepKey | str) -> WorkflowStep: try: return next(step for step in FILING_WORKFLOW if step.key == step_key) except StopIteration as exc: raise KeyError(f"Unknown workflow step: {step_key}") from exc -def get_step_index(step_key: str) -> int: +def get_step_index(step_key: WorkflowStepKey | str) -> int: for index, step in enumerate(FILING_WORKFLOW): if step.key == step_key: return index raise KeyError(f"Unknown workflow step: {step_key}") -def get_previous_step(step_key: str) -> WorkflowStep | None: +def get_previous_step(step_key: WorkflowStepKey | str) -> WorkflowStep | None: index = get_step_index(step_key) if index == 0: return None return FILING_WORKFLOW[index - 1] -def get_next_step(step_key: str) -> WorkflowStep | None: +def get_next_step(step_key: WorkflowStepKey | str) -> WorkflowStep | None: index = get_step_index(step_key) try: return FILING_WORKFLOW[index + 1] @@ -75,12 +89,12 @@ def get_next_step(step_key: str) -> WorkflowStep | None: return None -def get_step_url(step_key: str, jurisdiction: str) -> str: +def get_step_url(step_key: WorkflowStepKey | str, jurisdiction: str) -> str: step = get_step(step_key) return reverse(step.url_name, kwargs={"jurisdiction": jurisdiction}) -def get_workflow_context(current_step: str, jurisdiction: str) -> dict: +def get_workflow_context(current_step: WorkflowStepKey | str, jurisdiction: str) -> dict: previous_step = get_previous_step(current_step) next_step = get_next_step(current_step) previous_url = None From 1b7fd8ac6114b24a892785e0154c2e7b5794e48d Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:54:51 -0400 Subject: [PATCH 14/24] Use workflow enum in options view --- efile_app/efile/views/options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efile_app/efile/views/options.py b/efile_app/efile/views/options.py index 9e4752d..f6d6182 100644 --- a/efile_app/efile/views/options.py +++ b/efile_app/efile/views/options.py @@ -3,7 +3,7 @@ from efile.api.suffolk_api_views import get_tyler_token from ..utils.case_data_utils import get_case_data -from ..workflow import get_workflow_context +from ..workflow import WorkflowStepKey, get_workflow_context def efile_options(request, jurisdiction): @@ -24,6 +24,6 @@ def efile_options(request, jurisdiction): "case_data": case_data, "has_case_data": bool(case_data), } - context.update(get_workflow_context("options", jurisdiction)) + context.update(get_workflow_context(WorkflowStepKey.OPTIONS, jurisdiction)) return render(request, "efile/options.html", context) From 03e77f49fef58defe0e58c7d218ca43e6c5136ab Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:55:01 -0400 Subject: [PATCH 15/24] Use workflow enum in lead upload view --- efile_app/efile/views/upload_first.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efile_app/efile/views/upload_first.py b/efile_app/efile/views/upload_first.py index e2dc789..1a63de6 100644 --- a/efile_app/efile/views/upload_first.py +++ b/efile_app/efile/views/upload_first.py @@ -12,7 +12,7 @@ get_upload_data, ) from ..utils.django_helpers import flush_cache_stay_logged_in -from ..workflow import get_workflow_context +from ..workflow import WorkflowStepKey, get_workflow_context logger = logging.getLogger(__name__) @@ -56,6 +56,6 @@ def efile_upload_first(request, jurisdiction): "name_sought_info": name_sought_info, "case_classification": case_classification, } - context.update(get_workflow_context("upload_first", jurisdiction)) + context.update(get_workflow_context(WorkflowStepKey.UPLOAD_FIRST, jurisdiction)) return render(request, "efile/upload_first.html", context) From dc8dc7ffb109c417ea0c8da3290d7553c75bf571 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:55:12 -0400 Subject: [PATCH 16/24] Use workflow enum in case information view --- efile_app/efile/views/expert_form.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efile_app/efile/views/expert_form.py b/efile_app/efile/views/expert_form.py index 4a22bf6..96dfd99 100644 --- a/efile_app/efile/views/expert_form.py +++ b/efile_app/efile/views/expert_form.py @@ -5,7 +5,7 @@ from efile.api.suffolk_api_views import get_tyler_token from ..utils.case_data_utils import get_upload_data -from ..workflow import get_workflow_context +from ..workflow import WorkflowStepKey, get_workflow_context logger = logging.getLogger(__name__) @@ -60,6 +60,6 @@ def efile_expert_form(request, jurisdiction): "missing_required_fields": not has_all_required, "missing_party_info": has_all_required and not has_party_info, } - context.update(get_workflow_context("case_information", jurisdiction)) + context.update(get_workflow_context(WorkflowStepKey.CASE_INFORMATION, jurisdiction)) return render(request, "efile/expert_form.html", context) From 98af8223e7f1790a57ea828727ceafb82de0334a Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:55:21 -0400 Subject: [PATCH 17/24] Use workflow enum in document upload view --- efile_app/efile/views/upload.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efile_app/efile/views/upload.py b/efile_app/efile/views/upload.py index ef60440..3393cb5 100644 --- a/efile_app/efile/views/upload.py +++ b/efile_app/efile/views/upload.py @@ -13,7 +13,7 @@ get_petitioner_info, get_upload_data, ) -from ..workflow import get_workflow_context +from ..workflow import WorkflowStepKey, get_workflow_context logger = logging.getLogger(__name__) @@ -58,6 +58,6 @@ def efile_upload(request, jurisdiction): "filing_type_raw": case_classification["filing_type"], "court_raw": case_classification["court"], } - context.update(get_workflow_context("documents", jurisdiction)) + context.update(get_workflow_context(WorkflowStepKey.DOCUMENTS, jurisdiction)) return render(request, "efile/upload.html", context) From deeaa61786a05cb47b91d603959c615e1a52d860 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:55:29 -0400 Subject: [PATCH 18/24] Use workflow enum in payment view --- efile_app/efile/views/payment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efile_app/efile/views/payment.py b/efile_app/efile/views/payment.py index 1079383..8462887 100644 --- a/efile_app/efile/views/payment.py +++ b/efile_app/efile/views/payment.py @@ -7,7 +7,7 @@ from efile.api.suffolk_api_views import get_tyler_token from ..utils.case_data_utils import get_case_data -from ..workflow import get_workflow_context +from ..workflow import WorkflowStepKey, get_workflow_context logger = logging.getLogger(__name__) @@ -38,6 +38,6 @@ def efile_payment(request, jurisdiction): "new_toga_url": new_toga_url, "case_data": case_data, } - context.update(get_workflow_context("payment", jurisdiction)) + context.update(get_workflow_context(WorkflowStepKey.PAYMENT, jurisdiction)) return render(request, "efile/payment.html", context) From a8bdbb19cd748ca968466e513c4a26fba9bebd63 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:55:44 -0400 Subject: [PATCH 19/24] Use workflow enum in review view --- efile_app/efile/views/review.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efile_app/efile/views/review.py b/efile_app/efile/views/review.py index d3db397..d980aee 100644 --- a/efile_app/efile/views/review.py +++ b/efile_app/efile/views/review.py @@ -7,7 +7,7 @@ from efile.api.suffolk_api_views import get_tyler_token from ..utils.case_data_utils import get_case_classification, get_case_data, get_name_sought_info, get_petitioner_info -from ..workflow import get_workflow_context +from ..workflow import WorkflowStepKey, get_workflow_context logger = logging.getLogger(__name__) @@ -113,6 +113,6 @@ def case_review(request, jurisdiction): "document_type": friendly_document_type, }, } - context.update(get_workflow_context("review", jurisdiction)) + context.update(get_workflow_context(WorkflowStepKey.REVIEW, jurisdiction)) return render(request, "efile/review.html", context) From 1ad9a0d4825c9ddc4c952254a2d066c3db802a27 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 16:55:52 -0400 Subject: [PATCH 20/24] Use workflow enum in confirmation view --- efile_app/efile/views/confirmation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efile_app/efile/views/confirmation.py b/efile_app/efile/views/confirmation.py index a5da143..424f2d1 100644 --- a/efile_app/efile/views/confirmation.py +++ b/efile_app/efile/views/confirmation.py @@ -2,7 +2,7 @@ from efile.api.suffolk_api_views import get_tyler_token -from ..workflow import get_workflow_context +from ..workflow import WorkflowStepKey, get_workflow_context def filing_confirmation(request, jurisdiction): @@ -19,6 +19,6 @@ def filing_confirmation(request, jurisdiction): "page_title": "Filing Confirmation", "success_message": "Your filing has been successfully submitted!", } - context.update(get_workflow_context("confirmation", jurisdiction)) + context.update(get_workflow_context(WorkflowStepKey.CONFIRMATION, jurisdiction)) return render(request, "efile/confirmation.html", context) From f031f593211b5c84b54be5810d437e74568dadd1 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 17:01:52 -0400 Subject: [PATCH 21/24] Use workflow enum in workflow tests --- efile_app/efile/tests/test_workflow.py | 62 ++++++++++++++------------ 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/efile_app/efile/tests/test_workflow.py b/efile_app/efile/tests/test_workflow.py index 15f2ea2..0cfe965 100644 --- a/efile_app/efile/tests/test_workflow.py +++ b/efile_app/efile/tests/test_workflow.py @@ -3,6 +3,7 @@ from efile.workflow import ( FILING_WORKFLOW, + WorkflowStepKey, get_next_step, get_previous_step, get_step, @@ -12,16 +13,27 @@ ) +EXPECTED_WORKFLOW_KEYS = [ + WorkflowStepKey.OPTIONS, + WorkflowStepKey.UPLOAD_FIRST, + WorkflowStepKey.CASE_INFORMATION, + WorkflowStepKey.DOCUMENTS, + WorkflowStepKey.PAYMENT, + WorkflowStepKey.REVIEW, + WorkflowStepKey.CONFIRMATION, +] + + @pytest.mark.parametrize( ("step_key", "label"), [ - ("options", "Options"), - ("upload_first", "Upload lead document"), - ("case_information", "Case information"), - ("documents", "Documents"), - ("payment", "Payment"), - ("review", "Review"), - ("confirmation", "Confirmation"), + (WorkflowStepKey.OPTIONS, "Options"), + (WorkflowStepKey.UPLOAD_FIRST, "Upload lead document"), + (WorkflowStepKey.CASE_INFORMATION, "Case information"), + (WorkflowStepKey.DOCUMENTS, "Documents"), + (WorkflowStepKey.PAYMENT, "Payment"), + (WorkflowStepKey.REVIEW, "Review"), + (WorkflowStepKey.CONFIRMATION, "Confirmation"), ], ) def test_get_step_returns_registered_step(step_key, label): @@ -33,47 +45,39 @@ def test_get_step_returns_registered_step(step_key, label): def test_get_workflow_steps_returns_ordered_workflow(): assert get_workflow_steps() == FILING_WORKFLOW - assert [step.key for step in get_workflow_steps()] == [ - "options", - "upload_first", - "case_information", - "documents", - "payment", - "review", - "confirmation", - ] - - -def test_get_step_raises_key_error_for_unknown_step(): + assert [step.key for step in get_workflow_steps()] == EXPECTED_WORKFLOW_KEYS + + +def test_get_step_raises_key_error_for_invalid_step(): with pytest.raises(KeyError): - get_step("unknown") + get_step("invalid_step") def test_get_previous_step_returns_none_for_first_step(): - assert get_previous_step("options") is None + assert get_previous_step(WorkflowStepKey.OPTIONS) is None def test_get_previous_step_returns_prior_step(): - assert get_previous_step("case_information").key == "upload_first" + assert get_previous_step(WorkflowStepKey.CASE_INFORMATION).key == WorkflowStepKey.UPLOAD_FIRST def test_get_next_step_returns_following_step(): - assert get_next_step("case_information").key == "documents" + assert get_next_step(WorkflowStepKey.CASE_INFORMATION).key == WorkflowStepKey.DOCUMENTS def test_get_next_step_returns_none_for_last_step(): - assert get_next_step("confirmation") is None + assert get_next_step(WorkflowStepKey.CONFIRMATION) is None def test_get_step_url_reverses_workflow_route(): - assert get_step_url("payment", "illinois") == reverse("payment", kwargs={"jurisdiction": "illinois"}) + assert get_step_url(WorkflowStepKey.PAYMENT, "illinois") == reverse("payment", kwargs={"jurisdiction": "illinois"}) def test_get_workflow_context_includes_current_previous_and_next_urls(): - context = get_workflow_context("payment", "illinois") + context = get_workflow_context(WorkflowStepKey.PAYMENT, "illinois") - assert context["workflow_current_step"].key == "payment" - assert context["workflow_previous_step"].key == "documents" - assert context["workflow_next_step"].key == "review" + assert context["workflow_current_step"].key == WorkflowStepKey.PAYMENT + assert context["workflow_previous_step"].key == WorkflowStepKey.DOCUMENTS + assert context["workflow_next_step"].key == WorkflowStepKey.REVIEW assert context["workflow_previous_url"] == reverse("upload", kwargs={"jurisdiction": "illinois"}) assert context["workflow_next_url"] == reverse("case_review", kwargs={"jurisdiction": "illinois"}) From 9bf8a3c358380bc610dd7e21e3f23f4e8078ed26 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 17:03:03 -0400 Subject: [PATCH 22/24] Fix workflow test lint issues --- efile_app/efile/tests/test_workflow.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/efile_app/efile/tests/test_workflow.py b/efile_app/efile/tests/test_workflow.py index 0cfe965..68b5081 100644 --- a/efile_app/efile/tests/test_workflow.py +++ b/efile_app/efile/tests/test_workflow.py @@ -58,11 +58,15 @@ def test_get_previous_step_returns_none_for_first_step(): def test_get_previous_step_returns_prior_step(): - assert get_previous_step(WorkflowStepKey.CASE_INFORMATION).key == WorkflowStepKey.UPLOAD_FIRST + previous_step = get_previous_step(WorkflowStepKey.CASE_INFORMATION) + + assert previous_step.key == WorkflowStepKey.UPLOAD_FIRST def test_get_next_step_returns_following_step(): - assert get_next_step(WorkflowStepKey.CASE_INFORMATION).key == WorkflowStepKey.DOCUMENTS + next_step = get_next_step(WorkflowStepKey.CASE_INFORMATION) + + assert next_step.key == WorkflowStepKey.DOCUMENTS def test_get_next_step_returns_none_for_last_step(): @@ -70,14 +74,18 @@ def test_get_next_step_returns_none_for_last_step(): def test_get_step_url_reverses_workflow_route(): - assert get_step_url(WorkflowStepKey.PAYMENT, "illinois") == reverse("payment", kwargs={"jurisdiction": "illinois"}) + expected_url = reverse("payment", kwargs={"jurisdiction": "illinois"}) + + assert get_step_url(WorkflowStepKey.PAYMENT, "illinois") == expected_url def test_get_workflow_context_includes_current_previous_and_next_urls(): context = get_workflow_context(WorkflowStepKey.PAYMENT, "illinois") + previous_url = reverse("upload", kwargs={"jurisdiction": "illinois"}) + next_url = reverse("case_review", kwargs={"jurisdiction": "illinois"}) assert context["workflow_current_step"].key == WorkflowStepKey.PAYMENT assert context["workflow_previous_step"].key == WorkflowStepKey.DOCUMENTS assert context["workflow_next_step"].key == WorkflowStepKey.REVIEW - assert context["workflow_previous_url"] == reverse("upload", kwargs={"jurisdiction": "illinois"}) - assert context["workflow_next_url"] == reverse("case_review", kwargs={"jurisdiction": "illinois"}) + assert context["workflow_previous_url"] == previous_url + assert context["workflow_next_url"] == next_url From ecd148bce8a4f12574c9f76644ba88cd3a35b79e Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 17:05:43 -0400 Subject: [PATCH 23/24] Sort workflow test imports --- efile_app/efile/tests/test_workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efile_app/efile/tests/test_workflow.py b/efile_app/efile/tests/test_workflow.py index 68b5081..ea9f08f 100644 --- a/efile_app/efile/tests/test_workflow.py +++ b/efile_app/efile/tests/test_workflow.py @@ -1,5 +1,5 @@ -import pytest from django.urls import reverse +import pytest from efile.workflow import ( FILING_WORKFLOW, From e40b17e961153a3c6d5500e4bcb798fd90971521 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 29 Jun 2026 17:08:18 -0400 Subject: [PATCH 24/24] fix ruff --- efile_app/efile/tests/test_workflow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/efile_app/efile/tests/test_workflow.py b/efile_app/efile/tests/test_workflow.py index ea9f08f..98437bd 100644 --- a/efile_app/efile/tests/test_workflow.py +++ b/efile_app/efile/tests/test_workflow.py @@ -1,5 +1,5 @@ -from django.urls import reverse import pytest +from django.urls import reverse from efile.workflow import ( FILING_WORKFLOW, @@ -12,7 +12,6 @@ get_workflow_steps, ) - EXPECTED_WORKFLOW_KEYS = [ WorkflowStepKey.OPTIONS, WorkflowStepKey.UPLOAD_FIRST,