Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ad9e948
Complete reorganized filing workflow
nonprofittechy Aug 10, 2026
6da86df
Address remaining Copilot review comments on review/submit flow
nonprofittechy Aug 10, 2026
0c1a679
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
1c70ba9
Merge migration graph forks from document-prep and review-submit
nonprofittechy Aug 11, 2026
f361ca6
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
866914f
Review page: filing type per document, payment fees, and edit round-trip
nonprofittechy Aug 11, 2026
f329020
Label payment accounts by their real Tyler type instead of guessing
nonprofittechy Aug 11, 2026
7cd3a23
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
e563b1d
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
3a4a960
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
9c716e8
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
afeeef8
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
110aabd
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
8aea1eb
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
cce1dde
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
d03287c
Merge remote-tracking branch 'origin/workflow/people' into workflow/r…
nonprofittechy Aug 11, 2026
b3a277f
Send amount_in_controversy in the filing payload
nonprofittechy Aug 11, 2026
23f8683
Worked on visual consistency with the new flow
nonprofittechy Aug 11, 2026
36ca8be
Give every screen one color system instead of five blues
nonprofittechy Aug 11, 2026
d469b77
Rewrite workflow screen text to meet the readability style guide
nonprofittechy Aug 11, 2026
919a135
Ruff format
nonprofittechy Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/screenshots/reorganized-flow/12-payment.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/reorganized-flow/13-review.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions efile_app/efile/api/auth_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,55 @@ def payment_accounts(request):
except Exception as e:
return AuthAPIViews.error_response(f"Error: {str(e)}")

@staticmethod
@require_http_methods(["GET"])
def payment_account_types(request):
"""List the court's payment account types (e.g. "CC", "WV") with names.

A payment account only carries its type *code*, not a human-readable
name, so the frontend needs this list to label account types other
than the ones it special-cases (card, waiver).
"""
try:
jurisdiction = get_jurisdiction_from_request(request)
tyler_token = get_tyler_token(request, jurisdiction)
api_key = getattr(settings, "SUFFOLK_EFILE_API_KEY", None)

headers = {
"Content-Type": "application/json",
"User-Agent": f"{jurisdiction.title()}-eFile-Client/1.0",
"X-API-Key": api_key if api_key else "",
}
if tyler_token:
headers[f"tyler-token-{jurisdiction}"] = tyler_token

url = f"{settings.EFSP_URL}/jurisdictions/{jurisdiction}/payments/types"
logger.debug("GET %s header keys=%s", url, list(headers.keys()))
api_response = requests.get(url, headers=headers, timeout=10)

if api_response.status_code == 200:
return AuthAPIViews.success_response(api_response.json())
elif api_response.status_code == 401:
return AuthAPIViews.success_response([])
else:
return AuthAPIViews.error_response(
f"Payment account types API returned status {api_response.status_code}: {api_response.text[:200]}",
api_response.status_code,
)

except Timeout:
return AuthAPIViews.error_response("Payment account types API request timed out", 408)
except RequestException as e:
return AuthAPIViews.error_response(f"Could not connect to payment account types API: {str(e)}", 503)
except Exception as e:
return AuthAPIViews.error_response(f"Error: {str(e)}")


# Individual view functions for URL mapping
user_login = AuthAPIViews.user_login
user_logout = AuthAPIViews.user_logout
user_profile = AuthAPIViews.user_profile
external_profile = AuthAPIViews.external_profile
payment_accounts = AuthAPIViews.payment_accounts
payment_account_types = AuthAPIViews.payment_account_types
tyler_token = AuthAPIViews.tyler_token
2 changes: 2 additions & 0 deletions efile_app/efile/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from .auth_views import (
external_profile,
payment_account_types,
payment_accounts,
tyler_token,
user_login,
Expand Down Expand Up @@ -62,6 +63,7 @@
path("auth/tyler-token/", tyler_token, name="tyler_token"),
# Payment API endpoints
path("payment-accounts/", payment_accounts, name="payment_accounts"),
path("payment-account-types/", payment_account_types, name="payment_account_types"),
path("payment-fees/", payment_fees, name="payment_fees"),
# Filing API endpoints
path("filings/", get_filings, name="get_filings"),
Expand Down
54 changes: 54 additions & 0 deletions efile_app/efile/migrations/0007_complete_workflow_migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from django.db import migrations, models


STEP_MAPPINGS = {
"options": "filing_path",
"upload_first": "upload_documents",
"case_information": "extraction_review",
"documents": "organize_documents",
}


def migrate_saved_workflow_positions(apps, schema_editor):
FilingDraft = apps.get_model("efile", "FilingDraft")
for old_step, new_step in STEP_MAPPINGS.items():
FilingDraft.objects.filter(current_step=old_step).update(current_step=new_step)
FilingDraft.objects.exclude(workflow_version=2).update(workflow_version=2)


class Migration(migrations.Migration):
dependencies = [("efile", "0006_filingparty_party_type_name")]

operations = [
migrations.RunPython(migrate_saved_workflow_positions, migrations.RunPython.noop),
migrations.AlterField(
model_name="filingdraft",
name="current_step",
field=models.CharField(
choices=[
("options", "Options"),
("filing_path", "Filing"),
("upload_documents", "Upload documents"),
("extraction_review", "Confirm filing"),
("case_lookup", "Find your case"),
("case_confirmation", "Confirm your case"),
("document_checklist", "Check documents"),
("organize_documents", "Organize documents"),
("your_information", "Your information"),
("parties", "People in this filing"),
("party_details", "Person details"),
("case_questions", "Case questions"),
("payment", "Fees"),
("review", "Review"),
("confirmation", "Confirmation"),
],
default="options",
max_length=64,
),
),
migrations.AlterField(
model_name="filingdraft",
name="workflow_version",
field=models.PositiveSmallIntegerField(default=2),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 5.2.5 on 2026-08-11 00:21

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('efile', '0006_filingdocument_requested_optional_services'),
('efile', '0007_complete_workflow_migration'),
]

operations = [
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [("efile", "0008_merge_document_prep_and_people_migrations")]

operations = [
migrations.AddField(
model_name="filingdraft",
name="selected_payment_account_type",
field=models.CharField(max_length=50, blank=True),
),
migrations.AddField(
model_name="filingdraft",
name="quoted_fee_total",
field=models.CharField(max_length=50, blank=True),
),
migrations.AddField(
model_name="filingdraft",
name="quoted_fee_breakdown",
field=models.JSONField(default=list, blank=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 5.2.5 on 2026-08-11 12:19

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('efile', '0007_amount_in_controversy'),
('efile', '0009_filingdraft_payment_type_and_quoted_fees'),
]

operations = [
]
9 changes: 8 additions & 1 deletion efile_app/efile/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Status(models.TextChoices):
choices=get_workflow_step_choices(),
default=WorkflowStepKey.OPTIONS,
)
workflow_version = models.PositiveSmallIntegerField(default=1)
workflow_version = models.PositiveSmallIntegerField(default=2)

existing_case = models.CharField(
max_length=20,
Expand All @@ -80,6 +80,13 @@ class Status(models.TextChoices):

selected_payment_account_id = models.CharField(max_length=255, blank=True)
selected_payment_account_name = models.CharField(max_length=255, blank=True)
# Tyler's paymentAccountTypeCode for the selected account (e.g. "WV" for a fee
# waiver). Drives whether Review shows a fee total or waiver messaging.
selected_payment_account_type = models.CharField(max_length=50, blank=True)
# The fee quote shown on the Payment step, carried forward so Review can
# display the same numbers instead of telling the filer to go look again.
quoted_fee_total = models.CharField(max_length=50, blank=True)
quoted_fee_breakdown = models.JSONField(default=list, blank=True)

name_change_reason = models.TextField(blank=True)

Expand Down
4 changes: 2 additions & 2 deletions efile_app/efile/services/current_drafts.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def create_current_draft(
jurisdiction: str,
*,
current_step: WorkflowStepKey | str = WorkflowStepKey.OPTIONS,
workflow_version: int = 1,
workflow_version: int = 2,
) -> FilingDraft:
draft = create_draft(
user=_authenticated_user(request),
Expand All @@ -109,7 +109,7 @@ def ensure_current_draft(
request,
jurisdiction,
current_step=current_step or WorkflowStepKey.OPTIONS,
workflow_version=workflow_version or 1,
workflow_version=workflow_version or 2,
)
if current_step is not None:
set_current_step(draft, current_step)
Expand Down
2 changes: 1 addition & 1 deletion efile_app/efile/services/drafts.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def create_draft(
user,
jurisdiction: str,
current_step: WorkflowStepKey | str = WorkflowStepKey.OPTIONS,
workflow_version: int = 1,
workflow_version: int = 2,
) -> FilingDraft:
"""Create a durable draft owned by an authenticated user."""

Expand Down
68 changes: 66 additions & 2 deletions efile_app/efile/static/css/common.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,51 @@
/* Single source of truth for color across every screen.
Anything user-facing should reference a token from this block rather than
its own hex value, so the app reads as one product instead of a set of
pages that each invented a slightly different blue. */
:root {
/* Brand blues. --better-blue is the one action color: primary buttons,
links, and accents all use it. */
--suffolk-blue: #1e3a5f;
--better-blue: #2c5aa0;
--primary-btn-color: #007bff;
--brand-blue-hover: #24497f;
--brand-blue-active: #1e3a5f;

/* Older pages theme their buttons through this name. Pointing it at the
brand blue keeps them in step with the rest of the app. */
--primary-btn-color: var(--better-blue);

/* Text tiers. Every value below clears WCAG AA (4.5:1) on white and on
both tinted surfaces defined here. */
--text-heading: #1e3a5f;
--text-body: #48576c;
--text-muted: #616c82;

/* Surfaces */
--surface-subtle: #f6f9fd;
--surface-accent: #eef5ff;
--light-blue-background: #f8f9fa;

/* Borders. --border-strong is for edges that outline a control; the
lighter two are decorative dividers. */
--border-subtle: #e3e8ef;
--border-default: #dce3ec;
--border-accent: #cbdcf1;
--border-strong: #7d8ca3;

/* Status */
--success: #28a745;
--success-text: #16703a;
--success-surface: #e5f6eb;
--success-border: #cde8d5;
--failure: #dc3545;
--light-blue-background: #f8f9fa;
--danger-icon: #b23b3b;
--warning-surface: #fffaf0;
--warning-border: #ead8ad;

/* Links follow the brand blue rather than Bootstrap's default indigo. */
--bs-link-color: var(--better-blue);
--bs-link-hover-color: var(--brand-blue-hover);
--bs-link-color-rgb: 44, 90, 160;
}

body {
Expand All @@ -26,4 +67,27 @@ h1 {
h2 {
color: var(--better-blue);
font-weight: 500;
}

/* One primary action color on every screen. Bootstrap themes buttons through
its own custom properties, so setting those keeps the hover, active, and
disabled states in step instead of repainting only the resting state. */
.btn-primary {
--bs-btn-bg: var(--better-blue);
--bs-btn-border-color: var(--better-blue);
--bs-btn-hover-bg: var(--brand-blue-hover);
--bs-btn-hover-border-color: var(--brand-blue-hover);
--bs-btn-active-bg: var(--brand-blue-active);
--bs-btn-active-border-color: var(--brand-blue-active);
--bs-btn-disabled-bg: var(--better-blue);
--bs-btn-disabled-border-color: var(--better-blue);
}

.btn-outline-primary {
--bs-btn-color: var(--better-blue);
--bs-btn-border-color: var(--better-blue);
--bs-btn-hover-bg: var(--better-blue);
--bs-btn-hover-border-color: var(--better-blue);
--bs-btn-active-bg: var(--brand-blue-active);
--bs-btn-active-border-color: var(--brand-blue-active);
}
4 changes: 2 additions & 2 deletions efile_app/efile/static/css/components/search-dropdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
.search-dropdown-input:focus {
border-color: #86b7fe;
outline: 0;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
box-shadow: 0 0 0 0.25rem rgba(44, 90, 160, 0.25);
}

.search-dropdown-input:disabled {
Expand Down Expand Up @@ -93,7 +93,7 @@

.search-dropdown-selected:focus-within {
border-color: #86b7fe;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
box-shadow: 0 0 0 0.25rem rgba(44, 90, 160, 0.25);
}

.search-dropdown-selected .selected-text {
Expand Down
Loading