Commit 878eaa9f by Muhammad Shoaib Committed by Chris Dodge

added django admin pages for Coupon Table

added the suggested changes by cdonge
parent 4333e539
...@@ -2,6 +2,50 @@ ...@@ -2,6 +2,50 @@
Allows django admin site to add PaidCourseRegistrationAnnotations Allows django admin site to add PaidCourseRegistrationAnnotations
""" """
from ratelimitbackend import admin from ratelimitbackend import admin
from shoppingcart.models import PaidCourseRegistrationAnnotation from shoppingcart.models import PaidCourseRegistrationAnnotation, Coupon
class SoftDeleteCouponAdmin(admin.ModelAdmin):
"""
Admin for the Coupon table.
soft-delete on the coupons
"""
fields = ('code', 'description', 'course_id', 'percentage_discount', 'created_by', 'created_at', 'is_active')
raw_id_fields = ("created_by",)
readonly_fields = ('created_at',)
actions = ['really_delete_selected']
def queryset(self, request):
""" Returns a QuerySet of all model instances that can be edited by the
admin site. This is used by changelist_view. """
# Default: qs = self.model._default_manager.get_active_coupons_query_set()
# Queryset with all the coupons including the soft-deletes: qs = self.model._default_manager.get_query_set()
query_string = self.model._default_manager.get_active_coupons_query_set() # pylint: disable=W0212
return query_string
def get_actions(self, request):
actions = super(SoftDeleteCouponAdmin, self).get_actions(request)
del actions['delete_selected']
return actions
def really_delete_selected(self, request, queryset):
"""override the default behavior of selected delete method"""
for obj in queryset:
obj.is_active = False
obj.save()
if queryset.count() == 1:
message_bit = "1 coupon entry was"
else:
message_bit = "%s coupon entries were" % queryset.count()
self.message_user(request, "%s successfully deleted." % message_bit)
def delete_model(self, request, obj):
"""override the default behavior of single instance of model delete method"""
obj.is_active = False
obj.save()
really_delete_selected.short_description = "Delete s selected entries"
admin.site.register(PaidCourseRegistrationAnnotation) admin.site.register(PaidCourseRegistrationAnnotation)
admin.site.register(Coupon, SoftDeleteCouponAdmin)
...@@ -337,6 +337,22 @@ class RegistrationCodeRedemption(models.Model): ...@@ -337,6 +337,22 @@ class RegistrationCodeRedemption(models.Model):
redeemed_at = models.DateTimeField(default=datetime.now(pytz.utc), null=True) redeemed_at = models.DateTimeField(default=datetime.now(pytz.utc), null=True)
class SoftDeleteCouponManager(models.Manager):
""" Use this manager to get objects that have a is_active=True """
def get_active_coupons_query_set(self):
"""
filter the is_active = True Coupons only
"""
return super(SoftDeleteCouponManager, self).get_query_set().filter(is_active=True)
def get_query_set(self):
"""
get all the coupon objects
"""
return super(SoftDeleteCouponManager, self).get_query_set()
class Coupon(models.Model): class Coupon(models.Model):
""" """
This table contains coupon codes This table contains coupon codes
...@@ -350,6 +366,11 @@ class Coupon(models.Model): ...@@ -350,6 +366,11 @@ class Coupon(models.Model):
created_at = models.DateTimeField(default=datetime.now(pytz.utc)) created_at = models.DateTimeField(default=datetime.now(pytz.utc))
is_active = models.BooleanField(default=True) is_active = models.BooleanField(default=True)
def __unicode__(self):
return "[Coupon] code: {} course: {}".format(self.code, self.course_id)
objects = SoftDeleteCouponManager()
class CouponRedemption(models.Model): class CouponRedemption(models.Model):
""" """
......
""" """
Tests for Shopping Cart views Tests for Shopping Cart views
""" """
from django.http import HttpRequest
from urlparse import urlparse from urlparse import urlparse
from django.conf import settings from django.conf import settings
...@@ -8,18 +9,21 @@ from django.test import TestCase ...@@ -8,18 +9,21 @@ from django.test import TestCase
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
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.contrib.auth.models import Group from django.contrib.admin.sites import AdminSite
from django.contrib.auth.models import Group, User
from django.contrib.messages.storage.fallback import FallbackStorage
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
from shoppingcart.views import _can_download_report, _get_date_from_str from shoppingcart.views import _can_download_report, _get_date_from_str
from shoppingcart.models import Order, CertificateItem, PaidCourseRegistration, Coupon from shoppingcart.models import Order, CertificateItem, PaidCourseRegistration, Coupon
from student.tests.factories import UserFactory from student.tests.factories import UserFactory, AdminFactory
from student.models import CourseEnrollment from student.models import CourseEnrollment
from course_modes.models import CourseMode from course_modes.models import CourseMode
from edxmako.shortcuts import render_to_response from edxmako.shortcuts import render_to_response
from shoppingcart.processors import render_purchase_form_html from shoppingcart.processors import render_purchase_form_html
from shoppingcart.admin import SoftDeleteCouponAdmin
from mock import patch, Mock from mock import patch, Mock
from shoppingcart.views import initialize_report from shoppingcart.views import initialize_report
from decimal import Decimal from decimal import Decimal
...@@ -143,6 +147,39 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): ...@@ -143,6 +147,39 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
self.assertEqual(resp.status_code, 400) self.assertEqual(resp.status_code, 400)
self.assertIn("Coupon '{0}' already used.".format(self.coupon_code), resp.content) self.assertIn("Coupon '{0}' already used.".format(self.coupon_code), resp.content)
def test_soft_delete_coupon(self): # pylint: disable=E1101
self.add_coupon(self.course_key, True)
coupon = Coupon(code='TestCode', description='testing', course_id=self.course_key,
percentage_discount=12, created_by=self.user, is_active=True)
coupon.save()
self.assertEquals(coupon.__unicode__(), '[Coupon] code: TestCode course: MITx/999/Robot_Super_Course')
admin = User.objects.create_user('Mark', 'admin+courses@edx.org', 'foo')
admin.is_staff = True
get_coupon = Coupon.objects.get(id=1)
request = HttpRequest()
request.user = admin
setattr(request, 'session', 'session') # pylint: disable=E1101
messages = FallbackStorage(request) # pylint: disable=E1101
setattr(request, '_messages', messages) # pylint: disable=E1101
coupon_admin = SoftDeleteCouponAdmin(Coupon, AdminSite())
test_query_set = coupon_admin.queryset(request)
test_actions = coupon_admin.get_actions(request)
self.assertTrue('really_delete_selected' in test_actions['really_delete_selected'])
self.assertEqual(get_coupon.is_active, True)
coupon_admin.really_delete_selected(request, test_query_set) # pylint: disable=E1101
for coupon in test_query_set:
self.assertEqual(coupon.is_active, False)
coupon_admin.delete_model(request, get_coupon) # pylint: disable=E1101
self.assertEqual(get_coupon.is_active, False)
coupon = Coupon(code='TestCode123', description='testing123', course_id=self.course_key,
percentage_discount=22, created_by=self.user, is_active=True)
coupon.save()
test_query_set = coupon_admin.queryset(request)
coupon_admin.really_delete_selected(request, test_query_set) # pylint: disable=E1101
for coupon in test_query_set:
self.assertEqual(coupon.is_active, False)
@patch('shoppingcart.views.log.debug') @patch('shoppingcart.views.log.debug')
def test_non_existing_coupon_redemption_on_removing_item(self, debug_log): def test_non_existing_coupon_redemption_on_removing_item(self, debug_log):
......
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