renew commit

This commit is contained in:
2024-10-29 16:13:58 +09:00
parent f17c6b3a1a
commit d1855a1af8
34 changed files with 573 additions and 348 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
__pycache__ __pycache__
.venv .venv
.history .history
static/qr_codes

1
smartsoltech/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
static/qr-qr_codes

View File

@@ -126,6 +126,7 @@
import telebot import telebot
from telebot import types
from decouple import config from decouple import config
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from web.models import Client, ServiceRequest, Order from web.models import Client, ServiceRequest, Order
@@ -152,7 +153,10 @@ class TelegramBot:
if match: if match:
self.handle_confirm_command(message, match) self.handle_confirm_command(message, match)
elif message.text.strip() == '/start': elif message.text.strip() == '/start':
self.bot.reply_to(message, "Ошибка: Некорректная команда. Пожалуйста, используйте ссылку, предоставленную на сайте для регистрации.") kbd = types.InlineKeyboardMarkup()
url_btn = types.InlineKeyboardButton('Перейти на сайт', url=config("URL"))
kbd.add(url_btn)
self.bot.reply_to(message, "Здравствуйте! Данный бот предназначен для информирования клиентов SmartSolTech и регистрации на сайте. Пройдите на сайт для получения информации.", reply_markup = kbd)
else: else:
self.bot.reply_to(message, "Здравствуйте! Пожалуйста, используйте команду /start с корректными параметрами для подтверждения регистрации.") self.bot.reply_to(message, "Здравствуйте! Пожалуйста, используйте команду /start с корректными параметрами для подтверждения регистрации.")
@@ -161,11 +165,14 @@ class TelegramBot:
chat_id = message.chat.id chat_id = message.chat.id
client = Client.objects.filter(chat_id=chat_id).first() client = Client.objects.filter(chat_id=chat_id).first()
if client: if client:
service_requests = ServiceRequest.objects.filter(client_email=client.email) service_requests = ServiceRequest.objects.filter(chat_id=client.chat_id)
if service_requests.exists(): if service_requests.exists():
response = "Ваши заявки:\n" response = "Ваши заявки:\n"
for req in service_requests: for req in service_requests:
response += f"Номер заявки: {req.id}, Услуга: {req.service.name}, Дата создания: {req.created_at.strftime('%d-%m-%Y')}\n" response += f"Номер заявки: {req.id}\n" \
f"Услуга: {req.service.name}\n" \
f"Дата создания: {req.created_at.strftime('%Y-%m-%d')}\n" \
f"UID заявки: {req.token}\n"
else: else:
response = "У вас нет активных заявок." response = "У вас нет активных заявок."
else: else:
@@ -198,16 +205,14 @@ class TelegramBot:
request_id = match.group(1) request_id = match.group(1)
encoded_token = match.group(2) encoded_token = match.group(2)
# Декодируем токен из base64 # Декодируем токен
try: try:
token = base64.urlsafe_b64decode(encoded_token + '==').decode('utf-8') token = base64.urlsafe_b64decode(encoded_token + '==').decode('utf-8')
logging.info(f"Декодированный токен: {token}")
except Exception as e: except Exception as e:
logging.error(f"Ошибка при декодировании токена: {e}")
self.bot.send_message(chat_id, "Ошибка: Некорректный токен. Пожалуйста, повторите попытку позже.") self.bot.send_message(chat_id, "Ошибка: Некорректный токен. Пожалуйста, повторите попытку позже.")
return return
# Получаем заявку по ID и токену # Получаем заявку
service_request = ServiceRequest.objects.filter(id=request_id, token=token).first() service_request = ServiceRequest.objects.filter(id=request_id, token=token).first()
if service_request: if service_request:
# Обновляем chat_id клиента # Обновляем chat_id клиента
@@ -215,12 +220,19 @@ class TelegramBot:
service_request.client_name = message.from_user.first_name service_request.client_name = message.from_user.first_name
service_request.save() service_request.save()
response_message = ( # Отправляем данные обратно на сервер для создания заявки
f"Здравствуйте, {message.from_user.first_name}!\n" data = {
f"Ваш Telegram аккаунт успешно подтвержден. Пожалуйста, вернитесь на сайт для заполнения остальных данных." "service_request_id": request_id,
) "client_name": message.from_user.first_name,
"client_chat_id": chat_id
}
response = requests.post('http://localhost:8000/service/send_telegram_notification/', json=data)
if response.status_code == 200:
self.bot.send_message(chat_id, "Ваш аккаунт успешно подтвержден! Вернитесь на сайт для продолжения.")
else: else:
response_message = "Ошибка: Неверная заявка или токен. Пожалуйста, проверьте ссылку." self.bot.send_message(chat_id, "Ошибка при подтверждении. Пожалуйста, повторите попытку позже.")
else:
self.bot.send_message(chat_id, "Ошибка: Неверная заявка или токен. Пожалуйста, проверьте ссылку.")
self.bot.send_message(chat_id, response_message) self.bot.send_message(chat_id, response_message)
else: else:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -43,6 +43,6 @@ class CategoryAdmin(admin.ModelAdmin):
@admin.register(ServiceRequest) @admin.register(ServiceRequest)
class ServiceRequestAdmin(admin.ModelAdmin): class ServiceRequestAdmin(admin.ModelAdmin):
list_display = ('service','token', 'chat_id','client_name', 'client_email', 'client_phone', 'created_at') list_display = ('service','token', 'client', 'created_at')
search_fields = ('service','token','client_name', 'client_email', 'client_phone') search_fields = ('service','token', 'client')
list_filter = ('service','token','client_name', 'client_phone') list_filter = ('service','token','client')

View File

@@ -0,0 +1,20 @@
# Generated by Django 5.1.1 on 2024-10-14 11:10
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0005_alter_blogpost_options_alter_category_options_and_more'),
]
operations = [
migrations.AddField(
model_name='order',
name='service_request',
field=models.OneToOneField(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='related_order', to='web.servicerequest'),
preserve_default=False,
),
]

View File

@@ -0,0 +1,32 @@
# Generated by Django 5.1.1 on 2024-10-14 11:46
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0006_order_service_request'),
]
operations = [
migrations.RemoveField(
model_name='servicerequest',
name='client_email',
),
migrations.RemoveField(
model_name='servicerequest',
name='client_name',
),
migrations.RemoveField(
model_name='servicerequest',
name='client_phone',
),
migrations.AddField(
model_name='servicerequest',
name='client',
field=models.ForeignKey(default=12, on_delete=django.db.models.deletion.CASCADE, related_name='related_service_requests', to='web.client'),
preserve_default=False,
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.1.1 on 2024-10-14 11:48
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0007_remove_servicerequest_client_email_and_more'),
]
operations = [
migrations.AlterField(
model_name='servicerequest',
name='client',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='related_service_requests', to='web.client'),
),
]

View File

@@ -70,9 +70,25 @@ class BlogPost(models.Model):
def __str__(self): def __str__(self):
return self.title return self.title
class ServiceRequest(models.Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE)
client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name='related_service_requests', null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
token = models.UUIDField(default=uuid.uuid4, unique=True) # Генерация уникального токена
chat_id = models.CharField(max_length=100, blank=True, null=True) # Telegram chat ID
class Meta:
verbose_name = 'Заявка на услугу'
verbose_name_plural = 'Заявки на услуги'
ordering = ['-created_at']
def __str__(self):
return f"Request for {self.service.name} by {self.client.first_name}"
class Order(models.Model): class Order(models.Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name='related_orders') service_request = models.OneToOneField(ServiceRequest, on_delete=models.CASCADE, related_name='related_order')
client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name='related_orders') client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name='related_orders')
service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name='related_orders')
message = models.TextField(blank=True, null=True) message = models.TextField(blank=True, null=True)
order_date = models.DateTimeField(auto_now_add=True) order_date = models.DateTimeField(auto_now_add=True)
status = models.CharField( status = models.CharField(
@@ -136,19 +152,3 @@ class Review(models.Model):
def __str__(self): def __str__(self):
return f"Review by {self.client.first_name} {self.client.last_name} for {self.service.name}" return f"Review by {self.client.first_name} {self.client.last_name} for {self.service.name}"
class ServiceRequest(models.Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE)
client_name = models.CharField(max_length=100)
client_email = models.EmailField()
client_phone = models.CharField(max_length=20)
created_at = models.DateTimeField(auto_now_add=True)
token = models.UUIDField(default=uuid.uuid4, unique=True) # Генерация уникального токена
chat_id = models.CharField(max_length=100, blank=True, null=True) # Telegram chat ID
class Meta:
verbose_name = 'Заявка на услугу'
verbose_name_plural = 'Заявки на услуги'
ordering = ['-created_at']
def __str__(self):
return f"Request for {self.service.name} by {self.client_name}"

View File

@@ -44,7 +44,7 @@
} }
#qrCodeImg { #qrCodeImg {
display: block; display: none;
margin: 20px auto; margin: 20px auto;
width: 200px; width: 200px;
height: 200px; height: 200px;
@@ -58,17 +58,7 @@
<div class="modal-content"> <div class="modal-content">
<span class="close">&times;</span> <span class="close">&times;</span>
<h4>Заполните заявку на услугу</h4> <h4>Заполните заявку на услугу</h4>
<p>QR-код для завершения регистрации:</p>
<img id="qrCodeImg" src="" alt="QR Code">
<form id="serviceRequestForm"> <form id="serviceRequestForm">
<div class="form-group">
<label for="clientName">Ваше имя:</label>
<input type="text" class="form-control" id="clientName" name="client_name" placeholder="Введите ваше имя" required minlength="2" maxlength="50" readonly>
</div>
<div class="form-group">
<label for="clientChatId">Ваш chat ID:</label>
<input type="text" class="form-control" id="clientChatId" name="client_chat_id" placeholder="Ваш chat ID" readonly>
</div>
<div class="form-group"> <div class="form-group">
<label for="clientEmail">Ваш email:</label> <label for="clientEmail">Ваш email:</label>
<input type="email" class="form-control" id="clientEmail" name="client_email" placeholder="Введите ваш email" required> <input type="email" class="form-control" id="clientEmail" name="client_email" placeholder="Введите ваш email" required>
@@ -81,71 +71,101 @@
<label for="description">Описание заявки:</label> <label for="description">Описание заявки:</label>
<textarea class="form-control" id="description" name="description" placeholder="Опишите вашу заявку" required></textarea> <textarea class="form-control" id="description" name="description" placeholder="Опишите вашу заявку" required></textarea>
</div> </div>
<button type="submit" class="btn btn-success" id="submitButton" disabled>Отправить заявку</button> <button type="button" class="btn btn-primary" id="generateQrButton">Продолжить</button>
</form> </form>
<div id="qrCodeContainer">
<p>QR-код для завершения регистрации:</p>
<img id="qrCodeImg" src="" alt="QR Code">
</div>
</div>
</div>
<div id="confirmationModal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h4>Заявка успешно создана!</h4>
<p>Ваши данные были отправлены и заявка зарегистрирована. Пожалуйста, проверьте ваш Telegram для получения подтверждения.</p>
</div> </div>
</div> </div>
<script> <script>
// Обработчик открытия модального окна // Обработчик открытия модального окна
document.getElementById('openModalBtn').addEventListener('click', function () { document.getElementById('openModalBtn').addEventListener('click', function () {
const serviceId = this.getAttribute('data-service-id');
// Открываем модальное окно // Открываем модальное окно
document.getElementById('serviceModal').style.display = 'block'; document.getElementById('serviceModal').style.display = 'block';
// Выполняем запрос на генерацию QR-кода
fetch(`/service/generate_qr_code/${serviceId}/`)
.then(response => response.json())
.then(data => {
// Обновляем src изображения QR-кода
document.getElementById('qrCodeImg').src = data.qr_code_url;
// Запуск проверки статуса каждые 5 секунд
const interval = setInterval(() => {
checkVerificationStatus(data.service_request_id, interval);
}, 5000);
})
.catch(error => console.error('Ошибка при генерации QR-кода:', error));
}); });
// Обработчик закрытия модального окна // Обработчик закрытия модального окна
document.querySelector('.close').addEventListener('click', function () { document.querySelectorAll('.close').forEach(closeBtn => {
closeBtn.addEventListener('click', function () {
document.getElementById('serviceModal').style.display = 'none'; document.getElementById('serviceModal').style.display = 'none';
document.getElementById('confirmationModal').style.display = 'none';
});
}); });
// Обработчик отправки формы // Обработчик кнопки "Продолжить" для генерации QR-кода
document.getElementById('serviceRequestForm').addEventListener('submit', function (event) { document.getElementById('generateQrButton').addEventListener('click', function () {
event.preventDefault(); const clientEmail = document.getElementById('clientEmail').value;
const formData = new FormData(this); const clientPhone = document.getElementById('clientPhone').value;
const serviceId = document.getElementById('openModalBtn').getAttribute('data-service-id'); const description = document.getElementById('description').value;
// Отправка данных формы на сервер
fetch('/service/request/' + serviceId + '/', { if (clientEmail && clientPhone && description) {
method: 'POST', // Выполняем запрос на генерацию QR-кода
body: formData const openModalBtn = document.getElementById('openModalBtn');
}).then(response => { if (!openModalBtn) {
if (response.ok) { console.error('Не удалось найти элемент openModalBtn');
alert('Заявка успешно отправлена!'); return;
document.getElementById('serviceModal').style.display = 'none'; }
// Отправка сообщения в Telegram
sendTelegramNotification(formData); const serviceId = openModalBtn.getAttribute('data-service-id');
} else { if (!serviceId) {
alert('Ошибка при отправке заявки. Пожалуйста, попробуйте снова.'); console.error('Не удалось найти идентификатор услуги');
return;
}
fetch(`/service/generate_qr_code/${serviceId}/`)
.then(response => {
if (!response.ok) {
throw new Error('Ошибка при генерации QR-кода');
}
return response.json();
})
.then(data => {
// Проверка наличия ссылки на QR-код в ответе
if (!data.qr_code_url) {
throw new Error('Ответ не содержит QR-код');
}
// Обновляем src изображения QR-кода и показываем его
const qrCodeImg = document.getElementById('qrCodeImg');
qrCodeImg.src = data.qr_code_url;
qrCodeImg.style.display = 'block';
// Запуск проверки статуса каждые 5 секунд
const interval = setInterval(() => {
checkVerificationStatus(data.service_request_id, interval, clientEmail, clientPhone, description);
}, 5000);
})
.catch(error => {
console.error('Ошибка при генерации QR-кода:', error);
});
} else {
console.error('Поля email, телефон и описание обязательны');
} }
}).catch(error => console.error('Ошибка при отправке данных формы:', error));
}); });
// Проверка статуса заявки на наличие подтверждения Telegram // Проверка статуса заявки на наличие подтверждения Telegram
const checkVerificationStatus = (serviceRequestId, interval) => { const checkVerificationStatus = (serviceRequestId, interval, clientEmail, clientPhone, description) => {
fetch(`/service/request_status/${serviceRequestId}/`) fetch(`/service/request_status/${serviceRequestId}/`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.is_verified) { if (data.is_verified) {
// Заполнение полей формы данными пользователя // Закрываем форму и открываем окно подтверждения
document.getElementById('clientName').value = data.client_name; document.getElementById('serviceModal').style.display = 'none';
document.getElementById('clientChatId').value = data.client_chat_id; document.getElementById('confirmationModal').style.display = 'block';
// Активируем кнопку отправки, если все поля заполнены // Создание заявки с использованием данных формы и Telegram
updateButtonState(); createServiceRequest(serviceRequestId, data.client_name, data.client_chat_id, clientEmail, clientPhone, description);
// Останавливаем интервал проверки статуса // Останавливаем интервал проверки статуса
clearInterval(interval); clearInterval(interval);
@@ -154,43 +174,36 @@
.catch(error => console.error('Ошибка при проверке статуса заявки:', error)); .catch(error => console.error('Ошибка при проверке статуса заявки:', error));
}; };
// Код для активации кнопки "Отправить" при заполнении всех полей // Создание заявки с использованием данных из формы и Telegram
const clientEmail = document.getElementById('clientEmail'); const createServiceRequest = (serviceRequestId, clientName, chatId, clientEmail, clientPhone, description) => {
const clientPhone = document.getElementById('clientPhone'); fetch('/service/create_request/', {
const clientName = document.getElementById('clientName'); method: 'POST',
const description = document.getElementById('description'); headers: {
const clientChatId = document.getElementById('clientChatId'); 'Content-Type': 'application/json'
const submitButton = document.getElementById('submitButton'); },
body: JSON.stringify({
const updateButtonState = () => { service_request_id: serviceRequestId,
if (clientEmail.value && clientPhone.value && clientName.value && description.value && clientChatId.value) { client_name: clientName,
submitButton.disabled = false; client_chat_id: chatId,
client_email: clientEmail,
client_phone: clientPhone,
description: description
})
}).then(response => {
if (response.ok) {
console.log('Заявка успешно создана');
sendTelegramNotification({ client_name: clientName, client_chat_id: chatId, description: description });
} else { } else {
submitButton.disabled = true; console.error('Ошибка при создании заявки');
} }
}).catch(error => console.error('Ошибка при создании заявки:', error));
}; };
// Привязка событий к полям для обновления состояния кнопки отправки
clientEmail.addEventListener('input', updateButtonState);
clientPhone.addEventListener('input', updateButtonState);
description.addEventListener('input', updateButtonState);
// Удаление placeholder при установке фокуса на поле
document.querySelectorAll('input, textarea').forEach(field => {
field.addEventListener('focus', function () {
this.dataset.placeholder = this.placeholder;
this.placeholder = '';
});
field.addEventListener('blur', function () {
this.placeholder = this.dataset.placeholder;
});
});
// Функция для отправки уведомления в Telegram // Функция для отправки уведомления в Telegram
const sendTelegramNotification = (formData) => { const sendTelegramNotification = (data) => {
const clientName = formData.get('client_name'); const clientName = data.client_name;
const serviceDescription = formData.get('description'); const serviceDescription = data.description;
const chatId = formData.get('client_chat_id'); const chatId = data.client_chat_id;
const message = `Здравствуйте, ${clientName}! Ваша заявка успешно зарегистрирована. Детали: ${serviceDescription}`; const message = `Здравствуйте, ${clientName}! Ваша заявка успешно зарегистрирована. Детали: ${serviceDescription}`;
fetch('/service/send_telegram_notification/', { fetch('/service/send_telegram_notification/', {
@@ -208,6 +221,7 @@
}).catch(error => console.error('Ошибка при отправке уведомления в Telegram:', error)); }).catch(error => console.error('Ошибка при отправке уведомления в Telegram:', error));
}; };
</script> </script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body> </body>

View File

@@ -1,161 +1,214 @@
<!-- web/templates/web/modal_order_form.html --> <!DOCTYPE html>
<div id="orderModal" class="modal fade" tabindex="-1"> <html lang="ru">
<div class="modal-dialog"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<title>Модальное окно для заявки на услугу</title>
<style>
/* Стили для модального окна */
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
max-width: 600px;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
#qrCodeImg {
display: block;
margin: 20px auto;
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<!-- Модальное окно -->
<div id="serviceModal" class="modal">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <span class="close">&times;</span>
<h5 class="modal-title">Оформление заявки на услугу</h5> <h4>Заполните заявку на услугу</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <p>QR-код для завершения регистрации:</p>
<img id="qrCodeImg" src="" alt="QR Code">
<form id="serviceRequestForm">
<div class="form-group">
<label for="clientName">Ваше имя:</label>
<input type="text" class="form-control" id="clientName" name="client_name" placeholder="Введите ваше имя" required minlength="2" maxlength="50" readonly>
</div> </div>
<div class="modal-body"> <div class="form-group">
<form id="orderForm" method="post" action="{% url 'create_service_request' service_id=service.pk %}"> <label for="clientChatId">Ваш chat ID:</label>
{% csrf_token %} <input type="text" class="form-control" id="clientChatId" name="client_chat_id" placeholder="Ваш chat ID" readonly>
<div class="form-group mb-3">
<label class="form-label">Имя</label>
<input id="client_name" class="form-control" type="text" name="client_name" required minlength="2" maxlength="50" />
</div> </div>
<div class="form-group mb-3"> <div class="form-group">
<label class="form-label">Телефон</label> <label for="clientEmail">Ваш email:</label>
<input id="client_phone" class="form-control" type="tel" name="client_phone" required pattern="^\+?[0-9\s\-]{7,15}$" /> <input type="email" class="form-control" id="clientEmail" name="client_email" placeholder="Введите ваш email" required>
</div> </div>
<div class="form-group mb-3"> <div class="form-group">
<label class="form-label">Адрес электронной почты</label> <label for="clientPhone">Ваш телефон:</label>
<input id="client_email" class="form-control" type="email" name="client_email" required /> <input type="text" class="form-control" id="clientPhone" name="client_phone" placeholder="Введите ваш телефон" required pattern="^\+?[0-9\s\-]{7,15}$">
</div> </div>
<div class="form-group mb-3 text-center"> <div class="form-group">
<label class="form-label">Сканируйте QR код для регистрации в Telegram боте</label> <label for="description">Описание заявки:</label>
<div id="qrCodeContainer"> <textarea class="form-control" id="description" name="description" placeholder="Опишите вашу заявку" required></textarea>
<img id="qrCodeImage" src="{{ qr_code_url }}" alt="QR код для Telegram бота" class="img-fluid" style="max-width: 150px;" />
</div>
<div class="form-group mt-3">
<a id="registrationLink" href="#" target="_blank">Перейдите по этой ссылке для регистрации в Telegram боте</a>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
<button type="submit" class="btn btn-primary" id="submitButton" disabled>Отправить заявку</button>
</div> </div>
<button type="submit" class="btn btn-success" id="submitButton" disabled>Отправить заявку</button>
</form> </form>
{% comment %} <div id="diagnostic_info" class="mt-3">
<form id="registrationForm">
<h3>Диагностическая информация</h3>
<div class="form-group mb-3">
<label for="registrationLinkField" class="form-label">Ссылка для регистрации в Telegram боте:</label>
<input type="text" id="registrationLinkField" class="form-control" readonly />
</div>
<div class="form-group mb-3">
<label for="requestIdField" class="form-label">Номер заявки:</label>
<input type="text" id="requestIdField" class="form-control" readonly />
</div>
</form>
</div> {% endcomment %}
</div>
</div>
</div> </div>
</div> </div>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { // Обработчик открытия модального окна
const form = document.getElementById('registrationForm'); document.getElementById('openModalBtn').addEventListener('click', function () {
const submitButton = document.getElementById('submitButton'); const serviceId = this.getAttribute('data-service-id');
const qrCodeImage = document.getElementById('qrCodeImage'); // Открываем модальное окно
const registrationLink = document.getElementById('registrationLink'); document.getElementById('serviceModal').style.display = 'block';
let serviceId = "{{ service.pk }}"; // Получаем значение serviceId из шаблона
// Генерация QR-кода при открытии формы // Выполняем запрос на генерацию QR-кода
fetch(`/service/generate_qr_code/${serviceId}/`) fetch(`/service/generate_qr_code/${serviceId}/`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
qrCodeImage.src = data.qr_code_url; // Обновляем src изображения QR-кода
registrationLink.href = data.registration_link; document.getElementById('qrCodeImg').src = data.qr_code_url;
// Извлекаем номер заявки из ссылки на регистрацию
const requestMatch = data.registration_link.match(/request_(\d+)_token/);
if (requestMatch) {
serviceId = requestMatch[1];
}
// Отображение диагностической информации на форме
//document.getElementById('registrationLinkField').value = data.registration_link;
//document.getElementById('requestIdField').value = serviceId;
// Запуск проверки статуса каждые 5 секунд // Запуск проверки статуса каждые 5 секунд
const interval = setInterval(() => { const interval = setInterval(() => {
checkVerificationStatus(serviceId, interval); checkVerificationStatus(data.service_request_id, interval);
}, 5000); }, 5000);
}) })
.catch(error => console.error('Ошибка при генерации QR-кода:', error)); .catch(error => console.error('Ошибка при генерации QR-кода:', error));
});
const checkVerificationStatus = (serviceId, interval) => { // Обработчик закрытия модального окна
fetch(`/service/request_status/${serviceId}/`) document.querySelector('.close').addEventListener('click', function () {
.then(response => { document.getElementById('serviceModal').style.display = 'none';
if (!response.ok) { });
throw new Error('Network response was not ok');
// Обработчик отправки формы
document.getElementById('serviceRequestForm').addEventListener('submit', function (event) {
event.preventDefault();
const formData = new FormData(this);
const serviceId = document.getElementById('openModalBtn').getAttribute('data-service-id');
// Отправка данных формы на сервер
fetch('/service/request/' + serviceId + '/', {
method: 'POST',
body: formData
}).then(response => {
if (response.ok) {
alert('Заявка успешно отправлена!');
document.getElementById('serviceModal').style.display = 'none';
// Отправка сообщения в Telegram
sendTelegramNotification(formData);
} else {
alert('Ошибка при отправке заявки. Пожалуйста, попробуйте снова.');
} }
return response.json(); }).catch(error => console.error('Ошибка при отправке данных формы:', error));
}) });
// Проверка статуса заявки на наличие подтверждения Telegram
const checkVerificationStatus = (serviceRequestId, interval) => {
fetch(`/service/request_status/${serviceRequestId}/`)
.then(response => response.json())
.then(data => { .then(data => {
if (data.is_verified) { if (data.is_verified) {
// Заполнение полей формы данными пользователя // Заполнение полей формы данными пользователя
document.getElementById('client_name').value = data.client_name; document.getElementById('clientName').value = data.client_name;
document.getElementById('client_email').value = data.client_email; document.getElementById('clientChatId').value = data.client_chat_id;
document.getElementById('client_phone').value = data.client_phone;
// Активируем кнопку отправки, если поля заполнены // Активируем кнопку отправки, если все поля заполнены
updateButtonState(); updateButtonState();
// Останавливаем интервал проверки статуса // Останавливаем интервал проверки статуса
clearInterval(interval); clearInterval(interval);
} }
}) })
.catch(error => console.error('Ошибка при проверке статуса:', error)); .catch(error => console.error('Ошибка при проверке статуса заявки:', error));
}; };
// Обработчик кнопки отправки формы // Код для активации кнопки "Отправить" при заполнении всех полей
submitButton.addEventListener('click', function () { const clientEmail = document.getElementById('clientEmail');
if (submitButton.disabled) { const clientPhone = document.getElementById('clientPhone');
return; const clientName = document.getElementById('clientName');
} const description = document.getElementById('description');
const clientChatId = document.getElementById('clientChatId');
// Проверка наличия данных в таблице ServiceRequest перед отправкой формы const submitButton = document.getElementById('submitButton');
fetch(`/service/check_service_request_data/?request_id=${serviceId}`)
.then(response => response.json())
.then(data => {
if (data.exists) {
// Обратная связь пользователю
alert('Заявка уже существует. Данные будут обновлены.');
// Заполнение формы данными из заявки
document.getElementById('client_name').value = data.client_name;
document.getElementById('client_email').value = data.client_email;
document.getElementById('client_phone').value = data.client_phone;
// Отправка формы
form.submit();
} else {
// Если данных нет, отправляем форму как новую заявку
form.submit();
}
})
.catch(error => {
console.error('Ошибка при проверке данных заявки:', error);
alert('Произошла ошибка при проверке данных. Пожалуйста, попробуйте еще раз.');
});
});
// Код для активации кнопки "Отправить" при заполнении полей телефона и email
const clientEmail = document.getElementById('client_email');
const clientPhone = document.getElementById('client_phone');
const updateButtonState = () => { const updateButtonState = () => {
if (clientEmail.value && clientPhone.value) { if (clientEmail.value && clientPhone.value && clientName.value && description.value && clientChatId.value) {
submitButton.disabled = false; submitButton.disabled = false;
} else { } else {
submitButton.disabled = true; submitButton.disabled = true;
} }
}; };
// Привязка событий к полям email и телефона // Привязка событий к полям для обновления состояния кнопки отправки
clientEmail.addEventListener('input', updateButtonState); clientEmail.addEventListener('input', updateButtonState);
clientPhone.addEventListener('input', updateButtonState); clientPhone.addEventListener('input', updateButtonState);
description.addEventListener('input', updateButtonState);
// Удаление placeholder при установке фокуса на поле
document.querySelectorAll('input, textarea').forEach(field => {
field.addEventListener('focus', function () {
this.dataset.placeholder = this.placeholder;
this.placeholder = '';
}); });
field.addEventListener('blur', function () {
this.placeholder = this.dataset.placeholder;
});
});
// Функция для отправки уведомления в Telegram
const sendTelegramNotification = (formData) => {
const clientName = formData.get('client_name');
const serviceDescription = formData.get('description');
const chatId = formData.get('client_chat_id');
const message = `Здравствуйте, ${clientName}! Ваша заявка успешно зарегистрирована. Детали: ${serviceDescription}`;
fetch('/service/send_telegram_notification/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ chat_id: chatId, message: message })
}).then(response => {
if (response.ok) {
console.log('Уведомление успешно отправлено в Telegram');
} else {
console.error('Ошибка при отправке уведомления в Telegram');
}
}).catch(error => console.error('Ошибка при отправке уведомления в Telegram:', error));
};
</script> </script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>

View File

@@ -14,7 +14,6 @@
<div style="max-width: 350px;"> <div style="max-width: 350px;">
<h2 class="text-uppercase fw-bold">{{ service.name }}<br /></h2> <h2 class="text-uppercase fw-bold">{{ service.name }}<br /></h2>
<p class="my-3">{{ service.description }}</p> <p class="my-3">{{ service.description }}</p>
<button id="orderButton" data-service-id="{{ service.pk }}" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#orderModal">Заказать услугу</button>
<!-- Кнопка открытия модального окна --> <!-- Кнопка открытия модального окна -->
<button id="openModalBtn" class="btn btn-primary" data-service-id="{{ service.id }}">Открыть заявку на услугу</button> <button id="openModalBtn" class="btn btn-primary" data-service-id="{{ service.id }}">Открыть заявку на услугу</button>

View File

@@ -64,87 +64,166 @@ def services_view(request):
def about_view(request): def about_view(request):
return render(request, 'web/about.html') return render(request, 'web/about.html')
# def create_service_request(request, service_id):
# service = get_object_or_404(Service, pk=service_id)
# if request.method == 'POST':
# client_name = request.POST.get('client_name')
# client_email = request.POST.get('client_email')
# client_phone = request.POST.get('client_phone')
# description = request.POST.get('description')
# chat_id = request.POST.get('chat_id')
# token = uuid.uuid4().hex
# # Создаем заявку
# service_request = ServiceRequest.objects.create(
# service=service,
# client_name=client_name,
# client_email=client_email,
# client_phone=client_phone,
# chat_id=chat_id,
# token=token
# )
# # Генерация уникальных данных для пользователя
# username = f"{client_email.split('@')[0]}_{get_random_string(5)}"
# password = get_random_string(8)
# # Создание пользователя
# user = User.objects.create_user(username=username, password=password)
# user.first_name = client_name.split()[0] if client_name else ""
# user.last_name = client_name.split()[-1] if len(client_name.split()) > 1 else ""
# user.email = client_email
# user.save()
# # Создание клиента и привязка к пользователю
# client, created = Client.objects.get_or_create(
# email=client_email,
# defaults={
# 'user': user,
# 'first_name': user.first_name,
# 'last_name': user.last_name,
# 'phone_number': client_phone,
# 'chat_id': chat_id,
# }
# )
# # Создание заказа на основе заявки
# order = Order.objects.create(
# service_request=service_request,
# client=client,
# service=service,
# message=description,
# status="pending"
# )
# # Отправка сообщения в Telegram
# if chat_id:
# bot.send_telegram_message(client.id, service_request.id, "Ваши данные для входа на сайт.", order.id)
# return redirect(reverse('order_detail', args=[order.pk]))
# return render(request, 'web/create_service_request.html', {'service': service})
def create_service_request(request, service_id): def create_service_request(request, service_id):
service = get_object_or_404(Service, pk=service_id) service = get_object_or_404(Service, pk=service_id)
if request.method == 'POST': if request.method == 'POST':
client_name = request.POST.get('client_name') # Извлечение данных формы
client_email = request.POST.get('client_email') client_email = request.POST.get('client_email')
client_phone = request.POST.get('client_phone') client_phone = request.POST.get('client_phone')
description = request.POST.get('description') # New description field description = request.POST.get('description')
chat_id = request.POST.get('chat_id') chat_id = request.POST.get('client_chat_id')
token = uuid.uuid4().hex client_name = request.POST.get('client_name')
# Check for existing service request # Проверка на наличие существующей заявки
service_request = ServiceRequest.objects.filter(client_email=client_email, client_phone=client_phone).first() service_request = get_object_or_404(ServiceRequest, chat_id=chat_id)
if not service_request: # Обновление данных заявки
# Create a new service request service_request.client_email = client_email
service_request = ServiceRequest.objects.create( service_request.client_phone = client_phone
service=service, service_request.message = description
client_name=client_name, service_request.save()
client_email=client_email,
client_phone=client_phone, # Создание клиента и пользователя, если необходимо
chat_id=chat_id, user, _ = User.objects.get_or_create(
token=token username=f"{client_email.split('@')[0]}_{get_random_string(5)}",
defaults={"email": client_email}
) )
# Generate user credentials
username = f"{client_email.split('@')[0]}_{get_random_string(5)}"
password = get_random_string(8)
# Create a new user
user = User.objects.create_user(username=username, password=password)
user.first_name = client_name.split()[0] if client_name else "" user.first_name = client_name.split()[0] if client_name else ""
user.last_name = client_name.split()[-1] if len(client_name.split()) > 1 else "" user.last_name = client_name.split()[-1] if len(client_name.split()) > 1 else ""
user.email = client_email
user.save() user.save()
# Create or get client client, _ = Client.objects.get_or_create(
client, created = Client.objects.get_or_create(
email=client_email, email=client_email,
defaults={ defaults={
'user': user,
'first_name': user.first_name, 'first_name': user.first_name,
'last_name': user.last_name, 'last_name': user.last_name,
'phone_number': client_phone, 'phone_number': client_phone,
'chat_id': chat_id,
} }
) )
# Create an order linked to the service request and client # Создание заказа, связанного с заявкой
order = Order.objects.create( order = Order.objects.create(
service=service, service_request=service_request,
client=client, client=client,
service=service_request.service,
message=description, message=description,
status="pending" status="pending"
) )
# Send credentials via Telegram # Отправка уведомления в Telegram
if chat_id: bot.send_telegram_message(
bot.send_telegram_message(client.id, service_request.id, "Ваши данные для входа на сайт.", order.id) client.id,
service_request.id,
else: f"Ваш заказ на услугу '{service_request.service.name}' был успешно создан.",
# If service request exists, update the chat_id order.id
service_request.chat_id = chat_id )
service_request.save()
return redirect(reverse('order_detail', args=[order.pk])) return redirect(reverse('order_detail', args=[order.pk]))
return render(request, 'web/create_service_request.html', {'service': service})
def generate_qr_code(request, service_id): def generate_qr_code(request, service_id):
service = get_object_or_404(Service, pk=service_id) if request.method == 'POST':
telegram_settings = get_object_or_404(TelegramSettings, pk=1) client_email = request.POST.get('client_email')
token = uuid.uuid4().hex client_phone = request.POST.get('client_phone')
client_name = request.POST.get('client_name')
# Создание или получение клиента
user, _ = User.objects.get_or_create(
username=f"{client_email.split('@')[0]}_{get_random_string(5)}",
defaults={"email": client_email}
)
user.first_name = client_name.split()[0] if client_name else ""
user.last_name = client_name.split()[-1] if len(client_name.split()) > 1 else ""
user.save()
client, _ = Client.objects.get_or_create(
email=client_email,
defaults={
'user': user,
'first_name': user.first_name,
'last_name': user.last_name,
'phone_number': client_phone
}
)
# Создание новой заявки на услугу # Создание новой заявки на услугу
service = get_object_or_404(Service, pk=service_id)
token = uuid.uuid4().hex
service_request = ServiceRequest.objects.create( service_request = ServiceRequest.objects.create(
service=service, service=service,
client_name='', client=client,
client_email='',
client_phone='',
token=token token=token
) )
# Генерация ссылки для регистрации в Telegram # Генерация ссылки для регистрации в Telegram
registration_link = (f'https://t.me/{telegram_settings.bot_name}?start=request_{service_request.id}_token_{urlsafe_base64_encode(force_bytes(token))}' telegram_settings = get_object_or_404(TelegramSettings, pk=1)
) registration_link = f'https://t.me/{telegram_settings.bot_name}?start=request_{service_request.id}_token_{urlsafe_base64_encode(force_bytes(token))}'
# Генерация QR-кода # Генерация QR-кода
qr = qrcode.make(registration_link) qr = qrcode.make(registration_link)
@@ -162,6 +241,8 @@ def generate_qr_code(request, service_id):
'qr_code_url': f"/{external_qr_link}", 'qr_code_url': f"/{external_qr_link}",
'service_request_id': service_request.id 'service_request_id': service_request.id
}) })
else:
return JsonResponse({'error': 'Метод запроса должен быть POST'}, status=405)
def complete_registration(request, request_id): def complete_registration(request, request_id):
# Завершение регистрации по идентификатору заявки # Завершение регистрации по идентификатору заявки
@@ -200,13 +281,6 @@ def complete_registration_basic(request):
client_email = request.POST.get('client_email') client_email = request.POST.get('client_email')
client_phone = request.POST.get('client_phone') client_phone = request.POST.get('client_phone')
# # Создаем новую запись заявки
# service_request = ServiceRequest.objects.create(
# client_name=client_name,
# client_email=client_email,
# client_phone=client_phone
# )
return redirect('home') return redirect('home')
return render(request, 'web/complete_registration_basic.html') return render(request, 'web/complete_registration_basic.html')