diff --git a/apps/content/migrations/0031_auto_20190925_1723.py b/apps/content/migrations/0031_auto_20190925_1723.py new file mode 100644 index 00000000..71067608 --- /dev/null +++ b/apps/content/migrations/0031_auto_20190925_1723.py @@ -0,0 +1,24 @@ +# Generated by Django 2.0.7 on 2019-09-25 17:23 + +from django.db import migrations +import project.utils.db + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0030_auto_20190809_0133'), + ] + + operations = [ + migrations.AlterField( + model_name='banner', + name='image', + field=project.utils.db.SafeImageField(upload_to=''), + ), + migrations.AlterField( + model_name='imageobject', + name='image', + field=project.utils.db.SafeImageField(upload_to='content/imageobject', verbose_name='Изображение'), + ), + ] diff --git a/apps/course/templates/course/course.html b/apps/course/templates/course/course.html index db228e96..adc2de97 100644 --- a/apps/course/templates/course/course.html +++ b/apps/course/templates/course/course.html @@ -111,13 +111,13 @@
diff --git a/apps/course/views.py b/apps/course/views.py index d4bd0298..aed63b75 100644 --- a/apps/course/views.py +++ b/apps/course/views.py @@ -246,9 +246,8 @@ class CourseView(DetailView): ]) payment = payments.filter(access_expire__gte=now().date()).order_by('-access_expire').first() context['payment'] = payment - context['access_duration'] = ((payment.access_expire - now().date()).days + 1) if payment else self.object.access_duration context['paid'] = bool(payment) - context['can_buy_again'] = bool(self.object.price) and (context['access_duration'] <= 7 if payment else + context['can_buy_again'] = bool(self.object.price) and (payment.access_duration <= 7 if payment else payments.filter(access_expire__lt=now().date()).exists()) context['pending'] = self.object.payments.filter( user=self.request.user, diff --git a/apps/notification/management/commands/send_course_access_expire_email.py b/apps/notification/management/commands/send_course_access_expire_email.py new file mode 100644 index 00000000..3e358383 --- /dev/null +++ b/apps/notification/management/commands/send_course_access_expire_email.py @@ -0,0 +1,19 @@ +from django.core.management.base import BaseCommand + +from apps.notification.tasks import send_course_access_expire_email + + +class Command(BaseCommand): + help = 'Send course access expire email' + + def add_arguments(self, parser): + parser.add_argument( + '--days', + dest='days', + type=int, + help='Days before access expired', + ) + + def handle(self, *args, **options): + send_course_access_expire_email(options.get('days')) + diff --git a/apps/notification/migrations/0003_coursenotification.py b/apps/notification/migrations/0003_coursenotification.py new file mode 100644 index 00000000..e48a63c7 --- /dev/null +++ b/apps/notification/migrations/0003_coursenotification.py @@ -0,0 +1,26 @@ +# Generated by Django 2.0.7 on 2019-09-25 17:23 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0050_auto_20190818_1043'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('notification', '0002_usernotification_camp_certificate_last_email'), + ] + + operations = [ + migrations.CreateModel( + name='CourseNotification', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('access_expire_last_email', models.DateTimeField(blank=True, null=True)), + ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.Course')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/apps/notification/models.py b/apps/notification/models.py index c60c91cc..6770745c 100644 --- a/apps/notification/models.py +++ b/apps/notification/models.py @@ -1,7 +1,6 @@ from django.db import models from django.contrib.auth import get_user_model - User = get_user_model() @@ -10,3 +9,9 @@ class UserNotification(models.Model): certificate_number = models.SmallIntegerField(blank=True, null=True) certificate_last_email = models.DateTimeField(blank=True, null=True) camp_certificate_last_email = models.DateTimeField(blank=True, null=True) + + +class CourseNotification(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + course = models.ForeignKey('course.Course', on_delete=models.CASCADE) + access_expire_last_email = models.DateTimeField(blank=True, null=True) diff --git a/apps/notification/tasks.py b/apps/notification/tasks.py index 791ed307..759ba298 100644 --- a/apps/notification/tasks.py +++ b/apps/notification/tasks.py @@ -12,7 +12,7 @@ from django.utils.timezone import now from django.conf import settings from django.utils.text import slugify -from apps.notification.models import UserNotification +from apps.notification.models import UserNotification, CourseNotification from apps.notification.utils import send_email from apps.payment.models import SchoolPayment, CoursePayment, Payment, UserGiftCertificate, UserBonus, DrawingCampPayment from project.celery import app @@ -245,3 +245,30 @@ def send_camp_certificates(email=None, dry_run=False, certificate_number=None): for fn in file_names: if os.path.isfile(fn): os.remove(fn) + + +@app.task +def send_course_access_expire_email(days=None): + if days is None: + days = 30 + payments = CoursePayment.objects.paid().filter(access_expire=now() + timedelta(days - 1), created_at__lte=now() - timedelta(10)) + for payment in payments: + cn, created = CourseNotification.objects.get_or_create(course=payment.course, user=payment.user) + if not created and cn.access_expire_last_email and cn.access_expire_last_email.date() >= now().date() - timedelta(days): + continue + print(payment.user.email) + try: + #payment.user.email + send_email('Доступ к курсу скоро закончится', 'gzbender74@gmail.com', 'notification/email/course_access_expire.html', + username=payment.user.get_full_name(), course_title=payment.course.title, + access_duration=payment.access_duration) + except: + print('Not OK') + continue + else: + cn.access_expire_last_email = now() + cn.save() + user_courses = dict(CoursePayment.objects.paid().filter(access_expire__lt=now().date()).values_list('user_id', 'course_id')) + for cn in CourseNotification.objects.filter(course_id__in=user_courses.values(), user_id__in=user_courses.keys()): + if user_courses.get(cn.user_id) == cn.course_id: + cn.delete() diff --git a/apps/notification/templates/notification/email/buy_email.html b/apps/notification/templates/notification/email/buy_email.html index 5733ed7a..fb4393df 100644 --- a/apps/notification/templates/notification/email/buy_email.html +++ b/apps/notification/templates/notification/email/buy_email.html @@ -1,21 +1,23 @@ {% extends "notification/email/_base.html" %} -{% load settings %} +{% load rupluralize from plural %} {% block content %} {% if product_type == 'course' %} -Добрый день! Спасибо за покупку знаний в «Lil School»!
-Где искать уроки?
-После оплаты курс появится в вашем личном кабинете на платформе.
-- https://{% setting 'MAIN_HOST' %}{{ url }}
+Добрый день, {{ username }}!
+Вы приобрели видеокурс «{{ course_title }}». Спасибо за покупку!
+Обратите внимание, что доступ к курсу действует {{ access_duration | rupluralize:'день,дня,дней' }}. Этого должно хватить, чтобы пройти его. + Если вы не успеете, то по окончании этого срока система автоматически предложит вам продлить доступ к курсу за 50% от его стоимости./p> +
Найти курс можно в вашем личном кабинете на платформе.
++ https://{{ settings.MAIN_HOST }}{{ url }}
Все ваши покупки будут храниться там в рамках срока доступа к курсу.
{% endif %} {% if product_type == 'school' %}Добрый день! Спасибо за покупку знаний в «Lil School»!
Где искать уроки?
После оплаты уроки появятся в вашем личном кабинете на платформе.
-- https://{% setting 'MAIN_HOST' %}{% url 'school:school' %}
++ https://{{ settings.MAIN_HOST }}{% url 'school:school' %}
В онлайн-школе урок хранится неделю. Ровно до следующего урока.
{% endif %} {% if product_type == 'drawing_camp' %} @@ -76,8 +78,8 @@ Обязательно делитесь своими впечатлениями и работами, отмечая их хэштегом #lil_summer. Спасибо, что вы с нами! {% else %} -Рисовальный лагерь ждет вас по ссылке - https://{% setting 'MAIN_HOST' %}{% url 'school:drawing-camp' %}
+Рисовальный лагерь ждет вас по ссылке + https://{{ settings.MAIN_HOST }}{% url 'school:drawing-camp' %}
{% endif %} {% endif %} diff --git a/apps/notification/templates/notification/email/course_access_expire.html b/apps/notification/templates/notification/email/course_access_expire.html new file mode 100644 index 00000000..0c8f22f3 --- /dev/null +++ b/apps/notification/templates/notification/email/course_access_expire.html @@ -0,0 +1,8 @@ +{% load rupluralize from plural %} +Добрый день, {{ username }}!
+ +Доступ к видеокурсу «{{ course_title }}», который вы приобретали на платформе lil.school, + заканчивается через {{ access_duration|rupluralize:'день,дня,дней' }}. Если вы ещё не успели пройти этот курс, самое время это сделать. + По окончании этого срока система автоматически предложит вам продлить доступ к курсу за 50% от его стоимости.
+ +Команда «Lil School».
diff --git a/apps/payment/migrations/0039_auto_20190925_1723.py b/apps/payment/migrations/0039_auto_20190925_1723.py new file mode 100644 index 00000000..d04deda6 --- /dev/null +++ b/apps/payment/migrations/0039_auto_20190925_1723.py @@ -0,0 +1,24 @@ +# Generated by Django 2.0.7 on 2019-09-25 17:23 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('payment', '0038_auto_20190814_1506'), + ] + + operations = [ + 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'), + ), + ] diff --git a/apps/payment/models.py b/apps/payment/models.py index 47af6711..86f40dfc 100644 --- a/apps/payment/models.py +++ b/apps/payment/models.py @@ -325,6 +325,10 @@ class CoursePayment(Payment): verbose_name = 'Платеж за курс' verbose_name_plural = 'Платежи за курсы' + @property + def access_duration(self): + return (self.access_expire - now().date()).days + 1 + class SchoolPayment(Payment): weekdays = ArrayField(models.IntegerField(), size=7, verbose_name='Дни недели') diff --git a/apps/payment/templates/payment/gift_certificate_item.html b/apps/payment/templates/payment/gift_certificate_item.html index 7d4d3d8f..f9e92e8d 100644 --- a/apps/payment/templates/payment/gift_certificate_item.html +++ b/apps/payment/templates/payment/gift_certificate_item.html @@ -4,7 +4,7 @@