openedx.features.discounts package

Contents

openedx.features.discounts package#

Submodules#

openedx.features.discounts.applicability module#

Contains code related to computing discount percentage and discount applicability.

WARNING: Keep in mind that the code in this file only applies to discounts controlled in the lms like the first purchase offer, not other discounts like coupons or enterprise/program offers configured in ecommerce.

openedx.features.discounts.applicability.can_receive_discount(user, course, discount_expiration_date=None)#

Check all the business logic about whether this combination of user and course can receive a discount.

openedx.features.discounts.applicability.can_show_streak_discount_coupon(user, course)#

Check whether this combination of user and course can receive the streak discount.

openedx.features.discounts.applicability.discount_percentage(course)#

Get the configured discount amount.

openedx.features.discounts.applicability.get_discount_expiration_date(user, course)#

Returns the date when the discount expires for the user. Returns none if the user is not enrolled.

openedx.features.discounts.apps module#

Discounts application configuration

class openedx.features.discounts.apps.DiscountsConfig(app_name, app_module)#

Bases: AppConfig

name = 'openedx.features.discounts'#

openedx.features.discounts.models module#

DiscountRestrictionConfig Models

class openedx.features.discounts.models.DiscountPercentageConfig(*args, **kwargs)#

Bases: StackedConfigurationModel

A ConfigurationModel to configure the discount percentage for the first purchase discount

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

STACKABLE_FIELDS = ('percentage',)#
change_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

changed_by#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

changed_by_id#
course#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

course_id#
enabled#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_change_date(*, field=<django.db.models.fields.DateTimeField: change_date>, is_next=True, **kwargs)#
get_previous_by_change_date(*, field=<django.db.models.fields.DateTimeField: change_date>, is_next=False, **kwargs)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

org#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

org_course#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

percentage#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

site#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

site_id#
class openedx.features.discounts.models.DiscountRestrictionConfig(*args, **kwargs)#

Bases: StackedConfigurationModel

A ConfigurationModel used to manage restrictons for lms-controlled discounts

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

STACKABLE_FIELDS = ('disabled',)#
change_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

changed_by#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

changed_by_id#
course#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

course_id#
disabled#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

classmethod disabled_for_course_stacked_config(course)#

Return whether lms-controlled discounts are disabled for this course. Checks if discounts are disabled for attributes of this course like Site, Partner, Course or Course Run.

Parameters:

course – The CourseOverview of the course being queried.

enabled#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_change_date(*, field=<django.db.models.fields.DateTimeField: change_date>, is_next=True, **kwargs)#
get_previous_by_change_date(*, field=<django.db.models.fields.DateTimeField: change_date>, is_next=False, **kwargs)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

org#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

org_course#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

site#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

site_id#

openedx.features.discounts.urls module#

Discount API URLs

openedx.features.discounts.utils module#

Utility functions for working with discounts and discounted pricing.

openedx.features.discounts.utils.format_strikeout_price(user, course)#
Return a formatted price, including a struck-out original price if a discount applies, and also

whether a discount was applied, as the tuple (formatted_price, has_discount).

openedx.features.discounts.utils.generate_offer_data(user, course)#

Create a dictionary of information about the current discount offer.

Used by serializers to pass onto frontends and by the LMS locally to generate HTML for template rendering.

Returns a dictionary of data, or None if no offer is applicable.

openedx.features.discounts.utils.offer_banner_wrapper(user, block, view, frag, context)#

A wrapper that prepends the First Purchase Discount banner if the user hasn’t upgraded yet.

openedx.features.discounts.views module#

The Discount API Views should return information about discounts that apply to the user and course.

class openedx.features.discounts.views.CourseUserDiscount(**kwargs)#

Bases: DeveloperErrorViewMixin, APIView

Use Cases

Request discount information for a user and course

Example Requests

GET /api/discounts/course/{course_key_string}

Response Values

Body consists of the following fields:
discount_applicable:

whether the user can receive a discount for this course

jwt:

the jwt with user information and discount information

Parameters:

course_key_string:

The course key for which the discount should be applied

Returns

  • 200 on success with above fields.

  • 401 if there is no user signed in.

Example response: {

“discount_applicable”: false, “jwt”: xxxxxxxx.xxxxxxxx.xxxxxxx

}

authentication_classes = (<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'openedx.core.lib.api.authentication.BearerAuthenticationAllowInactiveUser'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>)#
get(request, course_key_string)#

Return the discount percent, if the user has appropriate permissions.

permission_classes = (<class 'openedx.core.lib.api.permissions.ApiKeyHeaderPermissionIsAuthenticated'>,)#
class openedx.features.discounts.views.CourseUserDiscountWithUserParam(**kwargs)#

Bases: DeveloperErrorViewMixin, APIView

DO NOT USE

This should not be used for anything other than getting the course/user discount information from ecommerce after payment in order to build an order. We plan to build orders before payment in this ticket: REV-692, at which point, this endpoint will no longer be necessary and should be removed.

Use Cases

Request discount information for a user and course

Example Requests

GET /api/discounts/user/{user_id}/course/{course_key_string}

Response Values

Body consists of the following fields:
discount_applicable:

whether the user can receive a discount for this course

jwt:

the jwt with user information and discount information

Parameters:

course_key_string:

The course key for which the discount should be applied

user_id

The user id for which the discount should be applied

Returns

  • 200 on success with above fields.

Example response: {

“discount_applicable”: false, “jwt”: xxxxxxxx.xxxxxxxx.xxxxxxx

}

authentication_classes = (<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'openedx.core.lib.api.authentication.BearerAuthenticationAllowInactiveUser'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>)#
get(request, course_key_string, user_id)#

Return the discount percent, if the user has appropriate permissions.

permission_classes = (<class 'openedx.core.lib.api.permissions.ApiKeyHeaderPermissionIsAuthenticated'>, <class 'rest_framework.permissions.IsAdminUser'>)#

Module contents#

Discounts are determined by a combination of user and course, and have a one to one relationship with the enrollment (if already enrolled) or a join table of user and course. They are determined in LMS, because all of the data for the business rules exists here. Discount rules are meant to be permanent.