Skip to content

Commit 2111f9a

Browse files
chore: decouple subsidy actions and user message dependencies
1 parent d0cfb0c commit 2111f9a

File tree

5 files changed

+114
-65
lines changed

5 files changed

+114
-65
lines changed

enterprise_access/apps/api/v1/views/browse_and_request.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@
5151
from enterprise_access.apps.subsidy_access_policy.models import SubsidyAccessPolicy
5252
from enterprise_access.apps.subsidy_request.constants import (
5353
REUSABLE_REQUEST_STATES,
54-
LearnerCreditAdditionalActionStates,
5554
LearnerCreditRequestActionErrorReasons,
55+
LearnerCreditRequestActionTypes,
56+
LearnerCreditRequestUserMessages,
5657
SegmentEvents,
5758
SubsidyRequestStates,
5859
SubsidyTypeChoices
@@ -72,9 +73,7 @@
7273
send_reminder_email_for_pending_learner_credit_request
7374
)
7475
from enterprise_access.apps.subsidy_request.utils import (
75-
get_action_choice,
7676
get_error_reason_choice,
77-
get_user_message_choice
7877
)
7978
from enterprise_access.apps.track.segment import track_event
8079
from enterprise_access.utils import format_traceback, get_subsidy_model
@@ -898,8 +897,8 @@ def create(self, request, *args, **kwargs):
898897
self._reuse_existing_request(existing_request, course_price)
899898
LearnerCreditRequestActions.create_action(
900899
learner_credit_request=existing_request,
901-
recent_action=get_action_choice(SubsidyRequestStates.REQUESTED),
902-
status=get_user_message_choice(SubsidyRequestStates.REQUESTED),
900+
recent_action=LearnerCreditRequestActionTypes.REQUESTED,
901+
status=LearnerCreditRequestUserMessages.REQUESTED,
903902
)
904903
# Trigger admin email notification with the latest request
905904
send_learner_credit_bnr_admins_email_with_new_requests_task.delay(
@@ -941,8 +940,8 @@ def create(self, request, *args, **kwargs):
941940
lcr = LearnerCreditRequest.objects.get(uuid=lcr_uuid)
942941
LearnerCreditRequestActions.create_action(
943942
learner_credit_request=lcr,
944-
recent_action=get_action_choice(SubsidyRequestStates.REQUESTED),
945-
status=get_user_message_choice(SubsidyRequestStates.REQUESTED),
943+
recent_action=LearnerCreditRequestActionTypes.REQUESTED,
944+
status=LearnerCreditRequestUserMessages.REQUESTED,
946945
)
947946

948947
# Trigger admin email notification with the latest request
@@ -982,8 +981,8 @@ def approve(self, request, *args, **kwargs):
982981
# Log "approve" as recent action in the Request Action model.
983982
lc_request_action = LearnerCreditRequestActions.create_action(
984983
learner_credit_request=lc_request,
985-
recent_action=get_action_choice(SubsidyRequestStates.APPROVED),
986-
status=get_user_message_choice(SubsidyRequestStates.APPROVED),
984+
recent_action=LearnerCreditRequestActionTypes.APPROVED,
985+
status=LearnerCreditRequestUserMessages.APPROVED,
987986
)
988987

989988
try:
@@ -1014,7 +1013,7 @@ def approve(self, request, *args, **kwargs):
10141013
logger.exception(error_msg)
10151014

10161015
# Update approve action with error reason.
1017-
lc_request_action.status = get_user_message_choice(SubsidyRequestStates.REQUESTED)
1016+
lc_request_action.status = LearnerCreditRequestUserMessages.REQUESTED
10181017
lc_request_action.error_reason = get_error_reason_choice(
10191018
LearnerCreditRequestActionErrorReasons.FAILED_APPROVAL
10201019
)
@@ -1044,8 +1043,8 @@ def cancel(self, request, *args, **kwargs):
10441043
error_msg = None
10451044
lc_action = LearnerCreditRequestActions.create_action(
10461045
learner_credit_request=learner_credit_request,
1047-
recent_action=get_action_choice(SubsidyRequestStates.CANCELLED),
1048-
status=get_user_message_choice(SubsidyRequestStates.CANCELLED),
1046+
recent_action=LearnerCreditRequestActionTypes.CANCELLED,
1047+
status=LearnerCreditRequestUserMessages.CANCELLED,
10491048
)
10501049

10511050
try:
@@ -1059,7 +1058,7 @@ def cancel(self, request, *args, **kwargs):
10591058
lc_action.error_reason = get_error_reason_choice(
10601059
LearnerCreditRequestActionErrorReasons.FAILED_CANCELLATION
10611060
)
1062-
lc_action.status = get_user_message_choice(SubsidyRequestStates.APPROVED)
1061+
lc_action.status = LearnerCreditRequestUserMessages.APPROVED
10631062
lc_action.traceback = error_msg
10641063
lc_action.save()
10651064
return Response(error_msg, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
@@ -1081,7 +1080,7 @@ def cancel(self, request, *args, **kwargs):
10811080
lc_action.error_reason = get_error_reason_choice(
10821081
LearnerCreditRequestActionErrorReasons.FAILED_CANCELLATION
10831082
)
1084-
lc_action.status = get_user_message_choice(SubsidyRequestStates.APPROVED)
1083+
lc_action.status = LearnerCreditRequestUserMessages.APPROVED
10851084
lc_action.traceback = error_msg
10861085
lc_action.save()
10871086
return Response(status=status.HTTP_422_UNPROCESSABLE_ENTITY)
@@ -1102,17 +1101,20 @@ def remind(self, request, *args, **kwargs):
11021101

11031102
action_instance = LearnerCreditRequestActions.create_action(
11041103
learner_credit_request=learner_credit_request,
1105-
recent_action=get_action_choice(LearnerCreditAdditionalActionStates.REMINDED),
1106-
status=get_user_message_choice(LearnerCreditAdditionalActionStates.REMINDED),
1104+
recent_action=LearnerCreditRequestActionTypes.REMINDED,
1105+
status=LearnerCreditRequestUserMessages.REMINDED,
11071106
)
11081107

11091108
try:
11101109
send_reminder_email_for_pending_learner_credit_request.delay(assignment.uuid)
11111110
return Response(status=status.HTTP_200_OK)
11121111
except Exception as exc: # pylint: disable=broad-except
11131112
# Optionally log an errored action here if the task couldn't be queued
1114-
action_instance.status = get_user_message_choice(LearnerCreditRequestActionErrorReasons.EMAIL_ERROR)
1115-
action_instance.error_reason = str(exc)
1113+
action_instance.status = LearnerCreditRequestUserMessages.APPROVED
1114+
action_instance.error_reason = get_error_reason_choice(
1115+
LearnerCreditRequestActionErrorReasons.EMAIL_ERROR
1116+
)
1117+
action_instance.traceback = format_traceback(exc)
11161118
action_instance.save()
11171119
return Response(status=status.HTTP_422_UNPROCESSABLE_ENTITY)
11181120

@@ -1142,19 +1144,19 @@ def decline(self, *args, **kwargs):
11421144
# Create the action instance before attempting the decline operation
11431145
action_instance = LearnerCreditRequestActions.create_action(
11441146
learner_credit_request=learner_credit_request,
1145-
recent_action=get_action_choice(SubsidyRequestStates.DECLINED),
1146-
status=get_user_message_choice(SubsidyRequestStates.DECLINED),
1147+
recent_action=LearnerCreditRequestActionTypes.DECLINED,
1148+
status=LearnerCreditRequestUserMessages.DECLINED,
11471149
)
11481150

11491151
try:
11501152
with transaction.atomic():
11511153
learner_credit_request.decline(self.user)
11521154
except (ValidationError, IntegrityError, DatabaseError) as exc:
1153-
action_instance.status = get_user_message_choice(SubsidyRequestStates.REQUESTED)
1155+
action_instance.status = LearnerCreditRequestActionTypes.REQUESTED
11541156
action_instance.error_reason = get_error_reason_choice(
11551157
LearnerCreditRequestActionErrorReasons.FAILED_DECLINE
11561158
)
1157-
action_instance.traceback = str(exc)
1159+
action_instance.traceback = format_traceback(exc)
11581160
action_instance.save()
11591161

11601162
logger.exception(f"Error declining learner credit request {learner_credit_request_uuid}: {exc}")
@@ -1178,11 +1180,11 @@ def decline(self, *args, **kwargs):
11781180
try:
11791181
unlink_users_from_enterprise_task.delay(enterprise_customer_uuid, [lms_user_id])
11801182
except (ConnectionError, TimeoutError, OSError) as exc:
1181-
action_instance.status = get_user_message_choice(SubsidyRequestStates.REQUESTED)
1183+
action_instance.status = LearnerCreditRequestActionTypes.REQUESTED
11821184
action_instance.error_reason = get_error_reason_choice(
11831185
LearnerCreditRequestActionErrorReasons.FAILED_DECLINE
11841186
)
1185-
action_instance.traceback = str(exc)
1187+
action_instance.traceback = format_traceback(exc)
11861188
action_instance.save()
11871189

11881190
logger.exception(

enterprise_access/apps/subsidy_request/constants.py

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ class SubsidyRequestStates:
3535
CHOICES = COMMON_STATES + LC_REQUEST_STATES
3636

3737

38+
# DEPRECATED: This class was used to add 'reminded' to the list of possible
39+
# actions. Its functionality has been consolidated into the self-contained
40+
# `LearnerCreditRequestActionTypes` class.
3841
class LearnerCreditAdditionalActionStates:
3942
""" Additional states specifically for LearnerCreditRequestActions. """
4043

@@ -44,7 +47,8 @@ class LearnerCreditAdditionalActionStates:
4447
)
4548

4649

47-
# Combined choices for LearnerCreditRequestAction model
50+
# DEPRECATED: This variable combined states from multiple classes in a way that
51+
# was confusing and brittle. Use `LearnerCreditRequestActionTypes.CHOICES` instead.
4852
LearnerCreditRequestActionChoices = SubsidyRequestStates.CHOICES + LearnerCreditAdditionalActionStates.CHOICES
4953

5054

@@ -85,20 +89,61 @@ class SubsidyTypeChoices:
8589
SUBSIDY_REQUEST_BULK_OPERATION_BATCH_SIZE = 100
8690

8791

92+
class LearnerCreditRequestActionTypes:
93+
"""
94+
Defines the set of possible values for the `recent_action` field on the
95+
`LearnerCreditRequestActions` model. This represents the specific event
96+
or operation that occurred (e.g., an approval, a reminder).
97+
"""
98+
REQUESTED = 'requested'
99+
APPROVED = 'approved'
100+
DECLINED = 'declined'
101+
ERROR = 'error'
102+
ACCEPTED = 'accepted'
103+
CANCELLED = 'cancelled'
104+
EXPIRED = 'expired'
105+
REVERSED = 'reversed'
106+
REMINDED = 'reminded'
107+
108+
CHOICES = (
109+
(REQUESTED, "Requested"),
110+
(APPROVED, "Approved"),
111+
(DECLINED, "Declined"),
112+
(ERROR, "Error"),
113+
(ACCEPTED, "Accepted"),
114+
(CANCELLED, "Cancelled"),
115+
(EXPIRED, "Expired"),
116+
(REVERSED, "Reversed"),
117+
(REMINDED, "Reminded"),
118+
)
119+
120+
88121
class LearnerCreditRequestUserMessages:
89122
"""
90-
User-facing messages for LearnerCreditRequestActions status field.
91-
Reusing the state keys from SubsidyRequestStates but with different display messages.
123+
Defines the set of possible values for the `status` field on the
124+
`LearnerCreditRequestActions` model. This represents the user-facing
125+
status label that is displayed in the UI as a result of an action.
92126
"""
127+
REQUESTED = 'requested'
128+
REMINDED = 'reminded'
129+
APPROVED = 'approved'
130+
ACCEPTED = 'accepted'
131+
DECLINED = 'declined'
132+
REVERSED = 'reversed'
133+
CANCELLED = 'cancelled'
134+
EXPIRED = 'expired'
135+
ERROR = 'error'
136+
93137
CHOICES = (
94-
(SubsidyRequestStates.REQUESTED, "Requested"),
95-
(LearnerCreditAdditionalActionStates.REMINDED, "Waiting For Learner"),
96-
(SubsidyRequestStates.APPROVED, "Waiting For Learner"),
97-
(SubsidyRequestStates.ACCEPTED, "Redeemed By Learner"),
98-
(SubsidyRequestStates.DECLINED, "Declined"),
99-
(SubsidyRequestStates.REVERSED, "Refunded"),
100-
(SubsidyRequestStates.CANCELLED, "Cancelled"),
101-
(SubsidyRequestStates.EXPIRED, "Expired"),
138+
(REQUESTED, "Requested"),
139+
(REMINDED, "Waiting For Learner"),
140+
(APPROVED, "Waiting For Learner"),
141+
(ACCEPTED, "Redeemed By Learner"),
142+
(DECLINED, "Declined"),
143+
(REVERSED, "Refunded"),
144+
(CANCELLED, "Cancelled"),
145+
(EXPIRED, "Expired"),
146+
(ERROR, "Error"),
102147
)
103148

104149

enterprise_access/apps/subsidy_request/models.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@
2121

2222
from enterprise_access.apps.subsidy_request.constants import (
2323
SUBSIDY_REQUEST_BULK_OPERATION_BATCH_SIZE,
24-
LearnerCreditAdditionalActionStates,
25-
LearnerCreditRequestActionChoices,
2624
LearnerCreditRequestActionErrorReasons,
25+
LearnerCreditRequestActionTypes,
2726
LearnerCreditRequestUserMessages,
2827
SubsidyRequestStates,
2928
SubsidyTypeChoices
@@ -487,19 +486,19 @@ def annotate_dynamic_fields_onto_queryset(cls, queryset):
487486
),
488487
When(
489488
Q(state=SubsidyRequestStates.REQUESTED),
490-
then=Value(SubsidyRequestStates.REQUESTED)
489+
then=Value(LearnerCreditRequestUserMessages.REQUESTED)
491490
),
492491
When(
493492
Q(state=SubsidyRequestStates.DECLINED),
494-
then=Value(SubsidyRequestStates.DECLINED)
493+
then=Value(LearnerCreditRequestUserMessages.DECLINED)
495494
),
496495
When(
497496
Q(state=SubsidyRequestStates.CANCELLED),
498-
then=Value(SubsidyRequestStates.CANCELLED)
497+
then=Value(LearnerCreditRequestUserMessages.CANCELLED)
499498
),
500499
When(
501500
Q(state=SubsidyRequestStates.ERROR),
502-
then=Value(SubsidyRequestStates.ERROR)
501+
then=Value(LearnerCreditRequestUserMessages.ERROR)
503502
),
504503
When(
505504
Q(state=SubsidyRequestStates.APPROVED),
@@ -560,7 +559,7 @@ class LearnerCreditRequestActions(TimeStampedModel):
560559
blank=False,
561560
null=False,
562561
db_index=True,
563-
choices=LearnerCreditRequestActionChoices,
562+
choices=LearnerCreditRequestActionTypes.CHOICES,
564563
help_text="The type of action taken on the learner credit request.",
565564
)
566565

@@ -615,7 +614,7 @@ def create_action(
615614
Args:
616615
learner_credit_request (LearnerCreditRequest): The associated learner credit request.
617616
recent_action (str): The type of action taken (must be a valid choice from
618-
LearnerCreditRequestActionChoices).
617+
LearnerCreditRequestActionTypes).
619618
status (str): The status message (must be a valid choice from LearnerCreditRequestUserMessages.CHOICES).
620619
error_reason (str, optional): The error reason if applicable (must be a valid choice
621620
from LearnerCreditRequestActionErrorReasons.CHOICES).

enterprise_access/apps/subsidy_request/tests/factories.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010

1111
from enterprise_access.apps.content_assignments.tests.factories import LearnerContentAssignmentFactory
1212
from enterprise_access.apps.core.tests.factories import UserFactory
13-
from enterprise_access.apps.subsidy_request.constants import SubsidyRequestStates, SubsidyTypeChoices
13+
from enterprise_access.apps.subsidy_request.constants import (
14+
LearnerCreditRequestActionTypes,
15+
LearnerCreditRequestUserMessages,
16+
SubsidyRequestStates,
17+
SubsidyTypeChoices
18+
)
1419
from enterprise_access.apps.subsidy_request.models import (
1520
CouponCodeRequest,
1621
LearnerCreditRequest,
@@ -105,8 +110,8 @@ class LearnerCreditRequestActionsFactory(factory.django.DjangoModelFactory):
105110
Test factory for the `LearnerCreditRequestActions` model.
106111
"""
107112
uuid = factory.LazyFunction(uuid4)
108-
recent_action = get_action_choice(SubsidyRequestStates.REQUESTED)
109-
status = get_user_message_choice(SubsidyRequestStates.REQUESTED)
113+
recent_action = LearnerCreditRequestActionTypes.REQUESTED
114+
status = LearnerCreditRequestUserMessages.REQUESTED
110115
learner_credit_request = factory.SubFactory(LearnerCreditRequestFactory)
111116
error_reason = None
112117
traceback = None

0 commit comments

Comments
 (0)