add discount banner to track selection

This commit is contained in:
Matthew Piatetsky
2019-05-22 16:45:50 -04:00
parent 05df361950
commit ad77392f8d
7 changed files with 118 additions and 96 deletions

1
.github/CODEOWNERS vendored
View File

@@ -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

View File

@@ -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'''<div class="first-purchase-offer-banner"><span class="first-purchase-offer-banner-bold">
15% off your first upgrade.</span> Discount automatically applied.</div>'''
button = u'''<button type="submit" name="verified_mode">
Pursue a Verified Certificate ($8.50 USD
<del>$10 USD</del>)
</button>'''
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

View File

@@ -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()

View File

@@ -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":

View File

@@ -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 {

View File

@@ -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
</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>')}
@@ -121,8 +125,12 @@ from openedx.core.djangolib.markup import HTML, Text
<div class="copy-inline list-actions">
<ul class="list-actions">
<li class="action action-select">
<input type="hidden" name="contribution" value="${min_price}" />
<input type="submit" name="verified_mode" value="${_('Pursue a Verified Certificate')} ($${min_price} USD)" />
<input type="hidden" name="contribution" value="${price_before_discount or min_price}" />
<button type="submit" name="verified_mode">
${_('Pursue a Verified Certificate')} ($${min_price} USD${Text(' {open}${price} USD{close})').format(price=price_before_discount,
open=HTML('<del>'),
close=HTML('</del>')) if price_before_discount else ')'}
</button>
</li>
</ul>
</div>
@@ -165,17 +173,25 @@ from openedx.core.djangolib.markup import HTML, Text
<div class="copy-inline list-actions">
<ul class="list-actions">
<li class="action action-select">
<input type="hidden" name="contribution" value="${min_price}" />
<input type="hidden" name="contribution" value="${price_before_discount or min_price}" />
% if content_gating_enabled or course_duration_limit_enabled:
<input type="submit" name="verified_mode" value="${_('Pursue the Verified Track')} ($${min_price} USD)" />
<button type="submit" name="verified_mode">
${_('Pursue the Verified Track')} ($${min_price} USD${Text(' {open}${price} USD{close})').format(price=price_before_discount,
open=HTML('<del>'),
close=HTML('</del>')) if price_before_discount else ')'}
</button>
% else:
<input type="submit" name="verified_mode" value="${_('Pursue a Verified Certificate')} ($${min_price} USD)" />
<button type="submit" name="verified_mode">
${_('Pursue a Verified Certificate')} ($${min_price} USD${Text(' {open}${price} USD{close})').format(price=price_before_discount,
open=HTML('<del>'),
close=HTML('</del>')) if price_before_discount else ')'}
</button>
% endif
</li>
</ul>
</div>
</div>
</p>
</p>
</div>
% endif
</div>

View File

@@ -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
});
</script>
@@ -83,54 +78,27 @@ from openedx.core.djangolib.markup import HTML, Text
%endif
<div id="currency_data" value="${currency_data}"></div>
<div class="container">
<section class="wrapper">
<div class="wrapper-register-choose wrapper-content-main">
<article class="register-choose content-main">
<header class="page-header content-main">
<h3 class="title v1">
<h3 class="title">
${title_content}
</h3>
<!-- This div was added as part of the LEARNER-1726 experiment. The v2 class should be removed if the experiment is implemented-->
<h3 class="title v2 hidden">
Next, Select Your Learning Path
</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>')}
%>
% if "verified" in modes:
<!-- This div was added as part of the LEARNER-1726 experiment. The v2 class should be removed if the experiment is implemented-->
<div class="register-choice register-choice-certificate v2 hidden">
<h4 class="title">Pursue a Verified Certificate</h4>
<div class="wrapper-copy-inline">
<div class="wrapper-copy-inline">
<div class="wrapper-copy">
Get premium level support throughout the course and commit to completion up front.
</div>
<img src="/static/images/cert-verified-thumb.png" class="visual-reference img-certificate" alt="Visual representation of a Certificate"/>
</div>
</div>
<div class="copy-inline">
<ul class="list-actions">
<li class="action action-select">
<input type="hidden" name="contribution" value="${min_price}" />
<!-- The class verified_mode should be added to this selector if the experiment is implemented-->
<div class="upgradev1">
<input type="submit" name="verified_mode" value="Upgrade to a Certificate ($${min_price} USD)" />
</div>
<div class="upgradev2 hidden">
<button type="submit" name="verified_mode">Upgrade to a Certificate (<del>$${min_price} USD</del>)</button>
<br>
<div class="savings-message">Save 5% if you upgrade now! ($${int(min_price * .95)} USD)</div>
</div>
</li>
</ul>
</div>
</div>
<div class="register-choice register-choice-certificate v1">
<div class="register-choice register-choice-certificate">
<div class="wrapper-copy">
<span class="deco-ribbon"></span>
% if has_credit_upsell:
@@ -170,8 +138,12 @@ from openedx.core.djangolib.markup import HTML, Text
<div class="copy-inline list-actions">
<ul class="list-actions">
<li class="action action-select">
<input type="hidden" name="contribution" value="${min_price}" />
<input type="submit" name="verified_mode" value="${_('Pursue a Verified Certificate')} ($${min_price} USD)" />
<input type="hidden" name="contribution" value="${price_before_discount or min_price}" />
<button type="submit" name="verified_mode">
${_('Pursue a Verified Certificate')} ($${min_price} USD${Text(' {open}${price} USD{close})').format(price=price_before_discount,
open=HTML('<del>'),
close=HTML('</del>')) if price_before_discount else ')'}
</button>
</li>
</ul>
</div>
@@ -216,11 +188,19 @@ from openedx.core.djangolib.markup import HTML, Text
<div class="copy-inline list-actions">
<ul class="list-actions">
<li class="action action-select">
<input type="hidden" name="contribution" value="${min_price}" />
<input type="hidden" name="contribution" value="${price_before_discount or min_price}" />
% if content_gating_enabled or course_duration_limit_enabled:
<input type="submit" name="verified_mode" value="${_('Pursue the Verified Track')} ($${min_price} USD)" />
<button type="submit" name="verified_mode">
${_('Pursue the Verified Track')} ($${min_price} USD${Text(' {open}${price} USD{close})').format(price=price_before_discount,
open=HTML('<del>'),
close=HTML('</del>')) if price_before_discount else ')'}
</button>
% else:
<input type="submit" name="verified_mode" value="${_('Pursue a Verified Certificate')} ($${min_price} USD)" />
<button type="submit" name="verified_mode">
${_('Pursue a Verified Certificate')} ($${min_price} USD${Text(' {open}${price} USD{close})').format(price=price_before_discount,
open=HTML('<del>'),
close=HTML('</del>')) if price_before_discount else ')'}
</button>
% endif
</li>
</ul>
@@ -254,50 +234,11 @@ from openedx.core.djangolib.markup import HTML, Text
</ul>
</div>
% elif "audit" in modes:
<span class="deco-divider v1">
<span class="copy">${_("or")}</span>
</span>
<!-- This div was added as part of the LEARNER-1726 experiment. The v2 class should be removed if the experiment is implemented-->
<span class="deco-divider v2 hidden">
<span class="deco-divider">
<span class="copy">${_("or")}</span>
</span>
<!-- This div was added as part of the LEARNER-1726 experiment. The v2 class should be removed if the experiment is implemented-->
<div class="register-choice register-choice-continue v2 hidden">
<h4 class="title">
I Don't Want to Upgrade or Donate Today
</h4>
<div class="wrapper-copy-inline">
<div class="wrapper-copy">
If you do not want to add a certificate or donate to edX's mission today, you can skip this step for now and continue to the course.
</div>
<img src="/static/images/edx-home-graphic.png" class="visual-reference img-donate" alt="Visual of two hands forming a heart shape" >
</div>
<div class="copy-inline">
<ul class="list-actions">
<li class="action action-select">
<a class="continue-link" href="/dashboard">Continue to Course</a>
</li>
</ul>
</div>
</div>
<!-- This div was added as part of the LEARNER-1726 experiment. The v2 class should be removed if the experiment is implemented-->
<div class="register-choice register-choice-v2-donate register-choice-view v2 hidden">
<h4 class="title">Donate to Support our Non-Profit Mission</h4>
<div class="wrapper-copy-inline">
<div class="wrapper-copy">
Even if you are not interested in pursuing a Verified Certificate, a donation helps edX continue to work towards its non-profit mission of making the world's best education more accessible to learners everywhere.
</div>
<div class="copy-inline">
<ul class="list-actions">
<a class="donation-link" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AG9VK2LC29L5Y">Donate and Continue to Course</a>
</ul>
</div>
</div>
</div>
<div class="register-choice register-choice-audit v1">
<div class="register-choice register-choice-audit">
<div class="wrapper-copy">
<span class="deco-ribbon"></span>
<h4 class="title">${_("Audit This Course (No Certificate)")}</h4>