Механизм расчета сидок и покрытие тестами

remotes/origin/feature/discounts-12-9-19
Ivan Kazionov 6 years ago
parent bef692e71d
commit db0bbdf21f
  1. 37
      apps/payment/models.py
  2. 335
      apps/payment/tests/tests_models.py
  3. 19
      project/tests/factories.py

@ -3,12 +3,13 @@ from decimal import Decimal
import arrow
import short_url
from django.db.models.functions import Coalesce
from paymentwall import Pingback
from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager
from django.db.models import Func, F
from django.db.models import Func, F, Q, Max
from django.db import models
from django.contrib.auth import get_user_model
from django.contrib.postgres.fields import ArrayField, JSONField
@ -423,6 +424,38 @@ class UserGiftCertificate(models.Model):
return short_url.encode_url(self.id) if self.id else None
class DiscountManager(models.Manager):
def get_actual_discounts(self, user=None):
now_dt = now()
qs = self.filter(start__lte=now_dt, end__gte=now_dt, is_active=True, promo_id__isnull=True)
if user:
qs = qs.filter(Q(client=user) | Q(client__isnull=True))
else:
qs = qs.filter(client__isnull=True)
return qs
def get_courses_discounts(self, user=None, course=None):
actual_discounts = self.get_actual_discounts(user=user)
all_courses_max_discount = actual_discounts.filter(product=Discount.PRODUCT_ALL_COURSES)\
.aggregate(max_discount=Max('value'))
if course:
actual_discounts = actual_discounts.filter(course=course)
courses_max_discounts = actual_discounts.filter(product=Discount.PRODUCT_ONE_COURSE).values('course')\
.annotate(max_discount=Max('value'))
return all_courses_max_discount, courses_max_discounts
def get_packages_discounts(self, user=None, package=None):
actual_discounts = self.get_actual_discounts(user=user)
all_packages_max_discount = actual_discounts.filter(product=Discount.PRODUCT_ALL_PACKAGES) \
.aggregate(max_discount=Max('value'))
if package:
actual_discounts = actual_discounts.filter(package=package)
packages_max_discounts = actual_discounts.filter(product=Discount.PRODUCT_ONE_PACKAGE).values('package') \
.annotate(max_discount=Max('value'))
return all_packages_max_discount, packages_max_discounts
class Discount(models.Model):
PRODUCT_ALL_COURSES = 0
PRODUCT_ALL_PACKAGES = 1
@ -467,6 +500,8 @@ class Discount(models.Model):
author = models.ForeignKey(User, verbose_name='Автор', null=True, blank=True, related_name='author_discounts',
on_delete=models.CASCADE)
objects = DiscountManager()
def __str__(self):
return self.name

@ -1,3 +1,336 @@
from datetime import timedelta
from django.test import TestCase
from django.utils.timezone import now
from apps.payment.models import Discount
from project.tests.factories import CourseFactory, DiscountFactory, UserFactory, PackageFactory
class DiscountForCoursesModelTestCase(TestCase):
def setUp(self):
self.user = UserFactory.create()
def test_discounts_for_courses_without_user(self):
course_1 = CourseFactory.create()
course_2 = CourseFactory.create()
course_3 = CourseFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course_1,
product=Discount.PRODUCT_ONE_COURSE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course_2,
product=Discount.PRODUCT_ONE_COURSE)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts()
self.assertEqual(all_curses_discounts, {'max_discount': None})
self.assertEqual(discounts_for_courses[0], {'course': course_1.pk, 'max_discount': 30})
self.assertEqual(discounts_for_courses[1], {'course': course_2.pk, 'max_discount': 50})
def test_greater_value_discount_without_user(self):
course = CourseFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course,
product=Discount.PRODUCT_ONE_COURSE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course,
product=Discount.PRODUCT_ONE_COURSE)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts()
self.assertEqual(all_curses_discounts, {'max_discount': None})
self.assertEqual(discounts_for_courses[0], {'course': course.pk, 'max_discount': 50})
def test_exclude_personal_discounts_without_user(self):
user_1 = UserFactory.create()
course = CourseFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course,
product=Discount.PRODUCT_ONE_COURSE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course,
product=Discount.PRODUCT_ONE_COURSE, client=user_1)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts()
self.assertEqual(all_curses_discounts, {'max_discount': None})
self.assertEqual(discounts_for_courses[0], {'course': course.pk, 'max_discount': 30})
def test_discount_for_one_course_and_all_courses(self):
course = CourseFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course,
product=Discount.PRODUCT_ONE_COURSE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course,
product=Discount.PRODUCT_ONE_COURSE)
DiscountFactory.create(end=now() + timedelta(days=5), value=10, product=Discount.PRODUCT_ALL_COURSES)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts()
self.assertEqual(all_curses_discounts, {'max_discount': 10})
self.assertEqual(discounts_for_courses[0], {'course': course.pk, 'max_discount': 50})
def test_personal_discounts(self):
course = CourseFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course,
product=Discount.PRODUCT_ONE_COURSE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course,
product=Discount.PRODUCT_ONE_COURSE, client=self.user)
DiscountFactory.create(end=now() + timedelta(days=5), value=10, product=Discount.PRODUCT_ALL_COURSES)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts(user=self.user)
self.assertEqual(all_curses_discounts, {'max_discount': 10})
self.assertEqual(discounts_for_courses[0], {'course': course.pk, 'max_discount': 50})
def test_personal_discounts_multiple_users(self):
user_1 = UserFactory()
course = CourseFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course,
product=Discount.PRODUCT_ONE_COURSE, client=user_1)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course,
product=Discount.PRODUCT_ONE_COURSE, client=self.user)
DiscountFactory.create(end=now() + timedelta(days=5), value=10, product=Discount.PRODUCT_ALL_COURSES,
client=self.user)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts(user=self.user)
self.assertEqual(all_curses_discounts, {'max_discount': 10})
self.assertEqual(discounts_for_courses[0], {'course': course.pk, 'max_discount': 50})
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts(user=user_1)
self.assertEqual(all_curses_discounts, {'max_discount': None})
self.assertEqual(discounts_for_courses[0], {'course': course.pk, 'max_discount': 30})
def test_discount_for_one_course_without_user(self):
course_1 = CourseFactory.create()
course_2 = CourseFactory.create()
course_3 = CourseFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course_1,
product=Discount.PRODUCT_ONE_COURSE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course_2,
product=Discount.PRODUCT_ONE_COURSE)
DiscountFactory.create(end=now() + timedelta(days=5), value=60, course=course_3,
product=Discount.PRODUCT_ONE_COURSE)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts(user=None, course=course_1)
self.assertEqual(all_curses_discounts, {'max_discount': None})
self.assertEqual(len(discounts_for_courses), 1)
self.assertEqual(discounts_for_courses[0], {'course': course_1.pk, 'max_discount': 30})
def test_discount_for_one_course_with_multiple_users(self):
user_1 = UserFactory.create()
course_1 = CourseFactory.create()
course_2 = CourseFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=10, product=Discount.PRODUCT_ALL_COURSES)
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course_1,
product=Discount.PRODUCT_ONE_COURSE, client=user_1)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course_2,
product=Discount.PRODUCT_ONE_COURSE, client=user_1)
DiscountFactory.create(end=now() + timedelta(days=5), value=30, course=course_1,
product=Discount.PRODUCT_ONE_COURSE, client=self.user)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, course=course_2,
product=Discount.PRODUCT_ONE_COURSE, client=self.user)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, product=Discount.PRODUCT_ALL_COURSES,
client=self.user)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts(user=user_1,
course=course_1)
self.assertEqual(all_curses_discounts, {'max_discount': 10})
self.assertEqual(len(discounts_for_courses), 1)
self.assertEqual(discounts_for_courses[0], {'course': course_1.pk, 'max_discount': 30})
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts(user=self.user,
course=course_1)
self.assertEqual(all_curses_discounts, {'max_discount': 50})
self.assertEqual(len(discounts_for_courses), 1)
self.assertEqual(discounts_for_courses[0], {'course': course_1.pk, 'max_discount': 30})
def test_not_active_discount(self):
DiscountFactory.create(end=now() + timedelta(days=5), value=60, product=Discount.PRODUCT_ALL_COURSES,
is_active=False)
DiscountFactory.create(end=now() + timedelta(days=5), value=40, product=Discount.PRODUCT_ALL_COURSES)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts()
self.assertEqual(all_curses_discounts, {'max_discount': 40})
self.assertEqual(len(discounts_for_courses), 0)
def test_old_discount(self):
DiscountFactory.create(start=now() - timedelta(days=2), end=now() - timedelta(days=1), value=60,
product=Discount.PRODUCT_ALL_COURSES)
DiscountFactory.create(end=now() + timedelta(days=5), value=40, product=Discount.PRODUCT_ALL_COURSES)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts()
self.assertEqual(all_curses_discounts, {'max_discount': 40})
self.assertEqual(len(discounts_for_courses), 0)
def test_discount_from_the_future(self):
DiscountFactory.create(start=now() + timedelta(days=2), end=now() + timedelta(days=3), value=60,
product=Discount.PRODUCT_ALL_COURSES)
DiscountFactory.create(end=now() + timedelta(days=5), value=40, product=Discount.PRODUCT_ALL_COURSES)
all_curses_discounts, discounts_for_courses = Discount.objects.get_courses_discounts()
self.assertEqual(all_curses_discounts, {'max_discount': 40})
self.assertEqual(len(discounts_for_courses), 0)
class DiscountForPackagesModelTestCase(TestCase):
def setUp(self):
self.user = UserFactory.create()
def test_discounts_for_packages_without_user(self):
package_1 = PackageFactory.create()
package_2 = PackageFactory.create()
package_3 = PackageFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package_1,
product=Discount.PRODUCT_ONE_PACKAGE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package_2,
product=Discount.PRODUCT_ONE_PACKAGE)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts()
self.assertEqual(all_packages_discounts, {'max_discount': None})
self.assertEqual(discounts_for_packages[0], {'package': package_1.pk, 'max_discount': 30})
self.assertEqual(discounts_for_packages[1], {'package': package_2.pk, 'max_discount': 50})
def test_greater_value_discount_without_user(self):
package = PackageFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package,
product=Discount.PRODUCT_ONE_PACKAGE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package,
product=Discount.PRODUCT_ONE_PACKAGE)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts()
self.assertEqual(all_packages_discounts, {'max_discount': None})
self.assertEqual(discounts_for_packages[0], {'package': package.pk, 'max_discount': 50})
def test_exclude_personal_discounts_without_user(self):
user_1 = UserFactory.create()
package = PackageFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package,
product=Discount.PRODUCT_ONE_PACKAGE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package,
product=Discount.PRODUCT_ONE_PACKAGE, client=user_1)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts()
self.assertEqual(all_packages_discounts, {'max_discount': None})
self.assertEqual(discounts_for_packages[0], {'package': package.pk, 'max_discount': 30})
def test_discount_for_one_package_and_all_packages(self):
package = PackageFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package,
product=Discount.PRODUCT_ONE_PACKAGE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package,
product=Discount.PRODUCT_ONE_PACKAGE)
DiscountFactory.create(end=now() + timedelta(days=5), value=10, product=Discount.PRODUCT_ALL_PACKAGES)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts()
self.assertEqual(all_packages_discounts, {'max_discount': 10})
self.assertEqual(discounts_for_packages[0], {'package': package.pk, 'max_discount': 50})
def test_personal_discounts(self):
package = PackageFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package,
product=Discount.PRODUCT_ONE_PACKAGE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package,
product=Discount.PRODUCT_ONE_PACKAGE, client=self.user)
DiscountFactory.create(end=now() + timedelta(days=5), value=10, product=Discount.PRODUCT_ALL_PACKAGES)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts(user=self.user)
self.assertEqual(all_packages_discounts, {'max_discount': 10})
self.assertEqual(discounts_for_packages[0], {'package': package.pk, 'max_discount': 50})
def test_personal_discounts_multiple_users(self):
user_1 = UserFactory()
package = PackageFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package,
product=Discount.PRODUCT_ONE_PACKAGE, client=user_1)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package,
product=Discount.PRODUCT_ONE_PACKAGE, client=self.user)
DiscountFactory.create(end=now() + timedelta(days=5), value=10, product=Discount.PRODUCT_ALL_PACKAGES,
client=self.user)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts(user=self.user)
self.assertEqual(all_packages_discounts, {'max_discount': 10})
self.assertEqual(discounts_for_packages[0], {'package': package.pk, 'max_discount': 50})
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts(user=user_1)
self.assertEqual(all_packages_discounts, {'max_discount': None})
self.assertEqual(discounts_for_packages[0], {'package': package.pk, 'max_discount': 30})
def test_discount_for_one_package_without_user(self):
package_1 = PackageFactory.create()
package_2 = PackageFactory.create()
package_3 = PackageFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package_1,
product=Discount.PRODUCT_ONE_PACKAGE)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package_2,
product=Discount.PRODUCT_ONE_PACKAGE)
DiscountFactory.create(end=now() + timedelta(days=5), value=60, package=package_3,
product=Discount.PRODUCT_ONE_PACKAGE)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts(user=None,
package=package_1)
self.assertEqual(all_packages_discounts, {'max_discount': None})
self.assertEqual(len(discounts_for_packages), 1)
self.assertEqual(discounts_for_packages[0], {'package': package_1.pk, 'max_discount': 30})
def test_discount_for_one_package_with_multiple_users(self):
user_1 = UserFactory.create()
package_1 = PackageFactory.create()
package_2 = PackageFactory.create()
DiscountFactory.create(end=now() + timedelta(days=5), value=10, product=Discount.PRODUCT_ALL_PACKAGES)
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package_1,
product=Discount.PRODUCT_ONE_PACKAGE, client=user_1)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package_2,
product=Discount.PRODUCT_ONE_PACKAGE, client=user_1)
DiscountFactory.create(end=now() + timedelta(days=5), value=30, package=package_1,
product=Discount.PRODUCT_ONE_PACKAGE, client=self.user)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, package=package_2,
product=Discount.PRODUCT_ONE_PACKAGE, client=self.user)
DiscountFactory.create(end=now() + timedelta(days=5), value=50, product=Discount.PRODUCT_ALL_PACKAGES,
client=self.user)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts(user=user_1,
package=package_1)
self.assertEqual(all_packages_discounts, {'max_discount': 10})
self.assertEqual(len(discounts_for_packages), 1)
self.assertEqual(discounts_for_packages[0], {'package': package_1.pk, 'max_discount': 30})
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts(user=self.user,
package=package_1)
self.assertEqual(all_packages_discounts, {'max_discount': 50})
self.assertEqual(len(discounts_for_packages), 1)
self.assertEqual(discounts_for_packages[0], {'package': package_1.pk, 'max_discount': 30})
def test_not_active_discount(self):
DiscountFactory.create(end=now() + timedelta(days=5), value=60, product=Discount.PRODUCT_ALL_PACKAGES,
is_active=False)
DiscountFactory.create(end=now() + timedelta(days=5), value=40, product=Discount.PRODUCT_ALL_PACKAGES)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts()
self.assertEqual(all_packages_discounts, {'max_discount': 40})
self.assertEqual(len(discounts_for_packages), 0)
def test_old_discount(self):
DiscountFactory.create(start=now() - timedelta(days=2), end=now() - timedelta(days=1), value=60,
product=Discount.PRODUCT_ALL_PACKAGES)
DiscountFactory.create(end=now() + timedelta(days=5), value=40, product=Discount.PRODUCT_ALL_PACKAGES)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts()
self.assertEqual(all_packages_discounts, {'max_discount': 40})
self.assertEqual(len(discounts_for_packages), 0)
def test_discount_from_the_future(self):
DiscountFactory.create(start=now() + timedelta(days=2), end=now() + timedelta(days=3), value=60,
product=Discount.PRODUCT_ALL_PACKAGES)
DiscountFactory.create(end=now() + timedelta(days=5), value=40, product=Discount.PRODUCT_ALL_PACKAGES)
all_packages_discounts, discounts_for_packages = Discount.objects.get_packages_discounts()
# Create your tests here.
self.assertEqual(all_packages_discounts, {'max_discount': 40})
self.assertEqual(len(discounts_for_packages), 0)

@ -9,6 +9,7 @@ from django.utils.text import slugify
from apps.course.models import *
from apps.content.models import *
from apps.payment.models import Discount
from apps.user.models import *
@ -94,3 +95,21 @@ class CourseFactory(DjangoModelFactory):
cover = None #factory.SubFactory(ImageObjectFactory)
gallery = None
status = factory.Iterator([s[0] for s in Course.STATUS_CHOICES])
class DiscountFactory(DjangoModelFactory):
author = factory.SubFactory(UserFactory, role=User.AUTHOR_ROLE)
name = factory.Faker('sentence', nb_words=3)
class Meta:
model = Discount
class PackageFactory(DjangoModelFactory):
description = factory.Faker('sentence', nb_words=5)
options = factory.Faker('sentence', nb_words=10)
price = factory.fuzzy.FuzzyDecimal(low=0, high=9999999.50)
duration = factory.fuzzy.FuzzyInteger(low=0, high=9999)
class Meta:
model = Package

Loading…
Cancel
Save