Commit b8e48146 by Simon Chen Committed by GitHub

Merge pull request #15811 from edx/schen/LEARNER-2222

Stop audit and honor mode creating basket and order
parents e1ad295a 893b7a00
......@@ -15,7 +15,7 @@ from django.test.utils import override_settings
from edx_rest_api_client import exceptions
from nose.plugins.attrib import attr
from commerce.api.v0.views import SAILTHRU_CAMPAIGN_COOKIE
from commerce.api.v0.views import SAILTHRU_CAMPAIGN_COOKIE, STOP_BASKET_CREATION_FLAG
from commerce.constants import Messages
from commerce.tests import TEST_BASKET_ID, TEST_ORDER_NUMBER, TEST_PAYMENT_DATA
from commerce.tests.mocks import mock_basket_order, mock_create_basket
......@@ -23,6 +23,7 @@ from commerce.tests.test_views import UserMixin
from course_modes.models import CourseMode
from enrollment.api import get_enrollment
from openedx.core.djangoapps.embargo.test_utils import restrict_course
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
from openedx.core.lib.django_test_client_utils import get_absolute_url
from student.models import CourseEnrollment
from student.tests.factories import CourseModeFactory
......@@ -192,6 +193,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
cookie_name=UTM_COOKIE_NAME, cookie_contents=json.dumps(UTM_COOKIE_CONTENTS))
self.assertIn(cookie_string, httpretty.last_request().headers['cookie'])
@override_waffle_flag(STOP_BASKET_CREATION_FLAG, active=False)
@ddt.data(True, False)
def test_course_with_honor_seat_sku(self, user_is_active):
"""
......@@ -214,6 +216,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
# Test that call with cookie passes cookie along
self._test_successful_ecommerce_api_call(utm_tracking_present=True)
@override_waffle_flag(STOP_BASKET_CREATION_FLAG, active=False)
@ddt.data(True, False)
def test_course_with_paid_seat_sku(self, user_is_active):
"""
......@@ -228,6 +231,27 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
with mock_create_basket(response=return_value):
self._test_successful_ecommerce_api_call(is_completed=False)
@override_waffle_flag(STOP_BASKET_CREATION_FLAG, active=True)
@ddt.data(True, False)
def test_course_without_creating_order(self, user_is_active):
"""
If the course has a SKU, and the STOP_BASKET_CREATION waffle flag is on,
the enrollment should happen without contacting ecommerce api
"""
# Set user's active flag
self.user.is_active = user_is_active
self.user.save() # pylint: disable=no-member
with mock_create_basket(expect_called=False):
response = self._post_to_view()
# Validate the response content
self.assertEqual(response.status_code, 200)
msg = Messages.ENROLL_DIRECTLY.format(
course_id=self.course.id,
username=self.user.username
)
self.assertResponseMessage(response, msg)
def _test_course_without_sku(self, enrollment_mode=CourseMode.DEFAULT_MODE_SLUG):
"""
Validates the view bypasses the E-Commerce API when the course has no CourseModes with SKUs.
......
......@@ -13,6 +13,7 @@ from rest_framework.views import APIView
from commerce.constants import Messages
from commerce.exceptions import InvalidResponseError
from commerce.http import DetailResponse, InternalRequestErrorResponse
from commerce.utils import COMMERCE_API_WAFFLE_FLAG_NAMESPACE
from course_modes.models import CourseMode
from courseware import courses
from enrollment.api import add_enrollment
......@@ -20,6 +21,7 @@ from enrollment.views import EnrollmentCrossDomainSessionAuth
from openedx.core.djangoapps.commerce.utils import ecommerce_api_client
from openedx.core.djangoapps.embargo import api as embargo_api
from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in
from openedx.core.djangoapps.waffle_utils import WaffleFlag
from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser
from openedx.core.lib.log_utils import audit_log
from student.models import CourseEnrollment, RegistrationCookieConfiguration
......@@ -27,6 +29,7 @@ from util.json_request import JsonResponse
log = logging.getLogger(__name__)
SAILTHRU_CAMPAIGN_COOKIE = 'sailthru_bid'
STOP_BASKET_CREATION_FLAG = WaffleFlag(COMMERCE_API_WAFFLE_FLAG_NAMESPACE, 'stop_basket_creation')
class BasketsView(APIView):
......@@ -82,7 +85,7 @@ class BasketsView(APIView):
def post(self, request, *args, **kwargs):
"""
Attempt to create the basket and enroll the user.
Attempt to enroll the user, and if needed, create the basket.
"""
user = request.user
valid, course_key, error = self._is_data_valid(request)
......@@ -121,26 +124,49 @@ class BasketsView(APIView):
if not default_enrollment_mode:
msg = Messages.NO_DEFAULT_ENROLLMENT_MODE.format(course_id=course_id)
return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE)
elif default_enrollment_mode and not default_enrollment_mode.sku:
# If there are no course modes with SKUs, enroll the user without contacting the external API.
msg = Messages.NO_SKU_ENROLLED.format(
enrollment_mode=default_enrollment_mode.slug,
course_id=course_id,
username=user.username
elif not default_enrollment_mode.sku or STOP_BASKET_CREATION_FLAG.is_enabled():
msg = Messages.ENROLL_DIRECTLY.format(
username=user.username,
course_id=course_id
)
if not default_enrollment_mode.sku:
# If there are no course modes with SKUs, return a different message.
msg = Messages.NO_SKU_ENROLLED.format(
enrollment_mode=default_enrollment_mode.slug,
course_id=course_id,
username=user.username
)
log.info(msg)
self._enroll(course_key, user, default_enrollment_mode.slug)
self._handle_marketing_opt_in(request, course_key, user)
return DetailResponse(msg)
else:
return self._create_basket_to_order(request, user, course_key, default_enrollment_mode)
# Setup the API
def _add_request_cookie_to_api_session(self, server_session, request, cookie_name):
""" Add cookie from user request into server session """
user_cookie = None
if cookie_name:
user_cookie = request.COOKIES.get(cookie_name)
if user_cookie:
server_cookie = {cookie_name: user_cookie}
if server_session.cookies:
requests.utils.add_dict_to_cookiejar(server_session.cookies, server_cookie)
else:
server_session.cookies = requests.utils.cookiejar_from_dict(server_cookie)
def _create_basket_to_order(self, request, user, course_key, default_enrollment_mode):
"""
Connect to the ecommerce service to create the basket and the order to do the enrollment
"""
# Setup the API
course_id = unicode(course_key)
try:
api_session = requests.Session()
api = ecommerce_api_client(user, session=api_session)
except ValueError:
self._enroll(course_key, user)
msg = Messages.NO_ECOM_API.format(username=user.username, course_id=unicode(course_key))
msg = Messages.NO_ECOM_API.format(username=user.username, course_id=course_id)
log.debug(msg)
return DetailResponse(msg)
......@@ -191,18 +217,6 @@ class BasketsView(APIView):
self._handle_marketing_opt_in(request, course_key, user)
return response
def _add_request_cookie_to_api_session(self, server_session, request, cookie_name):
""" Add cookie from user request into server session """
user_cookie = None
if cookie_name:
user_cookie = request.COOKIES.get(cookie_name)
if user_cookie:
server_cookie = {cookie_name: user_cookie}
if server_session.cookies:
requests.utils.add_dict_to_cookiejar(server_session.cookies, server_cookie)
else:
server_session.cookies = requests.utils.cookiejar_from_dict(server_cookie)
class BasketOrderView(APIView):
""" Retrieve the order associated with a basket. """
......
......@@ -12,6 +12,7 @@ class Messages(object):
""" Strings used to populate response messages. """
NO_ECOM_API = u'E-Commerce API not setup. Enrolled {username} in {course_id} directly.'
NO_SKU_ENROLLED = u'The {enrollment_mode} mode for {course_id} does not have a SKU. Enrolling {username} directly.'
ENROLL_DIRECTLY = u'Enroll {username} in {course_id} directly because no need for E-Commerce baskets and orders.'
ORDER_COMPLETED = u'Order {order_number} was completed.'
ORDER_INCOMPLETE_ENROLLED = u'Order {order_number} was created, but is not yet complete. User was enrolled.'
NO_HONOR_MODE = u'Course {course_id} does not have an honor mode.'
......
......@@ -7,6 +7,9 @@ from django.conf import settings
from commerce.models import CommerceConfiguration
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.waffle_utils import WaffleFlagNamespace
COMMERCE_API_WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='commerce_api')
def is_account_activation_requirement_disabled():
......
......@@ -208,7 +208,7 @@ class WaffleFlagNamespace(WaffleNamespace):
"""
# validate arguments
namespaced_flag_name = self._namespaced_name(flag_name)
value = None
if check_before_waffle_callback:
value = check_before_waffle_callback(namespaced_flag_name)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment