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

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,
)
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)
@ -70,3 +71,13 @@ class GiftCertificateAdmin(admin.ModelAdmin):
@admin.register(UserBonus)
class UserBonusAdmin(admin.ModelAdmin):
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.contrib.auth import get_user_model
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.conf import settings
@ -29,7 +29,8 @@ from project.utils import dates_overlap
config = Config.load()
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):
@ -420,3 +421,55 @@ class UserGiftCertificate(models.Model):
@property
def code(self):
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