Commit 7449f685 by jsa

Support setting email opt-in in calls to the Otto shim

XCOM-499
parent d4a5ad48
""" 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