Разработка CRM-системы в Telegram на Python: Полное руководство с примерами
Отличная идея! Вот подробная статья о создании CRM-приложения для Telegram на Python, с фокусом на понятность и практические примеры.
Разработка CRM-системы в Telegram на Python: Полное руководство с примерами
Введение: Почему Telegram как платформа для CRM?
В современном бизнесе важно быть там, где есть клиенты. А клиенты все чаще — в мессенджерах. Telegram, с его мощным API, кросс-платформенностью и популярностью, представляет собой идеальную площадку для развертывания легкой, эффективной и доступной CRM-системы.
Такая CRM не требует от ваших менеджеров по продажам или сотрудников поддершки постоянно сидеть в веб-интерфейсе. Уведомления, задачи и сообщения от клиентов приходят прямо в привычный мессенджер. Это значительно ускоряет реакцию и повышает удобство работы.
В этой статье мы поэтапно разберем, как создать свою собственную CRM для Telegram, используя Python. Мы рассмотрим архитектуру, ключевые библиотеки и напишем конкретные примеры кода для реализации основного функционала.
Что мы будем разрабатывать? Наша CRM будет иметь следующий базовый функционал:
- Телеграм-бот как интерфейс для сотрудников.
- Регистрация и аутентификация сотрудников.
- Управление клиентами (добавление, просмотр, редактирование).
- Управление заявками/сделками (создание, изменение статуса, назначение ответственного).
- Уведомления о новых заявках и изменениях.
- Простая база данных для хранения информации.
Технологический стек
- Python 3.8+
- python-telegram-bot (
python-telegram-botv20.x) — современная и асинхронная библиотека для работы с Telegram Bot API. - SQLAlchemy — ORM (Object-Relational Mapping) для работы с базой данных на высоком уровне.
- SQLite — простая файловая база данных для начала разработки (легко заменяется на PostgreSQL или MySQL).
- Alembic (опционально) — для управления миграциями базы данных.
Часть 1: Настройка проекта и окружения
1.1. Создание бота в Telegram
Первым делом нужно создать самого бота через @BotFather.
- Напишите
/startBotFather-у. - Затем команду
/newbot. - Следуйте инструкциям: задайте имя бота (например,
MyCompany CRM) и уникальный username (например,mycompany_crm_bot). - В завершение вы получите API-токен вида
1234567890:ABCDEFGhIjKlMnOpQRsTuvWxYZ-abcdefghi. Сохраните его, он понадобится для подключения к вашему коду.
1.2. Структура проекта Создайте следующую структуру папок:
/my_telegram_crm
/crm_bot.py # Главный файл, запуск бота
/config.py # Конфигурация: токен, настройки БД
/models.py # Модели SQLAlchemy (таблицы БД)
/handlers.py # Обработчики сообщений и команд
/database.py # Инициализация и работа с БД
/utils.py # Вспомогательные функции
/requirements.txt # Зависимости проекта
1.3. Установка зависимостей
Создайте файл requirements.txt:
python-telegram-bot==20.7
sqlalchemy==2.0.23
alembic==1.12.1
Установите их через pip:
pip install -r requirements.txt
1.4. Настройка конфигурации (config.py)
Вынесем критически важные данные в конфиг.
import os
class Config:
# Токен вашего бота, полученный от @BotFather
BOT_TOKEN = os.getenv('BOT_TOKEN', '1234567890:ABCDEFGhIjKlMnOpQRsTuvWxYZ-abcdefghi')
# Настройки базы данных (для начала используем SQLite)
DB_PATH = os.getenv('DB_PATH', 'sqlite:///crm_database.db')
# ID администратора/ов (узнать свой ID можно через @userinfobot)
# Уведомления будут отправляться сюда
ADMIN_IDS = [123456789, 987654321] # Замените на реальные ID
Часть 2: Проектирование и настройка базы данных (models.py)
Опишем основные сущности нашей CRM.
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, ForeignKey, Enum
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
from datetime import datetime
import enum
# Базовый класс для моделей
Base = declarative_base()
# Статусы для заявки
class StatusEnum(enum.Enum):
NEW = "Новая"
IN_PROGRESS = "В работе"
WAITING = "Ожидание"
DONE = "Завершена"
CANCELLED = "Отменена"
# Модель сотрудника
class Employee(Base):
__tablename__ = 'employees'
id = Column(Integer, primary_key=True)
telegram_id = Column(Integer, unique=True, nullable=False) # ID пользователя в Telegram
username = Column(String(100)) # @username
first_name = Column(String(100))
last_name = Column(String(100))
role = Column(String(50), default='manager') # manager, admin, etc.
is_active = Column(Integer, default=1) # 1 - активен, 0 - неактивен
created_at = Column(DateTime, default=datetime.utcnow)
# Связь "один ко многим" с заявками (один сотрудник - много заявок)
leads = relationship("Lead", back_populates="assignee")
# Модель клиента
class Customer(Base):
__tablename__ = 'customers'
id = Column(Integer, primary_key=True)
telegram_id = Column(Integer, unique=True) # Если клиент тоже из Telegram
username = Column(String(100))
first_name = Column(String(100))
last_name = Column(String(100))
phone_number = Column(String(20))
email = Column(String(100))
created_at = Column(DateTime, default=datetime.utcnow)
# Связь с заявками
leads = relationship("Lead", back_populates="customer")
# Модель заявки/сделки
class Lead(Base):
__tablename__ = 'leads'
id = Column(Integer, primary_key=True)
title = Column(String(200), nullable=False) # Краткое название заявки
description = Column(Text) # Подробное описание
status = Column(Enum(StatusEnum), default=StatusEnum.NEW)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Внешние ключи
customer_id = Column(Integer, ForeignKey('customers.id'))
assignee_id = Column(Integer, ForeignKey('employees.id')) # Ответственный сотрудник
# Связи
customer = relationship("Customer", back_populates="leads")
assignee = relationship("Employee", back_populates="leads")
Часть 3: Инициализация базы данных и сессии (database.py)
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Base
from config import Config
# Создаем движок для подключения к БД
engine = create_engine(Config.DB_PATH, echo=True) # echo=True для отладки SQL запросов
# Создаем таблицы в базе данных
Base.metadata.create_all(engine)
# Создаем фабрику сессий
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
# Функция для получения сессии (будет использоваться в обработчиках)
def get_db_session():
session = SessionLocal()
try:
yield session
finally:
session.close()
Часть 4: Регистрация сотрудников и система прав
Прежде чем работать с CRM, сотрудник должен быть в нее добавлен. Реализуем простую команду /start, которая будет проверять, есть ли пользователь в базе.
В handlers.py:
from telegram import Update, ReplyKeyboardMarkup
from telegram.ext import ContextTypes, CommandHandler, MessageHandler, filters, ConversationHandler
from models import Employee, Customer, Lead, StatusEnum
from database import get_db_session
from config import Config
# States для ConversationHandler
AWAITING_PHONE = 1
# Команда /start
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
session = next(get_db_session())
# Проверяем, есть ли сотрудник в базе
employee = session.query(Employee).filter(Employee.telegram_id == user.id).first()
if employee:
# Сотрудник найден
welcome_text = f"Добро пожаловать в CRM, {employee.first_name}!"
keyboard = [['📊 Мои заявки', '➕ Новая заявка'], ['👥 Клиенты', '❓ Помощь']]
reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True)
await update.message.reply_text(welcome_text, reply_markup=reply_markup)
else:
# Сотрудник не найден, проверяем, может это клиент?
customer = session.query(Customer).filter(Customer.telegram_id == user.id).first()
if not customer:
# Это новый клиент, предлагаем зарегистрироваться
new_customer = Customer(
telegram_id=user.id,
username=user.username,
first_name=user.first_name,
last_name=user.last_name
)
session.add(new_customer)
session.commit()
await update.message.reply_text(
"Спасибо за обращение! Ваша заявка будет обработана в ближайшее время."
)
# Отправляем уведомление администратору о новом клиенте
for admin_id in Config.ADMIN_IDS:
await context.bot.send_message(
chat_id=admin_id,
text=f"🎉 Новый потенциальный клиент: {user.first_name} @{user.username}"
)
else:
await update.message.reply_text("Вы уже зарегистрированы как клиент. С вами свяжется менеджер.")
session.close()
# ... другие обработчики ...
Часть 5: Ядро функционала — обработчики команд
5.1. Создание новой заявки (используем ConversationHandler) Это более сложный, но мощный инструмент для многошаговых диалогов.
# States для процесса создания заявки
TITLE, DESCRIPTION = range(2)
async def new_lead_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Начинает процесс создания заявки."""
await update.message.reply_text("Отлично! Давайте создадим новую заявку. Введите краткое название:")
return TITLE
async def new_lead_title(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Получает название заявки."""
user_title = update.message.text
context.user_data['lead_title'] = user_title
await update.message.reply_text("Хорошо. Теперь введите подробное описание:")
return DESCRIPTION
async def new_lead_description(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Получает описание и сохраняет заявку в БД."""
user_description = update.message.text
user = update.effective_user
session = next(get_db_session())
# Находим сотрудника, который создает заявку
employee = session.query(Employee).filter(Employee.telegram_id == user.id).first()
if not employee:
await update.message.reply_text("Ошибка: вы не зарегистрированы как сотрудник.")
session.close()
return ConversationHandler.END
# Находим или создаем клиента "по умолчанию" для примера.
# В реальной системе клиент должен выбираться из списка или привязываться иначе.
default_customer = session.query(Customer).first()
# Создаем заявку
new_lead = Lead(
title=context.user_data['lead_title'],
description=user_description,
customer_id=default_customer.id,
assignee_id=employee.id # Назначаем на себя
)
session.add(new_lead)
session.commit()
# Очищаем временные данные
context.user_data.clear()
await update.message.reply_text(f"✅ Заявка '#{new_lead.id} {new_lead.title}' успешно создана и назначена на вас!")
# Отправляем уведомление админам (если нужно)
for admin_id in Config.ADMIN_IDS:
if admin_id != user.id: # Чтобы не дублировать себе
await context.bot.send_message(
chat_id=admin_id,
text=f"🆕 Создана новая заявка: #{new_lead.id} {new_lead.title}\n"
f"Ответственный: {employee.first_name}"
)
session.close()
return ConversationHandler.END
async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Отменяет текущий диалог."""
await update.message.reply_text('Создание заявки отменено.')
context.user_data.clear()
return ConversationHandler.END
# Регистрируем ConversationHandler в главном файле (crm_bot.py)
lead_conv_handler = ConversationHandler(
entry_points=[MessageHandler(filters.Regex('^➕ Новая заявка$'), new_lead_start)],
states={
TITLE: [MessageHandler(filters.TEXT & ~filters.COMMAND, new_lead_title)],
DESCRIPTION: [MessageHandler(filters.TEXT & ~filters.COMMAND, new_lead_description)],
},
fallbacks=[CommandHandler('cancel', cancel)],
)
5.2. Просмотр списка заявок
async def show_my_leads(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Показывает заявки, назначенные на текущего сотрудника."""
user = update.effective_user
session = next(get_db_session())
employee = session.query(Employee).filter(Employee.telegram_id == user.id).first()
if not employee:
await update.message.reply_text("Ошибка доступа.")
session.close()
return
leads = session.query(Lead).filter(Lead.assignee_id == employee.id).order_by(Lead.status, Lead.updated_at.desc()).all()
if not leads:
await update.message.reply_text("У вас нет активных заявок.")
session.close()
return
response_text = "📋 *Ваши заявки:*\n\n"
for lead in leads:
response_text += f"*#{lead.id}* - {lead.title}\n"
response_text += f"Статус: `{lead.status.value}`\n"
response_text += f"Клиент: {lead.customer.first_name}\n"
response_text += f"Обновлена: {lead.updated_at.strftime('%d.%m.%Y %H:%M')}\n\n"
await update.message.reply_text(response_text, parse_mode='Markdown')
session.close()
Часть 6: Запуск бота (crm_bot.py)
Здесь мы соберем все компоненты вместе.
from config import Config
from telegram.ext import Application, CommandHandler, MessageHandler, filters
from handlers import start, show_my_leads, lead_conv_handler
def main():
# Создаем Application и передаем ему токен бота
application = Application.builder().token(Config.BOT_TOKEN).build()
# Регистрируем обработчики
application.add_handler(CommandHandler("start", start))
application.add_handler(MessageHandler(filters.Regex('^📊 Мои заявки$'), show_my_leads))
application.add_handler(lead_conv_handler) # Добавляем ConversationHandler
# Запускаем бота
print("Бот запущен...")
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == '__main__':
main()
Часть 7: Дальнейшее развитие и улучшения
Наша базовая CRM готова. Но это только фундамент. Вот куда можно двигаться дальше:
- Административная панель: Веб-интерфейс на Flask/Django для админов, где можно добавлять сотрудников, смотреть общую статистику, править любые данные.
- Инлайн-кнопки и меню: Замена текстовых кнопок на
InlineKeyboardButtonдля действий “Взять в работу”, “Изменить статус”, “Назначить другому менеджеру” прямо в сообщении с заявкой. - Интеграция с внешними системами: Отправка данных в Google Sheets, 1С или AmoCRM через их API.
- Финальная авторизация: Реализация более строгой системы ролей (админ, менеджер, гость).
- Каналы и группы: Настройка получения заявок не только в ЛС бота, но и из Telegram-каналов или чатов поддержки.
- Ведение диалога с клиентом: Функционал, при котором менеджер может ответить клиенту прямо из интерфейса бота, и сообщение перешлется клиенту (используя
bot.copy_message). - Миграция на PostgreSQL: Для большей надежности и производительности в продакшене.
Заключение
Разработка CRM в Telegram на Python — это мощный и относительно быстрый способ автоматизировать процессы вашего бизнеса, находясь в одном из самых популярных мессенджеров. Мы рассмотрели ключевые этапы: от настройки бота и проектирования базы данных до реализации базового функционала по управлению заявками с помощью асинхронной библиотеки python-telegram-bot и ORM SQLAlchemy.
Этот код является отправной точкой. Вы можете и должны адаптировать его под свои конкретные бизнес-процессы, расширять функционал и улучшать интерфейс. Удачи в разработке!