diff --git a/db.py b/db.py index a569dc1..6fb74ff 100644 --- a/db.py +++ b/db.py @@ -404,3 +404,71 @@ class OracleDatabase: return result[0] if result else 0 import asyncio return await asyncio.to_thread(_query) + + async def save_payment_log(self, user: User, service_type: str, vin: str, payment_data: dict, service_result: dict = None) -> bool: + """ + Логирует операцию оплаты с полной информацией о пользователе, услуге и результате + + Args: + user: Объект пользователя Telegram + service_type: Тип услуги ('decode_vin', 'check_salvage', 'get_photos') + vin: VIN номер автомобиля + payment_data: Данные о платеже (сумма, transaction_id, статус) + service_result: Результат предоставления услуги (количество данных, статус) + """ + def _save_log(): + with self._pool.acquire() as conn: + with conn.cursor() as cur: + insert_query = """ + INSERT INTO payment_logs ( + log_id, user_id, user_first_name, user_last_name, user_username, + user_language_code, user_is_premium, service_type, vin_number, + payment_amount, transaction_id, payment_status, payment_currency, + service_status, data_found_count, refund_status, refund_reason, + vehicle_make, vehicle_model, vehicle_year, error_message, + created_date, ip_address + ) VALUES ( + payment_logs_seq.NEXTVAL, :user_id, :user_first_name, :user_last_name, :user_username, + :user_language_code, :user_is_premium, :service_type, :vin_number, + :payment_amount, :transaction_id, :payment_status, :payment_currency, + :service_status, :data_found_count, :refund_status, :refund_reason, + :vehicle_make, :vehicle_model, :vehicle_year, :error_message, + SYSDATE, :ip_address + ) + """ + + params = { + "user_id": user.id, + "user_first_name": user.first_name, + "user_last_name": user.last_name, + "user_username": user.username, + "user_language_code": user.language_code, + "user_is_premium": 1 if user.is_premium else 0, + "service_type": service_type, + "vin_number": vin, + "payment_amount": payment_data.get('amount', 0), + "transaction_id": payment_data.get('transaction_id'), + "payment_status": payment_data.get('status', 'completed'), + "payment_currency": payment_data.get('currency', 'XTR'), + "service_status": service_result.get('status', 'success') if service_result else 'pending', + "data_found_count": service_result.get('data_count', 0) if service_result else 0, + "refund_status": payment_data.get('refund_status', 'no_refund'), + "refund_reason": payment_data.get('refund_reason'), + "vehicle_make": service_result.get('vehicle_make') if service_result else None, + "vehicle_model": service_result.get('vehicle_model') if service_result else None, + "vehicle_year": service_result.get('vehicle_year') if service_result else None, + "error_message": service_result.get('error') if service_result else None, + "ip_address": None # Telegram не предоставляет IP адреса + } + + cur.execute(insert_query, params) + conn.commit() + return True + + try: + import asyncio + loop = asyncio.get_event_loop() + return await loop.run_in_executor(None, _save_log) + except Exception as e: + print(f"Error saving payment log for user {user.id}: {e}") + return False diff --git a/main.py b/main.py index b86c41c..83fdc16 100644 --- a/main.py +++ b/main.py @@ -785,6 +785,15 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None await database.update_user_payment(message.from_user.id, payment_amount) + # Подготавливаем базовые данные платежа для логирования + payment_data = { + 'amount': payment_amount, + 'transaction_id': message.successful_payment.telegram_payment_charge_id, + 'status': 'completed', + 'currency': 'XTR', + 'refund_status': 'no_refund' + } + if payload.startswith("detailed_vin_info:"): vin = payload.split(":")[1] @@ -911,6 +920,17 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None await message.answer(plain_report, reply_markup=builder.as_markup()) logging.info("Plain text message sent successfully!") + # Логируем успешную операцию DecodeVin + service_result = { + 'status': 'success', + 'data_count': len(detailed_info['all_params']), + 'vehicle_make': params.get('make', 'N/A'), + 'vehicle_model': params.get('model', 'N/A'), + 'vehicle_year': params.get('model_year', 'N/A') + } + await database.save_payment_log(message.from_user, "decode_vin", vin, payment_data, service_result) + logging.info(f"Payment logged successfully for DecodeVin service - User: {message.from_user.id}, VIN: {vin}") + # Проверяем, является ли пользователь администратором и возвращаем звезды if message.from_user.id == ADMIN_USER_ID: try: @@ -918,6 +938,7 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None user_id=message.from_user.id, telegram_payment_charge_id=message.successful_payment.telegram_payment_charge_id ) + payment_data['refund_status'] = 'admin_refund' await message.answer( "🔧 **Admin Refund**\n\n" f"💰 Payment automatically refunded for admin user.\n" @@ -936,6 +957,16 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None ) else: # No detailed information found - refund the payment + service_result = { + 'status': 'no_data', + 'data_count': 0, + 'error': 'No detailed information found for VIN' + } + payment_data['refund_status'] = 'auto_refund' + payment_data['refund_reason'] = 'No detailed information found' + await database.save_payment_log(message.from_user, "decode_vin", vin, payment_data, service_result) + logging.info(f"Payment logged for DecodeVin no data case - User: {message.from_user.id}, VIN: {vin}") + try: await message.bot.refund_star_payment( user_id=message.from_user.id, @@ -954,10 +985,20 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None "⚠️ 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 detailed VIN info for {vin}: {e}") + # Логируем ошибку + service_result = { + 'status': 'error', + 'data_count': 0, + 'error': str(e) + } + payment_data['refund_status'] = 'auto_refund' + payment_data['refund_reason'] = 'Service error' + await database.save_payment_log(message.from_user, "decode_vin", vin, payment_data, service_result) + logging.info(f"Payment logged for DecodeVin error case - User: {message.from_user.id}, VIN: {vin}") + # Attempt to refund the payment due to service error try: await message.bot.refund_star_payment( @@ -1092,6 +1133,17 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None await message.answer(plain_report, reply_markup=builder.as_markup()) logging.info("Plain text message sent successfully!") + # Логируем успешную операцию CheckSalvage + service_result = { + 'status': 'success', + 'data_count': len(salvage_records), + 'vehicle_make': make, + 'vehicle_model': model, + 'vehicle_year': year + } + await database.save_payment_log(message.from_user, "check_salvage", vin, payment_data, service_result) + logging.info(f"Payment logged successfully for CheckSalvage service - User: {message.from_user.id}, VIN: {vin}") + # Отправляем отдельное сообщение о фотографиях if salvage_records and salvage_records[0]['img_count'] > 0: img_count = salvage_records[0]['img_count'] @@ -1109,6 +1161,7 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None user_id=message.from_user.id, telegram_payment_charge_id=message.successful_payment.telegram_payment_charge_id ) + payment_data['refund_status'] = 'admin_refund' await message.answer( "🔧 **Admin Refund**\n\n" f"💰 Payment automatically refunded for admin user.\n" @@ -1127,6 +1180,16 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None ) else: # Нет записей - возвращаем деньги + service_result = { + 'status': 'no_data', + 'data_count': 0, + 'error': 'No salvage records found for VIN' + } + payment_data['refund_status'] = 'auto_refund' + payment_data['refund_reason'] = 'No salvage records found' + await database.save_payment_log(message.from_user, "check_salvage", vin, payment_data, service_result) + logging.info(f"Payment logged for CheckSalvage no data case - User: {message.from_user.id}, VIN: {vin}") + try: await message.bot.refund_star_payment( user_id=message.from_user.id, @@ -1149,6 +1212,17 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None except Exception as e: logging.error(f"Error getting salvage info for {vin}: {e}") + # Логируем ошибку + service_result = { + 'status': 'error', + 'data_count': 0, + 'error': str(e) + } + payment_data['refund_status'] = 'auto_refund' + payment_data['refund_reason'] = 'Service error' + await database.save_payment_log(message.from_user, "check_salvage", vin, payment_data, service_result) + logging.info(f"Payment logged for CheckSalvage error case - User: {message.from_user.id}, VIN: {vin}") + # Возвращаем деньги при ошибке try: await message.bot.refund_star_payment( @@ -1215,12 +1289,32 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None # Отправляем фотографии await send_vehicle_photos(message, vin, full_photo_paths, make, model, year) + + # Логируем успешную операцию GetPhotos + service_result = { + 'status': 'success', + 'data_count': len(full_photo_paths), + 'vehicle_make': make, + 'vehicle_model': model, + 'vehicle_year': year + } + await database.save_payment_log(message.from_user, "get_photos", vin, payment_data, service_result) + logging.info(f"Payment logged successfully for GetPhotos service - User: {message.from_user.id}, VIN: {vin}") 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}") + + # Логируем проблему с путями к фотографиям + service_result = { + 'status': 'error', + 'data_count': 0, + 'error': 'Photo paths not found despite photo count > 0' + } + await database.save_payment_log(message.from_user, "get_photos", vin, payment_data, service_result) + logging.info(f"Payment logged for GetPhotos path error case - User: {message.from_user.id}, VIN: {vin}") except Exception as markdown_error: logging.error(f"Markdown parsing failed for photos payment: {markdown_error}") @@ -1240,12 +1334,32 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None # Отправляем фотографии await send_vehicle_photos(message, vin, full_photo_paths, make, model, year) + + # Логируем успешную операцию GetPhotos (fallback) + service_result = { + 'status': 'success', + 'data_count': len(full_photo_paths), + 'vehicle_make': make, + 'vehicle_model': model, + 'vehicle_year': year + } + await database.save_payment_log(message.from_user, "get_photos", vin, payment_data, service_result) + logging.info(f"Payment logged successfully for GetPhotos service (fallback) - User: {message.from_user.id}, VIN: {vin}") 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)") + + # Логируем проблему с путями к фотографиям (fallback) + service_result = { + 'status': 'error', + 'data_count': 0, + 'error': 'Photo paths not found despite photo count > 0 (fallback)' + } + await database.save_payment_log(message.from_user, "get_photos", vin, payment_data, service_result) + logging.info(f"Payment logged for GetPhotos fallback path error case - User: {message.from_user.id}, VIN: {vin}") # Проверяем, является ли пользователь администратором и возвращаем звезды if message.from_user.id == ADMIN_USER_ID: @@ -1254,6 +1368,7 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None user_id=message.from_user.id, telegram_payment_charge_id=message.successful_payment.telegram_payment_charge_id ) + payment_data['refund_status'] = 'admin_refund' await message.answer( "🔧 **Admin Refund**\n\n" f"💰 Payment automatically refunded for admin user.\n" @@ -1272,6 +1387,16 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None ) else: # Нет фотографий - возвращаем деньги + service_result = { + 'status': 'no_data', + 'data_count': 0, + 'error': 'No photos found for VIN' + } + payment_data['refund_status'] = 'auto_refund' + payment_data['refund_reason'] = 'No photos found' + await database.save_payment_log(message.from_user, "get_photos", vin, payment_data, service_result) + logging.info(f"Payment logged for GetPhotos no data case - User: {message.from_user.id}, VIN: {vin}") + try: await message.bot.refund_star_payment( user_id=message.from_user.id, @@ -1294,6 +1419,17 @@ async def successful_payment_handler(message: Message, db: OracleDatabase = None except Exception as e: logging.error(f"Error getting photos info for {vin}: {e}") + # Логируем ошибку + service_result = { + 'status': 'error', + 'data_count': 0, + 'error': str(e) + } + payment_data['refund_status'] = 'auto_refund' + payment_data['refund_reason'] = 'Service error' + await database.save_payment_log(message.from_user, "get_photos", vin, payment_data, service_result) + logging.info(f"Payment logged for GetPhotos error case - User: {message.from_user.id}, VIN: {vin}") + # Возвращаем деньги при ошибке try: await message.bot.refund_star_payment(