← Назад к портфолио

Интеграция оффлайн обменника с RetailCRM + веб админка

SatoshiEX Telegram Bot — Портфолио

SatoshiEX — Telegram-бот для офлайн-обменника криптовалют

Интеграция Telegram-бота с RetailCRM, партнёрской программой, Telegram Mini App и виджетом на сайте — полный цикл сопровождения клиента от первого контакта до завершения обмена.

⚡ Проблема

Обменник работает офлайн в Москве. Менеджеры вручную фиксировали заявки, не было единого канала связи с клиентами, партнёрская программа не велась, а заявки с сайта и Mini App не попадали в CRM автоматически.

✅ Решение

Telegram-бот @SmanagerEX_bot автоматически создаёт заявки в RetailCRM, ведёт двустороннюю переписку с клиентом через MessageGateway, управляет партнёрской программой и принимает заявки из трёх каналов одновременно.

⚙️ Что реализовано

📈

Актуальные курсы в реальном времени

USDT/RUB, USD green/RUB, USD blue/RUB с комиссией. Данные из биржи Grinex через Laravel API. Кнопка перехода прямо в Telegram Mini App.

🔄

FSM-диалоги оформления заявки

Пошаговый диалог обмена: валюта отдаёшь → валюта получаешь → сумма. Поддержка ₽, $, €, USDT. Inline-кнопка отмены заявки переводит в статус cancel-other в CRM.

💬

Двусторонняя переписка с CRM

Текст, фото и документы клиента пересылаются менеджеру через RetailCRM MessageGateway. Ответы менеджера доставляются клиенту: text, фото, видео, аудио, документы.

🤝

Партнёрская программа /partner

Регистрация в SQLite, генерация двух реферальных ссылок (бот + сайт), автоматическое накопление вознаграждений. Уведомление при завершении каждого реферального заказа.

📱

Telegram Mini App

Эндпоинты POST /api/miniapp/order и /api/miniapp/contact. Полная цепочка: клиент → заказ в CRM → системное сообщение менеджеру → активация контекста переписки.

🌐

Виджет-калькулятор на сайте

Эндпоинт POST /api/widget/order. Создаёт клиента и заказ в CRM без участия бота. Принимает дату визита, контакты и реферальный код партнёра.

🔍

UTM-трекинг и deep link

Сохранение UTM-меток при переходах по реферальным ссылкам. Laravel API возвращает HTTP 201 Created. Даже при заблокированном боте данные аналитики не теряются.

🖥️

Веб-админка партнёрской программы

admin.satoshi-ex.com — таблица партнёров, статистика рефералов и выплат, страница детализации, выплата с уведомлением в Telegram. Отдельный aiohttp-сервис.

🔗 Ключевые интеграции

🔵 RetailCRM

API v5 + MessageGateway

  • Поиск/создание клиента при каждой заявке
  • Запись кастомных полей: rid, tg_id, data_vizita
  • Цепочка MG-привязки: message_id → mg_customer_id
  • Кнопка «Перейти в диалог» в карточке заказа CRM
  • Webhook — приём сообщений менеджера → Telegram
🟣 Партнёры

SQLite + фоновая задача

  • Batch-запрос к CRM раз в 60 сек для всех рефералов
  • Статус complete → начисление вознаграждения
  • Автоматическое уведомление в Telegram партнёру
  • Привязка заказов с сайта по ref_code из cookie
  • История выплат в таблице payouts
🟢 Mini App

multipart/form-data API

  • Создание заявки на обмен USDT с датой визита
  • Активация FSM-диалога «Связаться с нами» из браузера
  • CORS-заголовки для кросс-доменных запросов
  • Возврат номера заявки: {"order_id": "№12345"}
  • nginx proxy_pass → aiohttp :8081
🟡 Сайт

JSON API для виджета

  • Автономная работа без Telegram-бота
  • Поля: amount, direction, rate, datetime, phone, email
  • Необязательный ref_code из localStorage
  • Защита от str(None) через _safe_str()
  • Конвертация даты: dd.mm.yyyy → yyyy-mm-dd HH:MM:00

🔄 Жизненный цикл заявки из бота

Команда /start или кнопка меню
Пользователь открывает бот. Если есть deep link параметр — UTM сохраняется, клиент привязывается к партнёру. TelegramForbiddenError обёрнут в try/except — аналитика сохраняется даже при заблокированном боте.
FSM-диалог обмена или «Связаться с нами»
Пошаговый диалог с Inline-кнопками. На каждом шаге доступна отмена. Состояния хранятся в MemoryStorage (планируется Redis).
Создание клиента и заказа в RetailCRM
Поиск клиента по tg_id или tg_username. При отсутствии — создание. Заказ записывается со статусом, методом, полями валют, курса и ID партнёра в customFields.rid.
Системное сообщение в чат менеджера (MG)
MessageGateway Transport API (JSON + X-Transport-Token). Из ответа извлекается message_id → получается mg_customer_id → обновляется клиент CRM. Появляется кнопка «Перейти в диалог» в карточке заказа.
Активация контекста переписки (TTL 5 мин)
Следующие 5 минут текст, фото и документы пользователя автоматически пересылаются менеджеру через MG. Фото: file_id → URL → upload_by_url → message.items.
Отслеживание и уведомление партнёра
Если клиент пришёл по реф-ссылке — заказ в SQLite. Фоновая задача раз в 60 сек batch-запросом проверяет статусы. При complete — начисление и уведомление партнёра в Telegram.

📡 Приём сообщений из CRM (Webhook)

01
Менеджер пишет клиенту в RetailCRM
MessageGateway отправляет POST-запрос на api.satoshi-ex.com по webhook-URL
CRM → nginx
02
nginx rewrite + proxy_pass
Rewrite пути → proxy_pass на 127.0.0.1:8081/webhook/mg. Параллельно с polling-режимом бота.
nginx → aiohttp
03
Парсинг WebhookMessage и определение типа
text / image / file / audio. Файлы делятся на видео (mp4, mov, avi) и документы (PDF, DOCX и др.) по расширению.
WebhookService
04
Скачивание файла из MG в память
URL файлов из MG требует авторизации X-Transport-Token. Прямая отправка в Telegram невозможна — скачиваем байты и передаём через Bot API.
Transport API
05
Доставка клиенту в Telegram
sendMessage / sendPhoto / sendVideo / sendVoice / sendDocument. Группы фото/видео — sendMediaGroup. Клиент видит сообщение менеджера прямо в Telegram.
Bot API

PHP-модуль выведен из эксплуатации 13.04.2026. Весь webhook-транспорт переписан на Python. Бэкап PHP-модуля сохранён в /root/backups/2026-04-13/. Теперь вся обработка — один Python-сервис без внешних зависимостей.

📊 Результаты

3
Канала приёма заявок: бот, Mini App, сайт
60 сек
Интервал проверки статусов рефералов
5 мин
TTL контекста переписки клиента с менеджером
8
Репозиториев по принципу Repository Pattern
9
Роутеров aiogram (handlers)
SOLID
Архитектурные принципы + DI через конструкторы

⚙️ Архитектурные особенности

🧱
SOLID + слоёная архитектура
Handlers → Services → Repositories → External API. Зависимости внедряются через конструкторы. Фабрика bot/factory.py — единственное место сборки конкретных реализаций. Обработчики работают с ABC-интерфейсами.
Полностью асинхронный стек
aiogram 3.x + aiohttp + aiosqlite. Webhook-сервер и бот работают параллельно в одном event loop. BaseHttpRepository предоставляет retry-логику с таймаутами для всех HTTP-репозиториев.
🗄️
Централизованный реестр CRM-констант
Все статусы заказов, имена кастомных полей, коды методов и эндпоинты собраны в config/crm_constants.py. При изменении параметра в RetailCRM — редактируется один файл.
🔍
Структурированное логирование с trace_id
Консоль — human-readable формат. Файл — полный JSON с trace_id, прослеживаемым через все слои: middleware → handler → service → repository. Ротация логов: 10 МБ, 5 копий.
🔐
Graceful shutdown и корректная остановка
Фоновая задача отслеживания рефералов корректно останавливается при shutdown бота. Все активные HTTP-соединения закрываются. Запущенные проверки CRM завершаются до выхода.
🏗️
6 паттернов проектирования
Repository, Template Method (BaseHttpRepository), Service Layer, Factory, Strategy (FSM-диалоги как взаимозаменяемые стратегии), Observer (периодический опрос статусов с batch-запросом filter[ids][]).
🔗

Автоматическая MG-привязка клиента: После отправки системного сообщения в MessageGateway извлекается message_id → по нему получается mg_customer_id → через update_mg_customer_id привязывается к CRM-клиенту. Это обеспечивает появление кнопки «Перейти в диалог» прямо в карточке заказа RetailCRM.

📦

Batch-оптимизация партнёрских проверок: Вместо N отдельных запросов к CRM — один GET /api/v5/orders с множественным filter[ids][] по всем ожидающим заказам. Внутренний числовой ID заказа, а не номер — id=10538 при number='10538A'.

🛠️ Технологии

Python 3.12 aiogram 3.x aiohttp aiosqlite SQLite RetailCRM API v5 MessageGateway nginx systemd aiohttp-jinja2 ruff mypy strict pre-commit dataclasses asyncio FSM Let's Encrypt

✅ Подойдёт вам, если

  • У вас офлайн-обменник или сервис с физическими визитами — нужен удобный канал приёма заявок и автоматическая передача данных в CRM
  • Хотите двустороннюю переписку с клиентом прямо из Telegram, при этом менеджер работает в привычном интерфейсе RetailCRM
  • Нужна партнёрская программа с реферальными ссылками, автоматическим отслеживанием заказов и начислением вознаграждений
  • Требуется принимать заявки сразу из нескольких точек: Telegram-бот, Mini App, виджет на сайте — всё в одну CRM
  • Важна надёжность: обработка ошибок на каждом слое, retry-логика для HTTP, graceful shutdown, структурированные логи с trace_id

Раньше менеджеры вручную переносили заявки из Telegram в таблицы. Теперь всё автоматически — клиент написал боту, заявка сразу в CRM, менеджер видит полный диалог прямо в карточке заказа. Партнёры сами видят свои начисления и не задают лишних вопросов.

— Команда SatoshiEX, Москва

Нужна интеграция Telegram-бота с вашей CRM?

Разработаю систему автоматического приёма заявок, двусторонней переписки и партнёрской программы под ваш бизнес

Обсудить проект →