Add document preparation flow - #147
Open
nonprofittechy wants to merge 15 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR continues the staged migration of the filing flow by replacing the remaining document-preparation bridge with durable-model screens for document checklist and per-document organization, while consolidating upload + extraction persistence into a shared service and persisting new draft state.
Changes:
- Add Document Checklist and Organize Documents screens (views, templates, JS, CSS) and wire them into the v2 workflow.
- Extract upload + lead-document analysis into a shared
document_uploadsservice and improve cleanup when removing documents. - Persist checklist acknowledgement state to
FilingDraft(model + migration) and add/adjust tests for the new flow behavior.
Reviewed changes
Copilot reviewed 21 out of 24 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| efile_app/efile/workflow.py | Optimizes incomplete-party detection for QuerySet-backed parties and adjusts legacy-workflow detection for shared steps without a draft. |
| efile_app/efile/views/upload_documents.py | Switches upload path to shared upload_files service and deletes S3 objects / stale guesses on removal. |
| efile_app/efile/views/organize_documents.py | Adds new organize-documents endpoint to persist per-document filing metadata and ordering. |
| efile_app/efile/views/extraction_review.py | Ensures draft step state is persisted before redirecting to the next step. |
| efile_app/efile/views/document_checklist.py | Adds checklist screen with inline “missing document” upload and acknowledgement persistence. |
| efile_app/efile/urls.py | Routes document checklist and organize-documents to the new v2 views (removes legacy redirect for those steps). |
| efile_app/efile/tests/test_workflow.py | Adds coverage for legacy default when shared steps are evaluated without a draft context. |
| efile_app/efile/tests/test_reorganized_start.py | Updates mocks for extracted upload logic and adds removal cleanup assertions; adjusts bridging test to target people screen. |
| efile_app/efile/tests/test_document_prep.py | Adds end-to-end tests for checklist acknowledgement, inline upload, and organize-documents persistence. |
| efile_app/efile/templates/efile/upload_documents.html | Updates user copy to reflect analysis of first PDF and deferred main-document choice. |
| efile_app/efile/templates/efile/organize_documents.html | New template for per-document organization (main doc selection, metadata, reordering, courtesy email). |
| efile_app/efile/templates/efile/document_checklist.html | New template for checklist review, inline upload, and acknowledgement gating. |
| efile_app/efile/templates/efile/case_confirmation.html | Improves i18n-safe fallbacks for missing case fields. |
| efile_app/efile/static/js/upload-documents.js | Updates analysis messaging and adds redirect handling for POST responses. |
| efile_app/efile/static/js/organize-documents.js | New client behavior for organizing documents: loads dropdowns, manages ordering UI, submits JSON payload. |
| efile_app/efile/static/js/document-checklist.js | New client behavior for inline checklist uploads. |
| efile_app/efile/static/css/reorganized-flow.css | Adds styling for checklist and organize-documents UI components. |
| efile_app/efile/services/drafts.py | Exposes checklist acknowledgement in draft snapshot; existing upload/case persistence utilities used by new screens. |
| efile_app/efile/services/document_uploads.py | New shared upload + lead analysis implementation for both intake and checklist uploads. |
| efile_app/efile/models.py | Adds document_checklist_acknowledged field to FilingDraft. |
| efile_app/efile/migrations/0005_document_checklist_state.py | Migration to add the new checklist acknowledgement column. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+45
to
+48
| document.filing_component_code = str(item.get("filing_component") or "")[:100] | ||
| document.filing_component_name = str(item.get("filing_component_name") or "")[:255] | ||
| document.courtesy_copy_email = str(item.get("courtesy_copy_email") or "")[:254] | ||
| if document.pk == main_document_id: |
Comment on lines
+228
to
+232
| }); | ||
| const result = await response.json(); | ||
| if (!response.ok || !result.success) throw new Error(result.error || "Could not save document details."); | ||
| window.location.assign(result.redirect_url); | ||
| } catch (error) { |
Validate and strip courtesy copy email server-side before persisting, and guard the checklist/organize JS fetch handlers against redirected (session-expired) responses before parsing JSON, matching the pattern already used in upload-documents.js. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
nonprofittechy
force-pushed
the
workflow/document-prep
branch
from
August 10, 2026 22:46
6d907fe to
d992ea0
Compare
nonprofittechy
marked this pull request as ready for review
August 10, 2026 22:47
boto3's upload_fileobj closes the Django UploadedFile it's given once the S3 upload completes. upload_files() then reused that same file object afterward to run LLM field extraction on the lead document, raising "ValueError: I/O operation on closed file." Run the lead analysis before the S3 upload instead, while the file is still open. Also log the traceback on upload failures instead of swallowing it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Court, case category, and case type on the extraction review page were free-text inputs that only ever wrote *_name columns. Tyler's e-filing API requires exact court/category/type codes, so a new case could never set draft.court_code -- which left organize_documents stuck permanently on "Missing required court parameter" once a filer reached it, with no way to recover even after re-entering a court name. - Replace the free-text court/category/type/filing-type inputs with cascading dropdowns backed by the existing /api/dropdowns/ endpoints, matching how organize_documents already resolves these values. A matched extraction guess renders as a reviewed value with an Edit affordance; an unmatched or absent guess renders as a plain choice to make, so reviewing, correcting, and filling in gaps are visually distinct. - When nothing was extracted from the document at all, say so plainly instead of presenting empty fields as "here's what we found," and link back to try a different upload. - Require a matched court/category/type before a new case can advance, both client- and server-side. - Persist a best-effort filing type guess onto the lead document so organize_documents can pre-fill it. - organize_documents now redirects back to fix the court instead of dead-ending on the missing-parameter error if a draft somehow reaches it without one. - Add the missing "request a certified copy" option next to the courtesy-copy-email checkbox, sourced from the same optional-services API the old expert form used, and persist selections per document. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…P error text - Group optional-service checkboxes so common ones (certified copy, courtesy copy, expedited, etc.) show by default and the rest sit behind a "Show more options" toggle -- some courts return over a dozen services, which buried the ones filers actually look for. - Add a return_to=review mechanism: editing a step from the Review screen now saves and returns to Review instead of continuing through the rest of the linear workflow. Wired into extraction_review and organize_documents here; people/payment pick it up in later commits. - describe_efsp_error() only read body["error"/"message"/"detail"], so Tyler's "Malformed Interview" errors (type + description, no error key) fell through to a bare "returned status 500" -- exactly what reached the filer for a docket number entered on a would-be new case. Surface body["description"] too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tyler rejects a docket number on a new case ("doesn't allow subsequent
filing into non-indexed cases"), so presenting it as a normal
always-visible field invited exactly the input that gets rejected.
Hide it behind a "This case already has a number from the court"
checkbox instead; the field is shown plainly for an existing case,
where it's expected. Switching from existing back to new clears
whatever was entered, since that's the value the API would reject.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
test_unmigrated_people_screen_bridges_to_legacy_flow tested your_information() falling back to the legacy expert_form for an unmigrated (v1) draft. It was deliberately deleted in 8d269e9 ("Add people and case question flow") once your_information was actually implemented and that fallback no longer applied -- but document-prep's copy of this test file predates that deletion and still had it, so merging document-prep into people resurrected it instead of respecting the delete. It fails outright now: your_information always forces workflow_version=2 and renders normally, never redirecting to expert_form. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
"Which PDF is the main document?" as a radio group made no sense with a single document -- there was nothing to actually choose. Show an informational sentence instead and submit that document's id via a hidden field, keeping the same form contract; the radio group still appears once there's more than one document to pick from. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A name suffix (Jr., Sr., III, ...) has to exactly match one of the
court's own codes to be accepted -- it's a closed list from Tyler's
codes API (.../courts/{court_id}/name_suffixes), the same shape as the
other code lookups here. Proxies it the same way so the suffix field
can become a dropdown instead of free text.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Checked ~/EfileProxyServer for what "Malformed Interview" and plain error messages the proxy actually raises (FilingError call sites in Ecf4Filer.java, FilingInformationDocassembleJacksonDeserializer.java, and EcfCourtSpecificSerializer.java -- the deserializer that parses this app's own efile_case_category/al_court_bundle payload shape). Not all of it is cataloged; wrong_vars/required_vars were already handled well by _describe_var, so this focuses on the free-text messages that weren't: docket number on a non-indexed case (belt and suspenders alongside the docket-number checkbox), a subsequent filing missing its docket number, oversized documents (single and combined), an empty filing-type list for the chosen case category/type, and amount-in-controversy -- a genuine gap this app doesn't collect yet, called out as such rather than implying it's self-serve fixable. Unrecognized messages still pass through unchanged, same as before. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Implements the "amount in controversy" gap flagged by describe_efsp_error's new hint: the EFSP rejects a filing whose filing type has amountincontroversy="Required" (from Tyler's filing-types codes API) unless the top-level amount_in_controversy field is set, and this app never collected or sent it. This is the data-capture half: prioritize_options() now passes through extra fields like amountincontroversy instead of dropping everything but code/name, organize-documents.js records whether the selected filing type requires it, and organize_documents persists that onto FilingDocument.filing_requires_amount_in_controversy. Asking for the actual dollar amount (case_questions) and sending it in the filing payload land in the following commits, since those live on other branches in this stack. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
case_questions saves it directly on FilingDraft (not through write_case_data, since it isn't config-driven), but read_case_data never echoed it back -- so the frontend had no way to read it for the fee quote or submission payload. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
get_filing_types logs response.headers.get("Content-Type") right
before the mocked call; a fake response without .headers raised
AttributeError there, caught by the view's own except Exception and
turned into a 400 that looked like the real thing was broken.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fourth PR in the staged filing-flow migration. This replaces the remaining document-preparation bridge with two durable-model screens:
FilingDraft/FilingDocumentStacked on #146; review only commit
fc63330.Screenshots
Document checklist
Organize documents
Validation
uv run pytest -q— 202 passednpm run test:unit— 17 passedgit diff --checkpassed