# SalvageDB Telegram Bot - Developer Documentation ## Оглавление 1. [Архитектура бота](#архитектура-бота) 2. [Переменные окружения](#переменные-окружения) 3. [Состояния FSM](#состояния-fsm) 4. [Основные функции](#основные-функции) 5. [Callback Handlers](#callback-handlers) 6. [Message Handlers](#message-handlers) 7. [Функции базы данных](#функции-базы-данных) 8. [Система платежей](#система-платежей) 9. [Работа с фотографиями](#работа-с-фотографиями) 10. [Системные функции](#системные-функции) 11. [Middleware](#middleware) 12. [Структура проекта](#структура-проекта) 13. [API Endpoints](#api-endpoints) --- ## Архитектура бота Бот построен на фреймворке `aiogram 3.x` с использованием Oracle Database для хранения данных о транспортных средствах и их истории повреждений. ### Основные компоненты: - **main.py** - основной файл с логикой бота - **db.py** - класс для работы с Oracle Database - **middlewares/db.py** - middleware для передачи подключения к БД ### Схема работы: ``` User Input → FSM States → Database Query → Response Formatting → Telegram API ``` --- ## Переменные окружения ### Обязательные переменные: ```env BOT_TOKEN=ваш_токен_бота BOT_NAME=имя_бота db_user=пользователь_oracle db_password=пароль_oracle db_dsn=строка_подключения_oracle ADMIN_USER_ID=id_администратора ``` ### Опциональные переменные: ```env DEBUG=1 # Включает детальное логирование DECODE_PRICE=1 # Цена за детальную информацию VIN (звезды) CHECK_PRICE=10 # Цена за проверку salvage записей (звезды) IMG_PRICE=100 # Цена за фотографии (звезды) ``` ### Автоматические пути к изображениям: ```python if is_windows(): image_path = "D:\\SALVAGEDB\\salvagedb_bot\\images" else: image_path = "/images/" ``` --- ## Состояния FSM Бот использует Finite State Machine для управления диалогами: ```python class VinStates(StatesGroup): waiting_for_vin = State() # Ожидание VIN для декодирования waiting_for_check_vin = State() # Ожидание VIN для проверки salvage waiting_for_photo_vin = State() # Ожидание VIN для поиска фотографий ``` ### Переходы между состояниями: - **Start** → `waiting_for_vin` (кнопка "Decode VIN") - **Start** → `waiting_for_check_vin` (кнопка "Check VIN") - **Start** → `waiting_for_photo_vin` (кнопка "Search car Photo") - **Any State** → **Start** (кнопка "Back to Main Menu") --- ## Основные функции ### Системные функции #### `get_operating_system() -> str` Определяет операционную систему. ```python Returns: 'Windows', 'Linux', 'macOS' или 'Unknown' ``` #### `is_windows() -> bool`, `is_linux() -> bool`, `is_macos() -> bool` Быстрые проверки операционной системы. #### `log_system_info()` Логирует подробную информацию о системе при запуске. ### Функции обработки данных #### `get_us_state_name(state_code: str) -> str` Конвертирует двухбуквенный код штата США в полное название. ```python get_us_state_name("TX") # Returns: "Texas" ``` #### `format_sale_date(date_str: str) -> str` Форматирует дату из MM/YYYY в читаемый формат. ```python format_sale_date("3/2023") # Returns: "March 2023" ``` #### `parse_location(location_str: str) -> str` Парсит локацию из формата ST/TOWN в "City, State". ```python parse_location("TX/DALLAS") # Returns: "Dallas, Texas" ``` #### `escape_markdown(text: str) -> str` Экранирует специальные символы Markdown для безопасной отправки. ### Функции работы с фотографиями #### `convert_photo_path(db_path: str) -> str` Конвертирует путь из БД в полный путь с учетом OS. ```python # Windows convert_photo_path("20250530/vin/photo.jpg") # Returns: "D:\SALVAGEDB\salvagedb_bot\images\20250530\vin\photo.jpg" # Linux convert_photo_path("20250530/vin/photo.jpg") # Returns: "/images/20250530/vin/photo.jpg" ``` #### `prepare_photo_paths(db_paths: list) -> list` Подготавливает список полных путей к фотографиям. #### `send_vehicle_photos(message, vin, photo_paths, make, model, year)` Отправляет фотографии пользователю группами по 10 штук. **Особенности:** - Разбивает фотографии на группы по 10 (лимит Telegram) - Добавляет описания к первым фото каждой группы - Пауза 0.5 сек между группами - Обработка ошибок для каждой фотографии - Итоговое сообщение с количеством отправленных фото --- ## Callback Handlers ### `@dp.callback_query(lambda c: c.data == "decode_vin")` **Функция:** `decode_vin_callback` **Действие:** Устанавливает состояние `waiting_for_vin`, запрашивает VIN для декодирования. ### `@dp.callback_query(lambda c: c.data == "check_vin")` **Функция:** `check_vin_callback` **Действие:** Устанавливает состояние `waiting_for_check_vin`, запрашивает VIN для проверки salvage. ### `@dp.callback_query(lambda c: c.data == "search_car_photo")` **Функция:** `search_car_photo_callback` **Действие:** Устанавливает состояние `waiting_for_photo_vin`, запрашивает VIN для поиска фотографий. ### `@dp.callback_query(lambda c: c.data == "main_menu")` **Функция:** `main_menu_callback` **Действие:** Очищает состояние, возвращает в главное меню. ### Платежные handlers #### `@dp.callback_query(lambda c: c.data.startswith("pay_detailed_info:"))` **Функция:** `pay_detailed_info_callback` **Payload:** `detailed_vin_info:{vin}` **Цена:** `DECODE_PRICE` звезд #### `@dp.callback_query(lambda c: c.data.startswith("pay_check_detailed:"))` **Функция:** `pay_check_detailed_callback` **Payload:** `detailed_salvage_check:{vin}` **Цена:** `CHECK_PRICE` звезд #### `@dp.callback_query(lambda c: c.data.startswith("pay_photos:"))` **Функция:** `pay_photos_callback` **Payload:** `vehicle_photos:{vin}` **Цена:** `IMG_PRICE` звезд --- ## Message Handlers ### `@dp.message(Command("start"))` **Функция:** `command_start_handler` **Действие:** Показывает приветственное сообщение и главное меню. **Кнопки:** - Decode VIN - Check VIN - Search car Photo - Help - Prices - Go Salvagedb.com ### `@dp.message(Command("admin_stats"))` **Функция:** `admin_stats_handler` **Доступ:** Только для `ADMIN_USER_ID` **Действие:** Показывает статистику пользователей бота. ### Обработчики состояний #### `@dp.message(VinStates.waiting_for_vin)` **Функция:** `process_vin` **Логика:** 1. Валидация VIN (17 символов, без I/O/Q) 2. Запрос `fetch_vin_info(vin)` 3. Проверка успешности декодирования (не все UNKNOWN) 4. Показ кнопки детальной информации при `cnt > 9` #### `@dp.message(VinStates.waiting_for_check_vin)` **Функция:** `process_check_vin` **Логика:** 1. Валидация VIN 2. Запрос `fetch_vin_info(vin)` и `count_salvage_records(vin)` 3. Показ информации о количестве найденных записей 4. Кнопка оплаты при наличии записей #### `@dp.message(VinStates.waiting_for_photo_vin)` **Функция:** `process_photo_vin` **Логика:** 1. Валидация VIN 2. Запрос `fetch_vin_info(vin)` и `count_photo_records(vin)` 3. Показ информации о количестве фотографий 4. Кнопка оплаты при наличии фотографий ### `@dp.message(lambda message: message.successful_payment)` **Функция:** `successful_payment_handler` **Логика обработки платежей по payload:** #### `detailed_vin_info:{vin}` 1. Запрос `fetch_detailed_vin_info(vin)` 2. Форматирование детального отчета по категориям 3. Возврат денег при отсутствии данных 4. Автоматический возврат админу #### `detailed_salvage_check:{vin}` 1. Запрос `fetch_salvage_detailed_info(vin)` 2. Форматирование salvage отчета с повреждениями 3. Отдельное сообщение о фотографиях 4. Возврат денег при отсутствии данных 5. Автоматический возврат админу #### `vehicle_photos:{vin}` 1. Запрос `fetch_photo_paths(vin)` 2. Конвертация путей под текущую OS 3. Отправка фотографий группами по 10 4. Возврат денег при отсутствии фотографий 5. Автоматический возврат админу --- ## Функции базы данных ### Класс `OracleDatabase` #### `__init__(user, password, dsn)` Инициализация подключения к Oracle DB. #### `async def connect()` Создает пул подключений (min=1, max=4). #### `async def fetch_vin_info(vin: str) -> Tuple[str, str, str, int]` **Возвращает:** `(make, model, year, nhtsa_records_count)` **SQL запрос:** ```sql select 'None', COALESCE((select value from salvagedb.m_JSONS_FROM_NHTSA v3 where v3.svin = s.svin and v3.variableid = '26'), (select val from salvagedb.vind2 where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) and varb = 'Make'),'UNKNOWN') make, -- аналогично для model и year (select count(*) from salvagedb.m_JSONS_FROM_NHTSA v3 where v3.svin = s.svin) cnt from (select substr(:vin,1,10) svin, :vin vin from dual) s ``` #### `async def count_salvage_records(vin: str) -> int` **SQL:** `SELECT COUNT(*) FROM salvagedb.salvagedb WHERE vin = :vin and svin = substr(:vin,1,10)` #### `async def count_photo_records(vin: str) -> int` **SQL:** `SELECT COUNT(*) FROM salvagedb.salvage_images WHERE vin = :vin AND fn = 1` #### `async def fetch_photo_paths(vin: str) -> list` **SQL:** `SELECT ipath FROM salvagedb.salvage_images WHERE fn = 1 AND vin = :vin` **Возвращает:** Список путей к фотографиям. #### `async def fetch_salvage_detailed_info(vin: str) -> list` **Возвращает:** Детальную информацию о salvage записях. **SQL запрос:** ```sql SELECT odo, odos, dem1, dem2, month||'/'||year as sale_date, JSON_VALUE(jdata, '$.RepCost') AS j_rep_cost, JSON_VALUE(jdata, '$.Runs_Drive') AS j_runs_drive, JSON_VALUE(jdata, '$.Locate') AS j_locate, (select count(*) from salvagedb.salvage_images si where si.vin = s.vin and fn = 1) img_count FROM salvagedb.salvagedb s LEFT JOIN salvagedb.addinfo i ON s.num = i.numid WHERE vin = :vin AND svin = substr(:vin, 1, 10) ORDER BY year DESC, month DESC ``` #### `async def fetch_detailed_vin_info(vin: str) -> dict` **Возвращает:** Детальную информацию о VIN по категориям. **Категории:** - basic_characteristics - engine_and_powertrain - transmission - active_safety - passive_safety - dimensions_and_construction - brake_system - lighting - additional_features - manufacturing_and_localization - ncsa_data - technical_information_and_errors #### Пользовательские функции #### `async def save_user(user: User, interaction_source: str) -> bool` Сохраняет/обновляет данные пользователя при каждом взаимодействии. #### `async def update_user_payment(user_id: int, payment_amount: float) -> bool` Обновляет статистику платежей пользователя. #### `async def get_user_stats(user_id: int) -> dict` Возвращает статистику конкретного пользователя. #### `async def get_users_summary() -> dict` Возвращает общую статистику по всем пользователям. --- ## Система платежей ### Telegram Stars Бот использует Telegram Stars для приема платежей. ### Типы платежей: 1. **Детальная информация VIN** - `DECODE_PRICE` звезд 2. **Salvage проверка** - `CHECK_PRICE` звезд 3. **Фотографии автомобиля** - `IMG_PRICE` звезд ### Процесс оплаты: 1. Пользователь нажимает кнопку оплаты 2. Создается invoice с уникальным payload 3. Pre-checkout подтверждение 4. Successful payment обработка 5. Предоставление услуги или возврат средств ### Автоматический возврат админу: Если `message.from_user.id == ADMIN_USER_ID`, после предоставления услуги автоматически возвращаются потраченные звезды. ### Обработка ошибок: - Отсутствие данных → автоматический возврат - Ошибка сервера → автоматический возврат - Ошибка возврата → уведомление с transaction ID --- ## Работа с фотографиями ### Структура хранения: ``` База данных: 20250530/1c4hjxdg0pw697757/photo.jpg Windows: D:\SALVAGEDB\salvagedb_bot\images\20250530\1c4hjxdg0pw697757\photo.jpg Linux: /images/20250530/1c4hjxdg0pw697757/photo.jpg ``` ### Процесс отправки: 1. Получение путей из БД 2. Конвертация под текущую OS 3. Разбивка на группы по 10 фотографий 4. Отправка media groups с описаниями 5. Итоговое сообщение ### Ограничения: - Максимум 10 фотографий в одной группе (Telegram API) - Пауза 0.5 сек между группами - Проверка существования файлов --- ## Системные функции ### Логирование: ```python # Основное логирование logging.basicConfig(level=logging.WARNING) # Debug режим if getenv("DEBUG",'0') == '1': logging.basicConfig(level=logging.INFO) ``` ### Middleware: ```python # Передача подключения к БД во все handlers dp.message.middleware(DbSessionMiddleware(oracle_db)) dp.callback_query.middleware(DbSessionMiddleware(oracle_db)) dp.pre_checkout_query.middleware(DbSessionMiddleware(oracle_db)) ``` ### Startup/Shutdown: ```python async def on_startup(): log_system_info() # Системная информация await oracle_db.connect() # Подключение к БД # Регистрация middleware async def on_shutdown(): await oracle_db.close() # Закрытие пула подключений ``` --- ## Middleware ### `DbSessionMiddleware` **Файл:** `middlewares/db.py` **Назначение:** Передает экземпляр подключения к БД во все handlers. **Использование:** ```python async def handler(message: Message, db: OracleDatabase = None): database = db or oracle_db # Fallback на глобальный ``` --- ## Структура проекта ``` salvagedb_bot/ ├── main.py # Основной файл бота ├── db.py # Класс работы с БД ├── read_dev.md # Документация (этот файл) ├── middlewares/ │ └── db.py # Middleware для БД └── images/ # Директория с фотографиями (Windows) └── 20250530/ └── vin_lower/ └── photo.jpg ``` --- ## API Endpoints ### Telegram Bot API Бот использует стандартные методы Telegram Bot API: #### Отправка сообщений: - `message.answer()` - текстовые сообщения - `message.answer_media_group()` - группы фотографий #### Платежи: - `bot.send_invoice()` - создание счета - `bot.refund_star_payment()` - возврат звезд #### Webhook vs Polling: Текущая конфигурация использует polling: ```python await dp.start_polling(bot) ``` --- ## Примеры использования ### Запуск бота: ```bash # Установка переменных окружения export BOT_TOKEN="your_token" export db_user="oracle_user" # ... другие переменные # Запуск python main.py ``` ### Тестирование платежей: 1. Установить `ADMIN_USER_ID` на свой Telegram ID 2. Выполнить любую оплату 3. Получить услугу + автоматический возврат звезд ### Debug режим: ```bash export DEBUG=1 python main.py ``` Включает детальное логирование всех операций. --- ## Troubleshooting ### Проблемы с фотографиями: 1. Проверить права доступа к директории images 2. Убедиться в правильности путей для текущей OS 3. Проверить логи на ошибки файловой системы ### Проблемы с БД: 1. Проверить строку подключения DSN 2. Убедиться в доступности Oracle DB 3. Проверить права пользователя БД ### Проблемы с платежами: 1. Убедиться в корректности BOT_TOKEN 2. Проверить что бот добавлен в Telegram Stars 3. Проверить логи на ошибки Telegram API --- ## Обновления и изменения При внесении изменений в код обязательно обновляйте эту документацию. ### История изменений: - **v1.0** - Базовая функциональность (decode VIN, check VIN) - **v1.1** - Добавлена поддержка фотографий - **v1.2** - Улучшена отправка множественных фотографий - **v1.3** - Добавлены функции определения OS и автоматические пути --- *Документация актуальна на момент последнего обновления кода.*