Skip to content

Commit

Permalink
refactor(enrollment): extract logic handling POST requests to enrollment
Browse files Browse the repository at this point in the history
reuse it in the `in_person.enrollment` view.

this gets us back to having a working form submission in the in-person
enrollment view, but we need to be able to configure which templates
to return for the various success / error scenarios.
  • Loading branch information
angela-tran committed Sep 4, 2024
1 parent 0724750 commit c9281ed
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 89 deletions.
177 changes: 90 additions & 87 deletions benefits/enrollment/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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(
Expand Down
5 changes: 3 additions & 2 deletions benefits/in_person/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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")
Expand Down
9 changes: 9 additions & 0 deletions tests/pytest/in_person/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,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)

0 comments on commit c9281ed

Please sign in to comment.