Добавлены функции для получения путей к фотографиям и подсчета их количества по VIN в классе OracleDatabase. Обновлены обработчики в main.py для обработки запросов на получение фотографий, включая логику оплаты и отправки изображений пользователю. Эти изменения улучшают функциональность бота и позволяют пользователям получать доступ к фотографиям повреждений автомобилей.
This commit is contained in:
parent
3474fe5f96
commit
5f3d478adb
26
db.py
26
db.py
@ -127,6 +127,19 @@ class OracleDatabase:
|
||||
import asyncio
|
||||
return await asyncio.to_thread(_query)
|
||||
|
||||
async def fetch_photo_paths(self, vin: str) -> list:
|
||||
"""
|
||||
Получает список путей к фотографиям для данного VIN
|
||||
"""
|
||||
def _query():
|
||||
with self._pool.acquire() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SELECT ipath FROM salvagedb.salvage_images WHERE fn = 1 AND vin = :vin", {"vin": vin})
|
||||
results = cur.fetchall()
|
||||
return [row[0] for row in results if row[0]] if results else []
|
||||
import asyncio
|
||||
return await asyncio.to_thread(_query)
|
||||
|
||||
async def fetch_detailed_vin_info(self, vin: str) -> dict:
|
||||
# Manual async wrapper since oracledb is synchronous (threaded)
|
||||
def _query():
|
||||
@ -378,3 +391,16 @@ class OracleDatabase:
|
||||
except Exception as e:
|
||||
print(f"Error getting users summary: {e}")
|
||||
return {}
|
||||
|
||||
async def count_photo_records(self, vin: str) -> int:
|
||||
"""
|
||||
Подсчитывает количество фотографий для данного VIN
|
||||
"""
|
||||
def _query():
|
||||
with self._pool.acquire() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SELECT COUNT(*) FROM salvagedb.salvage_images WHERE vin = :vin AND fn = 1", {"vin": vin})
|
||||
result = cur.fetchone()
|
||||
return result[0] if result else 0
|
||||
import asyncio
|
||||
return await asyncio.to_thread(_query)
|
||||
|
||||
77
db_sql/salvage.sql
Normal file
77
db_sql/salvage.sql
Normal file
@ -0,0 +1,77 @@
|
||||
-- Create table
|
||||
create table SALVAGEDB
|
||||
(
|
||||
num NUMBER(20),
|
||||
vin VARCHAR2(20),
|
||||
svin VARCHAR2(15),
|
||||
odo NUMBER(11),
|
||||
odos VARCHAR2(50),
|
||||
title VARCHAR2(200),
|
||||
dem1 VARCHAR2(200),
|
||||
dem2 VARCHAR2(200),
|
||||
year NUMBER(4),
|
||||
month NUMBER(4),
|
||||
last_update DATE,
|
||||
auction VARCHAR2(1)
|
||||
)
|
||||
tablespace USERS
|
||||
pctfree 10
|
||||
initrans 1
|
||||
maxtrans 255
|
||||
storage
|
||||
(
|
||||
initial 3581M
|
||||
next 1M
|
||||
minextents 1
|
||||
maxextents unlimited
|
||||
)
|
||||
compress;
|
||||
-- Add comments to the columns
|
||||
comment on column SALVAGEDB.num
|
||||
is 'ID';
|
||||
comment on column SALVAGEDB.vin
|
||||
is 'vin';
|
||||
comment on column SALVAGEDB.odo
|
||||
is 'îäîìåòð';
|
||||
comment on column SALVAGEDB.odos
|
||||
is 'îäîìåòð ñòàòóñ';
|
||||
comment on column SALVAGEDB.title
|
||||
is 'äîêóìåíò';
|
||||
comment on column SALVAGEDB.dem1
|
||||
is 'ïîâðåäåëíèå 1';
|
||||
comment on column SALVAGEDB.dem2
|
||||
is 'ïîâðåæåäíèå 2';
|
||||
comment on column SALVAGEDB.year
|
||||
is 'ìåñÿö';
|
||||
comment on column SALVAGEDB.month
|
||||
is 'ãîä';
|
||||
comment on column SALVAGEDB.auction
|
||||
is 'Ñ êîïàðò I - IAAI';
|
||||
-- Create/Recreate indexes
|
||||
create index IDX_SALVAGEDB_NUM on SALVAGEDB (NUM)
|
||||
tablespace USERS
|
||||
pctfree 10
|
||||
initrans 2
|
||||
maxtrans 255
|
||||
storage
|
||||
(
|
||||
initial 64K
|
||||
next 1M
|
||||
minextents 1
|
||||
maxextents unlimited
|
||||
)
|
||||
compress nologging;
|
||||
create index IDX_SALVAGEDB_SVIN_VIN on SALVAGEDB (SVIN, VIN)
|
||||
tablespace USERS
|
||||
pctfree 10
|
||||
initrans 2
|
||||
maxtrans 255
|
||||
storage
|
||||
(
|
||||
initial 64K
|
||||
next 1M
|
||||
minextents 1
|
||||
maxextents unlimited
|
||||
);
|
||||
-- Grant/Revoke object privileges
|
||||
grant read on SALVAGEDB to SALVAGEBOT;
|
||||
36
db_sql/salvage_images.sql
Normal file
36
db_sql/salvage_images.sql
Normal file
@ -0,0 +1,36 @@
|
||||
-- Create table
|
||||
create table SALVAGE_IMAGES
|
||||
(
|
||||
vin VARCHAR2(20) not null,
|
||||
dateadd TIMESTAMP(6) not null,
|
||||
ipath VARCHAR2(500) not null,
|
||||
fn NUMBER(1) default 0 not null
|
||||
)
|
||||
tablespace USERS
|
||||
pctfree 0
|
||||
initrans 1
|
||||
maxtrans 255
|
||||
storage
|
||||
(
|
||||
initial 64K
|
||||
next 1M
|
||||
minextents 1
|
||||
maxextents unlimited
|
||||
)
|
||||
compress;
|
||||
-- Create/Recreate indexes
|
||||
create unique index VIB_DATEADD_IDX on SALVAGE_IMAGES (VIN, DATEADD)
|
||||
tablespace USERS
|
||||
pctfree 10
|
||||
initrans 2
|
||||
maxtrans 255
|
||||
storage
|
||||
(
|
||||
initial 64K
|
||||
next 1M
|
||||
minextents 1
|
||||
maxextents unlimited
|
||||
)
|
||||
compress 1;
|
||||
-- Grant/Revoke object privileges
|
||||
grant read on SALVAGE_IMAGES to SALVAGEBOT;
|
||||
413
main.py
413
main.py
@ -7,7 +7,7 @@ import os
|
||||
|
||||
from aiogram import Bot, Dispatcher
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, LabeledPrice, PreCheckoutQuery
|
||||
from aiogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, LabeledPrice, PreCheckoutQuery, InputMediaPhoto, FSInputFile
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.fsm.context import FSMContext
|
||||
@ -148,6 +148,165 @@ def is_macos() -> bool:
|
||||
return get_operating_system() == 'macOS'
|
||||
|
||||
|
||||
def convert_photo_path(db_path: str) -> str:
|
||||
"""
|
||||
Конвертирует путь к фотографии в зависимости от операционной системы
|
||||
Args:
|
||||
db_path: путь из базы данных в Linux формате (с /)
|
||||
Returns:
|
||||
str: полный путь к файлу с учетом OS и базового пути
|
||||
"""
|
||||
if not db_path:
|
||||
return ""
|
||||
|
||||
# Базовый путь из константы
|
||||
base_path = image_path
|
||||
|
||||
if is_windows():
|
||||
# Конвертируем Linux пути в Windows формат
|
||||
windows_path = db_path.replace('/', '\\')
|
||||
full_path = f"{base_path}\\{windows_path}"
|
||||
logging.info(f"Converted path for Windows: {db_path} -> {full_path}")
|
||||
return full_path
|
||||
else:
|
||||
# Для Linux/macOS оставляем как есть
|
||||
full_path = f"{base_path}/{db_path}"
|
||||
logging.info(f"Path for Linux/macOS: {db_path} -> {full_path}")
|
||||
return full_path
|
||||
|
||||
|
||||
def prepare_photo_paths(db_paths: list) -> list:
|
||||
"""
|
||||
Подготавливает список полных путей к фотографиям
|
||||
Args:
|
||||
db_paths: список путей из базы данных
|
||||
Returns:
|
||||
list: список полных путей к файлам
|
||||
"""
|
||||
if not db_paths:
|
||||
return []
|
||||
|
||||
full_paths = []
|
||||
for db_path in db_paths:
|
||||
full_path = convert_photo_path(db_path)
|
||||
if full_path:
|
||||
full_paths.append(full_path)
|
||||
|
||||
logging.info(f"Prepared {len(full_paths)} photo paths from {len(db_paths)} database paths")
|
||||
return full_paths
|
||||
|
||||
|
||||
async def send_vehicle_photos(message: Message, vin: str, photo_paths: list, make: str, model: str, year: str):
|
||||
"""
|
||||
Отправляет фотографии автомобиля пользователю
|
||||
Args:
|
||||
message: сообщение пользователя
|
||||
vin: VIN автомобиля
|
||||
photo_paths: список полных путей к фотографиям
|
||||
make, model, year: информация об автомобиле
|
||||
"""
|
||||
if not photo_paths:
|
||||
await message.answer("❌ No photos found to send.")
|
||||
return
|
||||
|
||||
try:
|
||||
# Telegram позволяет максимум 10 фотографий в media group
|
||||
photos_per_group = 10
|
||||
total_photos = len(photo_paths)
|
||||
|
||||
logging.info(f"Attempting to send {total_photos} photos for VIN: {vin}")
|
||||
|
||||
# Разбиваем фотографии на группы по 10
|
||||
photo_groups = [photo_paths[i:i + photos_per_group] for i in range(0, len(photo_paths), photos_per_group)]
|
||||
total_groups = len(photo_groups)
|
||||
|
||||
logging.info(f"Split {total_photos} photos into {total_groups} groups")
|
||||
|
||||
sent_count = 0
|
||||
|
||||
for group_num, photo_group in enumerate(photo_groups, 1):
|
||||
try:
|
||||
logging.info(f"Processing group {group_num}/{total_groups} with {len(photo_group)} photos")
|
||||
|
||||
# Создаем media group для текущей группы
|
||||
media_group = []
|
||||
|
||||
for i, photo_path in enumerate(photo_group):
|
||||
try:
|
||||
# Проверяем существование файла
|
||||
if os.path.exists(photo_path):
|
||||
# Создаем InputMediaPhoto
|
||||
if i == 0 and group_num == 1:
|
||||
# Первая фотография первой группы с полным описанием
|
||||
if make == "UNKNOWN" and model == "UNKNOWN" and year == "UNKNOWN":
|
||||
caption = f"📸 Vehicle damage photos\n📋 VIN: {vin}\n📊 Total photos: {total_photos}\n🗂️ Group {group_num}/{total_groups}"
|
||||
else:
|
||||
caption = f"📸 {year} {make} {model}\n📋 VIN: {vin}\n📊 Total photos: {total_photos}\n🗂️ Group {group_num}/{total_groups}"
|
||||
elif i == 0:
|
||||
# Первая фотография других групп с номером группы
|
||||
caption = f"🗂️ Group {group_num}/{total_groups}"
|
||||
else:
|
||||
# Остальные фотографии без описания
|
||||
caption = None
|
||||
|
||||
if caption:
|
||||
media_group.append(InputMediaPhoto(
|
||||
media=FSInputFile(photo_path),
|
||||
caption=caption
|
||||
))
|
||||
else:
|
||||
media_group.append(InputMediaPhoto(
|
||||
media=FSInputFile(photo_path)
|
||||
))
|
||||
|
||||
sent_count += 1
|
||||
logging.info(f"Added photo {sent_count}/{total_photos}: {photo_path}")
|
||||
else:
|
||||
logging.warning(f"Photo file not found: {photo_path}")
|
||||
except Exception as photo_error:
|
||||
logging.error(f"Error processing photo {sent_count + 1} ({photo_path}): {photo_error}")
|
||||
continue
|
||||
|
||||
if media_group:
|
||||
# Отправляем media group
|
||||
await message.answer_media_group(media_group)
|
||||
logging.info(f"Successfully sent group {group_num}/{total_groups} with {len(media_group)} photos")
|
||||
|
||||
# Небольшая пауза между группами для избежания rate limiting
|
||||
if group_num < total_groups:
|
||||
await asyncio.sleep(0.5)
|
||||
else:
|
||||
logging.warning(f"No valid photos in group {group_num}")
|
||||
|
||||
except Exception as group_error:
|
||||
logging.error(f"Error sending photo group {group_num}: {group_error}")
|
||||
await message.answer(f"❌ Error sending photo group {group_num}. Continuing with remaining photos...")
|
||||
continue
|
||||
|
||||
if sent_count > 0:
|
||||
# Отправляем итоговое сообщение
|
||||
await message.answer(
|
||||
f"✅ **Photos sent successfully!**\n"
|
||||
f"📊 **{sent_count} of {total_photos} photos** delivered\n"
|
||||
f"🗂️ **{total_groups} photo groups** sent"
|
||||
)
|
||||
logging.info(f"Successfully sent {sent_count}/{total_photos} photos for VIN: {vin}")
|
||||
else:
|
||||
# Если ни одна фотография не найдена
|
||||
await message.answer(
|
||||
"❌ **Error:** Photo files not found on server.\n"
|
||||
"Please contact support with your transaction details."
|
||||
)
|
||||
logging.error(f"No valid photo files found for VIN: {vin}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error sending photos for VIN {vin}: {e}")
|
||||
await message.answer(
|
||||
"❌ **Error sending photos.** Please contact support with your transaction details.\n"
|
||||
f"Error details: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
if getenv("DEBUG",'0') == '1':
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
else:
|
||||
@ -182,6 +341,7 @@ dp = Dispatcher()
|
||||
class VinStates(StatesGroup):
|
||||
waiting_for_vin = State()
|
||||
waiting_for_check_vin = State()
|
||||
waiting_for_photo_vin = State()
|
||||
|
||||
|
||||
# Command handler
|
||||
@ -240,6 +400,19 @@ async def check_vin_callback(callback: CallbackQuery, state: FSMContext, db: Ora
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@dp.callback_query(lambda c: c.data == "search_car_photo")
|
||||
async def search_car_photo_callback(callback: CallbackQuery, state: FSMContext, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
database = db or oracle_db
|
||||
|
||||
# Сохраняем данные пользователя при нажатии кнопки
|
||||
await database.save_user(callback.from_user, "search_car_photo_button")
|
||||
|
||||
await callback.message.answer("Please enter the vehicle VIN to search for damage photos.")
|
||||
await state.set_state(VinStates.waiting_for_photo_vin)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@dp.callback_query(lambda c: c.data == "main_menu")
|
||||
async def main_menu_callback(callback: CallbackQuery, state: FSMContext, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
@ -412,6 +585,31 @@ async def pay_check_detailed_callback(callback: CallbackQuery, db: OracleDatabas
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@dp.callback_query(lambda c: c.data and c.data.startswith("pay_photos:"))
|
||||
async def pay_photos_callback(callback: CallbackQuery, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
database = db or oracle_db
|
||||
|
||||
# Сохраняем данные пользователя при инициации платежа
|
||||
await database.save_user(callback.from_user, "photos_payment_initiation")
|
||||
|
||||
# Извлекаем VIN из callback data
|
||||
vin = callback.data.split(":")[1]
|
||||
prices = [LabeledPrice(label="Vehicle Damage Photos", amount=IMG_PRICE)]
|
||||
logging.info(f"Sending invoice for photos VIN: {vin}")
|
||||
|
||||
await callback.bot.send_invoice(
|
||||
chat_id=callback.message.chat.id,
|
||||
title="Vehicle Damage Photos",
|
||||
description=f"Get access to all damage photos for this vehicle for {IMG_PRICE} Telegram Stars",
|
||||
payload=f"vehicle_photos:{vin}", # Уникальный payload для фотографий
|
||||
provider_token="", # Empty for Telegram Stars
|
||||
currency="XTR", # Telegram Stars currency
|
||||
prices=prices
|
||||
)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@dp.pre_checkout_query()
|
||||
async def pre_checkout_handler(pre_checkout_query: PreCheckoutQuery, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
@ -475,7 +673,13 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None
|
||||
payload = message.successful_payment.invoice_payload
|
||||
|
||||
# Определяем сумму платежа в зависимости от типа
|
||||
payment_amount = 10.0 if payload.startswith("detailed_salvage_check:") else 1.0
|
||||
if payload.startswith("detailed_salvage_check:"):
|
||||
payment_amount = float(CHECK_PRICE)
|
||||
elif payload.startswith("vehicle_photos:"):
|
||||
payment_amount = float(IMG_PRICE)
|
||||
else:
|
||||
payment_amount = float(DECODE_PRICE)
|
||||
|
||||
await database.update_user_payment(message.from_user.id, payment_amount)
|
||||
|
||||
if payload.startswith("detailed_vin_info:"):
|
||||
@ -861,6 +1065,151 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None
|
||||
"⚠️ Please contact support immediately with this transaction ID for a manual refund:\n"
|
||||
f"🆔 {message.successful_payment.telegram_payment_charge_id}"
|
||||
)
|
||||
elif payload.startswith("vehicle_photos:"):
|
||||
vin = payload.split(":")[1]
|
||||
|
||||
try:
|
||||
# Получаем информацию о VIN и количество фотографий
|
||||
make, model, year, cnt = await database.fetch_vin_info(vin)
|
||||
photo_count = await database.count_photo_records(vin)
|
||||
|
||||
logging.info(f"Photos payment for VIN: {vin}, make: {make}, model: {model}, year: {year}, photo_count: {photo_count}")
|
||||
|
||||
if photo_count > 0:
|
||||
# Есть фотографии - предоставляем доступ (пока заглушка)
|
||||
if make == "UNKNOWN" and model == "UNKNOWN" and year == "UNKNOWN":
|
||||
response_text = f"📸 **Vehicle Damage Photos**\n\n"
|
||||
else:
|
||||
response_text = f"🚗 **{year} {make} {model}**\n\n"
|
||||
response_text += f"📸 **Vehicle Damage Photos**\n\n"
|
||||
|
||||
response_text += f"✅ **Payment successful!** You now have access to **{photo_count} damage photos** for this vehicle.\n\n"
|
||||
response_text += f"📁 **Photos will be sent separately** - please wait while we prepare your images.\n\n"
|
||||
response_text += f"---\n"
|
||||
response_text += f"💰 **Transaction ID:** {escape_markdown(message.successful_payment.telegram_payment_charge_id)}\n"
|
||||
response_text += f"📋 **VIN:** {escape_markdown(vin)}"
|
||||
|
||||
# Создаем клавиатуру с дополнительными действиями
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="Search another VIN", callback_data="search_car_photo")
|
||||
builder.button(text="Back to Main Menu", callback_data="main_menu")
|
||||
builder.adjust(2)
|
||||
|
||||
logging.info("Attempting to send photos payment success message...")
|
||||
try:
|
||||
await message.answer(response_text, reply_markup=builder.as_markup(), parse_mode="Markdown")
|
||||
logging.info("Photos payment message sent successfully!")
|
||||
|
||||
# Получаем пути к фотографиям из базы данных
|
||||
logging.info(f"Fetching photo paths for VIN: {vin}")
|
||||
db_photo_paths = await database.fetch_photo_paths(vin)
|
||||
logging.info(f"Found {len(db_photo_paths)} photo paths in database")
|
||||
|
||||
if db_photo_paths:
|
||||
# Подготавливаем полные пути к файлам
|
||||
full_photo_paths = prepare_photo_paths(db_photo_paths)
|
||||
logging.info(f"Prepared {len(full_photo_paths)} full photo paths")
|
||||
|
||||
# Отправляем фотографии
|
||||
await send_vehicle_photos(message, vin, full_photo_paths, make, model, year)
|
||||
else:
|
||||
await message.answer(
|
||||
"⚠️ **Warning:** No photo paths found in database despite photo count > 0.\n"
|
||||
"Please contact support with your transaction details."
|
||||
)
|
||||
logging.warning(f"No photo paths found for VIN {vin} despite photo_count = {photo_count}")
|
||||
|
||||
except Exception as markdown_error:
|
||||
logging.error(f"Markdown parsing failed for photos payment: {markdown_error}")
|
||||
plain_response = response_text.replace("**", "").replace("*", "")
|
||||
await message.answer(plain_response, reply_markup=builder.as_markup())
|
||||
logging.info("Plain text photos payment message sent successfully!")
|
||||
|
||||
# Получаем пути к фотографиям из базы данных (fallback)
|
||||
logging.info(f"Fetching photo paths for VIN: {vin} (fallback)")
|
||||
db_photo_paths = await database.fetch_photo_paths(vin)
|
||||
logging.info(f"Found {len(db_photo_paths)} photo paths in database (fallback)")
|
||||
|
||||
if db_photo_paths:
|
||||
# Подготавливаем полные пути к файлам
|
||||
full_photo_paths = prepare_photo_paths(db_photo_paths)
|
||||
logging.info(f"Prepared {len(full_photo_paths)} full photo paths (fallback)")
|
||||
|
||||
# Отправляем фотографии
|
||||
await send_vehicle_photos(message, vin, full_photo_paths, make, model, year)
|
||||
else:
|
||||
await message.answer(
|
||||
"Warning: No photo paths found in database despite photo count > 0. "
|
||||
"Please contact support with your transaction details."
|
||||
)
|
||||
logging.warning(f"No photo paths found for VIN {vin} despite photo_count = {photo_count} (fallback)")
|
||||
|
||||
# Проверяем, является ли пользователь администратором и возвращаем звезды
|
||||
if message.from_user.id == ADMIN_USER_ID:
|
||||
try:
|
||||
await message.bot.refund_star_payment(
|
||||
user_id=message.from_user.id,
|
||||
telegram_payment_charge_id=message.successful_payment.telegram_payment_charge_id
|
||||
)
|
||||
await message.answer(
|
||||
"🔧 **Admin Refund**\n\n"
|
||||
f"💰 Payment automatically refunded for admin user.\n"
|
||||
f"🆔 Transaction ID: {escape_markdown(message.successful_payment.telegram_payment_charge_id)}\n"
|
||||
"ℹ️ Admin access - no charges applied.",
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
logging.info(f"Admin refund successful for user {message.from_user.id}")
|
||||
except Exception as refund_error:
|
||||
logging.error(f"Failed to refund admin payment: {refund_error}")
|
||||
await message.answer(
|
||||
"⚠️ **Admin Refund Failed**\n\n"
|
||||
"Could not automatically refund admin payment. Please contact technical support.\n"
|
||||
f"🆔 Transaction ID: {escape_markdown(message.successful_payment.telegram_payment_charge_id)}",
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
else:
|
||||
# Нет фотографий - возвращаем деньги
|
||||
try:
|
||||
await message.bot.refund_star_payment(
|
||||
user_id=message.from_user.id,
|
||||
telegram_payment_charge_id=message.successful_payment.telegram_payment_charge_id
|
||||
)
|
||||
await message.answer(
|
||||
"❌ No photos found for this VIN in our database.\n"
|
||||
"💰 Your payment has been automatically refunded.\n"
|
||||
"Please try another VIN or contact support if you believe this is an error."
|
||||
)
|
||||
logging.info(f"Refund successful for user {message.from_user.id} - no photos found for VIN {vin}")
|
||||
except Exception as refund_error:
|
||||
logging.error(f"Failed to refund payment for user {message.from_user.id}: {refund_error}")
|
||||
await message.answer(
|
||||
"❌ No photos found for this VIN.\n"
|
||||
"⚠️ Please contact support with this transaction ID for a refund:\n"
|
||||
f"🆔 {message.successful_payment.telegram_payment_charge_id}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error getting photos info for {vin}: {e}")
|
||||
|
||||
# Возвращаем деньги при ошибке
|
||||
try:
|
||||
await message.bot.refund_star_payment(
|
||||
user_id=message.from_user.id,
|
||||
telegram_payment_charge_id=message.successful_payment.telegram_payment_charge_id
|
||||
)
|
||||
await message.answer(
|
||||
"❌ Error retrieving photos information from our database.\n"
|
||||
"💰 Your payment has been automatically refunded.\n"
|
||||
"Please try again later or contact support if the issue persists."
|
||||
)
|
||||
logging.info(f"Refund successful for user {message.from_user.id}, charge_id: {message.successful_payment.telegram_payment_charge_id}")
|
||||
except Exception as refund_error:
|
||||
logging.error(f"Failed to refund payment for user {message.from_user.id}: {refund_error}")
|
||||
await message.answer(
|
||||
"❌ Error retrieving photos information from our database.\n"
|
||||
"⚠️ Please contact support immediately with this transaction ID for a manual refund:\n"
|
||||
f"🆔 {message.successful_payment.telegram_payment_charge_id}"
|
||||
)
|
||||
else:
|
||||
await message.answer(
|
||||
f"✅ Payment successful! Thank you for your purchase.\n"
|
||||
@ -892,6 +1241,66 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None
|
||||
)
|
||||
|
||||
|
||||
@dp.message(VinStates.waiting_for_photo_vin)
|
||||
async def process_photo_vin(message: Message, state: FSMContext, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
database = db or oracle_db
|
||||
|
||||
# Сохраняем данные пользователя при обработке VIN
|
||||
await database.save_user(message.from_user, "photo_vin_processing")
|
||||
|
||||
vin = message.text.strip().upper()
|
||||
if len(vin) == 17 and vin.isalnum() and all(c not in vin for c in ["I", "O", "Q"]):
|
||||
try:
|
||||
# Получаем базовую информацию о VIN для заголовка
|
||||
make, model, year, cnt = await database.fetch_vin_info(vin)
|
||||
|
||||
# Получаем количество фотографий
|
||||
photo_count = await database.count_photo_records(vin)
|
||||
|
||||
logging.info(f"Photo search VIN: make: {make}, model: {model}, year: {year}, photo_count: {photo_count}")
|
||||
|
||||
# Формируем ответ в зависимости от наличия фотографий
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
if photo_count > 0:
|
||||
# Есть фотографии - показываем информацию и кнопку оплаты
|
||||
if make == "UNKNOWN" and model == "UNKNOWN" and year == "UNKNOWN":
|
||||
response_text = f"📸 **Photo Information**\n\n"
|
||||
else:
|
||||
response_text = f"🚗 **{year} {make} {model}**\n\n"
|
||||
response_text += f"📸 **Photo Information**\n\n"
|
||||
|
||||
response_text += f"🖼️ **{photo_count} damage photos** found in our database for this vehicle.\n"
|
||||
response_text += f"These photos show the actual condition and damage of the vehicle during auction."
|
||||
|
||||
builder.button(text=f"Pay {IMG_PRICE} ⭐️ for photos", callback_data=f"pay_photos:{vin}", pay=True)
|
||||
builder.button(text="Try another VIN", callback_data="search_car_photo")
|
||||
builder.button(text="Back to Main Menu", callback_data="main_menu")
|
||||
builder.adjust(1, 1, 1) # Each button on separate row
|
||||
else:
|
||||
# Нет фотографий
|
||||
if make == "UNKNOWN" and model == "UNKNOWN" and year == "UNKNOWN":
|
||||
response_text = f"❌ **Unable to decode VIN or no photos found**\n\n"
|
||||
else:
|
||||
response_text = f"🚗 **{year} {make} {model}**\n\n"
|
||||
|
||||
response_text += f"📸 **No damage photos found** for this VIN in our database."
|
||||
|
||||
builder.button(text="Try another VIN", callback_data="search_car_photo")
|
||||
builder.button(text="Back to Main Menu", callback_data="main_menu")
|
||||
builder.adjust(1, 1) # Each button on separate row
|
||||
|
||||
await message.answer(response_text, reply_markup=builder.as_markup(), parse_mode="Markdown")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Database error for photo search VIN {vin}: {e}")
|
||||
await message.answer("Error retrieving data from database. Please try again later.")
|
||||
await state.clear()
|
||||
else:
|
||||
await message.answer("Invalid VIN. Please enter a valid 17-character VIN (letters and numbers, no I, O, Q).")
|
||||
|
||||
|
||||
async def on_startup():
|
||||
log_system_info() # Логируем информацию о системе
|
||||
await oracle_db.connect()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user