Добавлены новые функции для работы с записями о повреждениях в классе OracleDatabase и обновлены обработчики в main.py:
- Реализован метод count_salvage_records для подсчета записей по VIN. - Добавлен метод fetch_salvage_detailed_info для получения детальной информации о повреждениях. - Обновлены обработчики для проверки VIN и получения детальной информации о записях, включая интеграцию с платежной системой. Эти изменения улучшают функциональность бота и позволяют пользователям получать более полную информацию о состоянии автомобилей.
This commit is contained in:
parent
5ee0435758
commit
e589ddafc5
74
db.py
74
db.py
@ -62,6 +62,80 @@ class OracleDatabase:
|
||||
import asyncio
|
||||
return await asyncio.to_thread(_query)
|
||||
|
||||
async def count_salvage_records(self, vin: str) -> int:
|
||||
"""
|
||||
Подсчитывает количество записей в таблице salvagedb.salvagedb для данного VIN
|
||||
"""
|
||||
def _query():
|
||||
with self._pool.acquire() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SELECT COUNT(*) FROM salvagedb.salvagedb WHERE vin = :vin", {"vin": vin})
|
||||
result = cur.fetchone()
|
||||
return result[0] if result else 0
|
||||
import asyncio
|
||||
return await asyncio.to_thread(_query)
|
||||
|
||||
async def fetch_salvage_detailed_info(self, vin: str) -> list:
|
||||
"""
|
||||
Получает детальную информацию о поврежденияхи истории из таблицы salvagedb.salvagedb
|
||||
"""
|
||||
def _query():
|
||||
with self._pool.acquire() as conn:
|
||||
with conn.cursor() as cur:
|
||||
query = """
|
||||
SELECT
|
||||
vin,
|
||||
make,
|
||||
model,
|
||||
vehicle_year,
|
||||
vehicle_type,
|
||||
primary_damage,
|
||||
secondary_damage,
|
||||
sale_date,
|
||||
odometer,
|
||||
sale_title_state,
|
||||
sale_title_type,
|
||||
seller,
|
||||
lot,
|
||||
estimate_repair_cost,
|
||||
actual_cash_value,
|
||||
sale_country,
|
||||
sale_location
|
||||
FROM salvagedb.salvagedb
|
||||
WHERE vin = :vin
|
||||
ORDER BY sale_date DESC
|
||||
"""
|
||||
cur.execute(query, {"vin": vin})
|
||||
results = cur.fetchall()
|
||||
|
||||
# Преобразуем результаты в список словарей
|
||||
detailed_records = []
|
||||
for row in results:
|
||||
record = {
|
||||
'vin': row[0],
|
||||
'make': row[1],
|
||||
'model': row[2],
|
||||
'vehicle_year': row[3],
|
||||
'vehicle_type': row[4],
|
||||
'primary_damage': row[5],
|
||||
'secondary_damage': row[6],
|
||||
'sale_date': row[7],
|
||||
'odometer': row[8],
|
||||
'sale_title_state': row[9],
|
||||
'sale_title_type': row[10],
|
||||
'seller': row[11],
|
||||
'lot': row[12],
|
||||
'estimate_repair_cost': row[13],
|
||||
'actual_cash_value': row[14],
|
||||
'sale_country': row[15],
|
||||
'sale_location': row[16]
|
||||
}
|
||||
detailed_records.append(record)
|
||||
|
||||
return detailed_records
|
||||
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():
|
||||
|
||||
254
main.py
254
main.py
@ -34,6 +34,7 @@ dp = Dispatcher()
|
||||
|
||||
class VinStates(StatesGroup):
|
||||
waiting_for_vin = State()
|
||||
waiting_for_check_vin = State()
|
||||
|
||||
|
||||
# Command handler
|
||||
@ -79,6 +80,19 @@ async def decode_vin_callback(callback: CallbackQuery, state: FSMContext, db: Or
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@dp.callback_query(lambda c: c.data == "check_vin")
|
||||
async def check_vin_callback(callback: CallbackQuery, state: FSMContext, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
database = db or oracle_db
|
||||
|
||||
# Сохраняем данные пользователя при нажатии кнопки
|
||||
await database.save_user(callback.from_user, "check_vin_button")
|
||||
|
||||
await callback.message.answer("Please enter the vehicle VIN to check salvage records.")
|
||||
await state.set_state(VinStates.waiting_for_check_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
|
||||
@ -154,6 +168,129 @@ async def process_vin(message: Message, state: FSMContext, db: OracleDatabase =
|
||||
await message.answer("Invalid VIN. Please enter a valid 17-character VIN (letters and numbers, no I, O, Q).")
|
||||
|
||||
|
||||
@dp.message(VinStates.waiting_for_check_vin)
|
||||
async def process_check_vin(message: Message, state: FSMContext, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
database = db or oracle_db
|
||||
|
||||
# Сохраняем данные пользователя при обработке VIN
|
||||
await database.save_user(message.from_user, "check_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)
|
||||
|
||||
# Получаем количество записей в salvagedb.salvagedb
|
||||
salvage_count = await database.count_salvage_records(vin)
|
||||
|
||||
logging.info(f"Check VIN: make: {make}, model: {model}, year: {year}, cnt: {cnt}, salvage_count: {salvage_count}")
|
||||
|
||||
# Формируем текст ответа
|
||||
if cnt == 0:
|
||||
response_text = "❌ **Unable to decode VIN, possibly incorrect**\n\n"
|
||||
else:
|
||||
response_text = f"🚗 **{year} {make} {model}**\n\n"
|
||||
|
||||
response_text += f"📊 **Records found in database:** {salvage_count}\n\n"
|
||||
|
||||
# Создаем клавиатуру в зависимости от наличия записей
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
if salvage_count > 0:
|
||||
# Есть записи - показываем кнопки: Get detailed info, Pay 10⭐️, Try another VIN, Back to main menu
|
||||
builder.button(text="Get detailed info", callback_data=f"get_detailed_info:{vin}")
|
||||
builder.button(text="Pay 10 ⭐️", callback_data=f"pay_check_detailed:{vin}", pay=True)
|
||||
builder.button(text="Try another VIN", callback_data="check_vin")
|
||||
builder.button(text="Back to Main Menu", callback_data="main_menu")
|
||||
builder.adjust(1, 1, 1, 1) # Each button on separate row
|
||||
else:
|
||||
# Нет записей - показываем кнопки: Try another VIN, Back to main menu
|
||||
response_text += "ℹ️ **No salvage records found for this VIN**"
|
||||
builder.button(text="Try another VIN", callback_data="check_vin")
|
||||
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 check 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).")
|
||||
|
||||
|
||||
@dp.callback_query(lambda c: c.data and c.data.startswith("get_detailed_info:"))
|
||||
async def get_detailed_info_callback(callback: CallbackQuery, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
database = db or oracle_db
|
||||
|
||||
# Сохраняем данные пользователя
|
||||
await database.save_user(callback.from_user, "get_detailed_info_button")
|
||||
|
||||
# Извлекаем VIN из callback data
|
||||
vin = callback.data.split(":")[1]
|
||||
|
||||
try:
|
||||
# Получаем детальную информацию из таблицы salvagedb.salvagedb
|
||||
salvage_count = await database.count_salvage_records(vin)
|
||||
|
||||
if salvage_count > 0:
|
||||
response_text = f"🔍 **Detailed Salvage Information for VIN:** {vin}\n\n"
|
||||
response_text += f"📊 **Total salvage records found:** {salvage_count}\n\n"
|
||||
response_text += "💡 **This vehicle has salvage records in our database.**\n"
|
||||
response_text += "For complete detailed analysis including damage history, "
|
||||
response_text += "accident reports, and comprehensive vehicle information, "
|
||||
response_text += "please use our paid detailed report service.\n\n"
|
||||
response_text += "💰 **Price:** 10 ⭐️ (Telegram Stars)"
|
||||
else:
|
||||
response_text = f"✅ **Good news!** No salvage records found for VIN: {vin}\n\n"
|
||||
response_text += "This vehicle appears to have no salvage history in our database."
|
||||
|
||||
# Создаем клавиатуру
|
||||
builder = InlineKeyboardBuilder()
|
||||
if salvage_count > 0:
|
||||
builder.button(text="Pay 10 ⭐️ for Full Report", callback_data=f"pay_check_detailed:{vin}", pay=True)
|
||||
builder.button(text="Try another VIN", callback_data="check_vin")
|
||||
builder.button(text="Back to Main Menu", callback_data="main_menu")
|
||||
builder.adjust(1, 1, 1) if salvage_count > 0 else builder.adjust(1, 1)
|
||||
|
||||
await callback.message.answer(response_text, reply_markup=builder.as_markup(), parse_mode="Markdown")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error getting detailed info for VIN {vin}: {e}")
|
||||
await callback.message.answer("Error retrieving detailed information. Please try again later.")
|
||||
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@dp.callback_query(lambda c: c.data and c.data.startswith("pay_check_detailed:"))
|
||||
async def pay_check_detailed_callback(callback: CallbackQuery, db: OracleDatabase = None):
|
||||
# Используем переданный db или глобальный oracle_db
|
||||
database = db or oracle_db
|
||||
|
||||
# Сохраняем данные пользователя при инициации платежа
|
||||
await database.save_user(callback.from_user, "check_payment_initiation")
|
||||
|
||||
# Извлекаем VIN из callback data
|
||||
vin = callback.data.split(":")[1]
|
||||
prices = [LabeledPrice(label="Detailed Salvage Report", amount=10)]
|
||||
logging.info(f"Sending invoice for salvage check VIN: {vin}")
|
||||
|
||||
await callback.bot.send_invoice(
|
||||
chat_id=callback.message.chat.id,
|
||||
title="Detailed Salvage Report",
|
||||
description="Get comprehensive salvage history and damage information for 10 Telegram Stars",
|
||||
payload=f"detailed_salvage_check:{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
|
||||
@ -213,10 +350,13 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None
|
||||
|
||||
# Сохраняем данные о платеже пользователя
|
||||
await database.save_user(message.from_user, "successful_payment")
|
||||
await database.update_user_payment(message.from_user.id, 1.0) # 1 Telegram Star
|
||||
|
||||
payload = message.successful_payment.invoice_payload
|
||||
|
||||
# Определяем сумму платежа в зависимости от типа
|
||||
payment_amount = 10.0 if payload.startswith("detailed_salvage_check:") else 1.0
|
||||
await database.update_user_payment(message.from_user.id, payment_amount)
|
||||
|
||||
if payload.startswith("detailed_vin_info:"):
|
||||
vin = payload.split(":")[1]
|
||||
|
||||
@ -374,6 +514,118 @@ 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("detailed_salvage_check:"):
|
||||
vin = payload.split(":")[1]
|
||||
|
||||
try:
|
||||
# Получаем детальную информацию о salvage записях
|
||||
salvage_records = await database.fetch_salvage_detailed_info(vin)
|
||||
|
||||
if salvage_records:
|
||||
# Получаем базовую информацию о VIN для заголовка
|
||||
make, model, year, cnt = await database.fetch_vin_info(vin)
|
||||
|
||||
report = f"🚗 **{year} {make} {model}**\n"
|
||||
report += f"📋 **VIN:** {vin}\n\n"
|
||||
report += f"🔍 **DETAILED SALVAGE HISTORY REPORT**\n"
|
||||
report += f"📊 **Total Records Found:** {len(salvage_records)}\n\n"
|
||||
|
||||
# Добавляем информацию по каждой записи
|
||||
for idx, record in enumerate(salvage_records[:5], 1): # Показываем максимум 5 записей
|
||||
report += f"📋 **Record #{idx}**\n"
|
||||
|
||||
if record['sale_date']:
|
||||
report += f"📅 **Sale Date:** {record['sale_date']}\n"
|
||||
|
||||
if record['primary_damage']:
|
||||
report += f"⚠️ **Primary Damage:** {record['primary_damage']}\n"
|
||||
|
||||
if record['secondary_damage']:
|
||||
report += f"⚠️ **Secondary Damage:** {record['secondary_damage']}\n"
|
||||
|
||||
if record['vehicle_type']:
|
||||
report += f"🚙 **Vehicle Type:** {record['vehicle_type']}\n"
|
||||
|
||||
if record['odometer']:
|
||||
report += f"🛣️ **Odometer:** {record['odometer']:,} miles\n"
|
||||
|
||||
if record['sale_title_state']:
|
||||
report += f"📍 **Title State:** {record['sale_title_state']}\n"
|
||||
|
||||
if record['sale_title_type']:
|
||||
report += f"📄 **Title Type:** {record['sale_title_type']}\n"
|
||||
|
||||
if record['seller']:
|
||||
report += f"🏢 **Seller:** {record['seller']}\n"
|
||||
|
||||
if record['estimate_repair_cost']:
|
||||
report += f"💰 **Estimated Repair Cost:** ${record['estimate_repair_cost']:,}\n"
|
||||
|
||||
if record['actual_cash_value']:
|
||||
report += f"💵 **Actual Cash Value:** ${record['actual_cash_value']:,}\n"
|
||||
|
||||
if record['sale_location']:
|
||||
report += f"📍 **Sale Location:** {record['sale_location']}\n"
|
||||
|
||||
report += "\n"
|
||||
|
||||
if len(salvage_records) > 5:
|
||||
report += f"📋 **... and {len(salvage_records) - 5} more records**\n\n"
|
||||
|
||||
report += "---\n"
|
||||
report += f"💰 **Transaction ID:** {message.successful_payment.telegram_payment_charge_id}\n"
|
||||
report += "⚠️ **This report shows salvage/damage history. Please consult with automotive experts for vehicle evaluation.**"
|
||||
|
||||
# Создаем клавиатуру
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="Try another VIN", callback_data="check_vin")
|
||||
builder.button(text="Back to Main Menu", callback_data="main_menu")
|
||||
builder.adjust(2)
|
||||
|
||||
await message.answer(report, reply_markup=builder.as_markup(), 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 salvage records found for this VIN in our database.\n"
|
||||
"💰 Your payment has been automatically refunded.\n"
|
||||
"This is actually good news - no salvage history found!"
|
||||
)
|
||||
logging.info(f"Refund successful for user {message.from_user.id} - no salvage data 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 salvage records 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 salvage 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 salvage 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 salvage 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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user