savagedb_bot/wiki/read_dev.md

540 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 и автоматические пути
---
*Документация актуальна на момент последнего обновления кода.*