diff --git a/AUTHORS b/AUTHORS
index 3510bcd3ab55a12d5c631ebd0df2ef5b55c17c9a..1db151f2407b22f6929f611d880b19e36c5ce1ad 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -158,3 +158,5 @@ Tim Babych <tim.babych@gmail.com>
 Brandon DeRosier <btd@cheesekeg.com>
 Daniel Li <swli@edx.org>
 Daniel Friedman <dfriedman@edx.org>
+Asad Iqbal <aiqbal@edx.org>
+Muhammad Shoaib <mshoaib@edx.org>
diff --git a/common/djangoapps/student/admin.py b/common/djangoapps/student/admin.py
index 209f7cf6c0a31656054042ae20ffdbdc200dbba1..e64caedd4f54d0ce82b5ff2228ddc4bf4587837b 100644
--- a/common/djangoapps/student/admin.py
+++ b/common/djangoapps/student/admin.py
@@ -3,7 +3,7 @@ django admin pages for courseware model
 '''
 
 from student.models import UserProfile, UserTestGroup, CourseEnrollmentAllowed
-from student.models import CourseEnrollment, Registration, PendingNameChange
+from student.models import CourseEnrollment, Registration, PendingNameChange, CourseAccessRole
 from ratelimitbackend import admin
 
 admin.site.register(UserProfile)
@@ -17,3 +17,5 @@ admin.site.register(CourseEnrollmentAllowed)
 admin.site.register(Registration)
 
 admin.site.register(PendingNameChange)
+
+admin.site.register(CourseAccessRole)
diff --git a/common/djangoapps/student/migrations/0037_auto__add_courseregistrationcode.py b/common/djangoapps/student/migrations/0037_auto__add_courseregistrationcode.py
new file mode 100644
index 0000000000000000000000000000000000000000..5853fcdd34bb28c3b1569982cae57cbe513d7158
--- /dev/null
+++ b/common/djangoapps/student/migrations/0037_auto__add_courseregistrationcode.py
@@ -0,0 +1,179 @@
+# -*- 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 'CourseRegistrationCode'
+        db.create_table('student_courseregistrationcode', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('code', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
+            ('course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255, db_index=True)),
+            ('transaction_group_name', self.gf('django.db.models.fields.CharField')(db_index=True, max_length=255, null=True, blank=True)),
+            ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='created_by_user', to=orm['auth.User'])),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 6, 24, 0, 0))),
+            ('redeemed_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='redeemed_by_user', null=True, to=orm['auth.User'])),
+            ('redeemed_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 6, 24, 0, 0), null=True)),
+        ))
+        db.send_create_signal('student', ['CourseRegistrationCode'])
+
+
+    def backwards(self, orm):
+        # Deleting model 'CourseRegistrationCode'
+        db.delete_table('student_courseregistrationcode')
+
+
+    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'})
+        },
+        'student.anonymoususerid': {
+            'Meta': {'object_name': 'AnonymousUserId'},
+            'anonymous_user_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.courseaccessrole': {
+            'Meta': {'unique_together': "(('user', 'org', 'course_id', 'role'),)", 'object_name': 'CourseAccessRole'},
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'org': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'blank': 'True'}),
+            'role': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.courseenrollment': {
+            'Meta': {'ordering': "('user', 'course_id')", 'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'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']"})
+        },
+        'student.courseenrollmentallowed': {
+            'Meta': {'unique_together': "(('email', 'course_id'),)", 'object_name': 'CourseEnrollmentAllowed'},
+            'auto_enroll': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
+            'email': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'student.courseregistrationcode': {
+            'Meta': {'object_name': 'CourseRegistrationCode'},
+            'code': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 6, 24, 0, 0)'}),
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_by_user'", 'to': "orm['auth.User']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'redeemed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 6, 24, 0, 0)', 'null': 'True'}),
+            'redeemed_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'redeemed_by_user'", 'null': 'True', 'to': "orm['auth.User']"}),
+            'transaction_group_name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        'student.loginfailures': {
+            'Meta': {'object_name': 'LoginFailures'},
+            'failure_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lockout_until': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.passwordhistory': {
+            'Meta': {'object_name': 'PasswordHistory'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'time_set': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.pendingemailchange': {
+            'Meta': {'object_name': 'PendingEmailChange'},
+            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_email': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.pendingnamechange': {
+            'Meta': {'object_name': 'PendingNameChange'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'rationale': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.registration': {
+            'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
+            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.userprofile': {
+            'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
+            'allow_certificate': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'city': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}),
+            'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
+            'gender': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
+            'goals': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'level_of_education': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
+            'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'mailing_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'meta': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"}),
+            'year_of_birth': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
+        },
+        'student.userstanding': {
+            'Meta': {'object_name': 'UserStanding'},
+            'account_status': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}),
+            'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'standing_last_changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'standing'", 'unique': 'True', 'to': "orm['auth.User']"})
+        },
+        'student.usertestgroup': {
+            'Meta': {'object_name': 'UserTestGroup'},
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
+        }
+    }
+
+    complete_apps = ['student']
\ No newline at end of file
diff --git a/common/djangoapps/student/migrations/0038_auto__add_usersignupsource.py b/common/djangoapps/student/migrations/0038_auto__add_usersignupsource.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd6c7a883c0bb5669cf003e98edec39024baa920
--- /dev/null
+++ b/common/djangoapps/student/migrations/0038_auto__add_usersignupsource.py
@@ -0,0 +1,180 @@
+# -*- 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 'UserSignupSource'
+        db.create_table('student_usersignupsource', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('site', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)),
+        ))
+        db.send_create_signal('student', ['UserSignupSource'])
+
+
+    def backwards(self, orm):
+        # Deleting model 'UserSignupSource'
+        db.delete_table('student_usersignupsource')
+
+
+    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'})
+        },
+        'student.anonymoususerid': {
+            'Meta': {'object_name': 'AnonymousUserId'},
+            'anonymous_user_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.courseaccessrole': {
+            'Meta': {'unique_together': "(('user', 'org', 'course_id', 'role'),)", 'object_name': 'CourseAccessRole'},
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'org': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'blank': 'True'}),
+            'role': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.courseenrollment': {
+            'Meta': {'ordering': "('user', 'course_id')", 'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'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']"})
+        },
+        'student.courseenrollmentallowed': {
+            'Meta': {'unique_together': "(('email', 'course_id'),)", 'object_name': 'CourseEnrollmentAllowed'},
+            'auto_enroll': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
+            'email': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'student.courseregistrationcode': {
+            'Meta': {'object_name': 'CourseRegistrationCode'},
+            'code': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 6, 25, 0, 0)'}),
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_by_user'", 'to': "orm['auth.User']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'redeemed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 6, 25, 0, 0)', 'null': 'True'}),
+            'redeemed_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'redeemed_by_user'", 'null': 'True', 'to': "orm['auth.User']"}),
+            'transaction_group_name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        'student.loginfailures': {
+            'Meta': {'object_name': 'LoginFailures'},
+            'failure_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lockout_until': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.passwordhistory': {
+            'Meta': {'object_name': 'PasswordHistory'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'time_set': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.pendingemailchange': {
+            'Meta': {'object_name': 'PendingEmailChange'},
+            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_email': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.pendingnamechange': {
+            'Meta': {'object_name': 'PendingNameChange'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'rationale': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.registration': {
+            'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
+            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.userprofile': {
+            'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
+            'allow_certificate': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'city': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}),
+            'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
+            'gender': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
+            'goals': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'level_of_education': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
+            'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'mailing_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'meta': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"}),
+            'year_of_birth': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
+        },
+        'student.usersignupsource': {
+            'Meta': {'object_name': 'UserSignupSource'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'site': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'user_id': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.userstanding': {
+            'Meta': {'object_name': 'UserStanding'},
+            'account_status': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}),
+            'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'standing_last_changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'standing'", 'unique': 'True', 'to': "orm['auth.User']"})
+        },
+        'student.usertestgroup': {
+            'Meta': {'object_name': 'UserTestGroup'},
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
+        }
+    }
+
+    complete_apps = ['student']
\ No newline at end of file
diff --git a/common/djangoapps/student/migrations/0039_auto__del_courseregistrationcode.py b/common/djangoapps/student/migrations/0039_auto__del_courseregistrationcode.py
new file mode 100644
index 0000000000000000000000000000000000000000..4960e2cbc4d9a1c0a74cb37734fb9ca9d16857ff
--- /dev/null
+++ b/common/djangoapps/student/migrations/0039_auto__del_courseregistrationcode.py
@@ -0,0 +1,174 @@
+# -*- 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 model 'CourseRegistrationCode'
+        db.delete_table('student_courseregistrationcode')
+
+
+    def backwards(self, orm):
+        # Adding model 'CourseRegistrationCode'
+        db.create_table('student_courseregistrationcode', (
+            ('code', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
+            ('transaction_group_name', self.gf('django.db.models.fields.CharField')(blank=True, max_length=255, null=True, db_index=True)),
+            ('redeemed_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='redeemed_by_user', null=True, to=orm['auth.User'])),
+            ('course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255, db_index=True)),
+            ('redeemed_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 6, 25, 0, 0), null=True)),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 6, 25, 0, 0))),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='created_by_user', to=orm['auth.User'])),
+        ))
+        db.send_create_signal('student', ['CourseRegistrationCode'])
+
+
+    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'})
+        },
+        'student.anonymoususerid': {
+            'Meta': {'object_name': 'AnonymousUserId'},
+            'anonymous_user_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.courseaccessrole': {
+            'Meta': {'unique_together': "(('user', 'org', 'course_id', 'role'),)", 'object_name': 'CourseAccessRole'},
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'org': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'blank': 'True'}),
+            'role': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.courseenrollment': {
+            'Meta': {'ordering': "('user', 'course_id')", 'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'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']"})
+        },
+        'student.courseenrollmentallowed': {
+            'Meta': {'unique_together': "(('email', 'course_id'),)", 'object_name': 'CourseEnrollmentAllowed'},
+            'auto_enroll': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
+            'email': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'student.loginfailures': {
+            'Meta': {'object_name': 'LoginFailures'},
+            'failure_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lockout_until': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.passwordhistory': {
+            'Meta': {'object_name': 'PasswordHistory'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'time_set': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.pendingemailchange': {
+            'Meta': {'object_name': 'PendingEmailChange'},
+            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_email': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.pendingnamechange': {
+            'Meta': {'object_name': 'PendingNameChange'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'rationale': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.registration': {
+            'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
+            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'student.userprofile': {
+            'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
+            'allow_certificate': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'city': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}),
+            'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
+            'gender': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
+            'goals': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'level_of_education': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
+            'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'mailing_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'meta': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"}),
+            'year_of_birth': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
+        },
+        'student.usersignupsource': {
+            'Meta': {'object_name': 'UserSignupSource'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'site': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'user_id': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'student.userstanding': {
+            'Meta': {'object_name': 'UserStanding'},
+            'account_status': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}),
+            'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'standing_last_changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'standing'", 'unique': 'True', 'to': "orm['auth.User']"})
+        },
+        'student.usertestgroup': {
+            'Meta': {'object_name': 'UserTestGroup'},
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
+        }
+    }
+
+    complete_apps = ['student']
\ No newline at end of file
diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py
index b487088b8c7a9ebd08f67d0bac2c45b5e30bfdf9..40d4ac0d6c41ef2586095cdbea337277e520ad8e 100644
--- a/common/djangoapps/student/models.py
+++ b/common/djangoapps/student/models.py
@@ -271,6 +271,15 @@ class UserProfile(models.Model):
         self.save()
 
 
+class UserSignupSource(models.Model):
+    """
+    This table contains information about users registering
+    via Micro-Sites
+    """
+    user_id = models.ForeignKey(User, db_index=True)
+    site = models.CharField(max_length=255, db_index=True)
+
+
 def unique_id_for_user(user, save=True):
     """
     Return a unique id for a user, suitable for inserting into
@@ -1035,6 +1044,9 @@ class CourseAccessRole(models.Model):
         """
         return self._key < other._key
 
+    def __unicode__(self):
+        return "[CourseAccessRole] user: {}   role: {}   org: {}   course: {}".format(self.user.username, self.role, self.org, self.course_id)
+
 
 #### Helper methods for use from python manage.py shell and other classes.
 
diff --git a/common/djangoapps/student/roles.py b/common/djangoapps/student/roles.py
index 640b7cd7033b8a69cb524e93406c7d172175196b..6061ce1ea2deac7a9fc3d84e69072255b0ee750e 100644
--- a/common/djangoapps/student/roles.py
+++ b/common/djangoapps/student/roles.py
@@ -201,6 +201,13 @@ class CourseInstructorRole(CourseRole):
         super(CourseInstructorRole, self).__init__(self.ROLE, *args, **kwargs)
 
 
+class CourseFinanceAdminRole(CourseRole):
+    """A course Instructor"""
+    ROLE = 'finance_admin'
+
+    def __init__(self, *args, **kwargs):
+        super(CourseFinanceAdminRole, self).__init__(self.ROLE, *args, **kwargs)
+
 class CourseBetaTesterRole(CourseRole):
     """A course Beta Tester"""
     ROLE = 'beta_testers'
diff --git a/common/djangoapps/student/tests/test_microsite.py b/common/djangoapps/student/tests/test_microsite.py
new file mode 100644
index 0000000000000000000000000000000000000000..b447ad3a13c10e2b8c2d08eb2ea18f2141b07bb1
--- /dev/null
+++ b/common/djangoapps/student/tests/test_microsite.py
@@ -0,0 +1,51 @@
+"""
+Test for User Creation from Micro-Sites
+"""
+from django.test import TestCase
+from student.models import UserSignupSource
+import mock
+from django.core.urlresolvers import reverse
+
+
+def fake_site_name(name, default=None):  # pylint: disable=W0613
+    """
+    create a fake microsite site name
+    """
+    if name == 'SITE_NAME':
+        return 'openedx.localhost'
+    else:
+        return None
+
+
+class TestMicrosite(TestCase):
+    """Test for Account Creation from a white labeled Micro-Sites"""
+    def setUp(self):
+        self.username = "test_user"
+        self.url = reverse("create_account")
+        self.params = {
+            "username": self.username,
+            "email": "test@example.org",
+            "password": "testpass",
+            "name": "Test User",
+            "honor_code": "true",
+            "terms_of_service": "true",
+        }
+
+    @mock.patch("microsite_configuration.microsite.get_value", fake_site_name)
+    def test_user_signup_source(self):
+        """
+        test to create a user form the microsite and see that it record has been
+        saved in the UserSignupSource Table
+        """
+        response = self.client.post(self.url, self.params)
+        self.assertEqual(response.status_code, 200)
+        self.assertGreater(len(UserSignupSource.objects.filter(site='openedx.localhost')), 0)
+
+    def test_user_signup_from_non_micro_site(self):
+        """
+        test to create a user form the non-microsite. The record should not be saved
+        in the UserSignupSource Table
+        """
+        response = self.client.post(self.url, self.params)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(UserSignupSource.objects.filter(site='openedx.localhost')), 0)
diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py
index cd69ebc046da4404ed1634559acb0394c5e3e9a2..0f408ab0dd84bba472b43fea1014b90e0a18253e 100644
--- a/common/djangoapps/student/views.py
+++ b/common/djangoapps/student/views.py
@@ -30,6 +30,9 @@ from django.utils.translation import ugettext as _, get_language
 from django.views.decorators.cache import never_cache
 from django.views.decorators.http import require_POST, require_GET
 
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+
 from django.template.response import TemplateResponse
 
 from ratelimitbackend.exceptions import RateLimitException
@@ -42,7 +45,7 @@ from student.models import (
     Registration, UserProfile, PendingNameChange,
     PendingEmailChange, CourseEnrollment, unique_id_for_user,
     CourseEnrollmentAllowed, UserStanding, LoginFailures,
-    create_comments_service_user, PasswordHistory
+    create_comments_service_user, PasswordHistory, UserSignupSource
 )
 from student.forms import PasswordResetFormNoActive
 
@@ -1021,6 +1024,21 @@ class AccountValidationError(Exception):
         super(AccountValidationError, self).__init__(message)
         self.field = field
 
+
+@receiver(post_save, sender=User)
+def user_signup_handler(sender, **kwargs):  # pylint: disable=W0613
+    """
+    handler that saves the user Signup Source
+    when the user is created
+    """
+    if 'created' in kwargs and kwargs['created']:
+        site = microsite.get_value('SITE_NAME')
+        if site:
+            user_signup_source = UserSignupSource(user_id=kwargs['instance'], site=site)
+            user_signup_source.save()
+            log.info(u'user {} originated from a white labeled "Microsite"'.format(kwargs['instance'].id))
+
+
 def _do_create_account(post_vars):
     """
     Given cleaned post variables, create the User and UserProfile objects, as well as the
diff --git a/lms/djangoapps/instructor/tests/test_ecommerce.py b/lms/djangoapps/instructor/tests/test_ecommerce.py
new file mode 100644
index 0000000000000000000000000000000000000000..8cb4b1435a45a79c9c9990118dad65bbd0504885
--- /dev/null
+++ b/lms/djangoapps/instructor/tests/test_ecommerce.py
@@ -0,0 +1,193 @@
+"""
+Unit tests for Ecommerce feature flag in new instructor dashboard.
+"""
+
+from django.test.utils import override_settings
+from django.core.urlresolvers import reverse
+
+from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
+from student.tests.factories import AdminFactory
+from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
+from xmodule.modulestore.tests.factories import CourseFactory
+
+from course_modes.models import CourseMode
+from shoppingcart.models import Coupon, PaidCourseRegistration
+from mock import patch
+from student.roles import CourseFinanceAdminRole
+
+
+# pylint: disable=E1101
+@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
+class TestECommerceDashboardViews(ModuleStoreTestCase):
+    """
+    Check for email view on the new instructor dashboard
+    for Mongo-backed courses
+    """
+    def setUp(self):
+        self.course = CourseFactory.create()
+
+        # Create instructor account
+        self.instructor = AdminFactory.create()
+        self.client.login(username=self.instructor.username, password="test")
+        mode = CourseMode(
+            course_id=self.course.id.to_deprecated_string(), mode_slug='honor',
+            mode_display_name='honor', min_price=10, currency='usd'
+        )
+        mode.save()
+        # URL for instructor dash
+        self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
+        self.e_commerce_link = '<a href="" data-section="e-commerce">E-Commerce</a>'
+        CourseFinanceAdminRole(self.course.id).add_users(self.instructor)
+
+    def tearDown(self):
+        """
+        Undo all patches.
+        """
+        patch.stopall()
+
+    def test_pass_e_commerce_tab_in_instructor_dashboard(self):
+        """
+        Test Pass E-commerce Tab is in the Instructor Dashboard
+        """
+        response = self.client.get(self.url)
+        self.assertTrue(self.e_commerce_link in response.content)
+
+    def test_user_has_finance_admin_rights_in_e_commerce_tab(self):
+        response = self.client.get(self.url)
+        self.assertTrue(self.e_commerce_link in response.content)
+
+        # Total amount html should render in e-commerce page, total amount will be 0
+        total_amount = PaidCourseRegistration.get_total_amount_of_purchased_item(self.course.id)
+        self.assertTrue('<span>Total Amount: <span>$' + str(total_amount) + '</span></span>' in response.content)
+
+        # removing the course finance_admin role of login user
+        CourseFinanceAdminRole(self.course.id).remove_users(self.instructor)
+
+        # total amount should not be visible in e-commerce page if the user is not finance admin
+        url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
+        response = self.client.post(url)
+        total_amount = PaidCourseRegistration.get_total_amount_of_purchased_item(self.course.id)
+        self.assertFalse('<span>Total Amount: <span>$' + str(total_amount) + '</span></span>' in response.content)
+
+    def test_add_coupon(self):
+        """
+        Test Add Coupon Scenarios. Handle all the HttpResponses return by add_coupon view
+        """
+        # URL for add_coupon
+        add_coupon_url = reverse('add_coupon', kwargs={'course_id': self.course.id.to_deprecated_string()})
+        data = {
+            'code': 'A2314', 'course_id': self.course.id.to_deprecated_string(),
+            'description': 'ADSADASDSAD', 'created_by': self.instructor, 'discount': 5
+        }
+        response = self.client.post(add_coupon_url, data)
+        self.assertTrue("coupon with the coupon code ({code}) added successfully".format(code=data['code']) in response.content)
+
+        data = {
+            'code': 'A2314', 'course_id': self.course.id.to_deprecated_string(),
+            'description': 'asdsasda', 'created_by': self.instructor, 'discount': 111
+        }
+        response = self.client.post(add_coupon_url, data)
+        self.assertTrue("coupon with the coupon code ({code}) already exist".format(code='A2314') in response.content)
+
+        response = self.client.post(self.url)
+        self.assertTrue('<td>ADSADASDSAD</td>' in response.content)
+        self.assertTrue('<td>A2314</td>' in response.content)
+        self.assertFalse('<td>111</td>' in response.content)
+
+    def test_delete_coupon(self):
+        """
+        Test Delete Coupon Scenarios. Handle all the HttpResponses return by remove_coupon view
+        """
+        coupon = Coupon(
+            code='AS452', description='asdsadsa', course_id=self.course.id.to_deprecated_string(),
+            percentage_discount=10, created_by=self.instructor
+        )
+
+        coupon.save()
+
+        response = self.client.post(self.url)
+        self.assertTrue('<td>AS452</td>' in response.content)
+
+        # URL for remove_coupon
+        delete_coupon_url = reverse('remove_coupon', kwargs={'course_id': self.course.id.to_deprecated_string()})
+        response = self.client.post(delete_coupon_url, {'id': coupon.id})
+        self.assertTrue('coupon with the coupon id ({coupon_id}) updated successfully'.format(coupon_id=coupon.id) in response.content)
+
+        coupon.is_active = False
+        coupon.save()
+
+        response = self.client.post(delete_coupon_url, {'id': coupon.id})
+        self.assertTrue('coupon with the coupon id ({coupon_id}) is already inactive'.format(coupon_id=coupon.id) in response.content)
+
+        response = self.client.post(delete_coupon_url, {'id': 24454})
+        self.assertTrue('coupon with the coupon id ({coupon_id}) DoesNotExist'.format(coupon_id=24454) in response.content)
+
+        response = self.client.post(delete_coupon_url, {'id': ''})
+        self.assertTrue('coupon id is None' in response.content)
+
+    def test_get_coupon_info(self):
+        """
+        Test Edit Coupon Info Scenarios. Handle all the HttpResponses return by edit_coupon_info view
+        """
+        coupon = Coupon(
+            code='AS452', description='asdsadsa', course_id=self.course.id.to_deprecated_string(),
+            percentage_discount=10, created_by=self.instructor
+        )
+        coupon.save()
+        # URL for edit_coupon_info
+        edit_url = reverse('get_coupon_info', kwargs={'course_id': self.course.id.to_deprecated_string()})
+        response = self.client.post(edit_url, {'id': coupon.id})
+        self.assertTrue('coupon with the coupon id ({coupon_id}) updated successfully'.format(coupon_id=coupon.id) in response.content)
+
+        response = self.client.post(edit_url, {'id': 444444})
+        self.assertTrue('coupon with the coupon id ({coupon_id}) DoesNotExist'.format(coupon_id=444444) in response.content)
+
+        response = self.client.post(edit_url, {'id': ''})
+        self.assertTrue('coupon id not found"' in response.content)
+
+        coupon.is_active = False
+        coupon.save()
+
+        response = self.client.post(edit_url, {'id': coupon.id})
+        self.assertTrue("coupon with the coupon id ({coupon_id}) is already inactive".format(coupon_id=coupon.id) in response.content)
+
+    def test_update_coupon(self):
+        """
+        Test Update Coupon Info Scenarios. Handle all the HttpResponses return by update_coupon view
+        """
+        coupon = Coupon(
+            code='AS452', description='asdsadsa', course_id=self.course.id.to_deprecated_string(),
+            percentage_discount=10, created_by=self.instructor
+        )
+        coupon.save()
+        response = self.client.post(self.url)
+        self.assertTrue('<td>AS452</td>' in response.content)
+        data = {
+            'coupon_id': coupon.id, 'code': 'update_code', 'discount': '12',
+            'course_id': coupon.course_id.to_deprecated_string()
+        }
+        # URL for update_coupon
+        update_coupon_url = reverse('update_coupon', kwargs={'course_id': self.course.id.to_deprecated_string()})
+        response = self.client.post(update_coupon_url, data=data)
+        self.assertTrue('coupon with the coupon id ({coupon_id}) updated Successfully'.format(coupon_id=coupon.id)in response.content)
+
+        response = self.client.post(self.url)
+        self.assertTrue('<td>update_code</td>' in response.content)
+        self.assertTrue('<td>12</td>' in response.content)
+
+        data['coupon_id'] = 1000  # Coupon Not Exist with this ID
+        response = self.client.post(update_coupon_url, data=data)
+        self.assertTrue('coupon with the coupon id ({coupon_id}) DoesNotExist'.format(coupon_id=1000) in response.content)
+
+        data['coupon_id'] = ''  # Coupon id is not provided
+        response = self.client.post(update_coupon_url, data=data)
+        self.assertTrue('coupon id not found' in response.content)
+
+        coupon1 = Coupon(
+            code='11111', description='coupon', course_id=self.course.id.to_deprecated_string(),
+            percentage_discount=20, created_by=self.instructor
+        )
+        coupon1.save()
+        data = {'coupon_id': coupon.id, 'code': '11111', 'discount': '12'}
+        response = self.client.post(update_coupon_url, data=data)
+        self.assertTrue('coupon with the coupon id ({coupon_id}) already exist'.format(coupon_id=coupon.id) in response.content)
diff --git a/lms/djangoapps/instructor/views/coupons.py b/lms/djangoapps/instructor/views/coupons.py
new file mode 100644
index 0000000000000000000000000000000000000000..7251e470c5b5f7bbd1ae425d1fe3dd70ab13d994
--- /dev/null
+++ b/lms/djangoapps/instructor/views/coupons.py
@@ -0,0 +1,135 @@
+"""
+E-commerce Tab Instructor Dashboard Coupons Operations views
+"""
+from django.contrib.auth.decorators import login_required
+from django.core.exceptions import ObjectDoesNotExist
+from django.db.models import Q
+from django.views.decorators.http import require_POST
+from django.utils.translation import ugettext as _
+from util.json_request import JsonResponse
+from django.http import HttpResponse, HttpResponseNotFound
+from shoppingcart.models import Coupon
+
+import logging
+
+log = logging.getLogger(__name__)
+
+
+@require_POST
+@login_required
+def remove_coupon(request, course_id):  # pylint: disable=W0613
+    """
+    remove the coupon against the coupon id
+    set the coupon is_active flag to false
+    """
+    coupon_id = request.POST.get('id', None)
+    if not coupon_id:
+        return JsonResponse({
+            'message': _('coupon id is None')
+        }, status=400)  # status code 400: Bad Request
+
+    try:
+        coupon = Coupon.objects.get(id=coupon_id)
+    except ObjectDoesNotExist:
+        return JsonResponse({
+            'message': _('coupon with the coupon id ({coupon_id}) DoesNotExist').format(coupon_id=coupon_id)
+        }, status=400)  # status code 400: Bad Request
+    if not coupon.is_active:
+        return JsonResponse({
+            'message': _('coupon with the coupon id ({coupon_id}) is already inactive').format(coupon_id=coupon_id)
+        }, status=400)  # status code 400: Bad Request
+    coupon.is_active = False
+    coupon.save()
+    return JsonResponse({
+        'message': _('coupon with the coupon id ({coupon_id}) updated successfully').format(coupon_id=coupon_id)
+    })  # status code 200: OK by default
+
+
+@require_POST
+@login_required
+def add_coupon(request, course_id):  # pylint: disable=W0613
+    """
+    add coupon in the Coupons Table
+    """
+    code = request.POST.get('code')
+
+    # check if the code is already in the Coupons Table and active
+    coupon = Coupon.objects.filter(is_active=True, code=code)
+
+    if coupon:
+        return HttpResponseNotFound(_("coupon with the coupon code ({code}) already exist").format(code=code))
+
+    description = request.POST.get('description')
+    course_id = request.POST.get('course_id')
+    discount = request.POST.get('discount')
+    coupon = Coupon(
+        code=code, description=description, course_id=course_id,
+        percentage_discount=discount, created_by_id=request.user.id
+    )
+    coupon.save()
+    return HttpResponse(_("coupon with the coupon code ({code}) added successfully").format(code=code))
+
+
+@require_POST
+@login_required
+def update_coupon(request, course_id):  # pylint: disable=W0613
+    """
+    update the coupon object in the database
+    """
+    coupon_id = request.POST.get('coupon_id', None)
+    if not coupon_id:
+        return HttpResponseNotFound(_("coupon id not found"))
+
+    try:
+        coupon = Coupon.objects.get(pk=coupon_id)
+    except ObjectDoesNotExist:
+        return HttpResponseNotFound(_("coupon with the coupon id ({coupon_id}) DoesNotExist").format(coupon_id=coupon_id))
+
+    code = request.POST.get('code')
+    filtered_coupons = Coupon.objects.filter(~Q(id=coupon_id), code=code, is_active=True)
+
+    if filtered_coupons:
+        return HttpResponseNotFound(_("coupon with the coupon id ({coupon_id}) already exists").format(coupon_id=coupon_id))
+
+    description = request.POST.get('description')
+    course_id = request.POST.get('course_id')
+    discount = request.POST.get('discount')
+    coupon.code = code
+    coupon.description = description
+    coupon.course_id = course_id
+    coupon.percentage_discount = discount
+    coupon.save()
+    return HttpResponse(_("coupon with the coupon id ({coupon_id}) updated Successfully").format(coupon_id=coupon_id))
+
+
+@require_POST
+@login_required
+def get_coupon_info(request, course_id):  # pylint: disable=W0613
+    """
+    get the coupon information to display in the pop up form
+    """
+    coupon_id = request.POST.get('id', None)
+    if not coupon_id:
+        return JsonResponse({
+            'message': _("coupon id not found")
+        }, status=400)  # status code 400: Bad Request
+
+    try:
+        coupon = Coupon.objects.get(id=coupon_id)
+    except ObjectDoesNotExist:
+        return JsonResponse({
+            'message': _("coupon with the coupon id ({coupon_id}) DoesNotExist").format(coupon_id=coupon_id)
+        }, status=400)  # status code 400: Bad Request
+
+    if not coupon.is_active:
+        return JsonResponse({
+            'message': _("coupon with the coupon id ({coupon_id}) is already inactive").format(coupon_id=coupon_id)
+        }, status=400)  # status code 400: Bad Request
+
+    return JsonResponse({
+        'coupon_code': coupon.code,
+        'coupon_description': coupon.description,
+        'coupon_course_id': coupon.course_id.to_deprecated_string(),
+        'coupon_discount': coupon.percentage_discount,
+        'message': _('coupon with the coupon id ({coupon_id}) updated successfully').format(coupon_id=coupon_id)
+    })  # status code 200: OK by default
diff --git a/lms/djangoapps/instructor/views/instructor_dashboard.py b/lms/djangoapps/instructor/views/instructor_dashboard.py
index abebd0fb116437ace335d81d74f2cac19b539504..f2e7fba5e1cc9723ac1be2ed84a2b61dcdfafe31 100644
--- a/lms/djangoapps/instructor/views/instructor_dashboard.py
+++ b/lms/djangoapps/instructor/views/instructor_dashboard.py
@@ -26,6 +26,10 @@ from courseware.courses import get_course_by_id, get_cms_course_link, get_course
 from django_comment_client.utils import has_forum_access
 from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
 from student.models import CourseEnrollment
+from shoppingcart.models import Coupon, PaidCourseRegistration
+from course_modes.models import CourseMode
+from student.roles import CourseFinanceAdminRole
+
 from bulk_email.models import CourseAuthorization
 from class_dashboard.dashboard_data import get_section_display_name, get_array_section_has_problem
 
@@ -49,6 +53,7 @@ def instructor_dashboard_2(request, course_id):
     access = {
         'admin': request.user.is_staff,
         'instructor': has_access(request.user, 'instructor', course),
+        'finance_admin': CourseFinanceAdminRole(course_key).has_user(request.user),
         'staff': has_access(request.user, 'staff', course),
         'forum_admin': has_forum_access(
             request.user, course_key, FORUM_ROLE_ADMINISTRATOR
@@ -66,6 +71,12 @@ def instructor_dashboard_2(request, course_id):
         _section_analytics(course_key, access),
     ]
 
+    #check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course
+    course_honor_mode = CourseMode.mode_for_course(course_key, 'honor')
+    course_mode_has_price = False
+    if course_honor_mode and course_honor_mode.min_price > 0:
+        course_mode_has_price = True
+
     if (settings.FEATURES.get('INDIVIDUAL_DUE_DATES') and access['instructor']):
         sections.insert(3, _section_extensions(course))
 
@@ -77,6 +88,11 @@ def instructor_dashboard_2(request, course_id):
     if settings.FEATURES['CLASS_DASHBOARD'] and access['staff']:
         sections.append(_section_metrics(course_key, access))
 
+     # Gate access to Ecommerce tab
+    if course_mode_has_price:
+        sections.append(_section_e_commerce(course_key, access))
+
+
     studio_url = None
     if is_studio_course:
         studio_url = get_cms_course_link(course)
@@ -111,6 +127,29 @@ section_display_name will be used to generate link titles in the nav bar.
 """  # pylint: disable=W0105
 
 
+def _section_e_commerce(course_key, access):
+    """ Provide data for the corresponding dashboard section """
+    coupons = Coupon.objects.filter(course_id=course_key).order_by('-is_active')
+    total_amount = None
+    if access['finance_admin']:
+        total_amount = PaidCourseRegistration.get_total_amount_of_purchased_item(course_key)
+
+    section_data = {
+        'section_key': 'e-commerce',
+        'section_display_name': _('E-Commerce'),
+        'access': access,
+        'course_id': course_key.to_deprecated_string(),
+        'ajax_remove_coupon_url': reverse('remove_coupon', kwargs={'course_id': course_key.to_deprecated_string()}),
+        'ajax_get_coupon_info': reverse('get_coupon_info', kwargs={'course_id': course_key.to_deprecated_string()}),
+        'ajax_update_coupon': reverse('update_coupon', kwargs={'course_id': course_key.to_deprecated_string()}),
+        'ajax_add_coupon': reverse('add_coupon', kwargs={'course_id': course_key.to_deprecated_string()}),
+        'instructor_url': reverse('instructor_dashboard', kwargs={'course_id': course_key.to_deprecated_string()}),
+        'coupons': coupons,
+        'total_amount': total_amount,
+    }
+    return section_data
+
+
 def _section_course_info(course_key, access):
     """ Provide data for the corresponding dashboard section """
     course = get_course_by_id(course_key, depth=None)
diff --git a/lms/djangoapps/shoppingcart/exceptions.py b/lms/djangoapps/shoppingcart/exceptions.py
index b6f826040bfeb9865c3ca3e98cb3feb1d7a7ad46..8f4b30c583ab2d42b1ec1559dbca0e129b08a3a2 100644
--- a/lms/djangoapps/shoppingcart/exceptions.py
+++ b/lms/djangoapps/shoppingcart/exceptions.py
@@ -28,6 +28,18 @@ class CourseDoesNotExistException(InvalidCartItem):
     pass
 
 
+class CouponDoesNotExistException(InvalidCartItem):
+    pass
+
+
+class CouponAlreadyExistException(InvalidCartItem):
+    pass
+
+
+class ItemDoesNotExistAgainstCouponException(InvalidCartItem):
+    pass
+
+
 class ReportException(Exception):
     pass
 
diff --git a/lms/djangoapps/shoppingcart/migrations/0008_auto__add_coupons__add_couponredemption__chg_field_certificateitem_cou.py b/lms/djangoapps/shoppingcart/migrations/0008_auto__add_coupons__add_couponredemption__chg_field_certificateitem_cou.py
new file mode 100644
index 0000000000000000000000000000000000000000..8ff9a0d7ae5eaae87f021d0c6246e1a958605ac2
--- /dev/null
+++ b/lms/djangoapps/shoppingcart/migrations/0008_auto__add_coupons__add_couponredemption__chg_field_certificateitem_cou.py
@@ -0,0 +1,189 @@
+# -*- 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 'Coupons'
+        db.create_table('shoppingcart_coupons', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('code', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
+            ('description', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+            ('course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255)),
+            ('percentage_discount', self.gf('django.db.models.fields.IntegerField')(default=0)),
+            ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 6, 24, 0, 0))),
+            ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)),
+        ))
+        db.send_create_signal('shoppingcart', ['Coupons'])
+
+        # Adding model 'CouponRedemption'
+        db.create_table('shoppingcart_couponredemption', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('order', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['shoppingcart.Order'])),
+            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('coupon', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['shoppingcart.Coupons'])),
+        ))
+        db.send_create_signal('shoppingcart', ['CouponRedemption'])
+
+
+        # Changing field 'CertificateItem.course_id'
+        db.alter_column('shoppingcart_certificateitem', 'course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=128))
+
+        # Changing field 'PaidCourseRegistrationAnnotation.course_id'
+        db.alter_column('shoppingcart_paidcourseregistrationannotation', 'course_id', self.gf('xmodule_django.models.CourseKeyField')(unique=True, max_length=128))
+
+        # Changing field 'PaidCourseRegistration.course_id'
+        db.alter_column('shoppingcart_paidcourseregistration', 'course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=128))
+        # Adding field 'OrderItem.discount_price'
+        db.add_column('shoppingcart_orderitem', 'discount_price',
+                      self.gf('django.db.models.fields.DecimalField')(null=True, max_digits=30, decimal_places=2),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting model 'Coupons'
+        db.delete_table('shoppingcart_coupons')
+
+        # Deleting model 'CouponRedemption'
+        db.delete_table('shoppingcart_couponredemption')
+
+
+        # Changing field 'CertificateItem.course_id'
+        db.alter_column('shoppingcart_certificateitem', 'course_id', self.gf('django.db.models.fields.CharField')(max_length=128))
+
+        # Changing field 'PaidCourseRegistrationAnnotation.course_id'
+        db.alter_column('shoppingcart_paidcourseregistrationannotation', 'course_id', self.gf('django.db.models.fields.CharField')(max_length=128, unique=True))
+
+        # Changing field 'PaidCourseRegistration.course_id'
+        db.alter_column('shoppingcart_paidcourseregistration', 'course_id', self.gf('django.db.models.fields.CharField')(max_length=128))
+        # Deleting field 'OrderItem.discount_price'
+        db.delete_column('shoppingcart_orderitem', 'discount_price')
+
+
+    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': ('xmodule_django.models.CourseKeyField', [], {'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.couponredemption': {
+            'Meta': {'object_name': 'CouponRedemption'},
+            'coupon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shoppingcart.Coupons']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'order': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shoppingcart.Order']"}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'shoppingcart.coupons': {
+            'Meta': {'object_name': 'Coupons'},
+            'code': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 6, 24, 0, 0)'}),
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'percentage_discount': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+        },
+        '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'}),
+            'refunded_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'}),
+            'discount_price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '30', 'decimal_places': '2'}),
+            'fulfilled_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            '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'}),
+            'refund_requested_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'}),
+            'report_comments': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            'service_fee': ('django.db.models.fields.DecimalField', [], {'default': '0.0', 'max_digits': '30', 'decimal_places': '2'}),
+            'status': ('django.db.models.fields.CharField', [], {'default': "'cart'", 'max_length': '32', 'db_index': 'True'}),
+            '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': ('xmodule_django.models.CourseKeyField', [], {'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'})
+        },
+        'shoppingcart.paidcourseregistrationannotation': {
+            'Meta': {'object_name': 'PaidCourseRegistrationAnnotation'},
+            'annotation': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'unique': 'True', 'max_length': '128', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'student.courseenrollment': {
+            'Meta': {'ordering': "('user', 'course_id')", 'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'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
diff --git a/lms/djangoapps/shoppingcart/migrations/0009_auto__del_coupons__add_courseregistrationcode__add_coupon__chg_field_c.py b/lms/djangoapps/shoppingcart/migrations/0009_auto__del_coupons__add_courseregistrationcode__add_coupon__chg_field_c.py
new file mode 100644
index 0000000000000000000000000000000000000000..3850c104999c2bcf130dfa677c831b6dee385f89
--- /dev/null
+++ b/lms/djangoapps/shoppingcart/migrations/0009_auto__del_coupons__add_courseregistrationcode__add_coupon__chg_field_c.py
@@ -0,0 +1,216 @@
+# -*- 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 model 'Coupons'
+        db.delete_table('shoppingcart_coupons')
+
+        # Adding model 'CourseRegistrationCode'
+        db.create_table('shoppingcart_courseregistrationcode', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('code', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
+            ('course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255, db_index=True)),
+            ('transaction_group_name', self.gf('django.db.models.fields.CharField')(db_index=True, max_length=255, null=True, blank=True)),
+            ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='created_by_user', to=orm['auth.User'])),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 7, 1, 0, 0))),
+            ('redeemed_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='redeemed_by_user', null=True, to=orm['auth.User'])),
+            ('redeemed_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 7, 1, 0, 0), null=True)),
+        ))
+        db.send_create_signal('shoppingcart', ['CourseRegistrationCode'])
+
+        # Adding model 'Coupon'
+        db.create_table('shoppingcart_coupon', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('code', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
+            ('description', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+            ('course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255)),
+            ('percentage_discount', self.gf('django.db.models.fields.IntegerField')(default=0)),
+            ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 7, 1, 0, 0))),
+            ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)),
+        ))
+        db.send_create_signal('shoppingcart', ['Coupon'])
+
+
+        # Changing field 'CouponRedemption.coupon'
+        db.alter_column('shoppingcart_couponredemption', 'coupon_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['shoppingcart.Coupon']))
+        # Deleting field 'OrderItem.discount_price'
+        db.delete_column('shoppingcart_orderitem', 'discount_price')
+
+        # Adding field 'OrderItem.list_price'
+        db.add_column('shoppingcart_orderitem', 'list_price',
+                      self.gf('django.db.models.fields.DecimalField')(null=True, max_digits=30, decimal_places=2),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Adding model 'Coupons'
+        db.create_table('shoppingcart_coupons', (
+            ('code', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
+            ('percentage_discount', self.gf('django.db.models.fields.IntegerField')(default=0)),
+            ('description', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+            ('course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255)),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 6, 24, 0, 0))),
+            ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+        ))
+        db.send_create_signal('shoppingcart', ['Coupons'])
+
+        # Deleting model 'CourseRegistrationCode'
+        db.delete_table('shoppingcart_courseregistrationcode')
+
+        # Deleting model 'Coupon'
+        db.delete_table('shoppingcart_coupon')
+
+
+        # Changing field 'CouponRedemption.coupon'
+        db.alter_column('shoppingcart_couponredemption', 'coupon_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['shoppingcart.Coupons']))
+        # Adding field 'OrderItem.discount_price'
+        db.add_column('shoppingcart_orderitem', 'discount_price',
+                      self.gf('django.db.models.fields.DecimalField')(null=True, max_digits=30, decimal_places=2),
+                      keep_default=False)
+
+        # Deleting field 'OrderItem.list_price'
+        db.delete_column('shoppingcart_orderitem', 'list_price')
+
+
+    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': ('xmodule_django.models.CourseKeyField', [], {'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.coupon': {
+            'Meta': {'object_name': 'Coupon'},
+            'code': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 7, 1, 0, 0)'}),
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'percentage_discount': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+        },
+        'shoppingcart.couponredemption': {
+            'Meta': {'object_name': 'CouponRedemption'},
+            'coupon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shoppingcart.Coupon']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'order': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shoppingcart.Order']"}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'shoppingcart.courseregistrationcode': {
+            'Meta': {'object_name': 'CourseRegistrationCode'},
+            'code': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 7, 1, 0, 0)'}),
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_by_user'", 'to': "orm['auth.User']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'redeemed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 7, 1, 0, 0)', 'null': 'True'}),
+            'redeemed_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'redeemed_by_user'", 'null': 'True', 'to': "orm['auth.User']"}),
+            'transaction_group_name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': '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'}),
+            'refunded_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'}),
+            'fulfilled_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'line_desc': ('django.db.models.fields.CharField', [], {'default': "'Misc. Item'", 'max_length': '1024'}),
+            'list_price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '30', 'decimal_places': '2'}),
+            'order': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shoppingcart.Order']"}),
+            'qty': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+            'refund_requested_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'}),
+            'report_comments': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            'service_fee': ('django.db.models.fields.DecimalField', [], {'default': '0.0', 'max_digits': '30', 'decimal_places': '2'}),
+            'status': ('django.db.models.fields.CharField', [], {'default': "'cart'", 'max_length': '32', 'db_index': 'True'}),
+            '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': ('xmodule_django.models.CourseKeyField', [], {'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'})
+        },
+        'shoppingcart.paidcourseregistrationannotation': {
+            'Meta': {'object_name': 'PaidCourseRegistrationAnnotation'},
+            'annotation': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'unique': 'True', 'max_length': '128', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'student.courseenrollment': {
+            'Meta': {'ordering': "('user', 'course_id')", 'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
+            'course_id': ('xmodule_django.models.CourseKeyField', [], {'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
diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py
index 8e54a977b621f6ae0531113498a252d98cf54935..406257fd016f118dd3af3cfc128a5ef990d419f7 100644
--- a/lms/djangoapps/shoppingcart/models.py
+++ b/lms/djangoapps/shoppingcart/models.py
@@ -31,7 +31,7 @@ from xmodule_django.models import CourseKeyField
 from verify_student.models import SoftwareSecurePhotoVerification
 
 from .exceptions import (InvalidCartItem, PurchasedCallbackException, ItemAlreadyInCartException,
-                         AlreadyEnrolledInCourseException, CourseDoesNotExistException)
+                         AlreadyEnrolledInCourseException, CourseDoesNotExistException, CouponAlreadyExistException, ItemDoesNotExistAgainstCouponException)
 
 from microsite_configuration import microsite
 
@@ -217,6 +217,7 @@ class OrderItem(models.Model):
     status = models.CharField(max_length=32, default='cart', choices=ORDER_STATUSES, db_index=True)
     qty = models.IntegerField(default=1)
     unit_cost = models.DecimalField(default=0.0, decimal_places=2, max_digits=30)
+    list_price = models.DecimalField(decimal_places=2, max_digits=30, null=True)
     line_desc = models.CharField(default="Misc. Item", max_length=1024)
     currency = models.CharField(default="usd", max_length=8)  # lower case ISO currency codes
     fulfilled_time = models.DateTimeField(null=True, db_index=True)
@@ -304,6 +305,78 @@ class OrderItem(models.Model):
         return ''
 
 
+class CourseRegistrationCode(models.Model):
+    """
+    This table contains registration codes
+    With registration code, a user can register for a course for free
+    """
+    code = models.CharField(max_length=32, db_index=True)
+    course_id = CourseKeyField(max_length=255, db_index=True)
+    transaction_group_name = models.CharField(max_length=255, db_index=True, null=True, blank=True)
+    created_by = models.ForeignKey(User, related_name='created_by_user')
+    created_at = models.DateTimeField(default=datetime.now(pytz.utc))
+    redeemed_by = models.ForeignKey(User, null=True, related_name='redeemed_by_user')
+    redeemed_at = models.DateTimeField(default=datetime.now(pytz.utc), null=True)
+
+
+class Coupon(models.Model):
+    """
+    This table contains coupon codes
+    A user can get a discount offer on course if provide coupon code
+    """
+    code = models.CharField(max_length=32, db_index=True)
+    description = models.CharField(max_length=255, null=True, blank=True)
+    course_id = CourseKeyField(max_length=255)
+    percentage_discount = models.IntegerField(default=0)
+    created_by = models.ForeignKey(User)
+    created_at = models.DateTimeField(default=datetime.now(pytz.utc))
+    is_active = models.BooleanField(default=True)
+
+
+class CouponRedemption(models.Model):
+    """
+    This table contain coupon redemption info
+    """
+    order = models.ForeignKey(Order, db_index=True)
+    user = models.ForeignKey(User, db_index=True)
+    coupon = models.ForeignKey(Coupon, db_index=True)
+
+    @classmethod
+    def get_discount_price(cls, percentage_discount, value):
+        """
+        return discounted price against coupon
+        """
+        discount = Decimal("{0:.2f}".format(Decimal(percentage_discount / 100.00) * value))
+        return value - discount
+
+    @classmethod
+    def add_coupon_redemption(cls, coupon, order):
+        """
+        add coupon info into coupon_redemption model
+        """
+        cart_items = order.orderitem_set.all().select_subclasses()
+
+        for item in cart_items:
+            if getattr(item, 'course_id'):
+                if item.course_id == coupon.course_id:
+                    coupon_redemption, created = cls.objects.get_or_create(order=order, user=order.user, coupon=coupon)
+                    if not created:
+                        log.exception("Coupon '{0}' already exist for user '{1}' against order id '{2}'"
+                                      .format(coupon.code, order.user.username, order.id))
+                        raise CouponAlreadyExistException
+
+                    discount_price = cls.get_discount_price(coupon.percentage_discount, item.unit_cost)
+                    item.list_price = item.unit_cost
+                    item.unit_cost = discount_price
+                    item.save()
+                    log.info("Discount generated for user {0} against order id '{1}' "
+                             .format(order.user.username, order.id))
+                    return coupon_redemption
+
+        log.warning("Course item does not exist for coupon '{0}'".format(coupon.code))
+        raise ItemDoesNotExistAgainstCouponException
+
+
 class PaidCourseRegistration(OrderItem):
     """
     This is an inventory item for paying for a course registration
@@ -319,6 +392,19 @@ class PaidCourseRegistration(OrderItem):
         return course_id in [item.paidcourseregistration.course_id
                              for item in order.orderitem_set.all().select_subclasses("paidcourseregistration")]
 
+    @classmethod
+    def get_total_amount_of_purchased_item(cls, course_key):
+        """
+        This will return the total amount of money that a purchased course generated
+        """
+        total_cost = 0
+        result = cls.objects.filter(course_id=course_key, status='purchased').aggregate(total=Sum('unit_cost', field='qty * unit_cost'))  # pylint: disable=E1101
+
+        if result['total'] is not None:
+            total_cost = result['total']
+
+        return total_cost
+
     @classmethod
     @transaction.commit_on_success
     def add_to_order(cls, order, course_id, mode_slug=CourseMode.DEFAULT_MODE_SLUG, cost=None, currency=None):
diff --git a/lms/djangoapps/shoppingcart/processors/CyberSource.py b/lms/djangoapps/shoppingcart/processors/CyberSource.py
index 5c980073d71f58f960f5ea19769148507a865418..b2ad8ccd660a0a2e48fb161b0e8db34770e902a0 100644
--- a/lms/djangoapps/shoppingcart/processors/CyberSource.py
+++ b/lms/djangoapps/shoppingcart/processors/CyberSource.py
@@ -16,8 +16,25 @@ from django.utils.translation import ugettext as _
 from edxmako.shortcuts import render_to_string
 from shoppingcart.models import Order
 from shoppingcart.processors.exceptions import *
+from microsite_configuration import microsite
 
 
+def get_cybersource_config():
+    """
+    This method will return any microsite specific cybersource configuration, otherwise
+    we return the default configuration
+    """
+    config_key = microsite.get_value('cybersource_config_key')
+    config = {}
+    if config_key:
+        # The microsite CyberSource configuration will be subkeys inside of the normal default
+        # CyberSource configuration
+        config = settings.CC_PROCESSOR['CyberSource']['microsites'][config_key]
+    else:
+        config = settings.CC_PROCESSOR['CyberSource']
+
+    return config
+
 def process_postpay_callback(params):
     """
     The top level call to this module, basically
@@ -53,7 +70,7 @@ def processor_hash(value):
     """
     Performs the base64(HMAC_SHA1(key, value)) used by CyberSource Hosted Order Page
     """
-    shared_secret = settings.CC_PROCESSOR['CyberSource'].get('SHARED_SECRET', '')
+    shared_secret = get_cybersource_config().get('SHARED_SECRET', '')
     hash_obj = hmac.new(shared_secret.encode('utf-8'), value.encode('utf-8'), sha1)
     return binascii.b2a_base64(hash_obj.digest())[:-1]  # last character is a '\n', which we don't want
 
@@ -63,9 +80,9 @@ def sign(params, signed_fields_key='orderPage_signedFields', full_sig_key='order
     params needs to be an ordered dict, b/c cybersource documentation states that order is important.
     Reverse engineered from PHP version provided by cybersource
     """
-    merchant_id = settings.CC_PROCESSOR['CyberSource'].get('MERCHANT_ID', '')
-    order_page_version = settings.CC_PROCESSOR['CyberSource'].get('ORDERPAGE_VERSION', '7')
-    serial_number = settings.CC_PROCESSOR['CyberSource'].get('SERIAL_NUMBER', '')
+    merchant_id = get_cybersource_config().get('MERCHANT_ID', '')
+    order_page_version = get_cybersource_config().get('ORDERPAGE_VERSION', '7')
+    serial_number = get_cybersource_config().get('SERIAL_NUMBER', '')
 
     params['merchantID'] = merchant_id
     params['orderPage_timestamp'] = int(time.time() * 1000)
@@ -123,7 +140,7 @@ def get_purchase_params(cart):
     return params
 
 def get_purchase_endpoint():
-    return settings.CC_PROCESSOR['CyberSource'].get('PURCHASE_ENDPOINT', '')
+    return get_cybersource_config().get('PURCHASE_ENDPOINT', '')
 
 def payment_accepted(params):
     """
@@ -215,7 +232,9 @@ def record_purchase(params, order):
 
 def get_processor_decline_html(params):
     """Have to parse through the error codes to return a helpful message"""
-    payment_support_email = settings.PAYMENT_SUPPORT_EMAIL
+
+    # see if we have an override in the microsites
+    payment_support_email = microsite.get_value('payment_support_email', settings.PAYMENT_SUPPORT_EMAIL)
 
     msg = dedent(_(
             """
@@ -238,7 +257,8 @@ def get_processor_decline_html(params):
 def get_processor_exception_html(exception):
     """Return error HTML associated with exception"""
 
-    payment_support_email = settings.PAYMENT_SUPPORT_EMAIL
+    # see if we have an override in the microsites
+    payment_support_email = microsite.get_value('payment_support_email', settings.PAYMENT_SUPPORT_EMAIL)
     if isinstance(exception, CCProcessorDataException):
         msg = dedent(_(
                 """
diff --git a/lms/djangoapps/shoppingcart/processors/CyberSource2.py b/lms/djangoapps/shoppingcart/processors/CyberSource2.py
new file mode 100644
index 0000000000000000000000000000000000000000..ecc928f8258d58e45cdfd27d9e66ddea6c6e6ebc
--- /dev/null
+++ b/lms/djangoapps/shoppingcart/processors/CyberSource2.py
@@ -0,0 +1,404 @@
+### Implementation of support for the Cybersource Credit card processor using the new
+### Secure Acceptance API. The previous Hosted Order Page API is being deprecated as of 9/14
+### It is mostly the same as the CyberSource.py file, but we have a new file so that we can
+### maintain some backwards-compatibility in case of a need to quickly roll back (i.e.
+### configuration change rather than code rollback )
+
+### The name of this file should be used as the key of the dict in the CC_PROCESSOR setting
+### Implementes interface as specified by __init__.py
+
+import hmac
+import binascii
+import re
+import json
+import uuid
+from datetime import datetime
+from collections import OrderedDict, defaultdict
+from decimal import Decimal, InvalidOperation
+from hashlib import sha256
+from textwrap import dedent
+from django.conf import settings
+from django.utils.translation import ugettext as _
+from edxmako.shortcuts import render_to_string
+from shoppingcart.models import Order
+from shoppingcart.processors.exceptions import *
+from microsite_configuration import microsite
+from django.core.urlresolvers import reverse
+
+
+def get_cybersource_config():
+    """
+    This method will return any microsite specific cybersource configuration, otherwise
+    we return the default configuration
+    """
+    config_key = microsite.get_value('cybersource_config_key')
+    config = {}
+    if config_key:
+        # The microsite CyberSource configuration will be subkeys inside of the normal default
+        # CyberSource configuration
+        config = settings.CC_PROCESSOR['CyberSource2']['microsites'][config_key]
+    else:
+        config = settings.CC_PROCESSOR['CyberSource2']
+
+    return config
+
+
+def process_postpay_callback(params):
+    """
+    The top level call to this module, basically
+    This function is handed the callback request after the customer has entered the CC info and clicked "buy"
+    on the external Hosted Order Page.
+    It is expected to verify the callback and determine if the payment was successful.
+    It returns {'success':bool, 'order':Order, 'error_html':str}
+    If successful this function must have the side effect of marking the order purchased and calling the
+    purchased_callbacks of the cart  items.
+    If unsuccessful this function should not have those side effects but should try to figure out why and
+    return a helpful-enough error message in error_html.
+    """
+    try:
+        result = payment_accepted(params)
+        if result['accepted']:
+            # SUCCESS CASE first, rest are some sort of oddity
+            record_purchase(params, result['order'])
+            return {'success': True,
+                    'order': result['order'],
+                    'error_html': ''}
+        else:
+            return {'success': False,
+                    'order': result['order'],
+                    'error_html': get_processor_decline_html(params)}
+    except CCProcessorException as error:
+        return {'success': False,
+                'order': None,  # due to exception we may not have the order
+                'error_html': get_processor_exception_html(error)}
+
+
+def processor_hash(value):
+    """
+    Performs the base64(HMAC_SHA1(key, value)) used by CyberSource Hosted Order Page
+    """
+    secret_key = get_cybersource_config().get('SECRET_KEY', '')
+    hash_obj = hmac.new(secret_key, value, sha256)
+    return binascii.b2a_base64(hash_obj.digest())[:-1]  # last character is a '\n', which we don't want
+
+
+def sign(params, signed_fields_key='signed_field_names', full_sig_key='signature'):
+    """
+    params needs to be an ordered dict, b/c cybersource documentation states that order is important.
+    Reverse engineered from PHP version provided by cybersource
+    """
+    fields = u",".join(params.keys())
+    params[signed_fields_key] = fields
+
+    signed_fields = params.get(signed_fields_key, '').split(',')
+    values = u",".join([u"{0}={1}".format(i, params.get(i, '')) for i in signed_fields])
+    params[full_sig_key] = processor_hash(values)
+    params[signed_fields_key] = fields
+
+    return params
+
+
+def render_purchase_form_html(cart):
+    """
+    Renders the HTML of the hidden POST form that must be used to initiate a purchase with CyberSource
+    """
+    return render_to_string('shoppingcart/cybersource_form.html', {
+        'action': get_purchase_endpoint(),
+        'params': get_signed_purchase_params(cart),
+    })
+
+
+def get_signed_purchase_params(cart):
+    """
+    This method will return a digitally signed set of CyberSource parameters
+    """
+    return sign(get_purchase_params(cart))
+
+
+def get_purchase_params(cart):
+    """
+    This method will build out a dictionary of parameters needed by CyberSource to complete the transaction
+    """
+    total_cost = cart.total_cost
+    amount = "{0:0.2f}".format(total_cost)
+    params = OrderedDict()
+
+    params['amount'] = amount
+    params['currency'] = cart.currency
+    params['orderNumber'] = "OrderId: {0:d}".format(cart.id)
+
+    params['access_key'] = get_cybersource_config().get('ACCESS_KEY', '')
+    params['profile_id'] = get_cybersource_config().get('PROFILE_ID', '')
+    params['reference_number'] = cart.id
+    params['transaction_type'] = 'sale'
+
+    params['locale'] = 'en'
+    params['signed_date_time'] =  datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
+    params['signed_field_names'] = 'access_key,profile_id,amount,currency,transaction_type,reference_number,signed_date_time,locale,transaction_uuid,signed_field_names,unsigned_field_names,orderNumber'
+    params['unsigned_field_names'] = ''
+    params['transaction_uuid'] = uuid.uuid4()
+    params['payment_method'] = 'card'
+
+    if hasattr(cart, 'context') and 'request_domain' in cart.context:
+        params['override_custom_receipt_page'] = '{0}{1}'.format(
+            cart.context['request_domain'],
+            reverse('shoppingcart.views.postpay_callback')
+        )
+
+    return params
+
+
+def get_purchase_endpoint():
+    """
+    Helper function to return the CyberSource endpoint configuration
+    """
+    return get_cybersource_config().get('PURCHASE_ENDPOINT', '')
+
+
+def payment_accepted(params):
+    """
+    Check that cybersource has accepted the payment
+    params: a dictionary of POST parameters returned by CyberSource in their post-payment callback
+
+    returns: true if the payment was correctly accepted, for the right amount
+             false if the payment was not accepted
+
+    raises: CCProcessorDataException if the returned message did not provide required parameters
+            CCProcessorWrongAmountException if the amount charged is different than the order amount
+
+    """
+    #make sure required keys are present and convert their values to the right type
+    valid_params = {}
+    for key, key_type in [('req_reference_number', int),
+                          ('req_currency', str),
+                          ('decision', str)]:
+        if key not in params:
+            raise CCProcessorDataException(
+                _("The payment processor did not return a required parameter: {0}".format(key))
+            )
+        try:
+            valid_params[key] = key_type(params[key])
+        except ValueError:
+            raise CCProcessorDataException(
+                _("The payment processor returned a badly-typed value {0} for param {1}.".format(params[key], key))
+            )
+
+    try:
+        order = Order.objects.get(id=valid_params['req_reference_number'])
+    except Order.DoesNotExist:
+        raise CCProcessorDataException(_("The payment processor accepted an order whose number is not in our system."))
+
+    if valid_params['decision'] == 'ACCEPT':
+        try:
+            # Moved reading of charged_amount here from the valid_params loop above because
+            # only 'ACCEPT' messages have a 'ccAuthReply_amount' parameter
+            charged_amt = Decimal(params['auth_amount'])
+        except InvalidOperation:
+            raise CCProcessorDataException(
+                _("The payment processor returned a badly-typed value {0} for param {1}.".format(
+                    params['auth_amount'], 'auth_amount'))
+            )
+
+        if charged_amt == order.total_cost and valid_params['req_currency'] == order.currency:
+            return {'accepted': True,
+                    'amt_charged': charged_amt,
+                    'currency': valid_params['req_currency'],
+                    'order': order}
+        else:
+            raise CCProcessorWrongAmountException(
+                _("The amount charged by the processor {0} {1} is different than the total cost of the order {2} {3}."
+                    .format(charged_amt, valid_params['req_currency'],
+                            order.total_cost, order.currency))
+            )
+    else:
+        return {'accepted': False,
+                'amt_charged': 0,
+                'currency': 'usd',
+                'order': order}
+
+
+def record_purchase(params, order):
+    """
+    Record the purchase and run purchased_callbacks
+    """
+    ccnum_str = params.get('req_card_number', '')
+    mm = re.search("\d", ccnum_str)
+    if mm:
+        ccnum = ccnum_str[mm.start():]
+    else:
+        ccnum = "####"
+
+    order.purchase(
+        first=params.get('req_bill_to_forename', ''),
+        last=params.get('req_bill_to_surname', ''),
+        street1=params.get('req_bill_to_address_line1', ''),
+        street2=params.get('req_bill_to_address_line2', ''),
+        city=params.get('req_bill_to_address_city', ''),
+        state=params.get('req_bill_to_address_state', ''),
+        country=params.get('req_bill_to_address_country', ''),
+        postalcode=params.get('req_bill_to_address_postal_code', ''),
+        ccnum=ccnum,
+        cardtype=CARDTYPE_MAP[params.get('req_card_type', '')],
+        processor_reply_dump=json.dumps(params)
+    )
+
+
+def get_processor_decline_html(params):
+    """Have to parse through the error codes to return a helpful message"""
+    payment_support_email = microsite.get_value('payment_support_email', settings.PAYMENT_SUPPORT_EMAIL)
+
+    msg = dedent(_(
+            """
+            <p class="error_msg">
+            Sorry! Our payment processor did not accept your payment.
+            The decision they returned was <span class="decision">{decision}</span>,
+            and the reason was <span class="reason">{reason_code}:{reason_msg}</span>.
+            You were not charged. Please try a different form of payment.
+            Contact us with payment-related questions at {email}.
+            </p>
+            """))
+
+    return msg.format(
+        decision=params['decision'],
+        reason_code=params['reason_code'],
+        reason_msg=REASONCODE_MAP[params['reason_code']],
+        email=payment_support_email
+    )
+
+
+def get_processor_exception_html(exception):
+    """Return error HTML associated with exception"""
+
+    payment_support_email = microsite.get_value('payment_support_email', settings.PAYMENT_SUPPORT_EMAIL)
+    if isinstance(exception, CCProcessorDataException):
+        msg = dedent(_(
+                """
+                <p class="error_msg">
+                Sorry! Our payment processor sent us back a payment confirmation that had inconsistent data!
+                We apologize that we cannot verify whether the charge went through and take further action on your order.
+                The specific error message is: <span class="exception_msg">{msg}</span>.
+                Your credit card may possibly have been charged.  Contact us with payment-specific questions at {email}.
+                </p>
+                """.format(msg=exception.message, email=payment_support_email)))
+        return msg
+    elif isinstance(exception, CCProcessorWrongAmountException):
+        msg = dedent(_(
+                """
+                <p class="error_msg">
+                Sorry! Due to an error your purchase was charged for a different amount than the order total!
+                The specific error message is: <span class="exception_msg">{msg}</span>.
+                Your credit card has probably been charged. Contact us with payment-specific questions at {email}.
+                </p>
+                """.format(msg=exception.message, email=payment_support_email)))
+        return msg
+
+    # fallthrough case, which basically never happens
+    return '<p class="error_msg">EXCEPTION!</p>'
+
+
+CARDTYPE_MAP = defaultdict(lambda: "UNKNOWN")
+CARDTYPE_MAP.update(
+    {
+        '001': 'Visa',
+        '002': 'MasterCard',
+        '003': 'American Express',
+        '004': 'Discover',
+        '005': 'Diners Club',
+        '006': 'Carte Blanche',
+        '007': 'JCB',
+        '014': 'EnRoute',
+        '021': 'JAL',
+        '024': 'Maestro',
+        '031': 'Delta',
+        '033': 'Visa Electron',
+        '034': 'Dankort',
+        '035': 'Laser',
+        '036': 'Carte Bleue',
+        '037': 'Carta Si',
+        '042': 'Maestro Int.',
+        '043': 'GE Money UK card'
+    }
+)
+
+REASONCODE_MAP = defaultdict(lambda: "UNKNOWN REASON")
+REASONCODE_MAP.update(
+    {
+        '100': _('Successful transaction.'),
+        '102': _('One or more fields in the request contains invalid data.'),
+        '104': dedent(_(
+            """
+            The access_key and transaction_uuid fields for this authorization request matches the access_key and
+            transaction_uuid of another authorization request that you sent in the last 15 minutes.
+            Possible fix: retry the payment after 15 minutes.
+            """)),
+        '110': _('Only a partial amount was approved.'),
+        '200': dedent(_(
+            """
+            The authorization request was approved by the issuing bank but declined by CyberSource
+            becouse it did not pass the Address Verification System (AVS).
+            """)),
+        '201': dedent(_(
+            """
+            The issuing bank has questions about the request. You do not receive an
+            authorization code programmatically, but you might receive one verbally by calling the processor.
+            Possible fix: retry with another form of payment
+            """)),
+        '202': dedent(_(
+            """
+            Expired card. You might also receive this if the expiration date you
+            provided does not match the date the issuing bank has on file.
+            Possible fix: retry with another form of payment
+            """)),
+        '203': dedent(_(
+            """
+            General decline of the card. No other information provided by the issuing bank.
+            Possible fix: retry with another form of payment
+            """)),
+        '204': _('Insufficient funds in the account. Possible fix: retry with another form of payment'),
+        # 205 was Stolen or lost card.  Might as well not show this message to the person using such a card.
+        '205': _('Stolen or lost card'),
+        '207': _('Issuing bank unavailable. Possible fix: retry again after a few minutes'),
+        '208': dedent(_(
+            """
+            Inactive card or card not authorized for card-not-present transactions.
+            Possible fix: retry with another form of payment
+            """)),
+        '210': _('The card has reached the credit limit. Possible fix: retry with another form of payment'),
+        '211': _('Invalid card verification number (CVN). Possible fix: retry with another form of payment'),
+        # 221 was The customer matched an entry on the processor's negative file.
+        # Might as well not show this message to the person using such a card.
+        '221': _('The customer matched an entry on the processors negative file.'),
+        '222': _('Account frozen. Possible fix: retry with another form of payment'),
+        '230': dedent(_(
+            """
+            The authorization request was approved by the issuing bank but declined by
+            CyberSource because it did not pass the CVN check.
+            Possible fix: retry with another form of payment
+            """)),
+        '231': _('Invalid account number. Possible fix: retry with another form of payment'),
+        '232': dedent(_(
+            """
+            The card type is not accepted by the payment processor.
+            Possible fix: retry with another form of payment
+            """)),
+        '233': _('General decline by the processor.  Possible fix: retry with another form of payment'),
+        '234': dedent(_(
+            """
+            There is a problem with the information in your CyberSource account.  Please let us know at {0}
+            """.format(settings.PAYMENT_SUPPORT_EMAIL))),
+        '236': _('Processor Failure.  Possible fix: retry the payment'),
+        '240': dedent(_(
+            """
+            The card type sent is invalid or does not correlate with the credit card number.
+            Possible fix: retry with the same card or another form of payment
+            """)),
+        '475': _('The cardholder is enrolled for payer authentication'),
+        '476': _('Payer authentication could not be authenticated'),
+        '520': dedent(_(
+            """
+            The authorization request was approved by the issuing bank but declined by CyberSource based
+            on your legacy Smart Authorization settings.
+            Possible fix: retry with a different form of payment.
+            """)),
+    }
+)
diff --git a/lms/djangoapps/shoppingcart/processors/tests/test_CyberSource.py b/lms/djangoapps/shoppingcart/processors/tests/test_CyberSource.py
index 6f708f3bc3d70c4f3706031780b7a6ca0d3dd3b1..8d1c9aeb51985850ea6f24e756f7d3cfe04d3330 100644
--- a/lms/djangoapps/shoppingcart/processors/tests/test_CyberSource.py
+++ b/lms/djangoapps/shoppingcart/processors/tests/test_CyberSource.py
@@ -10,6 +10,8 @@ from shoppingcart.models import Order, OrderItem
 from shoppingcart.processors.CyberSource import *
 from shoppingcart.processors.exceptions import *
 from mock import patch, Mock
+from microsite_configuration import microsite
+import mock
 
 
 TEST_CC_PROCESSOR = {
@@ -19,10 +21,28 @@ TEST_CC_PROCESSOR = {
         'SERIAL_NUMBER': '12345',
         'ORDERPAGE_VERSION': '7',
         'PURCHASE_ENDPOINT': '',
+        'microsites': {
+            'test_microsite': {
+                'SHARED_SECRET': 'secret_override',
+                'MERCHANT_ID': 'edx_test_override',
+                'SERIAL_NUMBER': '12345_override',
+                'ORDERPAGE_VERSION': '7',
+                'PURCHASE_ENDPOINT': '',
+            }
+        }
     }
 }
 
 
+def fakemicrosite(name, default=None):
+    """
+    This is a test mocking function to return a microsite configuration
+    """
+    if name == 'cybersource_config_key':
+        return 'test_microsite'
+    else:
+        return None
+
 @override_settings(CC_PROCESSOR=TEST_CC_PROCESSOR)
 class CyberSourceTests(TestCase):
 
@@ -33,6 +53,15 @@ class CyberSourceTests(TestCase):
         self.assertEqual(settings.CC_PROCESSOR['CyberSource']['MERCHANT_ID'], 'edx_test')
         self.assertEqual(settings.CC_PROCESSOR['CyberSource']['SHARED_SECRET'], 'secret')
 
+    def test_microsite_no_override_settings(self):
+        self.assertEqual(get_cybersource_config()['MERCHANT_ID'], 'edx_test')
+        self.assertEqual(get_cybersource_config()['SHARED_SECRET'], 'secret')
+
+    @mock.patch("microsite_configuration.microsite.get_value", fakemicrosite)
+    def test_microsite_override_settings(self):
+        self.assertEqual(get_cybersource_config()['MERCHANT_ID'], 'edx_test_override')
+        self.assertEqual(get_cybersource_config()['SHARED_SECRET'], 'secret_override')
+
     def test_hash(self):
         """
         Tests the hash function.  Basically just hardcodes the answer.
diff --git a/lms/djangoapps/shoppingcart/tests/test_views.py b/lms/djangoapps/shoppingcart/tests/test_views.py
index fc7cd7158d40d2b0453b1d0d2563de30e5ee979e..8f0e93f8095bafdc7382a024a1d01df4f8516bf6 100644
--- a/lms/djangoapps/shoppingcart/tests/test_views.py
+++ b/lms/djangoapps/shoppingcart/tests/test_views.py
@@ -14,7 +14,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
 from xmodule.modulestore.tests.factories import CourseFactory
 from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
 from shoppingcart.views import _can_download_report, _get_date_from_str
-from shoppingcart.models import Order, CertificateItem, PaidCourseRegistration
+from shoppingcart.models import Order, CertificateItem, PaidCourseRegistration, Coupon
 from student.tests.factories import UserFactory
 from student.models import CourseEnrollment
 from course_modes.models import CourseMode
@@ -22,7 +22,8 @@ from edxmako.shortcuts import render_to_response
 from shoppingcart.processors import render_purchase_form_html
 from mock import patch, Mock
 from shoppingcart.views import initialize_report
-
+from decimal import Decimal
+from student.tests.factories import AdminFactory
 
 def mock_render_purchase_form_html(*args, **kwargs):
     return render_purchase_form_html(*args, **kwargs)
@@ -45,7 +46,10 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
         self.user = UserFactory.create()
         self.user.set_password('password')
         self.user.save()
+        self.instructor = AdminFactory.create()
         self.cost = 40
+        self.coupon_code = 'abcde'
+        self.percentage_discount = 10
         self.course = CourseFactory.create(org='MITx', number='999', display_name='Robot Super Course')
         self.course_key = self.course.id
         self.course_mode = CourseMode(course_id=self.course_key,
@@ -58,6 +62,29 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
         self.cart = Order.get_cart_for_user(self.user)
         self.addCleanup(patcher.stop)
 
+    def get_discount(self):
+        """
+        This method simple return the discounted amount
+        """
+        val = Decimal("{0:.2f}".format(Decimal(self.percentage_discount / 100.00) * self.cost))
+        return self.cost - val
+
+    def add_coupon(self, course_key, is_active):
+        """
+        add dummy coupon into models
+        """
+        coupon = Coupon(code=self.coupon_code, description='testing code', course_id=course_key,
+                        percentage_discount=self.percentage_discount, created_by=self.user, is_active=is_active)
+        coupon.save()
+
+    def add_course_to_user_cart(self):
+        """
+        adding course to user cart
+        """
+        self.login_user()
+        reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
+        return reg_item
+
     def login_user(self):
         self.client.login(username=self.user.username, password="password")
 
@@ -72,6 +99,141 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
         self.assertEqual(resp.status_code, 400)
         self.assertIn('The course {0} is already in your cart.'.format(self.course_key.to_deprecated_string()), resp.content)
 
+    def test_course_discount_invalid_coupon(self):
+        self.add_coupon(self.course_key, True)
+        self.add_course_to_user_cart()
+        non_existing_code = "non_existing_code"
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': non_existing_code})
+        self.assertEqual(resp.status_code, 404)
+        self.assertIn("Discount does not exist against coupon '{0}'.".format(non_existing_code), resp.content)
+
+    def test_course_discount_inactive_coupon(self):
+        self.add_coupon(self.course_key, False)
+        self.add_course_to_user_cart()
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 400)
+        self.assertIn("Coupon '{0}' is inactive.".format(self.coupon_code), resp.content)
+
+    def test_course_does_not_exist_in_cart_against_valid_coupon(self):
+        course_key = self.course_key.to_deprecated_string() + 'testing'
+        self.add_coupon(course_key, True)
+        self.add_course_to_user_cart()
+
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 404)
+        self.assertIn("Coupon '{0}' is not valid for any course in the shopping cart.".format(self.coupon_code), resp.content)
+
+    def test_course_discount_for_valid_active_coupon_code(self):
+
+        self.add_coupon(self.course_key, True)
+        self.add_course_to_user_cart()
+
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 200)
+
+        # unit price should be updated for that course
+        item = self.cart.orderitem_set.all().select_subclasses()[0]
+        self.assertEquals(item.unit_cost, self.get_discount())
+
+        # after getting 10 percent discount
+        self.assertEqual(self.cart.total_cost, self.get_discount())
+
+        # now testing coupon code already used scenario, reusing the same coupon code
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 400)
+        self.assertIn("Coupon '{0}' already used.".format(self.coupon_code), resp.content)
+
+    @patch('shoppingcart.views.log.debug')
+    def test_non_existing_coupon_redemption_on_removing_item(self, debug_log):
+
+        reg_item = self.add_course_to_user_cart()
+        resp = self.client.post(reverse('shoppingcart.views.remove_item', args=[]),
+                                {'id': reg_item.id})
+        debug_log.assert_called_with(
+            'Coupon redemption does not exist for order item id={0}.'.format(reg_item.id))
+
+        self.assertEqual(resp.status_code, 200)
+        self.assertEquals(self.cart.orderitem_set.count(), 0)
+
+    @patch('shoppingcart.views.log.info')
+    def test_existing_coupon_redemption_on_removing_item(self, info_log):
+
+        self.add_coupon(self.course_key, True)
+        reg_item = self.add_course_to_user_cart()
+
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 200)
+
+        resp = self.client.post(reverse('shoppingcart.views.remove_item', args=[]),
+                                {'id': reg_item.id})
+
+        self.assertEqual(resp.status_code, 200)
+        self.assertEquals(self.cart.orderitem_set.count(), 0)
+        info_log.assert_called_with(
+            'Coupon "{0}" redemption entry removed for user "{1}" for order item "{2}"'.format(self.coupon_code, self.user, reg_item.id))
+
+    @patch('shoppingcart.views.log.info')
+    def test_coupon_discount_for_multiple_courses_in_cart(self, info_log):
+
+        reg_item = self.add_course_to_user_cart()
+        self.add_coupon(self.course_key, True)
+        cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
+        self.assertEquals(self.cart.orderitem_set.count(), 2)
+
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 200)
+
+        # unit_cost should be updated for that particular course for which coupon code is registered
+        items = self.cart.orderitem_set.all().select_subclasses()
+        for item in items:
+            if item.id == reg_item.id:
+                self.assertEquals(item.unit_cost, self.get_discount())
+            elif item.id == cert_item.id:
+                self.assertEquals(item.list_price, None)
+
+        # Delete the discounted item, corresponding coupon redemption should be removed for that particular discounted item
+        resp = self.client.post(reverse('shoppingcart.views.remove_item', args=[]),
+                                {'id': reg_item.id})
+
+        self.assertEqual(resp.status_code, 200)
+        self.assertEquals(self.cart.orderitem_set.count(), 1)
+        info_log.assert_called_with(
+            'Coupon "{0}" redemption entry removed for user "{1}" for order item "{2}"'.format(self.coupon_code, self.user, reg_item.id))
+
+    @patch('shoppingcart.views.log.info')
+    def test_delete_certificate_item(self, info_log):
+
+        reg_item = self.add_course_to_user_cart()
+        cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
+        self.assertEquals(self.cart.orderitem_set.count(), 2)
+
+        # Delete the discounted item, corresponding coupon redemption should be removed for that particular discounted item
+        resp = self.client.post(reverse('shoppingcart.views.remove_item', args=[]),
+                                {'id': cert_item.id})
+
+        self.assertEqual(resp.status_code, 200)
+        self.assertEquals(self.cart.orderitem_set.count(), 1)
+        info_log.assert_called_with(
+            'order item {0} removed for user {1}'.format(cert_item.id, self.user))
+
+    @patch('shoppingcart.views.log.info')
+    def test_remove_coupon_redemption_on_clear_cart(self, info_log):
+
+        reg_item = self.add_course_to_user_cart()
+        CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
+        self.assertEquals(self.cart.orderitem_set.count(), 2)
+
+        self.add_coupon(self.course_key, True)
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 200)
+
+        resp = self.client.post(reverse('shoppingcart.views.clear_cart', args=[]))
+        self.assertEqual(resp.status_code, 200)
+        self.assertEquals(self.cart.orderitem_set.count(), 0)
+
+        info_log.assert_called_with(
+            'Coupon redemption entry removed for user {0} for order {1}'.format(self.user, reg_item.id))
+
     def test_add_course_to_cart_already_registered(self):
         CourseEnrollment.enroll(self.user, self.course_key)
         self.login_user()
@@ -188,6 +350,41 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
         resp2 = self.client.get(reverse('shoppingcart.views.show_receipt', args=[1000]))
         self.assertEqual(resp2.status_code, 404)
 
+    def test_total_amount_of_purchased_course(self):
+        self.add_course_to_user_cart()
+        self.assertEquals(self.cart.orderitem_set.count(), 1)
+        self.add_coupon(self.course_key, True)
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 200)
+
+        self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
+
+        # Total amount of a particular course that is purchased by different users
+        total_amount = PaidCourseRegistration.get_total_amount_of_purchased_item(self.course_key)
+        self.assertEqual(total_amount, 36)
+
+        self.client.login(username=self.instructor.username, password="test")
+        cart = Order.get_cart_for_user(self.instructor)
+        PaidCourseRegistration.add_to_order(cart, self.course_key)
+        cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
+
+        total_amount = PaidCourseRegistration.get_total_amount_of_purchased_item(self.course_key)
+        self.assertEqual(total_amount, 76)
+
+    @patch('shoppingcart.views.render_to_response', render_mock)
+    def test_show_receipt_success_with_valid_coupon_code(self):
+        self.add_course_to_user_cart()
+        self.add_coupon(self.course_key, True)
+
+        resp = self.client.post(reverse('shoppingcart.views.use_coupon'), {'coupon_code': self.coupon_code})
+        self.assertEqual(resp.status_code, 200)
+        self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
+
+        resp = self.client.get(reverse('shoppingcart.views.show_receipt', args=[self.cart.id]))
+        self.assertEqual(resp.status_code, 200)
+        self.assertIn('FirstNameTesting123', resp.content)
+        self.assertIn(str(self.get_discount()), resp.content)
+
     @patch('shoppingcart.views.render_to_response', render_mock)
     def test_show_receipt_success(self):
         reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
diff --git a/lms/djangoapps/shoppingcart/urls.py b/lms/djangoapps/shoppingcart/urls.py
index 2dd083c88c7a8a6707b7c2273e6ba9f16635d87c..14ea008f97e345a4b2d5458008a492beec52e2ab 100644
--- a/lms/djangoapps/shoppingcart/urls.py
+++ b/lms/djangoapps/shoppingcart/urls.py
@@ -14,6 +14,7 @@ if settings.FEATURES['ENABLE_SHOPPING_CART']:
         url(r'^clear/$', 'clear_cart'),
         url(r'^remove_item/$', 'remove_item'),
         url(r'^add/course/{}/$'.format(settings.COURSE_ID_PATTERN), 'add_course_to_cart', name='add_course_to_cart'),
+        url(r'^use_coupon/$', 'use_coupon'),
     )
 
 if settings.FEATURES.get('ENABLE_PAYMENT_FAKE'):
diff --git a/lms/djangoapps/shoppingcart/views.py b/lms/djangoapps/shoppingcart/views.py
index a01648e0cb0edf08800815e364e9c7b8027ede57..7f60780cc0125522eae48cb70c74339e8b578ede 100644
--- a/lms/djangoapps/shoppingcart/views.py
+++ b/lms/djangoapps/shoppingcart/views.py
@@ -14,9 +14,10 @@ from edxmako.shortcuts import render_to_response
 from opaque_keys.edx.locations import SlashSeparatedCourseKey
 from shoppingcart.reports import RefundReport, ItemizedPurchaseReport, UniversityRevenueShareReport, CertificateStatusReport
 from student.models import CourseEnrollment
-from .exceptions import ItemAlreadyInCartException, AlreadyEnrolledInCourseException, CourseDoesNotExistException, ReportTypeDoesNotExistException
-from .models import Order, PaidCourseRegistration, OrderItem
+from .exceptions import ItemAlreadyInCartException, AlreadyEnrolledInCourseException, CourseDoesNotExistException, ReportTypeDoesNotExistException, CouponAlreadyExistException, ItemDoesNotExistAgainstCouponException
+from .models import Order, PaidCourseRegistration, OrderItem, Coupon, CouponRedemption
 from .processors import process_postpay_callback, render_purchase_form_html
+import json
 
 log = logging.getLogger("shoppingcart")
 
@@ -69,6 +70,16 @@ def show_cart(request):
     cart = Order.get_cart_for_user(request.user)
     total_cost = cart.total_cost
     cart_items = cart.orderitem_set.all()
+
+    # add the request protocol, domain, and port to the cart object so that any specific
+    # CC_PROCESSOR implementation can construct callback URLs, if necessary
+    cart.context = {
+        'request_domain': '{0}://{1}'.format(
+            'https' if request.is_secure() else 'http',
+            request.get_host()
+        )
+    }
+
     form_html = render_purchase_form_html(cart)
     return render_to_response("shoppingcart/list.html",
                               {'shoppingcart_items': cart_items,
@@ -81,6 +92,11 @@ def show_cart(request):
 def clear_cart(request):
     cart = Order.get_cart_for_user(request.user)
     cart.clear()
+    coupon_redemption = CouponRedemption.objects.filter(user=request.user, order=cart.id)
+    if coupon_redemption:
+        coupon_redemption.delete()
+        log.info('Coupon redemption entry removed for user {0} for order {1}'.format(request.user, cart.id))
+
     return HttpResponse('Cleared')
 
 
@@ -90,12 +106,50 @@ def remove_item(request):
     try:
         item = OrderItem.objects.get(id=item_id, status='cart')
         if item.user == request.user:
+            order_item_course_id = None
+            if hasattr(item, 'paidcourseregistration'):
+                order_item_course_id = item.paidcourseregistration.course_id
             item.delete()
+            log.info('order item {0} removed for user {1}'.format(item_id, request.user))
+            try:
+                coupon_redemption = CouponRedemption.objects.get(user=request.user, order=item.order_id)
+                if order_item_course_id == coupon_redemption.coupon.course_id:
+                    coupon_redemption.delete()
+                    log.info('Coupon "{0}" redemption entry removed for user "{1}" for order item "{2}"'
+                             .format(coupon_redemption.coupon.code, request.user, item_id))
+            except CouponRedemption.DoesNotExist:
+                log.debug('Coupon redemption does not exist for order item id={0}.'.format(item_id))
     except OrderItem.DoesNotExist:
         log.exception('Cannot remove cart OrderItem id={0}. DoesNotExist or item is already purchased'.format(item_id))
     return HttpResponse('OK')
 
 
+@login_required
+def use_coupon(request):
+    """
+    This method generate discount against valid coupon code and save its entry into coupon redemption table
+    """
+    coupon_code = request.POST["coupon_code"]
+    try:
+        coupon = Coupon.objects.get(code=coupon_code)
+    except Coupon.DoesNotExist:
+        return HttpResponseNotFound(_("Discount does not exist against coupon '{0}'.".format(coupon_code)))
+
+    if coupon.is_active:
+        try:
+            cart = Order.get_cart_for_user(request.user)
+            CouponRedemption.add_coupon_redemption(coupon, cart)
+        except CouponAlreadyExistException:
+            return HttpResponseBadRequest(_("Coupon '{0}' already used.".format(coupon_code)))
+        except ItemDoesNotExistAgainstCouponException:
+            return HttpResponseNotFound(_("Coupon '{0}' is not valid for any course in the shopping cart.".format(coupon_code)))
+
+        response = HttpResponse(json.dumps({'response': 'success'}), content_type="application/json")
+        return response
+    else:
+        return HttpResponseBadRequest(_("Coupon '{0}' is inactive.".format(coupon_code)))
+
+
 @csrf_exempt
 @require_POST
 def postpay_callback(request):
@@ -122,6 +176,7 @@ def show_receipt(request, ordernum):
     Displays a receipt for a particular order.
     404 if order is not yet purchased or request.user != order.user
     """
+
     try:
         order = Order.objects.get(id=ordernum)
     except Order.DoesNotExist:
diff --git a/lms/static/sass/course/instructor/_instructor_2.scss b/lms/static/sass/course/instructor/_instructor_2.scss
index d1c3964d9330cb54deaca0a72af2d629cd67f6cd..76a491e1cd4669aea96fa737da5313f8a85f8ab1 100644
--- a/lms/static/sass/course/instructor/_instructor_2.scss
+++ b/lms/static/sass/course/instructor/_instructor_2.scss
@@ -597,7 +597,7 @@ section.instructor-dashboard-content-2 {
     float: left;
     clear: both;
     margin-top: 25px;
-  
+
     .metrics-left, .metrics-left-header {
       position: relative;
       width: 30%;
@@ -611,7 +611,7 @@ section.instructor-dashboard-content-2 {
     .metrics-section.metrics-left {
     	height: 640px;
     }
-    
+
     .metrics-right, .metrics-right-header {
       position: relative;
       width: 65%;
@@ -627,7 +627,7 @@ section.instructor-dashboard-content-2 {
     .metrics-section.metrics-right {
     	height: 295px;
     }
-          
+
     svg {
       .stacked-bar {
         cursor: pointer;
@@ -775,3 +775,267 @@ input[name="subject"] {
     font-weight: bold;
   }
 }
+
+.ecommerce-wrapper{
+  h2{
+    height: 26px;
+    line-height: 26px;
+    span{
+      float: right;
+      font-size: 16px;
+      font-weight: bold;
+      span{
+        background: #ddd;
+        padding: 2px 9px;
+        border-radius: 2px;
+        float: none;
+        font-weight: 400;
+      }
+    }
+  }
+  span.tip{
+    padding: 10px 15px;
+    display: block;
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    background: #f8f4ec;
+    color: #3c3c3c;
+    line-height: 30px;
+    .add{
+      @include button(simple, $blue);
+      @extend .button-reset;
+      font-size: em(13);
+      float: right;
+    }
+  }
+
+}
+#e-commerce{
+  .coupon-errors {
+    background: #FFEEF5;color:#B72667;text-align: center;padding: 10px 0px;
+    font-family: "Open Sans",Verdana,Geneva,sans-serif,sans-serif;font-size: 15px;
+    border-bottom: 1px solid #B72667;
+    margin-bottom: 20px;
+    display: none;
+    }
+  .content{
+    padding: 0 !important;
+  }
+  .coupons-table {
+    width: 100%;
+    tr:nth-child(even){
+        background-color: #f8f8f8;
+        border-bottom: 1px solid #f3f3f3;
+      }
+    tr.always-gray{
+      background: #eee !important;
+      border-top: 2px solid #FFFFFF;
+    }
+    tr.always-white{
+      background: #fff !important;
+      td{
+        padding: 30px 0px 10px;
+      }
+    }
+    .coupons-headings {
+      height: 40px;
+      border-bottom: 1px solid #BEBEBE;
+
+      th:nth-child(5){
+        text-align: center;
+        width: 120px;
+      }
+      th:first-child{
+        padding-left: 20px;
+      }
+      th {
+        text-align: left;
+        border-bottom: 1px solid $border-color-1;
+
+        &.c_code {
+          width: 170px;
+        }
+        &.c_count {
+          width: 85px;
+        }
+        &.c_course_id {
+          width: 320px;
+          word-wrap: break-word;
+        }
+        &.c_discount {
+          width: 90px;
+        }
+        &.c_action {
+          width: 89px;
+        }
+        &.c_dsc{
+          width: 260px;
+          word-wrap: break-word;
+        }
+      }
+    }
+
+    // in_active coupon rows style
+    .inactive_coupon{
+      background:  #FFF0F0 !important;
+      text-decoration: line-through;
+      color: rgba(51,51,51,0.2);
+      border-bottom: 1px solid #fff;
+      td {
+        a {
+          color:  rgba(51,51,51,0.2);
+        }
+      }
+    }
+
+    // coupon items style
+    .coupons-items {
+      td {
+        padding: 10px 0px;
+        position: relative;
+        line-height: normal;
+        span.old-price{
+          left: -75px;
+          position: relative;
+          text-decoration: line-through;
+          color: red;
+          font-size: 12px;
+          top: -1px;
+        }
+      }
+      td:nth-child(5),td:first-child{
+        padding-left: 20px;
+      }
+      td:nth-child(2){
+         line-height: 22px;
+        padding-right: 0px;
+        word-wrap: break-word;
+      }
+      td:nth-child(5){
+        padding-left: 0;
+        text-align: center;
+      }
+      td{
+        a.edit-right{
+          margin-left: 15px;
+        }
+      }
+    }
+  }
+
+  // coupon edit and add modals 
+  #add-coupon-modal, #edit-coupon-modal{
+    .inner-wrapper {
+      background: #fff;
+    }
+    top:-95px !important;
+    width: 650px;
+    margin-left: -325px;
+    border-radius: 2px;
+    input[type="submit"]#update_coupon_button{
+      @include button(simple, $blue);
+      @extend .button-reset;
+    }
+    input[type="submit"]#add_coupon_button{
+      @include button(simple, $blue);
+      @extend .button-reset;
+    }
+    .modal-form-error {
+      box-shadow: inset 0 -1px 2px 0 #f3d9db;
+      -webkit-box-sizing: border-box;
+      -moz-box-sizing: border-box;
+      box-sizing: border-box;
+      margin: 20px 0 10px 0 !important;
+      padding: 20px;
+      border: none;
+      border-bottom: 3px solid #a0050e;
+      background: #fbf2f3;
+    }
+    ol.list-input{
+      li{
+        width: 278px;
+        float: left;
+        label.required:after {
+          content: "*";
+          margin-left: 5px;
+        }
+      }
+      li:nth-child(even){
+        margin-left: 30px !important;
+      }
+      li:nth-child(3), li:nth-child(4){
+        margin-left: 0px !important;
+        width: 100%;
+      }
+      li:nth-child(3) {
+        margin-bottom: 0px !important;
+        textarea {
+          min-height: 100px;
+        }
+      }
+      li:last-child{
+        margin-bottom: 0px !important;
+      }
+
+    }
+    #coupon-content {
+      padding: 20px;
+      header {
+        margin: 0;
+        padding: 0;
+        h2 {
+          font-size: 24px;
+          font-weight: 100;
+          color: #1580b0;
+          text-align: left;
+        }
+      }
+      .instructions p {
+        margin-bottom: 5px;
+      }
+      form {
+        border-radius: 0;
+        box-shadow: none;
+        margin: 0;
+        border: none;
+        padding: 0;
+        .group-form {
+          margin: 0;
+          padding-top: 0;
+          padding-bottom: 20px;
+        }
+        .list-input {
+          margin: 0;
+          padding: 0;
+          list-style: none;
+        }
+        .readonly {
+          background-color: #eee !important;
+          color: #aaa;
+        }
+        .field {
+          margin: 0 0 20px 0;
+        }
+        .field.required label {
+          font-weight: 600;
+        }
+        .field label {
+          -webkit-transition: color 0.15s ease-in-out 0s;
+          -moz-transition: color 0.15s ease-in-out 0s;
+          transition: color 0.15s ease-in-out 0s;
+          margin: 0 0 5px 0;
+          color: #333;
+        }
+        .field.text input {
+          background: #fff;
+          margin-bottom: 0;
+        }
+        .field input {
+          width: 100%;
+          margin: 0;
+          padding: 10px 15px;
+        }
+      }
+    }
+  }
+}
diff --git a/lms/static/sass/views/_shoppingcart.scss b/lms/static/sass/views/_shoppingcart.scss
index 1b3da66893dfea5ac3303d5afab73460c4e38862..6c0808518142d0dc84c7b891596f191e1adef65e 100644
--- a/lms/static/sass/views/_shoppingcart.scss
+++ b/lms/static/sass/views/_shoppingcart.scss
@@ -12,14 +12,20 @@
   border: 1px solid $red;
 
 }
-
+.cart-errors{
+  background: #FFEEF5;color:#B72667;text-align: center;padding: 10px 0px;
+  font-family: "Open Sans",Verdana,Geneva,sans-serif,sans-serif;font-size: 15px;
+  border-bottom: 1px solid #B72667;
+  margin-bottom: 20px;
+  display: none;
+}
 .cart-list {
   padding: 30px;
   margin-top: 40px;
   border-radius: 3px;
   border: 1px solid $border-color-1;
   background-color: $action-primary-fg;
-  
+
   > h2 {
     font-size: 1.5em;
     color: $base-font-color;
@@ -27,13 +33,42 @@
   
   .cart-table {
     width: 100%;
-    
+    tr:nth-child(even){
+        background-color: #f8f8f8;
+        border-bottom: 1px solid #f3f3f3;
+      }
+    tr.always-gray{
+      background: #eee !important;
+      border-top: 2px solid #FFFFFF;
+    }
+    tr.always-white{
+      background: #fff !important;
+      td{
+        padding: 30px 0px 10px;
+      }
+    }
+    tr{
+        td.cart-total{
+            padding: 10px 0;
+            span{
+                display: inline-block;
+                margin-right: 15px;
+                margin-left: 15px;
+                font-weight: bold;
+              }
+        }
+
+    }
     .cart-headings {
       height: 35px;
-      
+      border-bottom: 1px solid #BEBEBE;
+
+      th:nth-child(5),th:first-child{
+        text-align: center;
+        width: 120px;
+      }
       th {
         text-align: left;
-        padding-left: 5px;
         border-bottom: 1px solid $border-color-1;
         
         &.qty {
@@ -48,12 +83,35 @@
         &.cur {
           width: 100px;
         }
+        &.dsc{
+          width: 640px;
+          padding-right: 50px;
+        }
       }
     }
     
     .cart-items {
       td {
-        padding: 10px 25px;
+        padding: 10px 0px;
+        position: relative;
+        line-height: normal;
+        span.old-price{
+          left: -75px;
+          position: relative;
+          text-decoration: line-through;
+          color: red;
+          font-size: 12px;
+          top: -1px;
+        }
+      }
+      td:nth-child(5),td:first-child{
+        text-align: center;
+
+
+      }
+      td:nth-child(2){
+         line-height: 22px;
+        padding-right: 50px;
       }
     }
     
@@ -64,6 +122,7 @@
           font-weight: bold;
           padding: 10px 25px;
         }
+
       }
     }
   }
@@ -80,11 +139,10 @@
     .items-ordered {
       padding-top: 50px;
     }
-    
+
     tr {
-      
     }
-    
+
     th {
       text-align: left;
       padding: 25px 0 15px 0;
@@ -105,6 +163,9 @@
     tr.order-item {
       td {
         padding-bottom: 10px;
+        span.old-price{
+          text-decoration: line-through !important;
+        }
       }
     }
   }
diff --git a/lms/templates/instructor/instructor_dashboard_2/add_coupon_modal.html b/lms/templates/instructor/instructor_dashboard_2/add_coupon_modal.html
new file mode 100644
index 0000000000000000000000000000000000000000..8befb90f109de7dfb6e47cfb5fad7b0342f28a8b
--- /dev/null
+++ b/lms/templates/instructor/instructor_dashboard_2/add_coupon_modal.html
@@ -0,0 +1,62 @@
+<%! from django.utils.translation import ugettext as _ %>
+<%! from django.core.urlresolvers import reverse %>
+<%page args="section_data"/>
+<section id="add-coupon-modal" class="modal" role="dialog" tabindex="-1" aria-label="${_('Password Reset')}">
+  <div class="inner-wrapper">
+    <button class="close-modal">
+      <i class="icon-remove"></i>
+      <span class="sr">
+        ## Translators: this is a control to allow users to exit out of this modal interface (a menu or piece of UI that takes the full focus of the screen)
+        ${_('Close')}
+      </span>
+    </button>
+
+    <div id="coupon-content">
+      <header>
+        <h2>${_("Add Coupon")}</h2>
+      </header>
+
+      <div class="instructions">
+        <p>
+          ${_("Please enter Coupon detail below")}</p>
+      </div>
+
+      <form id="add_coupon_form" action="${section_data['ajax_add_coupon']}" method="post" data-remote="true">
+        <div id="coupon_form_error" class="modal-form-error"></div>
+        <fieldset class="group group-form group-form-requiredinformation">
+          <legend class="is-hidden">${_("Required Information")}</legend>
+
+          <ol class="list-input">
+            <li class="field required text" id="add-coupon-modal-field-code">
+              <label for="coupon_code" class="required">${_("Code")}</label>
+              <input class="" id="coupon_code" type="text" name="code" maxlength="16" value="" placeholder="example: A123DS"
+                    aria-required="true"/>
+            </li>
+            <li class="field required text" id="add-coupon-modal-field-discount">
+              <label for="coupon_discount" class="required text">${_("Percentage Discount")}</label>
+              <input class="field required" id="coupon_discount" type="text" name="discount" value="" maxlength="5"
+                     aria-required="true"/>
+            </li>
+
+            <li class="field" id="add-coupon-modal-field-description">
+              <label for="coupon_description">${_("Description")}</label>
+              <textarea class="field" id="coupon_description" type="text" name="description" value=""
+                     aria-describedby="pwd_reset_email-tip" aria-required="true"> </textarea>
+            </li>
+
+            <li class="field" id="add-coupon-modal-field-course_id">
+              <label for="coupon_course_id">${_("Course ID")}</label>
+              <input class="field readonly" id="coupon_course_id" type="text" name="course_id" value="${section_data['course_id']}"
+                     readonly aria-required="true"/>
+            </li>
+
+          </ol>
+        </fieldset>
+
+        <div class="submit">
+          <input name="submit" type="submit" id="add_coupon_button" value="${_('Add Coupon')}"/>
+        </div>
+      </form>
+    </div>
+  </div>
+</section>
diff --git a/lms/templates/instructor/instructor_dashboard_2/e-commerce.html b/lms/templates/instructor/instructor_dashboard_2/e-commerce.html
new file mode 100644
index 0000000000000000000000000000000000000000..90ec854828490384a8f4d6ea8eec35de62a9b00c
--- /dev/null
+++ b/lms/templates/instructor/instructor_dashboard_2/e-commerce.html
@@ -0,0 +1,256 @@
+<%! from django.utils.translation import ugettext as _ %>
+<%page args="section_data"/>
+<%include file="add_coupon_modal.html" args="section_data=section_data" />
+<%include file="edit_coupon_modal.html" args="section_data=section_data" />
+
+<div class="ecommerce-wrapper">
+  <h2>${_("Coupons List")}
+      %if section_data['total_amount'] is not None:
+           <span>${_("Total Amount: ")}<span>$${section_data['total_amount']}</span></span>
+      %endif
+  </h2>
+
+  <h3 class="coupon-errors" id="coupon-error"></h3>
+  <span class="tip">${_("Coupons Information")} <a id="add_coupon_link" href="#add-coupon-modal" rel="leanModal"
+                                                   class="add blue-button">${_("+ Add Coupon")}</a></span>
+</div>
+<div class="wrapper-content wrapper">
+  <section class="content">
+    %if len(section_data['coupons']):
+    <table class="coupons-table">
+      <thead>
+      <tr class="coupons-headings">
+        <th class="c_code">${_("Code")}</th>
+        <th class="c_dsc">${_("Description")}</th>
+        <th class="c_course_id">${_("Course_id")}</th>
+        <th class="c_discount">${_("Discount(%)")}</th>
+        <th class="c_count">${_("Count")}</th>
+        <th class="c_action">${_("Actions")}</th>
+      </tr>
+      </thead>
+
+      <tbody>
+      %for coupon in section_data['coupons']:
+      %if coupon.is_active == False:
+      <tr class="coupons-items inactive_coupon">
+      %else:
+      <tr class="coupons-items">
+      %endif
+        <td>${coupon.code}</td>
+
+        <td>${coupon.description}</td>
+        <td>${coupon.course_id.to_deprecated_string()}</td>
+        <td>${coupon.percentage_discount}</td>
+        <td>
+           ${ coupon.couponredemption_set.all().count() }
+        </td>
+        <!--<td>${coupon.is_active}</td>-->
+        <td><a data-item-id="${coupon.id}" class='remove_coupon' href='#'>[x]</a><a href="#edit-modal" data-item-id="${coupon.id}" class="edit-right">Edit</a></td>
+      </tr>
+      %endfor
+      </tbody>
+    </table>
+    <a id="edit-modal-trigger" href="#edit-coupon-modal" rel="leanModal"></a>
+    %endif
+  </section>
+</div>
+
+
+<script>
+  $(function () {
+    $('a[rel*=leanModal]').leanModal();
+    $.each($("a.edit-right"), function () {
+      if ($(this).parent().parent('tr').hasClass('inactive_coupon')) {
+        $(this).removeAttr('href')
+      }
+    });
+    $.each($("a.remove_coupon"), function () {
+      if ($(this).parent().parent('tr').hasClass('inactive_coupon')) {
+        $(this).removeAttr('href')
+      }
+    });
+    $('a.edit-right').click(function (event) {
+      $('#edit_coupon_form #coupon_form_error').attr('style', 'display: none');
+      $('#edit_coupon_form #coupon_form_error').text();
+      event.preventDefault();
+      event.stopPropagation();
+      var coupon_id = $(this).data('item-id');
+      $('#coupon_id').val(coupon_id);
+      if ($(this).parent().parent('tr').hasClass('inactive_coupon')) {
+        return false;
+      }
+      $.ajax({
+        type: "POST",
+        data: {id: coupon_id},
+        url: "${section_data['ajax_get_coupon_info']}",
+        success: function (data) {
+            $('#coupon-error').val('');
+            $('#coupon-error').attr('style', 'display: none');
+            $('input#edit_coupon_code').val(data.coupon_code);
+            $('input#edit_coupon_discount').val(data.coupon_discount);
+            $('textarea#edit_coupon_description').val(data.coupon_description);
+            $('input#edit_coupon_course_id').val(data.coupon_course_id);
+            $('#edit-modal-trigger').click();
+          },
+        error: function(jqXHR, textStatus, errorThrown) {
+          var data = $.parseJSON(jqXHR.responseText);
+          $('#coupon-error').html(data.message).show();
+        }
+      });
+    });
+    $('a.remove_coupon').click(function (event) {
+      var anchor = $(this);
+      if (anchor.data("disabled")) {
+        return false;
+      }
+      anchor.data("disabled", "disabled");
+      event.preventDefault();
+      if ($(this).parent().parent('tr').hasClass('inactive_coupon')) {
+        return false;
+      }
+      $.ajax({
+        type: "POST",
+        data: {id: $(this).data('item-id')},
+        url: "${section_data['ajax_remove_coupon_url']}",
+        success: function (data) {
+            anchor.removeData("disabled");
+            location.reload(true);
+          },
+        error: function(jqXHR, textStatus, errorThrown) {
+          var data = $.parseJSON(jqXHR.responseText);
+          $('#coupon-error').html(data.message).show();
+          anchor.removeData("disabled");
+        }
+      });
+    });
+    $('#edit_coupon_form').submit(function () {
+      $("#update_coupon_button").attr('disabled', true);
+      // Get the Code and Discount value and trim it
+      var code = $.trim($('#edit_coupon_code').val());
+      var coupon_discount = $.trim($('#edit_coupon_discount').val());
+
+      // Check if empty of not
+      if (code === '') {
+        $('#edit_coupon_form #coupon_form_error').attr('style', 'display: block !important');
+        $('#edit_coupon_form #coupon_form_error').text("${_('Please Enter the Coupon Code')}");
+        $("#update_coupon_button").removeAttr('disabled');
+        return false;
+      }
+      if (coupon_discount == '0') {
+        $('#edit_coupon_form #coupon_form_error').attr('style', 'display: block !important');
+        $('#edit_coupon_form #coupon_form_error').text("${_('Please Enter the Value Greater than 0')}");
+        $("#update_coupon_button").removeAttr('disabled');
+        return false;
+      }
+      if (!$.isNumeric(coupon_discount)) {
+        $('#edit_coupon_form #coupon_form_error').attr('style', 'display: block !important');
+        $('#edit_coupon_form #coupon_form_error').text("${_('Please Enter the Coupon Discount Value Greater than 0')}");
+        $("#update_coupon_button").removeAttr('disabled');
+        return false;
+      }
+    });
+    $('#add_coupon_link').click(function () {
+      reset_input_fields();
+    });
+    $('#add_coupon_form').submit(function () {
+      $("#add_coupon_button").attr('disabled', true);
+      // Get the Code and Discount value and trim it
+      var code = $.trim($('#coupon_code').val());
+      var coupon_discount = $.trim($('#coupon_discount').val());
+
+      // Check if empty of not
+      if (code === '') {
+        $("#add_coupon_button").removeAttr('disabled');
+        $('#add_coupon_form #coupon_form_error').attr('style', 'display: block !important');
+        $('#add_coupon_form #coupon_form_error').text("${_('Please Enter the Coupon Code')}");
+        return false;
+      }
+      if (coupon_discount == '0') {
+        $('#add_coupon_form #coupon_form_error').attr('style', 'display: block !important');
+        $('#add_coupon_form #coupon_form_error').text("${_('Please Enter the Coupon Discount Value Greater than 0')}");
+        $("#add_coupon_button").removeAttr('disabled');
+        return false;
+      }
+      if (!$.isNumeric(coupon_discount)) {
+        $("#add_coupon_button").removeAttr('disabled');
+        $('#add_coupon_form #coupon_form_error').attr('style', 'display: block !important');
+        $('#add_coupon_form #coupon_form_error').text("${_('Please Enter the Numeric value for Discount')}");
+        return false;
+      }
+    });
+
+    $('#add_coupon_form').on('ajax:complete', function (event, xhr) {
+      if (xhr.status == 200) {
+        location.reload(true);
+      } else {
+        $("#add_coupon_button").removeAttr('disabled');
+        $('#add_coupon_form #coupon_form_error').attr('style', 'display: block !important');
+        $('#add_coupon_form #coupon_form_error').text(xhr.responseText);
+      }
+    });
+
+    $('#edit_coupon_form').on('ajax:complete', function (event, xhr) {
+      if (xhr.status == 200) {
+        location.reload(true);
+      } else {
+        $("#update_coupon_button").removeAttr('disabled');
+        $('#edit_coupon_form #coupon_form_error').attr('style', 'display: block !important');
+        $('#edit_coupon_form #coupon_form_error').text(xhr.responseText);
+      }
+    });
+    // removing close link's default behavior
+    $('.close-modal').click(function (e) {
+      $("#update_coupon_button").removeAttr('disabled');
+      $("#add_coupon_button").removeAttr('disabled');
+      reset_input_fields();
+      e.preventDefault();
+    });
+
+    var onModalClose = function () {
+      $("#add-coupon-modal").attr("aria-hidden", "true");
+      $(".remove_coupon").focus();
+      $("#edit-coupon-modal").attr("aria-hidden", "true");
+      $(".edit-right").focus();
+      $("#add_coupon_button").removeAttr('disabled');
+      $("#update_coupon_button").removeAttr('disabled');
+      reset_input_fields();
+    };
+
+    var cycle_modal_tab = function (from_element_name, to_element_name) {
+      $(from_element_name).on('keydown', function (e) {
+        var keyCode = e.keyCode || e.which;
+        var TAB_KEY = 9;  // 9 corresponds to the tab key
+        if (keyCode === TAB_KEY) {
+          e.preventDefault();
+          $(to_element_name).focus();
+        }
+      });
+    };
+
+    $("#add-coupon-modal .close-modal").click(onModalClose);
+    $("#edit-coupon-modal .close-modal").click(onModalClose);
+    $("#add-coupon-modal .close-modal").click(reset_input_fields);
+
+
+    // Hitting the ESC key will exit the modal
+    $("#add-coupon-modal, #edit-coupon-modal").on("keydown", function (e) {
+      var keyCode = e.keyCode || e.which;
+      // 27 is the ESC key
+      if (keyCode === 27) {
+        e.preventDefault();
+        $("#add-coupon-modal .close-modal").click();
+        $("#edit-coupon-modal .close-modal").click();
+      }
+    });
+  });
+  var reset_input_fields = function () {
+    $('#coupon-error').val('');
+    $('#coupon-error').attr('style', 'display: none');
+    $('#add_coupon_form #coupon_form_error').attr('style', 'display: none');
+    $('#add_coupon_form #coupon_form_error').text();
+    $('input#coupon_code').val('');
+    $('input#coupon_discount').val('');
+    $('textarea#coupon_description').val('');
+
+  }
+</script>
diff --git a/lms/templates/instructor/instructor_dashboard_2/edit_coupon_modal.html b/lms/templates/instructor/instructor_dashboard_2/edit_coupon_modal.html
new file mode 100644
index 0000000000000000000000000000000000000000..2d292abf129a8118e991a20078a31e84d11a1d0e
--- /dev/null
+++ b/lms/templates/instructor/instructor_dashboard_2/edit_coupon_modal.html
@@ -0,0 +1,63 @@
+<%! from django.utils.translation import ugettext as _ %>
+<%! from django.core.urlresolvers import reverse %>
+<%page args="section_data"/>
+<section id="edit-coupon-modal" class="modal" role="dialog" tabindex="-1" aria-label="${_('Edit Coupon')}">
+  <div class="inner-wrapper">
+    <button class="close-modal">
+      <i class="icon-remove"></i>
+      <span class="sr">
+        ## Translators: this is a control to allow users to exit out of this modal interface (a menu or piece of UI that takes the full focus of the screen)
+        ${_('Close')}
+      </span>
+    </button>
+
+    <div id="coupon-content">
+      <header>
+        <h2>${_("Update Coupon")}</h2>
+      </header>
+
+      <div class="instructions">
+        <p>
+          ${_("Update Coupon Information")}</p>
+      </div>
+
+      <form id="edit_coupon_form" action="${section_data['ajax_update_coupon']}" method="post" data-remote="true">
+        <div id="coupon_form_error" class="modal-form-error"></div>
+        <fieldset class="group group-form group-form-requiredinformation">
+          <legend class="is-hidden">${_("Required Information")}</legend>
+
+          <ol class="list-input">
+            <li class="field required text" id="edit-coupon-modal-field-code">
+              <label for="edit_coupon_code" class="required">${_("Code")}</label>
+              <input class="field" id="edit_coupon_code" type="text" name="code" maxlength="16" value="" placeholder="example: A123DS"
+                    aria-required="true"/>
+            </li>
+            <li class="field required text" id="edit-coupon-modal-field-discount">
+              <label for="edit_coupon_discount" class="required">${_("Percentage Discount")}</label>
+              <input class="field" id="edit_coupon_discount" type="text" name="discount" value="" maxlength="5"
+                     aria-required="true"/>
+            </li>
+
+            <li class="field" id="edit-coupon-modal-field-description">
+              <label for="edit_coupon_description">${_("Description")}</label>
+              <textarea class="field" id="edit_coupon_description" type="text" name="description" value=""
+                    aria-required="true"></textarea>
+            </li>
+
+            <li class="field" id="edit-coupon-modal-field-course_id">
+              <label for="edit_coupon_course_id">${_("Course ID")}</label>
+              <input class="field readonly" id="edit_coupon_course_id" type="text" name="course_id" value=""
+                     readonly aria-required="true"/>
+            </li>
+
+          </ol>
+        </fieldset>
+
+        <div class="submit">
+          <input type="hidden" name="coupon_id" id="coupon_id"/>
+          <input name="submit" type="submit" id="update_coupon_button" value="${_('Update Coupon')}"/>
+        </div>
+      </form>
+    </div>
+  </div>
+</section>
diff --git a/lms/templates/shoppingcart/cybersource_form.html b/lms/templates/shoppingcart/cybersource_form.html
index b29ea79aa167bcc6e51ece152f25dcf5f49f56e9..b07af57ab7d24d6088926dd617962cd4638a0998 100644
--- a/lms/templates/shoppingcart/cybersource_form.html
+++ b/lms/templates/shoppingcart/cybersource_form.html
@@ -2,5 +2,6 @@
             % for pk, pv in params.iteritems():
                 <input type="hidden" name="${pk}" value="${pv}" />
             % endfor
+
                 <input type="submit" value="Check Out" />
-        </form>
+        </form> 
\ No newline at end of file
diff --git a/lms/templates/shoppingcart/list.html b/lms/templates/shoppingcart/list.html
index 89eeb0d1ccf9c78fda2573c99b8949a059157223..060a813c7edb8fb120f4750da0b01275c71ee2a2 100644
--- a/lms/templates/shoppingcart/list.html
+++ b/lms/templates/shoppingcart/list.html
@@ -8,6 +8,7 @@
 
 <section class="container cart-list">
   <h2>${_("Your selected items:")}</h2>
+    <h3 class="cart-errors" id="cart-error">Error goes here.</h3>
   % if shoppingcart_items:
     <table class="cart-table">
       <thead>
@@ -24,24 +25,39 @@
         <tr class="cart-items">
           <td>${item.qty}</td>
           <td>${item.line_desc}</td>
-          <td>${"{0:0.2f}".format(item.unit_cost)}</td>
+          <td>
+              ${"{0:0.2f}".format(item.unit_cost)}
+              % if item.list_price != None:
+                <span class="old-price"> ${"{0:0.2f}".format(item.list_price)}</span>
+              % endif
+          </td>
           <td>${"{0:0.2f}".format(item.line_cost)}</td>
           <td>${item.currency.upper()}</td>
           <td><a data-item-id="${item.id}" class='remove_line_item' href='#'>[x]</a></td>
         </tr>
         % endfor
-        <tr class="cart-headings">
-          <td colspan="4"></td>
-          <th>${_("Total Amount")}</th>
-        </tr>
-        <tr class="cart-totals">
-          <td colspan="4"></td>
-          <td class="cart-total-cost">${"{0:0.2f}".format(amount)}</td>
+        <tr class="always-gray">
+          <td colspan="3"></td>
+            <td colspan="3" valign="middle" class="cart-total" align="right">
+                <b>${_("Total Amount")}: <span> ${"{0:0.2f}".format(amount)} </span> </b>
+            </td>
         </tr>
+
       </tbody>
+      <tfoot>
+        <tr class="always-white">
+            <td colspan="2">
+                 <input type="text" placeholder="Enter coupon code here" name="coupon_code" id="couponCode">
+                 <input type="button" value="Use Coupon" id="cart-coupon">
+            </td>
+            <td colspan="4" align="right">
+                ${form_html}
+            </td>
+        </tr>
+
+      </tfoot>
     </table>
     <!-- <input id="back_input" type="submit" value="Return" /> -->
-    ${form_html}
   % else:
     <p>${_("You have selected no items for purchase.")}</p>
   % endif
@@ -60,9 +76,39 @@
       });
     });
 
+    $('#cart-coupon').click(function(event){
+      event.preventDefault();
+      var post_url = "${reverse('shoppingcart.views.use_coupon')}";
+      $.post(post_url,{
+               "coupon_code" :  $('#couponCode').val(),
+                beforeSend: function(xhr, options){
+                 if($('#couponCode').val() == "") {
+                     showErrorMsgs('Must contain a valid coupon code')
+                     xhr.abort();
+                    }
+                }
+               }
+      )
+      .success(function(data) {
+                 location.reload(true);
+              })
+      .error(function(data,status) {
+                  if(status=="parsererror"){
+                       location.reload(true);
+                  }else{
+                        showErrorMsgs(data.responseText)
+                      }
+             })
+    });
+
     $('#back_input').click(function(){
       history.back();
     });
+
+    function showErrorMsgs(msg){
+        $(".cart-errors").css('display', 'block');
+        $("#cart-error").html(msg);
+    }
   });
 </script>
 
diff --git a/lms/templates/shoppingcart/receipt.html b/lms/templates/shoppingcart/receipt.html
index 4ff99a9f7e12582e1547844cc9485cb6313645cf..81da34c0725f197f84300ec42adf2403c21e89a0 100644
--- a/lms/templates/shoppingcart/receipt.html
+++ b/lms/templates/shoppingcart/receipt.html
@@ -3,6 +3,7 @@
 <%! from django.conf import settings %>
 
 <%inherit file="../main.html" />
+
 <%block name="bodyclass">purchase-receipt</%block>
 
 <%block name="pagetitle">${_("Register for [Course Name] | Receipt (Order")} ${order.id})</%block>
@@ -37,16 +38,25 @@
           <tr>
             <th class="qty">${_("Qty")}</th>
             <th class="desc">${_("Description")}</th>
+            <th class="url">${_("URL")}</th>
             <th class="u-pr">${_("Unit Price")}</th>
             <th class="pri">${_("Price")}</th>
             <th class="curr">${_("Currency")}</th>
           </tr>
           % for item in order_items:
+
+            <% course_id = reverse('info', args=[item.course_id.to_deprecated_string()]) %>
+
             <tr class="order-item">
               % if item.status == "purchased":
                 <td>${item.qty}</td>
                 <td>${item.line_desc}</td>
-                <td>${"{0:0.2f}".format(item.unit_cost)}</td>
+                <td><a href="${course_id}" class="enter-course">${_('View Course')}</a></td>
+                <td>${"{0:0.2f}".format(item.unit_cost)}
+                    % if item.list_price != None:
+                        <span class="old-price"> ${"{0:0.2f}".format(item.list_price)}</span>
+                    % endif
+                    </td>
                 <td>${"{0:0.2f}".format(item.line_cost)}</td>
                 <td>${item.currency.upper()}</td></tr>
               % elif item.status == "refunded":
diff --git a/lms/urls.py b/lms/urls.py
index a112daea5be91dc94cbc353131fbb1b47dbb4a3d..49465863163c13a5b5f603fc867400352f087414 100644
--- a/lms/urls.py
+++ b/lms/urls.py
@@ -283,6 +283,14 @@ if settings.COURSEWARE_ENABLED:
             'instructor.views.instructor_dashboard.instructor_dashboard_2', name="instructor_dashboard"),
         url(r'^courses/{}/instructor/api/'.format(settings.COURSE_ID_PATTERN),
             include('instructor.views.api_urls')),
+        url(r'^courses/{}/remove_coupon$'.format(settings.COURSE_ID_PATTERN),
+            'instructor.views.coupons.remove_coupon', name="remove_coupon"),
+        url(r'^courses/{}/add_coupon$'.format(settings.COURSE_ID_PATTERN),
+            'instructor.views.coupons.add_coupon', name="add_coupon"),
+        url(r'^courses/{}/update_coupon$'.format(settings.COURSE_ID_PATTERN),
+            'instructor.views.coupons.update_coupon', name="update_coupon"),
+        url(r'^courses/{}/get_coupon_info$'.format(settings.COURSE_ID_PATTERN),
+            'instructor.views.coupons.get_coupon_info', name="get_coupon_info"),
 
         # see ENABLE_INSTRUCTOR_LEGACY_DASHBOARD section for legacy dash urls