Commit 83bfb178 by Will Daly

Use new-style course locators consistently when setting the donation amount in the session

Update devstack settings to use new CyberSource API
parent 9a554ec3
import ddt
import unittest import unittest
import decimal
import ddt
from django.conf import settings from django.conf import settings
from django.test.utils import override_settings from django.test.utils import override_settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -162,7 +163,7 @@ class CourseModeViewTest(ModuleStoreTestCase): ...@@ -162,7 +163,7 @@ class CourseModeViewTest(ModuleStoreTestCase):
POST_PARAMS_FOR_COURSE_MODE = { POST_PARAMS_FOR_COURSE_MODE = {
'audit': {'audit_mode': True}, 'audit': {'audit_mode': True},
'honor': {'honor-code': True}, 'honor': {'honor-code': True},
'verified': {'certificate_mode': True} 'verified': {'certificate_mode': True, 'contribution': '1.23'}
} }
# TODO (ECOM-16): Remove the auto-register flag once the AB-test completes # TODO (ECOM-16): Remove the auto-register flag once the AB-test completes
...@@ -203,3 +204,20 @@ class CourseModeViewTest(ModuleStoreTestCase): ...@@ -203,3 +204,20 @@ class CourseModeViewTest(ModuleStoreTestCase):
self.fail("Must provide a valid redirect URL name") self.fail("Must provide a valid redirect URL name")
self.assertRedirects(resp, redirect_url) self.assertRedirects(resp, redirect_url)
def test_remember_donation_for_course(self):
# Create the course modes
for mode in ('audit', 'honor', 'verified'):
CourseModeFactory(mode_slug=mode, course_id=self.course.id)
# Choose the mode (POST request)
choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['verified'])
# Expect that the contribution amount is stored in the user's session
self.assertIn('donation_for_course', self.client.session)
self.assertIn(unicode(self.course.id), self.client.session['donation_for_course'])
actual_amount = self.client.session['donation_for_course'][unicode(self.course.id)]
expected_amount = decimal.Decimal(self.POST_PARAMS_FOR_COURSE_MODE['verified']['contribution'])
self.assertEqual(actual_amount, expected_amount)
...@@ -16,7 +16,6 @@ from edxmako.shortcuts import render_to_response ...@@ -16,7 +16,6 @@ from edxmako.shortcuts import render_to_response
from course_modes.models import CourseMode from course_modes.models import CourseMode
from courseware.access import has_access from courseware.access import has_access
from student.models import CourseEnrollment from student.models import CourseEnrollment
from verify_student.models import SoftwareSecurePhotoVerification
from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.locations import SlashSeparatedCourseKey
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -92,7 +91,7 @@ class ChooseModeView(View): ...@@ -92,7 +91,7 @@ class ChooseModeView(View):
) )
donation_for_course = request.session.get("donation_for_course", {}) donation_for_course = request.session.get("donation_for_course", {})
chosen_price = donation_for_course.get(course_key, None) chosen_price = donation_for_course.get(unicode(course_key), None)
course = modulestore().get_course(course_key) course = modulestore().get_course(course_key)
context = { context = {
...@@ -164,7 +163,7 @@ class ChooseModeView(View): ...@@ -164,7 +163,7 @@ class ChooseModeView(View):
return self.get(request, course_id, error=error_msg) return self.get(request, course_id, error=error_msg)
donation_for_course = request.session.get("donation_for_course", {}) donation_for_course = request.session.get("donation_for_course", {})
donation_for_course[course_key] = amount_value donation_for_course[unicode(course_key)] = amount_value
request.session["donation_for_course"] = donation_for_course request.session["donation_for_course"] = donation_for_course
return redirect( return redirect(
......
...@@ -13,6 +13,7 @@ verify_student/start?course_id=MITx/6.002x/2013_Spring # create ...@@ -13,6 +13,7 @@ verify_student/start?course_id=MITx/6.002x/2013_Spring # create
import json import json
import mock import mock
import urllib import urllib
import decimal
from mock import patch, Mock from mock import patch, Mock
import pytz import pytz
from datetime import timedelta, datetime from datetime import timedelta, datetime
...@@ -98,6 +99,21 @@ class TestVerifyView(ModuleStoreTestCase): ...@@ -98,6 +99,21 @@ class TestVerifyView(ModuleStoreTestCase):
response = self.client.get(url, {'upgrade': "True"}) response = self.client.get(url, {'upgrade': "True"})
self.assertIn("You are upgrading your registration for", response.content) self.assertIn("You are upgrading your registration for", response.content)
def test_show_selected_contribution_amount(self):
# Set the donation amount in the client's session
session = self.client.session
session['donation_for_course'] = {
unicode(self.course_key): decimal.Decimal('1.23')
}
session.save()
# Retrieve the page
url = reverse('verify_student_verify', kwargs={"course_id": unicode(self.course_key)})
response = self.client.get(url)
# Expect that the user's contribution amount is shown on the page
self.assertContains(response, '1.23')
@override_settings(MODULESTORE=MODULESTORE_CONFIG) @override_settings(MODULESTORE=MODULESTORE_CONFIG)
class TestVerifiedView(ModuleStoreTestCase): class TestVerifiedView(ModuleStoreTestCase):
...@@ -126,6 +142,25 @@ class TestVerifiedView(ModuleStoreTestCase): ...@@ -126,6 +142,25 @@ class TestVerifiedView(ModuleStoreTestCase):
# Location should contains dashboard. # Location should contains dashboard.
self.assertIn('dashboard', response._headers.get('location')[1]) self.assertIn('dashboard', response._headers.get('location')[1])
def test_show_selected_contribution_amount(self):
# Configure the course to have a verified mode
for mode in ('audit', 'honor', 'verified'):
CourseModeFactory(mode_slug=mode, course_id=self.course.id)
# Set the donation amount in the client's session
session = self.client.session
session['donation_for_course'] = {
unicode(self.course_id): decimal.Decimal('1.23')
}
session.save()
# Retrieve the page
url = reverse('verify_student_verified', kwargs={"course_id": unicode(self.course_id)})
response = self.client.get(url)
# Expect that the user's contribution amount is shown on the page
self.assertContains(response, '1.23')
@override_settings(MODULESTORE=MODULESTORE_CONFIG) @override_settings(MODULESTORE=MODULESTORE_CONFIG)
class TestReverifyView(ModuleStoreTestCase): class TestReverifyView(ModuleStoreTestCase):
...@@ -548,6 +583,26 @@ class TestCreateOrder(ModuleStoreTestCase): ...@@ -548,6 +583,26 @@ class TestCreateOrder(ModuleStoreTestCase):
data = json.loads(response.content) data = json.loads(response.content)
self.assertEqual(data['override_custom_receipt_page'], "http://testserver/shoppingcart/postpay_callback/") self.assertEqual(data['override_custom_receipt_page'], "http://testserver/shoppingcart/postpay_callback/")
def test_create_order_set_donation_amount(self):
# Verify the student so we don't need to submit photos
self._verify_student()
# Create an order
url = reverse('verify_student_create_order')
params = {
'course_id': unicode(self.course.id),
'contribution': '1.23'
}
self.client.post(url, params)
# Verify that the client's session contains the new donation amount
self.assertIn('donation_for_course', self.client.session)
self.assertIn(unicode(self.course.id), self.client.session['donation_for_course'])
actual_amount = self.client.session['donation_for_course'][unicode(self.course.id)]
expected_amount = decimal.Decimal('1.23')
self.assertEqual(actual_amount, expected_amount)
def _verify_student(self): def _verify_student(self):
""" Simulate that the student's identity has already been verified. """ """ Simulate that the student's identity has already been verified. """
attempt = SoftwareSecurePhotoVerification.objects.create(user=self.user) attempt = SoftwareSecurePhotoVerification.objects.create(user=self.user)
......
...@@ -82,7 +82,7 @@ class VerifyView(View): ...@@ -82,7 +82,7 @@ class VerifyView(View):
if not current_mode: if not current_mode:
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
if course_id.to_deprecated_string() in request.session.get("donation_for_course", {}): if course_id.to_deprecated_string() in request.session.get("donation_for_course", {}):
chosen_price = request.session["donation_for_course"][course_id.to_deprecated_string()] chosen_price = request.session["donation_for_course"][unicode(course_id)]
else: else:
chosen_price = current_mode.min_price chosen_price = current_mode.min_price
...@@ -145,7 +145,7 @@ class VerifiedView(View): ...@@ -145,7 +145,7 @@ class VerifiedView(View):
if not current_mode: if not current_mode:
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
if course_id.to_deprecated_string() in request.session.get("donation_for_course", {}): if course_id.to_deprecated_string() in request.session.get("donation_for_course", {}):
chosen_price = request.session["donation_for_course"][course_id.to_deprecated_string()] chosen_price = request.session["donation_for_course"][unicode(course_id)]
else: else:
chosen_price = current_mode.min_price chosen_price = current_mode.min_price
...@@ -189,15 +189,15 @@ def create_order(request): ...@@ -189,15 +189,15 @@ def create_order(request):
course_id = request.POST['course_id'] course_id = request.POST['course_id']
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
donation_for_course = request.session.get('donation_for_course', {}) donation_for_course = request.session.get('donation_for_course', {})
current_donation = donation_for_course.get(course_id, decimal.Decimal(0)) current_donation = donation_for_course.get(unicode(course_id), decimal.Decimal(0))
contribution = request.POST.get("contribution", donation_for_course.get(course_id, 0)) contribution = request.POST.get("contribution", donation_for_course.get(unicode(course_id), 0))
try: try:
amount = decimal.Decimal(contribution).quantize(decimal.Decimal('.01'), rounding=decimal.ROUND_DOWN) amount = decimal.Decimal(contribution).quantize(decimal.Decimal('.01'), rounding=decimal.ROUND_DOWN)
except decimal.InvalidOperation: except decimal.InvalidOperation:
return HttpResponseBadRequest(_("Selected price is not valid number.")) return HttpResponseBadRequest(_("Selected price is not valid number."))
if amount != current_donation: if amount != current_donation:
donation_for_course[course_id] = amount donation_for_course[unicode(course_id)] = amount
request.session['donation_for_course'] = donation_for_course request.session['donation_for_course'] = donation_for_course
# prefer professional mode over verified_mode # prefer professional mode over verified_mode
......
...@@ -84,8 +84,15 @@ PIPELINE_SASS_ARGUMENTS = '--debug-info --require {proj_dir}/static/sass/bourbon ...@@ -84,8 +84,15 @@ PIPELINE_SASS_ARGUMENTS = '--debug-info --require {proj_dir}/static/sass/bourbon
FEATURES['AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'] = True FEATURES['AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'] = True
FEATURES['ENABLE_PAYMENT_FAKE'] = True FEATURES['ENABLE_PAYMENT_FAKE'] = True
for processor in CC_PROCESSOR.values(): CC_PROCESSOR_NAME = 'CyberSource2'
processor['PURCHASE_ENDPOINT'] = '/shoppingcart/payment_fake/' CC_PROCESSOR = {
'CyberSource2': {
"PURCHASE_ENDPOINT": '/shoppingcart/payment_fake/',
"SECRET_KEY": 'abcd123',
"ACCESS_KEY": 'abcd123',
"PROFILE_ID": 'edx',
}
}
##################################################################### #####################################################################
# See if the developer has any local overrides. # See if the developer has any local overrides.
......
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