diff --git a/benefits/core/analytics.py b/benefits/core/analytics.py index bb0d82e32..d6f13dc35 100644 --- a/benefits/core/analytics.py +++ b/benefits/core/analytics.py @@ -25,7 +25,7 @@ class Event: _counter = itertools.count() _domain_re = re.compile(r"^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)", re.IGNORECASE) - def __init__(self, request, event_type, **kwargs): + def __init__(self, request, event_type, enrollment_method=models.EnrollmentMethods.DIGITAL, **kwargs): self.app_version = VERSION # device_id is generated based on the user_id, and both are set explicitly (per session) self.device_id = session.did(request) @@ -51,6 +51,7 @@ def __init__(self, request, event_type, **kwargs): path=request.path, transit_agency=agency_name, eligibility_verifier=verifier_name, + enrollment_method=enrollment_method, ) uagent = request.headers.get("user-agent") @@ -65,6 +66,7 @@ def __init__(self, request, event_type, **kwargs): user_agent=uagent, transit_agency=agency_name, eligibility_verifier=verifier_name, + enrollment_method=enrollment_method, ) if flow: diff --git a/benefits/eligibility/analytics.py b/benefits/eligibility/analytics.py index 44a55e634..9cb62efad 100644 --- a/benefits/eligibility/analytics.py +++ b/benefits/eligibility/analytics.py @@ -8,8 +8,8 @@ class EligibilityEvent(core.Event): """Base analytics event for eligibility verification.""" - def __init__(self, request, event_type, flow: models.EnrollmentFlow): - super().__init__(request, event_type) + def __init__(self, request, event_type, flow: models.EnrollmentFlow, enrollment_method=models.EnrollmentMethods.DIGITAL): + super().__init__(request, event_type, enrollment_method) # overwrite core.Event enrollment flow self.update_enrollment_flows(flow) @@ -17,35 +17,37 @@ def __init__(self, request, event_type, flow: models.EnrollmentFlow): class SelectedVerifierEvent(EligibilityEvent): """Analytics event representing the user selecting an enrollment flow.""" - def __init__(self, request, flow: models.EnrollmentFlow): - super().__init__(request, "selected enrollment flow", flow) + def __init__(self, request, flow: models.EnrollmentFlow, enrollment_method=models.EnrollmentMethods.DIGITAL): + super().__init__(request, "selected enrollment flow", flow, enrollment_method) class StartedEligibilityEvent(EligibilityEvent): """Analytics event representing the beginning of an eligibility verification check.""" - def __init__(self, request, flow: models.EnrollmentFlow): - super().__init__(request, "started eligibility", flow) + def __init__(self, request, flow: models.EnrollmentFlow, enrollment_method=models.EnrollmentMethods.DIGITAL): + super().__init__(request, "started eligibility", flow, enrollment_method) class ReturnedEligibilityEvent(EligibilityEvent): """Analytics event representing the end of an eligibility verification check.""" - def __init__(self, request, flow: models.EnrollmentFlow, status, error=None): - super().__init__(request, "returned eligibility", flow) + def __init__( + self, request, flow: models.EnrollmentFlow, status, error=None, enrollment_method=models.EnrollmentMethods.DIGITAL + ): + super().__init__(request, "returned eligibility", flow, enrollment_method) status = str(status).lower() if status in ("error", "fail", "success"): self.update_event_properties(status=status, error=error) -def selected_verifier(request, flow: models.EnrollmentFlow): +def selected_verifier(request, flow: models.EnrollmentFlow, enrollment_method: str = models.EnrollmentMethods.DIGITAL): """Send the "selected eligibility verifier" analytics event.""" - core.send_event(SelectedVerifierEvent(request, flow)) + core.send_event(SelectedVerifierEvent(request, flow, enrollment_method=enrollment_method)) -def started_eligibility(request, flow: models.EnrollmentFlow): +def started_eligibility(request, flow: models.EnrollmentFlow, enrollment_method: str = models.EnrollmentMethods.DIGITAL): """Send the "started eligibility" analytics event.""" - core.send_event(StartedEligibilityEvent(request, flow)) + core.send_event(StartedEligibilityEvent(request, flow, enrollment_method=enrollment_method)) def returned_error(request, flow: models.EnrollmentFlow, error): @@ -58,6 +60,6 @@ def returned_fail(request, flow: models.EnrollmentFlow): core.send_event(ReturnedEligibilityEvent(request, flow, status="fail")) -def returned_success(request, flow: models.EnrollmentFlow): +def returned_success(request, flow: models.EnrollmentFlow, enrollment_method: str = models.EnrollmentMethods.DIGITAL): """Send the "returned eligibility" analytics event with a success status.""" - core.send_event(ReturnedEligibilityEvent(request, flow, status="success")) + core.send_event(ReturnedEligibilityEvent(request, flow, enrollment_method=enrollment_method, status="success")) diff --git a/benefits/enrollment/analytics.py b/benefits/enrollment/analytics.py index 8e751c350..da6b1bf9e 100644 --- a/benefits/enrollment/analytics.py +++ b/benefits/enrollment/analytics.py @@ -2,14 +2,14 @@ The enrollment application: analytics implementation. """ -from benefits.core import analytics as core +from benefits.core import analytics as core, models class ReturnedEnrollmentEvent(core.Event): """Analytics event representing the end of transit processor enrollment request.""" - def __init__(self, request, status, error=None, enrollment_group=None): - super().__init__(request, "returned enrollment") + def __init__(self, request, status, error=None, enrollment_group=None, enrollment_method=models.EnrollmentMethods.DIGITAL): + super().__init__(request, "returned enrollment", enrollment_method) if str(status).lower() in ("error", "retry", "success"): self.update_event_properties(status=status, error=error) if enrollment_group is not None: @@ -19,27 +19,31 @@ def __init__(self, request, status, error=None, enrollment_group=None): class FailedAccessTokenRequestEvent(core.Event): """Analytics event representing a failure to acquire an access token for card tokenization.""" - def __init__(self, request, status_code=None): - super().__init__(request, "failed access token request") + def __init__(self, request, status_code=None, enrollment_method=models.EnrollmentMethods.DIGITAL): + super().__init__(request, "failed access token request", enrollment_method) if status_code is not None: self.update_event_properties(status_code=status_code) -def returned_error(request, error): +def returned_error(request, error, enrollment_method: str = models.EnrollmentMethods.DIGITAL): """Send the "returned enrollment" analytics event with an error status and message.""" - core.send_event(ReturnedEnrollmentEvent(request, status="error", error=error)) + core.send_event(ReturnedEnrollmentEvent(request, status="error", error=error, enrollment_method=enrollment_method)) -def returned_retry(request): +def returned_retry(request, enrollment_method: str = models.EnrollmentMethods.DIGITAL): """Send the "returned enrollment" analytics event with a retry status.""" - core.send_event(ReturnedEnrollmentEvent(request, status="retry")) + core.send_event(ReturnedEnrollmentEvent(request, status="retry", enrollment_method=enrollment_method)) -def returned_success(request, enrollment_group): +def returned_success(request, enrollment_group, enrollment_method: str = models.EnrollmentMethods.DIGITAL): """Send the "returned enrollment" analytics event with a success status.""" - core.send_event(ReturnedEnrollmentEvent(request, status="success", enrollment_group=enrollment_group)) + core.send_event( + ReturnedEnrollmentEvent( + request, status="success", enrollment_group=enrollment_group, enrollment_method=enrollment_method + ) + ) -def failed_access_token_request(request, status_code=None): +def failed_access_token_request(request, status_code=None, enrollment_method: str = models.EnrollmentMethods.DIGITAL): """Send the "failed access token request" analytics event with the response status code.""" - core.send_event(FailedAccessTokenRequestEvent(request, status_code=status_code)) + core.send_event(FailedAccessTokenRequestEvent(request, status_code=status_code, enrollment_method=enrollment_method)) diff --git a/benefits/enrollment/templates/enrollment/index.html b/benefits/enrollment/templates/enrollment/index.html index d503958bb..7ad1bb38c 100644 --- a/benefits/enrollment/templates/enrollment/index.html +++ b/benefits/enrollment/templates/enrollment/index.html @@ -56,7 +56,8 @@

$("#{{ cta_button }}").on("click", function() { amplitude.getInstance().logEvent(startedEvent, { card_tokenize_url: "{{ card_tokenize_url }}", - card_tokenize_func: "{{ card_tokenize_func }}" + card_tokenize_func: "{{ card_tokenize_func }}", + enrollment_method: "{{ enrollment_method }}" }); $(this).addClass("disabled").attr("aria-disabled", "true").text("{{ loading_text }}"); }); @@ -73,7 +74,7 @@

/* This function executes when the /* card verification returns /* successfully with a token from enrollment server */ - amplitude.getInstance().logEvent(closedEvent, {status: "success"}); + amplitude.getInstance().logEvent(closedEvent, {status: "success", enrollment_method: "{{ enrollment_method }}"}); var form = $("form#{{ form_success }}"); $("#{{ token_field }}", form).val(response.token); @@ -83,7 +84,7 @@

/* This function executes when the /* card verification fails and server /* return verification failure message */ - amplitude.getInstance().logEvent(closedEvent, {status: "fail"}); + amplitude.getInstance().logEvent(closedEvent, {status: "fail", enrollment_method: "{{ enrollment_method }}"}); var form = $("form#{{ form_retry }}"); form.submit(); @@ -92,7 +93,7 @@

/* This function executes when the /* server returns error or token is invalid. /* 400 or 500 will return. */ - amplitude.getInstance().logEvent(closedEvent, {status: "error", error: response}); + amplitude.getInstance().logEvent(closedEvent, {status: "error", error: response, enrollment_method: "{{ enrollment_method }}"}); if (response.status >= 500) { var form = $("form#{{ form_system_error }}"); @@ -105,7 +106,7 @@

/* This function executes when the /* user cancels and closes the window /* and returns to home page. */ - amplitude.getInstance().logEvent(closedEvent, {status: "cancel"}); + amplitude.getInstance().logEvent(closedEvent, {status: "cancel", enrollment_method: "{{ enrollment_method }}"}); return location.reload(); } diff --git a/benefits/enrollment/views.py b/benefits/enrollment/views.py index ac6c252bb..f0da5a828 100644 --- a/benefits/enrollment/views.py +++ b/benefits/enrollment/views.py @@ -117,6 +117,7 @@ def index(request): "card_tokenize_env": agency.transit_processor.card_tokenize_env, "card_tokenize_func": agency.transit_processor.card_tokenize_func, "card_tokenize_url": agency.transit_processor.card_tokenize_url, + "enrollment_method": models.EnrollmentMethods.DIGITAL, "token_field": "card_token", "form_retry": tokenize_retry_form.id, "form_server_error": tokenize_server_error_form.id, diff --git a/benefits/in_person/templates/in_person/enrollment.html b/benefits/in_person/templates/in_person/enrollment.html index 7792c3642..5623d0323 100644 --- a/benefits/in_person/templates/in_person/enrollment.html +++ b/benefits/in_person/templates/in_person/enrollment.html @@ -41,6 +41,7 @@

In-person enrollment