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 }}

+

Все ваши покупки будут храниться там в рамках срока доступа к курсу.

{% endif %} {% if product_type == 'school' %} -

Школа ждет вас по ссылке +

Добрый день! Спасибо за покупку знаний в «Lil School»!

+

Где искать уроки?

+

После оплаты уроки появятся в вашем личном кабинете на платформе.

+

https://{% setting 'MAIN_HOST' %}{% url 'school:school' %}

+

В онлайн-школе урок хранится неделю. Ровно до следующего урока.

{% endif %} {% if product_type == 'drawing_camp' %} {% if date_start.month == 7 and date_start.day == 1 and date_end.day == 31 %} @@ -72,7 +80,6 @@ https://{% setting 'MAIN_HOST' %}{% url 'school:drawing-camp' %}

{% endif %} {% endif %} -

Так же вы можете найти ссылку в личном кабинете в разделе «Мои покупки».

Занимайтесь с удовольствием!

diff --git a/apps/payment/migrations/0038_auto_20190814_1506.py b/apps/payment/migrations/0038_auto_20190814_1506.py new file mode 100644 index 00000000..90dbfce2 --- /dev/null +++ b/apps/payment/migrations/0038_auto_20190814_1506.py @@ -0,0 +1,25 @@ +# Generated by Django 2.0.7 on 2019-08-14 15:06 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0030_auto_20190809_0133'), + ('payment', '0037_add_paid_one_more_bonuses'), + ] + + operations = [ + migrations.AddField( + model_name='schoolpayment', + name='package', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='content.Package'), + ), + migrations.AlterField( + model_name='payment', + name='bonus', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='purchase_payments', to='payment.UserBonus'), + ), + ] diff --git a/apps/payment/models.py b/apps/payment/models.py index b8e2d8c1..0d4d7c25 100644 --- a/apps/payment/models.py +++ b/apps/payment/models.py @@ -16,12 +16,14 @@ from django.core.validators import RegexValidator from django.utils.timezone import now from django.conf import settings +from apps.content.models import Package from project.utils import weekdays_in_date_range from apps.course.models import Course from apps.config.models import Config from apps.school.models import SchoolSchedule from apps.notification.utils import send_email +from project.utils import dates_overlap config = Config.load() @@ -126,11 +128,11 @@ class Payment(PolymorphicModel): ordering = ('created_at',) @classmethod - def ajust_date_bounds(cls, date_start=None, date_end=None, is_camp=False): - school_start = date(now().year, 9, 1) - school_end = date(now().year, 5, 31) - camp_start = date(now().year, 6, 1) - camp_end = date(now().year, 8, 31) + def adjust_date_bounds(cls, date_start=None, date_end=None, is_camp=False): + school_start = date((date_start or date_end).year, 9, 1) + school_end = date((date_end or date_start).year, 5, 31) + camp_start = date((date_start or date_end).year, 6, 1) + camp_end = date((date_end or date_start).year, 8, 31) if date_start: if is_camp: @@ -151,24 +153,32 @@ class Payment(PolymorphicModel): else: return date_start or date_end + @classmethod + def date_add(cls, date_start, days=0, months=0, is_camp=False): + date_end = arrow.get(date_start + timedelta(days=days), settings.TIME_ZONE).shift( + months=months).date() - timedelta(1) + if months == 1: + if is_camp or (date_start.month == 2 and date_start.day >= 28) or ( + date_start.day == 31 and date_end.day <= 30) \ + or (date_start.month == 1 and date_start.day >= 29 and date_end.day == 28): + date_end = date_start.replace(day=1, month=date_start.month + 1) - timedelta(1) + return date_end + @classmethod def get_date_range(cls, date_start=None, days=0, months=0, is_camp=False): date_start = date_start or now().date() if isinstance(date_start, datetime): date_start = date_start.date() - date_start = cls.ajust_date_bounds(date_start=date_start, is_camp=is_camp) + date_start = cls.adjust_date_bounds(date_start=date_start, is_camp=is_camp) if is_camp and date_start.month == 6 and date_start.day > 16: date_start = date_start.replace(month=7, day=1) - date_end = arrow.get(date_start + timedelta(days=days), settings.TIME_ZONE).shift(months=months).date() - timedelta(1) - if months == 1: - if is_camp or (date_start.month == 2 and date_start.day >= 28) or (date_start.day == 31 and date_end.day <= 30) \ - or (date_start.month == 1 and date_start.day >= 29 and date_end.day == 28): - date_end = date_start.replace(day=1, month=date_start.month + 1) - timedelta(1) - date_end = cls.ajust_date_bounds(date_end=date_end, is_camp=is_camp) + date_end = cls.date_add(date_start, days, months, is_camp) + if is_camp: + date_end = cls.adjust_date_bounds(date_end, is_camp=is_camp) return [date_start, date_end] @classmethod - def calc_amount(cls, payment=None, user=None, course=None, date_start=None, weekdays=None, is_camp=False): + def calc_amount(cls, package=None, payment=None, user=None, course=None, date_start=None, weekdays=None, is_camp=False): price = 0 discount = 0 referral_bonus = 0 @@ -178,14 +188,14 @@ class Payment(PolymorphicModel): user = payment.user if isinstance(payment, SchoolPayment): user = payment.user - weekdays = payment.weekdays date_start = payment.date_start + package=payment.package if isinstance(payment, DrawingCampPayment): user = payment.user date_start = payment.date_start if issubclass(cls, DrawingCampPayment): is_camp = True - date_start, date_end = Payment.get_date_range(date_start, months=1, is_camp=is_camp) + date_start, date_end = Payment.get_date_range(date_start, months=package.duration if package else 1, is_camp=is_camp) if hasattr(user, 'referral') and not user.referral.payment: referral_bonus = user.referral.bonus referrer_bonus = user.referral.referrer_bonus @@ -213,40 +223,22 @@ class Payment(PolymorphicModel): date_end__gte=date_start, status__in=Payment.PW_PAID_STATUSES, ) - school_schedules_purchased = school_payments.annotate( - joined_weekdays=Func(F('weekdays'), function='unnest', ) - ).values_list('joined_weekdays', flat=True).distinct() - weekdays = list(set(map(int, weekdays)) - set(school_schedules_purchased)) prev_school_payment = school_payments.filter(add_days=False).last() - add_days = bool(prev_school_payment) - else: - add_days = False - school_schedules = SchoolSchedule.objects.filter( - weekday__in=weekdays, - is_camp=False, - ) - if add_days: - date_end = prev_school_payment.date_end - weekdays_count = weekdays_in_date_range(date_start, prev_school_payment.date_end) - all_weekdays_count = weekdays_in_date_range(prev_school_payment.date_start, prev_school_payment.date_end) - for ss in school_schedules: - price += ss.month_price // all_weekdays_count.get(ss.weekday, 0) * weekdays_count.get( - ss.weekday, 0) + if prev_school_payment: + date_start, date_end = Payment.get_date_range(prev_school_payment.date_end + timedelta(1), + months=package.duration, is_camp=False) + school_schedules = SchoolSchedule.objects.filter(is_camp=False).exclude(title='') + weekdays = list(school_schedules.values_list('weekday', flat=True)) + # FIXME после мая 2019 убрать? + # Если хотят купить школу в мае, то оплатить ее можно только до 31 мая, потом школа закроется + if date_start.month == 5: + weekdays_count = weekdays_in_date_range(date_start, date_end) + weekdays_count = sum(weekdays_count[wd] for wd in weekdays) + all_weekdays_count = weekdays_in_date_range(date_start.replace(day=1), date_end) + all_weekdays_count = sum(all_weekdays_count[wd] for wd in weekdays) + price = package.price // all_weekdays_count * weekdays_count else: - # FIXME после мая 2019 убрать? - # Если хотят купить школу в мае, то оплатить ее можно только до 31 мая, потом школа закроется - if date_start.month == 5: - weekdays_count = weekdays_in_date_range(date_start, date_end) - all_weekdays_count = weekdays_in_date_range(date_start.replace(day=1), date_end) - for ss in school_schedules: - price += ss.month_price // all_weekdays_count.get(ss.weekday, 0) * weekdays_count.get( - ss.weekday, 0) - else: - price = school_schedules.aggregate( - models.Sum('month_price'), - ).get('month_price__sum', 0) - if not (payment and payment.id) and price >= config.SERVICE_DISCOUNT_MIN_AMOUNT: - discount = config.SERVICE_DISCOUNT + price = package.price amount = price - discount referral_bonus = round(amount * referral_bonus / 100) referrer_bonus = round(amount * referrer_bonus / 100) @@ -337,6 +329,7 @@ class CoursePayment(Payment): class SchoolPayment(Payment): weekdays = ArrayField(models.IntegerField(), size=7, verbose_name='Дни недели') add_days = models.BooleanField('Докупленные дни', default=False) + package = models.ForeignKey(Package, null=True, blank=True, on_delete=models.SET_NULL) date_start = models.DateField('Дата начала подписки', null=True, blank=True) date_end = models.DateField('Дата окончания подписки', null=True, blank=True) diff --git a/apps/payment/templates/payment/package_payment_success.html b/apps/payment/templates/payment/package_payment_success.html new file mode 100644 index 00000000..c4bb469a --- /dev/null +++ b/apps/payment/templates/payment/package_payment_success.html @@ -0,0 +1,12 @@ +{% extends "templates/lilcity/index.html" %} {% load static %} {% block content %} +
+
+
+
Вы успешно приобрели подписку с {{ package.date_start }} по {{ package.date_end }}!
+ +
+
+
+{% endblock content %} diff --git a/apps/payment/templates/payment/payment_success.html b/apps/payment/templates/payment/payment_success.html index 5686ee03..c9b8d6fb 100644 --- a/apps/payment/templates/payment/payment_success.html +++ b/apps/payment/templates/payment/payment_success.html @@ -1,9 +1,10 @@ -{% extends "templates/lilcity/index.html" %} {% load static %} {% block content %} +{% extends "templates/lilcity/index.html" %} {% load static %}{% load plural %} +{% block content %}
{% if school %} -
Вы успешно приобрели доступ к урокам онлайн-школы!
+
Вы успешно приобрели доступ на {{ duration|rupluralize:"месяц,месяца,месяцев" }}!
diff --git a/apps/payment/views.py b/apps/payment/views.py index 9aca10df..8eb30777 100644 --- a/apps/payment/views.py +++ b/apps/payment/views.py @@ -20,6 +20,7 @@ from django.utils.timezone import now from paymentwall import Pingback, Product, Widget +from apps.content.models import Package from apps.course.models import Course from apps.payment.tasks import transaction_to_mixpanel, product_payment_to_mixpanel, transaction_to_roistat from apps.notification.utils import send_email @@ -48,7 +49,12 @@ class SchoolBuySuccessView(TemplateView): template_name = 'payment/payment_success.html' def get(self, request, pk=None, is_camp=False, *args, **kwargs): - return self.render_to_response(context={'camp': True} if is_camp else {'school': True}) + context = { + 'duration': request.GET.get('duration'), + 'camp': is_camp, + 'school': not is_camp + } + return self.render_to_response(context=context) @method_decorator(login_required, name='dispatch') @@ -116,56 +122,23 @@ class SchoolBuyView(TemplateView): template_name = 'payment/paymentwall_widget.html' def get(self, request, *args, **kwargs): - raise Http404() # FIXME host = urlsplit(self.request.META.get('HTTP_REFERER')) host = str(host[0]) + '://' + str(host[1]) - weekdays = set(request.GET.getlist('weekdays', [])) use_bonuses = request.GET.get('use_bonuses') roistat_visit = request.COOKIES.get('roistat_visit', None) date_start = request.GET.get('date_start') + duration = request.GET.get('duration') + package = get_object_or_404(Package, duration=duration) date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date() - date_start, date_end = Payment.get_date_range(date_start, months=1) - if not weekdays: - messages.error(request, 'Выберите несколько дней недели.') - return redirect('school:school') - try: - weekdays = [int(weekday) for weekday in weekdays] - except ValueError: - messages.error(request, 'Ошибка выбора дней недели.') - return redirect('school:school') - prev_school_payment = SchoolPayment.objects.filter( + amount_data = SchoolPayment.calc_amount(package=package, user=request.user, date_start=date_start) + school_payment = SchoolPayment.objects.create( user=request.user, - date_start__lte=date_start, - date_end__gte=date_start, - add_days=False, - status__in=[ - Pingback.PINGBACK_TYPE_REGULAR, - Pingback.PINGBACK_TYPE_GOODWILL, - Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, - ], - ).last() - add_days = bool(prev_school_payment) - if add_days: - school_payment = SchoolPayment.objects.create( - user=request.user, - weekdays=weekdays, - date_start=date_start, - date_end=prev_school_payment.date_end, - add_days=True, - roistat_visit=roistat_visit, - ) - # Если произойдет ошибка и оплату бонусами повторят еще раз на те же дни, то вернет ошибку - if school_payment.amount <= 0: - messages.error(request, 'Выбранные дни отсутствуют в оставшемся периоде подписки') - return redirect(reverse_lazy('school:school')) - else: - school_payment = SchoolPayment.objects.create( - user=request.user, - weekdays=weekdays, - roistat_visit=roistat_visit, - date_start=date_start, - date_end=date_end, - ) + weekdays=amount_data.get('weekdays'), + roistat_visit=roistat_visit, + date_start=amount_data.get('date_start'), + date_end=amount_data.get('date_end'), + package=package, + ) if use_bonuses and request.user.bonus: if request.user.bonus >= school_payment.amount: bonus = UserBonus.objects.create(amount= -school_payment.amount, user=request.user, payment=school_payment) @@ -183,7 +156,7 @@ class SchoolBuyView(TemplateView): f'school_{school_payment.id}', school_payment.amount, 'RUB', - 'Школа', + 'Подписка', ) widget = Widget( str(request.user.id), @@ -195,7 +168,7 @@ class SchoolBuyView(TemplateView): 'evaluation': 1, 'demo': 1, 'test_mode': 1, - 'success_url': host + str(reverse_lazy('payment-success')), + 'success_url': host + str(reverse_lazy('payment-success')) + '?duration=%s' % duration, 'failure_url': host + str(reverse_lazy('payment-error')), } ) @@ -362,6 +335,7 @@ class PaymentwallCallbackView(View): 'created_at': payment.created_at, 'update_at': payment.update_at, } + payment.save() product_payment_to_mixpanel.delay( diff --git a/apps/school/views.py b/apps/school/views.py index bd32cb7b..c737f199 100644 --- a/apps/school/views.py +++ b/apps/school/views.py @@ -70,7 +70,7 @@ class DrawingCampLessonsView(ListView): def get_queryset(self): date_start = (now() - timedelta(days=7)).date() - date_start, date_end = DrawingCampPayment.ajust_date_bounds(date_start, date_start + timedelta(days=23), is_camp=True) + date_start, date_end = DrawingCampPayment.adjust_date_bounds(date_start, date_start + timedelta(days=23), is_camp=True) date_range = Q( date__range=[date_start, date_end] ) @@ -106,15 +106,15 @@ class LiveLessonsDetailView(DetailView): is_purchased = DrawingCampPayment.objects.all() else: is_purchased = SchoolPayment.objects.filter(weekdays__contains=[self.object.date.weekday() + 1],) - is_purchased = is_purchased.filter( + is_purchased = is_purchased.paid().filter( user=request.user, date_start__lte=now(), date_end__gte=now() - timedelta(days=7), - status__in=[ - Pingback.PINGBACK_TYPE_REGULAR, - Pingback.PINGBACK_TYPE_GOODWILL, - Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, - ], + ).exists() or is_purchased.paid().filter( + user=request.user, + date_start__lte=now(), + date_end__gte=now() - timedelta(days=30), + package__duration__lte=9, ).exists() if not is_purchased and request.user.role not in [User.ADMIN_ROLE, User.TEACHER_ROLE]: raise Http404 @@ -221,7 +221,10 @@ class SchoolView(TemplateView): # берем все подписки, которые были в периоде for sp in prev_school_payments: # берем все уроки в оплаченном промежутке - date_range = [max(sp.date_start, prev_range[0]), min(sp.date_end, prev_range[1])] + if sp.package and sp.package.duration >= 9: + date_range = [max(sp.date_start, date_now - timedelta(30)), min(sp.date_end, prev_range[1])] + else: + date_range = [max(sp.date_start, prev_range[0]), min(sp.date_end, prev_range[1])] prev_live_lessons += list(LiveLesson.objects.filter( date__range=date_range, deactivated_at__isnull=True, diff --git a/apps/user/admin.py b/apps/user/admin.py index 63398df0..50915f33 100644 --- a/apps/user/admin.py +++ b/apps/user/admin.py @@ -12,7 +12,8 @@ User = get_user_model() class UserAdmin(BaseUserAdmin): fieldsets = ( (None, {'fields': ('username', 'password')}), - (_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'gender', 'about', 'photo')}), + (_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'gender', 'about', 'photo',)}), + ('Teacher', {'fields': ('show_in_mainpage', 'trial_lesson', 'instagram_hashtag',)}), ('Facebook Auth data', {'fields': ('fb_id', 'fb_data', 'is_email_proved')}), (_('Permissions'), {'fields': ('role', 'is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions', 'show_in_mainpage')}), diff --git a/project/templates/blocks/about.html b/project/templates/blocks/about.html index e2c8b3c4..d24701e3 100644 --- a/project/templates/blocks/about.html +++ b/project/templates/blocks/about.html @@ -1,12 +1,23 @@ +{% load static %}
-
+
-
-

Вы житель мегаполиса и у вас нет времени дополнительно развивать своего ребенка? - Или вы живете в маленьком городе, - где нет качественных школ и секций для детей?

-

Lil School это решение для тех родителей, кто стремится дать лучшее своему ребенку. - Учитесь не выходя из дома!

+
+
+
+
Для кого?
+
+

Вы житель мегаполиса и у вас нет времени дополнительно развивать своего ребенка? + Или вы живете в маленьком городе, + где нет качественных школ и секций для детей?

+

Lil-School это решение для тех родителей, кто стремится дать лучшее своему ребенку. + Учитесь, не выходя из дома!

+
+
diff --git a/project/templates/blocks/banner.html b/project/templates/blocks/banner.html index f047c2cf..f60baa34 100644 --- a/project/templates/blocks/banner.html +++ b/project/templates/blocks/banner.html @@ -1,5 +1,5 @@ {% else %} - {% include 'templates/blocks/banner.html' with banner=banners.0 %} +
+ {% include 'templates/blocks/banner.html' with banner=banners.0 %} +
{% endif %} diff --git a/project/templates/blocks/counters.html b/project/templates/blocks/counters.html index 40198a07..2fc03840 100644 --- a/project/templates/blocks/counters.html +++ b/project/templates/blocks/counters.html @@ -1,11 +1,10 @@ {% load static %} {% load ruplural from plural %} -
+
- -
Lil School в цифрах
+
@@ -32,6 +31,5 @@
со всего мира со счастливыми учениками Lil School
-
diff --git a/project/templates/blocks/footer.html b/project/templates/blocks/footer.html index 21c8df71..021faff8 100644 --- a/project/templates/blocks/footer.html +++ b/project/templates/blocks/footer.html @@ -1,7 +1,17 @@ {% load static %}