Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
ecommerce
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
ecommerce
Commits
35efdd39
Commit
35efdd39
authored
Sep 20, 2017
by
Waheed Ahmed
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use GA clientId from cookie on all analytics events instead of DB.
LEARNER-2596
parent
0e07009e
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
117 additions
and
97 deletions
+117
-97
ecommerce/extensions/analytics/middleware.py
+23
-0
ecommerce/extensions/analytics/tests/test_middleware.py
+30
-0
ecommerce/extensions/analytics/tests/test_utils.py
+14
-18
ecommerce/extensions/analytics/utils.py
+6
-7
ecommerce/extensions/basket/tests/test_models.py
+2
-2
ecommerce/extensions/checkout/signals.py
+2
-8
ecommerce/extensions/checkout/tests/test_mixins.py
+8
-4
ecommerce/extensions/checkout/tests/test_signals.py
+14
-33
ecommerce/extensions/fulfillment/tests/test_modules.py
+15
-23
ecommerce/extensions/refund/tests/test_signals.py
+2
-2
ecommerce/settings/base.py
+1
-0
No files found.
ecommerce/extensions/analytics/middleware.py
0 → 100644
View file @
35efdd39
"""
Middleware for analytics app to parse GA cookie.
"""
from
ecommerce.extensions.analytics.utils
import
get_google_analytics_client_id
class
TrackingMiddleware
(
object
):
"""
Middleware that parse `_ga` cookie and save/update in user tracking context.
"""
def
process_request
(
self
,
request
):
user
=
request
.
user
if
user
.
is_authenticated
():
tracking_context
=
user
.
tracking_context
or
{}
old_client_id
=
tracking_context
.
get
(
'ga_client_id'
)
ga_client_id
=
get_google_analytics_client_id
(
request
)
if
ga_client_id
and
ga_client_id
!=
old_client_id
:
tracking_context
[
'ga_client_id'
]
=
ga_client_id
user
.
tracking_context
=
tracking_context
user
.
save
()
ecommerce/extensions/analytics/tests/test_middleware.py
0 → 100644
View file @
35efdd39
from
django.test.client
import
RequestFactory
from
ecommerce.extensions.analytics
import
middleware
from
ecommerce.tests.testcases
import
TestCase
class
TrackingMiddlewareTests
(
TestCase
):
""" Test for TrackingMiddleware. """
def
setUp
(
self
):
super
(
TrackingMiddlewareTests
,
self
)
.
setUp
()
self
.
middleware
=
middleware
.
TrackingMiddleware
()
self
.
request_factory
=
RequestFactory
()
self
.
user
=
self
.
create_user
()
def
_assert_ga_client_id
(
self
,
ga_client_id
):
self
.
request_factory
.
cookies
[
'_ga'
]
=
'GA1.2.{}'
.
format
(
ga_client_id
)
request
=
self
.
request_factory
.
get
(
'/'
)
request
.
user
=
self
.
user
self
.
middleware
.
process_request
(
request
)
expected_client_id
=
self
.
user
.
tracking_context
.
get
(
'ga_client_id'
)
self
.
assertEqual
(
ga_client_id
,
expected_client_id
)
def
test_process_request
(
self
):
""" Test that middleware save/update GA client id in user tracking context. """
self
.
assertIsNone
(
self
.
user
.
tracking_context
)
self
.
_assert_ga_client_id
(
'test-client-id'
)
updated_client_id
=
'updated-client-id'
self
.
assertNotEqual
(
updated_client_id
,
self
.
user
.
tracking_context
.
get
(
'ga_client_id'
))
self
.
_assert_ga_client_id
(
updated_client_id
)
ecommerce/extensions/analytics/tests/test_utils.py
View file @
35efdd39
...
@@ -51,18 +51,18 @@ class UtilsTest(DiscoveryTestMixin, BasketMixin, TestCase):
...
@@ -51,18 +51,18 @@ class UtilsTest(DiscoveryTestMixin, BasketMixin, TestCase):
def
test_parse_tracking_context
(
self
):
def
test_parse_tracking_context
(
self
):
""" The method should parse the tracking context on the User object. """
""" The method should parse the tracking context on the User object. """
tracking_context
=
{
tracking_context
=
{
'ga_client_id'
:
'test-client-id'
,
'lms_user_id'
:
'foo'
,
'lms_user_id'
:
'foo'
,
'lms_client_id'
:
'bar'
,
'lms_ip'
:
'18.0.0.1'
,
'lms_ip'
:
'18.0.0.1'
,
}
}
user
=
self
.
create_user
(
tracking_context
=
tracking_context
)
user
=
self
.
create_user
(
tracking_context
=
tracking_context
)
expected
=
(
tracking_context
[
'lms_user_id'
],
tracking_context
[
'
lms
_client_id'
],
tracking_context
[
'lms_ip'
])
expected
=
(
tracking_context
[
'lms_user_id'
],
tracking_context
[
'
ga
_client_id'
],
tracking_context
[
'lms_ip'
])
self
.
assertEqual
(
parse_tracking_context
(
user
),
expected
)
self
.
assertEqual
(
parse_tracking_context
(
user
),
expected
)
# If no LMS user ID is provided, we should create one based on the E-Commerce ID
# If no LMS user ID is provided, we should create one based on the E-Commerce ID
del
tracking_context
[
'lms_user_id'
]
del
tracking_context
[
'lms_user_id'
]
user
=
self
.
create_user
(
tracking_context
=
tracking_context
)
user
=
self
.
create_user
(
tracking_context
=
tracking_context
)
expected
=
(
'ecommerce-{}'
.
format
(
user
.
id
),
tracking_context
[
'
lms
_client_id'
],
tracking_context
[
'lms_ip'
])
expected
=
(
'ecommerce-{}'
.
format
(
user
.
id
),
tracking_context
[
'
ga
_client_id'
],
tracking_context
[
'lms_ip'
])
self
.
assertEqual
(
parse_tracking_context
(
user
),
expected
)
self
.
assertEqual
(
parse_tracking_context
(
user
),
expected
)
def
test_track_segment_event_without_segment_key
(
self
):
def
test_track_segment_event_without_segment_key
(
self
):
...
@@ -76,33 +76,29 @@ class UtilsTest(DiscoveryTestMixin, BasketMixin, TestCase):
...
@@ -76,33 +76,29 @@ class UtilsTest(DiscoveryTestMixin, BasketMixin, TestCase):
self
.
assertEqual
(
track_segment_event
(
self
.
site
,
self
.
create_user
(),
'foo'
,
{}),
(
False
,
msg
))
self
.
assertEqual
(
track_segment_event
(
self
.
site
,
self
.
create_user
(),
'foo'
,
{}),
(
False
,
msg
))
mock_debug
.
assert_called_with
(
msg
)
mock_debug
.
assert_called_with
(
msg
)
@ddt.data
(
'1033501218.1368477899'
,
None
)
def
test_track_segment_event
(
self
):
def
test_track_segment_event
(
self
,
ga_client_id
):
""" The function should fire an event to Segment if the site is properly configured. """
""" The function should fire an event to Segment if the site is properly configured. """
properties
=
{
'key'
:
'value'
}
properties
=
{
'key'
:
'value'
}
self
.
site_configuration
.
segment_key
=
'fake-key'
self
.
site_configuration
.
segment_key
=
'fake-key'
self
.
site_configuration
.
save
()
self
.
site_configuration
.
save
()
user
=
self
.
create_user
(
user
=
self
.
create_user
(
tracking_context
=
{
tracking_context
=
{
'ga_client_id'
:
'test-client-id'
,
'lms_user_id'
:
'foo'
,
'lms_user_id'
:
'foo'
,
'lms_client_id'
:
'bar'
,
'lms_ip'
:
'18.0.0.1'
,
'lms_ip'
:
'18.0.0.1'
,
}
}
)
)
user_tracking_id
,
lms
_client_id
,
lms_ip
=
parse_tracking_context
(
user
)
user_tracking_id
,
ga
_client_id
,
lms_ip
=
parse_tracking_context
(
user
)
context
=
{
context
=
{
'ip'
:
lms_ip
,
'ip'
:
lms_ip
,
'Google Analytics'
:
{
'Google Analytics'
:
{
'clientId'
:
ga_client_id
if
ga_client_id
else
lms_client_id
'clientId'
:
ga_client_id
}
}
}
}
event
=
'foo'
event
=
'foo'
with
mock
.
patch
.
object
(
Client
,
'track'
)
as
mock_track
:
with
mock
.
patch
.
object
(
Client
,
'track'
)
as
mock_track
:
if
ga_client_id
:
track_segment_event
(
self
.
site
,
user
,
event
,
properties
)
track_segment_event
(
self
.
site
,
user
,
event
,
properties
,
ga_client_id
=
ga_client_id
)
else
:
track_segment_event
(
self
.
site
,
user
,
event
,
properties
)
mock_track
.
assert_called_once_with
(
user_tracking_id
,
event
,
properties
,
context
=
context
)
mock_track
.
assert_called_once_with
(
user_tracking_id
,
event
,
properties
,
context
=
context
)
def
test_translate_basket_line_for_segment
(
self
):
def
test_translate_basket_line_for_segment
(
self
):
...
@@ -146,13 +142,13 @@ class UtilsTest(DiscoveryTestMixin, BasketMixin, TestCase):
...
@@ -146,13 +142,13 @@ class UtilsTest(DiscoveryTestMixin, BasketMixin, TestCase):
def
test_get_google_analytics_client_id
(
self
):
def
test_get_google_analytics_client_id
(
self
):
""" Test that method return's the GA clientId. """
""" Test that method return's the GA clientId. """
client_id
=
'1033501218.1368477899'
request_factory
=
RequestFactory
()
request_factory
.
cookies
[
'_ga'
]
=
'GA1.2.{}'
.
format
(
client_id
)
request
=
request_factory
.
get
(
'/'
)
expected_client_id
=
get_google_analytics_client_id
(
None
)
expected_client_id
=
get_google_analytics_client_id
(
None
)
self
.
assertIsNone
(
expected_client_id
)
self
.
assertIsNone
(
expected_client_id
)
ga_client_id
=
'test-client-id'
request_factory
=
RequestFactory
()
request_factory
.
cookies
[
'_ga'
]
=
'GA1.2.{}'
.
format
(
ga_client_id
)
request
=
request_factory
.
get
(
'/'
)
expected_client_id
=
get_google_analytics_client_id
(
request
)
expected_client_id
=
get_google_analytics_client_id
(
request
)
self
.
assertEqual
(
client_id
,
expected_client_id
)
self
.
assertEqual
(
ga_
client_id
,
expected_client_id
)
ecommerce/extensions/analytics/utils.py
View file @
35efdd39
...
@@ -14,7 +14,7 @@ def parse_tracking_context(user):
...
@@ -14,7 +14,7 @@ def parse_tracking_context(user):
user (User): An instance of the User model.
user (User): An instance of the User model.
Returns:
Returns:
Tuple of strings: user_tracking_id,
lms
_client_id, lms_ip
Tuple of strings: user_tracking_id,
ga
_client_id, lms_ip
"""
"""
tracking_context
=
user
.
tracking_context
or
{}
tracking_context
=
user
.
tracking_context
or
{}
...
@@ -26,10 +26,10 @@ def parse_tracking_context(user):
...
@@ -26,10 +26,10 @@ def parse_tracking_context(user):
# at some point.
# at some point.
user_tracking_id
=
'ecommerce-{}'
.
format
(
user
.
id
)
user_tracking_id
=
'ecommerce-{}'
.
format
(
user
.
id
)
lms_client_id
=
tracking_context
.
get
(
'lms_client_id'
)
lms_ip
=
tracking_context
.
get
(
'lms_ip'
)
lms_ip
=
tracking_context
.
get
(
'lms_ip'
)
ga_client_id
=
tracking_context
.
get
(
'ga_client_id'
)
return
user_tracking_id
,
lms
_client_id
,
lms_ip
return
user_tracking_id
,
ga
_client_id
,
lms_ip
def
silence_exceptions
(
msg
):
def
silence_exceptions
(
msg
):
...
@@ -118,7 +118,7 @@ def prepare_analytics_data(user, segment_key):
...
@@ -118,7 +118,7 @@ def prepare_analytics_data(user, segment_key):
return
json
.
dumps
(
data
)
return
json
.
dumps
(
data
)
def
track_segment_event
(
site
,
user
,
event
,
properties
,
ga_client_id
=
None
):
def
track_segment_event
(
site
,
user
,
event
,
properties
):
""" Fire a tracking event via Segment.
""" Fire a tracking event via Segment.
Args:
Args:
...
@@ -126,7 +126,6 @@ def track_segment_event(site, user, event, properties, ga_client_id=None):
...
@@ -126,7 +126,6 @@ def track_segment_event(site, user, event, properties, ga_client_id=None):
user (User): User to which the event should be associated.
user (User): User to which the event should be associated.
event (str): Event name.
event (str): Event name.
properties (dict): Event properties.
properties (dict): Event properties.
ga_client_id (str): Google Analytics clientId.
Returns:
Returns:
(success, msg): Tuple indicating the success of enqueuing the event on the message queue.
(success, msg): Tuple indicating the success of enqueuing the event on the message queue.
...
@@ -139,11 +138,11 @@ def track_segment_event(site, user, event, properties, ga_client_id=None):
...
@@ -139,11 +138,11 @@ def track_segment_event(site, user, event, properties, ga_client_id=None):
logger
.
debug
(
msg
)
logger
.
debug
(
msg
)
return
False
,
msg
return
False
,
msg
user_tracking_id
,
lms
_client_id
,
lms_ip
=
parse_tracking_context
(
user
)
user_tracking_id
,
ga
_client_id
,
lms_ip
=
parse_tracking_context
(
user
)
context
=
{
context
=
{
'ip'
:
lms_ip
,
'ip'
:
lms_ip
,
'Google Analytics'
:
{
'Google Analytics'
:
{
'clientId'
:
ga_client_id
if
ga_client_id
else
lms_client_id
'clientId'
:
ga_client_id
}
}
}
}
return
site
.
siteconfiguration
.
segment_client
.
track
(
user_tracking_id
,
event
,
properties
,
context
=
context
)
return
site
.
siteconfiguration
.
segment_client
.
track
(
user_tracking_id
,
event
,
properties
,
context
=
context
)
...
...
ecommerce/extensions/basket/tests/test_models.py
View file @
35efdd39
...
@@ -123,11 +123,11 @@ class BasketTests(CatalogMixin, BasketMixin, TestCase):
...
@@ -123,11 +123,11 @@ class BasketTests(CatalogMixin, BasketMixin, TestCase):
basket
.
add_product
(
seat
)
basket
.
add_product
(
seat
)
properties
=
translate_basket_line_for_segment
(
basket
.
lines
.
first
())
properties
=
translate_basket_line_for_segment
(
basket
.
lines
.
first
())
user_tracking_id
,
lms
_client_id
,
lms_ip
=
parse_tracking_context
(
basket
.
owner
)
user_tracking_id
,
ga
_client_id
,
lms_ip
=
parse_tracking_context
(
basket
.
owner
)
context
=
{
context
=
{
'ip'
:
lms_ip
,
'ip'
:
lms_ip
,
'Google Analytics'
:
{
'Google Analytics'
:
{
'clientId'
:
lms
_client_id
'clientId'
:
ga
_client_id
}
}
}
}
...
...
ecommerce/extensions/checkout/signals.py
View file @
35efdd39
...
@@ -5,11 +5,7 @@ from django.dispatch import receiver
...
@@ -5,11 +5,7 @@ from django.dispatch import receiver
from
oscar.core.loading
import
get_class
,
get_model
from
oscar.core.loading
import
get_class
,
get_model
from
ecommerce.courses.utils
import
mode_for_seat
from
ecommerce.courses.utils
import
mode_for_seat
from
ecommerce.extensions.analytics.utils
import
(
from
ecommerce.extensions.analytics.utils
import
silence_exceptions
,
track_segment_event
get_google_analytics_client_id
,
silence_exceptions
,
track_segment_event
)
from
ecommerce.extensions.checkout.utils
import
get_credit_provider_details
,
get_receipt_page_url
from
ecommerce.extensions.checkout.utils
import
get_credit_provider_details
,
get_receipt_page_url
from
ecommerce.notifications.notifications
import
send_notification
from
ecommerce.notifications.notifications
import
send_notification
from
ecommerce.programs.utils
import
get_program
from
ecommerce.programs.utils
import
get_program
...
@@ -83,9 +79,7 @@ def track_completed_order(sender, order=None, **kwargs): # pylint: disable=unus
...
@@ -83,9 +79,7 @@ def track_completed_order(sender, order=None, **kwargs): # pylint: disable=unus
except
BasketAttribute
.
DoesNotExist
:
except
BasketAttribute
.
DoesNotExist
:
logger
.
info
(
'There is no program or bundle associated with order number
%
s'
,
order
.
number
)
logger
.
info
(
'There is no program or bundle associated with order number
%
s'
,
order
.
number
)
ga_client_id
=
get_google_analytics_client_id
(
kwargs
.
get
(
'request'
))
track_segment_event
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
)
track_segment_event
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
,
ga_client_id
=
ga_client_id
)
@receiver
(
post_checkout
,
dispatch_uid
=
'send_completed_order_email'
)
@receiver
(
post_checkout
,
dispatch_uid
=
'send_completed_order_email'
)
...
...
ecommerce/extensions/checkout/tests/test_mixins.py
View file @
35efdd39
...
@@ -114,7 +114,7 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, PaymentEventsMixin,
...
@@ -114,7 +114,7 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, PaymentEventsMixin,
Ensure that tracking events are fired with correct content when order
Ensure that tracking events are fired with correct content when order
placement event handling is invoked.
placement event handling is invoked.
"""
"""
tracking_context
=
{
'
lms_user_id'
:
'test-user-id'
,
'lms_client_id'
:
'test-client
-id'
,
'lms_ip'
:
'127.0.0.1'
}
tracking_context
=
{
'
ga_client_id'
:
'test-client-id'
,
'lms_user_id'
:
'test-user
-id'
,
'lms_ip'
:
'127.0.0.1'
}
self
.
user
.
tracking_context
=
tracking_context
self
.
user
.
tracking_context
=
tracking_context
self
.
user
.
save
()
self
.
user
.
save
()
...
@@ -127,7 +127,7 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, PaymentEventsMixin,
...
@@ -127,7 +127,7 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, PaymentEventsMixin,
mock_track
,
mock_track
,
self
.
order
,
self
.
order
,
tracking_context
[
'lms_user_id'
],
tracking_context
[
'lms_user_id'
],
tracking_context
[
'
lms
_client_id'
],
tracking_context
[
'
ga
_client_id'
],
tracking_context
[
'lms_ip'
],
tracking_context
[
'lms_ip'
],
self
.
order
.
number
,
self
.
order
.
number
,
self
.
order
.
currency
,
self
.
order
.
currency
,
...
@@ -272,16 +272,20 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, PaymentEventsMixin,
...
@@ -272,16 +272,20 @@ class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, PaymentEventsMixin,
"""
"""
Verify the "Payment Info Entered" Segment event is fired after payment info is validated
Verify the "Payment Info Entered" Segment event is fired after payment info is validated
"""
"""
tracking_context
=
{
'ga_client_id'
:
'test-client-id'
,
'lms_user_id'
:
'test-user-id'
,
'lms_ip'
:
'127.0.0.1'
}
self
.
user
.
tracking_context
=
tracking_context
self
.
user
.
save
()
basket
=
create_basket
(
owner
=
self
.
user
,
site
=
self
.
site
)
basket
=
create_basket
(
owner
=
self
.
user
,
site
=
self
.
site
)
mixin
=
EdxOrderPlacementMixin
()
mixin
=
EdxOrderPlacementMixin
()
mixin
.
payment_processor
=
DummyProcessor
(
self
.
site
)
mixin
.
payment_processor
=
DummyProcessor
(
self
.
site
)
user_tracking_id
,
lms
_client_id
,
lms_ip
=
parse_tracking_context
(
self
.
user
)
user_tracking_id
,
ga
_client_id
,
lms_ip
=
parse_tracking_context
(
self
.
user
)
context
=
{
context
=
{
'ip'
:
lms_ip
,
'ip'
:
lms_ip
,
'Google Analytics'
:
{
'Google Analytics'
:
{
'clientId'
:
lms
_client_id
'clientId'
:
ga
_client_id
}
}
}
}
...
...
ecommerce/extensions/checkout/tests/test_signals.py
View file @
35efdd39
...
@@ -3,7 +3,6 @@ import json
...
@@ -3,7 +3,6 @@ import json
import
httpretty
import
httpretty
import
mock
import
mock
from
django.core
import
mail
from
django.core
import
mail
from
django.test.client
import
RequestFactory
from
oscar.core.loading
import
get_class
,
get_model
from
oscar.core.loading
import
get_class
,
get_model
from
oscar.test
import
factories
from
oscar.test
import
factories
from
oscar.test.newfactories
import
BasketFactory
from
oscar.test.newfactories
import
BasketFactory
...
@@ -36,10 +35,6 @@ LOGGER_NAME = 'ecommerce.extensions.checkout.signals'
...
@@ -36,10 +35,6 @@ LOGGER_NAME = 'ecommerce.extensions.checkout.signals'
class
SignalTests
(
ProgramTestMixin
,
CouponMixin
,
TestCase
):
class
SignalTests
(
ProgramTestMixin
,
CouponMixin
,
TestCase
):
def
setUp
(
self
):
def
setUp
(
self
):
super
(
SignalTests
,
self
)
.
setUp
()
super
(
SignalTests
,
self
)
.
setUp
()
self
.
ga_client_id
=
'1033501218.1368477899'
request_factory
=
RequestFactory
()
request_factory
.
cookies
[
'_ga'
]
=
'GA1.2.{}'
.
format
(
self
.
ga_client_id
)
self
.
request
=
request_factory
.
get
(
'/'
)
self
.
user
=
self
.
create_user
()
self
.
user
=
self
.
create_user
()
self
.
request
.
user
=
self
.
user
self
.
request
.
user
=
self
.
user
toggle_switch
(
'ENABLE_NOTIFICATIONS'
,
True
)
toggle_switch
(
'ENABLE_NOTIFICATIONS'
,
True
)
...
@@ -178,20 +173,16 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
...
@@ -178,20 +173,16 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
with
mock
.
patch
(
'ecommerce.extensions.checkout.signals.track_segment_event'
)
as
mock_track
:
with
mock
.
patch
(
'ecommerce.extensions.checkout.signals.track_segment_event'
)
as
mock_track
:
order
=
self
.
prepare_order
(
'verified'
)
order
=
self
.
prepare_order
(
'verified'
)
track_completed_order
(
None
,
order
,
request
=
self
.
request
)
track_completed_order
(
None
,
order
)
properties
=
self
.
_generate_event_properties
(
order
)
properties
=
self
.
_generate_event_properties
(
order
)
mock_track
.
assert_called_once_with
(
mock_track
.
assert_called_once_with
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
)
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
,
ga_client_id
=
self
.
ga_client_id
)
# We should be able to fire events even if the product is not related to a course.
# We should be able to fire events even if the product is not related to a course.
mock_track
.
reset_mock
()
mock_track
.
reset_mock
()
order
=
create_order
()
order
=
create_order
()
track_completed_order
(
None
,
order
,
request
=
self
.
request
)
track_completed_order
(
None
,
order
)
properties
=
self
.
_generate_event_properties
(
order
)
properties
=
self
.
_generate_event_properties
(
order
)
mock_track
.
assert_called_once_with
(
mock_track
.
assert_called_once_with
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
)
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
,
ga_client_id
=
self
.
ga_client_id
)
@mock.patch
(
'ecommerce.extensions.checkout.signals.track_segment_event'
)
@mock.patch
(
'ecommerce.extensions.checkout.signals.track_segment_event'
)
def
test_track_bundle_order
(
self
,
mock_track
):
def
test_track_bundle_order
(
self
,
mock_track
):
...
@@ -206,21 +197,17 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
...
@@ -206,21 +197,17 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
# Tracks a full bundle order
# Tracks a full bundle order
with
mock
.
patch
(
'ecommerce.extensions.checkout.signals.get_program'
,
with
mock
.
patch
(
'ecommerce.extensions.checkout.signals.get_program'
,
mock
.
Mock
(
return_value
=
self
.
mock_get_program_data
(
True
))):
mock
.
Mock
(
return_value
=
self
.
mock_get_program_data
(
True
))):
track_completed_order
(
None
,
order
,
request
=
self
.
request
)
track_completed_order
(
None
,
order
)
properties
=
self
.
_generate_event_properties
(
order
,
bundle_id
=
'test_bundle'
,
fullBundle
=
True
)
properties
=
self
.
_generate_event_properties
(
order
,
bundle_id
=
'test_bundle'
,
fullBundle
=
True
)
mock_track
.
assert_called_once_with
(
mock_track
.
assert_called_once_with
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
)
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
,
ga_client_id
=
self
.
ga_client_id
)
# Tracks a partial bundle order
# Tracks a partial bundle order
with
mock
.
patch
(
'ecommerce.extensions.checkout.signals.get_program'
,
with
mock
.
patch
(
'ecommerce.extensions.checkout.signals.get_program'
,
mock
.
Mock
(
return_value
=
self
.
mock_get_program_data
(
False
))):
mock
.
Mock
(
return_value
=
self
.
mock_get_program_data
(
False
))):
mock_track
.
reset_mock
()
mock_track
.
reset_mock
()
track_completed_order
(
None
,
order
,
request
=
self
.
request
)
track_completed_order
(
None
,
order
)
properties
=
self
.
_generate_event_properties
(
order
,
bundle_id
=
'test_bundle'
)
properties
=
self
.
_generate_event_properties
(
order
,
bundle_id
=
'test_bundle'
)
mock_track
.
assert_called_once_with
(
mock_track
.
assert_called_once_with
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
)
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
,
ga_client_id
=
self
.
ga_client_id
)
def
test_track_completed_discounted_order_with_voucher
(
self
):
def
test_track_completed_discounted_order_with_voucher
(
self
):
""" An event including coupon information should be sent to Segment"""
""" An event including coupon information should be sent to Segment"""
...
@@ -237,11 +224,9 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
...
@@ -237,11 +224,9 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
Applicator
()
.
apply
(
basket
,
user
=
basket
.
owner
,
request
=
self
.
request
)
Applicator
()
.
apply
(
basket
,
user
=
basket
.
owner
,
request
=
self
.
request
)
order
=
factories
.
create_order
(
basket
=
basket
,
user
=
self
.
user
)
order
=
factories
.
create_order
(
basket
=
basket
,
user
=
self
.
user
)
track_completed_order
(
None
,
order
,
request
=
self
.
request
)
track_completed_order
(
None
,
order
)
properties
=
self
.
_generate_event_properties
(
order
,
voucher
)
properties
=
self
.
_generate_event_properties
(
order
,
voucher
)
mock_track
.
assert_called_once_with
(
mock_track
.
assert_called_once_with
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
)
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
,
ga_client_id
=
self
.
ga_client_id
)
def
test_track_completed_discounted_order_with_voucher_with_offer
(
self
):
def
test_track_completed_discounted_order_with_voucher_with_offer
(
self
):
with
mock
.
patch
(
'ecommerce.extensions.checkout.signals.track_segment_event'
)
as
mock_track
:
with
mock
.
patch
(
'ecommerce.extensions.checkout.signals.track_segment_event'
)
as
mock_track
:
...
@@ -263,11 +248,9 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
...
@@ -263,11 +248,9 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
Applicator
()
.
apply
(
basket
,
user
=
basket
.
owner
,
request
=
self
.
request
)
Applicator
()
.
apply
(
basket
,
user
=
basket
.
owner
,
request
=
self
.
request
)
order
=
factories
.
create_order
(
basket
=
basket
,
user
=
self
.
user
)
order
=
factories
.
create_order
(
basket
=
basket
,
user
=
self
.
user
)
track_completed_order
(
None
,
order
,
request
=
self
.
request
)
track_completed_order
(
None
,
order
)
properties
=
self
.
_generate_event_properties
(
order
,
voucher
)
properties
=
self
.
_generate_event_properties
(
order
,
voucher
)
mock_track
.
assert_called_once_with
(
mock_track
.
assert_called_once_with
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
)
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
,
ga_client_id
=
self
.
ga_client_id
)
def
test_track_completed_discounted_order_with_offer
(
self
):
def
test_track_completed_discounted_order_with_offer
(
self
):
""" An event including a discount but no coupon should be sent to Segment"""
""" An event including a discount but no coupon should be sent to Segment"""
...
@@ -287,11 +270,9 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
...
@@ -287,11 +270,9 @@ class SignalTests(ProgramTestMixin, CouponMixin, TestCase):
Applicator
()
.
apply_offers
(
basket
,
[
site_offer
])
Applicator
()
.
apply_offers
(
basket
,
[
site_offer
])
order
=
factories
.
create_order
(
basket
=
basket
,
user
=
self
.
user
)
order
=
factories
.
create_order
(
basket
=
basket
,
user
=
self
.
user
)
track_completed_order
(
None
,
order
,
request
=
self
.
request
)
track_completed_order
(
None
,
order
)
properties
=
self
.
_generate_event_properties
(
order
)
properties
=
self
.
_generate_event_properties
(
order
)
mock_track
.
assert_called_once_with
(
mock_track
.
assert_called_once_with
(
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
)
order
.
site
,
order
.
user
,
'Order Completed'
,
properties
,
ga_client_id
=
self
.
ga_client_id
)
def
test_track_completed_coupon_order
(
self
):
def
test_track_completed_coupon_order
(
self
):
""" Make sure we do not send GA events for Coupon orders """
""" Make sure we do not send GA events for Coupon orders """
...
...
ecommerce/extensions/fulfillment/tests/test_modules.py
View file @
35efdd39
...
@@ -64,6 +64,10 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
...
@@ -64,6 +64,10 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
super
(
EnrollmentFulfillmentModuleTests
,
self
)
.
setUp
()
super
(
EnrollmentFulfillmentModuleTests
,
self
)
.
setUp
()
self
.
user
=
UserFactory
()
self
.
user
=
UserFactory
()
self
.
user
.
tracking_context
=
{
'ga_client_id'
:
'test-client-id'
,
'lms_user_id'
:
'test-user-id'
,
'lms_ip'
:
'127.0.0.1'
}
self
.
user
.
save
()
self
.
course
=
CourseFactory
(
id
=
self
.
course_id
,
name
=
'Demo Course'
,
site
=
self
.
site
)
self
.
course
=
CourseFactory
(
id
=
self
.
course_id
,
name
=
'Demo Course'
,
site
=
self
.
site
)
self
.
seat
=
self
.
course
.
create_or_update_seat
(
self
.
certificate_type
,
False
,
100
,
self
.
partner
,
self
.
provider
)
self
.
seat
=
self
.
course
.
create_or_update_seat
(
self
.
certificate_type
,
False
,
100
,
self
.
partner
,
self
.
provider
)
...
@@ -123,11 +127,9 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
...
@@ -123,11 +127,9 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
self
.
assertEqual
(
1
,
len
(
supported_lines
))
self
.
assertEqual
(
1
,
len
(
supported_lines
))
@httpretty.activate
@httpretty.activate
@mock.patch
(
'ecommerce.extensions.fulfillment.modules.parse_tracking_context'
)
def
test_enrollment_module_fulfill
(
self
):
def
test_enrollment_module_fulfill
(
self
,
parse_tracking_context
):
"""Happy path test to ensure we can properly fulfill enrollments."""
"""Happy path test to ensure we can properly fulfill enrollments."""
httpretty
.
register_uri
(
httpretty
.
POST
,
get_lms_enrollment_api_url
(),
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
httpretty
.
register_uri
(
httpretty
.
POST
,
get_lms_enrollment_api_url
(),
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
parse_tracking_context
.
return_value
=
(
'user_123'
,
'GA-123456789'
,
'11.22.33.44'
)
# Attempt to enroll.
# Attempt to enroll.
with
LogCapture
(
LOGGER_NAME
)
as
l
:
with
LogCapture
(
LOGGER_NAME
)
as
l
:
EnrollmentFulfillmentModule
()
.
fulfill_product
(
self
.
order
,
list
(
self
.
order
.
lines
.
all
()))
EnrollmentFulfillmentModule
()
.
fulfill_product
(
self
.
order
,
list
(
self
.
order
.
lines
.
all
()))
...
@@ -173,23 +175,21 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
...
@@ -173,23 +175,21 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
}
}
expected_headers
=
{
expected_headers
=
{
'X-Edx-Ga-Client-Id'
:
'GA-123456789'
,
'X-Edx-Ga-Client-Id'
:
self
.
user
.
tracking_context
[
'ga_client_id'
]
,
'X-Forwarded-For'
:
'11.22.33.44'
,
'X-Forwarded-For'
:
self
.
user
.
tracking_context
[
'lms_ip'
]
,
}
}
self
.
assertDictContainsSubset
(
expected_headers
,
actual_headers
)
self
.
assertDictContainsSubset
(
expected_headers
,
actual_headers
)
self
.
assertEqual
(
expected_body
,
actual_body
)
self
.
assertEqual
(
expected_body
,
actual_body
)
@httpretty.activate
@httpretty.activate
@mock.patch
(
'ecommerce.extensions.fulfillment.modules.parse_tracking_context'
)
def
test_enrollment_module_fulfill_order_with_discount_no_voucher
(
self
):
def
test_enrollment_module_fulfill_order_with_discount_no_voucher
(
self
,
parse_tracking_context
):
"""
"""
Test that components of the Fulfillment Module which trigger on the presence of a voucher do
Test that components of the Fulfillment Module which trigger on the presence of a voucher do
not cause failures in cases where a discount does not have a voucher included
not cause failures in cases where a discount does not have a voucher included
(such as with a Conditional Offer)
(such as with a Conditional Offer)
"""
"""
httpretty
.
register_uri
(
httpretty
.
POST
,
get_lms_enrollment_api_url
(),
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
httpretty
.
register_uri
(
httpretty
.
POST
,
get_lms_enrollment_api_url
(),
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
parse_tracking_context
.
return_value
=
(
'user_123'
,
'GA-123456789'
,
'11.22.33.44'
)
self
.
create_seat_and_order
(
certificate_type
=
'credit'
,
provider
=
'MIT'
)
self
.
create_seat_and_order
(
certificate_type
=
'credit'
,
provider
=
'MIT'
)
self
.
order
.
discounts
.
create
()
self
.
order
.
discounts
.
create
()
__
,
lines
=
EnrollmentFulfillmentModule
()
.
fulfill_product
(
self
.
order
,
list
(
self
.
order
.
lines
.
all
()))
__
,
lines
=
EnrollmentFulfillmentModule
()
.
fulfill_product
(
self
.
order
,
list
(
self
.
order
.
lines
.
all
()))
...
@@ -231,11 +231,9 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
...
@@ -231,11 +231,9 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
self
.
assertEqual
(
LINE
.
FULFILLMENT_SERVER_ERROR
,
self
.
order
.
lines
.
all
()[
0
]
.
status
)
self
.
assertEqual
(
LINE
.
FULFILLMENT_SERVER_ERROR
,
self
.
order
.
lines
.
all
()[
0
]
.
status
)
@httpretty.activate
@httpretty.activate
@mock.patch
(
'ecommerce.extensions.fulfillment.modules.parse_tracking_context'
)
def
test_revoke_product
(
self
):
def
test_revoke_product
(
self
,
parse_tracking_context
):
""" The method should call the Enrollment API to un-enroll the student, and return True. """
""" The method should call the Enrollment API to un-enroll the student, and return True. """
httpretty
.
register_uri
(
httpretty
.
POST
,
get_lms_enrollment_api_url
(),
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
httpretty
.
register_uri
(
httpretty
.
POST
,
get_lms_enrollment_api_url
(),
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
parse_tracking_context
.
return_value
=
(
'user_123'
,
'GA-123456789'
,
'11.22.33.44'
)
line
=
self
.
order
.
lines
.
first
()
line
=
self
.
order
.
lines
.
first
()
with
LogCapture
(
LOGGER_NAME
)
as
l
:
with
LogCapture
(
LOGGER_NAME
)
as
l
:
...
@@ -271,8 +269,8 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
...
@@ -271,8 +269,8 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
}
}
expected_headers
=
{
expected_headers
=
{
'X-Edx-Ga-Client-Id'
:
'GA-123456789'
,
'X-Edx-Ga-Client-Id'
:
self
.
user
.
tracking_context
[
'ga_client_id'
]
,
'X-Forwarded-For'
:
'11.22.33.44'
,
'X-Forwarded-For'
:
self
.
user
.
tracking_context
[
'lms_ip'
]
,
}
}
self
.
assertDictContainsSubset
(
expected_headers
,
actual_headers
)
self
.
assertDictContainsSubset
(
expected_headers
,
actual_headers
)
...
@@ -402,10 +400,6 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
...
@@ -402,10 +400,6 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
'enrollment_attributes'
:
[]
'enrollment_attributes'
:
[]
}
}
# Create a dummy user and attach the tracking_context
user
=
UserFactory
()
user
.
tracking_context
=
{
'lms_user_id'
:
'1'
,
'lms_client_id'
:
'123.123'
,
'lms_ip'
:
'11.22.33.44'
}
# Now call the enrollment api to send POST request to LMS and verify
# Now call the enrollment api to send POST request to LMS and verify
# that the header of the request being sent contains the analytics
# that the header of the request being sent contains the analytics
# header 'x-edx-ga-client-id'.
# header 'x-edx-ga-client-id'.
...
@@ -413,12 +407,12 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
...
@@ -413,12 +407,12 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
# not available for ecommerce tests.
# not available for ecommerce tests.
try
:
try
:
# pylint: disable=protected-access
# pylint: disable=protected-access
EnrollmentFulfillmentModule
()
.
_post_to_enrollment_api
(
data
=
data
,
user
=
user
)
EnrollmentFulfillmentModule
()
.
_post_to_enrollment_api
(
data
=
data
,
user
=
self
.
user
)
except
ConnectionError
as
exp
:
except
ConnectionError
as
exp
:
# Check that the enrollment request object has the analytics header
# Check that the enrollment request object has the analytics header
# 'x-edx-ga-client-id' and 'x-forwarded-for'.
# 'x-edx-ga-client-id' and 'x-forwarded-for'.
self
.
assertEqual
(
exp
.
request
.
headers
.
get
(
'x-edx-ga-client-id'
),
'123.123'
)
self
.
assertEqual
(
exp
.
request
.
headers
.
get
(
'x-edx-ga-client-id'
),
self
.
user
.
tracking_context
[
'ga_client_id'
]
)
self
.
assertEqual
(
exp
.
request
.
headers
.
get
(
'x-forwarded-for'
),
'11.22.33.44'
)
self
.
assertEqual
(
exp
.
request
.
headers
.
get
(
'x-forwarded-for'
),
self
.
user
.
tracking_context
[
'lms_ip'
]
)
def
test_voucher_usage
(
self
):
def
test_voucher_usage
(
self
):
"""
"""
...
@@ -428,13 +422,11 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
...
@@ -428,13 +422,11 @@ class EnrollmentFulfillmentModuleTests(ProgramTestMixin, DiscoveryTestMixin, Ful
self
.
assertEqual
(
self
.
order
.
basket
.
total_excl_tax
,
0.00
)
self
.
assertEqual
(
self
.
order
.
basket
.
total_excl_tax
,
0.00
)
@httpretty.activate
@httpretty.activate
@mock.patch
(
'ecommerce.extensions.fulfillment.modules.parse_tracking_context'
)
def
test_voucher_usage_with_program
(
self
):
def
test_voucher_usage_with_program
(
self
,
parse_tracking_context
):
"""
"""
Test that using a voucher with a program basket results in a fulfilled order.
Test that using a voucher with a program basket results in a fulfilled order.
"""
"""
httpretty
.
register_uri
(
httpretty
.
POST
,
get_lms_enrollment_api_url
(),
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
httpretty
.
register_uri
(
httpretty
.
POST
,
get_lms_enrollment_api_url
(),
status
=
200
,
body
=
'{}'
,
content_type
=
JSON
)
parse_tracking_context
.
return_value
=
(
'user_123'
,
'GA-123456789'
,
'11.22.33.44'
)
self
.
create_seat_and_order
(
certificate_type
=
'credit'
,
provider
=
'MIT'
)
self
.
create_seat_and_order
(
certificate_type
=
'credit'
,
provider
=
'MIT'
)
program_uuid
=
uuid
.
uuid4
()
program_uuid
=
uuid
.
uuid4
()
self
.
mock_program_detail_endpoint
(
program_uuid
,
self
.
site_configuration
.
discovery_api_url
)
self
.
mock_program_detail_endpoint
(
program_uuid
,
self
.
site_configuration
.
discovery_api_url
)
...
...
ecommerce/extensions/refund/tests/test_signals.py
View file @
35efdd39
...
@@ -27,7 +27,7 @@ class RefundTrackingTests(RefundTestMixin, TestCase):
...
@@ -27,7 +27,7 @@ class RefundTrackingTests(RefundTestMixin, TestCase):
expected_context
=
{
expected_context
=
{
'ip'
:
tracking_context
.
get
(
'lms_ip'
),
'ip'
:
tracking_context
.
get
(
'lms_ip'
),
'Google Analytics'
:
{
'Google Analytics'
:
{
'clientId'
:
tracking_context
.
get
(
'
lms
_client_id'
)
'clientId'
:
tracking_context
.
get
(
'
ga
_client_id'
)
}
}
}
}
self
.
assertEqual
(
kwargs
[
'context'
],
expected_context
)
self
.
assertEqual
(
kwargs
[
'context'
],
expected_context
)
...
@@ -44,7 +44,7 @@ class RefundTrackingTests(RefundTestMixin, TestCase):
...
@@ -44,7 +44,7 @@ class RefundTrackingTests(RefundTestMixin, TestCase):
def
test_successful_refund_tracking
(
self
,
mock_track
):
def
test_successful_refund_tracking
(
self
,
mock_track
):
"""Verify that a successfully placed refund is tracked when Segment is enabled."""
"""Verify that a successfully placed refund is tracked when Segment is enabled."""
tracking_context
=
{
'
lms_user_id'
:
'test-user-id'
,
'lms_client_id'
:
'test-client
-id'
,
'lms_ip'
:
'127.0.0.1'
}
tracking_context
=
{
'
ga_client_id'
:
'test-client-id'
,
'lms_user_id'
:
'test-user
-id'
,
'lms_ip'
:
'127.0.0.1'
}
self
.
refund
.
user
.
tracking_context
=
tracking_context
self
.
refund
.
user
.
tracking_context
=
tracking_context
self
.
refund
.
user
.
save
()
self
.
refund
.
user
.
save
()
self
.
approve
(
self
.
refund
)
self
.
approve
(
self
.
refund
)
...
...
ecommerce/settings/base.py
View file @
35efdd39
...
@@ -224,6 +224,7 @@ MIDDLEWARE_CLASSES = (
...
@@ -224,6 +224,7 @@ MIDDLEWARE_CLASSES = (
'waffle.middleware.WaffleMiddleware'
,
'waffle.middleware.WaffleMiddleware'
,
# NOTE: The overridden BasketMiddleware relies on request.site. This middleware
# NOTE: The overridden BasketMiddleware relies on request.site. This middleware
# MUST appear AFTER CurrentSiteMiddleware.
# MUST appear AFTER CurrentSiteMiddleware.
'ecommerce.extensions.analytics.middleware.TrackingMiddleware'
,
'ecommerce.extensions.basket.middleware.BasketMiddleware'
,
'ecommerce.extensions.basket.middleware.BasketMiddleware'
,
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'
,
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'
,
'social_django.middleware.SocialAuthExceptionMiddleware'
,
'social_django.middleware.SocialAuthExceptionMiddleware'
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment