Response to Dave & Diana's CR
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -11,3 +11,4 @@ class CourseModeFactory(DjangoModelFactory):
|
||||
mode_display_name = 'audit course'
|
||||
min_price = 0
|
||||
currency = 'usd'
|
||||
expiration_date = None
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'):
|
||||
|
||||
Reference in New Issue
Block a user