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