Coverage for benefits / in_person / forms.py: 74%
44 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-01 15:39 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-01 15:39 +0000
1"""
2The in-person eligibility application: Form definition for the
3in-person eligibility verification flow, in which a
4transit agency employee manually verifies a rider's eligibility.
5"""
7from dataclasses import dataclass
9from django import forms
11from benefits.core import models
12from benefits.enrollment.forms import CardTokenizeFailForm, CardTokenizeSuccessForm # noqa
13from benefits.routes import routes
16@dataclass
17class EligibilityPolicy:
18 details: str
21class InPersonEligibilityForm(forms.Form):
22 """Form to capture eligibility for in-person verification flow selection."""
24 action_url = routes.IN_PERSON_ELIGIBILITY
25 id = "form-flow-selection"
26 method = "POST"
28 flow = forms.ChoiceField(label="Choose an eligibility type to qualify this rider.", widget=forms.widgets.RadioSelect)
30 cancel_url = routes.ADMIN_INDEX
32 flow_field_error_message = "Choose an eligibility type"
33 verified_field_error_message = "Check the box to verify you have confirmed eligibility"
35 eligibility_policies = {
36 models.SystemName.COURTESY_CARD.value: EligibilityPolicy(
37 details="I confirmed this rider’s identity using a government-issued ID and verified they possess an MST "
38 "Courtesy Card."
39 ),
40 models.SystemName.MEDICARE.value: EligibilityPolicy(
41 details="I confirmed this rider’s identity using a government-issued ID and verified they possess a valid "
42 "Medicare card."
43 ),
44 models.SystemName.OLDER_ADULT.value: EligibilityPolicy(
45 details="I confirmed this rider’s identity using a government-issued ID and verified they are age 65 or older."
46 ),
47 models.SystemName.REDUCED_FARE_MOBILITY_ID.value: EligibilityPolicy(
48 details="I confirmed this rider’s identity using a government-issued ID and verified they possess an SBMTD "
49 "Reduced Fare Mobility ID."
50 ),
51 }
53 def __init__(self, agency: models.TransitAgency, *args, **kwargs):
54 super().__init__(*args, **kwargs)
55 flows = agency.enrollment_flows.filter(supported_enrollment_methods__contains=models.EnrollmentMethods.IN_PERSON)
57 self.classes = "in-person-eligibility-form"
58 flow_field = self.fields["flow"]
59 flow_field.choices = [(f.id, f.label) for f in flows]
60 flow_field.widget.attrs.update({"data-custom-validity": self.flow_field_error_message})
62 # dynamically add a BooleanField for each flow
63 for flow in flows:
64 field_id = f"verified_{flow.id}"
65 self.fields[field_id] = forms.BooleanField(
66 required=False, # `clean()` will handle requiring the specific field
67 label=self.get_policy_details(flow),
68 widget=forms.widgets.CheckboxInput(attrs={"class": "d-none"}), # start out hidden
69 )
70 field = self.fields[field_id]
71 field.hide = True
72 field.widget.attrs.update({"data-custom-validity": self.verified_field_error_message})
74 self.use_custom_validity = True
76 def get_policy_details(self, flow: models.EnrollmentFlow):
77 policy = self.eligibility_policies.get(flow.system_name, None)
78 return policy.details if policy else None
80 def clean(self):
81 cleaned_data = super().clean()
83 flow_field_name = "flow"
84 selected_flow = cleaned_data.get(flow_field_name)
86 if not selected_flow:
87 self.add_error(flow_field_name, self.flow_field_error_message)
88 else:
89 verified_field_name = f"verified_{selected_flow}"
90 verified = cleaned_data.get(verified_field_name)
91 if not verified:
92 self.add_error(verified_field_name, self.verified_field_error_message)