Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
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
edx-platform
Commits
66ff4e67
Commit
66ff4e67
authored
Nov 13, 2014
by
Stephen Sanchez
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5946 from edx/sanchez/ecommerce_info_to_ga
Adding new Google Analytics eCommerce event to shoppingcart.
parents
a4fea913
822f1554
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
145 additions
and
0 deletions
+145
-0
lms/djangoapps/shoppingcart/models.py
+112
-0
lms/djangoapps/shoppingcart/tests/test_models.py
+33
-0
No files found.
lms/djangoapps/shoppingcart/models.py
View file @
66ff4e67
...
...
@@ -3,6 +3,7 @@
from
collections
import
namedtuple
from
datetime
import
datetime
from
decimal
import
Decimal
import
analytics
import
pytz
import
logging
import
smtplib
...
...
@@ -30,6 +31,7 @@ from config_models.models import ConfigurationModel
from
course_modes.models
import
CourseMode
from
edxmako.shortcuts
import
render_to_string
from
student.models
import
CourseEnrollment
,
UNENROLL_DONE
from
eventtracking
import
tracker
from
util.query
import
use_read_replica_if_available
from
xmodule_django.models
import
CourseKeyField
...
...
@@ -395,6 +397,49 @@ class Order(models.Model):
csv_file
,
courses_info
=
self
.
generate_registration_codes_csv
(
orderitems
,
site_name
)
self
.
send_confirmation_emails
(
orderitems
,
self
.
order_type
==
OrderTypes
.
BUSINESS
,
csv_file
,
site_name
,
courses_info
)
self
.
_emit_purchase_event
(
orderitems
)
def
_emit_purchase_event
(
self
,
orderitems
):
"""
Emit an analytics purchase event for this Order. Will iterate over all associated
OrderItems and add them as products in the event as well.
"""
event_name
=
'Completed Order'
# Required event name by Segment
try
:
products
=
[]
for
item
in
orderitems
:
mode
=
item
.
mode
if
hasattr
(
item
,
'mode'
)
else
''
item
=
{
'id'
:
item
.
id
,
'sku'
:
item
.
sku
,
'price'
:
str
(
item
.
unit_cost
),
'quantity'
:
item
.
qty
,
'category'
:
'{type} {mode}'
.
format
(
type
=
type
(
item
)
.
__name__
,
mode
=
mode
)
}
products
.
append
(
item
)
if
settings
.
FEATURES
.
get
(
'SEGMENT_IO_LMS'
)
and
settings
.
SEGMENT_IO_LMS_KEY
:
tracking_context
=
tracker
.
get_tracker
()
.
resolve_context
()
analytics
.
track
(
self
.
user
.
id
,
event_name
,
{
# pylint: disable=E1101
'orderId'
:
self
.
id
,
# pylint: disable=E1101
'total'
:
str
(
self
.
total_cost
),
'currency'
:
self
.
currency
,
'products'
:
products
},
context
=
{
'Google Analytics'
:
{
'clientId'
:
tracking_context
.
get
(
'client_id'
)
}
})
except
Exception
:
# pylint: disable=W0703
# Capturing all exceptions thrown while tracking analytics events. We do not want
# an operation to fail because of an analytics event, so we will capture these
# errors in the logs.
log
.
exception
(
u'Unable to emit {event} event for user {user} and order {order}'
.
format
(
event
=
event_name
,
user
=
self
.
user
.
id
,
order
=
self
.
id
)
# pylint: disable=E1101
)
def
add_billing_details
(
self
,
company_name
=
''
,
company_contact_name
=
''
,
company_contact_email
=
''
,
recipient_name
=
''
,
recipient_email
=
''
,
customer_reference_number
=
''
):
...
...
@@ -549,6 +594,15 @@ class OrderItem(TimeStampedModel):
"""
return
''
@property
def
sku
(
self
):
"""Generate a SKU that uniquely defines the OrderItem
Uses properties of the OrderItem to distinguish it from other types of items.
"""
return
type
(
self
)
.
__name__
class
Invoice
(
models
.
Model
):
"""
...
...
@@ -880,6 +934,21 @@ class PaidCourseRegistration(OrderItem):
except
PaidCourseRegistrationAnnotation
.
DoesNotExist
:
return
u""
@property
def
sku
(
self
):
"""Generate a SKU that uniquely defines the OrderItem
Uses properties of the OrderItem to distinguish it from other types of items. The
associated course ID and SKU will be added to the SKU if available.
"""
sku
=
type
(
self
)
.
__name__
if
self
.
course_id
!=
CourseKeyField
.
Empty
:
sku
=
sku
+
u'-'
+
unicode
(
self
.
course_id
)
if
self
.
mode
:
sku
=
sku
+
u'-'
+
unicode
(
self
.
mode
)
return
sku
class
CourseRegCodeItem
(
OrderItem
):
"""
...
...
@@ -1001,6 +1070,21 @@ class CourseRegCodeItem(OrderItem):
except
CourseRegCodeItemAnnotation
.
DoesNotExist
:
return
u""
@property
def
sku
(
self
):
"""Generate a SKU that uniquely defines the OrderItem
Uses properties of the OrderItem to distinguish it from other types of items. The associated
course and mode will be added to the SKU if available.
"""
sku
=
type
(
self
)
.
__name__
if
self
.
course_id
!=
CourseKeyField
.
Empty
:
sku
=
sku
+
u'-'
+
unicode
(
self
.
course_id
)
if
self
.
mode
:
sku
=
sku
+
u'-'
+
unicode
(
self
.
mode
)
return
sku
class
CourseRegCodeItemAnnotation
(
models
.
Model
):
"""
...
...
@@ -1222,6 +1306,21 @@ class CertificateItem(OrderItem):
status
=
'purchased'
,
unit_cost__gt
=
(
CourseMode
.
min_course_price_for_verified_for_currency
(
course_id
,
'usd'
))))
.
count
()
@property
def
sku
(
self
):
"""Generate a SKU that uniquely defines the OrderItem
Uses properties of the OrderItem to distinguish it from other types of items. A certificate
mode will be added to the SKU, as well as the associated course.
"""
sku
=
type
(
self
)
.
__name__
if
self
.
course_id
!=
CourseKeyField
.
Empty
:
sku
=
sku
+
u'-'
+
unicode
(
self
.
course_id
)
if
self
.
mode
:
sku
=
sku
+
u'-'
+
unicode
(
self
.
mode
)
return
sku
class
DonationConfiguration
(
ConfigurationModel
):
"""Configure whether donations are enabled on the site."""
...
...
@@ -1369,3 +1468,16 @@ class Donation(OrderItem):
return
{
'receipt_has_donation_item'
:
True
,
}
@property
def
sku
(
self
):
"""Generate a SKU that uniquely defines the Donation type.
Uses properties of the OrderItem to distinguish it from other types of items. Donations
may be bound to a course, which will be added to the SKU if available.
"""
sku
=
type
(
self
)
.
__name__
if
self
.
course_id
!=
CourseKeyField
.
Empty
:
sku
=
sku
+
u'-'
+
unicode
(
self
.
course_id
)
return
sku
lms/djangoapps/shoppingcart/tests/test_models.py
View file @
66ff4e67
...
...
@@ -49,6 +49,11 @@ class OrderTest(ModuleStoreTestCase):
self
.
other_course_keys
.
append
(
CourseFactory
.
create
()
.
id
)
self
.
cost
=
40
# Add mock tracker for event testing.
patcher
=
patch
(
'shoppingcart.models.analytics'
)
self
.
mock_tracker
=
patcher
.
start
()
self
.
addCleanup
(
patcher
.
stop
)
def
test_get_cart_for_user
(
self
):
# create a cart
cart
=
Order
.
get_cart_for_user
(
user
=
self
.
user
)
...
...
@@ -148,6 +153,13 @@ class OrderTest(ModuleStoreTestCase):
for
item
in
cart
.
orderitem_set
.
all
():
self
.
assertEqual
(
item
.
status
,
'purchased'
)
@override_settings
(
SEGMENT_IO_LMS_KEY
=
"foobar"
,
FEATURES
=
{
'SEGMENT_IO_LMS'
:
True
,
'STORE_BILLING_INFO'
:
True
,
}
)
def
test_purchase
(
self
):
# This test is for testing the subclassing functionality of OrderItem, but in
# order to do this, we end up testing the specific functionality of
...
...
@@ -167,6 +179,27 @@ class OrderTest(ModuleStoreTestCase):
self
.
assertIn
(
unicode
(
cart
.
total_cost
),
mail
.
outbox
[
0
]
.
body
)
self
.
assertIn
(
item
.
additional_instruction_text
,
mail
.
outbox
[
0
]
.
body
)
# Assert Google Analytics event fired for purchase.
self
.
mock_tracker
.
track
.
assert_called_once_with
(
# pylint: disable=E1103
1
,
'Completed Order'
,
{
'orderId'
:
1
,
'currency'
:
'usd'
,
'total'
:
'40'
,
'products'
:
[
{
'sku'
:
u'CertificateItem-'
+
unicode
(
self
.
course_key
)
+
u'-honor'
,
'category'
:
'CertificateItem honor'
,
'price'
:
'40'
,
'id'
:
1
,
'quantity'
:
1
}
]
},
context
=
{
'Google Analytics'
:
{
'clientId'
:
None
}}
)
def
test_purchase_item_failure
(
self
):
# once again, we're testing against the specific implementation of
# CertificateItem
...
...
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