diff --git a/common/djangoapps/course_modes/migrations/0008_auto__del_field_coursemodesarchive_description__add_field_coursemode_s.py b/common/djangoapps/course_modes/migrations/0008_auto__del_field_coursemodesarchive_description__add_field_coursemode_s.py new file mode 100644 index 0000000000000000000000000000000000000000..c096f6c6bc29a20d44de279528c1af8cc4d1b575 --- /dev/null +++ b/common/djangoapps/course_modes/migrations/0008_auto__del_field_coursemodesarchive_description__add_field_coursemode_s.py @@ -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'] diff --git a/common/djangoapps/course_modes/models.py b/common/djangoapps/course_modes/models.py index c4f73447c5e718a3cd2704abd519ba56838cc19e..db036457c36ba695674353c84086bcbbdfc41f5b 100644 --- a/common/djangoapps/course_modes/models.py +++ b/common/djangoapps/course_modes/models.py @@ -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): diff --git a/common/djangoapps/course_modes/tests/test_models.py b/common/djangoapps/course_modes/tests/test_models.py index 8a2aa3f065d113be4b346716c90dfb25553b4ff2..ff19119c7fa9ae5f3be8c9281ef163b2b9f7bf5e 100644 --- a/common/djangoapps/course_modes/tests/test_models.py +++ b/common/djangoapps/course_modes/tests/test_models.py @@ -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) diff --git a/common/djangoapps/course_modes/tests/test_views.py b/common/djangoapps/course_modes/tests/test_views.py index a779f1a24b7fa50cbd77ec828398388c319b8808..339588db48dab77104757aef77088c34831a617d 100644 --- a/common/djangoapps/course_modes/tests/test_views.py +++ b/common/djangoapps/course_modes/tests/test_views.py @@ -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) diff --git a/common/djangoapps/enrollment/api.py b/common/djangoapps/enrollment/api.py index 7fd5599caceb4466424ec943349b5ed249c1de6f..24d058b9cc8454c86f52c48221250736bedc3a53 100644 --- a/common/djangoapps/enrollment/api.py +++ b/common/djangoapps/enrollment/api.py @@ -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, diff --git a/common/djangoapps/enrollment/serializers.py b/common/djangoapps/enrollment/serializers.py index 4cdc6faabc41e2ab250fc122d8d00cb43d288a12..15de998d55cc9f24d7ddffb252408cad0ccfa085 100644 --- a/common/djangoapps/enrollment/serializers.py +++ b/common/djangoapps/enrollment/serializers.py @@ -85,3 +85,4 @@ class ModeSerializer(serializers.Serializer): currency = serializers.CharField(max_length=8) expiration_datetime = serializers.DateTimeField() description = serializers.CharField() + sku = serializers.CharField() diff --git a/common/djangoapps/enrollment/tests/test_views.py b/common/djangoapps/enrollment/tests/test_views.py index 4d0fd9ee22758f726b40ae9f18adf63c4a5a2c80..998ba0cec5ee1059852e881a44f5f41e0b417772 100644 --- a/common/djangoapps/enrollment/tests/test_views.py +++ b/common/djangoapps/enrollment/tests/test_views.py @@ -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)