Commit 6a3d5eb0 by Usman Khalid

Do not refund student if a certificate entry already exists for them.

LMS-2920
parent d118fb8c
......@@ -36,13 +36,15 @@ from importlib import import_module
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from course_modes.models import CourseMode
import lms.lib.comment_client as cc
from util.query import use_read_replica_if_available
from xmodule_django.models import CourseKeyField, NoneToEmptyManager
from opaque_keys.edx.keys import CourseKey
from functools import total_ordering
from certificates.models import GeneratedCertificate
from course_modes.models import CourseMode
unenroll_done = Signal(providing_args=["course_enrollment"])
log = logging.getLogger(__name__)
AUDIT_LOG = logging.getLogger("audit")
......@@ -953,6 +955,11 @@ class CourseEnrollment(models.Model):
# (side-effects are bad)
if getattr(self, 'can_refund', None) is not None:
return True
# If the student has already been given a certificate they should not be refunded
if GeneratedCertificate.certificate_for_student(self.user, self.course_id) is not None:
return False
course_mode = CourseMode.mode_for_course(self.course_id, 'verified')
if course_mode is None:
return False
......
......@@ -30,6 +30,8 @@ from student.views import (process_survey_link, _cert_info,
change_enrollment, complete_course_mode_info)
from student.tests.factories import UserFactory, CourseModeFactory
from certificates.models import CertificateStatuses
from certificates.tests.factories import GeneratedCertificateFactory
import shoppingcart
log = logging.getLogger(__name__)
......@@ -216,6 +218,7 @@ class DashboardTest(TestCase):
self.assertFalse(course_mode_info['show_upsell'])
self.assertIsNone(course_mode_info['days_for_upsell'])
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_refundable(self):
verified_mode = CourseModeFactory.create(
course_id=self.course.id,
......@@ -231,6 +234,26 @@ class DashboardTest(TestCase):
verified_mode.save()
self.assertFalse(enrollment.refundable())
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_refundable_when_certificate_exists(self):
verified_mode = CourseModeFactory.create(
course_id=self.course.id,
mode_slug='verified',
mode_display_name='Verified',
expiration_datetime=datetime.now(pytz.UTC) + timedelta(days=1)
)
enrollment = CourseEnrollment.enroll(self.user, self.course.id, mode='verified')
self.assertTrue(enrollment.refundable())
generated_certificate = GeneratedCertificateFactory.create(
user=self.user,
course_id=self.course.id,
status=CertificateStatuses.downloadable,
mode='verified'
)
self.assertFalse(enrollment.refundable())
class EnrollInCourseTest(TestCase):
......
......@@ -80,6 +80,8 @@ class CertificateWhitelist(models.Model):
whitelist = models.BooleanField(default=0)
MODES = Choices('verified', 'honor', 'audit')
class GeneratedCertificate(models.Model):
user = models.ForeignKey(User)
course_id = CourseKeyField(max_length=255, blank=True, default=None)
......@@ -90,7 +92,6 @@ class GeneratedCertificate(models.Model):
key = models.CharField(max_length=32, blank=True, default='')
distinction = models.BooleanField(default=False)
status = models.CharField(max_length=32, default='unavailable')
MODES = Choices('verified', 'honor', 'audit')
mode = models.CharField(max_length=32, choices=MODES, default=MODES.honor)
name = models.CharField(blank=True, max_length=255)
created_date = models.DateTimeField(
......@@ -102,6 +103,18 @@ class GeneratedCertificate(models.Model):
class Meta:
unique_together = (('user', 'course_id'),)
@classmethod
def certificate_for_student(cls, student, course_id):
"""
This returns the certificate for a student for a particular course
or None if no such certificate exits.
"""
try:
return cls.objects.get(user=student, course_id=course_id)
except cls.DoesNotExist:
pass
return None
def certificate_status_for_student(student, course_id):
'''
......
from factory.django import DjangoModelFactory
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from certificates.models import GeneratedCertificate, CertificateStatuses, MODES
# Factories don't have __init__ methods, and are self documenting
# pylint: disable=W0232
class GeneratedCertificateFactory(DjangoModelFactory):
FACTORY_FOR = GeneratedCertificate
course_id = None
status = CertificateStatuses.unavailable
mode = MODES.honor
name = ''
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