Commit 0e16aa8c by Jim Abramson

Merge pull request #8924 from edx/jsa/xcom-499

Support setting email opt-in in calls to the Otto shim
parents 98a8f0e2 afa77f86
""" Commerce API v0 view tests. """
import json
import itertools
from uuid import uuid4
from nose.plugins.attrib import attr
import ddt
from django.conf import settings
......@@ -9,6 +9,7 @@ from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.utils import override_settings
import mock
from nose.plugins.attrib import attr
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
......@@ -33,7 +34,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
"""
Tests for the commerce orders view.
"""
def _post_to_view(self, course_id=None):
def _post_to_view(self, course_id=None, marketing_email_opt_in=False):
"""
POST to the view being tested.
......@@ -42,8 +43,12 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
:return: Response
"""
course_id = unicode(course_id or self.course.id)
return self.client.post(self.url, {'course_id': course_id})
payload = {
"course_id": unicode(course_id or self.course.id)
}
if marketing_email_opt_in:
payload["email_opt_in"] = True
return self.client.post(self.url, payload)
def assertResponseMessage(self, response, expected_msg):
""" Asserts the detail field in the response's JSON body equals the expected message. """
......@@ -297,6 +302,28 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
with mock_create_basket():
self._test_successful_ecommerce_api_call(False)
@mock.patch('commerce.api.v0.views.update_email_opt_in')
@ddt.data(*itertools.product((False, True), (False, True), (False, True)))
@ddt.unpack
def test_marketing_email_opt_in(self, is_opt_in, has_sku, is_exception, mock_update):
"""
Ensures the email opt-in flag is handled, if present, and that problems handling the
flag don't cause the rest of the enrollment transaction to fail.
"""
if not has_sku:
for course_mode in CourseMode.objects.filter(course_id=self.course.id):
course_mode.sku = None
course_mode.save()
if is_exception:
mock_update.side_effect = Exception("boink")
return_value = {'id': TEST_BASKET_ID, 'payment_data': None, 'order': {'number': TEST_ORDER_NUMBER}}
with mock_create_basket(response=return_value, expect_called=has_sku):
response = self._post_to_view(marketing_email_opt_in=is_opt_in)
self.assertEqual(mock_update.called, is_opt_in)
self.assertEqual(response.status_code, 200)
@attr('shard_1')
@override_settings(ECOMMERCE_API_URL=TEST_API_URL, ECOMMERCE_API_SIGNING_KEY=TEST_API_SIGNING_KEY)
......
......@@ -19,6 +19,7 @@ from courseware import courses
from embargo import api as embargo_api
from enrollment.api import add_enrollment
from enrollment.views import EnrollmentCrossDomainSessionAuth
from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in
from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser
from student.models import CourseEnrollment
from util.json_request import JsonResponse
......@@ -62,6 +63,22 @@ class BasketsView(APIView):
""" Enroll the user in the course. """
add_enrollment(user.username, unicode(course_key))
def _handle_marketing_opt_in(self, request, course_key, user):
"""
Handle the marketing email opt-in flag, if it was set.
Errors here aren't expected, but should not break the outer enrollment transaction.
"""
email_opt_in = request.DATA.get('email_opt_in', None)
if email_opt_in is not None:
try:
update_email_opt_in(user, course_key.org, email_opt_in)
except Exception: # pylint: disable=broad-except
# log the error, return silently
log.exception(
'Failed to handle marketing opt-in flag: user="%s", course="%s"', user.username, course_key
)
def post(self, request, *args, **kwargs): # pylint: disable=unused-argument
"""
Attempt to create the basket and enroll the user.
......@@ -96,6 +113,7 @@ class BasketsView(APIView):
username=user.username)
log.debug(msg)
self._enroll(course_key, user)
self._handle_marketing_opt_in(request, course_key, user)
return DetailResponse(msg)
# Setup the API
......@@ -108,6 +126,8 @@ class BasketsView(APIView):
log.debug(msg)
return DetailResponse(msg)
response = None
# Make the API call
try:
response_data = api.baskets.post({
......@@ -118,12 +138,12 @@ class BasketsView(APIView):
payment_data = response_data["payment_data"]
if payment_data:
# Pass data to the client to begin the payment flow.
return JsonResponse(payment_data)
response = JsonResponse(payment_data)
elif response_data['order']:
# The order was completed immediately because there is no charge.
msg = Messages.ORDER_COMPLETED.format(order_number=response_data['order']['number'])
log.debug(msg)
return DetailResponse(msg)
response = DetailResponse(msg)
else:
msg = u'Unexpected response from basket endpoint.'
log.error(
......@@ -143,6 +163,9 @@ class BasketsView(APIView):
user_id=user.id
)
self._handle_marketing_opt_in(request, course_key, user)
return response
class BasketOrderView(APIView):
""" Retrieve the order associated with a basket. """
......
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