Coverage for benefits/enrollment/enrollment.py: 95%
47 statements
« prev ^ index » next coverage.py v7.11.3, created at 2025-11-15 00:14 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2025-11-15 00:14 +0000
1from datetime import datetime, timedelta
2from enum import Enum
4from django.shortcuts import redirect
5from django.utils import timezone
6import sentry_sdk
8from benefits.routes import routes
9from benefits.core import models, session
10from . import analytics
13class Status(Enum):
14 # SUCCESS means the enrollment went through successfully
15 SUCCESS = 1
17 # SYSTEM_ERROR means the enrollment system encountered an internal error (returned a 500 HTTP status)
18 SYSTEM_ERROR = 2
20 # EXCEPTION means the enrollment system is working, but something unexpected happened
21 # because of a misconfiguration or invalid request from our side
22 EXCEPTION = 3
24 # REENROLLMENT_ERROR means that the user tried to re-enroll but is not within the reenrollment window
25 REENROLLMENT_ERROR = 4
28def _is_expired(expiry_date: datetime):
29 """Returns whether the passed in datetime is expired or not."""
30 return expiry_date <= timezone.now()
33def _is_within_reenrollment_window(expiry_date: datetime, enrollment_reenrollment_date: datetime):
34 """Returns if we are currently within the reenrollment window."""
35 return enrollment_reenrollment_date <= timezone.now() < expiry_date
38def _calculate_expiry(expiration_days: int):
39 """Returns the expiry datetime, which should be midnight in our configured timezone of the (N + 1)th day from now,
40 where N is expiration_days."""
41 default_time_zone = timezone.get_default_timezone()
42 expiry_date = timezone.localtime(timezone=default_time_zone) + timedelta(days=expiration_days + 1)
43 expiry_datetime = expiry_date.replace(hour=0, minute=0, second=0, microsecond=0)
45 return expiry_datetime
48def handle_enrollment_results(
49 request,
50 status: Status,
51 verified_by: str,
52 exception: Exception = None,
53 enrollment_method: str = models.EnrollmentMethods.DIGITAL,
54 route_reenrollment_error=routes.ENROLLMENT_REENROLLMENT_ERROR,
55 route_success=routes.ENROLLMENT_SUCCESS,
56 route_system_error=routes.ENROLLMENT_SYSTEM_ERROR,
57 card_category: str = None,
58 card_scheme: str = None,
59):
60 flow = session.flow(request)
61 agency = session.agency(request)
62 match (status):
63 case Status.SUCCESS:
64 agency = session.agency(request)
65 expiry = session.enrollment_expiry(request)
66 oauth_extra_claims = session.oauth_extra_claims(request)
67 # EnrollmentEvent expects a string value for extra_claims
68 if oauth_extra_claims: 68 ↛ 71line 68 didn't jump to line 71 because the condition on line 68 was always true
69 str_extra_claims = ", ".join(oauth_extra_claims)
70 else:
71 str_extra_claims = ""
72 event = models.EnrollmentEvent.objects.create(
73 transit_agency=agency,
74 enrollment_flow=flow,
75 enrollment_method=enrollment_method,
76 verified_by=verified_by,
77 expiration_datetime=expiry,
78 extra_claims=str_extra_claims,
79 )
80 event.save()
81 analytics.returned_success(
82 request,
83 enrollment_group=flow.group_id,
84 transit_processor=agency.transit_processor,
85 enrollment_method=enrollment_method,
86 extra_claims=oauth_extra_claims,
87 card_scheme=card_scheme,
88 card_category=card_category,
89 )
90 return redirect(route_success)
92 case Status.SYSTEM_ERROR:
93 analytics.returned_error(
94 request,
95 str(exception),
96 enrollment_group=flow.group_id,
97 transit_processor=agency.transit_processor,
98 enrollment_method=enrollment_method,
99 )
100 sentry_sdk.capture_exception(exception)
101 return redirect(route_system_error)
103 case Status.EXCEPTION:
104 analytics.returned_error(
105 request,
106 str(exception),
107 enrollment_group=flow.group_id,
108 transit_processor=agency.transit_processor,
109 enrollment_method=enrollment_method,
110 )
111 raise exception
113 case Status.REENROLLMENT_ERROR: 113 ↛ exitline 113 didn't return from function 'handle_enrollment_results' because the pattern on line 113 always matched
114 analytics.returned_error(
115 request,
116 "Re-enrollment error.",
117 enrollment_group=flow.group_id,
118 transit_processor=agency.transit_processor,
119 enrollment_method=enrollment_method,
120 )
121 return redirect(route_reenrollment_error)