Table of Contents
Overview
The ability to generate enrollment and discount codes for courses currently exists on edX white label sites with the use of the shoppingcart module. There is now the need to transition this functionality to Otto (the ecommerce module currently used on edx.org).
...
The requirements for this work have been outlined in Enrollment & Discount Codes on edX.org v1.0. The new requirements are far greater than what is currently implemented in the white label offering so we will use a phased approach to accomplish all of the goals.
...
This document will outline the technical approach to enable these features.
A list of use cases has also been outlined and the following approach satisfies them as well as sets us up to enhance the functionality to support financial aid as well as gift cards in the future.
...
Establish a new product class. An order will be created with line items of this class. This class can handle a catalog of courses and if a single course is chosen a catalog will be created with the single course.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
class Migration(migrations.Migration): dependencies = [ ('catalogue', '0010_catalog'), ] operations = [ migrations.AddField( model_name='catalog', name='enrollment_code', field=models.ForeignKey(related_name='enrollment_codes', blank=True, to='catalogue.ProductClass', null=True), ), ] |
...
This new class will allow us to attach a client to an order of enrollment codes. We create this new class to separate clients from self service users.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
class Client(core.User): (an oscar user is a django user) pass |
Enrollment Code Invoice Payment Processor
...
A new fulfillment module will be created that will be responsible for creating enrollment codes for each line item in the order. We will create a new model to hold the codes.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
class EnrollmentCode(models.Model): date_created = models.DateField(auto_now_add=True) voucher[] = ManyToMany(Voucher.voucher) order_line_id = ForeignKey(Line.line) |
...
We need to extend the default Range of products to allow for a link to a catalog that will be created for the chosen courses. A Range is used to create an oscar Voucher that applies to a range of products.
Code Block | ||||
---|---|---|---|---|
| ||||
class Range(AbstractRange): catalog_id = ForeignKey(Catalog.catalog) |
Enrollment Code List View
Since enrollment codes are actual orders, the list view will be sorted by clients orders. The order details could then be viewed and therefore all the enrollment codes for that order would be displayed.
Discount Code Creation
SInce Discount Codes are not a product we will create them right from the management UI.
...
Validate discount code fields.
Create a catalog for selected courses
Create Client (if not already created)
Create a DiscountCode object
Create voucher of the desired discount
...
Endpoints
The following API endpoints will be implemented: These endpoints will be implemented using DRF.
url(r'^/actions/create_enrollment_code_order/$', views.EnrollmentCodeCreateView.as_view(), name='create_enrollment_code_order')
This endpoint is for creating new enrollment codes. The payload is a client id along with the courses that this code is associated with. The details of the code are also included, namely the dates and where or not the code is single or multi use and the number of codes to generate.
...
In order to redeem an enrollment code.
url(r'^enrollment_codes/<code>/redeem/$', 'register_code_redemption', name='register_code_redemption')
Code Block | ||||
---|---|---|---|---|
| ||||
GET Body: data = Empty response: 200 code redeemed response.json same as above response 400 Error in data provided |
...
The endpoint for creating a discount code will be an action that takes the details needed for a code. Creation of the discount code will be done and fulfilled immediately since this is not an order.
url(r'^/actions/create_discount_code/$', views.DiscountCodeCreateView.as_view(), name='create_discount_code')
Example:
Code Block | ||||
---|---|---|---|---|
| ||||
POST Body: data = { 'client_id': 1, 'stock_record_id': [1,2,3,4], 'start_date': “2015-01-01T00:00:00Z”, 'end_date': “2015-01-01T00:00:00Z”, 'type': multiple ‘fixed’: true | false ‘amount’ : amount ‘code’ : code } response: 200 Success response.json {"discount code" : "EDX-1234"} 400 Error in data provided 401 Unauthorized 403 No Permissions |
...
Endpoint to return the list of clients:
url(r'^/clients/$', views.ClientView.as_view(), name=”clients”)
Code Block | ||||
---|---|---|---|---|
| ||||
GET Body: data = Empty Response: 200 Clients response.json data = { ‘clients’: [{“name”: client, “email”: email}, {“name”: client, “email”: email},] } 400 Error in data provided 401 Unauthorized |
...