Commit 6f70c9b9 by Jason Bau Committed by Diana Huang

Adding migration to store purchased mode in PaidCourseRegistration

parent 5fbb12cb
...@@ -33,6 +33,7 @@ class CourseMode(models.Model): ...@@ -33,6 +33,7 @@ class CourseMode(models.Model):
currency = models.CharField(default="usd", max_length=8) currency = models.CharField(default="usd", max_length=8)
DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd') DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd')
DEFAULT_MODE_SLUG = 'honor'
class Meta: class Meta:
""" meta attributes of this model """ """ meta attributes of this model """
......
...@@ -827,9 +827,6 @@ class CourseEnrollment(models.Model): ...@@ -827,9 +827,6 @@ class CourseEnrollment(models.Model):
@classmethod @classmethod
def is_enrolled(cls, user, course_id): def is_enrolled(cls, user, course_id):
""" """
Remove the user from a given course. If the relevant `CourseEnrollment`
object doesn't exist, we log an error but don't throw an exception.
Returns True if the user is enrolled in the course (the entry must exist Returns True if the user is enrolled in the course (the entry must exist
and it must have `is_active=True`). Otherwise, returns False. and it must have `is_active=True`). Otherwise, returns False.
......
...@@ -3,3 +3,6 @@ class PaymentException(Exception): ...@@ -3,3 +3,6 @@ class PaymentException(Exception):
class PurchasedCallbackException(PaymentException): class PurchasedCallbackException(PaymentException):
pass pass
class InvalidCartItem(PaymentException):
pass
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'PaidCourseRegistration.mode'
db.add_column('shoppingcart_paidcourseregistration', 'mode',
self.gf('django.db.models.fields.SlugField')(default='honor', max_length=50),
keep_default=False)
def backwards(self, orm):
# Deleting field 'PaidCourseRegistration.mode'
db.delete_column('shoppingcart_paidcourseregistration', 'mode')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'shoppingcart.certificateitem': {
'Meta': {'object_name': 'CertificateItem', '_ormbases': ['shoppingcart.OrderItem']},
'course_enrollment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['student.CourseEnrollment']"}),
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
'mode': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
'orderitem_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['shoppingcart.OrderItem']", 'unique': 'True', 'primary_key': 'True'})
},
'shoppingcart.order': {
'Meta': {'object_name': 'Order'},
'bill_to_cardtype': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'bill_to_ccnum': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}),
'bill_to_city': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'bill_to_country': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'bill_to_first': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'bill_to_last': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'bill_to_postalcode': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'bill_to_state': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}),
'bill_to_street1': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'bill_to_street2': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'currency': ('django.db.models.fields.CharField', [], {'default': "'usd'", 'max_length': '8'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'processor_reply_dump': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'purchase_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'cart'", 'max_length': '32'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'shoppingcart.orderitem': {
'Meta': {'object_name': 'OrderItem'},
'currency': ('django.db.models.fields.CharField', [], {'default': "'usd'", 'max_length': '8'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'line_cost': ('django.db.models.fields.DecimalField', [], {'default': '0.0', 'max_digits': '30', 'decimal_places': '2'}),
'line_desc': ('django.db.models.fields.CharField', [], {'default': "'Misc. Item'", 'max_length': '1024'}),
'order': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shoppingcart.Order']"}),
'qty': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'cart'", 'max_length': '32'}),
'unit_cost': ('django.db.models.fields.DecimalField', [], {'default': '0.0', 'max_digits': '30', 'decimal_places': '2'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'shoppingcart.paidcourseregistration': {
'Meta': {'object_name': 'PaidCourseRegistration', '_ormbases': ['shoppingcart.OrderItem']},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
'mode': ('django.db.models.fields.SlugField', [], {'default': "'honor'", 'max_length': '50'}),
'orderitem_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['shoppingcart.OrderItem']", 'unique': 'True', 'primary_key': 'True'})
},
'student.courseenrollment': {
'Meta': {'ordering': "('user', 'course_id')", 'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'mode': ('django.db.models.fields.CharField', [], {'default': "'honor'", 'max_length': '100'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
}
}
complete_apps = ['shoppingcart']
\ No newline at end of file
...@@ -19,9 +19,6 @@ from .exceptions import * ...@@ -19,9 +19,6 @@ from .exceptions import *
log = logging.getLogger("shoppingcart") log = logging.getLogger("shoppingcart")
class InvalidCartItem(Exception):
pass
ORDER_STATUSES = ( ORDER_STATUSES = (
('cart', 'cart'), ('cart', 'cart'),
('purchased', 'purchased'), ('purchased', 'purchased'),
...@@ -153,6 +150,7 @@ class PaidCourseRegistration(OrderItem): ...@@ -153,6 +150,7 @@ class PaidCourseRegistration(OrderItem):
This is an inventory item for paying for a course registration This is an inventory item for paying for a course registration
""" """
course_id = models.CharField(max_length=128, db_index=True) course_id = models.CharField(max_length=128, db_index=True)
mode = models.SlugField(default=CourseMode.DEFAULT_MODE_SLUG)
@classmethod @classmethod
def part_of_order(cls, order, course_id): def part_of_order(cls, order, course_id):
...@@ -164,7 +162,7 @@ class PaidCourseRegistration(OrderItem): ...@@ -164,7 +162,7 @@ class PaidCourseRegistration(OrderItem):
if item.is_of_subtype(PaidCourseRegistration)] if item.is_of_subtype(PaidCourseRegistration)]
@classmethod @classmethod
def add_to_order(cls, order, course_id, mode_slug=None, cost=None, currency=None): def add_to_order(cls, order, course_id, mode_slug=CourseMode.DEFAULT_MODE_SLUG, cost=None, currency=None):
""" """
A standardized way to create these objects, with sensible defaults filled in. 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. Will update the cost if called on an order that already carries the course.
...@@ -178,16 +176,18 @@ class PaidCourseRegistration(OrderItem): ...@@ -178,16 +176,18 @@ class PaidCourseRegistration(OrderItem):
# throw errors if it doesn't # throw errors if it doesn't
item, created = cls.objects.get_or_create(order=order, user=order.user, course_id=course_id) item, created = cls.objects.get_or_create(order=order, user=order.user, course_id=course_id)
item.status = order.status item.status = order.status
if not mode_slug:
mode_slug = CourseMode.DEFAULT_MODE.slug
### Get this course_mode ### Get this course_mode
course_mode = CourseMode.mode_for_course(course_id, mode_slug) course_mode = CourseMode.mode_for_course(course_id, mode_slug)
if not course_mode: if not course_mode:
# user could have specified a mode that's not set, in that case return the DEFAULT_MODE
course_mode = CourseMode.DEFAULT_MODE course_mode = CourseMode.DEFAULT_MODE
if not cost: if not cost:
cost = course_mode.min_price cost = course_mode.min_price
if not currency: if not currency:
currency = course_mode.currency currency = course_mode.currency
item.mode = course_mode.slug
item.qty = 1 item.qty = 1
item.unit_cost = cost item.unit_cost = cost
item.line_cost = cost item.line_cost = cost
...@@ -202,8 +202,8 @@ class PaidCourseRegistration(OrderItem): ...@@ -202,8 +202,8 @@ class PaidCourseRegistration(OrderItem):
def purchased_callback(self): def purchased_callback(self):
""" """
When purchased, this should enroll the user in the course. We are assuming that When purchased, this should enroll the user in the course. We are assuming that
course settings for enrollment date are configured such that only if the (user.email, course_id) pair is found in course settings for enrollment date are configured such that only if the (user.email, course_id) pair is found
CourseEnrollmentAllowed will the user be allowed to enroll. Otherwise requiring payment in CourseEnrollmentAllowed will the user be allowed to enroll. Otherwise requiring payment
would in fact be quite silly since there's a clear back door. would in fact be quite silly since there's a clear back door.
""" """
course_loc = CourseDescriptor.id_to_location(self.course_id) course_loc = CourseDescriptor.id_to_location(self.course_id)
...@@ -211,7 +211,7 @@ class PaidCourseRegistration(OrderItem): ...@@ -211,7 +211,7 @@ class PaidCourseRegistration(OrderItem):
if not course_exists: if not course_exists:
raise PurchasedCallbackException( raise PurchasedCallbackException(
"The customer purchased Course {0}, but that course doesn't exist!".format(self.course_id)) "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) CourseEnrollment.enroll(user=self.user, course_id=self.course_id, mode=self.mode)
log.info("Enrolled {0} in paid course {1}, paid ${2}".format(self.user.email, self.course_id, self.line_cost)) 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("/") org, course_num, run = self.course_id.split("/")
......
...@@ -24,7 +24,7 @@ def add_course_to_cart(request, course_id): ...@@ -24,7 +24,7 @@ def add_course_to_cart(request, course_id):
cart = Order.get_cart_for_user(request.user) cart = Order.get_cart_for_user(request.user)
if PaidCourseRegistration.part_of_order(cart, course_id): if PaidCourseRegistration.part_of_order(cart, course_id):
return HttpResponseNotFound(_('The course {0} is already in your cart.'.format(course_id))) return HttpResponseNotFound(_('The course {0} is already in your cart.'.format(course_id)))
if CourseEnrollment.objects.filter(user=request.user, course_id=course_id).exists(): if CourseEnrollment.is_enrolled(user=request.user, course_id=course_id):
return HttpResponseNotFound(_('You are already registered in course {0}.'.format(course_id))) return HttpResponseNotFound(_('You are already registered in course {0}.'.format(course_id)))
try: try:
PaidCourseRegistration.add_to_order(cart, course_id) PaidCourseRegistration.add_to_order(cart, course_id)
......
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