Coverage for benefits/in_person/views.py: 99%
108 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-14 01:41 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-14 01:41 +0000
1import logging
3from django.contrib.admin import site as admin_site
4from django.http import JsonResponse
5from django.template.response import TemplateResponse
6from django.shortcuts import redirect
7from django.urls import reverse
8import sentry_sdk
11from benefits.routes import routes
12from benefits.core import models, session
13from benefits.eligibility import analytics as eligibility_analytics
14from benefits.enrollment import analytics as enrollment_analytics
15from benefits.enrollment.enrollment import Status, request_card_tokenization_access, enroll
17from benefits.in_person import forms
19logger = logging.getLogger(__name__)
22def eligibility(request):
23 """View handler for the in-person eligibility flow selection form."""
25 agency = session.agency(request)
26 context = {
27 **admin_site.each_context(request),
28 "form": forms.InPersonEligibilityForm(agency=agency),
29 "title": f"{agency.long_name} | In-person enrollment | {admin_site.site_title}",
30 }
32 if request.method == "POST":
33 form = forms.InPersonEligibilityForm(data=request.POST, agency=agency)
35 if form.is_valid():
36 flow_id = form.cleaned_data.get("flow")
37 flow = models.EnrollmentFlow.objects.get(id=flow_id)
38 session.update(request, flow=flow)
39 eligibility_analytics.selected_flow(request, flow, enrollment_method=models.EnrollmentMethods.IN_PERSON)
40 eligibility_analytics.started_eligibility(request, flow, enrollment_method=models.EnrollmentMethods.IN_PERSON)
42 in_person_enrollment = reverse(routes.IN_PERSON_ENROLLMENT)
43 response = redirect(in_person_enrollment)
44 else:
45 context["form"] = form
46 response = TemplateResponse(request, "in_person/eligibility.html", context)
47 else:
48 response = TemplateResponse(request, "in_person/eligibility.html", context)
50 return response
53def token(request):
54 """View handler for the enrollment auth token."""
55 if not session.enrollment_token_valid(request):
56 response = request_card_tokenization_access(request)
58 if response.status is Status.SUCCESS:
59 session.update(request, enrollment_token=response.access_token, enrollment_token_exp=response.expires_at)
60 elif response.status is Status.SYSTEM_ERROR or response.status is Status.EXCEPTION: 60 ↛ 75line 60 didn't jump to line 75 because the condition on line 60 was always true
61 logger.debug("Error occurred while requesting access token", exc_info=response.exception)
62 sentry_sdk.capture_exception(response.exception)
63 enrollment_analytics.failed_access_token_request(
64 request, response.status_code, enrollment_method=models.EnrollmentMethods.IN_PERSON
65 )
67 if response.status is Status.SYSTEM_ERROR:
68 redirect = reverse(routes.IN_PERSON_ENROLLMENT_SYSTEM_ERROR)
69 else:
70 redirect = reverse(routes.IN_PERSON_SERVER_ERROR)
72 data = {"redirect": redirect}
73 return JsonResponse(data)
75 data = {"token": session.enrollment_token(request)}
77 return JsonResponse(data)
80def enrollment(request):
81 """View handler for the in-person enrollment page."""
82 # POST back after transit processor form, process card token
83 if request.method == "POST":
84 form = forms.CardTokenizeSuccessForm(request.POST)
85 if not form.is_valid():
86 raise Exception("Invalid card token form")
88 flow = session.flow(request)
89 eligibility_analytics.returned_success(request, flow, enrollment_method=models.EnrollmentMethods.IN_PERSON)
90 card_token = form.cleaned_data.get("card_token")
91 status, exception = enroll(request, card_token)
93 match (status):
94 case Status.SUCCESS:
95 agency = session.agency(request)
96 expiry = session.enrollment_expiry(request)
97 verified_by = f"{request.user.first_name} {request.user.last_name}"
98 event = models.EnrollmentEvent.objects.create(
99 transit_agency=agency,
100 enrollment_flow=flow,
101 enrollment_method=models.EnrollmentMethods.IN_PERSON,
102 verified_by=verified_by,
103 expiration_datetime=expiry,
104 )
105 event.save()
106 enrollment_analytics.returned_success(
107 request, flow.group_id, enrollment_method=models.EnrollmentMethods.IN_PERSON
108 )
109 return redirect(routes.IN_PERSON_ENROLLMENT_SUCCESS)
111 case Status.SYSTEM_ERROR:
112 enrollment_analytics.returned_error(
113 request, str(exception), enrollment_method=models.EnrollmentMethods.IN_PERSON
114 )
115 sentry_sdk.capture_exception(exception)
116 return redirect(routes.IN_PERSON_ENROLLMENT_SYSTEM_ERROR)
118 case Status.EXCEPTION:
119 enrollment_analytics.returned_error(
120 request, str(exception), enrollment_method=models.EnrollmentMethods.IN_PERSON
121 )
122 sentry_sdk.capture_exception(exception)
123 return redirect(routes.IN_PERSON_SERVER_ERROR)
125 case Status.REENROLLMENT_ERROR: 125 ↛ exitline 125 didn't return from function 'enrollment' because the pattern on line 125 always matched
126 enrollment_analytics.returned_error(
127 request, "Re-enrollment error.", enrollment_method=models.EnrollmentMethods.IN_PERSON
128 )
129 return redirect(routes.IN_PERSON_ENROLLMENT_REENROLLMENT_ERROR)
130 # GET enrollment index
131 else:
132 agency = session.agency(request)
134 tokenize_retry_form = forms.CardTokenizeFailForm(routes.IN_PERSON_ENROLLMENT_RETRY, "form-card-tokenize-fail-retry")
135 tokenize_server_error_form = forms.CardTokenizeFailForm(
136 routes.IN_PERSON_SERVER_ERROR, "form-card-tokenize-fail-server-error"
137 )
138 tokenize_system_error_form = forms.CardTokenizeFailForm(
139 routes.IN_PERSON_ENROLLMENT_SYSTEM_ERROR, "form-card-tokenize-fail-system-error"
140 )
141 tokenize_success_form = forms.CardTokenizeSuccessForm(
142 action_url=routes.IN_PERSON_ENROLLMENT, auto_id=True, label_suffix=""
143 )
145 context = {
146 **admin_site.each_context(request),
147 "forms": [tokenize_retry_form, tokenize_server_error_form, tokenize_system_error_form, tokenize_success_form],
148 "cta_button": "tokenize_card",
149 "enrollment_method": models.EnrollmentMethods.IN_PERSON,
150 "token_field": "card_token",
151 "form_retry": tokenize_retry_form.id,
152 "form_server_error": tokenize_server_error_form.id,
153 "form_success": tokenize_success_form.id,
154 "form_system_error": tokenize_system_error_form.id,
155 "title": f"{agency.long_name} | In-person enrollment | {admin_site.site_title}",
156 }
157 context.update({"transit_processor": agency.littlepay_config.transit_processor_context})
159 return TemplateResponse(request, "in_person/enrollment/index.html", context)
162def reenrollment_error(request):
163 """View handler for a re-enrollment attempt that is not yet within the re-enrollment window."""
165 agency = session.agency(request)
166 context = {
167 **admin_site.each_context(request),
168 "title": f"{agency.long_name} | In-person enrollment | {admin_site.site_title}",
169 }
171 flow = session.flow(request)
172 context["flow_label"] = flow.label
174 return TemplateResponse(request, "in_person/enrollment/reenrollment_error.html", context)
177def retry(request):
178 """View handler for card verification failure."""
179 # enforce POST-only route for sending analytics
180 if request.method == "POST":
181 enrollment_analytics.returned_retry(request, enrollment_method=models.EnrollmentMethods.IN_PERSON)
183 agency = session.agency(request)
184 context = {
185 **admin_site.each_context(request),
186 "title": f"{agency.long_name} | In-person enrollment | {admin_site.site_title}",
187 }
189 return TemplateResponse(request, "in_person/enrollment/retry.html", context)
192def system_error(request):
193 """View handler for an enrollment system error."""
194 agency = session.agency(request)
195 context = {
196 **admin_site.each_context(request),
197 "title": f"{agency.long_name} | In-person enrollment | {admin_site.site_title}",
198 }
200 return TemplateResponse(request, "in_person/enrollment/system_error.html", context)
203def server_error(request):
204 """View handler for errors caused by a misconfiguration or bad request."""
205 agency = session.agency(request)
206 context = {
207 **admin_site.each_context(request),
208 "title": f"{agency.long_name} | In-person enrollment | {admin_site.site_title}",
209 }
211 return TemplateResponse(request, "in_person/enrollment/server_error.html", context)
214def success(request):
215 """View handler for the final success page."""
216 agency = session.agency(request)
217 context = {
218 **admin_site.each_context(request),
219 "title": f"{agency.long_name} | In-person enrollment | {admin_site.site_title}",
220 }
222 return TemplateResponse(request, "in_person/enrollment/success.html", context)