savagedb_bot/handlers/payment_handlers.py

226 lines
10 KiB
Python
Raw Permalink 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.

# Обработчики платежей
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.")