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