Froud
This commit is contained in:
16
bot/operations/froud_notify.py
Normal file
16
bot/operations/froud_notify.py
Normal file
@@ -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)
|
||||||
@@ -3,7 +3,7 @@ from asgiref.sync import sync_to_async
|
|||||||
from hotels.models import Hotel, UserHotel
|
from hotels.models import Hotel, UserHotel
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from pms_integration.manager import PMSIntegrationManager
|
from pms_integration.manager import PMSIntegrationManager
|
||||||
|
from bot.utils.froud_check import detect_fraud
|
||||||
async def manage_hotels(update: Update, context):
|
async def manage_hotels(update: Update, context):
|
||||||
"""Отображение списка отелей, связанных с пользователем."""
|
"""Отображение списка отелей, связанных с пользователем."""
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
@@ -45,6 +45,7 @@ async def hotel_actions(update: Update, context):
|
|||||||
|
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[InlineKeyboardButton("🗑️ Удалить отель", callback_data=f"delete_hotel_{hotel_id}")],
|
[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("🔗 Проверить интеграцию с PMS", callback_data=f"check_pms_{hotel_id}")],
|
||||||
[InlineKeyboardButton("🛏️ Настроить номера", callback_data=f"setup_rooms_{hotel_id}")],
|
[InlineKeyboardButton("🛏️ Настроить номера", callback_data=f"setup_rooms_{hotel_id}")],
|
||||||
[InlineKeyboardButton("🏠 Главная", callback_data="main_menu")],
|
[InlineKeyboardButton("🏠 Главная", callback_data="main_menu")],
|
||||||
@@ -53,6 +54,11 @@ async def hotel_actions(update: Update, context):
|
|||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
await query.edit_message_text(f"Управление отелем: {hotel.name}", reply_markup=reply_markup)
|
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):
|
async def delete_hotel(update: Update, context):
|
||||||
"""Удаление отеля."""
|
"""Удаление отеля."""
|
||||||
|
|||||||
54
bot/utils/froud_check.py
Normal file
54
bot/utils/froud_check.py
Normal file
@@ -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-систему провалилась."
|
||||||
|
)
|
||||||
@@ -6,7 +6,8 @@ from .models import (
|
|||||||
APIConfiguration,
|
APIConfiguration,
|
||||||
APIRequestLog,
|
APIRequestLog,
|
||||||
Reservation,
|
Reservation,
|
||||||
Guest
|
Guest,
|
||||||
|
FraudLog
|
||||||
)
|
)
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
@@ -53,6 +54,12 @@ class HotelAdmin(admin.ModelAdmin):
|
|||||||
self.message_user(request, f"Ошибка: {str(e)}", level="error")
|
self.message_user(request, f"Ошибка: {str(e)}", level="error")
|
||||||
return redirect("..")
|
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)
|
@admin.register(UserHotel)
|
||||||
class UserHotelAdmin(admin.ModelAdmin):
|
class UserHotelAdmin(admin.ModelAdmin):
|
||||||
|
|||||||
@@ -117,3 +117,14 @@ class Guest(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Гость"
|
verbose_name = "Гость"
|
||||||
verbose_name_plural = "Гости"
|
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})"
|
||||||
Reference in New Issue
Block a user