226 lines
10 KiB
Python
226 lines
10 KiB
Python
# Обработчики платежей
|
||
|
||
import logging
|
||
from aiogram import Router
|
||
from aiogram.types import Message, CallbackQuery, LabeledPrice, PreCheckoutQuery
|
||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||
|
||
from database import DatabaseManager
|
||
from config.settings import PRICES, BOT_TOKEN
|
||
from utils.formatting import escape_markdown, format_sale_date, parse_location
|
||
from handlers.vin_handlers import send_vehicle_photos
|
||
|
||
|
||
router = Router()
|
||
|
||
|
||
@router.callback_query(lambda c: c.data and c.data.startswith("pay_detailed_info:"))
|
||
async def pay_detailed_info_callback(callback: CallbackQuery, db: DatabaseManager = None):
|
||
"""Оплата детальной информации через платёжную форму"""
|
||
vin = callback.data.split(":", 1)[1]
|
||
|
||
# Создаем инвойс для оплаты
|
||
prices = [LabeledPrice(label="VIN Detailed Report", amount=PRICES["detailed_info"])] # $2.99 в копейках
|
||
|
||
await callback.message.answer_invoice(
|
||
title="VIN Detailed Report",
|
||
description=f"Comprehensive salvage report for VIN: {vin}",
|
||
payload=f"detailed_info:{vin}",
|
||
provider_token="", # Для Telegram Stars не нужен
|
||
currency="XTR", # Telegram Stars
|
||
prices=prices,
|
||
start_parameter="detailed_info"
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(lambda c: c.data and c.data.startswith("pay_check_detailed:"))
|
||
async def pay_check_detailed_callback(callback: CallbackQuery, db: DatabaseManager = None):
|
||
"""Оплата детального отчета через платёжную форму"""
|
||
vin = callback.data.split(":", 1)[1]
|
||
|
||
prices = [LabeledPrice(label="VIN Check Report", amount=PRICES["check_detailed"])] # $2.99
|
||
|
||
await callback.message.answer_invoice(
|
||
title="VIN Check - Detailed Report",
|
||
description=f"Complete salvage and auction history for VIN: {vin}",
|
||
payload=f"check_detailed:{vin}",
|
||
provider_token="",
|
||
currency="XTR",
|
||
prices=prices,
|
||
start_parameter="check_detailed"
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(lambda c: c.data and c.data.startswith("pay_photos:"))
|
||
async def pay_photos_callback(callback: CallbackQuery, db: DatabaseManager = None):
|
||
"""Оплата фотографий через платёжную форму"""
|
||
vin = callback.data.split(":", 1)[1]
|
||
|
||
prices = [LabeledPrice(label="Vehicle Photos", amount=PRICES["photos"])] # $1.99
|
||
|
||
await callback.message.answer_invoice(
|
||
title="Vehicle Photos",
|
||
description=f"High-quality auction photos for VIN: {vin}",
|
||
payload=f"photos:{vin}",
|
||
provider_token="",
|
||
currency="XTR",
|
||
prices=prices,
|
||
start_parameter="photos"
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.pre_checkout_query()
|
||
async def pre_checkout_handler(pre_checkout_query: PreCheckoutQuery, db: DatabaseManager = None):
|
||
"""Подтверждение предварительной проверки платежа"""
|
||
await pre_checkout_query.answer(ok=True)
|
||
|
||
|
||
@router.message(lambda message: message.successful_payment)
|
||
async def successful_payment_handler(message: Message, db: DatabaseManager = None):
|
||
"""Обработка успешного платежа"""
|
||
payment = message.successful_payment
|
||
payload_parts = payment.invoice_payload.split(":", 1)
|
||
|
||
if len(payload_parts) != 2:
|
||
logging.error(f"Invalid payment payload: {payment.invoice_payload}")
|
||
await message.answer("❌ **Payment Error**\n\nInvalid payment data. Please contact support.")
|
||
return
|
||
|
||
service_type, vin = payload_parts
|
||
user_id = message.from_user.id
|
||
amount = payment.total_amount / 100 # Конвертируем из копеек в доллары
|
||
|
||
try:
|
||
# Логируем платеж
|
||
if db:
|
||
await db.log_payment(user_id, vin, service_type, amount, payment.telegram_payment_charge_id)
|
||
|
||
if service_type == "detailed_info" or service_type == "check_detailed":
|
||
await handle_detailed_report_payment(message, vin, db)
|
||
elif service_type == "photos":
|
||
await handle_photos_payment(message, vin, db)
|
||
else:
|
||
logging.error(f"Unknown service type: {service_type}")
|
||
await message.answer("❌ **Payment Error**\n\nUnknown service type. Please contact support.")
|
||
|
||
except Exception as e:
|
||
logging.error(f"Error in successful_payment_handler: {e}")
|
||
await message.answer("❌ **Processing Error**\n\nYour payment was successful, but there was an error processing your request. Please contact support.")
|
||
|
||
|
||
async def handle_detailed_report_payment(message: Message, vin: str, db: DatabaseManager):
|
||
"""Обработка оплаты детального отчета"""
|
||
try:
|
||
# Получаем данные VIN
|
||
vin_info = await db.get_vin_info(vin)
|
||
if not vin_info:
|
||
await message.answer(f"❌ **Data Error**\n\nVIN `{escape_markdown(vin)}` not found in database.")
|
||
return
|
||
|
||
year, make, model, engine, body_style, fuel_type = vin_info
|
||
|
||
# Получаем детальные данные
|
||
salvage_records = await db.get_salvage_records(vin)
|
||
nhtsa_data = await db.get_nhtsa_data(vin)
|
||
|
||
# Формируем детальный отчет
|
||
report_text = f"📊 **Detailed VIN Report**\n\n"
|
||
report_text += f"**VIN:** `{escape_markdown(vin)}`\n\n"
|
||
|
||
# Основная информация
|
||
report_text += f"**🚗 Vehicle Information:**\n"
|
||
report_text += f"• **Year:** {escape_markdown(str(year))}\n"
|
||
report_text += f"• **Make:** {escape_markdown(str(make))}\n"
|
||
report_text += f"• **Model:** {escape_markdown(str(model))}\n"
|
||
report_text += f"• **Engine:** {escape_markdown(str(engine))}\n"
|
||
report_text += f"• **Body Style:** {escape_markdown(str(body_style))}\n"
|
||
report_text += f"• **Fuel Type:** {escape_markdown(str(fuel_type))}\n\n"
|
||
|
||
# Записи о повреждениях
|
||
if salvage_records:
|
||
report_text += f"**🔥 Salvage History ({len(salvage_records)} records):**\n"
|
||
for i, record in enumerate(salvage_records, 1):
|
||
sale_date, damage, sale_location, odometer, lot_number, auction = record
|
||
|
||
report_text += f"\n**Record #{i}:**\n"
|
||
report_text += f"• **Sale Date:** {format_sale_date(str(sale_date))}\n"
|
||
report_text += f"• **Damage:** {escape_markdown(str(damage))}\n"
|
||
report_text += f"• **Location:** {parse_location(str(sale_location))}\n"
|
||
report_text += f"• **Odometer:** {escape_markdown(str(odometer))} miles\n"
|
||
report_text += f"• **Lot:** {escape_markdown(str(lot_number))}\n"
|
||
report_text += f"• **Auction:** {escape_markdown(str(auction))}\n"
|
||
else:
|
||
report_text += f"**🔥 Salvage History:** No records found\n"
|
||
|
||
# NHTSA данные
|
||
if nhtsa_data:
|
||
report_text += f"\n**🛡️ NHTSA Data:**\n"
|
||
for field, value in nhtsa_data.items():
|
||
if value and str(value) != 'None':
|
||
report_text += f"• **{field}:** {escape_markdown(str(value))}\n"
|
||
|
||
# Создаем кнопки
|
||
builder = InlineKeyboardBuilder()
|
||
builder.button(text="📸 Get Photos ($1.99)", callback_data=f"pay_photos:{vin}")
|
||
builder.button(text="🔍 Check Another VIN", callback_data="check_vin")
|
||
builder.button(text="🏠 Main Menu", callback_data="main_menu")
|
||
builder.adjust(1)
|
||
|
||
# Отправляем отчет (может быть длинным, делим на части если нужно)
|
||
if len(report_text) > 4000:
|
||
# Разделяем на части
|
||
parts = [report_text[i:i+4000] for i in range(0, len(report_text), 4000)]
|
||
for i, part in enumerate(parts):
|
||
if i == len(parts) - 1: # Последняя часть с кнопками
|
||
await message.answer(part, reply_markup=builder.as_markup(), parse_mode="Markdown")
|
||
else:
|
||
await message.answer(part, parse_mode="Markdown")
|
||
else:
|
||
await message.answer(report_text, reply_markup=builder.as_markup(), parse_mode="Markdown")
|
||
|
||
logging.info(f"Detailed report sent for VIN {vin} to user {message.from_user.id}")
|
||
|
||
except Exception as e:
|
||
logging.error(f"Error in handle_detailed_report_payment: {e}")
|
||
await message.answer("❌ **Report Error**\n\nThere was an error generating your report. Please contact support.")
|
||
|
||
|
||
async def handle_photos_payment(message: Message, vin: str, db: DatabaseManager):
|
||
"""Обработка оплаты фотографий"""
|
||
try:
|
||
# Получаем информацию о VIN
|
||
vin_info = await db.get_vin_info(vin)
|
||
if not vin_info:
|
||
await message.answer(f"❌ **Data Error**\n\nVIN `{escape_markdown(vin)}` not found in database.")
|
||
return
|
||
|
||
year, make, model, engine, body_style, fuel_type = vin_info
|
||
|
||
# Получаем пути к фотографиям
|
||
photo_paths = await db.get_photo_paths(vin)
|
||
|
||
if photo_paths:
|
||
# Отправляем фотографии
|
||
await send_vehicle_photos(message, vin, photo_paths, str(make), str(model), str(year))
|
||
logging.info(f"Photos sent for VIN {vin} to user {message.from_user.id}")
|
||
else:
|
||
builder = InlineKeyboardBuilder()
|
||
builder.button(text="🚗 Get Detailed Report", callback_data=f"pay_check_detailed:{vin}")
|
||
builder.button(text="📸 Search Another VIN", callback_data="search_car_photo")
|
||
builder.button(text="🏠 Main Menu", callback_data="main_menu")
|
||
builder.adjust(1)
|
||
|
||
await message.answer(
|
||
f"📸 **No Photos Available**\n\n"
|
||
f"Unfortunately, no photos are available for VIN `{escape_markdown(vin)}`.\n\n"
|
||
f"Your payment has been processed. Please contact support if you believe this is an error.",
|
||
reply_markup=builder.as_markup(),
|
||
parse_mode="Markdown"
|
||
)
|
||
|
||
except Exception as e:
|
||
logging.error(f"Error in handle_photos_payment: {e}")
|
||
await message.answer("❌ **Photo Error**\n\nThere was an error retrieving your photos. Please contact support.") |