add first purchase discount banner on course home
This commit is contained in:
@@ -20,6 +20,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
// First purchase offer banner
|
||||
.first-purchase-offer-banner {
|
||||
background-color: #DEE3F1;
|
||||
font-size: 16px;
|
||||
border-radius: 7px;
|
||||
padding: 20px;
|
||||
margin: 20px auto;
|
||||
|
||||
.first-purchase-offer-banner-bold {
|
||||
font-weight: bold;
|
||||
color: #23419F;
|
||||
margin-right: 3px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Course call to action message
|
||||
.course-message {
|
||||
display: flex;
|
||||
|
||||
@@ -47,6 +47,10 @@ USE_BOOTSTRAP_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'use_bootstrap', fl
|
||||
SEO_WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='seo')
|
||||
COURSE_ENABLE_UNENROLLED_ACCESS_FLAG = CourseWaffleFlag(SEO_WAFFLE_FLAG_NAMESPACE, 'enable_anonymous_courseware_access')
|
||||
|
||||
# Flag to control display of first purchase offer banner
|
||||
FIRST_PURCHASE_OFFER_BANNER = WaffleFlagNamespace(name='first_purchase_offer_banner')
|
||||
FIRST_PURCHASE_OFFER_BANNER_DISPLAY = WaffleFlag(FIRST_PURCHASE_OFFER_BANNER, 'display', flag_undefined_default=False)
|
||||
|
||||
|
||||
def course_home_page_title(course): # pylint: disable=unused-argument
|
||||
"""
|
||||
|
||||
@@ -81,6 +81,9 @@ from openedx.features.portfolio_project import INCLUDE_PORTFOLIO_UPSELL_MODAL
|
||||
</header>
|
||||
<div class="page-content">
|
||||
<div class="page-content-main">
|
||||
% if offer_banner_fragment:
|
||||
${HTML(offer_banner_fragment.content)}
|
||||
% endif
|
||||
% if course_expiration_fragment:
|
||||
${HTML(course_expiration_fragment.content)}
|
||||
% endif
|
||||
|
||||
@@ -21,6 +21,7 @@ from waffle.testutils import override_flag
|
||||
from course_modes.models import CourseMode
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from courseware.tests.helpers import get_expiration_banner_text
|
||||
|
||||
from django_comment_client.tests.factories import RoleFactory
|
||||
from django_comment_common.models import (
|
||||
FORUM_ROLE_ADMINISTRATOR,
|
||||
@@ -48,6 +49,7 @@ from openedx.features.course_duration_limits.config import EXPERIMENT_DATA_HOLDB
|
||||
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
|
||||
from openedx.features.course_experience import (
|
||||
COURSE_ENABLE_UNENROLLED_ACCESS_FLAG,
|
||||
FIRST_PURCHASE_OFFER_BANNER_DISPLAY,
|
||||
SHOW_REVIEWS_TOOL_FLAG,
|
||||
SHOW_UPGRADE_MSG_ON_COURSE_HOME,
|
||||
UNIFIED_COURSE_TAB_FLAG
|
||||
@@ -409,6 +411,19 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
|
||||
)
|
||||
self.assertRedirects(response, expected_url)
|
||||
|
||||
@override_waffle_flag(FIRST_PURCHASE_OFFER_BANNER_DISPLAY, active=True)
|
||||
def test_first_purchase_offer_banner(self):
|
||||
"""
|
||||
Ensure first purchase offer banner displays correctly
|
||||
"""
|
||||
user = self.create_user_for_course(self.course, CourseUserType.ENROLLED)
|
||||
self.client.login(username=user.username, password=self.TEST_PASSWORD)
|
||||
url = course_home_url(self.course)
|
||||
response = self.client.get(url)
|
||||
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>'''
|
||||
self.assertContains(response, bannerText, html=True)
|
||||
|
||||
@mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False})
|
||||
def test_course_does_not_expire_for_verified_user(self):
|
||||
"""
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
Common utilities for the course experience, including course outline.
|
||||
"""
|
||||
from completion.models import BlockCompletion
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from lms.djangoapps.course_api.blocks.api import get_blocks
|
||||
from lms.djangoapps.course_blocks.utils import get_student_module_as_dict
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from openedx.core.djangolib.markup import HTML
|
||||
from openedx.core.lib.cache_utils import request_cached
|
||||
from openedx.features.course_experience import FIRST_PURCHASE_OFFER_BANNER_DISPLAY
|
||||
from web_fragments.fragment import Fragment
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
|
||||
@@ -182,3 +186,17 @@ def get_resume_block(block):
|
||||
if resume_block:
|
||||
return resume_block
|
||||
return block
|
||||
|
||||
|
||||
def get_first_purchase_offer_banner_fragment(user, course):
|
||||
if FIRST_PURCHASE_OFFER_BANNER_DISPLAY.is_enabled() and user and course:
|
||||
# Translator: xgettext:no-python-format
|
||||
offer_message = _(u'{banner_open}15% off your first upgrade.{span_close}'
|
||||
u' Discount automatically applied.{div_close}')
|
||||
return Fragment(HTML(offer_message).format(
|
||||
banner_open=HTML(
|
||||
'<div class="first-purchase-offer-banner"><span class="first-purchase-offer-banner-bold">'
|
||||
),
|
||||
span_close=HTML('</span>'),
|
||||
div_close=HTML('</div>')
|
||||
))
|
||||
|
||||
@@ -31,6 +31,7 @@ from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
|
||||
from openedx.core.djangoapps.util.maintenance_banner import add_maintenance_banner
|
||||
from openedx.features.course_duration_limits.access import generate_course_expired_fragment
|
||||
from openedx.features.course_experience.course_tools import CourseToolsPluginManager
|
||||
from openedx.features.course_experience.utils import get_first_purchase_offer_banner_fragment
|
||||
from student.models import CourseEnrollment
|
||||
from util.views import ensure_valid_course_key
|
||||
from xmodule.course_module import COURSE_VISIBILITY_PUBLIC, COURSE_VISIBILITY_PUBLIC_OUTLINE
|
||||
@@ -139,6 +140,7 @@ class CourseHomeFragmentView(EdxFragmentView):
|
||||
outline_fragment = None
|
||||
update_message_fragment = None
|
||||
course_sock_fragment = None
|
||||
offer_banner_fragment = None
|
||||
course_expiration_fragment = None
|
||||
has_visited_course = None
|
||||
resume_course_url = None
|
||||
@@ -159,9 +161,14 @@ class CourseHomeFragmentView(EdxFragmentView):
|
||||
course_sock_fragment = CourseSockFragmentView().render_to_fragment(request, course=course, **kwargs)
|
||||
has_visited_course, resume_course_url = self._get_resume_course_info(request, course_id)
|
||||
handouts_html = self._get_course_handouts(request, course)
|
||||
course_overview = CourseOverview.get_from_id(course.id)
|
||||
offer_banner_fragment = get_first_purchase_offer_banner_fragment(
|
||||
request.user,
|
||||
course_overview
|
||||
)
|
||||
course_expiration_fragment = generate_course_expired_fragment(
|
||||
request.user,
|
||||
CourseOverview.get_from_id(course.id)
|
||||
course_overview
|
||||
)
|
||||
elif allow_public_outline or allow_public:
|
||||
outline_fragment = CourseOutlineFragmentView().render_to_fragment(
|
||||
@@ -212,6 +219,7 @@ class CourseHomeFragmentView(EdxFragmentView):
|
||||
'outline_fragment': outline_fragment,
|
||||
'handouts_html': handouts_html,
|
||||
'course_home_message_fragment': course_home_message_fragment,
|
||||
'offer_banner_fragment': offer_banner_fragment,
|
||||
'course_expiration_fragment': course_expiration_fragment,
|
||||
'has_visited_course': has_visited_course,
|
||||
'resume_course_url': resume_course_url,
|
||||
|
||||
Reference in New Issue
Block a user