From 7889117d6ec8251758246efcbe8db936e206e6a0 Mon Sep 17 00:00:00 2001 From: trevor Date: Mon, 9 Dec 2024 17:42:23 +0900 Subject: [PATCH] Froud --- bot/operations/froud_notify.py | 16 ++++++++++ bot/operations/hotels.py | 10 +++++-- bot/utils/froud_check.py | 54 ++++++++++++++++++++++++++++++++++ hotels/admin.py | 11 +++++-- hotels/models.py | 13 +++++++- 5 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 bot/operations/froud_notify.py create mode 100644 bot/utils/froud_check.py diff --git a/bot/operations/froud_notify.py b/bot/operations/froud_notify.py new file mode 100644 index 00000000..20ae2eb0 --- /dev/null +++ b/bot/operations/froud_notify.py @@ -0,0 +1,16 @@ +from telegram import Bot + +async def notify_fraud(hotel, fraud_logs): + """ + Уведомляет о FRAUD-действиях через Telegram. + :param hotel: Отель, для которого обнаружены FRAUD-действия. + :param fraud_logs: Список записей о FRAUD. + """ + bot = Bot(token="TELEGRAM_BOT_TOKEN") + admin_chat_id = "ADMIN_CHAT_ID" + + message = f"🚨 FRAUD обнаружен для отеля {hotel.name}:\n" + for log in fraud_logs: + message += f"- Гость: {log.guest_name}, Дата заезда: {log.check_in_date}\n" + + await bot.send_message(chat_id=admin_chat_id, text=message) diff --git a/bot/operations/hotels.py b/bot/operations/hotels.py index d0bc4b6e..cb0c8bd3 100644 --- a/bot/operations/hotels.py +++ b/bot/operations/hotels.py @@ -3,7 +3,7 @@ from asgiref.sync import sync_to_async from hotels.models import Hotel, UserHotel from users.models import User from pms_integration.manager import PMSIntegrationManager - +from bot.utils.froud_check import detect_fraud async def manage_hotels(update: Update, context): """Отображение списка отелей, связанных с пользователем.""" query = update.callback_query @@ -45,6 +45,7 @@ async def hotel_actions(update: Update, context): keyboard = [ [InlineKeyboardButton("🗑️ Удалить отель", callback_data=f"delete_hotel_{hotel_id}")], + [InlineKeyboardButton("Проверить на FRAUD", callback_data=f"check_fraud_{hotel_id}")], [InlineKeyboardButton("🔗 Проверить интеграцию с PMS", callback_data=f"check_pms_{hotel_id}")], [InlineKeyboardButton("🛏️ Настроить номера", callback_data=f"setup_rooms_{hotel_id}")], [InlineKeyboardButton("🏠 Главная", callback_data="main_menu")], @@ -53,7 +54,12 @@ async def hotel_actions(update: Update, context): reply_markup = InlineKeyboardMarkup(keyboard) await query.edit_message_text(f"Управление отелем: {hotel.name}", reply_markup=reply_markup) - +async def handle_fraud_check(update, context): + query = update.callback_query + hotel_id = int(query.data.split("_")[2]) + await detect_fraud(hotel_id) + await query.edit_message_text("Проверка на FRAUD завершена. Администратор уведомлен.") + async def delete_hotel(update: Update, context): """Удаление отеля.""" query = update.callback_query diff --git a/bot/utils/froud_check.py b/bot/utils/froud_check.py new file mode 100644 index 00000000..b6bf4b0d --- /dev/null +++ b/bot/utils/froud_check.py @@ -0,0 +1,54 @@ +from asgiref.sync import sync_to_async +from django.db import connections +from datetime import datetime, timedelta +from hotels.models import Reservation, Hotel, FraudLog + + +async def detect_fraud(hotel_id, period="day"): + """ + Сравнивает данные из PMS и QR базы для обнаружения FRAUD-действий. + :param hotel_id: ID отеля для анализа. + :param period: Период времени для анализа (day, week, month). + """ + now = datetime.now() + if period == "day": + start_date = now - timedelta(days=1) + elif period == "week": + start_date = now - timedelta(weeks=1) + elif period == "month": + start_date = now - timedelta(days=30) + else: + start_date = None + + end_date = now + + # Данные из PMS + reservations = await sync_to_async(list)( + Reservation.objects.filter( + hotel_id=hotel_id, + check_in__date__range=(start_date, end_date) + ) + ) + + # Данные из QR-системы + qr_checkins = [] + with connections['wordpress'].cursor() as cursor: + cursor.execute( + "SELECT reservation_id, guest_name, check_in_date FROM qr_checkins WHERE check_in_date BETWEEN %s AND %s", + [start_date, end_date] + ) + qr_checkins = cursor.fetchall() + + qr_checkins_set = {row[0] for row in qr_checkins} # Множество reservation_id + + # Сравнение данных + for res in reservations: + if res.id not in qr_checkins_set: + # Записываем FRAUD + await sync_to_async(FraudLog.objects.create)( + hotel_id=hotel_id, + reservation_id=res.id, + guest_name=res.guest_name, + check_in_date=res.check_in.date(), + message="Проверка на QR-систему провалилась." + ) diff --git a/hotels/admin.py b/hotels/admin.py index a4192bcb..300dfbb6 100644 --- a/hotels/admin.py +++ b/hotels/admin.py @@ -6,7 +6,8 @@ from .models import ( APIConfiguration, APIRequestLog, Reservation, - Guest + Guest, + FraudLog ) from django.urls import path from django.shortcuts import redirect @@ -53,7 +54,13 @@ class HotelAdmin(admin.ModelAdmin): self.message_user(request, f"Ошибка: {str(e)}", level="error") return redirect("..") - +@admin.register(FraudLog) +class FroudAdmin(admin.ModelAdmin): + list_display = ('hotel', 'reservation_id', 'guest_name', 'check_in_date', 'detected_at', 'message') + search_fields = ('hotel__name', 'reservation_id', 'guest_name', 'check_in_date', 'message') + list_filter = ('hotel', 'check_in_date', 'detected_at') + ordering = ('-detected_at',) + @admin.register(UserHotel) class UserHotelAdmin(admin.ModelAdmin): list_display = ('user', 'hotel') diff --git a/hotels/models.py b/hotels/models.py index 3a9af67a..9dc4ffc0 100644 --- a/hotels/models.py +++ b/hotels/models.py @@ -116,4 +116,15 @@ class Guest(models.Model): class Meta: verbose_name = "Гость" - verbose_name_plural = "Гости" \ No newline at end of file + verbose_name_plural = "Гости" + +class FraudLog(models.Model): + hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name="frauds") + reservation_id = models.CharField(max_length=255) + guest_name = models.CharField(max_length=255, null=True, blank=True) + check_in_date = models.DateField() + detected_at = models.DateTimeField(auto_now_add=True) + message = models.TextField() + + def __str__(self): + return f"FRAUD: {self.guest_name} ({self.check_in_date})" \ No newline at end of file