diff --git a/benefits/enrollment/views.py b/benefits/enrollment/views.py index eba6123d6..d8b7ef32c 100644 --- a/benefits/enrollment/views.py +++ b/benefits/enrollment/views.py @@ -81,45 +81,83 @@ def index(request): # POST back after transit processor form, process card token if request.method == "POST": - form = forms.CardTokenizeSuccessForm(request.POST) - if not form.is_valid(): - raise Exception("Invalid card token form") + return enrollment_post(request, agency, flow) - card_token = form.cleaned_data.get("card_token") + # GET enrollment index + else: + tokenize_retry_form = forms.CardTokenizeFailForm(routes.ENROLLMENT_RETRY, "form-card-tokenize-fail-retry") + tokenize_server_error_form = forms.CardTokenizeFailForm(routes.SERVER_ERROR, "form-card-tokenize-fail-server-error") + tokenize_system_error_form = forms.CardTokenizeFailForm( + routes.ENROLLMENT_SYSTEM_ERROR, "form-card-tokenize-fail-system-error" + ) + tokenize_success_form = forms.CardTokenizeSuccessForm(routes.ENROLLMENT_INDEX, auto_id=True, label_suffix="") - client = Client( - base_url=agency.transit_processor.api_base_url, - client_id=agency.transit_processor_client_id, - client_secret=agency.transit_processor_client_secret, - audience=agency.transit_processor_audience, + context = enrollment_get_context( + request, + agency, + tokenize_retry_form=tokenize_retry_form, + tokenize_server_error_form=tokenize_server_error_form, + tokenize_system_error_form=tokenize_system_error_form, + tokenize_success_form=tokenize_success_form, ) - client.oauth.ensure_active_token(client.token) + logger.debug(f'card_tokenize_url: {context["card_tokenize_url"]}') - funding_source = client.get_funding_source_by_token(card_token) - group_id = flow.group_id + return TemplateResponse(request, flow.enrollment_index_template, context) - try: - group_funding_source = _get_group_funding_source( - client=client, group_id=group_id, funding_source_id=funding_source.id - ) - already_enrolled = group_funding_source is not None +def enrollment_post(request, agency, flow): + """Processes the card token returned from transit processor form.""" + form = forms.CardTokenizeSuccessForm(request.POST) + if not form.is_valid(): + raise Exception("Invalid card token form") - if flow.supports_expiration: - # set expiry on session - if already_enrolled and group_funding_source.expiry_date is not None: - session.update(request, enrollment_expiry=group_funding_source.expiry_date) - else: - session.update(request, enrollment_expiry=_calculate_expiry(flow.expiration_days)) + card_token = form.cleaned_data.get("card_token") + + client = Client( + base_url=agency.transit_processor.api_base_url, + client_id=agency.transit_processor_client_id, + client_secret=agency.transit_processor_client_secret, + audience=agency.transit_processor_audience, + ) + client.oauth.ensure_active_token(client.token) + + funding_source = client.get_funding_source_by_token(card_token) + group_id = flow.group_id + + try: + group_funding_source = _get_group_funding_source(client=client, group_id=group_id, funding_source_id=funding_source.id) - if not already_enrolled: - # enroll user with an expiration date, return success - client.link_concession_group_funding_source( - group_id=group_id, funding_source_id=funding_source.id, expiry=session.enrollment_expiry(request) + already_enrolled = group_funding_source is not None + + if flow.supports_expiration: + # set expiry on session + if already_enrolled and group_funding_source.expiry_date is not None: + session.update(request, enrollment_expiry=group_funding_source.expiry_date) + else: + session.update(request, enrollment_expiry=_calculate_expiry(flow.expiration_days)) + + if not already_enrolled: + # enroll user with an expiration date, return success + client.link_concession_group_funding_source( + group_id=group_id, funding_source_id=funding_source.id, expiry=session.enrollment_expiry(request) + ) + return success(request) + else: # already_enrolled + if group_funding_source.expiry_date is None: + # update expiration of existing enrollment, return success + client.update_concession_group_funding_source_expiry( + group_id=group_id, + funding_source_id=funding_source.id, + expiry=session.enrollment_expiry(request), ) return success(request) - else: # already_enrolled - if group_funding_source.expiry_date is None: + else: + is_expired = _is_expired(group_funding_source.expiry_date) + is_within_reenrollment_window = _is_within_reenrollment_window( + group_funding_source.expiry_date, session.enrollment_reenrollment(request) + ) + + if is_expired or is_within_reenrollment_window: # update expiration of existing enrollment, return success client.update_concession_group_funding_source_expiry( group_id=group_id, @@ -128,68 +166,33 @@ def index(request): ) return success(request) else: - is_expired = _is_expired(group_funding_source.expiry_date) - is_within_reenrollment_window = _is_within_reenrollment_window( - group_funding_source.expiry_date, session.enrollment_reenrollment(request) - ) - - if is_expired or is_within_reenrollment_window: - # update expiration of existing enrollment, return success - client.update_concession_group_funding_source_expiry( - group_id=group_id, - funding_source_id=funding_source.id, - expiry=session.enrollment_expiry(request), - ) - return success(request) - else: - # re-enrollment error, return enrollment error with expiration and reenrollment_date - return reenrollment_error(request) - else: # eligibility does not support expiration - if not already_enrolled: - # enroll user with no expiration date, return success - client.link_concession_group_funding_source(group_id=group_id, funding_source_id=funding_source.id) + # re-enrollment error, return enrollment error with expiration and reenrollment_date + return reenrollment_error(request) + else: # eligibility does not support expiration + if not already_enrolled: + # enroll user with no expiration date, return success + client.link_concession_group_funding_source(group_id=group_id, funding_source_id=funding_source.id) + return success(request) + else: # already_enrolled + if group_funding_source.expiry_date is None: + # no action, return success return success(request) - else: # already_enrolled - if group_funding_source.expiry_date is None: - # no action, return success - return success(request) - else: - # remove expiration date, return success - raise NotImplementedError("Removing expiration date is currently not supported") - - except HTTPError as e: - if e.response.status_code >= 500: - analytics.returned_error(request, str(e)) - sentry_sdk.capture_exception(e) + else: + # remove expiration date, return success + raise NotImplementedError("Removing expiration date is currently not supported") - return system_error(request) - else: - analytics.returned_error(request, str(e)) - raise Exception(f"{e}: {e.response.json()}") - except Exception as e: + except HTTPError as e: + if e.response.status_code >= 500: analytics.returned_error(request, str(e)) - raise e - - # GET enrollment index - else: - tokenize_retry_form = forms.CardTokenizeFailForm(routes.ENROLLMENT_RETRY, "form-card-tokenize-fail-retry") - tokenize_server_error_form = forms.CardTokenizeFailForm(routes.SERVER_ERROR, "form-card-tokenize-fail-server-error") - tokenize_system_error_form = forms.CardTokenizeFailForm( - routes.ENROLLMENT_SYSTEM_ERROR, "form-card-tokenize-fail-system-error" - ) - tokenize_success_form = forms.CardTokenizeSuccessForm(routes.ENROLLMENT_INDEX, auto_id=True, label_suffix="") - - context = enrollment_get_context( - request, - agency, - tokenize_retry_form=tokenize_retry_form, - tokenize_server_error_form=tokenize_server_error_form, - tokenize_system_error_form=tokenize_system_error_form, - tokenize_success_form=tokenize_success_form, - ) - logger.debug(f'card_tokenize_url: {context["card_tokenize_url"]}') + sentry_sdk.capture_exception(e) - return TemplateResponse(request, flow.enrollment_index_template, context) + return system_error(request) + else: + analytics.returned_error(request, str(e)) + raise Exception(f"{e}: {e.response.json()}") + except Exception as e: + analytics.returned_error(request, str(e)) + raise e def enrollment_get_context( diff --git a/benefits/in_person/views.py b/benefits/in_person/views.py index 0721c625f..5ed038dd0 100644 --- a/benefits/in_person/views.py +++ b/benefits/in_person/views.py @@ -3,7 +3,7 @@ from benefits.core import session from benefits.enrollment import forms -from benefits.enrollment.views import enrollment_get_context +from benefits.enrollment.views import enrollment_get_context, enrollment_post from benefits.routes import routes @@ -17,10 +17,11 @@ def eligibility(request): def enrollment(request): agency = session.agency(request) + flow = session.flow(request) # POST back after transit processor form, process card token if request.method == "POST": - pass + return enrollment_post(request, agency, flow) # GET enrollment page else: tokenize_retry_form = forms.CardTokenizeFailForm(routes.IN_PERSON_ENROLLMENT_RETRY, "form-card-tokenize-fail-retry") diff --git a/tests/pytest/in_person/test_views.py b/tests/pytest/in_person/test_views.py index 2f1db95d4..c0c88f116 100644 --- a/tests/pytest/in_person/test_views.py +++ b/tests/pytest/in_person/test_views.py @@ -5,6 +5,11 @@ from benefits.routes import routes +@pytest.fixture +def invalid_form_data(): + return {"invalid": "data"} + + @pytest.mark.django_db @pytest.mark.parametrize("viewname", [routes.IN_PERSON_ELIGIBILITY, routes.IN_PERSON_ENROLLMENT]) def test_view_not_logged_in(client, viewname): @@ -44,3 +49,12 @@ def test_enrollment_logged_in_get(admin_client): assert "form_retry" in response.context_data assert "form_success" in response.context_data assert "overlay_language" in response.context_data + + +@pytest.mark.django_db +@pytest.mark.usefixtures("mocked_session_agency", "mocked_session_flow") +def test_enrollment_logged_in_post_invalid_form(admin_client, invalid_form_data): + path = reverse(routes.IN_PERSON_ENROLLMENT) + + with pytest.raises(Exception, match=r"form"): + admin_client.post(path, invalid_form_data)