diff --git a/cms/envs/common.py b/cms/envs/common.py index 379794faea..8070c0a931 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -1177,6 +1177,7 @@ INSTALLED_APPS = [ 'openedx.features.course_duration_limits', 'openedx.features.content_type_gating', + 'openedx.features.discounts', 'experiments', ] diff --git a/lms/static/sass/features/_course-upgrade-message.scss b/lms/static/sass/features/_course-upgrade-message.scss index bcc0e45ee0..7ad6abdc68 100644 --- a/lms/static/sass/features/_course-upgrade-message.scss +++ b/lms/static/sass/features/_course-upgrade-message.scss @@ -30,9 +30,12 @@ Search for the courseware_verified_certificate_upsell promotion ID. } .section-upgrade .upgrade-container { + margin-top: 15px; +} + +.section-upgrade.no-discount .upgrade-container { float: right; text-align: center; - margin-top: 15px; } @media only screen and (max-width: 991px) and (min-width: 768px) { @@ -45,6 +48,10 @@ Search for the courseware_verified_certificate_upsell promotion ID. margin: 0.5em 0; } +.section.section-upgrade.discount p { + display: inline-block; +} + .section-upgrade .btn-brand.btn-upgrade { color: white !important; } diff --git a/openedx/features/content_type_gating/partitions.py b/openedx/features/content_type_gating/partitions.py index b3e8c492da..c6ce2d7bdf 100644 --- a/openedx/features/content_type_gating/partitions.py +++ b/openedx/features/content_type_gating/partitions.py @@ -17,9 +17,11 @@ from web_fragments.fragment import Fragment from course_modes.models import CourseMode from lms.djangoapps.commerce.utils import EcommerceService +from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.lib.mobile_utils import is_request_from_mobile_app from openedx.features.content_type_gating.helpers import CONTENT_GATING_PARTITION_ID, FULL_ACCESS, LIMITED_ACCESS from openedx.features.content_type_gating.models import ContentTypeGatingConfig +from openedx.features.discounts.utils import format_strikeout_price from xmodule.partitions.partitions import UserPartition, UserPartitionError LOG = logging.getLogger(__name__) @@ -76,7 +78,8 @@ class ContentTypeGatingPartition(UserPartition): """ def access_denied_fragment(self, block, user, user_group, allowed_groups): course_key = self._get_course_key_from_course_block(block) - modes = CourseMode.modes_for_course_dict(course_key) + course = CourseOverview.get_from_id(course_key) + modes = CourseMode.modes_for_course_dict(course=course) verified_mode = modes.get(CourseMode.VERIFIED) if (verified_mode is None or user_group == FULL_ACCESS or user_group in allowed_groups): @@ -84,10 +87,13 @@ class ContentTypeGatingPartition(UserPartition): ecommerce_checkout_link = self._get_checkout_link(user, verified_mode.sku) request = crum.get_current_request() + + upgrade_price, _ = format_strikeout_price(user, course) + frag = Fragment(render_to_string('content_type_gating/access_denied_message.html', { 'mobile_app': request and is_request_from_mobile_app(request), 'ecommerce_checkout_link': ecommerce_checkout_link, - 'min_price': str(verified_mode.min_price) + 'min_price': upgrade_price, })) return frag diff --git a/openedx/features/content_type_gating/templates/content_type_gating/access_denied_message.html b/openedx/features/content_type_gating/templates/content_type_gating/access_denied_message.html index b47de960f5..f3c736dc12 100644 --- a/openedx/features/content_type_gating/templates/content_type_gating/access_denied_message.html +++ b/openedx/features/content_type_gating/templates/content_type_gating/access_denied_message.html @@ -12,7 +12,7 @@ {% if not mobile_app and ecommerce_checkout_link %} - {% trans "Upgrade to unlock" %} (${{min_price}} USD) + {% trans "Upgrade to unlock" %} ({{min_price}}) {% endif %} diff --git a/openedx/features/content_type_gating/tests/test_access.py b/openedx/features/content_type_gating/tests/test_access.py index 2d8d2d7ad0..65f9c38f83 100644 --- a/openedx/features/content_type_gating/tests/test_access.py +++ b/openedx/features/content_type_gating/tests/test_access.py @@ -15,11 +15,12 @@ from django.test.utils import override_settings from django.urls import reverse from django.utils import timezone from django.contrib.auth.models import User -from mock import patch +from mock import patch, Mock from pyquery import PyQuery as pq from six.moves.html_parser import HTMLParser +from course_modes.models import CourseMode from course_api.blocks.api import get_blocks from course_modes.tests.factories import CourseModeFactory from experiments.models import ExperimentData, ExperimentKeyValue @@ -42,6 +43,7 @@ from openedx.core.djangoapps.django_comment_common.models import ( ) from openedx.core.djangoapps.user_api.tests.factories import UserCourseTagFactory from openedx.core.djangoapps.util.testing import TestConditionalContent +from openedx.core.djangolib.markup import HTML from openedx.core.lib.url_utils import quote_slashes from openedx.features.content_type_gating.helpers import CONTENT_GATING_PARTITION_ID, CONTENT_TYPE_GATE_GROUP_IDS from openedx.features.content_type_gating.models import ContentTypeGatingConfig @@ -780,6 +782,22 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase): request_factory=self.factory, ) + @patch( + 'openedx.features.content_type_gating.partitions.format_strikeout_price', + Mock(return_value=(HTML("DISCOUNT_PRICE"), True)) + ) + def test_discount_display(self): + + with patch.object(ContentTypeGatingPartition, '_get_checkout_link', return_value='#'): + block_content = _get_content_from_lms_index( + block=self.blocks_dict['problem'], + user_id=self.audit_user.id, + course=self.course, + request_factory=self.factory, + ) + + assert 'DISCOUNT_PRICE' in block_content + @override_settings(FIELD_OVERRIDE_PROVIDERS=( 'openedx.features.content_type_gating.field_override.ContentTypeGatingFieldOverride', diff --git a/openedx/features/content_type_gating/tests/test_partitions.py b/openedx/features/content_type_gating/tests/test_partitions.py index a6e6a6f8f8..b05b4d76f3 100644 --- a/openedx/features/content_type_gating/tests/test_partitions.py +++ b/openedx/features/content_type_gating/tests/test_partitions.py @@ -13,6 +13,7 @@ from openedx.core.djangolib.testing.utils import CacheIsolationTestCase from openedx.features.content_type_gating.helpers import CONTENT_GATING_PARTITION_ID, FULL_ACCESS, LIMITED_ACCESS from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.content_type_gating.partitions import ContentTypeGatingPartition, create_content_gating_partition +from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory from student.tests.factories import GroupFactory from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID, UserPartitionError @@ -20,6 +21,7 @@ from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID, UserPar class TestContentTypeGatingPartition(CacheIsolationTestCase): def setUp(self): self.course_key = CourseKey.from_string('course-v1:test+course+key') + CourseOverviewFactory.create(id=self.course_key) def test_create_content_gating_partition_happy_path(self): @@ -117,7 +119,7 @@ class TestContentTypeGatingPartition(CacheIsolationTestCase): message = partition.access_denied_message(mock_block.scope_ids.usage_id, global_staff, FULL_ACCESS, 'test_allowed_group') self.assertIsNone(message) - def test_acess_denied_fragment_for_null_request(self): + def test_access_denied_fragment_for_null_request(self): """ Verifies the access denied fragment is visible when HTTP request is not available. diff --git a/openedx/features/course_experience/templates/course_experience/course-home-fragment.html b/openedx/features/course_experience/templates/course_experience/course-home-fragment.html index c90825a9dd..ee08433af7 100644 --- a/openedx/features/course_experience/templates/course_experience/course-home-fragment.html +++ b/openedx/features/course_experience/templates/course_experience/course-home-fragment.html @@ -13,7 +13,7 @@ from django.urls import reverse from lms.djangoapps.discussion.django_comment_client.permissions import has_permission from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string -from openedx.core.djangolib.markup import HTML +from openedx.core.djangolib.markup import Text, HTML from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, SHOW_REVIEWS_TOOL_FLAG %> @@ -124,7 +124,7 @@ from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, SHOW_REV % endif % if upgrade_url and upgrade_price: -