From ad77392f8d357c927308c6e8d8bb9a0b46d59b7b Mon Sep 17 00:00:00 2001
From: Matthew Piatetsky
Date: Wed, 22 May 2019 16:45:50 -0400
Subject: [PATCH 1/2] add discount banner to track selection
---
.github/CODEOWNERS | 1 +
.../course_modes/tests/test_views.py | 31 +++++
common/djangoapps/course_modes/views.py | 15 ++-
.../acceptance/pages/lms/track_selection.py | 2 +-
lms/static/sass/views/_verification.scss | 22 +++-
lms/templates/course_modes/choose.html | 30 +++--
.../lms/templates/course_modes/choose.html | 113 +++++-------------
7 files changed, 118 insertions(+), 96 deletions(-)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index fb2367e6b1..693a3e688b 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -38,3 +38,4 @@ lms/djangoapps/experiments/ @edx/rev-team
lms/djangoapps/learner_dashboard/ @edx/platform-discovery
openedx/features/content_type_gating/ @edx/rev-team
openedx/features/course_duration_limits/ @edx/rev-team
+openedx/features/discounts/ @edx/rev-team
diff --git a/common/djangoapps/course_modes/tests/test_views.py b/common/djangoapps/course_modes/tests/test_views.py
index d836b4ea80..78a4ea34fe 100644
--- a/common/djangoapps/course_modes/tests/test_views.py
+++ b/common/djangoapps/course_modes/tests/test_views.py
@@ -23,6 +23,8 @@ from lms.djangoapps.commerce.tests import test_utils as ecomm_test_utils
from openedx.core.djangoapps.catalog.tests.mixins import CatalogIntegrationMixin
from openedx.core.djangoapps.embargo.test_utils import restrict_course
from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme
+from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
+from openedx.features.course_experience import FIRST_PURCHASE_OFFER_BANNER_DISPLAY
from student.models import CourseEnrollment
from student.tests.factories import CourseEnrollmentFactory, UserFactory
from util.testing import UrlResetMixin
@@ -397,6 +399,35 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest
self.assertEquals(course_mode, expected_mode)
+ @patch('openedx.features.course_experience.utils.can_receive_discount')
+ @patch('openedx.features.course_experience.utils.discount_percentage')
+ @override_waffle_flag(FIRST_PURCHASE_OFFER_BANNER_DISPLAY, active=True)
+ 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)
+
+ response = self.client.get(
+ reverse('course_modes_choose', args=[six.text_type(self.course.id)]),
+ follow=False,
+ )
+
+ bannerText = u'''
+ 15% off your first upgrade. Discount automatically applied.
'''
+ button = u''''''
+ self.assertContains(response, bannerText, html=True)
+ 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 9eb116bf27..25f324c0d7 100644
--- a/common/djangoapps/course_modes/views.py
+++ b/common/djangoapps/course_modes/views.py
@@ -34,6 +34,8 @@ from openedx.core.djangoapps.catalog.utils import get_currency_data
from openedx.core.djangoapps.embargo import api as embargo_api
from openedx.features.content_type_gating.models import ContentTypeGatingConfig
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
+from openedx.features.course_experience.utils import get_first_purchase_offer_banner_fragment
+from openedx.features.discounts.applicability import discount_percentage
from student.models import CourseEnrollment
from util.db import outer_atomic
from xmodule.modulestore.django import modulestore
@@ -190,11 +192,22 @@ class ChooseModeView(View):
for x in verified_mode.suggested_prices.split(",")
if x.strip()
]
+ price_before_discount = verified_mode.min_price
+
context["currency"] = verified_mode.currency.upper()
- context["min_price"] = verified_mode.min_price
+ context["min_price"] = price_before_discount
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()) / 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/common/test/acceptance/pages/lms/track_selection.py b/common/test/acceptance/pages/lms/track_selection.py
index 4f519aa1e2..11d12d34be 100644
--- a/common/test/acceptance/pages/lms/track_selection.py
+++ b/common/test/acceptance/pages/lms/track_selection.py
@@ -49,7 +49,7 @@ class TrackSelectionPage(PageObject):
if mode == "verified":
# Check the first contribution option, then click the enroll button
self.q(css=".contribution-option > input").first.click()
- self.q(css="input[name='verified_mode']").click()
+ self.q(css="button[name='verified_mode']").click()
return PaymentAndVerificationFlow(self.browser, self._course_id).wait_for_page()
elif mode == "audit":
diff --git a/lms/static/sass/views/_verification.scss b/lms/static/sass/views/_verification.scss
index ed2fdbc320..4e06aba456 100644
--- a/lms/static/sass/views/_verification.scss
+++ b/lms/static/sass/views/_verification.scss
@@ -1556,10 +1556,15 @@
@include text-align(left);
}
- .action-select input {
+ .action-select input, .action-select button {
@extend %btn-verify-primary;
}
+ .action-select button[name="verified_mode"] {
+ font-weight: 600;
+ padding: 10px 15px;
+ }
+
// extra register options/info
.title-expand {
@extend %t-copy-sub1;
@@ -2249,6 +2254,21 @@
margin-top: 20px;
}
}
+
+ // First purchase offer banner
+ .first-purchase-offer-banner {
+ background-color: #dee3f1;
+ font-size: 16px;
+ border-radius: 7px;
+ padding: 20px;
+
+ .first-purchase-offer-banner-bold {
+ font-weight: bold;
+ color: #23419f;
+ margin-right: 3px;
+ margin-left: 5px;
+ }
+ }
}
.reverify-blocked {
diff --git a/lms/templates/course_modes/choose.html b/lms/templates/course_modes/choose.html
index 7859ab228b..80dc286566 100644
--- a/lms/templates/course_modes/choose.html
+++ b/lms/templates/course_modes/choose.html
@@ -42,7 +42,7 @@ from openedx.core.djangolib.markup import HTML, Text
});
% if use_ecommerce_payment_flow:
- $('input[name=verified_mode]').click(function(e){
+ $('button[name=verified_mode]').click(function(e){
e.preventDefault();
window.location.href = '${ecommerce_payment_page | n, js_escaped_string}?sku=' +
encodeURIComponent('${sku | n, js_escaped_string}');
@@ -77,6 +77,10 @@ from openedx.core.djangolib.markup import HTML, Text
+ % if offer_banner_fragment:
+ ${HTML(offer_banner_fragment.content)}
+ % endif
+
+
% endif
diff --git a/themes/edx.org/lms/templates/course_modes/choose.html b/themes/edx.org/lms/templates/course_modes/choose.html
index 79ed10a561..557328a2e4 100644
--- a/themes/edx.org/lms/templates/course_modes/choose.html
+++ b/themes/edx.org/lms/templates/course_modes/choose.html
@@ -45,16 +45,11 @@ from openedx.core.djangolib.markup import HTML, Text
});
% if use_ecommerce_payment_flow:
- $('input[name=verified_mode]').click(function(e){
+ $('button[name=verified_mode]').click(function(e){
e.preventDefault();
window.location.href = '${ecommerce_payment_page | n, js_escaped_string}?sku=' +
encodeURIComponent('${sku | n, js_escaped_string}');
});
- $('.v2 button[name=verified_mode]').click(function(e){
- e.preventDefault();
- window.location.href = 'https://ecommerce.edx.org/coupons/redeem/?code=EDXTSV35&sku=' +
- encodeURIComponent('${sku | n, js_escaped_string}');
- });
% endif
});
@@ -83,54 +78,27 @@ from openedx.core.djangolib.markup import HTML, Text
%endif
+
-
+
${title_content}
-
-
- Next, Select Your Learning Path
-
+ % if offer_banner_fragment:
+ ${HTML(offer_banner_fragment.content)}
+ % endif
+
- -
-
- % if content_gating_enabled or course_duration_limit_enabled:
-
- % else:
-
- % endif
-
+ <%include file='_upgrade_button.html' args='content_gating_enabled=content_gating_enabled, course_duration_limit_enabled=course_duration_limit_enabled, min_price=min_price, price_before_discount=price_before_discount' />