Files
new_lottery_bot/docs/ACCOUNT_BASED_CONFIRMATION.md
Andrew K. Choi 505d26f0e9
Some checks reported errors
continuous-integration/drone/push Build encountered an error
feat: Система автоматического подтверждения выигрышей с поддержкой множественных счетов
Основные изменения:

 Новые функции:
- Система регистрации пользователей с множественными счетами
- Автоматическое подтверждение выигрышей через inline-кнопки
- Механизм переигровки для неподтвержденных выигрышей (24 часа)
- Подтверждение на уровне счетов (каждый счет подтверждается отдельно)
- Скрипт полной очистки базы данных

🔧 Технические улучшения:
- Исправлена ошибка MissingGreenlet при lazy loading (добавлен joinedload/selectinload)
- Добавлено поле claimed_at для отслеживания времени подтверждения
- Пакетное добавление счетов с выбором розыгрыша
- Проверка владения конкретным счетом при подтверждении

📚 Документация:
- docs/AUTO_CONFIRM_SYSTEM.md - Полная документация системы подтверждения
- docs/ACCOUNT_BASED_CONFIRMATION.md - Подтверждение на уровне счетов
- docs/REGISTRATION_SYSTEM.md - Система регистрации
- docs/ADMIN_COMMANDS.md - Команды администратора
- docs/CLEAR_DATABASE.md - Очистка БД
- docs/QUICK_GUIDE.md - Быстрое начало
- docs/UPDATE_LOG.md - Журнал обновлений

🗄️ База данных:
- Миграция 003: Таблицы accounts, winner_verifications
- Миграция 004: Поле claimed_at в таблице winners
- Скрипт scripts/clear_database.py для полной очистки

🎮 Новые команды:
Админские:
- /check_unclaimed <lottery_id> - Проверка неподтвержденных выигрышей
- /redraw <lottery_id> - Повторный розыгрыш
- /add_accounts - Пакетное добавление счетов
- /list_accounts <telegram_id> - Список счетов пользователя

Пользовательские:
- /register - Регистрация с вводом данных
- /my_account - Просмотр своих счетов
- Callback confirm_win_{id} - Подтверждение выигрыша

🛠️ Makefile:
- make clear-db - Очистка всех данных из БД (с подтверждением)

🔒 Безопасность:
- Проверка владения счетом при подтверждении
- Защита от подтверждения чужих счетов
- Независимое подтверждение каждого выигрышного счета

📊 Логика работы:
1. Пользователь регистрируется и добавляет счета
2. Счета участвуют в розыгрыше
3. Победители получают уведомление с кнопкой подтверждения
4. Каждый счет подтверждается отдельно (24 часа на подтверждение)
5. Неподтвержденные выигрыши переигрываются через /redraw
2025-11-16 14:01:30 +09:00

280 lines
11 KiB
Markdown
Raw Permalink 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` - Руководство администратора