Обновлены обработчики в main.py для улучшения логики обработки запросов на получение информации о повреждениях. Добавлены новые функции для работы с данными о повреждениях, включая оптимизацию SQL-запросов и улучшение форматирования выводимой информации. Эти изменения повышают точность и удобство использования бота.

This commit is contained in:
Vlad 2025-06-02 00:48:40 +03:00
parent 5f3d478adb
commit fe0aaefbec

540
read_dev.md Normal file
View File

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