Response to Dave & Diana's CR

This commit is contained in:
Julia Hansbrough
2013-10-30 13:33:34 +00:00
parent bf916b6624
commit 7ab8142e82
11 changed files with 165 additions and 139 deletions

View File

@@ -11,7 +11,6 @@ from django.db.models import Q
Mode = namedtuple('Mode', ['slug', 'name', 'min_price', 'suggested_prices', 'currency', 'expiration_date'])
class CourseMode(models.Model):
"""
We would like to offer a course in a variety of modes.
@@ -72,8 +71,8 @@ class CourseMode(models.Model):
@classmethod
def modes_for_course_dict(cls, course_id):
"""
Returns the modes for a particular course as a dictionary with
the mode slug as the key
Returns the non-expired modes for a particular course as a
dictionary with the mode slug as the key
"""
return {mode.slug: mode for mode in cls.modes_for_course(course_id)}
@@ -82,6 +81,8 @@ class CourseMode(models.Model):
"""
Returns the mode for the course corresponding to mode_slug.
Returns only non-expired modes.
If this particular mode is not set for the course, returns None
"""
modes = cls.modes_for_course(course_id)
@@ -95,7 +96,8 @@ class CourseMode(models.Model):
@classmethod
def min_course_price_for_currency(cls, course_id, currency):
"""
Returns the minimum price of the course in the appropriate currency over all the course's modes.
Returns the minimum price of the course in the appropriate currency over all the course's
non-expired modes.
If there is no mode found, will return the price of DEFAULT_MODE, which is 0
"""
modes = cls.modes_for_course(course_id)

View File

@@ -11,3 +11,4 @@ class CourseModeFactory(DjangoModelFactory):
mode_display_name = 'audit course'
min_price = 0
currency = 'usd'
expiration_date = None

View File

@@ -23,14 +23,13 @@ from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
import django.dispatch
from django.forms import ModelForm, forms
import comment_client as cc
from pytz import UTC
import django.dispatch
verified_unenroll_done = django.dispatch.Signal(providing_args=["user", "user_email", "course_id"])
unenroll_done = django.dispatch.Signal(providing_args=["course_enrollment"])
log = logging.getLogger(__name__)
AUDIT_LOG = logging.getLogger("audit")
@@ -823,10 +822,12 @@ class CourseEnrollment(models.Model):
`course_id` is our usual course_id string (e.g. "edX/Test101/2013_Fall)
"""
refund_error = "Refund Error"
try:
record = CourseEnrollment.objects.get(user=user, course_id=course_id)
record.is_active = False
record.save()
unenroll_done.send(sender=cls, course_enrollment=record)
except cls.DoesNotExist:
err_msg = u"Tried to unenroll student {} from {} but they were not enrolled"
log.error(err_msg.format(user, course_id))

View File

@@ -36,8 +36,6 @@ from student.tests.test_email import mock_render_to_string
import shoppingcart
from course_modes.models import CourseMode
COURSE_1 = 'edX/toy/2012_Fall'
COURSE_2 = 'edx/full/6.002_Spring_2012'
@@ -424,50 +422,3 @@ class PaidRegistrationTest(ModuleStoreTestCase):
self.assertEqual(response.content, reverse('shoppingcart.views.show_cart'))
self.assertTrue(shoppingcart.models.PaidCourseRegistration.contained_in_order(
shoppingcart.models.Order.get_cart_for_user(self.user), self.course.id))
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
class RefundUnenrollmentTests(ModuleStoreTestCase):
"""
Tests views for unenrollment with refunds
"""
# test data
COURSE_SLUG = "100"
COURSE_NAME = "test_course"
COURSE_ORG = "EDX"
def setUp(self):
# Create course, user, and enroll them as a verified student
self.user = UserFactory.create()
self.course_id = "org/test/Test_Course"
self.cost = 40
CourseFactory.create(org='org', number='test', run='course', display_name='Test Course')
course_mode = CourseMode(course_id=self.course_id,
mode_slug="honor",
mode_display_name="honor cert",
min_price=self.cost)
course_mode.save()
course_mode = CourseMode(course_id=self.course_id,
mode_slug="verified",
mode_display_name="verified cert",
min_price=self.cost)
course_mode.save()
self.req_factory = RequestFactory()
course_enrollment = CourseEnrollment.create_enrollment(self.user, self.course_id, 'verified', is_active=True)
course_enrollment.save()
# Student is verified and paid; we should be able to refund them
def test_unenroll_and_refund(self):
request = self.req_factory.post(reverse('change_enrollment'), {'course_id': self.course_id, 'enrollment_action': 'unenroll'})
request.user = self.user
response = change_enrollment(request)
self.assertEqual(response.status_code, 200)
self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_id))
def test_unenroll_but_no_course(self):
request = self.req_factory.post(reverse('change_enrollment'), {'course_id': 'non/existent/course', 'enrollment_action': 'unenroll'})
request.user = self.user
response = change_enrollment(request)
self.assertEqual(response.status_code, 400)

View File

@@ -43,7 +43,6 @@ from student.models import (
TestCenterRegistration, TestCenterRegistrationForm, PendingNameChange,
PendingEmailChange, CourseEnrollment, unique_id_for_user,
get_testcenter_registration, CourseEnrollmentAllowed, UserStanding,
verified_unenroll_done
)
from student.forms import PasswordResetFormNoActive
@@ -472,29 +471,18 @@ def change_enrollment(request):
elif action == "unenroll":
try:
course = course_from_id(course_id)
enrollment_mode = CourseEnrollment.enrollment_mode_for_user(user, course_id)
# did they sign up for verified certs?
if(enrollment_mode == 'verified'):
# If the user is allowed a refund, do so
if has_access(user, course, 'refund'):
# triggers the callback to mark the certificate as refunded
verified_unenroll_done.send(sender=request, user=user, user_email=user.email, course_id=course_id)
CourseEnrollment.unenroll(user, course_id)
org, course_num, run = course_id.split("/")
dog_stats_api.increment(
"common.student.unenrollment",
tags=["org:{0}".format(org),
"course:{0}".format(course_num),
"run:{0}".format(run)]
)
return HttpResponse()
CourseEnrollment.enrollment_mode_for_user(user, course_id)
except CourseEnrollment.DoesNotExist:
return HttpResponseBadRequest(_("You are not enrolled in this course"))
except ItemNotFoundError:
log.warning("User {0} tried to unenroll from non-existent course {1}".format(user.username, course_id))
return HttpResponseBadRequest(_("Course id is invalid"))
CourseEnrollment.unenroll(user, course_id)
org, course_num, run = course_id.split("/")
dog_stats_api.increment(
"common.student.unenrollment",
tags=["org:{0}".format(org),
"course:{0}".format(course_num),
"run:{0}".format(run)]
)
return HttpResponse()
else:
return HttpResponseBadRequest(_("Enrollment action is invalid"))
@@ -909,7 +897,7 @@ def create_account(request, post_override=None):
subject = ''.join(subject.splitlines())
message = render_to_string('emails/activation_email.txt', d)
# dont send email if we are doing load testing or random user generation for some reason
# don't send email if we are doing load testing or random user generation for some reason
if not (settings.MITX_FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING')):
try:
if settings.MITX_FEATURES.get('REROUTE_ACTIVATION_EMAIL'):