From 65f2814d736f52ed22f266b9ef0ca6432862d17c Mon Sep 17 00:00:00 2001 From: Jason Bau <jbau@stanford.edu> Date: Tue, 20 Aug 2013 13:20:06 -0700 Subject: [PATCH] make PaidCourseRegistration mode aware --- common/djangoapps/course_modes/models.py | 15 +++++++++++++++ common/djangoapps/course_modes/tests.py | 3 +++ lms/djangoapps/shoppingcart/exceptions.py | 5 +++++ lms/djangoapps/shoppingcart/models.py | 35 +++++++++++++++++++++++++++-------- lms/djangoapps/shoppingcart/processors/exceptions.py | 3 +-- lms/envs/dev.py | 4 ++++ 6 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 lms/djangoapps/shoppingcart/exceptions.py diff --git a/common/djangoapps/course_modes/models.py b/common/djangoapps/course_modes/models.py index 561c078..3d1c6f0 100644 --- a/common/djangoapps/course_modes/models.py +++ b/common/djangoapps/course_modes/models.py @@ -51,3 +51,18 @@ class CourseMode(models.Model): if not modes: modes = [cls.DEFAULT_MODE] return modes + + @classmethod + def mode_for_course(cls, course_id, mode_slug): + """ + Returns the mode for the course corresponding to mode_slug. + + If this particular mode is not set for the course, returns None + """ + modes = cls.modes_for_course(course_id) + + matched = filter(lambda m: m.slug == mode_slug, modes) + if matched: + return matched[0] + else: + return None diff --git a/common/djangoapps/course_modes/tests.py b/common/djangoapps/course_modes/tests.py index 907797b..1fba5ca 100644 --- a/common/djangoapps/course_modes/tests.py +++ b/common/djangoapps/course_modes/tests.py @@ -60,3 +60,6 @@ class CourseModeModelTest(TestCase): modes = CourseMode.modes_for_course(self.course_id) self.assertEqual(modes, set_modes) + self.assertEqual(mode1, CourseMode.mode_for_course(self.course_id, u'honor')) + self.assertEqual(mode2, CourseMode.mode_for_course(self.course_id, u'verified')) + self.assertIsNone(CourseMode.mode_for_course(self.course_id, 'DNE')) diff --git a/lms/djangoapps/shoppingcart/exceptions.py b/lms/djangoapps/shoppingcart/exceptions.py new file mode 100644 index 0000000..fdfb9cc --- /dev/null +++ b/lms/djangoapps/shoppingcart/exceptions.py @@ -0,0 +1,5 @@ +class PaymentException(Exception): + pass + +class PurchasedCallbackException(PaymentException): + pass \ No newline at end of file diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py index 3a4039c..7c73adb 100644 --- a/lms/djangoapps/shoppingcart/models.py +++ b/lms/djangoapps/shoppingcart/models.py @@ -6,10 +6,17 @@ from django.core.exceptions import ObjectDoesNotExist from django.contrib.auth.models import User from django.utils.translation import ugettext as _ from model_utils.managers import InheritanceManager -from courseware.courses import get_course_about_section +from courseware.courses import course_image_url, get_course_about_section + +from xmodule.modulestore.django import modulestore +from xmodule.course_module import CourseDescriptor + +from course_modes.models import CourseMode from student.views import course_from_id from student.models import CourseEnrollment from statsd import statsd +from .exceptions import * + log = logging.getLogger("shoppingcart") class InvalidCartItem(Exception): @@ -157,7 +164,7 @@ class PaidCourseRegistration(OrderItem): if item.is_of_subtype(PaidCourseRegistration)] @classmethod - def add_to_order(cls, order, course_id, cost=None, currency=None): + def add_to_order(cls, order, course_id, mode_slug=None, cost=None, currency=None): """ A standardized way to create these objects, with sensible defaults filled in. Will update the cost if called on an order that already carries the course. @@ -171,10 +178,21 @@ class PaidCourseRegistration(OrderItem): # throw errors if it doesn't item, created = cls.objects.get_or_create(order=order, user=order.user, course_id=course_id) item.status = order.status + if not mode_slug: + mode_slug = CourseMode.DEFAULT_MODE.slug + ### Get this course_mode + course_mode = CourseMode.mode_for_course(course_id, mode_slug) + if not course_mode: + course_mode = CourseMode.DEFAULT_MODE + if not cost: + cost = course_mode.min_price + if not currency: + currency = course_mode.currency item.qty = 1 item.unit_cost = cost item.line_cost = cost - item.line_desc = 'Registration for Course: {0}'.format(get_course_about_section(course, "title")) + item.line_desc = 'Registration for Course: {0}. Mode: {1}'.format(get_course_about_section(course, "title"), + course_mode.name) item.currency = currency order.currency = currency order.save() @@ -188,11 +206,12 @@ class PaidCourseRegistration(OrderItem): CourseEnrollmentAllowed will the user be allowed to enroll. Otherwise requiring payment would in fact be quite silly since there's a clear back door. """ - course = course_from_id(self.course_id) # actually fetch the course to make sure it exists, use this to - # throw errors if it doesn't - # use get_or_create here to gracefully handle case where the user is already enrolled in the course, for - # whatever reason. - CourseEnrollment.objects.get_or_create(user=self.user, course_id=self.course_id) + course_loc = CourseDescriptor.id_to_location(self.course_id) + course_exists = modulestore().has_item(self.course_id, course_loc) + if not course_exists: + raise PurchasedCallbackException( + "The customer purchased Course {0}, but that course doesn't exist!".format(self.course_id)) + CourseEnrollment.enroll(user=self.user, course_id=self.course_id) log.info("Enrolled {0} in paid course {1}, paid ${2}".format(self.user.email, self.course_id, self.line_cost)) org, course_num, run = self.course_id.split("/") diff --git a/lms/djangoapps/shoppingcart/processors/exceptions.py b/lms/djangoapps/shoppingcart/processors/exceptions.py index e863688..098ed0f 100644 --- a/lms/djangoapps/shoppingcart/processors/exceptions.py +++ b/lms/djangoapps/shoppingcart/processors/exceptions.py @@ -1,5 +1,4 @@ -class PaymentException(Exception): - pass +from shoppingcart.exceptions import PaymentException class CCProcessorException(PaymentException): pass diff --git a/lms/envs/dev.py b/lms/envs/dev.py index cc78dcc..554c72d 100644 --- a/lms/envs/dev.py +++ b/lms/envs/dev.py @@ -270,6 +270,10 @@ CC_PROCESSOR['CyberSource']['PURCHASE_ENDPOINT'] = os.environ.get('CYBERSOURCE_P ########################## USER API ######################## EDX_API_KEY = None + +####################### Shoppingcart ########################### +MITX_FEATURES['ENABLE_SHOPPING_CART'] = True + ##################################################################### # Lastly, see if the developer has any local overrides. try: -- libgit2 0.26.0