diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py index a78b4effe5..d21d4e80eb 100644 --- a/common/djangoapps/student/models.py +++ b/common/djangoapps/student/models.py @@ -18,6 +18,8 @@ from pytz import UTC import uuid from collections import defaultdict from dogapi import dog_stats_api +from django.db.models import Q +import pytz from django.conf import settings from django.utils import timezone @@ -960,6 +962,17 @@ class CourseEnrollment(models.Model): d['total'] = total return d + def is_paid_course(self): + """ + Returns True, if course is paid + """ + paid_course = CourseMode.objects.filter(Q(course_id=self.course_id) & Q(mode_slug='honor') & + (Q(expiration_datetime__isnull=True) | Q(expiration_datetime__gte=datetime.now(pytz.UTC)))).exclude(min_price=0) + if paid_course: + return True + + return False + def activate(self): """Makes this `CourseEnrollment` record active. Saves immediately.""" self.update_enrollment(is_active=True) @@ -991,6 +1004,8 @@ class CourseEnrollment(models.Model): if GeneratedCertificate.certificate_for_student(self.user, self.course_id) is not None: return False + #TODO - When Course administrators to define a refund period for paid courses then refundable will be supported. # pylint: disable=W0511 + course_mode = CourseMode.mode_for_course(self.course_id, 'verified') if course_mode is None: return False diff --git a/common/djangoapps/student/tests/tests.py b/common/djangoapps/student/tests/tests.py index 0be58d64e5..9afc044f57 100644 --- a/common/djangoapps/student/tests/tests.py +++ b/common/djangoapps/student/tests/tests.py @@ -148,11 +148,6 @@ class DashboardTest(TestCase): self.course = CourseFactory.create(org=self.COURSE_ORG, display_name=self.COURSE_NAME, number=self.COURSE_SLUG) self.assertIsNotNone(self.course) self.user = UserFactory.create(username="jack", email="jack@fake.edx.org", password='test') - CourseModeFactory.create( - course_id=self.course.id, - mode_slug='honor', - mode_display_name='Honor Code', - ) self.client = Client() @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @@ -230,6 +225,26 @@ class DashboardTest(TestCase): verified_mode.save() self.assertFalse(enrollment.refundable()) + @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + def test_refundable_of_purchased_course(self): + + self.client.login(username="jack", password="test") + CourseModeFactory.create( + course_id=self.course.id, + mode_slug='honor', + min_price=10, + currency='usd', + mode_display_name='honor', + expiration_datetime=datetime.now(pytz.UTC) + timedelta(days=1) + ) + enrollment = CourseEnrollment.enroll(self.user, self.course.id, mode='honor') + + # TODO: Until we can allow course administrators to define a refund period for paid for courses show_refund_option should be False. # pylint: disable=W0511 + self.assertFalse(enrollment.refundable()) + + resp = self.client.post(reverse('student.views.dashboard', args=[])) + self.assertIn('You will not be refunded the amount you paid.', resp.content) + @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_refundable_when_certificate_exists(self): verified_mode = CourseModeFactory.create( diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index edcf9278ce..df8b9ce10a 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -483,6 +483,8 @@ def dashboard(request): show_refund_option_for = frozenset(course.id for course, _enrollment in course_enrollment_pairs if _enrollment.refundable()) + enrolled_courses_either_paid = frozenset(course.id for course, _enrollment in course_enrollment_pairs + if _enrollment.is_paid_course()) # get info w.r.t ExternalAuthMap external_auth_map = None try: @@ -535,6 +537,7 @@ def dashboard(request): 'duplicate_provider': None, 'logout_url': reverse(logout_user), 'platform_name': settings.PLATFORM_NAME, + 'enrolled_courses_either_paid': enrolled_courses_either_paid, 'provider_states': [], } diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index e03cda79ee..4f086d901c 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -302,7 +302,8 @@ <% show_email_settings = (course.id in show_email_settings_for) %> <% course_mode_info = all_course_modes.get(course.id) %> <% show_refund_option = (course.id in show_refund_option_for) %> - <%include file='dashboard/_dashboard_course_listing.html' args="course=course, enrollment=enrollment, show_courseware_link=show_courseware_link, cert_status=cert_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, show_refund_option = show_refund_option" /> + <% is_paid_course = (course.id in enrolled_courses_either_paid) %> + <%include file='dashboard/_dashboard_course_listing.html' args="course=course, enrollment=enrollment, show_courseware_link=show_courseware_link, cert_status=cert_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, show_refund_option = show_refund_option, is_paid_course = is_paid_course" /> % endfor diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html index 779de56636..d46634d520 100644 --- a/lms/templates/dashboard/_dashboard_course_listing.html +++ b/lms/templates/dashboard/_dashboard_course_listing.html @@ -1,4 +1,4 @@ -<%page args="course, enrollment, show_courseware_link, cert_status, show_email_settings, course_mode_info, show_refund_option" /> +<%page args="course, enrollment, show_courseware_link, cert_status, show_email_settings, course_mode_info, show_refund_option, is_paid_course" /> <%! from django.utils.translation import ugettext as _ %> <%! @@ -126,7 +126,19 @@ % endif % endif - % if enrollment.mode != "verified": + % if is_paid_course and show_refund_option: + ## Translators: The course's name will be added to the end of this sentence. + + ${_('Unregister')} + + % elif is_paid_course and not show_refund_option: + ## Translators: The course's name will be added to the end of this sentence. + + ${_('Unregister')} + + % elif enrollment.mode != "verified": ## Translators: The course's name will be added to the end of this sentence. ${_('Unregister')}