Commit 562f35bc by mikedikan Committed by GitHub

Merge pull request #14181 from edx/mdikan/add-utm-tracking-to-free-purchases

Adding support for UTM Tracking to apply to free purhases
parents 7daf1df9 8f4cf682
......@@ -31,6 +31,11 @@ from student.tests.tests import EnrollmentEventTestMixin
from xmodule.modulestore.django import modulestore
from commerce.api.v0.views import SAILTHRU_CAMPAIGN_COOKIE
UTM_COOKIE_NAME = 'edx.test.utm'
UTM_COOKIE_CONTENTS = {
'utm_source': 'test-source'
}
@attr(shard=1)
@ddt.ddt
......@@ -39,7 +44,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
"""
Tests for the commerce orders view.
"""
def _post_to_view(self, course_id=None, marketing_email_opt_in=False):
def _post_to_view(self, course_id=None, marketing_email_opt_in=False, include_utm_cookie=False):
"""
POST to the view being tested.
......@@ -55,6 +60,8 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
payload["email_opt_in"] = True
self.client.cookies[SAILTHRU_CAMPAIGN_COOKIE] = 'sailthru id'
if include_utm_cookie:
self.client.cookies[UTM_COOKIE_NAME] = json.dumps(UTM_COOKIE_CONTENTS)
return self.client.post(self.url, payload)
def assertResponseMessage(self, response, expected_msg):
......@@ -160,12 +167,12 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
self.assertValidEcommerceInternalRequestErrorResponse(response)
self.assertUserNotEnrolled()
def _test_successful_ecommerce_api_call(self, is_completed=True):
def _test_successful_ecommerce_api_call(self, is_completed=True, utm_tracking_present=False):
"""
Verifies that the view contacts the E-Commerce API with the correct data and headers.
"""
with mock.patch('commerce.api.v0.views.audit_log') as mock_audit_log:
response = self._post_to_view()
response = self._post_to_view(include_utm_cookie=utm_tracking_present)
# Verify that an audit message was logged
self.assertTrue(mock_audit_log.called)
......@@ -177,9 +184,15 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
else:
self.assertResponsePaymentData(response)
# make sure ecommerce API call forwards Sailthru cookie
# Make sure ecommerce API call forwards Sailthru cookie
self.assertIn('{}=sailthru id'.format(SAILTHRU_CAMPAIGN_COOKIE), httpretty.last_request().headers['cookie'])
# Check that UTM tracking cookie is passed along in request to ecommerce for attribution
if utm_tracking_present:
cookie_string = '{cookie_name}={cookie_contents}'.format(
cookie_name=UTM_COOKIE_NAME, cookie_contents=json.dumps(UTM_COOKIE_CONTENTS))
self.assertIn(cookie_string, httpretty.last_request().headers['cookie'])
@ddt.data(True, False)
def test_course_with_honor_seat_sku(self, user_is_active):
"""
......@@ -193,7 +206,14 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
return_value = {'id': TEST_BASKET_ID, 'payment_data': None, 'order': {'number': TEST_ORDER_NUMBER}}
with mock_create_basket(response=return_value):
# Test that call without utm tracking works
self._test_successful_ecommerce_api_call()
with mock.patch('student.models.RegistrationCookieConfiguration.current') as config:
instance = config.return_value
instance.utm_cookie_name = UTM_COOKIE_NAME
# Test that call with cookie passes cookie along
self._test_successful_ecommerce_api_call(utm_tracking_present=True)
@ddt.data(True, False)
def test_course_with_paid_seat_sku(self, user_is_active):
......@@ -207,7 +227,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
return_value = {'id': TEST_BASKET_ID, 'payment_data': TEST_PAYMENT_DATA, 'order': None}
with mock_create_basket(response=return_value):
self._test_successful_ecommerce_api_call(False)
self._test_successful_ecommerce_api_call(is_completed=False)
def _test_course_without_sku(self, enrollment_mode=CourseMode.DEFAULT_MODE_SLUG):
"""
......@@ -334,7 +354,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
self.assertIsNotNone(get_enrollment(self.user.username, unicode(self.course.id)))
with mock_create_basket():
self._test_successful_ecommerce_api_call(False)
self._test_successful_ecommerce_api_call(is_completed=False)
@mock.patch('commerce.api.v0.views.update_email_opt_in')
@ddt.data(*itertools.product((False, True), (False, True), (False, True)))
......
......@@ -22,7 +22,7 @@ from openedx.core.djangoapps.commerce.utils import ecommerce_api_client
from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in
from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser
from openedx.core.lib.log_utils import audit_log
from student.models import CourseEnrollment
from student.models import CourseEnrollment, RegistrationCookieConfiguration
from util.json_request import JsonResponse
......@@ -150,13 +150,11 @@ class BasketsView(APIView):
# Make the API call
try:
# Pass along Sailthru campaign id
campaign_cookie = request.COOKIES.get(SAILTHRU_CAMPAIGN_COOKIE)
if campaign_cookie:
cookie = {SAILTHRU_CAMPAIGN_COOKIE: campaign_cookie}
if api_session.cookies:
requests.utils.add_dict_to_cookiejar(api_session.cookies, cookie)
else:
api_session.cookies = requests.utils.cookiejar_from_dict(cookie)
self._add_request_cookie_to_api_session(api_session, request, SAILTHRU_CAMPAIGN_COOKIE)
# Pass along UTM tracking info
utm_cookie_name = RegistrationCookieConfiguration.current().utm_cookie_name
self._add_request_cookie_to_api_session(api_session, request, utm_cookie_name)
response_data = api.baskets.post({
'products': [{'sku': default_enrollment_mode.sku}],
......@@ -194,6 +192,18 @@ 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. """
......
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