171 lines
6.5 KiB
Python
171 lines
6.5 KiB
Python
"""
|
|
The Discount API Views should return information about discounts that apply to the user and course.
|
|
|
|
"""
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
import logging
|
|
|
|
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
|
from django.utils.decorators import method_decorator
|
|
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
|
|
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
|
|
from opaque_keys.edx.keys import CourseKey
|
|
from rest_framework.permissions import IsAdminUser
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
from lms.djangoapps.experiments.models import ExperimentData
|
|
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
|
from openedx.core.djangoapps.cors_csrf.decorators import ensure_csrf_cookie_cross_domain
|
|
from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user
|
|
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
|
|
from openedx.core.lib.api.permissions import ApiKeyHeaderPermissionIsAuthenticated
|
|
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin
|
|
|
|
from .applicability import can_receive_discount, discount_percentage, REV1008_EXPERIMENT_ID
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class CourseUserDiscount(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 = (JwtAuthentication, BearerAuthenticationAllowInactiveUser,
|
|
SessionAuthenticationAllowInactiveUser,)
|
|
permission_classes = (ApiKeyHeaderPermissionIsAuthenticated,)
|
|
|
|
# Since the course about page on the marketing site uses this API to auto-enroll users,
|
|
# we need to support cross-domain CSRF.
|
|
@method_decorator(ensure_csrf_cookie_cross_domain)
|
|
def get(self, request, course_key_string):
|
|
"""
|
|
Return the discount percent, if the user has appropriate permissions.
|
|
"""
|
|
course_key = CourseKey.from_string(course_key_string)
|
|
course = CourseOverview.get_from_id(course_key)
|
|
discount_applicable = can_receive_discount(user=request.user, course=course)
|
|
discount_percent = discount_percentage(course)
|
|
payload = {'discount_applicable': discount_applicable, 'discount_percent': discount_percent}
|
|
|
|
# Record whether the last basket loaded for this course had a discount
|
|
try:
|
|
ExperimentData.objects.update_or_create(
|
|
user=request.user,
|
|
experiment_id=REV1008_EXPERIMENT_ID,
|
|
key='discount_' + str(course),
|
|
value=discount_applicable
|
|
)
|
|
except Exception as e: # pylint: disable=broad-except
|
|
log.exception(str(e))
|
|
|
|
return Response({
|
|
'discount_applicable': discount_applicable,
|
|
'jwt': create_jwt_for_user(request.user, additional_claims=payload)})
|
|
|
|
|
|
class CourseUserDiscountWithUserParam(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 = (JwtAuthentication, BearerAuthenticationAllowInactiveUser,
|
|
SessionAuthenticationAllowInactiveUser,)
|
|
permission_classes = (ApiKeyHeaderPermissionIsAuthenticated, IsAdminUser)
|
|
|
|
# Since the course about page on the marketing site uses this API to auto-enroll users,
|
|
# we need to support cross-domain CSRF.
|
|
@method_decorator(ensure_csrf_cookie_cross_domain)
|
|
def get(self, request, course_key_string, user_id):
|
|
"""
|
|
Return the discount percent, if the user has appropriate permissions.
|
|
"""
|
|
course_key = CourseKey.from_string(course_key_string)
|
|
course = CourseOverview.get_from_id(course_key)
|
|
user = User.objects.get(id=user_id)
|
|
# Below code in try/except is temporarily replacing this call
|
|
# discount_applicable = can_receive_discount(user=user, course=course)
|
|
# Only show a discount on the order if the last basket loaded for this course had a discount
|
|
# Do not check any of the discount requirements
|
|
try:
|
|
discount_applicable = ExperimentData.objects.get(
|
|
user=user, experiment_id=REV1008_EXPERIMENT_ID, key='discount_' + str(course)
|
|
).value == 'True'
|
|
except ExperimentData.DoesNotExist:
|
|
discount_applicable = False
|
|
|
|
discount_percent = discount_percentage(course)
|
|
payload = {'discount_applicable': discount_applicable, 'discount_percent': discount_percent}
|
|
|
|
return Response({
|
|
'discount_applicable': discount_applicable,
|
|
'jwt': create_jwt_for_user(request.user, additional_claims=payload)})
|