Coverage for benefits/eligibility/forms.py: 95%
65 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-29 21:21 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-29 21:21 +0000
1"""
2The eligibility application: Form definition for the eligibility verification flow.
3"""
5import logging
7from django import forms
8from django.utils.translation import gettext_lazy as _
10from benefits.routes import routes
11from benefits.core import models, recaptcha, widgets
13logger = logging.getLogger(__name__)
16class EnrollmentFlowSelectionForm(forms.Form):
17 """Form to capture enrollment flow selection."""
19 action_url = routes.ELIGIBILITY_INDEX
20 id = "form-flow-selection"
21 method = "POST"
23 flow = forms.ChoiceField(label="", widget=widgets.FlowRadioSelect)
24 # sets label to empty string so the radio_select template can override the label style
25 submit_value = _("Choose this benefit")
27 def __init__(self, agency: models.TransitAgency, *args, **kwargs):
28 super().__init__(*args, **kwargs)
29 flows = agency.enrollment_flows.filter(supported_enrollment_methods__contains=models.EnrollmentMethods.DIGITAL)
31 # second element is not used since we render the whole label using selection_label_template,
32 # therefore set to None
33 flow_field = self.fields["flow"]
34 flow_field.choices = [(f.id, None) for f in flows]
35 flow_field.widget.selection_label_templates = {f.id: f.selection_label_template for f in flows}
36 flow_field.widget.attrs.update({"data-custom-validity": _("Please choose a transit benefit.")})
37 self.use_custom_validity = True
39 def clean(self):
40 if not recaptcha.verify(self.data): 40 ↛ 41line 40 didn't jump to line 41 because the condition on line 40 was never true
41 raise forms.ValidationError("reCAPTCHA failed")
44class EligibilityVerificationForm(forms.Form):
45 """Form to collect eligibility verification details."""
47 action_url = routes.ELIGIBILITY_CONFIRM
48 id = "form-eligibility-verification"
49 method = "POST"
51 submit_value = _("Find my record")
52 submitting_value = _("Checking")
54 def __init__(
55 self,
56 title,
57 headline,
58 blurb,
59 name_label,
60 name_placeholder,
61 name_help_text,
62 sub_label,
63 sub_placeholder,
64 sub_help_text,
65 name_max_length=None,
66 sub_input_mode=None,
67 sub_max_length=None,
68 sub_pattern=None,
69 sub_custom_validity=None,
70 name_custom_validity=None,
71 *args,
72 **kwargs,
73 ):
74 """Initialize a new EligibilityVerification form.
76 Args:
77 title (str): The page (i.e. tab) title for the form's page.
79 headline (str): The <h1> on the form's page.
81 blurb (str): Intro <p> on the form's page.
83 name_label (str): Label for the name form field.
85 name_placeholder (str): Field placeholder for the name form field.
87 name_help_text (str): Extra help text for the name form field.
89 sub_label (str): Label for the sub form field.
91 sub_placeholder (str): Field placeholder for the sub form field.
93 sub_help_text (str): Extra help text for the sub form field.
95 name_max_length (int): The maximum length accepted for the 'name' API field before sending an API request
97 sub_input_mode (str): Input mode can be "numeric", "tel", "search", etc. to override default "text" keyboard on
98 mobile devices
100 sub_max_length (int): The maximum length accepted for the 'sub' API field before sending an API request
102 sub_pattern (str): A regular expression used to validate the 'sub' API field before sending an API request
104 Extra args and kwargs are passed through to the underlying django.forms.Form.
105 """
106 super().__init__(auto_id=True, label_suffix="", *args, **kwargs)
108 self.title = title
109 self.headline = headline
110 self.blurb = blurb
111 self.classes = "eligibility-verification-form"
113 sub_widget = widgets.FormControlTextInput(placeholder=sub_placeholder)
114 if sub_pattern:
115 sub_widget.attrs.update({"pattern": sub_pattern})
116 if sub_input_mode:
117 sub_widget.attrs.update({"inputmode": sub_input_mode})
118 if sub_max_length:
119 sub_widget.attrs.update({"maxlength": sub_max_length})
120 if sub_custom_validity:
121 sub_widget.attrs.update({"data-custom-validity": sub_custom_validity})
122 self.use_custom_validity = True
124 self.fields["sub"] = forms.CharField(
125 label=sub_label,
126 widget=sub_widget,
127 help_text=sub_help_text,
128 )
130 name_widget = widgets.FormControlTextInput(placeholder=name_placeholder)
131 if name_max_length:
132 name_widget.attrs.update({"maxlength": name_max_length})
133 if name_custom_validity:
134 name_widget.attrs.update({"data-custom-validity": name_custom_validity})
135 self.use_custom_validity = True
137 self.fields["name"] = forms.CharField(label=name_label, widget=name_widget, help_text=name_help_text)
139 def clean(self):
140 if not recaptcha.verify(self.data): 140 ↛ 141line 140 didn't jump to line 141 because the condition on line 140 was never true
141 raise forms.ValidationError("reCAPTCHA failed")
144class CSTAgencyCard(EligibilityVerificationForm):
145 """EligibilityVerification form for the CST Agency Card."""
147 def __init__(self, *args, **kwargs):
148 super().__init__(
149 title=_("Agency card information"),
150 headline=_("Let’s find the record of your transit benefit."),
151 blurb=_(
152 "We use the information on your CST Agency Card to find the record of your transit benefit in our system."
153 ),
154 name_label=_("Last Name"),
155 name_placeholder="Hernandez-Demarcos",
156 name_help_text=_(
157 "Please enter your last name the same way it is printed on your card, including capital letters and hyphens."
158 ),
159 sub_label=_("Agency Card number"),
160 sub_help_text=_("This is a 5-digit number on the front and back of your card."),
161 sub_placeholder="12345",
162 name_max_length=255,
163 sub_input_mode="numeric",
164 sub_max_length=5,
165 sub_pattern=r"\d{5}",
166 sub_custom_validity=_("Please enter a 5-digit number."),
167 name_custom_validity=_("Please enter your last name."),
168 *args,
169 **kwargs,
170 )
173class MSTCourtesyCard(EligibilityVerificationForm):
174 """EligibilityVerification form for the MST Courtesy Card."""
176 def __init__(self, *args, **kwargs):
177 super().__init__(
178 title=_("Agency card information"),
179 headline=_("Let’s find the record of your transit benefit."),
180 blurb=_(
181 "We use the information on your MST Courtesy Card to find the record of your transit benefit in our system."
182 ),
183 name_label=_("Last Name"),
184 name_placeholder="Garcia",
185 name_help_text=_(
186 "Please enter your last name the same way it is printed on your card, including capital letters and hyphens."
187 ),
188 sub_label=_("Courtesy Card number"),
189 sub_help_text=_("This is a 5-digit number on the front and back of your card."),
190 sub_placeholder="12345",
191 name_max_length=255,
192 sub_input_mode="numeric",
193 sub_max_length=5,
194 sub_pattern=r"\d{5}",
195 sub_custom_validity=_("Please enter a 5-digit number."),
196 name_custom_validity=_("Please enter your last name."),
197 *args,
198 **kwargs,
199 )
202class SBMTDMobilityPass(EligibilityVerificationForm):
203 """EligibilityVerification form for the SBMTD Reduced Fare Mobility ID."""
205 def __init__(self, *args, **kwargs):
206 super().__init__(
207 title=_("Agency card information"),
208 headline=_("Let’s find the record of your transit benefit."),
209 blurb=_(
210 "We use the information on your SBMTD Reduced Fare Mobility ID card to find the record of your transit "
211 + "benefit in our system."
212 ),
213 name_label=_("Last Name"),
214 name_placeholder="Garcia",
215 name_help_text=_(
216 "Please enter your last name the same way it is printed on your card, including capital letters and hyphens."
217 ),
218 sub_label=_("Reduced Fare Mobility ID card number"),
219 sub_help_text=_("This is a 4-digit number on the back of your card."),
220 sub_placeholder="1234",
221 name_max_length=255,
222 sub_input_mode="numeric",
223 sub_max_length=4,
224 sub_pattern=r"\d{4}",
225 sub_custom_validity=_("Please enter a 4-digit number."),
226 name_custom_validity=_("Please enter your last name."),
227 *args,
228 **kwargs,
229 )