This will remove imports from __future__ that are no longer needed. https://docs.python.org/3.5/library/2to3.html#2to3fixer-future
143 lines
4.8 KiB
Python
143 lines
4.8 KiB
Python
"""
|
|
Views for manual refunds in the student support UI.
|
|
|
|
This interface is used by the support team to track refunds
|
|
entered manually in CyberSource (our payment gateway).
|
|
|
|
DEPRECATION WARNING:
|
|
We are currently in the process of replacing lms/djangoapps/shoppingcart
|
|
with an E-Commerce service that supports automatic refunds. Once that
|
|
transition is complete, we can remove this view.
|
|
|
|
"""
|
|
|
|
|
|
import logging
|
|
|
|
from django import forms
|
|
from django.contrib import messages
|
|
from django.contrib.auth.models import User
|
|
from django.http import HttpResponseRedirect
|
|
from django.utils.decorators import method_decorator
|
|
from django.utils.translation import ugettext as _
|
|
from django.views.generic.edit import FormView
|
|
|
|
from openedx.core.lib.courses import clean_course_id
|
|
from student.models import CourseEnrollment
|
|
from support.decorators import require_support_permission
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class RefundForm(forms.Form):
|
|
"""
|
|
Form for manual refunds
|
|
"""
|
|
user = forms.EmailField(label=_("Email Address"), required=True)
|
|
course_id = forms.CharField(label=_("Course ID"), required=True)
|
|
confirmed = forms.CharField(widget=forms.HiddenInput, required=False)
|
|
|
|
def clean_user(self):
|
|
"""
|
|
validate user field
|
|
"""
|
|
user_email = self.cleaned_data['user']
|
|
try:
|
|
user = User.objects.get(email=user_email)
|
|
except User.DoesNotExist:
|
|
raise forms.ValidationError(_("User not found"))
|
|
return user
|
|
|
|
def clean_course_id(self):
|
|
"""
|
|
Validate the course id
|
|
"""
|
|
return clean_course_id(self)
|
|
|
|
def clean(self):
|
|
"""
|
|
clean form
|
|
"""
|
|
user, course_id = self.cleaned_data.get('user'), self.cleaned_data.get('course_id')
|
|
if user and course_id:
|
|
self.cleaned_data['enrollment'] = enrollment = CourseEnrollment.get_or_create_enrollment(user, course_id)
|
|
if enrollment.refundable():
|
|
msg = _(u"Course {course_id} not past the refund window.").format(course_id=course_id)
|
|
raise forms.ValidationError(msg)
|
|
try:
|
|
self.cleaned_data['cert'] = enrollment.certificateitem_set.filter(
|
|
mode='verified',
|
|
status='purchased'
|
|
)[0]
|
|
except IndexError:
|
|
msg = _(u"No order found for {user} in course {course_id}").format(user=user, course_id=course_id)
|
|
raise forms.ValidationError(msg)
|
|
return self.cleaned_data
|
|
|
|
def is_valid(self):
|
|
"""
|
|
returns whether form is valid
|
|
"""
|
|
is_valid = super(RefundForm, self).is_valid()
|
|
if is_valid and self.cleaned_data.get('confirmed') != 'true':
|
|
# this is a two-step form: first look up the data, then issue the refund.
|
|
# first time through, set the hidden "confirmed" field to true and then redisplay the form
|
|
# second time through, do the unenrollment/refund.
|
|
data = dict(list(self.data.items()))
|
|
self.cleaned_data['confirmed'] = data['confirmed'] = 'true'
|
|
self.data = data
|
|
is_valid = False
|
|
return is_valid
|
|
|
|
|
|
class RefundSupportView(FormView):
|
|
"""
|
|
Refund form view
|
|
"""
|
|
template_name = 'support/refund.html'
|
|
form_class = RefundForm
|
|
success_url = '/support/'
|
|
|
|
@method_decorator(require_support_permission)
|
|
def dispatch(self, *args, **kwargs):
|
|
return super(RefundSupportView, self).dispatch(*args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""
|
|
extra context data to add to page
|
|
"""
|
|
kwargs = super(RefundSupportView, self).get_context_data(**kwargs)
|
|
form = getattr(kwargs['form'], 'cleaned_data', {})
|
|
if form.get('confirmed') == 'true':
|
|
kwargs['cert'] = form.get('cert')
|
|
kwargs['enrollment'] = form.get('enrollment')
|
|
return kwargs
|
|
|
|
def form_valid(self, form):
|
|
"""
|
|
unenrolls student, issues refund
|
|
"""
|
|
user = form.cleaned_data['user']
|
|
course_id = form.cleaned_data['course_id']
|
|
enrollment = form.cleaned_data['enrollment']
|
|
cert = form.cleaned_data['cert']
|
|
enrollment.can_refund = True
|
|
enrollment.update_enrollment(is_active=False)
|
|
|
|
log.info(u"%s manually refunded %s %s", self.request.user, user, course_id)
|
|
messages.success(
|
|
self.request,
|
|
_(u"Unenrolled {user} from {course_id}").format(
|
|
user=user,
|
|
course_id=course_id
|
|
)
|
|
)
|
|
messages.success(
|
|
self.request,
|
|
_(u"Refunded {cost} for order id {order_id}").format(
|
|
cost=cert.unit_cost,
|
|
order_id=cert.order.id
|
|
)
|
|
)
|
|
return HttpResponseRedirect('/support/refund/')
|