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

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 arrow
import short_url import short_url
from django.db.models.functions import Coalesce
from paymentwall import Pingback from paymentwall import Pingback
from polymorphic.models import PolymorphicModel from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager 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.db import models
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.postgres.fields import ArrayField, JSONField 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 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): class Discount(models.Model):
PRODUCT_ALL_COURSES = 0 PRODUCT_ALL_COURSES = 0
PRODUCT_ALL_PACKAGES = 1 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', author = models.ForeignKey(User, verbose_name='Автор', null=True, blank=True, related_name='author_discounts',
on_delete=models.CASCADE) on_delete=models.CASCADE)
objects = DiscountManager()
def __str__(self): def __str__(self):
return self.name return self.name

@ -1,3 +1,336 @@
from datetime import timedelta
from django.test import TestCase 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.course.models import *
from apps.content.models import * from apps.content.models import *
from apps.payment.models import Discount
from apps.user.models import * from apps.user.models import *
@ -94,3 +95,21 @@ class CourseFactory(DjangoModelFactory):
cover = None #factory.SubFactory(ImageObjectFactory) cover = None #factory.SubFactory(ImageObjectFactory)
gallery = None gallery = None
status = factory.Iterator([s[0] for s in Course.STATUS_CHOICES]) 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