diff --git a/api/v1/serializers/content.py b/api/v1/serializers/content.py index b2d47d15..d84e357b 100644 --- a/api/v1/serializers/content.py +++ b/api/v1/serializers/content.py @@ -4,7 +4,7 @@ from django.conf import settings from apps.content.models import ( Banner, Content, Image, Text, ImageText, Video, - Gallery, GalleryImage, ImageObject, FAQ) + Gallery, GalleryImage, ImageObject, FAQ, Package) from . import Base64ImageField @@ -268,3 +268,10 @@ class FAQSerializer(serializers.ModelSerializer): class Meta: model = FAQ fields = '__all__' + + +class PackageSerializer(serializers.ModelSerializer): + + class Meta: + model = Package + fields = '__all__' diff --git a/api/v1/urls.py b/api/v1/urls.py index 99921937..ab6e3525 100644 --- a/api/v1/urls.py +++ b/api/v1/urls.py @@ -19,7 +19,7 @@ from .views import ( SchoolScheduleViewSet, LiveLessonViewSet, PaymentViewSet, ObjectCommentsViewSet, ContestViewSet, ContestWorkViewSet, NotifiedAboutBonuses, - AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet, BonusesViewSet, TagViewSet) + AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet, BonusesViewSet, PackageViewSet, TagViewSet) router = DefaultRouter() router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests') @@ -48,6 +48,7 @@ router.register(r'users', UserViewSet, base_name='users') router.register(r'user-gallery', UserGalleryViewSet, base_name='user-gallery') router.register(r'contests', ContestViewSet, base_name='contests') router.register(r'contest-works', ContestWorkViewSet, base_name='contest_works') +router.register(r'packages', PackageViewSet, base_name='packages') router.register(r'tags', TagViewSet, base_name='tags') # router.register(r'configs', ConfigViewSet, base_name='configs') diff --git a/api/v1/views.py b/api/v1/views.py index ffc240fd..6972826e 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -31,7 +31,7 @@ from .serializers.content import ( VideoSerializer, VideoCreateSerializer, GallerySerializer, GalleryImageSerializer, GalleryImageCreateSerializer, - ImageObjectSerializer, FAQSerializer, + ImageObjectSerializer, FAQSerializer, PackageSerializer, ) from .serializers.school import ( SchoolScheduleSerializer, @@ -66,7 +66,7 @@ from apps.config.models import Config from apps.content.models import ( Banner, Image, Text, ImageText, Video, Gallery, GalleryImage, ImageObject, - Contest, ContestWork, FAQ) + Contest, ContestWork, FAQ, Package) from apps.payment.models import ( AuthorBalance, Payment, CoursePayment, SchoolPayment, UserBonus, @@ -653,14 +653,13 @@ class PaymentViewSet(viewsets.ModelViewSet): def calc_amount(self, request, pk=None): user = request.query_params.get('user') course = request.query_params.get('course') - weekdays = request.query_params.getlist('weekdays[]') date_start = request.query_params.get('date_start') is_camp = bool(request.query_params.get('is_camp')) user = user and User.objects.get(pk=user) course = course and Course.objects.get(pk=course) date_start = date_start and datetime.strptime(date_start, '%Y-%m-%d') - return Response(Payment.calc_amount(user=user, course=course, date_start=date_start, weekdays=weekdays, + return Response(Payment.calc_amount(user=user, course=course, date_start=date_start, is_camp=is_camp)) @@ -775,6 +774,10 @@ class NotifiedAboutBonuses(views.APIView): b.save() return Response({'status': 'ok'}) +class PackageViewSet(ExtendedModelViewSet): + queryset = Package.objects.all() + serializer_class = PackageSerializer + permission_classes = (IsAdmin,) class TagViewSet(ExtendedModelViewSet): queryset = Tag.objects.all() diff --git a/apps/content/admin.py b/apps/content/admin.py index a407d671..07d86380 100644 --- a/apps/content/admin.py +++ b/apps/content/admin.py @@ -8,7 +8,7 @@ from polymorphic.admin import ( from apps.content.models import ( Banner, Content, Image, Text, ImageText, Video, Gallery, GalleryImage, ImageObject, - Contest, ContestWork, FAQ, + Contest, ContestWork, FAQ, Package, ) @@ -99,3 +99,8 @@ class ContestWorkAdmin(admin.ModelAdmin): @admin.register(FAQ) class FAQAdmin(admin.ModelAdmin): base_model = FAQ + + +@admin.register(Package) +class PackageAdmin(admin.ModelAdmin): + base_model = Package diff --git a/apps/content/migrations/0029_auto_20190730_2032.py b/apps/content/migrations/0029_auto_20190730_2032.py new file mode 100644 index 00000000..645e97e2 --- /dev/null +++ b/apps/content/migrations/0029_auto_20190730_2032.py @@ -0,0 +1,38 @@ +# Generated by Django 2.0.7 on 2019-07-30 20:32 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0028_auto_20190726_0106'), + ] + + operations = [ + migrations.CreateModel( + name='Package', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('price', models.DecimalField(decimal_places=2, max_digits=10)), + ('high_price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)), + ('description', models.TextField(db_index=True, default='', verbose_name='Описание')), + ('duration', models.PositiveSmallIntegerField()), + ('options', models.TextField(db_index=True, default='', verbose_name='Описание')), + ], + options={ + 'ordering': ('duration',), + }, + ), + migrations.AlterField( + model_name='banner', + name='main_banner', + field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(choices=[(1, 'Главная'), (2, 'Курсы'), (3, 'Школа'), (4, 'Пакеты')]), blank=True, default=[], size=None), + ), + migrations.AlterField( + model_name='banner', + name='pages', + field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(choices=[(1, 'Главная'), (2, 'Курсы'), (3, 'Школа'), (4, 'Пакеты')]), blank=True, default=[], size=None), + ), + ] diff --git a/apps/content/migrations/0030_auto_20190809_0133.py b/apps/content/migrations/0030_auto_20190809_0133.py new file mode 100644 index 00000000..da8fed67 --- /dev/null +++ b/apps/content/migrations/0030_auto_20190809_0133.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.7 on 2019-08-09 01:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0029_auto_20190730_2032'), + ] + + operations = [ + migrations.AlterField( + model_name='package', + name='options', + field=models.TextField(db_index=True, default='', verbose_name='Опции'), + ), + ] diff --git a/apps/content/models.py b/apps/content/models.py index 101ffe7e..045bcafa 100644 --- a/apps/content/models.py +++ b/apps/content/models.py @@ -146,11 +146,13 @@ class Banner(models.Model): PAGE_INDEX = 1 PAGE_COURSES = 2 PAGE_SCHOOL = 3 + PAGE_PACKAGES = 4 PAGE_CHOICES = ( (PAGE_INDEX, 'Главная'), (PAGE_COURSES, 'Курсы'), (PAGE_SCHOOL, 'Школа'), + (PAGE_PACKAGES, 'Пакеты') ) text = models.TextField(blank=True, default='') @@ -241,3 +243,22 @@ class ContestWork(models.Model): class FAQ(models.Model): question = models.TextField(max_length=1000,) answer = models.TextField(max_length=1000,) + + +class Package(models.Model): + price = models.DecimalField(max_digits=10, decimal_places=2,) + high_price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) + description = models.TextField( + 'Описание', default='', db_index=True + ) + duration = models.PositiveSmallIntegerField() + options = models.TextField( + 'Опции', default='', db_index=True + ) + + class Meta: + ordering = ('duration',) + + @property + def options_html(self): + return ''.join(map(lambda x: '
%s
' % x, self.options.split('\n'))) diff --git a/apps/notification/templates/notification/email/buy_email.html b/apps/notification/templates/notification/email/buy_email.html index 4e7c71dd..5733ed7a 100644 --- a/apps/notification/templates/notification/email/buy_email.html +++ b/apps/notification/templates/notification/email/buy_email.html @@ -3,12 +3,20 @@ {% block content %} {% if product_type == 'course' %} -Курс ждет вас по ссылке
+ Добрый день! Спасибо за покупку знаний в «Lil School»! Где искать уроки? После оплаты курс появится в вашем личном кабинете на платформе.
https://{% setting 'MAIN_HOST' %}{{ url }} Все ваши покупки будут храниться там в рамках срока доступа к курсу. Школа ждет вас по ссылке
+ Добрый день! Спасибо за покупку знаний в «Lil School»! Где искать уроки? После оплаты уроки появятся в вашем личном кабинете на платформе.
https://{% setting 'MAIN_HOST' %}{% url 'school:school' %} В онлайн-школе урок хранится неделю. Ровно до следующего урока. Так же вы можете найти ссылку в личном кабинете в разделе «Мои покупки». Занимайтесь с удовольствием! Вы житель мегаполиса и у вас нет времени дополнительно развивать своего ребенка?
- Или вы живете в маленьком городе,
- где нет качественных школ и секций для детей? Lil School это решение для тех родителей, кто стремится дать лучшее своему ребенку.
- Учитесь не выходя из дома! Вы житель мегаполиса и у вас нет времени дополнительно развивать своего ребенка?
+ Или вы живете в маленьком городе,
+ где нет качественных школ и секций для детей? Lil-School это решение для тех родителей, кто стремится дать лучшее своему ребенку.
+ Учитесь, не выходя из дома!
-