diff --git a/apps/notification/management/commands/send_camp_certificates.py b/apps/notification/management/commands/send_camp_certificates.py new file mode 100644 index 00000000..3386afe2 --- /dev/null +++ b/apps/notification/management/commands/send_camp_certificates.py @@ -0,0 +1,32 @@ +from django.core.management.base import BaseCommand + +from apps.notification.tasks import send_camp_certificates + + +class Command(BaseCommand): + help = 'Send camp certificates at the end of month' + + def add_arguments(self, parser): + # Named (optional) arguments + parser.add_argument( + '--email', + dest='email', + help='Test email', + ) + parser.add_argument( + '--cert', + dest='certificate_number', + type=int, + help='Certificate number', + ) + parser.add_argument( + '--dry-run', + action='store_true', + dest='dry_run', + help='Only display emails', + ) + + def handle(self, *args, **options): + send_camp_certificates(email=options.get('email'), certificate_number=options.get('certificate_number'), + dry_run=options.get('dry_run')) + diff --git a/apps/notification/management/commands/send_certificates.py b/apps/notification/management/commands/send_certificates.py index 7ce5b8f4..49dc48c6 100644 --- a/apps/notification/management/commands/send_certificates.py +++ b/apps/notification/management/commands/send_certificates.py @@ -26,5 +26,5 @@ class Command(BaseCommand): ) def handle(self, *args, **options): - send_certificates(email=options.get('email'), date=options.get('date'), dry_run=options.get('dry_run')) + send_certificates(email=options.get('email'), date_end=options.get('date'), dry_run=options.get('dry_run')) diff --git a/apps/notification/migrations/0002_usernotification_camp_certificate_last_email.py b/apps/notification/migrations/0002_usernotification_camp_certificate_last_email.py new file mode 100644 index 00000000..398778bf --- /dev/null +++ b/apps/notification/migrations/0002_usernotification_camp_certificate_last_email.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.7 on 2019-05-23 01:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('notification', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='usernotification', + name='camp_certificate_last_email', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/apps/notification/models.py b/apps/notification/models.py index 6aa5d513..c60c91cc 100644 --- a/apps/notification/models.py +++ b/apps/notification/models.py @@ -9,3 +9,4 @@ class UserNotification(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) 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) diff --git a/apps/notification/tasks.py b/apps/notification/tasks.py index cce0ea4d..32f5db6d 100644 --- a/apps/notification/tasks.py +++ b/apps/notification/tasks.py @@ -1,5 +1,5 @@ import os -from datetime import datetime +from datetime import datetime, date, timedelta from PIL import Image from PIL import ImageFont from PIL import ImageDraw @@ -12,7 +12,7 @@ from django.conf import settings from apps.notification.models import UserNotification from apps.notification.utils import send_email -from apps.payment.models import SchoolPayment, CoursePayment, Payment, UserGiftCertificate, UserBonus +from apps.payment.models import SchoolPayment, CoursePayment, Payment, UserGiftCertificate, UserBonus, DrawingCampPayment from project.celery import app from project.utils.db import format_sql, execute_sql from project.sengrid import get_sendgrid_client @@ -21,27 +21,28 @@ from project.sengrid import get_sendgrid_client User = get_user_model() -def draw_cert(path, email, first_name, last_name): +def draw_cert(path, email, first_name, last_name, x=None, y=900, color=(29, 115, 224), font_size=170, fn_prefix=''): img = Image.open(path) draw = ImageDraw.Draw(img) - font = ImageFont.truetype(os.path.join(settings.STATIC_ROOT, 'ProximaNova-Reg.otf'), 170) + font = ImageFont.truetype(os.path.join(settings.STATIC_ROOT, 'ProximaNova-Reg.otf'), font_size) text = first_name.capitalize() if last_name: text += ' ' + last_name.capitalize() w, h = draw.textsize(text, font=font) - draw.text(((img.width - w) // 2, 900), text, (29, 115, 224), font=font) + _x = (img.width - w) // 2 if x is None else x + draw.text((_x, y), text, color, font=font) fn = os.path.join(settings.MEDIA_ROOT, 'tmp') try: os.mkdir(fn) except: pass - fn = os.path.join(fn, 'certificate-for-%s.jpg' % email) + fn = os.path.join(fn, '%scertificate-for-%s.jpg' % (fn_prefix, email)) img.save(fn) img.close() return fn @app.task -def send_certificates(email=None, date=None, dry_run=False): +def send_certificates(email=None, date_end=None, dry_run=False): path_pattern = 'img/user-certificates/%d.jpg' signed_path_pattern = 'img/signed-user-certificates/%d.jpg' if email: @@ -59,9 +60,9 @@ def send_certificates(email=None, date=None, dry_run=False): os.remove(fn) return - date = datetime.strptime(date, '%d-%m-%Y').date() if date else now().date() + date_end = datetime.strptime(date_end, '%d-%m-%Y').date() if date_end else now().date() today = now().date() - users = set(list(SchoolPayment.objects.paid().filter(date_end=date, add_days=False).values_list('user_id', flat=True))) + users = set(list(SchoolPayment.objects.paid().filter(date_end=date_end, add_days=False).values_list('user_id', flat=True))) user_notifications_qs = UserNotification.objects.filter(user_id__in=users) user_notifications = {un.user_id: un for un in user_notifications_qs} notified_users = user_notifications_qs.filter(certificate_last_email__date=today).values_list( @@ -160,3 +161,64 @@ def send_child_birthday_email_and_bonuses(): print('email has been sent') finally: file.close() + +@app.task +def send_camp_certificates(email=None, dry_run=False, certificate_number=None): + path_pattern = 'img/camp-certificates/%d.jpg' + color = (35, 59, 227) + if certificate_number is None: + certificate_number = 1 + if certificate_number == 2: + color = (0, 27, 94) + if email: + fn = draw_cert(staticfiles_storage.path(path_pattern % certificate_number), email, 'Имя', 'Фамилия', + font_size=70, y=550, color=color) + file = open(fn, 'rb') + try: + pass + send_email('Грамота от Lil School', email, 'notification/email/camp_certificate.html', + attachments=[(file.name, file.read(), 'image/jpeg')], certificate_number=certificate_number) + except: + pass + else: + print('Email has been sent') + finally: + file.close() + os.remove(fn) + return + + date_end = date(now().year, 6 + certificate_number, 1) - timedelta(1) + users = set(list(DrawingCampPayment.objects.paid().filter(date_end=date_end).values_list('user_id', flat=True))) + user_notifications_qs = UserNotification.objects.filter(user_id__in=users) + user_notifications = {un.user_id: un for un in user_notifications_qs} + notified_users = user_notifications_qs.filter(camp_certificate_last_email__date=date_end).values_list( + 'user_id', flat=True).distinct() + for user_id in users: + if user_id in notified_users: + print('skip', user_id) + continue + un = user_notifications.get(user_id, UserNotification(user_id=user_id)) + print(un.user.email) + if dry_run: + continue + + if un.user.child_first_name: + fn = staticfiles_storage.path(path_pattern % certificate_number) + fn = draw_cert(fn, un.user.email, un.user.child_first_name, un.user.child_last_name, + font_size=70, y=550, color=color) + else: + fn = staticfiles_storage.path(path_pattern % certificate_number) + file = open(fn, 'rb') + try: + send_email('Грамота от Lil School', un.user.email, 'notification/email/camp_certificate.html', + attachments=[(file.name, file.read(), 'image/jpeg')], user_notification=un, + certificate_number=certificate_number) + except: + print('Not OK') + continue + finally: + file.close() + if un.user.child_first_name: + os.remove(fn) + un.camp_certificate_last_email = date_end + un.save() diff --git a/apps/notification/templates/notification/email/camp_certificate.html b/apps/notification/templates/notification/email/camp_certificate.html new file mode 100644 index 00000000..98f83bbf --- /dev/null +++ b/apps/notification/templates/notification/email/camp_certificate.html @@ -0,0 +1,25 @@ +{% extends "notification/email/_base.html" %} + +{% block content %} +

Привет!

+
+ {% if certificate_number == 1 %} +

+Поздравляем! Вы прошли месяц обучения в лагере Lil School.
+К письму прикреплена грамота. Распечатайте её и вручите вашим детям.
+Ждём вас в следующем месяце на наших творческих занятиях! +

+ {% endif %} + {% if certificate_number == 2 %} +

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

+ {% endif %} +
+
+

+ Команда «Lil School». +

+
+{% endblock content %} diff --git a/project/settings.py b/project/settings.py index bb9b1b40..2cd1afd3 100644 --- a/project/settings.py +++ b/project/settings.py @@ -267,6 +267,16 @@ CELERY_BEAT_SCHEDULE = { 'schedule': crontab(minute=0, hour=0), 'args': (), }, + 'send_june_camp_certificates': { + 'task': 'apps.notification.tasks.send_camp_certificates', + 'schedule': crontab(0, 9, day_of_month='1', month_of_year='7'), + 'kwargs': {'certificate_number': 2}, + }, + 'send_jule_camp_certificates': { + 'task': 'apps.notification.tasks.send_camp_certificates', + 'schedule': crontab(0, 9, day_of_month='1', month_of_year='8'), + 'kwargs': {'certificate_number': 2}, + }, } try: diff --git a/web/src/img/camp-certificates/1.jpg b/web/src/img/camp-certificates/1.jpg new file mode 100644 index 00000000..ac240fe5 Binary files /dev/null and b/web/src/img/camp-certificates/1.jpg differ diff --git a/web/src/img/camp-certificates/2.jpg b/web/src/img/camp-certificates/2.jpg new file mode 100644 index 00000000..21cfe9d7 Binary files /dev/null and b/web/src/img/camp-certificates/2.jpg differ diff --git a/web/webpack.config.js b/web/webpack.config.js index 08ac624e..1cb88186 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -20,6 +20,7 @@ module.exports = { imagesCertificates: glob('./src/img/user-certificates/*'), imagesSignedCertificates: glob('./src/img/signed-user-certificates/*'), imagesGiftCertificates: glob('./src/img/gift-certificates/*'), + imagesCampCertificates: glob('./src/img/camp-certificates/*'), imagesReviews: glob('./src/img/reviews/*'), fonts: glob('./src/fonts/*'), sounds: glob('./src/sounds/*'), @@ -93,7 +94,7 @@ module.exports = { test: /\.(png|gif|jpg|svg)$/, exclude: [path.resolve(__dirname, 'src/icons'), path.resolve(__dirname, 'src/img/user-certificates'), path.resolve(__dirname, 'src/img/gift-certificates'), path.resolve(__dirname, 'src/img/reviews'), - path.resolve(__dirname, 'src/img/signed-user-certificates')], + path.resolve(__dirname, 'src/img/signed-user-certificates'), path.resolve(__dirname, 'src/img/camp-certificates')], loader: 'file-loader?name=[name].[ext]&outputPath=./img/' }, { @@ -111,6 +112,11 @@ module.exports = { include: path.resolve(__dirname, 'src/img/gift-certificates'), loader: 'file-loader?name=[name].[ext]&outputPath=./img/gift-certificates/' }, + { + test: /\.(png|jpg)$/, + include: path.resolve(__dirname, 'src/img/camp-certificates'), + loader: 'file-loader?name=[name].[ext]&outputPath=./img/camp-certificates/' + }, { test: /\.(png|jpg)$/, include: path.resolve(__dirname, 'src/img/reviews'),