В этой статье мы рассмотрим, как создать Telegram бота, который интегрируется с системой управления заявками (например, CRM), используя Python, библиотеку aiogram для работы с Telegram API и aiomysql для асинхронного взаимодействия с MySQL базой данных. Весь смысл в том что логика бота такова что он будет считывать данные с БД и вытягивать заявки оттуда, а так же коментарии в них, есть всего две таблицы, в одной коменты во второй сами заявки. Сам же бот создает заявки от уже созданного пользователя в БД и ведет переписки тоже с него. Собственно говоря таких заявок может быть множество от одного пользователя, но для того что бы были разные телеграмм юзеры, и их заявки и переписки не переплитались пришлось 3 таблицу создать для хранения айди чата, и соотвественно подвязывать для каждого айди тг айди заявки
В современном мире автоматизация бизнес-процессов играет ключевую роль в управлении клиентскими запросами и оперативной работе с заявками. Telegram, как одна из самых популярных платформ для мессенджеров, предлагает широкие возможности для интеграции бизнес-процессов. В этой статье мы поговорим о том, как можно создать Telegram бота, который поможет автоматизировать процесс управления заявками в CRM системе, используя Python, библиотеку aiogram для работы с Telegram API и aiomysql для асинхронного взаимодействия с MySQL базой данных.
Основная Идея и Логика Работы Бота
Бот разработан для того, чтобы обеспечить эффективное взаимодействие между клиентами и системой управления заявками напрямую через Telegram. Он позволяет пользователям создавать новые заявки, а также получать обновления по уже существующим, включая комментарии от администрации.
Для реализации такого взаимодействия было создано три основные таблицы в базе данных:
Техническая РеализацияПодключение к Базе Данных
Используя aiomysql, мы асинхронно подключаемся к базе данных. Это позволяет боту работать эффективно, не блокируя основной поток выполнения при обработке запросов к базе данных.
Так же, не забывай, подключение интеграция идет через БД а не АПИ
Создание Заявок
Пользователь может инициировать создание заявки, отправив команду /new_ticket. Бот запрашивает у пользователя название и описание заявки, после чего информация записывается в базу данных. Для каждой заявки присваивается уникальный идентификатор, который затем используется для общения с пользователем и обновления статуса заявки.
Обработка Комментариев
Бот периодически проверяет новые комментарии в базе данных и отправляет их соответствующим пользователям в Telegram. Это обеспечивает двустороннюю коммуникацию между администрацией и клиентом прямо в мессенджере.
Преимущества и Возможности
Такой подход позволяет:
Заключение
Интеграция Telegram бота с CRM системой — это эффективное решение для автоматизации управления заявками. Благодаря асинхронной работе с базой данных и возможности мгновенного общения с клиентами через популярный мессенджер, процесс обработки заявок становится проще и быстрее как для пользователей, так и для администрации.
Разработанный бот — это лишь один из примеров, как можно использовать современные технологии для оптимизации бизнес-процессов. Применение таких инновационных решений способствует повышению уровня клиентского сервиса и эффективности работы компании в целом.
Да, в заключение еще публикую код и к нему описание
# Конфигурация подключения к базе данных db_config = { 'host': 'localhost', 'port': 3306, 'user': 'root', 'password': 'Erik456_debul.ua21', 'db': 'crm', #'init_command': 'SET @@session.time_zone="02:00"', } from datetime import datetime, timedelta class TicketForm(StatesGroup): title = State() description = State() # Функция для добавления новой заявки в базу данных async def insert_new_ticket(telegram_user_id, title, description): client_id = 3 project_id = 0 ticket_type_id = 1 created_by = 5 # ID пользователя, от имени которого создаются тикеты requested_by = 5 status = 'new' assigned_to = 1 creator_name = 'Ernest Worker' creator_email = 'tawerkarespro18@gmail.com' labels = '' task_id = 0 closed_at = '9999-12-31 23:59:59' merged_with_ticket_id = 0 deleted = 0 async with aiomysql.connect(**db_config, charset='utf8mb4', autocommit=True) as conn: async with conn.cursor() as cur: await cur.execute(""" INSERT INTO rise_tickets (client_id, project_id, ticket_type_id, title, created_by, requested_by, created_at, status, last_activity_at, assigned_to, creator_name, creator_email, labels, task_id, closed_at, merged_with_ticket_id, deleted) VALUES (%s, %s, %s, %s, %s, %s, NOW(), %s, NOW(), %s, %s, %s, %s, %s, %s, %s, %s) """, (client_id, project_id, ticket_type_id, title, created_by, requested_by, status, assigned_to, creator_name, creator_email, labels, task_id, closed_at, merged_with_ticket_id, deleted)) ticket_id = cur.lastrowid # Получаем ID созданного тикета # Добавляем запись в telegram_ticket_link await cur.execute(""" INSERT INTO telegram_ticket_link (telegram_user_id, ticket_id) VALUES (%s, %s) """, (telegram_user_id, ticket_id)) logging.info(f"Тикет {ticket_id} успешно создан и связан с пользователем Telegram {telegram_user_id}.") # Обработчики команд и сообщений бота @dp.message_handler(commands=['new_ticket']) async def new_ticket(message: types.Message): await TicketForm.title.set() await message.answer("Введите название тикета:") @dp.message_handler(state=TicketForm.title) async def process_title(message: types.Message, state: FSMContext): async with state.proxy() as data: data['title'] = message.text await TicketForm.next() await message.answer("Введите описание тикета:") @dp.message_handler(state=TicketForm.description) async def process_description(message: types.Message, state: FSMContext): async with state.proxy() as data: data['description'] = message.text # Тут нужно получить telegram_user_id, например, так: telegram_user_id = message.from_user.id await insert_new_ticket(telegram_user_id, data['title'], data['description']) await state.finish() await message.answer("Ваш тикет успешно создан и добавлен в базу данных!") # Идентификатор последнего отправленного комментария для каждой заявки last_sent_comment_id = {} async def fetch_new_comments(): logging.info("Проверка новых комментариев от админа...") async with aiomysql.connect(**db_config) as conn: async with conn.cursor(aiomysql.DictCursor) as cur: await cur.execute(""" SELECT rtc.id, rtc.description, rtc.ticket_id, ttl.telegram_user_id FROM rise_ticket_comments AS rtc JOIN rise_tickets AS rt ON rtc.ticket_id = rt.id JOIN telegram_ticket_link AS ttl ON rt.id = ttl.ticket_id WHERE rtc.created_by = 1 AND rtc.deleted = 0 AND rt.status != 'closed' ORDER BY rtc.id DESC """) comments = await cur.fetchall() for comment in comments: ticket_id = comment['ticket_id'] if ticket_id not in last_sent_comment_id or comment['id'] > last_sent_comment_id[ticket_id]: chat_id = comment['telegram_user_id'] if chat_id: message = comment['description'].replace('<p>', '').replace('</p>', '\n').replace('<br>', '\n').strip() await bot.send_message(chat_id, f"Новый комментарий к заявке '{ticket_id}': {message}") last_sent_comment_id[ticket_id] = comment['id'] else: logging.warning(f"Chat ID для пользователя с Telegram ID {comment['telegram_user_id']} не найден.") @dp.message_handler(commands=['add_comment']) async def add_comment(message: types.Message): args = message.get_args().split(maxsplit=1) if len(args) < 2: await message.reply("Используйте команду в формате: /add_comment <id_заявки> <комментарий>") return ticket_id, comment_text = args[0], args[1] try: ticket_id = int(ticket_id) # Убедитесь, что ticket_id является числом except ValueError: await message.reply("ID заявки должен быть числом.") return sql_query = """ INSERT INTO rise_ticket_comments (created_by, ticket_id, description, created_at, deleted, files, is_note) VALUES (%s, %s, %s, NOW(), 0, 'a:0:{}', 0) """ sql_data = (5, ticket_id, comment_text) try: async with aiomysql.connect(**db_config, cursorclass=aiomysql.DictCursor) as conn: async with conn.cursor() as cur: await cur.execute("SELECT status FROM rise_tickets WHERE id = %s", (ticket_id,)) ticket = await cur.fetchone() if ticket and ticket['status'] != 'closed': await cur.execute(sql_query, sql_data) await conn.commit() # Явное подтверждение транзакции await message.reply("Ваш комментарий добавлен к заявке.") else: await message.reply("Заявка закрыта или не найдена. Добавление комментария невозможно.") except Exception as e: logging.error(f"Ошибка при выполнении SQL-запроса: {e}") await message.reply("Произошла ошибка при попытке добавить комментарий. Пожалуйста, попробуйте позже.") notified_closed_tickets = set() async def check_ticket_closed(): logging.info("Проверка статуса заявок...") async with aiomysql.connect(**db_config) as conn: async with conn.cursor(aiomysql.DictCursor) as cur: await cur.execute(""" SELECT rt.id, ttl.telegram_user_id FROM rise_tickets rt JOIN telegram_ticket_link ttl ON rt.id = ttl.ticket_id WHERE rt.status = 'closed' """) closed_tickets = await cur.fetchall() for ticket in closed_tickets: ticket_id = ticket['id'] if ticket_id not in notified_closed_tickets: telegram_user_id = ticket['telegram_user_id'] # Отправляем уведомление пользователю Telegram о закрытии тикета await bot.send_message(telegram_user_id, f"Заявка {ticket_id} была закрыта.") logging.info(f"Пользователь {telegram_user_id} уведомлен о закрытии заявки {ticket_id}.") # Добавляем идентификатор заявки в множество уведомленных notified_closed_tickets.add(ticket_id)
async def periodic_task(interval, task_func, *args): while True: try: await task_func(*args) # Выполнение вашей функции except Exception as e: logging.error(f"Ошибка при выполнении задачи {task_func.__name__}: {e}") await asyncio.sleep(interval) # Ожидание до следующего выполнения async def on_startup(dp): await bot.send_message(ADMIN_ID, "Bot has been started") # Запуск периодической задачи проверки новых комментариев каждые 60 секунд asyncio.create_task(periodic_task(10, fetch_new_comments)) # Запуск периодической задачи проверки закрытых заявок каждые 60 секунд asyncio.create_task(periodic_task(10, check_ticket_closed)) if __name__ == '__main__': from aiogram import executor executor.start_polling(dp, on_startup=on_startup)
Конфигурация базы данных
Состояния взаимодействия с пользователем
Асинхронная функция для вставки новых билетов
Обработчики команд
Обработка комментариев
Дополнительный обработчик команд для комментариев
Мониторинг статуса заявок
Периодические задачи
Запуск бота