diff --git a/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc b/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc
index b93c66d..f260f30 100644
Binary files a/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc and b/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc differ
diff --git a/OneCprogsite/OneCprogsite/settings.py b/OneCprogsite/OneCprogsite/settings.py
index 65ac19e..2d73e10 100644
--- a/OneCprogsite/OneCprogsite/settings.py
+++ b/OneCprogsite/OneCprogsite/settings.py
@@ -137,3 +137,25 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
+
+# Настройки email
+EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
+# EMAIL_HOST = 'smtp.yandex.ru' # или smtp.gmail.com, smtp.mail.ru
+# EMAIL_PORT = 587
+# EMAIL_USE_TLS = True
+# EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', 'it@yandex.ru')
+# EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', 'tifdctkrcjcqwxyc')
+# DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
+# SERVER_EMAIL = EMAIL_HOST_USER
+
+EMAIL_HOST = 'smtp.gmail.com' # или smtp.gmail.com, smtp.mail.ru
+EMAIL_PORT = 587
+EMAIL_USE_TLS = True
+EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', 'nikdizell@gmail.com')
+EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', 'qvmw yccb msqv mmpj')
+DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
+SERVER_EMAIL = EMAIL_HOST_USER
+
+# Email для уведомлений (можно указать несколько через запятую)
+# ADMIN_EMAILS = os.getenv('ADMIN_EMAILS', 'nikdizell@gmail.com').split(',')
+ADMIN_EMAILS = os.getenv('ADMIN_EMAILS', 'it@nserdyuk.ru').split(',')
diff --git a/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc
index e52d92c..38271a2 100644
Binary files a/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc and b/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc differ
diff --git a/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc
index e776b38..d708069 100644
Binary files a/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc and b/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc differ
diff --git a/OneCprogsite/programmer/admin.py b/OneCprogsite/programmer/admin.py
index 18a9935..5962719 100644
--- a/OneCprogsite/programmer/admin.py
+++ b/OneCprogsite/programmer/admin.py
@@ -49,6 +49,18 @@ class CallbackAdmin(admin.ModelAdmin):
search_fields = ('name', 'phone', 'email')
readonly_fields = ('time_create',)
actions = ['mark_as_read', 'mark_as_unread', 'mark_as_processed']
+ actions = ['mark_as_read', 'mark_as_unread', 'mark_as_processed', 'resend_notification']
+
+ def resend_notification(self, request, queryset):
+ from .utils.email_notifications import send_callback_notification
+ count = 0
+ for callback in queryset:
+ success = send_callback_notification(callback)
+ if success:
+ count += 1
+ self.message_user(request, f'Уведомления отправлены для {count} заявок')
+
+ resend_notification.short_description = "Переотправить email уведомления"
def new_badge(self, obj):
if not obj.is_read:
diff --git a/OneCprogsite/programmer/management/commands/__pycache__/test_email.cpython-310.pyc b/OneCprogsite/programmer/management/commands/__pycache__/test_email.cpython-310.pyc
new file mode 100644
index 0000000..20b9687
Binary files /dev/null and b/OneCprogsite/programmer/management/commands/__pycache__/test_email.cpython-310.pyc differ
diff --git a/OneCprogsite/programmer/management/commands/send_daily_summary.py b/OneCprogsite/programmer/management/commands/send_daily_summary.py
new file mode 100644
index 0000000..fadba37
--- /dev/null
+++ b/OneCprogsite/programmer/management/commands/send_daily_summary.py
@@ -0,0 +1,33 @@
+# programmer/management/commands/send_daily_summary.py
+from django.core.management.base import BaseCommand
+from django.utils import timezone
+from programmer.utils.email_notifications import send_daily_summary
+
+
+class Command(BaseCommand):
+ help = 'Отправляет ежедневную сводку по заявкам на email'
+
+ def add_arguments(self, parser):
+ parser.add_argument(
+ '--test',
+ action='store_true',
+ help='Тестовая отправка (не учитывает реальные данные)',
+ )
+
+ def handle(self, *args, **options):
+ if options['test']:
+ self.stdout.write(self.style.WARNING('Тестовая отправка ежедневной сводки...'))
+ # Здесь можно добавить тестовые данные
+ else:
+ self.stdout.write('Отправка ежедневной сводки...')
+
+ success = send_daily_summary()
+
+ if success:
+ self.stdout.write(
+ self.style.SUCCESS(f'Ежедневная сводка отправлена успешно! Время: {timezone.now()}')
+ )
+ else:
+ self.stdout.write(
+ self.style.WARNING('Ежедневная сводка не отправлена (нет данных или ошибка)')
+ )
\ No newline at end of file
diff --git a/OneCprogsite/programmer/management/commands/test_email.py b/OneCprogsite/programmer/management/commands/test_email.py
new file mode 100644
index 0000000..b2ccccf
--- /dev/null
+++ b/OneCprogsite/programmer/management/commands/test_email.py
@@ -0,0 +1,29 @@
+# programmer/management/commands/test_email.py
+from django.core.management.base import BaseCommand
+from django.conf import settings
+from programmer.utils.email_notifications import send_test_email
+
+
+class Command(BaseCommand):
+ help = 'Test email configuration'
+
+ def handle(self, *args, **options):
+ self.stdout.write("Testing email configuration...")
+
+ # Проверяем настройки
+ self.stdout.write(f"EMAIL_HOST: {settings.EMAIL_HOST}")
+ self.stdout.write(f"EMAIL_PORT: {settings.EMAIL_PORT}")
+ self.stdout.write(f"EMAIL_HOST_USER: {settings.EMAIL_HOST_USER}")
+ self.stdout.write(f"ADMIN_EMAILS: {settings.ADMIN_EMAILS}")
+
+ # Тестируем отправку
+ success = send_test_email()
+
+ if success:
+ self.stdout.write(
+ self.style.SUCCESS('✅ Test email sent successfully!')
+ )
+ else:
+ self.stdout.write(
+ self.style.ERROR('❌ Failed to send test email. Check your email settings.')
+ )
\ No newline at end of file
diff --git a/OneCprogsite/programmer/migrations/0013_callbackrequest_notification_sent.py b/OneCprogsite/programmer/migrations/0013_callbackrequest_notification_sent.py
new file mode 100644
index 0000000..7308578
--- /dev/null
+++ b/OneCprogsite/programmer/migrations/0013_callbackrequest_notification_sent.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.7 on 2025-11-14 10:03
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('programmer', '0012_callbackrequest_is_read'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='callbackrequest',
+ name='notification_sent',
+ field=models.BooleanField(default=False, verbose_name='Уведомление отправлено'),
+ ),
+ ]
diff --git a/OneCprogsite/programmer/migrations/__pycache__/0013_callbackrequest_notification_sent.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0013_callbackrequest_notification_sent.cpython-310.pyc
new file mode 100644
index 0000000..1bbd4b6
Binary files /dev/null and b/OneCprogsite/programmer/migrations/__pycache__/0013_callbackrequest_notification_sent.cpython-310.pyc differ
diff --git a/OneCprogsite/programmer/models.py b/OneCprogsite/programmer/models.py
index 4b08fa7..4f3165e 100644
--- a/OneCprogsite/programmer/models.py
+++ b/OneCprogsite/programmer/models.py
@@ -4,6 +4,7 @@ from django.utils import timezone
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.core.cache import cache
+from .utils.email_notifications import send_callback_notification
class Recall(models.Model):
@@ -95,6 +96,7 @@ class CallbackRequest(models.Model):
time_create = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')
is_processed = models.BooleanField(default=False, verbose_name='Обработано')
is_read = models.BooleanField(default=False, verbose_name='Прочитано')
+ notification_sent = models.BooleanField(default=False, verbose_name='Уведомление отправлено')
def __str__(self):
return f"{self.name} - {self.phone}"
@@ -105,6 +107,18 @@ class CallbackRequest(models.Model):
ordering = ['-time_create']
+# Сигнал для отправки уведомления при создании заявки
+@receiver(post_save, sender=CallbackRequest)
+def send_callback_email_notification(sender, instance, created, **kwargs):
+ if created and not instance.notification_sent:
+ # Отправляем email уведомление
+ success = send_callback_notification(instance)
+ if success:
+ instance.notification_sent = True
+ # Сохраняем без повторного вызова сигнала
+ sender.objects.filter(pk=instance.pk).update(notification_sent=True)
+
+
class PageView(models.Model):
url = models.CharField(max_length=500)
timestamp = models.DateTimeField(default=timezone.now)
diff --git a/OneCprogsite/programmer/templates/emails/callback_notification.html b/OneCprogsite/programmer/templates/emails/callback_notification.html
new file mode 100644
index 0000000..4e7cdd8
--- /dev/null
+++ b/OneCprogsite/programmer/templates/emails/callback_notification.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ⚠️ Срочно! Пользователь оставил заявку на обратный звонок.
+
+
+
+
📋 Информация о заявке:
+
👤 Имя: {{ callback.name }}
+
📞 Телефон: {{ callback.phone }}
+ {% if callback.email %}
+
📧 Email: {{ callback.email }}
+ {% endif %}
+ {% if callback.question %}
+
❓ Вопрос:
{{ callback.question }}
+ {% endif %}
+
🕒 Время отправки: {{ callback.time_create|date:"d.m.Y H:i" }}
+
+
+
+
+
Не забудьте отметить заявку как обработанную после связи с клиентом!
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OneCprogsite/programmer/templates/emails/daily_summary.html b/OneCprogsite/programmer/templates/emails/daily_summary.html
new file mode 100644
index 0000000..7886975
--- /dev/null
+++ b/OneCprogsite/programmer/templates/emails/daily_summary.html
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
📅 Вчерашние заявки
+
{{ yesterday_callbacks }}
+
+
+
+
⏳ Ожидают обработки
+
{{ unprocessed_callbacks }}
+
+
+
+ {% if unprocessed_callbacks > 0 %}
+
+ ⚠️ Внимание! У вас есть {{ unprocessed_callbacks }} необработанных заявок.
+
+ {% endif %}
+
+
+
+
Не забудьте обработать все pending заявки!
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OneCprogsite/programmer/utils/__pycache__/email_notifications.cpython-310.pyc b/OneCprogsite/programmer/utils/__pycache__/email_notifications.cpython-310.pyc
new file mode 100644
index 0000000..12f89e7
Binary files /dev/null and b/OneCprogsite/programmer/utils/__pycache__/email_notifications.cpython-310.pyc differ
diff --git a/OneCprogsite/programmer/utils/email_notifications.py b/OneCprogsite/programmer/utils/email_notifications.py
new file mode 100644
index 0000000..fa902a8
--- /dev/null
+++ b/OneCprogsite/programmer/utils/email_notifications.py
@@ -0,0 +1,65 @@
+# programmer/utils/email_notifications.py
+from django.core.mail import send_mail, EmailMultiAlternatives
+from django.template.loader import render_to_string
+from django.conf import settings
+from django.utils.html import strip_tags
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+def send_callback_notification(callback_request):
+ """
+ Отправляет уведомление о новой заявке на обратный звонок
+ """
+ try:
+ subject = f'🚨 Новая заявка на обратный звонок от {callback_request.name}'
+
+ # HTML версия письма
+ html_message = render_to_string('emails/callback_notification.html', {
+ 'callback': callback_request,
+ 'site_url': settings.ALLOWED_HOSTS[0] if settings.ALLOWED_HOSTS else 'localhost',
+ })
+
+ # Текстовая версия письма
+ plain_message = strip_tags(html_message)
+
+ # Проверяем настройки email
+ if not all([settings.EMAIL_HOST_USER, settings.EMAIL_HOST_PASSWORD]):
+ logger.error("Email settings are not configured properly")
+ return False
+
+ # Отправляем email
+ send_mail(
+ subject=subject,
+ message=plain_message,
+ from_email=settings.DEFAULT_FROM_EMAIL,
+ recipient_list=settings.ADMIN_EMAILS,
+ html_message=html_message,
+ fail_silently=False,
+ )
+
+ logger.info(f"Email notification sent successfully for callback #{callback_request.id}")
+ return True
+
+ except Exception as e:
+ logger.error(f"Error sending email notification: {e}")
+ return False
+
+
+def send_test_email():
+ """
+ Функция для тестирования отправки email
+ """
+ try:
+ send_mail(
+ subject='📧 Test Email from Django',
+ message='This is a test email from your Django application.',
+ from_email=settings.DEFAULT_FROM_EMAIL,
+ recipient_list=settings.ADMIN_EMAILS,
+ fail_silently=False,
+ )
+ return True
+ except Exception as e:
+ logger.error(f"Test email failed: {e}")
+ return False