diff --git a/common/djangoapps/entitlements/models.py b/common/djangoapps/entitlements/models.py
index 3fea5e07b5..66ddec0231 100644
--- a/common/djangoapps/entitlements/models.py
+++ b/common/djangoapps/entitlements/models.py
@@ -257,3 +257,32 @@ class CourseEntitlement(TimeStampedModel):
@classmethod
def unexpired_entitlements_for_user(cls, user):
return cls.objects.filter(user=user, expired_at=None).select_related('user')
+
+ @classmethod
+ def get_entitlement_if_active(cls, user, course_uuid):
+ """
+ Returns an entitlement for a given course uuid if an active entitlement exists, otherwise returns None.
+ An active entitlement is defined as an entitlement that has not yet expired or has a currently enrolled session.
+ """
+ return cls.objects.filter(
+ user=user,
+ course_uuid=course_uuid
+ ).exclude(expired_at__isnull=False, enrollment_course_run=None).first()
+
+ @classmethod
+ def get_active_entitlements_for_user(cls, user):
+ """
+ Returns a list of active (enrolled or not yet expired) entitlements.
+
+ Returns any entitlements that are:
+ 1) Not expired and no session selected
+ 2) Not expired and a session is selected
+ 3) Expired and a session is selected
+
+ Does not return any entitlements that are:
+ 1) Expired and no session selected
+ """
+ return cls.objects.filter(user=user).exclude(
+ expired_at__isnull=False,
+ enrollment_course_run=None
+ ).select_related('user').select_related('enrollment_course_run')
diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py
index 933ce59cdd..c8266b9a0c 100644
--- a/common/djangoapps/student/tests/test_views.py
+++ b/common/djangoapps/student/tests/test_views.py
@@ -376,11 +376,15 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
@patch.object(CourseOverview, 'get_from_id')
def test_unfulfilled_expired_entitlement(self, mock_course_overview, mock_course_runs):
"""
- When a learner has an unfulfilled, expired entitlement, their course dashboard should have:
- - a hidden 'View Course' button
- - a message saying that they can no longer select a session
+ When a learner has an unfulfilled, expired entitlement, a card should NOT appear on the dashboard.
+ This use case represents either an entitlement that the user waited too long to fulfill, or an entitlement
+ for which they received a refund.
"""
- CourseEntitlementFactory(user=self.user, created=self.THREE_YEARS_AGO)
+ CourseEntitlementFactory(
+ user=self.user,
+ created=self.THREE_YEARS_AGO,
+ expired_at=datetime.datetime.now()
+ )
mock_course_overview.return_value = CourseOverviewFactory(start=self.TOMORROW)
mock_course_runs.return_value = [
{
@@ -391,9 +395,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
}
]
response = self.client.get(self.path)
- self.assertIn('class="enter-course hidden"', response.content)
- self.assertIn('You can no longer select a session', response.content)
- self.assertNotIn('
'), 0)
@patch('student.views.get_course_runs_for_course')
@patch.object(CourseOverview, 'get_from_id')
diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py
index 9fc071c837..5c07b4585d 100644
--- a/common/djangoapps/student/views.py
+++ b/common/djangoapps/student/views.py
@@ -698,7 +698,7 @@ def dashboard(request):
course_enrollments = list(get_course_enrollments(user, site_org_whitelist, site_org_blacklist))
# Get the entitlements for the user and a mapping to all available sessions for that entitlement
- course_entitlements = list(CourseEntitlement.objects.filter(user=user).select_related('enrollment_course_run'))
+ course_entitlements = list(CourseEntitlement.get_active_entitlements_for_user(user))
course_entitlement_available_sessions = {}
for course_entitlement in course_entitlements:
course_entitlement.update_expired_at()
diff --git a/lms/static/js/spec/learner_dashboard/course_card_view_spec.js b/lms/static/js/spec/learner_dashboard/course_card_view_spec.js
index 2fa0c250d3..0e44a48f88 100644
--- a/lms/static/js/spec/learner_dashboard/course_card_view_spec.js
+++ b/lms/static/js/spec/learner_dashboard/course_card_view_spec.js
@@ -234,16 +234,6 @@ define([
expect(view.$('.course-title-link').length).toEqual(0);
});
- it('should show an unfulfilled expired user entitlement not allowing the changing of sessions', function() {
- course.user_entitlement = {
- uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
- course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
- expired_at: '2017-12-06 01:06:12',
- expiration_date: '2017-12-05 01:06:12'
- };
- setupView(course, false);
- expect(view.$('.info-expires-at').text().trim()).toContain('You can no longer select a session. Your');
- });
it('should show an unfulfilled user entitlement allows you to select a session', function() {
course.user_entitlement = {
diff --git a/lms/static/sass/views/_program-details.scss b/lms/static/sass/views/_program-details.scss
index cb0724d40f..654ab230cc 100644
--- a/lms/static/sass/views/_program-details.scss
+++ b/lms/static/sass/views/_program-details.scss
@@ -356,12 +356,16 @@
background-color: palette(primary, dark);
height: 37px;
width: 128px;
- border-radius: 0;
padding: 0;
margin-bottom: 5px;
margin-top: 7px;
font-size: 0.9375em;
+ &:hover {
+ color: palette(primary, dark);
+ background-color: theme-color("inverse");
+ }
+
/* IE11 CSS styles */
@media (min-width: $bp-screen-md) and (-ms-high-contrast: none), (-ms-high-contrast: active) {
@include float(right);
@@ -393,14 +397,7 @@
}
.run-select {
- @include margin-right(10px);
-
- width: 95%;
-
- @media (min-width: $bp-screen-sm) {
- width: 300px;
- }
-
+ width: 100%;
height: 34px;
padding: 0;
}
@@ -511,7 +508,7 @@
.course-actions {
@media (min-width: $bp-screen-md) {
- width: 200px;
+ width: 100%;
text-align: right;
float: right;
}
diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html
index 939294c758..4e07740307 100644
--- a/lms/templates/dashboard/_dashboard_course_listing.html
+++ b/lms/templates/dashboard/_dashboard_course_listing.html
@@ -131,9 +131,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
% if is_unfulfilled_entitlement:
- % if entitlement_expired_at:
- ${_('You can no longer select a session, your final day to select a session was {entitlement_expired_at}.').format(entitlement_expired_at=entitlement_expired_at)}
- % else:
+ % if not entitlement_expired_at:
% if entitlement_expiration_date:
${_('You must select a session by {expiration_date} to access the course.').format(expiration_date=entitlement_expiration_date)}
% else:
@@ -156,7 +154,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
% if entitlement and not is_unfulfilled_entitlement and entitlement_expiration_date:
-
+
% if entitlement_expired_at:
${_('You can no longer change sessions.')}
% else:
diff --git a/lms/templates/learner_dashboard/course_card.underscore b/lms/templates/learner_dashboard/course_card.underscore
index 53f8d35469..3c238e95b2 100644
--- a/lms/templates/learner_dashboard/course_card.underscore
+++ b/lms/templates/learner_dashboard/course_card.underscore
@@ -25,9 +25,7 @@
<% if (user_entitlement && user_entitlement.expiration_date) { %>
<% if (is_unfulfilled_entitlement) { %>
- <% if (user_entitlement.expired_at) { %>
- <%- StringUtils.interpolate(gettext('You can no longer select a session. Your final day to select a session was {expiration_date}.'), {expiration_date: user_entitlement.expiration_date}) %>
- <% } else { %>
+ <% if (!user_entitlement.expired_at) { %>
<%- StringUtils.interpolate(gettext('You must select a session by {expiration_date} to access the course.'), {expiration_date: user_entitlement.expiration_date}) %>
<% } %>
<% } else { %>
diff --git a/lms/templates/learner_dashboard/course_enroll.underscore b/lms/templates/learner_dashboard/course_enroll.underscore
index c12271a201..0038abfb2f 100644
--- a/lms/templates/learner_dashboard/course_enroll.underscore
+++ b/lms/templates/learner_dashboard/course_enroll.underscore
@@ -16,7 +16,7 @@
<% if (enrollable_course_runs.length > 1) { %>