Repository: cal-itp/benefits

Issue:
Django form to capture user's EligibilityVerifier selection
## Background

Building on #320 and #332, once a `TransitAgency` has multiple `EligibilityVerifier` references, the user needs a way to select which one they will use for verification.

Django has the [`ChoiceField`](https://docs.djangoproject.com/en/3.2/ref/forms/fields/#choicefield) which can use the `widget=RadioSelect` to render as a list of radio buttons. The field takes a list of `choices`, each a tuple where the first item is the value and the second is the label:

```
from django import forms

choices = [("value1", "Label One"), ("value2", "Label Two")]
field = forms.ChoiceField(choices=choices, widget=forms.RadioSelect)
```

See e.g. https://stackoverflow.com/a/5925240/453168

## Tasks

* [x] Create a new form class like `EligibilityVerifierSelectionForm` in [`benefits/eligibility/forms.py`](https://github.com/cal-itp/benefits/blob/dev/benefits/eligibility/forms.py); form should `POST` to `eligibility:index`
* [x] Add a `ChoiceField` using `widget=RadioSelect`
* [x] Create an `__init__()` method accepting an `agency` parameter
* [x] Seed the `ChoiceField.choices` from the `agency.eligibility_verifiers` property, using the above `choices` structure as an example
* [x] Rework the [`eligibility:index` view](https://github.com/cal-itp/benefits/blob/dev/benefits/eligibility/views.py#L16) to handle both `GET` and `POST`
  * for `GET`: If agency has multiple verifiers, initialize form with the selected agency's verifiers and send to the template; otherwise store the one verifier in session and immediately redirect to `eligibility:start`
  * for `POST`: store the selected verifier in session and redirect to `eligibility:start`


Discussion:

Resolving patch:
diff --git a/benefits/core/views.py b/benefits/core/views.py
--- a/benefits/core/views.py
+++ b/benefits/core/views.py
@@ -61,7 +61,7 @@ def index(request):
 def agency_index(request, agency):
     """View handler for an agency entry page."""
     session.reset(request)
-    session.update(request, agency=agency, verifier=agency.eligibility_verifiers.all()[0], origin=agency.index_url)
+    session.update(request, agency=agency, origin=agency.index_url)
 
     page = viewmodels.Page(
         content_title=_index_content_title(),
diff --git a/benefits/eligibility/forms.py b/benefits/eligibility/forms.py
--- a/benefits/eligibility/forms.py
+++ b/benefits/eligibility/forms.py
@@ -12,6 +12,22 @@
 logger = logging.getLogger(__name__)
 
 
+class EligibilityVerifierSelectionForm(forms.Form):
+    """Form to capture eligibility verifier selection."""
+
+    action_url = "eligibility:index"
+    method = "POST"
+
+    verifier = forms.ChoiceField(label="", widget=forms.RadioSelect)
+
+    submit_value = _("eligibility.pages.index.button")
+
+    def __init__(self, agency: models.TransitAgency, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        choices = [(v.id, v.selection_label) for v in agency.eligibility_verifiers.all()]
+        self.fields["verifier"].choices = choices
+
+
 class EligibilityVerificationForm(forms.Form):
     """Form to collect eligibility verification details."""
 
diff --git a/benefits/eligibility/views.py b/benefits/eligibility/views.py
--- a/benefits/eligibility/views.py
+++ b/benefits/eligibility/views.py
@@ -8,38 +8,49 @@
 from django.utils.translation import pgettext, gettext as _
 
 from benefits.core import middleware, recaptcha, session, viewmodels
+from benefits.core.models import EligibilityVerifier
 from benefits.core.views import PageTemplateResponse, _index_image
 from . import analytics, api, forms
 
 
 @decorator_from_middleware(middleware.AgencySessionRequired)
-@decorator_from_middleware(middleware.VerifierSessionRequired)
 def index(request):
-    """View handler for the eligibility verification getting started screen."""
+    """View handler for the eligibility verifier selection form."""
 
     session.update(request, eligibility_types=[], origin=reverse("eligibility:index"))
+    agency = session.agency(request)
+
+    eligibility_start = reverse("eligibility:start")
 
     page = viewmodels.Page(
         title=_("eligibility.pages.index.title"),
         content_title=_("eligibility.pages.index.content_title"),
-        media=[
-            viewmodels.MediaItem(
-                icon=viewmodels.Icon("idcardcheck", pgettext("image alt text", "core.icons.idcardcheck")),
-                heading=_("eligibility.pages.index.items[0].title"),
-                details=_("eligibility.pages.index.items[0].text"),
-            ),
-            viewmodels.MediaItem(
-                icon=viewmodels.Icon("bankcardcheck", pgettext("image alt text", "core.icons.bankcardcheck")),
-                heading=_("eligibility.pages.index.items[1].title"),
-                details=_("eligibility.pages.index.items[1].text"),
-            ),
-        ],
-        paragraphs=[_("eligibility.pages.index.p[0]")],
+        forms=forms.EligibilityVerifierSelectionForm(agency=agency),
         image=_index_image(),
-        button=viewmodels.Button.primary(text=_("eligibility.pages.index.button"), url=reverse("eligibility:confirm")),
     )
 
-    return PageTemplateResponse(request, page)
+    if request.method == "POST":
+        form = forms.EligibilityVerifierSelectionForm(data=request.POST, agency=agency)
+
+        if form.is_valid():
+            verifier_id = form.cleaned_data.get("verifier")
+            verifier = EligibilityVerifier.objects.get(id=verifier_id)
+            session.update(request, verifier=verifier)
+
+            response = redirect(eligibility_start)
+        else:
+            # form was not valid, allow for correction/resubmission
+            page.forms = [form]
+            response = PageTemplateResponse(request, page)
+    else:
+        if agency.eligibility_verifiers.count() == 1:
+            verifier = agency.eligibility_verifiers.first()
+            session.update(request, verifier=verifier)
+            response = redirect(eligibility_start)
+        else:
+            response = PageTemplateResponse(request, page)
+
+    return response
 
 
 @decorator_from_middleware(middleware.AgencySessionRequired)


Test patch: