Commit 75aa736d by Harry Rein

Do not show expired, unfulfilled entitlements on course/programs dashboard.

LEARNER-3636
parent ca46bfcf
...@@ -257,3 +257,32 @@ class CourseEntitlement(TimeStampedModel): ...@@ -257,3 +257,32 @@ class CourseEntitlement(TimeStampedModel):
@classmethod @classmethod
def unexpired_entitlements_for_user(cls, user): def unexpired_entitlements_for_user(cls, user):
return cls.objects.filter(user=user, expired_at=None).select_related('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')
...@@ -376,11 +376,15 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin): ...@@ -376,11 +376,15 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
@patch.object(CourseOverview, 'get_from_id') @patch.object(CourseOverview, 'get_from_id')
def test_unfulfilled_expired_entitlement(self, mock_course_overview, mock_course_runs): 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: When a learner has an unfulfilled, expired entitlement, a card should NOT appear on the dashboard.
- a hidden 'View Course' button This use case represents either an entitlement that the user waited too long to fulfill, or an entitlement
- a message saying that they can no longer select a session 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_overview.return_value = CourseOverviewFactory(start=self.TOMORROW)
mock_course_runs.return_value = [ mock_course_runs.return_value = [
{ {
...@@ -391,9 +395,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin): ...@@ -391,9 +395,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
} }
] ]
response = self.client.get(self.path) response = self.client.get(self.path)
self.assertIn('class="enter-course hidden"', response.content) self.assertEqual(response.content.count('<li class="course-item">'), 0)
self.assertIn('You can no longer select a session', response.content)
self.assertNotIn('<div class="course-entitlement-selection-container ">', response.content)
@patch('student.views.get_course_runs_for_course') @patch('student.views.get_course_runs_for_course')
@patch.object(CourseOverview, 'get_from_id') @patch.object(CourseOverview, 'get_from_id')
......
...@@ -698,7 +698,7 @@ def dashboard(request): ...@@ -698,7 +698,7 @@ def dashboard(request):
course_enrollments = list(get_course_enrollments(user, site_org_whitelist, site_org_blacklist)) 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 # 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 = {} course_entitlement_available_sessions = {}
for course_entitlement in course_entitlements: for course_entitlement in course_entitlements:
course_entitlement.update_expired_at() course_entitlement.update_expired_at()
......
...@@ -234,16 +234,6 @@ define([ ...@@ -234,16 +234,6 @@ define([
expect(view.$('.course-title-link').length).toEqual(0); 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() { it('should show an unfulfilled user entitlement allows you to select a session', function() {
course.user_entitlement = { course.user_entitlement = {
......
...@@ -356,12 +356,16 @@ ...@@ -356,12 +356,16 @@
background-color: palette(primary, dark); background-color: palette(primary, dark);
height: 37px; height: 37px;
width: 128px; width: 128px;
border-radius: 0;
padding: 0; padding: 0;
margin-bottom: 5px; margin-bottom: 5px;
margin-top: 7px; margin-top: 7px;
font-size: 0.9375em; font-size: 0.9375em;
&:hover {
color: palette(primary, dark);
background-color: theme-color("inverse");
}
/* IE11 CSS styles */ /* IE11 CSS styles */
@media (min-width: $bp-screen-md) and (-ms-high-contrast: none), (-ms-high-contrast: active) { @media (min-width: $bp-screen-md) and (-ms-high-contrast: none), (-ms-high-contrast: active) {
@include float(right); @include float(right);
...@@ -393,14 +397,7 @@ ...@@ -393,14 +397,7 @@
} }
.run-select { .run-select {
@include margin-right(10px); width: 100%;
width: 95%;
@media (min-width: $bp-screen-sm) {
width: 300px;
}
height: 34px; height: 34px;
padding: 0; padding: 0;
} }
...@@ -511,7 +508,7 @@ ...@@ -511,7 +508,7 @@
.course-actions { .course-actions {
@media (min-width: $bp-screen-md) { @media (min-width: $bp-screen-md) {
width: 200px; width: 100%;
text-align: right; text-align: right;
float: right; float: right;
} }
......
...@@ -131,9 +131,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_ ...@@ -131,9 +131,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
% if is_unfulfilled_entitlement: % if is_unfulfilled_entitlement:
<span class="info-date-block" aria-live="polite"> <span class="info-date-block" aria-live="polite">
<span class="icon fa fa-warning" aria-hidden="true"></span> <span class="icon fa fa-warning" aria-hidden="true"></span>
% if entitlement_expired_at: % if not 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 entitlement_expiration_date: % if entitlement_expiration_date:
${_('You must select a session by {expiration_date} to access the course.').format(expiration_date=entitlement_expiration_date)} ${_('You must select a session by {expiration_date} to access the course.').format(expiration_date=entitlement_expiration_date)}
% else: % else:
...@@ -156,7 +154,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_ ...@@ -156,7 +154,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
</span> </span>
% if entitlement and not is_unfulfilled_entitlement and entitlement_expiration_date: % if entitlement and not is_unfulfilled_entitlement and entitlement_expiration_date:
<div class="info-expires-at"> <div class="info-expires-at">
<span class="msg-icon fa fa-info" aria-hidden="true"></span> <span class="msg-icon fa fa-warning" aria-hidden="true"></span>
% if entitlement_expired_at: % if entitlement_expired_at:
${_('You can no longer change sessions.')} ${_('You can no longer change sessions.')}
% else: % else:
......
...@@ -25,9 +25,7 @@ ...@@ -25,9 +25,7 @@
<% if (user_entitlement && user_entitlement.expiration_date) { %> <% if (user_entitlement && user_entitlement.expiration_date) { %>
<div class="info-expires-at"> <div class="info-expires-at">
<% if (is_unfulfilled_entitlement) { %> <% if (is_unfulfilled_entitlement) { %>
<% if (user_entitlement.expired_at) { %> <% 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 { %>
<%- StringUtils.interpolate(gettext('You must select a session by {expiration_date} to access the course.'), {expiration_date: user_entitlement.expiration_date}) %> <%- StringUtils.interpolate(gettext('You must select a session by {expiration_date} to access the course.'), {expiration_date: user_entitlement.expiration_date}) %>
<% } %> <% } %>
<% } else { %> <% } else { %>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<% if (enrollable_course_runs.length > 1) { %> <% if (enrollable_course_runs.length > 1) { %>
<div class="run-select-container"> <div class="run-select-container">
<label class="select-choice" for="select-<%- course_key %>-run"> <label class="select-choice" for="select-<%- course_key %>-run">
<%- gettext('Choose a course run:') %> <%- gettext('Select a session:') %>
</label> </label>
<select id="select-<%- course_key %>-run" class="run-select field-input input-select" autocomplete="off"> <select id="select-<%- course_key %>-run" class="run-select field-input input-select" autocomplete="off">
<% _.each (enrollable_course_runs, function(courseRun) { %> <% _.each (enrollable_course_runs, function(courseRun) { %>
......
...@@ -222,16 +222,20 @@ class ProgramProgressMeter(object): ...@@ -222,16 +222,20 @@ class ProgramProgressMeter(object):
completed, in_progress, not_started = [], [], [] completed, in_progress, not_started = [], [], []
for course in program_copy['courses']: for course in program_copy['courses']:
entitlement = CourseEntitlement.objects.filter(user=self.user, active_entitlement = CourseEntitlement.get_entitlement_if_active(
course_uuid=course['uuid']).first() user=self.user,
course_uuid=course['uuid']
)
if self._is_course_complete(course): if self._is_course_complete(course):
completed.append(course) completed.append(course)
elif self._is_course_enrolled(course) or entitlement: elif self._is_course_enrolled(course) or active_entitlement:
# Show all currently enrolled courses and entitlements as in progress # Show all currently enrolled courses and active entitlements as in progress
if entitlement: if active_entitlement:
course['user_entitlement'] = entitlement.to_dict() course['user_entitlement'] = active_entitlement.to_dict()
course['enroll_url'] = reverse('entitlements_api:v1:enrollments', args=[str(entitlement.uuid)]) course['enroll_url'] = reverse(
'entitlements_api:v1:enrollments',
args=[str(active_entitlement.uuid)]
)
in_progress.append(course) in_progress.append(course)
else: else:
course_in_progress = self._is_course_in_progress(now, course) course_in_progress = self._is_course_in_progress(now, course)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment