Consider user entitlements and use entitlement products in bundle one-click purchase
This commit is contained in:
committed by
McKenzie Welter
parent
c25e4ba045
commit
f72cf800e1
@@ -460,57 +460,99 @@ class ProgramDataExtender(object):
|
||||
def _attach_course_run_may_certify(self, run_mode):
|
||||
run_mode['may_certify'] = self.course_overview.may_certify()
|
||||
|
||||
def _check_enrollment_for_user(self, course_run):
|
||||
applicable_seat_types = self.data['applicable_seat_types']
|
||||
def _filter_out_courses_with_entitlements(self, courses):
|
||||
"""
|
||||
Removes courses for which the current user already holds an applicable entitlement.
|
||||
|
||||
(enrollment_mode, active) = CourseEnrollment.enrollment_mode_for_user(
|
||||
self.user,
|
||||
CourseKey.from_string(course_run['key'])
|
||||
TODO:
|
||||
Add a NULL value of enrollment_course_run to filter, as courses with entitlements spent on applicable
|
||||
enrollments will already have been filtered out by _filter_out_courses_with_enrollments.
|
||||
|
||||
Arguments:
|
||||
courses (list): Containing dicts representing courses in a program
|
||||
|
||||
Returns:
|
||||
A subset of the given list of course dicts
|
||||
"""
|
||||
course_uuids = set(course['uuid'] for course in courses)
|
||||
# Filter the entitlements' modes with a case-insensitive match against applicable seat_types
|
||||
entitlements = self.user.courseentitlement_set.filter(
|
||||
mode__in=self.data['applicable_seat_types'],
|
||||
course_uuid__in=course_uuids,
|
||||
)
|
||||
# Here we check the entitlements' expired_at_datetime property rather than filter by the expired_at attribute
|
||||
# to ensure that the expiration status is as up to date as possible
|
||||
entitlements = [e for e in entitlements if not e.expired_at_datetime]
|
||||
courses_with_entitlements = set(unicode(entitlement.course_uuid) for entitlement in entitlements)
|
||||
return [course for course in courses if course['uuid'] not in courses_with_entitlements]
|
||||
|
||||
is_paid_seat = False
|
||||
if enrollment_mode is not None and active is not None and active is True:
|
||||
# Check all the applicable seat types
|
||||
# this will also check for no-id-professional as professional
|
||||
is_paid_seat = any(seat_type in enrollment_mode for seat_type in applicable_seat_types)
|
||||
def _filter_out_courses_with_enrollments(self, courses):
|
||||
"""
|
||||
Removes courses for which the current user already holds an active and applicable enrollment
|
||||
for one of that course's runs.
|
||||
|
||||
return is_paid_seat
|
||||
Arguments:
|
||||
courses (list): Containing dicts representing courses in a program
|
||||
|
||||
Returns:
|
||||
A subset of the given list of course dicts
|
||||
"""
|
||||
enrollments = self.user.courseenrollment_set.filter(
|
||||
is_active=True,
|
||||
mode__in=self.data['applicable_seat_types']
|
||||
)
|
||||
course_runs_with_enrollments = set(unicode(enrollment.course_id) for enrollment in enrollments)
|
||||
courses_without_enrollments = []
|
||||
for course in courses:
|
||||
if all(unicode(run['key']) not in course_runs_with_enrollments for run in course['course_runs']):
|
||||
courses_without_enrollments.append(course)
|
||||
|
||||
return courses_without_enrollments
|
||||
|
||||
def _collect_one_click_purchase_eligibility_data(self):
|
||||
"""
|
||||
Extend the program data with data about learner's eligibility for one click purchase,
|
||||
discount data of the program and SKUs of seats that should be added to basket.
|
||||
"""
|
||||
applicable_seat_types = self.data['applicable_seat_types']
|
||||
if 'professional' in self.data['applicable_seat_types']:
|
||||
self.data['applicable_seat_types'].append('no-id-professional')
|
||||
applicable_seat_types = set(seat for seat in self.data['applicable_seat_types'] if seat != 'credit')
|
||||
|
||||
is_learner_eligible_for_one_click_purchase = self.data['is_program_eligible_for_one_click_purchase']
|
||||
skus = []
|
||||
bundle_variant = 'full'
|
||||
|
||||
if is_learner_eligible_for_one_click_purchase:
|
||||
for course in self.data['courses']:
|
||||
add_course_sku = True
|
||||
course_runs = course.get('course_runs', [])
|
||||
published_course_runs = filter(lambda run: run['status'] == 'published', course_runs)
|
||||
courses = self.data['courses']
|
||||
if not self.user.is_anonymous():
|
||||
courses = self._filter_out_courses_with_enrollments(courses)
|
||||
courses = self._filter_out_courses_with_entitlements(courses)
|
||||
|
||||
if len(published_course_runs) == 1:
|
||||
for course_run in course_runs:
|
||||
is_paid_seat = self._check_enrollment_for_user(course_run)
|
||||
if len(courses) < len(self.data['courses']):
|
||||
bundle_variant = 'partial'
|
||||
|
||||
if is_paid_seat:
|
||||
add_course_sku = False
|
||||
break
|
||||
|
||||
if add_course_sku:
|
||||
for course in courses:
|
||||
entitlement_product = False
|
||||
for entitlement in course.get('entitlements', []):
|
||||
# We add the first entitlement product found with an applicable seat type because, at this time,
|
||||
# we are assuming that, for any given course, there is at most one paid entitlement available.
|
||||
if entitlement['mode'] in applicable_seat_types:
|
||||
skus.append(entitlement['sku'])
|
||||
entitlement_product = True
|
||||
break
|
||||
if not entitlement_product:
|
||||
course_runs = course.get('course_runs', [])
|
||||
published_course_runs = [run for run in course_runs if run['status'] == 'published']
|
||||
if len(published_course_runs) == 1:
|
||||
for seat in published_course_runs[0]['seats']:
|
||||
if seat['type'] in applicable_seat_types and seat['sku']:
|
||||
skus.append(seat['sku'])
|
||||
break
|
||||
else:
|
||||
bundle_variant = 'partial'
|
||||
else:
|
||||
# If a course in the program has more than 1 published course run
|
||||
# learner won't be eligible for a one click purchase.
|
||||
is_learner_eligible_for_one_click_purchase = False
|
||||
skus = []
|
||||
break
|
||||
# If a course in the program has more than 1 published course run
|
||||
# learner won't be eligible for a one click purchase.
|
||||
skus = []
|
||||
break
|
||||
|
||||
if skus:
|
||||
try:
|
||||
@@ -604,7 +646,7 @@ class ProgramMarketingDataExtender(ProgramDataExtender):
|
||||
def __init__(self, program_data, user):
|
||||
super(ProgramMarketingDataExtender, self).__init__(program_data, user)
|
||||
|
||||
# Aggregate list of instructors for the program
|
||||
# Aggregate list of instructors for the program keyed by name
|
||||
self.instructors = []
|
||||
|
||||
# Values for programs' price calculation.
|
||||
|
||||
Reference in New Issue
Block a user