Add SKU to Course Modes
XCOM-94
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
# -*- 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 'CourseMode.sku'
|
||||
db.add_column('course_modes_coursemode', 'sku',
|
||||
self.gf('django.db.models.fields.CharField')(max_length=255, null=True),
|
||||
keep_default=False)
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'CourseMode.sku'
|
||||
db.delete_column('course_modes_coursemode', 'sku')
|
||||
|
||||
models = {
|
||||
'course_modes.coursemode': {
|
||||
'Meta': {'unique_together': "(('course_id', 'mode_slug', 'currency'),)", 'object_name': 'CourseMode'},
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'currency': ('django.db.models.fields.CharField', [], {'default': "'usd'", 'max_length': '8'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'expiration_date': ('django.db.models.fields.DateField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
|
||||
'expiration_datetime': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'min_price': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'mode_display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'mode_slug': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'sku': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'suggested_prices': ('django.db.models.fields.CommaSeparatedIntegerField', [], {'default': "''", 'max_length': '255', 'blank': 'True'})
|
||||
},
|
||||
'course_modes.coursemodesarchive': {
|
||||
'Meta': {'object_name': 'CourseModesArchive'},
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'currency': ('django.db.models.fields.CharField', [], {'default': "'usd'", 'max_length': '8'}),
|
||||
'expiration_date': ('django.db.models.fields.DateField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
|
||||
'expiration_datetime': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'min_price': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'mode_display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'mode_slug': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'suggested_prices': ('django.db.models.fields.CommaSeparatedIntegerField', [], {'default': "''", 'max_length': '255', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['course_modes']
|
||||
@@ -19,7 +19,8 @@ Mode = namedtuple('Mode',
|
||||
'suggested_prices',
|
||||
'currency',
|
||||
'expiration_datetime',
|
||||
'description'
|
||||
'description',
|
||||
'sku',
|
||||
])
|
||||
|
||||
|
||||
@@ -56,7 +57,15 @@ class CourseMode(models.Model):
|
||||
# WARNING: will not be localized
|
||||
description = models.TextField(null=True, blank=True)
|
||||
|
||||
DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd', None, None)
|
||||
#optional SKU for Oscar integration
|
||||
sku = models.CharField(
|
||||
max_length=255,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="This is the SKU(stock keeping unit) of this mode in external services."
|
||||
)
|
||||
|
||||
DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd', None, None, None)
|
||||
DEFAULT_MODE_SLUG = 'honor'
|
||||
|
||||
# Modes that allow a student to pursue a verified certificate
|
||||
@@ -381,7 +390,8 @@ class CourseMode(models.Model):
|
||||
self.suggested_prices,
|
||||
self.currency,
|
||||
self.expiration_datetime,
|
||||
self.description
|
||||
self.description,
|
||||
self.sku
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
|
||||
@@ -53,7 +53,7 @@ class CourseModeModelTest(TestCase):
|
||||
|
||||
self.create_mode('verified', 'Verified Certificate')
|
||||
modes = CourseMode.modes_for_course(self.course_key)
|
||||
mode = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None, None)
|
||||
mode = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None, None, None)
|
||||
self.assertEqual([mode], modes)
|
||||
|
||||
modes_dict = CourseMode.modes_for_course_dict(self.course_key)
|
||||
@@ -65,8 +65,8 @@ class CourseModeModelTest(TestCase):
|
||||
"""
|
||||
Finding the modes when there's multiple modes
|
||||
"""
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None)
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None, None)
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None)
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None, None, None)
|
||||
set_modes = [mode1, mode2]
|
||||
for mode in set_modes:
|
||||
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices)
|
||||
@@ -85,9 +85,9 @@ class CourseModeModelTest(TestCase):
|
||||
self.assertEqual(0, CourseMode.min_course_price_for_currency(self.course_key, 'usd'))
|
||||
|
||||
# create some modes
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd', None, None)
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd', None, None)
|
||||
mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny', None, None)
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd', None, None, None)
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd', None, None, None)
|
||||
mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny', None, None, None)
|
||||
set_modes = [mode1, mode2, mode3]
|
||||
for mode in set_modes:
|
||||
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices, mode.currency)
|
||||
@@ -102,7 +102,7 @@ class CourseModeModelTest(TestCase):
|
||||
modes = CourseMode.modes_for_course(self.course_key)
|
||||
self.assertEqual([CourseMode.DEFAULT_MODE], modes)
|
||||
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None)
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None)
|
||||
self.create_mode(mode1.slug, mode1.name, mode1.min_price, mode1.suggested_prices)
|
||||
modes = CourseMode.modes_for_course(self.course_key)
|
||||
self.assertEqual([mode1], modes)
|
||||
@@ -110,7 +110,7 @@ class CourseModeModelTest(TestCase):
|
||||
expiration_datetime = datetime.now(pytz.UTC) + timedelta(days=1)
|
||||
expired_mode.expiration_datetime = expiration_datetime
|
||||
expired_mode.save()
|
||||
expired_mode_value = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', expiration_datetime, None)
|
||||
expired_mode_value = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', expiration_datetime, None, None)
|
||||
modes = CourseMode.modes_for_course(self.course_key)
|
||||
self.assertEqual([expired_mode_value, mode1], modes)
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
|
||||
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
expected_mode = [Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None)]
|
||||
expected_mode = [Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None)]
|
||||
course_mode = CourseMode.modes_for_course(self.course.id)
|
||||
|
||||
self.assertEquals(course_mode, expected_mode)
|
||||
@@ -254,7 +254,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
|
||||
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
expected_mode = [Mode(mode_slug, mode_display_name, min_price, suggested_prices, currency, None, None)]
|
||||
expected_mode = [Mode(mode_slug, mode_display_name, min_price, suggested_prices, currency, None, None, None)]
|
||||
course_mode = CourseMode.modes_for_course(self.course.id)
|
||||
|
||||
self.assertEquals(course_mode, expected_mode)
|
||||
@@ -277,8 +277,8 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
|
||||
url = reverse('create_mode', args=[unicode(self.course.id)])
|
||||
self.client.get(url, parameters)
|
||||
|
||||
honor_mode = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None)
|
||||
verified_mode = Mode(u'verified', u'Verified Certificate', 10, '10,20', 'usd', None, None)
|
||||
honor_mode = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None)
|
||||
verified_mode = Mode(u'verified', u'Verified Certificate', 10, '10,20', 'usd', None, None, None)
|
||||
expected_modes = [honor_mode, verified_mode]
|
||||
course_modes = CourseMode.modes_for_course(self.course.id)
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ def get_enrollments(user_id):
|
||||
"suggested_prices": "",
|
||||
"currency": "usd",
|
||||
"expiration_datetime": null,
|
||||
"description": null
|
||||
"description": null,
|
||||
"sku": null
|
||||
}
|
||||
],
|
||||
"enrollment_start": 2014-10-15T20:18:00Z,
|
||||
@@ -68,7 +69,8 @@ def get_enrollments(user_id):
|
||||
"suggested_prices": "",
|
||||
"currency": "usd",
|
||||
"expiration_datetime": null,
|
||||
"description": null
|
||||
"description": null,
|
||||
"sku": null
|
||||
}
|
||||
],
|
||||
"enrollment_start": 2014-10-15T20:18:00Z,
|
||||
@@ -111,7 +113,8 @@ def get_enrollment(user_id, course_id):
|
||||
"suggested_prices": "",
|
||||
"currency": "usd",
|
||||
"expiration_datetime": null,
|
||||
"description": null
|
||||
"description": null,
|
||||
"sku": null
|
||||
}
|
||||
],
|
||||
"enrollment_start": 2014-10-15T20:18:00Z,
|
||||
@@ -157,7 +160,8 @@ def add_enrollment(user_id, course_id, mode='honor', is_active=True):
|
||||
"suggested_prices": "",
|
||||
"currency": "usd",
|
||||
"expiration_datetime": null,
|
||||
"description": null
|
||||
"description": null,
|
||||
"sku": null
|
||||
}
|
||||
],
|
||||
"enrollment_start": 2014-10-15T20:18:00Z,
|
||||
@@ -201,7 +205,8 @@ def update_enrollment(user_id, course_id, mode=None, is_active=None):
|
||||
"suggested_prices": "",
|
||||
"currency": "usd",
|
||||
"expiration_datetime": null,
|
||||
"description": null
|
||||
"description": null,
|
||||
"sku": null
|
||||
}
|
||||
],
|
||||
"enrollment_start": 2014-10-15T20:18:00Z,
|
||||
@@ -243,7 +248,8 @@ def get_course_enrollment_details(course_id):
|
||||
"suggested_prices": "",
|
||||
"currency": "usd",
|
||||
"expiration_datetime": null,
|
||||
"description": null
|
||||
"description": null,
|
||||
"sku": null
|
||||
}
|
||||
],
|
||||
"enrollment_start": 2014-10-15T20:18:00Z,
|
||||
|
||||
@@ -85,3 +85,4 @@ class ModeSerializer(serializers.Serializer):
|
||||
currency = serializers.CharField(max_length=8)
|
||||
expiration_datetime = serializers.DateTimeField()
|
||||
description = serializers.CharField()
|
||||
sku = serializers.CharField()
|
||||
|
||||
@@ -206,6 +206,7 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
|
||||
course_id=self.course.id,
|
||||
mode_slug='honor',
|
||||
mode_display_name='Honor',
|
||||
sku='123',
|
||||
)
|
||||
resp = self.client.get(
|
||||
reverse('courseenrollmentdetails', kwargs={"course_id": unicode(self.course.id)})
|
||||
@@ -214,6 +215,10 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
|
||||
|
||||
data = json.loads(resp.content)
|
||||
self.assertEqual(unicode(self.course.id), data['course_id'])
|
||||
mode = data['course_modes'][0]
|
||||
self.assertEqual(mode['slug'], 'honor')
|
||||
self.assertEqual(mode['sku'], '123')
|
||||
self.assertEqual(mode['name'], 'Honor')
|
||||
|
||||
def test_with_invalid_course_id(self):
|
||||
self._create_enrollment(course_id='entirely/fake/course', expected_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
Reference in New Issue
Block a user