diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py index f4146db743..2817c46065 100644 --- a/common/djangoapps/student/models.py +++ b/common/djangoapps/student/models.py @@ -710,6 +710,25 @@ class CourseEnrollment(models.Model): return enrollment + @classmethod + def get_enrollment(cls, user, course_key): + """Returns a CoursewareEnrollment object. + + Args: + user (User): The user associated with the enrollment. + course_id (CourseKey): The key of the course associated with the enrollment. + + Returns: + Course enrollment object or None + """ + try: + return CourseEnrollment.objects.get( + user=user, + course_id=course_key + ) + except cls.DoesNotExist: + return None + @classmethod def num_enrolled_in(cls, course_id): """ diff --git a/lms/djangoapps/shoppingcart/tests/test_views.py b/lms/djangoapps/shoppingcart/tests/test_views.py index 4cb9fc02e9..0651312764 100644 --- a/lms/djangoapps/shoppingcart/tests/test_views.py +++ b/lms/djangoapps/shoppingcart/tests/test_views.py @@ -1,6 +1,7 @@ """ Tests for Shopping Cart views """ +from collections import OrderedDict import pytz from urlparse import urlparse from decimal import Decimal @@ -46,6 +47,7 @@ from shoppingcart.processors import render_purchase_form_html from shoppingcart.admin import SoftDeleteCouponAdmin from shoppingcart.views import initialize_report from shoppingcart.tests.payment_fake import PaymentFakeView +from shoppingcart.processors.CyberSource2 import sign def mock_render_purchase_form_html(*args, **kwargs): @@ -1178,18 +1180,9 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): 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_tracker.emit.reset_mock() # pylint: disable=maybe-no-member 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) @@ -1204,17 +1197,6 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): self.assertIn(cert_item, context['shoppingcart_items'][1]) self.assertFalse(context['any_refunds']) - course_enrollment = CourseEnrollment.get_or_create_enrollment(self.user, self.course_key) - course_enrollment.emit_event('edx.course.enrollment.upgrade.succeeded') - self.mock_tracker.emit.assert_any_call( # pylint: disable=maybe-no-member - 'edx.course.enrollment.upgrade.succeeded', - { - 'user_id': course_enrollment.user.id, - 'course_id': course_enrollment.course_id.to_deprecated_string(), - '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_key) @@ -1272,6 +1254,61 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): self._assert_404(reverse('shoppingcart.views.reset_code_redemption', args=[]), use_post=True) self._assert_404(reverse('shoppingcart.views.billing_details', args=[])) + def test_upgrade_postpay_callback_emits_ga_event(self): + # Enroll as honor in the course with the current user. + + CourseEnrollment.enroll(self.user, self.course_key) + + # add verified mode + CourseMode.objects.create( + course_id=self.verified_course_key, + mode_slug="verified", + mode_display_name="verified cert", + min_price=self.cost + ) + + # Purchase a verified certificate + self.cart = Order.get_cart_for_user(self.user) + CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'verified') + self.cart.start_purchase() + + self.login_user() + # setting the attempting upgrade session value. + session = self.client.session + session['attempting_upgrade'] = True + session.save() + + ordered_params = OrderedDict([ + ('amount', self.cost), + ('currency', 'usd'), + ('transaction_type', 'sale'), + ('orderNumber', str(self.cart.id)), + ('access_key', '123456789'), + ('merchantID', 'edx'), + ('djch', '012345678912'), + ('orderPage_version', 2), + ('orderPage_serialNumber', '1234567890'), + ('profile_id', "00000001"), + ('reference_number', str(self.cart.id)), + ('locale', 'en'), + ('signed_date_time', '2014-08-18T13:59:31Z'), + ]) + + resp_params = PaymentFakeView.response_post_params(sign(ordered_params)) + self.assertTrue(self.client.session.get('attempting_upgrade')) + url = reverse('shoppingcart.views.postpay_callback') + self.client.post(url, resp_params, follow=True) + self.assertFalse(self.client.session.get('attempting_upgrade')) + + self.mock_tracker.emit.assert_any_call( # pylint: disable=maybe-no-member + 'edx.course.enrollment.upgrade.succeeded', + { + 'user_id': self.user.id, + 'course_id': self.verified_course_key.to_deprecated_string(), + 'mode': 'verified' + } + ) + class ReceiptRedirectTest(ModuleStoreTestCase): """Test special-case redirect from the receipt page. """ diff --git a/lms/djangoapps/shoppingcart/views.py b/lms/djangoapps/shoppingcart/views.py index dff6d15428..39633c01c6 100644 --- a/lms/djangoapps/shoppingcart/views.py +++ b/lms/djangoapps/shoppingcart/views.py @@ -691,6 +691,19 @@ def postpay_callback(request): # See if this payment occurred as part of the verification flow process # If so, send the user back into the flow so they have the option # to continue with verification. + + # Only orders where order_items.count() == 1 might be attempting to upgrade + attempting_upgrade = request.session.get('attempting_upgrade', False) + if attempting_upgrade: + if result['order'].has_items(CertificateItem): + course_id = result['order'].orderitem_set.all().select_subclasses("certificateitem")[0].course_id + if course_id: + course_enrollment = CourseEnrollment.get_enrollment(request.user, course_id) + if course_enrollment: + course_enrollment.emit_event(EVENT_NAME_USER_UPGRADED) + + request.session['attempting_upgrade'] = False + verify_flow_redirect = _get_verify_flow_redirect(result['order']) if verify_flow_redirect is not None: return verify_flow_redirect @@ -698,6 +711,7 @@ def postpay_callback(request): # Otherwise, send the user to the receipt page return HttpResponseRedirect(reverse('shoppingcart.views.show_receipt', args=[result['order'].id])) else: + request.session['attempting_upgrade'] = False return render_to_response('shoppingcart/error.html', {'order': result['order'], 'error_html': result['error_html']}) @@ -892,13 +906,6 @@ def _show_receipt_html(request, order): __, instructions = order.generate_receipt_instructions() order_type = getattr(order, 'order_type') - # 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 - recipient_list = [] total_registration_codes = None reg_code_info_list = []