Files
new_lottery_bot/docs/ACCOUNT_BASED_CONFIRMATION.md
Andrew K. Choi 388c4e8aad
All checks were successful
continuous-integration/drone/push Build is passing
Пересборка клавиатур, рефакторинг чата
2026-02-13 20:03:44 +09:00

278 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# Подтверждение выигрышей по счетам
## 🎯 Концепция
Система подтверждения выигрышей работает **на уровне счетов**, а не пользователей.
### Основные принципы:
1. **Один пользователь = Много счетов**
- У клиента может быть несколько счетов (11-22-33..., 44-55-66..., и т.д.)
- Каждый счет участвует в розыгрыше независимо
2. **Один счет = Один выигрыш = Одно подтверждение**
- Если счет `11-22-33-44-55-66-77` выиграл 1 место - требуется подтверждение
- Если счет `44-55-66-77-88-99-00` выиграл 3 место - требуется отдельное подтверждение
- Даже если оба счета принадлежат одному клиенту
3. **Независимое подтверждение**
- Каждый выигрышный счет подтверждается отдельной кнопкой
- Подтверждение одного счета не влияет на другие
- У каждого счета свой 24-часовой лимит
## 📱 Как это работает для пользователя
### Сценарий: У клиента 3 счета, выиграли 2
**Счета клиента:**
- `11-22-33-44-55-66-77` ✅ Выиграл 1 место (iPhone 15)
- `22-33-44-55-66-77-88`Не выиграл
- `33-44-55-66-77-88-99` ✅ Выиграл 3 место (AirPods Pro)
**Клиент получает 2 сообщения:**
### Сообщение 1:
```
🎉 Поздравляем! Ваш счет выиграл!
🎯 Розыгрыш: Новогодний розыгрыш
🏆 Место: 1
🎁 Приз: iPhone 15
💳 Выигрышный счет: 11-22-33-44-55-66-77
У вас есть 24 часа для подтверждения!
Нажмите кнопку ниже, чтобы подтвердить получение приза по этому счету.
Если вы не подтвердите в течение 24 часов, приз будет разыгран заново.
Если у вас несколько выигрышных счетов, подтвердите каждый из них отдельно.
[✅ Подтвердить счет 11-22-33-44-55-66-77]
[📞 Связаться с администратором]
```
### Сообщение 2:
```
🎉 Поздравляем! Ваш счет выиграл!
🎯 Розыгрыш: Новогодний розыгрыш
🏆 Место: 3
🎁 Приз: AirPods Pro
💳 Выигрышный счет: 33-44-55-66-77-88-99
У вас есть 24 часа для подтверждения!
[✅ Подтвердить счет 33-44-55-66-77-88-99]
[📞 Связаться с администратором]
```
### Действия клиента:
1. **Нажимает первую кнопку** → Счет `11-22-33-44-55-66-77` подтвержден ✅
2. **Нажимает вторую кнопку** → Счет `33-44-55-66-77-88-99` подтвержден ✅
## 🔒 Безопасность
### Проверка владения счетом
При нажатии кнопки подтверждения система проверяет:
```python
# Получаем владельца КОНКРЕТНОГО счета
owner = await AccountService.get_account_owner(session, winner.account_number)
# Проверяем что текущий пользователь - владелец ЭТОГО счета
if not owner or owner.telegram_id != callback.from_user.id:
await callback.answer(
f"❌ Счет {winner.account_number} вам не принадлежит",
show_alert=True
)
return
```
### Что НЕ может сделать пользователь:
❌ Подтвердить чужой счет
❌ Подтвердить один счет дважды
### Что может сделать пользователь:
✅ Подтвердить каждый свой выигрышный счет отдельно
✅ Видеть номер счета на каждой кнопке
## 🎊 После подтверждения
### Сообщение пользователю:
```
✅ Выигрыш успешно подтвержден!
🎯 Розыгрыш: Новогодний розыгрыш
🏆 Место: 1
🎁 Приз: iPhone 15
💳 Счет: 11-22-33-44-55-66-77
🎊 Поздравляем! Администратор свяжется с вами
для передачи приза в ближайшее время.
Спасибо за участие!
```
### Уведомление администратору:
```
✅ Победитель подтвердил получение приза!
🎯 Розыгрыш: Новогодний розыгрыш
🏆 Место: 1
🎁 Приз: iPhone 15
💳 Подтвержденный счет: 11-22-33-44-55-66-77
👤 Владелец: Иван Петров (@ivan)
🎫 Клубная карта: 2223
📱 Телефон: +7 900 123-45-67
```
## 📊 База данных
### Таблица `winners`
Каждая запись = один выигрышный счет:
```sql
id | lottery_id | account_number | place | prize | is_claimed | claimed_at
---|------------|-----------------------|-------|------------|------------|------------------
1 | 5 | 11-22-33-44-55-66-77 | 1 | iPhone 15 | TRUE | 2025-11-16 14:00
2 | 5 | 33-44-55-66-77-88-99 | 3 | AirPods | TRUE | 2025-11-16 14:05
3 | 5 | 55-66-77-88-99-00-11 | 2 | MacBook | FALSE | NULL
```
### Ключевые поля:
- `account_number` - конкретный выигрышный счет
- `is_claimed` - подтвержден ли ЭТОТ счет
- `claimed_at` - когда ЭТОТ счет был подтвержден
## 🔄 Повторный розыгрыш
Если счет не подтвержден в течение 24 часов:
1. **Админ проверяет**: `/check_unclaimed 5`
```
⚠️ Неподтвержденные выигрыши:
🏆 2 место - MacBook
💳 55-66-77-88-99-00-11
⏰ Прошло: 26 часов
```
2. **Админ переигрывает**: `/redraw 5`
- Удаляется Winner с `account_number = 55-66-77-88-99-00-11`
- Выбирается новый случайный счет
- Новому владельцу счета отправляется уведомление
- Новый владелец получает свои 24 часа
## 💡 Преимущества подхода
### ✅ Для пользователей:
1. **Понятность** - видят конкретный номер счета на кнопке
2. **Контроль** - могут подтверждать счета независимо
3. **Гибкость** - один счет подтвердил, другой нет (если забыл)
### ✅ Для администраторов:
1. **Точность** - знают какой именно счет подтвержден
2. **Прозрачность** - видят все действия по каждому счету
3. **Справедливость** - переиграть можно конкретный неподтвержденный счет
### ✅ Для системы:
1. **Масштабируемость** - неограниченное количество счетов у одного пользователя
2. **Независимость** - каждый счет живет своей жизнью
3. **Целостность** - нет конфликтов между разными выигрышами
## 🔍 Примеры использования
### Пример 1: Один пользователь, два выигрыша
```
Клиент: Иван Петров (КК: 2223)
Счета:
- 11-22-33-44-55-66-77 → Выиграл 1 место ✅ Подтвержден
- 22-33-44-55-66-77-88 → Выиграл 3 место ✅ Подтвержден
Результат: Иван получит 2 приза
```
### Пример 2: Частичное подтверждение
```
Клиент: Мария Сидорова (КК: 3334)
Счета:
- 33-44-55-66-77-88-99 → Выиграл 2 место ✅ Подтвержден
- 44-55-66-77-88-99-00 → Выиграл 4 место ❌ Не подтвержден (> 24ч)
Результат:
- Мария получит приз за 2 место
- 4 место будет переиграно
```
### Пример 3: Полная неявка
```
Клиент: Петр Иванов (КК: 5556)
Счета:
- 55-66-77-88-99-00-11 → Выиграл 1 место ❌ Не подтвержден
- 66-77-88-99-00-11-22 → Выиграл 2 место ❌ Не подтвержден
Результат: Оба места будут переиграны отдельно
```
## 📝 Технические детали
### Callback данные
```python
# Формат: confirm_win_{winner_id}
callback_data = f"confirm_win_{winner.id}"
# winner.id - уникальный ID записи в таблице winners
# Каждый счет-выигрыш имеет свой winner_id
```
### Проверка при подтверждении
```python
# 1. Получаем winner по ID
winner = await session.get(Winner, winner_id)
# 2. Проверяем что счет принадлежит пользователю
owner = await AccountService.get_account_owner(session, winner.account_number)
if owner.telegram_id != current_user_id:
return "Не ваш счет"
# 3. Подтверждаем ЭТОТ счет
winner.is_claimed = True
winner.claimed_at = datetime.now(timezone.utc)
await session.commit()
```
## 🎓 Выводы
Подход "счет = выигрыш" обеспечивает:
- 🎯 **Точность** - подтверждается конкретный счет, а не абстрактный выигрыш
- 🔒 **Безопасность** - только владелец счета может подтвердить
- 📊 **Масштабируемость** - неограниченное количество счетов и выигрышей
- 👥 **Справедливость** - каждый счет обрабатывается независимо
- 💡 **Прозрачность** - всегда понятно какой именно счет подтверждается
---
## 📞 См. также
- `AUTO_CONFIRM_SYSTEM.md` - Полная документация системы подтверждения
- `REGISTRATION_SYSTEM.md` - Система регистрации счетов
- `ADMIN_GUIDE.md` - Руководство администратора