From b0c9662b514b3a7cb7de18175ad9017bbbc11bc3 Mon Sep 17 00:00:00 2001 From: Matthew Piatetsky <mpiatetsky@edx.org> Date: Fri, 8 Nov 2019 11:29:59 -0500 Subject: [PATCH] remove discount banner from track selection --- .../course_modes/tests/test_views.py | 34 -------------- common/djangoapps/course_modes/views.py | 9 ---- lms/djangoapps/courseware/tests/test_views.py | 4 +- .../tests/views/test_course_home.py | 2 +- openedx/features/discounts/applicability.py | 45 ++++++++++++------- openedx/features/discounts/utils.py | 18 +++++++- .../lms/templates/course_modes/choose.html | 4 -- 7 files changed, 49 insertions(+), 67 deletions(-) diff --git a/common/djangoapps/course_modes/tests/test_views.py b/common/djangoapps/course_modes/tests/test_views.py index 3beb8c6c34a..e45ec1a01ff 100644 --- a/common/djangoapps/course_modes/tests/test_views.py +++ b/common/djangoapps/course_modes/tests/test_views.py @@ -398,40 +398,6 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest self.assertEquals(course_mode, expected_mode) - @patch('openedx.features.discounts.utils.can_receive_discount') - @patch('openedx.features.discounts.utils.discount_percentage') - def test_discount_on_track_selection(self, discount_percentage_mock, can_receive_discount_mock): - can_receive_discount_mock.return_value = True - discount_percentage_mock.return_value = 15 - parameters = { - 'mode_slug': 'verified', - 'mode_display_name': 'Verified Certificate', - 'min_price': 10 - } - - url = reverse('create_mode', args=[six.text_type(self.course.id)]) - response = self.client.get(url, parameters) - - CourseEnrollmentFactory( - is_active=True, - course_id=self.course.id, - user=self.user - ) - - response = self.client.get( - reverse('course_modes_choose', args=[six.text_type(self.course.id)]), - follow=False, - ) - - banner = u'''<div class="first-purchase-offer-banner" role="note">''' - button = u'''<button type="submit" name="verified_mode"> - <span>Pursue a Verified Certificate</span> - (<span class="upgrade-price-string">$8.50 USD</span> - <del> <span class="upgrade-price-string">$10 USD</span></del>) - </button>''' - self.assertContains(response, banner) - self.assertContains(response, button, html=True) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_multiple_mode_creation(self): # Create an honor mode diff --git a/common/djangoapps/course_modes/views.py b/common/djangoapps/course_modes/views.py index 586fe8315c8..86961acea9c 100644 --- a/common/djangoapps/course_modes/views.py +++ b/common/djangoapps/course_modes/views.py @@ -211,15 +211,6 @@ class ChooseModeView(View): context["verified_name"] = verified_mode.name context["verified_description"] = verified_mode.description - offer_banner_fragment = get_first_purchase_offer_banner_fragment( - request.user, course - ) - if offer_banner_fragment: - context['offer_banner_fragment'] = offer_banner_fragment - discounted_price = "{:0.2f}".format(price_before_discount * ((100.0 - discount_percentage(course)) / 100)) - context["min_price"] = discounted_price - context["price_before_discount"] = price_before_discount - if verified_mode.sku: context["use_ecommerce_payment_flow"] = ecommerce_service.is_enabled(request.user) context["ecommerce_payment_page"] = ecommerce_service.payment_page_url() diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 03702e99600..aa0021bfbbf 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -225,8 +225,8 @@ class IndexQueryTestCase(ModuleStoreTestCase): NUM_PROBLEMS = 20 @ddt.data( - (ModuleStoreEnum.Type.mongo, 10, 179), - (ModuleStoreEnum.Type.split, 4, 175), + (ModuleStoreEnum.Type.mongo, 10, 181), + (ModuleStoreEnum.Type.split, 4, 177), ) @ddt.unpack def test_index_query_counts(self, store_type, expected_mongo_query_count, expected_mysql_query_count): diff --git a/openedx/features/course_experience/tests/views/test_course_home.py b/openedx/features/course_experience/tests/views/test_course_home.py index df3e3d2f091..d8dbb3103a5 100644 --- a/openedx/features/course_experience/tests/views/test_course_home.py +++ b/openedx/features/course_experience/tests/views/test_course_home.py @@ -219,7 +219,7 @@ class TestCourseHomePage(CourseHomePageTestCase): # Fetch the view and verify the query counts # TODO: decrease query count as part of REVO-28 - with self.assertNumQueries(88, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(90, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_home_url(self.course) self.client.get(url) diff --git a/openedx/features/discounts/applicability.py b/openedx/features/discounts/applicability.py index f967feba08d..d191979e012 100644 --- a/openedx/features/discounts/applicability.py +++ b/openedx/features/discounts/applicability.py @@ -14,10 +14,12 @@ from datetime import datetime, timedelta from crum import get_current_request, impersonate from django.utils import timezone +from django.utils.dateparse import parse_datetime import pytz from course_modes.models import CourseMode from entitlements.models import CourseEntitlement +from experiments.models import ExperimentData from lms.djangoapps.experiments.stable_bucketing import stable_bucketing_hash_group from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace from openedx.features.discounts.models import DiscountPercentageConfig, DiscountRestrictionConfig @@ -42,6 +44,7 @@ DISCOUNT_APPLICABILITY_FLAG = WaffleFlag( ) DISCOUNT_APPLICABILITY_HOLDBACK = 'first_purchase_discount_holdback' +REV1008_EXPERIMENT_ID = 15 def get_discount_expiration_date(user, course): @@ -61,23 +64,33 @@ def get_discount_expiration_date(user, course): if len(course_enrollment) != 1: return None - enrollment = course_enrollment.first() + time_limit_start = None try: - # Content availability date is equivalent to max(enrollment date, course start date) - # for most people. Using the schedule date will provide flexibility to deal with - # more complex business rules in the future. - content_availability_date = enrollment.schedule.start - # We have anecdotally observed a case where the schedule.start was - # equal to the course start, but should have been equal to the enrollment start - # https://openedx.atlassian.net/browse/PROD-58 - # This section is meant to address that case - if enrollment.created and course.start: - if (content_availability_date.date() == course.start.date() and - course.start < enrollment.created < timezone.now()): - content_availability_date = enrollment.created - except CourseEnrollment.schedule.RelatedObjectDoesNotExist: - content_availability_date = max(enrollment.created, course.start) - discount_expiration_date = content_availability_date + timedelta(weeks=1) + saw_banner = ExperimentData.objects.get(user=user, experiment_id=REV1008_EXPERIMENT_ID, key=str(course)) + time_limit_start = parse_datetime(saw_banner.value) + except ExperimentData.DoesNotExist: + pass + + if not time_limit_start: + enrollment = course_enrollment.first() + try: + # Content availability date is equivalent to max(enrollment date, course start date) + # for most people. Using the schedule date will provide flexibility to deal with + # more complex business rules in the future. + content_availability_date = enrollment.schedule.start + # We have anecdotally observed a case where the schedule.start was + # equal to the course start, but should have been equal to the enrollment start + # https://openedx.atlassian.net/browse/PROD-58 + # This section is meant to address that case + if enrollment.created and course.start: + if (content_availability_date.date() == course.start.date() and + course.start < enrollment.created < timezone.now()): + content_availability_date = enrollment.created + except CourseEnrollment.schedule.RelatedObjectDoesNotExist: + content_availability_date = max(enrollment.created, course.start) + time_limit_start = content_availability_date + + discount_expiration_date = time_limit_start + timedelta(weeks=1) # If the course has an upgrade deadline and discount time limit would put the discount expiration date # after the deadline, then change the expiration date to be the upgrade deadline diff --git a/openedx/features/discounts/utils.py b/openedx/features/discounts/utils.py index a5dc3b7811b..8f5576ea5a9 100644 --- a/openedx/features/discounts/utils.py +++ b/openedx/features/discounts/utils.py @@ -2,11 +2,17 @@ Utility functions for working with discounts and discounted pricing. """ +from datetime import datetime + import six from django.utils.translation import ugettext as _ +import pytz + from course_modes.models import get_course_prices, format_course_price from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +from experiments.models import ExperimentData + from openedx.core.djangolib.markup import HTML from web_fragments.fragment import Fragment from openedx.features.discounts.applicability import ( @@ -15,6 +21,8 @@ from openedx.features.discounts.applicability import ( discount_percentage ) +REV1008_EXPERIMENT_ID = 15 + def offer_banner_wrapper(user, block, view, frag, context): # pylint: disable=W0613 """ @@ -95,7 +103,15 @@ def get_first_purchase_offer_banner_fragment(user, course): which has the discount_expiration_date, price, discount percentage and a link to upgrade. """ - if user and course: + if user and not user.is_anonymous and course: + now = datetime.now(tz=pytz.UTC).strftime(u"%Y-%m-%d %H:%M:%S%z") + saw_banner = ExperimentData.objects.filter( + user=user, experiment_id=REV1008_EXPERIMENT_ID, key=str(course) + ) + if not saw_banner: + ExperimentData.objects.create( + user=user, experiment_id=REV1008_EXPERIMENT_ID, key=str(course), value=now + ) discount_expiration_date = get_discount_expiration_date(user, course) if (discount_expiration_date and can_receive_discount(user=user, course=course, discount_expiration_date=discount_expiration_date)): diff --git a/themes/edx.org/lms/templates/course_modes/choose.html b/themes/edx.org/lms/templates/course_modes/choose.html index ea35afc96ee..ff6461b847d 100644 --- a/themes/edx.org/lms/templates/course_modes/choose.html +++ b/themes/edx.org/lms/templates/course_modes/choose.html @@ -89,10 +89,6 @@ from openedx.core.djangolib.markup import HTML, Text </h3> </header> - % if offer_banner_fragment: - ${HTML(offer_banner_fragment.content)} - % endif - <form class="form-register-choose" method="post" name="enrollment_mode_form" id="enrollment_mode_form"> <% b_tag_kwargs = {'b_start': HTML('<b>'), 'b_end': HTML('</b>')} -- GitLab