diff --git a/openedx/core/djangoapps/programs/__init__.py b/openedx/core/djangoapps/programs/__init__.py index a6287c38bf..380a63c022 100644 --- a/openedx/core/djangoapps/programs/__init__.py +++ b/openedx/core/djangoapps/programs/__init__.py @@ -8,3 +8,10 @@ if and only if the service is deployed in the Open edX installation. To ensure maximum separation of concerns, and a minimum of interdependencies, this package should be kept small, thin, and stateless. """ +from openedx.core.djangoapps.waffle_utils import (WaffleSwitch, WaffleSwitchNamespace) + +PROGRAMS_WAFFLE_SWITCH_NAMESPACE = WaffleSwitchNamespace(name='programs') + +# This is meant to be enabled until https://openedx.atlassian.net/browse/LEARNER-5573 needs to be resolved +ALWAYS_CALCULATE_PROGRAM_PRICE_AS_ANONYMOUS_USER = WaffleSwitch( + PROGRAMS_WAFFLE_SWITCH_NAMESPACE, 'always_calculate_program_price_as_anonymous_user') diff --git a/openedx/core/djangoapps/programs/tests/test_utils.py b/openedx/core/djangoapps/programs/tests/test_utils.py index 107471bad2..9a8b6d32e9 100644 --- a/openedx/core/djangoapps/programs/tests/test_utils.py +++ b/openedx/core/djangoapps/programs/tests/test_utils.py @@ -17,6 +17,8 @@ from pytz import utc from course_modes.models import CourseMode from entitlements.tests.factories import CourseEntitlementFactory +from waffle.testutils import override_switch + from lms.djangoapps.certificates.api import MODES from lms.djangoapps.commerce.tests.test_utils import update_commerce_config from lms.djangoapps.commerce.utils import EcommerceService @@ -29,6 +31,10 @@ from openedx.core.djangoapps.catalog.tests.factories import ( SeatFactory, generate_course_run_key ) +from openedx.core.djangoapps.programs import ( + PROGRAMS_WAFFLE_SWITCH_NAMESPACE, + ALWAYS_CALCULATE_PROGRAM_PRICE_AS_ANONYMOUS_USER +) from openedx.core.djangoapps.programs.tests.factories import ProgressFactory from openedx.core.djangoapps.programs.utils import ( DEFAULT_ENROLLMENT_START_DATE, @@ -1535,6 +1541,31 @@ class TestProgramMarketingDataExtender(ModuleStoreTestCase): ) self.assertEqual(data['discount_data'], mock_discount_data) + @httpretty.activate + @override_switch("{}.{}".format( + PROGRAMS_WAFFLE_SWITCH_NAMESPACE.name, + ALWAYS_CALCULATE_PROGRAM_PRICE_AS_ANONYMOUS_USER.switch_name + ), active=True) + def test_fetching_program_price_when_forced_as_anonymous_user(self): + """ + When all users are forced as anonymous, all requests to calculate the program + price should have the query parameter is_anonymous=True + """ + self._prepare_program_for_discounted_price_calculation_endpoint() + mock_discount_data = { + 'total_incl_tax_excl_discounts': 200.0, + 'currency': 'USD', + 'total_incl_tax': 50.0 + } + httpretty.register_uri( + httpretty.GET, + self.ECOMMERCE_CALCULATE_DISCOUNT_ENDPOINT, + body=json.dumps(mock_discount_data), + content_type='application/json' + ) + ProgramMarketingDataExtender(self.program, self.user).extend() + self.assertEqual(httpretty.last_request().querystring.get('is_anonymous')[0], u'True') + @httpretty.activate def test_fetching_program_discounted_price_as_anonymous_user(self): """ diff --git a/openedx/core/djangoapps/programs/utils.py b/openedx/core/djangoapps/programs/utils.py index 5f178b92dc..57dec906e7 100644 --- a/openedx/core/djangoapps/programs/utils.py +++ b/openedx/core/djangoapps/programs/utils.py @@ -28,6 +28,7 @@ from openedx.core.djangoapps.catalog.utils import get_programs, get_fulfillable_ from openedx.core.djangoapps.commerce.utils import ecommerce_api_client from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.credentials.utils import get_credentials +from openedx.core.djangoapps.programs import ALWAYS_CALCULATE_PROGRAM_PRICE_AS_ANONYMOUS_USER from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from student.models import CourseEnrollment from util.date_utils import strftime_localized @@ -614,8 +615,9 @@ class ProgramDataExtender(object): api = ecommerce_api_client(api_user) - # Make an API call to calculate the discounted price - if is_anonymous: + # The user specific program price is slow to calculate, so use switch to force the + # anonymous price for all users. See LEARNER-5555 for more details. + if is_anonymous or ALWAYS_CALCULATE_PROGRAM_PRICE_AS_ANONYMOUS_USER.is_enabled(): discount_data = api.baskets.calculate.get(sku=skus, is_anonymous=True) else: discount_data = api.baskets.calculate.get(sku=skus, username=self.user.username)