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

1""" 

2The eligibility application: Form definition for the eligibility verification flow. 

3""" 

4 

5import logging 

6 

7from django import forms 

8from django.utils.translation import gettext_lazy as _ 

9 

10from benefits.routes import routes 

11from benefits.core import models, recaptcha, widgets 

12 

13logger = logging.getLogger(__name__) 

14 

15 

16class EnrollmentFlowSelectionForm(forms.Form): 

17 """Form to capture enrollment flow selection.""" 

18 

19 action_url = routes.ELIGIBILITY_INDEX 

20 id = "form-flow-selection" 

21 method = "POST" 

22 

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") 

26 

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) 

30 

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 

38 

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") 

42 

43 

44class EligibilityVerificationForm(forms.Form): 

45 """Form to collect eligibility verification details.""" 

46 

47 action_url = routes.ELIGIBILITY_CONFIRM 

48 id = "form-eligibility-verification" 

49 method = "POST" 

50 

51 submit_value = _("Find my record") 

52 submitting_value = _("Checking") 

53 

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. 

75 

76 Args: 

77 title (str): The page (i.e. tab) title for the form's page. 

78 

79 headline (str): The <h1> on the form's page. 

80 

81 blurb (str): Intro <p> on the form's page. 

82 

83 name_label (str): Label for the name form field. 

84 

85 name_placeholder (str): Field placeholder for the name form field. 

86 

87 name_help_text (str): Extra help text for the name form field. 

88 

89 sub_label (str): Label for the sub form field. 

90 

91 sub_placeholder (str): Field placeholder for the sub form field. 

92 

93 sub_help_text (str): Extra help text for the sub form field. 

94 

95 name_max_length (int): The maximum length accepted for the 'name' API field before sending an API request 

96 

97 sub_input_mode (str): Input mode can be "numeric", "tel", "search", etc. to override default "text" keyboard on 

98 mobile devices 

99 

100 sub_max_length (int): The maximum length accepted for the 'sub' API field before sending an API request 

101 

102 sub_pattern (str): A regular expression used to validate the 'sub' API field before sending an API request 

103 

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) 

107 

108 self.title = title 

109 self.headline = headline 

110 self.blurb = blurb 

111 self.classes = "eligibility-verification-form" 

112 

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 

123 

124 self.fields["sub"] = forms.CharField( 

125 label=sub_label, 

126 widget=sub_widget, 

127 help_text=sub_help_text, 

128 ) 

129 

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 

136 

137 self.fields["name"] = forms.CharField(label=name_label, widget=name_widget, help_text=name_help_text) 

138 

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") 

142 

143 

144class CSTAgencyCard(EligibilityVerificationForm): 

145 """EligibilityVerification form for the CST Agency Card.""" 

146 

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 ) 

171 

172 

173class MSTCourtesyCard(EligibilityVerificationForm): 

174 """EligibilityVerification form for the MST Courtesy Card.""" 

175 

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 ) 

200 

201 

202class SBMTDMobilityPass(EligibilityVerificationForm): 

203 """EligibilityVerification form for the SBMTD Reduced Fare Mobility ID.""" 

204 

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 )