Commit c5f353ec by Diana Huang

Major cleanup work on ShoppingCart models

* Make currency a property of the Order (for validation purposes)
* Remove null=True from Char fields
* Use InheritanceManager for subclassing OrderItem
* Change VerifiedCertificate to better handle some new use cases
* Cleaned out old migrations
* Tests!
parent 38ba856d
......@@ -12,9 +12,20 @@ class Migration(SchemaMigration):
db.create_table('shoppingcart_order', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
('currency', self.gf('django.db.models.fields.CharField')(default='usd', max_length=8)),
('status', self.gf('django.db.models.fields.CharField')(default='cart', max_length=32)),
('nonce', self.gf('django.db.models.fields.CharField')(max_length=128)),
('purchase_time', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
('bill_to_first', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)),
('bill_to_last', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)),
('bill_to_street1', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)),
('bill_to_street2', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)),
('bill_to_city', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)),
('bill_to_state', self.gf('django.db.models.fields.CharField')(max_length=8, blank=True)),
('bill_to_postalcode', self.gf('django.db.models.fields.CharField')(max_length=16, blank=True)),
('bill_to_country', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)),
('bill_to_ccnum', self.gf('django.db.models.fields.CharField')(max_length=8, blank=True)),
('bill_to_cardtype', self.gf('django.db.models.fields.CharField')(max_length=32, blank=True)),
('processor_reply_dump', self.gf('django.db.models.fields.TextField')(blank=True)),
))
db.send_create_signal('shoppingcart', ['Order'])
......@@ -25,9 +36,10 @@ class Migration(SchemaMigration):
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
('status', self.gf('django.db.models.fields.CharField')(default='cart', max_length=32)),
('qty', self.gf('django.db.models.fields.IntegerField')(default=1)),
('unit_cost', self.gf('django.db.models.fields.FloatField')(default=0.0)),
('line_cost', self.gf('django.db.models.fields.FloatField')(default=0.0)),
('unit_cost', self.gf('django.db.models.fields.DecimalField')(default=0.0, max_digits=30, decimal_places=2)),
('line_cost', self.gf('django.db.models.fields.DecimalField')(default=0.0, max_digits=30, decimal_places=2)),
('line_desc', self.gf('django.db.models.fields.CharField')(default='Misc. Item', max_length=1024)),
('currency', self.gf('django.db.models.fields.CharField')(default='usd', max_length=8)),
))
db.send_create_signal('shoppingcart', ['OrderItem'])
......@@ -38,6 +50,15 @@ class Migration(SchemaMigration):
))
db.send_create_signal('shoppingcart', ['PaidCourseRegistration'])
# Adding model 'CertificateItem'
db.create_table('shoppingcart_certificateitem', (
('orderitem_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['shoppingcart.OrderItem'], unique=True, primary_key=True)),
('course_id', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
('course_enrollment', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['student.CourseEnrollment'])),
('mode', self.gf('django.db.models.fields.SlugField')(max_length=50)),
))
db.send_create_signal('shoppingcart', ['CertificateItem'])
def backwards(self, orm):
# Deleting model 'Order'
......@@ -49,6 +70,9 @@ class Migration(SchemaMigration):
# Deleting model 'PaidCourseRegistration'
db.delete_table('shoppingcart_paidcourseregistration')
# Deleting model 'CertificateItem'
db.delete_table('shoppingcart_certificateitem')
models = {
'auth.group': {
......@@ -87,29 +111,57 @@ class Migration(SchemaMigration):
'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'}),
'nonce': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'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.FloatField', [], {'default': '0.0'}),
'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.FloatField', [], {'default': '0.0'}),
'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'}),
'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']"})
}
}
......
# -*- 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):
# Deleting field 'Order.nonce'
db.delete_column('shoppingcart_order', 'nonce')
# Adding field 'Order.bill_to_first'
db.add_column('shoppingcart_order', 'bill_to_first',
self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True),
keep_default=False)
# Adding field 'Order.bill_to_last'
db.add_column('shoppingcart_order', 'bill_to_last',
self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True),
keep_default=False)
# Adding field 'Order.bill_to_street1'
db.add_column('shoppingcart_order', 'bill_to_street1',
self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True),
keep_default=False)
# Adding field 'Order.bill_to_street2'
db.add_column('shoppingcart_order', 'bill_to_street2',
self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True),
keep_default=False)
# Adding field 'Order.bill_to_city'
db.add_column('shoppingcart_order', 'bill_to_city',
self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True),
keep_default=False)
# Adding field 'Order.bill_to_postalcode'
db.add_column('shoppingcart_order', 'bill_to_postalcode',
self.gf('django.db.models.fields.CharField')(max_length=16, null=True, blank=True),
keep_default=False)
# Adding field 'Order.bill_to_country'
db.add_column('shoppingcart_order', 'bill_to_country',
self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True),
keep_default=False)
# Adding field 'Order.bill_to_ccnum'
db.add_column('shoppingcart_order', 'bill_to_ccnum',
self.gf('django.db.models.fields.CharField')(max_length=8, null=True, blank=True),
keep_default=False)
# Adding field 'Order.bill_to_cardtype'
db.add_column('shoppingcart_order', 'bill_to_cardtype',
self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True),
keep_default=False)
# Adding field 'Order.processor_reply_dump'
db.add_column('shoppingcart_order', 'processor_reply_dump',
self.gf('django.db.models.fields.TextField')(null=True, blank=True),
keep_default=False)
# Adding field 'OrderItem.currency'
db.add_column('shoppingcart_orderitem', 'currency',
self.gf('django.db.models.fields.CharField')(default='usd', max_length=8),
keep_default=False)
def backwards(self, orm):
# Adding field 'Order.nonce'
db.add_column('shoppingcart_order', 'nonce',
self.gf('django.db.models.fields.CharField')(default='defaultNonce', max_length=128),
keep_default=False)
# Deleting field 'Order.bill_to_first'
db.delete_column('shoppingcart_order', 'bill_to_first')
# Deleting field 'Order.bill_to_last'
db.delete_column('shoppingcart_order', 'bill_to_last')
# Deleting field 'Order.bill_to_street1'
db.delete_column('shoppingcart_order', 'bill_to_street1')
# Deleting field 'Order.bill_to_street2'
db.delete_column('shoppingcart_order', 'bill_to_street2')
# Deleting field 'Order.bill_to_city'
db.delete_column('shoppingcart_order', 'bill_to_city')
# Deleting field 'Order.bill_to_postalcode'
db.delete_column('shoppingcart_order', 'bill_to_postalcode')
# Deleting field 'Order.bill_to_country'
db.delete_column('shoppingcart_order', 'bill_to_country')
# Deleting field 'Order.bill_to_ccnum'
db.delete_column('shoppingcart_order', 'bill_to_ccnum')
# Deleting field 'Order.bill_to_cardtype'
db.delete_column('shoppingcart_order', 'bill_to_cardtype')
# Deleting field 'Order.processor_reply_dump'
db.delete_column('shoppingcart_order', 'processor_reply_dump')
# Deleting field 'OrderItem.currency'
db.delete_column('shoppingcart_orderitem', 'currency')
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.order': {
'Meta': {'object_name': 'Order'},
'bill_to_cardtype': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'bill_to_ccnum': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'bill_to_city': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_country': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_first': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_last': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_postalcode': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}),
'bill_to_street1': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'bill_to_street2': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'processor_reply_dump': ('django.db.models.fields.TextField', [], {'null': 'True', '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.FloatField', [], {'default': '0.0'}),
'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.FloatField', [], {'default': '0.0'}),
'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'}),
'orderitem_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['shoppingcart.OrderItem']", 'unique': 'True', 'primary_key': 'True'})
}
}
complete_apps = ['shoppingcart']
\ No newline at end of file
# -*- 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 'Order.bill_to_state'
db.add_column('shoppingcart_order', 'bill_to_state',
self.gf('django.db.models.fields.CharField')(max_length=8, null=True, blank=True),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Order.bill_to_state'
db.delete_column('shoppingcart_order', 'bill_to_state')
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.order': {
'Meta': {'object_name': 'Order'},
'bill_to_cardtype': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'bill_to_ccnum': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'bill_to_city': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_country': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_first': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_last': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_postalcode': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}),
'bill_to_state': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'bill_to_street1': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'bill_to_street2': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'processor_reply_dump': ('django.db.models.fields.TextField', [], {'null': 'True', '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.FloatField', [], {'default': '0.0'}),
'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.FloatField', [], {'default': '0.0'}),
'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'}),
'orderitem_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['shoppingcart.OrderItem']", 'unique': 'True', 'primary_key': 'True'})
}
}
complete_apps = ['shoppingcart']
\ No newline at end of file
# -*- 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 model 'VerifiedCertificate'
db.create_table('shoppingcart_verifiedcertificate', (
('orderitem_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['shoppingcart.OrderItem'], unique=True, primary_key=True)),
('course_id', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
('course_enrollment', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['student.CourseEnrollment'])),
))
db.send_create_signal('shoppingcart', ['VerifiedCertificate'])
def backwards(self, orm):
# Deleting model 'VerifiedCertificate'
db.delete_table('shoppingcart_verifiedcertificate')
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.order': {
'Meta': {'object_name': 'Order'},
'bill_to_cardtype': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'bill_to_ccnum': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'bill_to_city': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_country': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_first': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_last': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'bill_to_postalcode': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}),
'bill_to_street1': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'bill_to_street2': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'processor_reply_dump': ('django.db.models.fields.TextField', [], {'null': 'True', '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.FloatField', [], {'default': '0.0'}),
'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.FloatField', [], {'default': '0.0'}),
'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'}),
'orderitem_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['shoppingcart.OrderItem']", 'unique': 'True', 'primary_key': 'True'})
},
'shoppingcart.verifiedcertificate': {
'Meta': {'object_name': 'VerifiedCertificate', '_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'}),
'orderitem_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['shoppingcart.OrderItem']", 'unique': 'True', 'primary_key': 'True'})
},
'student.courseenrollment': {
'Meta': {'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'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
}
}
complete_apps = ['shoppingcart']
\ No newline at end of file
import pytz
import logging
from datetime import datetime
from datetime import datetime
from django.db import models
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User
from courseware.courses import course_image_url, get_course_about_section
from django.utils.translation import ugettext as _
from model_utils.managers import InheritanceManager
from courseware.courses import get_course_about_section
from student.views import course_from_id
from student.models import CourseEnrollmentAllowed, CourseEnrollment
from student.models import CourseEnrollment
from statsd import statsd
log = logging.getLogger("shoppingcart")
class InvalidCartItem(Exception):
pass
ORDER_STATUSES = (
('cart', 'cart'),
('purchased', 'purchased'),
('refunded', 'refunded'), # Not used for now
)
class Order(models.Model):
"""
This is the model for an order. Before purchase, an Order and its related OrderItems are used
......@@ -23,43 +29,40 @@ class Order(models.Model):
FOR ANY USER, THERE SHOULD ONLY EVER BE ZERO OR ONE ORDER WITH STATUS='cart'.
"""
user = models.ForeignKey(User, db_index=True)
currency = models.CharField(default="usd", max_length=8) # lower case ISO currency codes
status = models.CharField(max_length=32, default='cart', choices=ORDER_STATUSES)
purchase_time = models.DateTimeField(null=True, blank=True)
# Now we store data needed to generate a reasonable receipt
# These fields only make sense after the purchase
bill_to_first = models.CharField(max_length=64, null=True, blank=True)
bill_to_last = models.CharField(max_length=64, null=True, blank=True)
bill_to_street1 = models.CharField(max_length=128, null=True, blank=True)
bill_to_street2 = models.CharField(max_length=128, null=True, blank=True)
bill_to_city = models.CharField(max_length=64, null=True, blank=True)
bill_to_state = models.CharField(max_length=8, null=True, blank=True)
bill_to_postalcode = models.CharField(max_length=16, null=True, blank=True)
bill_to_country = models.CharField(max_length=64, null=True, blank=True)
bill_to_ccnum = models.CharField(max_length=8, null=True, blank=True) # last 4 digits
bill_to_cardtype = models.CharField(max_length=32, null=True, blank=True)
bill_to_first = models.CharField(max_length=64, blank=True)
bill_to_last = models.CharField(max_length=64, blank=True)
bill_to_street1 = models.CharField(max_length=128, blank=True)
bill_to_street2 = models.CharField(max_length=128, blank=True)
bill_to_city = models.CharField(max_length=64, blank=True)
bill_to_state = models.CharField(max_length=8, blank=True)
bill_to_postalcode = models.CharField(max_length=16, blank=True)
bill_to_country = models.CharField(max_length=64, blank=True)
bill_to_ccnum = models.CharField(max_length=8, blank=True) # last 4 digits
bill_to_cardtype = models.CharField(max_length=32, blank=True)
# a JSON dump of the CC processor response, for completeness
processor_reply_dump = models.TextField(null=True, blank=True)
processor_reply_dump = models.TextField(blank=True)
@classmethod
def get_cart_for_user(cls, user):
"""
Always use this to preserve the property that at most 1 order per user has status = 'cart'
"""
order, created = cls.objects.get_or_create(user=user, status='cart')
return order
# find the newest element in the db
try:
cart_order = cls.objects.filter(user=user, status='cart').order_by('-id')[:1].get()
except ObjectDoesNotExist:
# if nothing exists in the database, create a new cart
cart_order, _created = cls.objects.get_or_create(user=user, status='cart')
return cart_order
@property
def total_cost(self):
return sum([i.line_cost for i in self.orderitem_set.filter(status=self.status)])
@property
def currency(self):
"""Assumes that all cart items are in the same currency"""
items = self.orderitem_set.all()
if not items:
return 'usd'
else:
return items[0].currency
return sum(i.line_cost for i in self.orderitem_set.filter(status=self.status))
def clear(self):
"""
......@@ -87,7 +90,10 @@ class Order(models.Model):
self.bill_to_cardtype = cardtype
self.processor_reply_dump = processor_reply_dump
self.save()
for item in self.orderitem_set.all():
# this should return all of the objects with the correct types of the
# subclasses
orderitems = OrderItem.objects.filter(order=self).select_subclasses()
for item in orderitems:
item.status = 'purchased'
item.purchased_callback()
item.save()
......@@ -101,60 +107,38 @@ class OrderItem(models.Model):
Each implementation of OrderItem should provide its own purchased_callback as
a method.
"""
objects = InheritanceManager()
order = models.ForeignKey(Order, db_index=True)
# this is denormalized, but convenient for SQL queries for reports, etc. user should always be = order.user
user = models.ForeignKey(User, db_index=True)
# this is denormalized, but convenient for SQL queries for reports, etc. status should always be = order.status
status = models.CharField(max_length=32, default='cart', choices=ORDER_STATUSES)
qty = models.IntegerField(default=1)
unit_cost = models.FloatField(default=0.0)
line_cost = models.FloatField(default=0.0) # qty * unit_cost
unit_cost = models.DecimalField(default=0.0, decimal_places=2, max_digits=30)
line_cost = models.DecimalField(default=0.0, decimal_places=2, max_digits=30) # qty * unit_cost
line_desc = models.CharField(default="Misc. Item", max_length=1024)
currency = models.CharField(default="usd", max_length=8) # lower case ISO currency codes
currency = models.CharField(default="usd", max_length=8) # lower case ISO currency codes
def add_to_order(self, *args, **kwargs):
@classmethod
def add_to_order(cls, *args, **kwargs):
"""
A suggested convenience function for subclasses.
"""
raise NotImplementedError
# this is a validation step to verify that the currency of the item we
# are adding is the same as the currency of the order we are adding it
# to
if isinstance(args[0], Order):
currency = kwargs['currency'] if 'currency' in kwargs else 'usd'
order = args[0]
if order.currency != currency and order.orderitem_set.count() > 0:
raise InvalidCartItem(_("Trying to add a different currency into the cart"))
def purchased_callback(self):
"""
This is called on each inventory item in the shopping cart when the
purchase goes through.
NOTE: We want to provide facilities for doing something like
for item in OrderItem.objects.filter(order_id=order_id):
item.purchased_callback()
Unfortunately the QuerySet used determines the class to be OrderItem, and not its most specific
subclasses. That means this parent class implementation of purchased_callback needs to act as
a dispatcher to call the callback the proper subclasses, and as such it needs to know about all
possible subclasses.
So keep ORDER_ITEM_SUBTYPES up-to-date
"""
for cls, lc_classname in ORDER_ITEM_SUBTYPES.iteritems():
try:
#Uses https://docs.djangoproject.com/en/1.4/topics/db/models/#multi-table-inheritance to test subclass
sub_instance = getattr(self,lc_classname)
sub_instance.purchased_callback()
except (ObjectDoesNotExist, AttributeError):
log.exception('Cannot call purchase_callback on non-existent subclass attribute {0} of OrderItem'\
.format(lc_classname))
pass
def is_of_subtype(self, cls):
"""
Checks if self is also a type of cls, in addition to being an OrderItem
Uses https://docs.djangoproject.com/en/1.4/topics/db/models/#multi-table-inheritance to test for subclass
"""
if cls not in ORDER_ITEM_SUBTYPES:
return False
try:
getattr(self, ORDER_ITEM_SUBTYPES[cls])
return True
except (ObjectDoesNotExist, AttributeError):
return False
raise NotImplementedError
class PaidCourseRegistration(OrderItem):
......@@ -180,6 +164,8 @@ class PaidCourseRegistration(OrderItem):
Returns the order item
"""
super(PaidCourseRegistration, cls).add_to_order(order, course_id, cost, currency=currency)
# TODO: Possibly add checking for whether student is already enrolled in course
course = course_from_id(course_id) # actually fetch the course to make sure it exists, use this to
# throw errors if it doesn't
......@@ -190,6 +176,8 @@ class PaidCourseRegistration(OrderItem):
item.line_cost = cost
item.line_desc = 'Registration for Course: {0}'.format(get_course_about_section(course, "title"))
item.currency = currency
order.currency = currency
order.save()
item.save()
return item
......@@ -214,45 +202,61 @@ class PaidCourseRegistration(OrderItem):
"run:{0}".format(run)])
class VerifiedCertificate(OrderItem):
class CertificateItem(OrderItem):
"""
This is an inventory item for purchasing verified certificates
This is an inventory item for purchasing certificates
"""
course_id = models.CharField(max_length=128, db_index=True)
course_enrollment = models.ForeignKey(CourseEnrollment)
mode = models.SlugField()
@classmethod
def add_to_order(cls, order, course_id, cost, currency='usd'):
def add_to_order(cls, order, course_id, cost, mode, currency='usd'):
"""
Add a VerifiedCertificate item to an order
Add a CertificateItem to an order
Returns the CertificateItem object after saving
`order` - an order that this item should be added to, generally the cart order
`course_id` - the course that we would like to purchase as a CertificateItem
`cost` - the amount the user will be paying for this CertificateItem
`mode` - the course mode that this certificate is going to be issued for
This item also creates a new enrollment if none exists for this user and this course.
Example Usage:
cart = Order.get_cart_for_user(user)
CertificateItem.add_to_order(cart, 'edX/Test101/2013_Fall', 30, 'verified')
"""
course_enrollment = CourseEnrollment.create_enrollment(order.user, course_id, mode="verified")
super(CertificateItem, cls).add_to_order(order, course_id, cost, currency=currency)
try:
course_enrollment = CourseEnrollment.objects.get(user=order.user, course_id=course_id)
except ObjectDoesNotExist:
course_enrollment = CourseEnrollment.create_enrollment(order.user, course_id, mode=mode)
item, _created = cls.objects.get_or_create(
order=order,
user=order.user,
course_id=course_id,
course_enrollment=course_enrollment
course_enrollment=course_enrollment,
mode=mode
)
item.status = order.status
item.qty = 1
item.unit_cost = cost
item.line_cost = cost
item.line_desc = "Verified Certificate for Course {0}".format(course_id)
item.line_desc = "{mode} certificate for course {course_id}".format(mode=item.mode,
course_id=course_id)
item.currency = currency
order.currency = currency
order.save()
item.save()
return item
def purchased_callback(self):
"""
When purchase goes through, activate the course enrollment
When purchase goes through, activate and update the course enrollment for the correct mode
"""
self.course_enrollment.mode = self.mode
self.course_enrollment.save()
self.course_enrollment.activate()
# Each entry is a dictionary of ModelName: 'lower_case_model_name'
# See https://docs.djangoproject.com/en/1.4/topics/db/models/#multi-table-inheritance for
# PLEASE KEEP THIS LIST UP_TO_DATE WITH THE SUBCLASSES OF OrderItem
ORDER_ITEM_SUBTYPES = {
PaidCourseRegistration: 'paidcourseregistration',
VerifiedCertificate: 'verifiedcertificate',
}
......@@ -4,32 +4,86 @@ Tests for the Shopping Cart
from factory import DjangoModelFactory
from django.test import TestCase
from shoppingcart.models import Order, VerifiedCertificate
from shoppingcart.models import Order, CertificateItem, InvalidCartItem
from student.tests.factories import UserFactory
class OrderFactory(DjangoModelFactory):
FACTORY_FOR = Order
class VerifiedCertificateFactory(DjangoModelFactory):
FACTORY_FOR = VerifiedCertificate
from student.models import CourseEnrollment
class OrderTest(TestCase):
def setUp(self):
self.user = UserFactory.create()
self.cart = OrderFactory.create(user=self.user, status='cart')
self.course_id = "test/course"
self.cost = 40
def test_get_cart_for_user(self):
# create a cart
cart = Order.get_cart_for_user(user=self.user)
# add something to it
CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified')
# should return the same cart
cart2 = Order.get_cart_for_user(user=self.user)
self.assertEquals(cart2.orderitem_set.count(), 1)
def test_cart_clear(self):
cart = Order.get_cart_for_user(user=self.user)
CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified')
CertificateItem.add_to_order(cart, 'test/course1', self.cost, 'verified')
self.assertEquals(cart.orderitem_set.count(), 2)
cart.clear()
self.assertEquals(cart.orderitem_set.count(), 0)
def test_add_item_to_cart(self):
pass
def test_add_item_to_cart_currency_match(self):
cart = Order.get_cart_for_user(user=self.user)
CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified', currency='eur')
# verify that a new item has been added
self.assertEquals(cart.orderitem_set.count(), 1)
# verify that the cart's currency was updated
self.assertEquals(cart.currency, 'eur')
with self.assertRaises(InvalidCartItem):
CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified', currency='usd')
# assert that this item did not get added to the cart
self.assertEquals(cart.orderitem_set.count(), 1)
def test_total_cost(self):
cart = Order.get_cart_for_user(user=self.user)
# add items to the order
cost = 30
iterations = 5
for _ in xrange(iterations):
VerifiedCertificate.add_to_order(self.cart, self.user, self.course_id, cost)
self.assertEquals(self.cart.total_cost, cost * iterations)
course_costs = [('test/course1', 30),
('test/course2', 40),
('test/course3', 10),
('test/course4', 20)]
for course, cost in course_costs:
CertificateItem.add_to_order(cart, course, cost, 'verified')
self.assertEquals(cart.orderitem_set.count(), len(course_costs))
self.assertEquals(cart.total_cost, sum(cost for _course, cost in course_costs))
def test_purchase(self):
# This test is for testing the subclassing functionality of OrderItem, but in
# order to do this, we end up testing the specific functionality of
# CertificateItem, which is not quite good unit test form. Sorry.
cart = Order.get_cart_for_user(user=self.user)
self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_id))
CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified')
# course enrollment object should be created but still inactive
self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_id))
cart.purchase()
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_id))
class CertificateItemTest(TestCase):
"""
Tests for verifying specific CertificateItem functionality
"""
def setUp(self):
self.user = UserFactory.create()
self.course_id = "test/course"
self.cost = 40
def test_existing_enrollment(self):
CourseEnrollment.enroll(self.user, self.course_id)
cart = Order.get_cart_for_user(user=self.user)
CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified')
# verify that we are still enrolled
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_id))
cart.purchase()
enrollment = CourseEnrollment.objects.get(user=self.user, course_id=self.course_id)
self.assertEquals(enrollment.mode, u'verified')
......@@ -38,7 +38,7 @@ def add_course_to_cart(request, course_id):
@login_required
def register_for_verified_cert(request, course_id):
cart = Order.get_cart_for_user(request.user)
VerifiedCertificate.add_to_order(cart, course_id, 30)
CertificateItem.add_to_order(cart, course_id, 30, 'verified')
return HttpResponse("Added")
@login_required
......
......@@ -438,10 +438,10 @@ ZENDESK_API_KEY = None
PAYMENT_SUPPORT_EMAIL = 'payment@edx.org'
##### Using cybersource by default #####
CC_PROCESSOR = {
'CyberSource' : {
'CyberSource': {
'SHARED_SECRET': '',
'MERCHANT_ID' : '',
'SERIAL_NUMBER' : '',
'MERCHANT_ID': '',
'SERIAL_NUMBER': '',
'ORDERPAGE_VERSION': '7',
'PURCHASE_ENDPOINT': '',
}
......
......@@ -53,6 +53,7 @@ South==0.7.6
sympy==0.7.1
xmltodict==0.4.1
django-ratelimit-backend==0.6
django-model-utils==1.4.0
# Used for debugging
ipython==0.13.1
......
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