Структура таблицы скидок + админский интерфейс

remotes/origin/feature/discounts-12-9-19
Ivan Kazionov 6 years ago
parent 7980b911f1
commit bef692e71d
  1. 13
      apps/payment/admin.py
  2. 26
      apps/payment/forms.py
  3. 53
      apps/payment/migrations/0039_auto_20190913_0755.py
  4. 57
      apps/payment/models.py
  5. 17
      apps/user/migrations/0035_auto_20190913_0755.py

@ -5,7 +5,8 @@ from polymorphic.admin import (
PolymorphicChildModelFilter, PolymorphicChildModelFilter,
) )
from .models import AuthorBalance, CoursePayment, SchoolPayment, Payment, GiftCertificate, UserBonus from apps.payment.forms import DiscountAdminForm
from .models import AuthorBalance, CoursePayment, SchoolPayment, Payment, GiftCertificate, UserBonus, Discount
@admin.register(AuthorBalance) @admin.register(AuthorBalance)
@ -70,3 +71,13 @@ class GiftCertificateAdmin(admin.ModelAdmin):
@admin.register(UserBonus) @admin.register(UserBonus)
class UserBonusAdmin(admin.ModelAdmin): class UserBonusAdmin(admin.ModelAdmin):
pass pass
@admin.register(Discount)
class DiscountAdmin(admin.ModelAdmin):
form = DiscountAdminForm
def save_model(self, request, obj, form, change):
if not obj.pk:
obj.author = request.user
obj.save()

@ -0,0 +1,26 @@
from django import forms
from apps.payment.models import Discount
class DiscountAdminForm(forms.ModelForm):
def clean(self):
clean_data = super().clean()
if clean_data['product'] == Discount.PRODUCT_ONE_COURSE and clean_data.get('course') is None:
self.add_error('course', 'Не выбран курс')
if clean_data['product'] == Discount.PRODUCT_ONE_PACKAGE and clean_data.get('package') is None:
self.add_error('package', 'Не выбрана подписка')
if clean_data['usage_type'] == Discount.USAGE_TYPE_LIMIT:
if clean_data.get('usage_count_limit') is None:
self.add_error('usage_count_limit', 'Не указан лимит использования')
elif clean_data['usage_count_limit'] == 0:
self.add_error('usage_count_limit', 'Лимит использования равен 0')
return clean_data
class Meta:
model = Discount
fields = '__all__'
exclude = ['author']

@ -0,0 +1,53 @@
# Generated by Django 2.0.7 on 2019-09-13 07:55
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('course', '0050_auto_20190818_1043'),
('content', '0030_auto_20190809_0133'),
('payment', '0038_auto_20190814_1506'),
]
operations = [
migrations.CreateModel(
name='Discount',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200, verbose_name='Название')),
('product', models.PositiveSmallIntegerField(choices=[(0, 'Все курсы'), (1, 'Все подписки'), (2, 'Один курс'), (3, 'Одна подписка')], default=0, verbose_name='На какие продукты распространяется скидка')),
('promo_id', models.CharField(blank=True, max_length=20, null=True, verbose_name='Промокод')),
('usage_type', models.PositiveSmallIntegerField(choices=[(0, 'Ограничен по количеству использований'), (1, 'Не ограничен по количеству использований')], default=0, verbose_name='Тип использования')),
('usage_count_limit', models.PositiveIntegerField(blank=True, null=True, verbose_name='Сколько раз можно использовать')),
('activate_count', models.PositiveIntegerField(default=0, verbose_name='Сколько раз использован')),
('value', models.PositiveIntegerField(default=0, validators=[django.core.validators.MaxValueValidator(100, 'Размер скидки не может быть больше 100')], verbose_name='Размер скидки в %')),
('start', models.DateTimeField(default=django.utils.timezone.now, verbose_name='Дата начала действия скидки')),
('end', models.DateTimeField(verbose_name='Дата окончания скидки')),
('is_active', models.BooleanField(default=True, verbose_name='Активность')),
('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='author_discounts', to=settings.AUTH_USER_MODEL, verbose_name='Автор')),
('client', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discounts', to=settings.AUTH_USER_MODEL, verbose_name='Пользователь скидки')),
('course', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='course_discounts', to='course.Course', verbose_name='Курс на который распространяется скидка')),
('package', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='package_discounts', to='content.Package', verbose_name='Подписка на которую распространяется скидка')),
],
options={
'verbose_name': 'Скидка',
'verbose_name_plural': 'Скидки',
},
),
migrations.AlterField(
model_name='userbonus',
name='payment',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='payment.Payment'),
),
migrations.AlterField(
model_name='userbonus',
name='referral',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='user.Referral'),
),
]

@ -12,7 +12,7 @@ from django.db.models import Func, F
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
from django.core.validators import RegexValidator from django.core.validators import RegexValidator, MaxValueValidator
from django.utils.timezone import now from django.utils.timezone import now
from django.conf import settings from django.conf import settings
@ -29,7 +29,8 @@ from project.utils import dates_overlap
config = Config.load() config = Config.load()
User = get_user_model() User = get_user_model()
CREDIT_CARD_RE = r'^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\d{11})$' CREDIT_CARD_RE = r'^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}' \
r'|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\d{11})$'
class AuthorBalance(models.Model): class AuthorBalance(models.Model):
@ -420,3 +421,55 @@ class UserGiftCertificate(models.Model):
@property @property
def code(self): def code(self):
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 Discount(models.Model):
PRODUCT_ALL_COURSES = 0
PRODUCT_ALL_PACKAGES = 1
PRODUCT_ONE_COURSE = 2
PRODUCT_ONE_PACKAGE = 3
USAGE_TYPE_LIMIT = 0
USAGE_TYPE_UNLIMITED = 1
PRODUCT_CHOICES = (
(PRODUCT_ALL_COURSES, 'Все курсы'),
(PRODUCT_ALL_PACKAGES, 'Все подписки'),
(PRODUCT_ONE_COURSE, 'Один курс'),
(PRODUCT_ONE_PACKAGE, 'Одна подписка')
)
USAGE_TYPE_CHOICES = (
(USAGE_TYPE_LIMIT, 'Ограничен по количеству использований'),
(USAGE_TYPE_UNLIMITED, 'Не ограничен по количеству использований')
)
name = models.CharField(verbose_name='Название', max_length=200)
client = models.ForeignKey(User, on_delete=models.CASCADE, related_name='discounts', null=True, blank=True,
verbose_name='Пользователь скидки')
product = models.PositiveSmallIntegerField('На какие продукты распространяется скидка', choices=PRODUCT_CHOICES,
default=PRODUCT_ALL_COURSES)
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='course_discounts', null=True, blank=True,
verbose_name='Курс на который распространяется скидка')
package = models.ForeignKey(Package, verbose_name='Подписка на которую распространяется скидка',
on_delete=models.CASCADE, related_name='package_discounts', null=True, blank=True)
promo_id = models.CharField(verbose_name='Промокод', max_length=20, null=True, blank=True)
usage_type = models.PositiveSmallIntegerField(verbose_name='Тип использования',
choices=USAGE_TYPE_CHOICES, default=USAGE_TYPE_LIMIT)
usage_count_limit = models.PositiveIntegerField(verbose_name='Сколько раз можно использовать', null=True,
blank=True)
activate_count = models.PositiveIntegerField(verbose_name='Сколько раз использован', default=0)
value = models.PositiveIntegerField(verbose_name='Размер скидки в %', default=0,
validators=[MaxValueValidator(100, 'Размер скидки не может быть больше 100')])
start = models.DateTimeField(verbose_name='Дата начала действия скидки', default=now)
end = models.DateTimeField(verbose_name='Дата окончания скидки')
is_active = models.BooleanField(verbose_name='Активность', default=True)
author = models.ForeignKey(User, verbose_name='Автор', null=True, blank=True, related_name='author_discounts',
on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
verbose_name = 'Скидка'
verbose_name_plural = 'Скидки'

@ -0,0 +1,17 @@
# Generated by Django 2.0.7 on 2019-09-13 07:55
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('user', '0034_auto_20190612_1852'),
]
operations = [
migrations.AlterModelOptions(
name='child',
options={'ordering': ('id',)},
),
]
Loading…
Cancel
Save