def test_is_enabled(self): """Verify that is_enabled() returns True when ecomm checkout is enabled. """ is_enabled = EcommerceService().is_enabled(self.request) self.assertTrue(is_enabled) config = CommerceConfiguration.current() config.checkout_on_ecommerce_service = False config.save() is_not_enabled = EcommerceService().is_enabled(self.request) self.assertFalse(is_not_enabled)
def program_details(request, program_uuid): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.enabled: raise Http404 meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 program_data = ProgramDataExtender(program_data, request.user).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') skus = program_data.get('skus') ecommerce_service = EcommerceService() urls = { 'program_listing_url': reverse('program_listing_view'), 'track_selection_url': strip_course_id( reverse('course_modes_choose', kwargs={'course_id': FAKE_COURSE_KEY})), 'commerce_api_url': reverse('commerce_api:v0:baskets:create'), 'buy_button_url': ecommerce_service.get_checkout_page_url(*skus) } context = { 'urls': urls, 'show_program_listing': programs_config.enabled, 'show_dashboard_tabs': True, 'nav_hidden': True, 'disable_courseware_js': True, 'uses_pattern_library': True, 'user_preferences': get_user_preferences(request.user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data } return render_to_response('learner_dashboard/program_details.html', context)
def get_verification_context(self, request, course): course_key = CourseKey.from_string(unicode(course.id)) # Establish whether the course has a verified mode available_modes = CourseMode.modes_for_course_dict(unicode(course.id)) has_verified_mode = CourseMode.has_verified_mode(available_modes) # Establish whether the user is already enrolled is_already_verified = CourseEnrollment.is_enrolled_as_verified( request.user, course_key) # Establish whether the verification deadline has already passed verification_deadline = VerifiedUpgradeDeadlineDate( course, request.user) deadline_has_passed = verification_deadline.deadline_has_passed() # If this proves its worth, we can internationalize and display for more than English speakers. show_course_sock = (has_verified_mode and not is_already_verified and not deadline_has_passed and get_language() == 'en') # Get information about the upgrade course_price = get_cosmetic_verified_display_price(course) upgrade_url = EcommerceService().upgrade_url(request.user, course_key) context = { 'show_course_sock': show_course_sock, 'course_price': course_price, 'course_id': course.id, 'upgrade_url': upgrade_url, } return context
def assert_upgrade_message_displayed(self): response = self.client.get(self.url) self.assertIn('vc-message', response.content) url = EcommerceService().get_checkout_page_url(self.verified_mode.sku) expected = '<a class="btn-upgrade" href="{url}">Upgrade (${price})</a>'.format( url=url, price=self.verified_mode.min_price) self.assertIn(expected, response.content)
def test_get_receipt_page_url(self): """Verify that the proper Receipt page URL is returned.""" order_number = 'ORDER1' url = EcommerceService().get_receipt_page_url(order_number) expected_url = 'http://ecommerce_url/checkout/receipt/?order_number={}'.format( order_number) self.assertEqual(url, expected_url)
def test_get_checkout_page_url(self, skus): """ Verify the checkout page URL is properly constructed and returned. """ url = EcommerceService().get_checkout_page_url(*skus) expected_url = '{root}/test_basket/?{skus}'.format( root=settings.ECOMMERCE_PUBLIC_URL_ROOT, skus=urlencode({'sku': skus}, doseq=True), ) self.assertEqual(url, expected_url)
def assert_upgrade_message_displayed(self): response = self.client.get(self.url) self.assertIn('vc-message', response.content) url = EcommerceService().get_checkout_page_url(self.verified_mode.sku) self.assertIn('<a class="btn btn-upgrade"', response.content) self.assertIn(url, response.content) self.assertIn( 'Upgrade (${price})</a>'.format( price=self.verified_mode.min_price), response.content)
def program_details(request, program_uuid): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.enabled: raise Http404 meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 program_data = ProgramDataExtender(program_data, request.user).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') skus = program_data.get('skus') ecommerce_service = EcommerceService() urls = { 'program_listing_url': reverse('program_listing_view'), 'track_selection_url': strip_course_id( reverse('course_modes_choose', kwargs={'course_id': FAKE_COURSE_KEY}) ), 'commerce_api_url': reverse('commerce_api:v0:baskets:create'), 'buy_button_url': ecommerce_service.get_checkout_page_url(*skus) } context = { 'urls': urls, 'show_program_listing': programs_config.enabled, 'show_dashboard_tabs': True, 'nav_hidden': True, 'disable_courseware_js': True, 'uses_pattern_library': True, 'user_preferences': get_user_preferences(request.user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data } return render_to_response('learner_dashboard/program_details.html', context)
def test_get_receipt_page_url_with_site_configuration(self): order_number = 'ORDER1' config = CommerceConfiguration.current() config.use_ecommerce_receipt_page = True config.save() receipt_page_url = EcommerceService().get_receipt_page_url( order_number) expected_url = '{ecommerce_root}{receipt_page_url}{order_number}'.format( ecommerce_root=settings.ECOMMERCE_PUBLIC_URL_ROOT, order_number=order_number, receipt_page_url=TEST_SITE_CONFIGURATION[ 'ECOMMERCE_RECEIPT_PAGE_URL']) self.assertEqual(receipt_page_url, expected_url)
def _redirect_if_necessary( self, message, already_verified, already_paid, is_enrolled, course_key, # pylint: disable=bad-continuation user_is_trying_to_pay, user, sku # pylint: disable=bad-continuation ): """Redirect the user to a more appropriate page if necessary. In some cases, a user may visit this page with verification / enrollment / payment state that we don't anticipate. For example, a user may unenroll from the course after paying for it, then visit the "verify now" page to complete verification. When this happens, we try to redirect the user to the most appropriate page. Arguments: message (string): The messaging of the page. Should be a key in `MESSAGES`. already_verified (bool): Whether the user has submitted a verification request recently. already_paid (bool): Whether the user is enrolled in a paid course mode. is_enrolled (bool): Whether the user has an active enrollment in the course. course_key (CourseKey): The key for the course. Returns: HttpResponse or None """ url = None course_kwargs = {'course_id': unicode(course_key)} if already_verified and already_paid: # If they've already paid and verified, there's nothing else to do, # so redirect them to the dashboard. if message != self.PAYMENT_CONFIRMATION_MSG: url = reverse('dashboard') elif message in [ self.VERIFY_NOW_MSG, self.VERIFY_LATER_MSG, self.PAYMENT_CONFIRMATION_MSG ]: if is_enrolled: # If the user is already enrolled but hasn't yet paid, # then the "upgrade" messaging is more appropriate. if not already_paid: url = reverse('verify_student_upgrade_and_verify', kwargs=course_kwargs) else: # If the user is NOT enrolled, then send him/her # to the first time verification page. url = reverse('verify_student_start_flow', kwargs=course_kwargs) elif message == self.UPGRADE_MSG: if is_enrolled: if already_paid: # If the student has paid, but not verified, redirect to the verification flow. url = reverse('verify_student_verify_now', kwargs=course_kwargs) else: url = reverse('verify_student_start_flow', kwargs=course_kwargs) if user_is_trying_to_pay and self._get_user_active_status( user) and not already_paid: # If the user is trying to pay, has activated their account, and the ecommerce service # is enabled redirect him to the ecommerce checkout page. ecommerce_service = EcommerceService() if ecommerce_service.is_enabled(user): url = ecommerce_service.checkout_page_url(sku) # Redirect if necessary, otherwise implicitly return None if url is not None: return redirect(url)
def render_to_fragment(self, request, course_id=None, **kwargs): """ Renders the course's home page as a fragment. """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, 'load', course_key) # Render the course dates as a fragment dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id, **kwargs) # Render the full content to enrolled users, as well as to course and global staff. # Unenrolled users who are not course or global staff are given only a subset. enrollment = CourseEnrollment.get_enrollment(request.user, course_key) user_access = { 'is_anonymous': request.user.is_anonymous(), 'is_enrolled': enrollment is not None, 'is_staff': has_access(request.user, 'staff', course_key), } if user_access['is_enrolled'] or user_access['is_staff']: outline_fragment = CourseOutlineFragmentView().render_to_fragment(request, course_id=course_id, **kwargs) if LATEST_UPDATE_FLAG.is_enabled(course_key): update_message_fragment = LatestUpdateFragmentView().render_to_fragment( request, course_id=course_id, **kwargs ) else: update_message_fragment = WelcomeMessageFragmentView().render_to_fragment( request, course_id=course_id, **kwargs ) 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) else: # Redirect the user to the dashboard if they are not enrolled and # this is a course that does not support direct enrollment. if not can_self_enroll_in_course(course_key): raise CourseAccessRedirect(reverse('dashboard')) # Set all the fragments outline_fragment = None update_message_fragment = None course_sock_fragment = None has_visited_course = None resume_course_url = None # Get the handouts handouts_html = self._get_course_handouts(request, course) # Get the course tools enabled for this user and course course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key) # Check if the user can access the course goal functionality has_goal_permission = has_course_goal_permission(request, course_id, user_access) # Grab the current course goal and the acceptable course goal keys mapped to translated values current_goal = get_course_goal(request.user, course_key) goal_options = get_course_goal_options() # Get the course goals api endpoint goal_api_url = get_goal_api_url(request) # Grab the course home messages fragment to render any relevant django messages course_home_message_fragment = CourseHomeMessageFragmentView().render_to_fragment( request, course_id=course_id, user_access=user_access, **kwargs ) # Get info for upgrade messaging upgrade_price = None upgrade_url = None # TODO Add switch to control deployment if SHOW_UPGRADE_MSG_ON_COURSE_HOME.is_enabled(course_key) and enrollment and enrollment.upgrade_deadline: upgrade_url = EcommerceService().upgrade_url(request.user, course_key) upgrade_price = get_cosmetic_verified_display_price(course) # Render the course home fragment context = { 'request': request, 'csrf': csrf(request)['csrf_token'], 'course': course, 'course_key': course_key, 'outline_fragment': outline_fragment, 'handouts_html': handouts_html, 'course_home_message_fragment': course_home_message_fragment, 'has_visited_course': has_visited_course, 'resume_course_url': resume_course_url, 'course_tools': course_tools, 'dates_fragment': dates_fragment, 'username': request.user.username, 'goal_api_url': goal_api_url, 'has_goal_permission': has_goal_permission, 'goal_options': goal_options, 'current_goal': current_goal, 'update_message_fragment': update_message_fragment, 'course_sock_fragment': course_sock_fragment, 'disable_courseware_js': True, 'uses_pattern_library': True, 'upgrade_price': upgrade_price, 'upgrade_url': upgrade_url, } html = render_to_string('course_experience/course-home-fragment.html', context) return Fragment(html)
def _redirect_if_necessary( self, message, already_verified, already_paid, is_enrolled, course_key, # pylint: disable=bad-continuation user_is_trying_to_pay, user, sku # pylint: disable=bad-continuation ): """Redirect the user to a more appropriate page if necessary. In some cases, a user may visit this page with verification / enrollment / payment state that we don't anticipate. For example, a user may unenroll from the course after paying for it, then visit the "verify now" page to complete verification. When this happens, we try to redirect the user to the most appropriate page. Arguments: message (string): The messaging of the page. Should be a key in `MESSAGES`. already_verified (bool): Whether the user has submitted a verification request recently. already_paid (bool): Whether the user is enrolled in a paid course mode. is_enrolled (bool): Whether the user has an active enrollment in the course. course_key (CourseKey): The key for the course. Returns: HttpResponse or None """ url = None course_kwargs = {'course_id': unicode(course_key)} if already_verified and already_paid: # If they've already paid and verified, there's nothing else to do, # so redirect them to the dashboard. if message != self.PAYMENT_CONFIRMATION_MSG: url = reverse('dashboard') elif message in [self.VERIFY_NOW_MSG, self.VERIFY_LATER_MSG, self.PAYMENT_CONFIRMATION_MSG]: if is_enrolled: # If the user is already enrolled but hasn't yet paid, # then the "upgrade" messaging is more appropriate. if not already_paid: url = reverse('verify_student_upgrade_and_verify', kwargs=course_kwargs) else: # If the user is NOT enrolled, then send him/her # to the first time verification page. url = reverse('verify_student_start_flow', kwargs=course_kwargs) elif message == self.UPGRADE_MSG: if is_enrolled: if already_paid: # If the student has paid, but not verified, redirect to the verification flow. url = reverse('verify_student_verify_now', kwargs=course_kwargs) else: url = reverse('verify_student_start_flow', kwargs=course_kwargs) if user_is_trying_to_pay and self._get_user_active_status(user) and not already_paid: # If the user is trying to pay, has activated their account, and the ecommerce service # is enabled redirect him to the ecommerce checkout page. ecommerce_service = EcommerceService() if ecommerce_service.is_enabled(user): url = ecommerce_service.get_checkout_page_url(sku) # Redirect if necessary, otherwise implicitly return None if url is not None: return redirect(url)
def test_checkout_page_url(self): """ Verify the checkout page URL is properly constructed and returned. """ url = EcommerceService().checkout_page_url(self.SKU) expected_url = 'http://ecommerce_url/test_basket/?sku={}'.format(self.SKU) self.assertEqual(url, expected_url)
def test_payment_page_url(self): """Verify that the proper URL is returned.""" url = EcommerceService().payment_page_url() self.assertEqual(url, 'http://ecommerce_url/test_basket/')
def test_is_enabled_for_microsites(self, is_microsite): """Verify that is_enabled() returns False if used for a microsite.""" is_microsite.return_value = True is_not_enabled = EcommerceService().is_enabled(self.request) self.assertFalse(is_not_enabled)
def test_is_enabled_activation_requirement_disabled(self): """Verify that is_enabled() returns True when ecomm checkout is enabled. """ self.user.is_active = False self.user.save() is_enabled = EcommerceService().is_enabled(self.user) self.assertTrue(is_enabled)
def render_to_fragment(self, request, course_id=None, **kwargs): """ Renders the course's home page as a fragment. """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, 'load', course_key) # Render the course dates as a fragment dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id, **kwargs) # Render the full content to enrolled users, as well as to course and global staff. # Unenrolled users who are not course or global staff are given only a subset. enrollment = CourseEnrollment.get_enrollment(request.user, course_key) user_access = { 'is_anonymous': request.user.is_anonymous(), 'is_enrolled': enrollment is not None, 'is_staff': has_access(request.user, 'staff', course_key), } if user_access['is_enrolled'] or user_access['is_staff']: outline_fragment = CourseOutlineFragmentView().render_to_fragment(request, course_id=course_id, **kwargs) if LATEST_UPDATE_FLAG.is_enabled(course_key): update_message_fragment = LatestUpdateFragmentView().render_to_fragment( request, course_id=course_id, **kwargs ) else: update_message_fragment = WelcomeMessageFragmentView().render_to_fragment( request, course_id=course_id, **kwargs ) 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) else: # Redirect the user to the dashboard if they are not enrolled and # this is a course that does not support direct enrollment. if not can_self_enroll_in_course(course_key): raise CourseAccessRedirect(reverse('dashboard')) # Set all the fragments outline_fragment = None update_message_fragment = None course_sock_fragment = None has_visited_course = None resume_course_url = None # Get the handouts handouts_html = self._get_course_handouts(request, course) # Get the course tools enabled for this user and course course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key) # Grab the course home messages fragment to render any relevant django messages course_home_message_fragment = CourseHomeMessageFragmentView().render_to_fragment( request, course_id=course_id, user_access=user_access, **kwargs ) # Get info for upgrade messaging upgrade_price = None upgrade_url = None # TODO Add switch to control deployment if SHOW_UPGRADE_MSG_ON_COURSE_HOME.is_enabled(course_key) and enrollment and enrollment.upgrade_deadline: verified_mode = enrollment.verified_mode if verified_mode: upgrade_price = verified_mode.min_price ecommerce_service = EcommerceService() if ecommerce_service.is_enabled(request.user): upgrade_url = ecommerce_service.get_checkout_page_url(verified_mode.sku) else: upgrade_url = reverse('verify_student_upgrade_and_verify', args=(course_key,)) # Render the course home fragment context = { 'request': request, 'csrf': csrf(request)['csrf_token'], 'course': course, 'course_key': course_key, 'outline_fragment': outline_fragment, 'handouts_html': handouts_html, 'course_home_message_fragment': course_home_message_fragment, 'has_visited_course': has_visited_course, 'resume_course_url': resume_course_url, 'course_tools': course_tools, 'dates_fragment': dates_fragment, 'update_message_fragment': update_message_fragment, 'course_sock_fragment': course_sock_fragment, 'disable_courseware_js': True, 'uses_pattern_library': True, 'upgrade_price': upgrade_price, 'upgrade_url': upgrade_url, } html = render_to_string('course_experience/course-home-fragment.html', context) return Fragment(html)
def test_get_absolute_ecommerce_url(self): """Verify that the proper URL is returned.""" url = EcommerceService().get_absolute_ecommerce_url('/test_basket/') self.assertEqual(url, 'http://ecommerce_url/test_basket/')
def test_ecommerce_url_root(self): """Verify that the proper root URL is returned.""" self.assertEqual(EcommerceService().ecommerce_url_root, 'http://ecommerce_url')