diff --git a/openedx_filters/learning/filters.py b/openedx_filters/learning/filters.py index 6db44fd3..0b0694c3 100644 --- a/openedx_filters/learning/filters.py +++ b/openedx_filters/learning/filters.py @@ -1445,3 +1445,48 @@ def run_filter(cls, schedules: QuerySet) -> QuerySet | None: """ data = super().run_pipeline(schedules=schedules) return data.get("schedules") + + +class DiscountEligibilityCheckRequested(OpenEdxPublicFilter): + """ + Filter used to allow plugins to mark a user as ineligible for a course discount. + + Purpose: + This filter is triggered during discount applicability checks, just before the + final eligibility decision is returned to the caller. Pipeline steps may set + ``is_eligible`` to ``False`` to exclude a user from receiving a discount. + + Filter Type: + org.openedx.learning.discount.eligibility.check.requested.v1 + + Trigger: + - Repository: openedx/edx-platform + - Path: openedx/features/discounts/applicability.py + - Function or Method: can_receive_discount, can_show_streak_discount_coupon + """ + + filter_type = "org.openedx.learning.discount.eligibility.check.requested.v1" + + @classmethod + def run_filter( + cls, + user: Any, + course_key: Any, + is_eligible: bool, + ) -> tuple: + """ + Process the inputs using the configured pipeline steps. + + Arguments: + user (User): the Django User being checked for discount eligibility. + course_key (CourseKey or course object): identifies the course. + is_eligible (bool): the current eligibility status before plugin evaluation. + + Returns: + tuple[User, CourseKey, bool]: + - User: the Django User object (unchanged). + - CourseKey: the course key (unchanged). + - bool: the (possibly overridden) eligibility flag. + """ + data = super().run_pipeline(user=user, course_key=course_key, is_eligible=is_eligible) + return data.get("user"), data.get("course_key"), data.get("is_eligible") diff --git a/openedx_filters/learning/tests/test_filters.py b/openedx_filters/learning/tests/test_filters.py index b4ccf69a..6c7bbda5 100644 --- a/openedx_filters/learning/tests/test_filters.py +++ b/openedx_filters/learning/tests/test_filters.py @@ -22,6 +22,7 @@ CourseRunAPIRenderStarted, CourseUnenrollmentStarted, DashboardRenderStarted, + DiscountEligibilityCheckRequested, IDVPageURLRequested, InstructorDashboardRenderStarted, ORASubmissionViewRenderStarted, @@ -801,3 +802,31 @@ def test_schedule_requested(self): result = ScheduleQuerySetRequested.run_filter(schedules) self.assertEqual(schedules, result) + + +class TestDiscountEligibilityCheckRequestedFilter(TestCase): + """ + Tests for the DiscountEligibilityCheckRequested filter. + """ + + def test_filter_type(self): + self.assertEqual( + DiscountEligibilityCheckRequested.filter_type, + "org.openedx.learning.discount.eligibility.check.requested.v1", + ) + + def test_run_filter_returns_false_when_pipeline_sets_ineligible(self): + user = Mock() + course_key = Mock() + + with patch( + "openedx_filters.tooling.OpenEdxPublicFilter.run_pipeline", + return_value={"user": user, "course_key": course_key, "is_eligible": False}, + ): + returned_user, returned_course_key, is_eligible = DiscountEligibilityCheckRequested.run_filter( + user=user, course_key=course_key, is_eligible=True + ) + + self.assertFalse(is_eligible) + self.assertIs(returned_user, user) + self.assertIs(returned_course_key, course_key)