Merge pull request #1744 from edx/flowerhack/feature/verified-cert-events
Events for entering verified flow & buying
This commit is contained in:
@@ -37,6 +37,7 @@ class ChooseModeView(View):
|
||||
|
||||
enrollment_mode = CourseEnrollment.enrollment_mode_for_user(request.user, course_id)
|
||||
upgrade = request.GET.get('upgrade', False)
|
||||
request.session['attempting_upgrade'] = upgrade
|
||||
|
||||
# verified users do not need to register or upgrade
|
||||
if enrollment_mode == 'verified':
|
||||
|
||||
@@ -35,9 +35,7 @@ from track import contexts
|
||||
from track.views import server_track
|
||||
from eventtracking import tracker
|
||||
|
||||
|
||||
unenroll_done = Signal(providing_args=["course_enrollment"])
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
AUDIT_LOG = logging.getLogger("audit")
|
||||
|
||||
|
||||
@@ -95,4 +95,4 @@ Feature: LMS.Verified certificates
|
||||
Then I see the course on my dashboard
|
||||
And I see that I am on the verified track
|
||||
And a "edx.course.enrollment.activated" server event is emitted
|
||||
|
||||
And a "edx.course.enrollment.upgrade.succeeded" server event is emitted
|
||||
|
||||
@@ -557,6 +557,7 @@ class CertificateItem(OrderItem):
|
||||
|
||||
"""
|
||||
super(CertificateItem, cls).add_to_order(order, course_id, cost, currency=currency)
|
||||
|
||||
course_enrollment = CourseEnrollment.get_or_create_enrollment(order.user, course_id)
|
||||
|
||||
# do some validation on the enrollment mode
|
||||
@@ -570,7 +571,7 @@ class CertificateItem(OrderItem):
|
||||
user=order.user,
|
||||
course_id=course_id,
|
||||
course_enrollment=course_enrollment,
|
||||
mode=mode
|
||||
mode=mode,
|
||||
)
|
||||
item.status = order.status
|
||||
item.qty = 1
|
||||
@@ -595,7 +596,6 @@ class CertificateItem(OrderItem):
|
||||
log.exception(
|
||||
"Could not submit verification attempt for enrollment {}".format(self.course_enrollment)
|
||||
)
|
||||
|
||||
self.course_enrollment.change_mode(self.mode)
|
||||
self.course_enrollment.activate()
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import StringIO
|
||||
from textwrap import dedent
|
||||
from boto.exception import BotoServerError # this is a super-class of SESError and catches connection errors
|
||||
|
||||
from mock import patch, MagicMock
|
||||
from mock import patch, MagicMock, sentinel
|
||||
from django.core import mail
|
||||
from django.conf import settings
|
||||
from django.db import DatabaseError
|
||||
@@ -425,12 +425,21 @@ class CertificateItemTest(ModuleStoreTestCase):
|
||||
min_price=self.cost)
|
||||
course_mode.save()
|
||||
|
||||
patcher = patch('student.models.server_track')
|
||||
self.mock_server_track = patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
crum_patcher = patch('student.models.crum.get_current_request')
|
||||
self.mock_get_current_request = crum_patcher.start()
|
||||
self.addCleanup(crum_patcher.stop)
|
||||
self.mock_get_current_request.return_value = sentinel.request
|
||||
|
||||
def test_existing_enrollment(self):
|
||||
CourseEnrollment.enroll(self.user, self.course_id)
|
||||
cart = Order.get_cart_for_user(user=self.user)
|
||||
CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified')
|
||||
# verify that we are still enrolled
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_id))
|
||||
self.mock_server_track.reset_mock()
|
||||
cart.purchase()
|
||||
enrollment = CourseEnrollment.objects.get(user=self.user, course_id=self.course_id)
|
||||
self.assertEquals(enrollment.mode, u'verified')
|
||||
|
||||
@@ -20,7 +20,7 @@ from student.models import CourseEnrollment
|
||||
from course_modes.models import CourseMode
|
||||
from edxmako.shortcuts import render_to_response
|
||||
from shoppingcart.processors import render_purchase_form_html
|
||||
from mock import patch, Mock
|
||||
from mock import patch, Mock, sentinel
|
||||
|
||||
|
||||
def mock_render_purchase_form_html(*args, **kwargs):
|
||||
@@ -39,6 +39,8 @@ postpay_mock = Mock()
|
||||
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
|
||||
class ShoppingCartViewsTests(ModuleStoreTestCase):
|
||||
def setUp(self):
|
||||
patcher = patch('student.models.server_track')
|
||||
self.mock_server_track = patcher.start()
|
||||
self.user = UserFactory.create()
|
||||
self.user.set_password('password')
|
||||
self.user.save()
|
||||
@@ -53,6 +55,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
|
||||
self.verified_course_id = 'org/test/Test_Course'
|
||||
CourseFactory.create(org='org', number='test', run='course1', display_name='Test Course')
|
||||
self.cart = Order.get_cart_for_user(self.user)
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
def login_user(self):
|
||||
self.client.login(username=self.user.username, password="password")
|
||||
@@ -83,6 +86,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
|
||||
|
||||
def test_add_course_to_cart_success(self):
|
||||
self.login_user()
|
||||
reverse('shoppingcart.views.add_course_to_cart', args=[self.course_id])
|
||||
resp = self.client.post(reverse('shoppingcart.views.add_course_to_cart', args=[self.course_id]))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertTrue(PaidCourseRegistration.contained_in_order(self.cart, self.course_id))
|
||||
@@ -202,6 +206,55 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
|
||||
self.assertIn(cert_item, context['order_items'])
|
||||
self.assertFalse(context['any_refunds'])
|
||||
|
||||
@patch('shoppingcart.views.render_to_response', render_mock)
|
||||
def test_show_receipt_success_with_upgrade(self):
|
||||
|
||||
reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_id)
|
||||
cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_id, self.cost, 'honor')
|
||||
self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
|
||||
|
||||
self.login_user()
|
||||
|
||||
# When we come from the upgrade flow, we'll have a session variable showing that
|
||||
s = self.client.session
|
||||
s['attempting_upgrade'] = True
|
||||
s.save()
|
||||
|
||||
self.mock_server_track.reset_mock()
|
||||
resp = self.client.get(reverse('shoppingcart.views.show_receipt', args=[self.cart.id]))
|
||||
|
||||
# Once they've upgraded, they're no longer *attempting* to upgrade
|
||||
attempting_upgrade = self.client.session.get('attempting_upgrade', False)
|
||||
self.assertFalse(attempting_upgrade)
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertIn('FirstNameTesting123', resp.content)
|
||||
self.assertIn('80.00', resp.content)
|
||||
|
||||
|
||||
((template, context), _) = render_mock.call_args
|
||||
|
||||
# When we come from the upgrade flow, we get these context variables
|
||||
|
||||
|
||||
self.assertEqual(template, 'shoppingcart/receipt.html')
|
||||
self.assertEqual(context['order'], self.cart)
|
||||
self.assertIn(reg_item, context['order_items'])
|
||||
self.assertIn(cert_item, context['order_items'])
|
||||
self.assertFalse(context['any_refunds'])
|
||||
|
||||
course_enrollment = CourseEnrollment.get_or_create_enrollment(self.user, self.course_id)
|
||||
course_enrollment.emit_event('edx.course.enrollment.upgrade.succeeded')
|
||||
self.mock_server_track.assert_any_call(
|
||||
None,
|
||||
'edx.course.enrollment.upgrade.succeeded',
|
||||
{
|
||||
'user_id': course_enrollment.user.id,
|
||||
'course_id': course_enrollment.course_id,
|
||||
'mode': course_enrollment.mode
|
||||
}
|
||||
)
|
||||
|
||||
@patch('shoppingcart.views.render_to_response', render_mock)
|
||||
def test_show_receipt_success_refund(self):
|
||||
reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_id)
|
||||
|
||||
@@ -12,11 +12,14 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from edxmako.shortcuts import render_to_response
|
||||
from .models import Order, PaidCourseRegistration, OrderItem
|
||||
from student.models import CourseEnrollment
|
||||
from .processors import process_postpay_callback, render_purchase_form_html
|
||||
from .exceptions import ItemAlreadyInCartException, AlreadyEnrolledInCourseException, CourseDoesNotExistException
|
||||
|
||||
log = logging.getLogger("shoppingcart")
|
||||
|
||||
EVENT_NAME_USER_UPGRADED = 'edx.course.enrollment.upgrade.succeeded'
|
||||
|
||||
|
||||
@require_POST
|
||||
def add_course_to_cart(request, course_id):
|
||||
@@ -124,6 +127,13 @@ def show_receipt(request, ordernum):
|
||||
receipt_template = order_items[0].single_item_receipt_template
|
||||
context.update(order_items[0].single_item_receipt_context)
|
||||
|
||||
# Only orders where order_items.count() == 1 might be attempting to upgrade
|
||||
attempting_upgrade = request.session.get('attempting_upgrade', False)
|
||||
if attempting_upgrade:
|
||||
course_enrollment = CourseEnrollment.get_or_create_enrollment(request.user, order_items[0].course_id)
|
||||
course_enrollment.emit_event(EVENT_NAME_USER_UPGRADED)
|
||||
request.session['attempting_upgrade'] = False
|
||||
|
||||
return render_to_response(receipt_template, context)
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<%!
|
||||
from django.core.urlresolvers import reverse
|
||||
import waffle
|
||||
%>
|
||||
<%inherit file="main.html" />
|
||||
|
||||
@@ -22,6 +23,21 @@
|
||||
$(this).closest('.message.is-expandable').toggleClass('is-expanded');
|
||||
}
|
||||
|
||||
$("#upgrade-to-verified").click(function(event) {
|
||||
user = $(event.target).data("user");
|
||||
course = $(event.target).data("course-id");
|
||||
Logger.log('edx.course.enrollment.upgrade.clicked', [user, course], null);
|
||||
% if waffle.flag_is_active(request, 'alternate_upsell_copy'):
|
||||
analytics.track("Clicked on Alternate Upsell Copy", {
|
||||
course: course
|
||||
});
|
||||
% else:
|
||||
analytics.track("Clicked on Regular Upsell Copy", {
|
||||
course: course
|
||||
});
|
||||
% endif
|
||||
});
|
||||
|
||||
$(".email-settings").click(function(event) {
|
||||
$("#email_settings_course_id").val( $(event.target).data("course-id") );
|
||||
$("#email_settings_course_number").text( $(event.target).data("course-number") );
|
||||
|
||||
@@ -61,13 +61,17 @@
|
||||
<%include file='_dashboard_certificate_information.html' args='cert_status=cert_status,course=course, enrollment=enrollment'/>
|
||||
% endif
|
||||
|
||||
%if course_mode_info['show_upsell']:
|
||||
% if course_mode_info['show_upsell']:
|
||||
<div class="message message-upsell has-actions is-expandable is-shown">
|
||||
|
||||
<div class="wrapper-tip">
|
||||
<h4 class="message-title">
|
||||
<i class="icon-caret-down ui-toggle-expansion"></i>
|
||||
<span class="value">${_("Challenge Yourself!")}</span>
|
||||
% if waffle.flag_is_active(request, 'alternate_upsell_copy'):
|
||||
<span class="value">${_("Document your accomplishment!")}</span>
|
||||
% else:
|
||||
<span class="value">${_("Challenge Yourself!")}</span>
|
||||
% endif
|
||||
</h4>
|
||||
<p class="message-copy">${_("Take this course as an ID-verified student.")}</p>
|
||||
</div>
|
||||
@@ -80,7 +84,7 @@
|
||||
<a class="action action-upgrade" href="${reverse('course_modes_choose', kwargs={'course_id': course.id})}?upgrade=True">
|
||||
<img class="deco-graphic" src="${static.url('images/vcert-ribbon-s.png')}" alt="ID Verified Ribbon/Badge">
|
||||
<span class="wrapper-copy">
|
||||
<span class="copy">${_("Upgrade to Verified Track")}</span>
|
||||
<span class="copy" id="upgrade-to-verified" data-course-id="${course.id}" data-user="${user.username}">${_("Upgrade to Verified Track")}</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user