Forms & Intake
What this module does
Orchid has a full dynamic form engine used for:
- Intake applications — when a donor or carrier applies to an agency
- Medical release forms — authorization forms for sharing medical records
- Closing forms — end-of-journey documentation
- Custom agency forms — arbitrary questionnaires an agency assigns to clients
- Public submissions — unauthenticated forms for external applicants
Forms are composed of typed questions, support different question types (text, multiple choice, date, file upload), and store all submissions per user/case.
Business value
Every piece of structured information Orchid collects from clients comes through forms. A donor’s medical history, an IP’s preferences, a carrier’s previous pregnancy information — all of it flows through the form engine. Without forms, the matching and screening modules have nothing to work with.
Key files
Directoryorchid/
Directorymodels/
- form.py 41 KB — Form, FormQuestion, UserForm, UserFormAnswer, IntakeFormSubmission, GeneralFormSubmission, MedicalReleaseForm
Directoryviews/
- forms.py 29 KB — form rendering views
- form_intake.py 51 KB — intake flow views
- circle_intake.py 3 KB — Circle partner agency intake
Directoryapi/
- forms.py 45 KB — form operations API
- external_form.py 32 KB — public/unauthenticated form submissions
Directoryinfo/
- prebuilt_forms.py 98 KB — pre-built question bank definitions
Directorytemplates/
Directoryforms/ — form rendering templates
- …
- macros_form_questions.html — question type rendering macros
Data model
erDiagram Form { int id int agency_id string name string form_type bool is_active } FormQuestion { int form_id int position string question_type string question_text bool is_required json options } UserForm { int user_id int case_id int form_id string status datetime submitted_at } UserFormAnswer { int user_form_id int question_id text answer string s3_key } IntakeFormSubmission { int user_id int agency_id string submission_type } GeneralFormSubmission { int form_id string external_email json answers }
Form ||--o{ FormQuestion : "has" UserForm }|--|| Form : "is instance of" UserForm ||--o{ UserFormAnswer : "has" Form ||--o{ IntakeFormSubmission : "has" Form ||--o{ GeneralFormSubmission : "has"Form types
form_type | Used for | Who fills it out |
|---|---|---|
'intake' | Donor/carrier application | Authenticated user |
'medical_release' | Medical record authorization | Authenticated user |
'closing' | End-of-case documentation | Authenticated user |
'general' | Custom agency questionnaires | Authenticated user |
'external' | Public inquiry/application | Unauthenticated visitor |
Question types
FormQuestion.question_type determines how the question is rendered and what kind of answer is stored:
| Type | Rendered as | Answer stored as |
|---|---|---|
'text' | Single-line text input | String |
'textarea' | Multi-line text area | String |
'multiple_choice' | Radio buttons | String (selected option) |
'checkboxes' | Checkboxes | JSON array |
'date' | Date picker | Date string |
'file' | File uploader | S3 key |
'yes_no' | Yes/No radio | 'yes' or 'no' |
Form submission lifecycle
1. Agency admin creates Form + FormQuestion records (either custom-built or from prebuilt_forms.py question bank)
2. Form is assigned to a user via a workflow task (CaseTask) → UserForm record created with status='pending'
3. User logs into /user portal → sees their assigned forms → navigates to /forms/form/<id>
4. User fills out the form → saves in progress → UserFormAnswer records created/updated
5. User submits the form → UserForm.status = 'submitted' → Workflow task marked complete → Admin notified
6. Admin reviews submission in admin portalIntake forms — the special case
Intake forms (form_type = 'intake') are the application forms that unauthenticated prospective donors/carriers fill out before they have a login. The intake flow at /forms/ (handled by form_intake.py, 51 KB) handles:
- Public landing page for the agency’s application
- reCAPTCHA verification
- Form rendering for unauthenticated visitors
- On submission: creating a
Useraccount andIntakeFormSubmissionrecord - Sending a confirmation email via SendGrid
The Circle intake flow
orchid/views/circle_intake.py handles a separate intake path for Circle — a partner agency’s referral system. The Circle intake is accessible at /circle/ and has different branding and routing than the standard intake, but it uses the same underlying form models.
External (public) form submissions
orchid/api/external_form.py handles form submissions from unauthenticated external users — people who fill out a form on an agency’s public website. These create GeneralFormSubmission records without requiring a login.
Key difference from intake forms: external submissions do not create user accounts automatically. They are reviewed by agency staff who then decide whether to create an account for the person.
prebuilt_forms.py — the question bank
orchid/info/prebuilt_forms.py (98 KB) defines a library of reusable question sets as Python dictionaries. When an agency builds a new intake form, they can pull from this library instead of creating questions from scratch.
Example structure:
PREBUILT_QUESTIONS = { 'personal_information': [ {'code': 'first_name', 'type': 'text', 'label': 'First Name', 'required': True}, {'code': 'date_of_birth', 'type': 'date', 'label': 'Date of Birth', 'required': True}, # ... ], 'medical_history': [ # ... ],}PDF printing
Forms can be printed to PDF via dedicated view routes:
/forms/<type>/<case_id>/form/<id>/print/forms/<type>/<case_id>/closing-form/<id>/print/forms/<type>/<case_id>/release-form/<id>/print/forms/<type>/custom-profile/<id>/printThese render PDF-optimized templates in templates/pdf/ rather than the standard UI templates.