feat: Система автоматического подтверждения выигрышей с поддержкой множественных счетов
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Основные изменения: ✨ Новые функции: - Система регистрации пользователей с множественными счетами - Автоматическое подтверждение выигрышей через 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
This commit is contained in:
439
docs/AUTO_CONFIRM_SYSTEM.md
Normal file
439
docs/AUTO_CONFIRM_SYSTEM.md
Normal file
@@ -0,0 +1,439 @@
|
||||
# Система автоматического подтверждения и повторного розыгрыша
|
||||
|
||||
## 🎯 Обзор системы
|
||||
|
||||
Реализована полная система автоматического подтверждения выигрышей с возможностью повторного розыгрыша для неподтвержденных призов.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Как это работает
|
||||
|
||||
### 1. Победитель получает уведомление
|
||||
|
||||
После проведения розыгрыша победителю автоматически отправляется сообщение с **интерактивной кнопкой**:
|
||||
|
||||
```
|
||||
🎉 Поздравляем! Ваш счет выиграл!
|
||||
|
||||
🎯 Розыгрыш: Новогодний розыгрыш
|
||||
🏆 Место: 1
|
||||
🎁 Приз: Главный приз
|
||||
💳 Счет: 11-22-33-44-55-66-77
|
||||
|
||||
⏰ У вас есть 24 часа для подтверждения!
|
||||
|
||||
Нажмите кнопку ниже, чтобы подтвердить получение приза.
|
||||
Если вы не подтвердите в течение 24 часов, приз будет разыгран заново.
|
||||
|
||||
[✅ Подтвердить получение приза]
|
||||
[📞 Связаться с администратором]
|
||||
```
|
||||
|
||||
### 2. Победитель подтверждает выигрыш
|
||||
|
||||
Пользователь нажимает кнопку "✅ Подтвердить получение приза":
|
||||
|
||||
**Что происходит:**
|
||||
- В БД устанавливается `is_claimed = True`
|
||||
- Сохраняется время подтверждения `claimed_at`
|
||||
- Победитель видит подтверждение:
|
||||
|
||||
```
|
||||
✅ Выигрыш успешно подтвержден!
|
||||
|
||||
🎯 Розыгрыш: Новогодний розыгрыш
|
||||
🏆 Место: 1
|
||||
🎁 Приз: Главный приз
|
||||
|
||||
🎊 Поздравляем! Администратор свяжется с вами
|
||||
для передачи приза в ближайшее время.
|
||||
|
||||
Спасибо за участие!
|
||||
```
|
||||
|
||||
**Администраторы получают уведомление:**
|
||||
|
||||
```
|
||||
✅ Победитель подтвердил получение приза!
|
||||
|
||||
🎯 Розыгрыш: Новогодний розыгрыш
|
||||
🏆 Место: 1
|
||||
🎁 Приз: Главный приз
|
||||
👤 Победитель: Иван (@ivan)
|
||||
🎫 Клубная карта: 2223
|
||||
📱 Телефон: +7 900 123-45-67
|
||||
💳 Счет: 11-22-33-44-55-66-77
|
||||
```
|
||||
|
||||
### 3. Если победитель не подтверждает (24 часа)
|
||||
|
||||
Администратор проверяет неподтвержденные выигрыши:
|
||||
|
||||
```
|
||||
/check_unclaimed 1
|
||||
```
|
||||
|
||||
**Ответ бота:**
|
||||
|
||||
```
|
||||
⚠️ Неподтвержденные выигрыши в розыгрыше 'Новогодний розыгрыш':
|
||||
|
||||
🏆 1 место - Главный приз
|
||||
👤 Иван (КК: 2223)
|
||||
💳 11-22-33-44-55-66-77
|
||||
⏰ Прошло: 26 часов
|
||||
|
||||
🏆 3 место - Третий приз
|
||||
👤 Петр (КК: 3334)
|
||||
💳 22-33-44-55-66-77-88
|
||||
⏰ Прошло: 30 часов
|
||||
|
||||
📊 Всего неподтвержденных: 2
|
||||
|
||||
Используйте /redraw 1 для повторного розыгрыша
|
||||
```
|
||||
|
||||
### 4. Повторный розыгрыш
|
||||
|
||||
Администратор запускает переигровку:
|
||||
|
||||
```
|
||||
/redraw 1
|
||||
```
|
||||
|
||||
**Что происходит:**
|
||||
|
||||
1. **Система находит неподтвержденные выигрыши** (старше 24 часов)
|
||||
2. **Получает пул участников** (исключая текущих победителей)
|
||||
3. **Случайно выбирает новых победителей** для каждого неподтвержденного места
|
||||
4. **Удаляет старых победителей** из БД
|
||||
5. **Создает новых победителей**
|
||||
6. **Отправляет уведомления** новым победителям (с кнопкой подтверждения)
|
||||
|
||||
**Результат для администратора:**
|
||||
|
||||
```
|
||||
🔄 Повторный розыгрыш завершен!
|
||||
|
||||
🎯 Розыгрыш: Новогодний розыгрыш
|
||||
📊 Переиграно мест: 2
|
||||
|
||||
🏆 1 место - Главный приз
|
||||
❌ Было: 11-22-33-44-55-66-77
|
||||
✅ Стало: 99-88-77-66-55-44-33
|
||||
|
||||
🏆 3 место - Третий приз
|
||||
❌ Было: 22-33-44-55-66-77-88
|
||||
✅ Стало: 12-34-56-78-90-12-34
|
||||
|
||||
📨 Новым победителям отправлены уведомления
|
||||
```
|
||||
|
||||
**Новые победители получают** то же уведомление с кнопкой подтверждения и 24-часовым лимитом.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Админские команды
|
||||
|
||||
### `/check_unclaimed <lottery_id>`
|
||||
|
||||
Проверить неподтвержденные выигрыши старше 24 часов.
|
||||
|
||||
**Пример:**
|
||||
```
|
||||
/check_unclaimed 1
|
||||
```
|
||||
|
||||
**Показывает:**
|
||||
- Список всех неподтвержденных выигрышей
|
||||
- Информацию о победителях
|
||||
- Сколько времени прошло с момента уведомления
|
||||
|
||||
### `/redraw <lottery_id>`
|
||||
|
||||
Переиграть розыгрыш для неподтвержденных выигрышей.
|
||||
|
||||
**Пример:**
|
||||
```
|
||||
/redraw 1
|
||||
```
|
||||
|
||||
**Требования:**
|
||||
- Должны быть неподтвержденные выигрыши старше 24 часов
|
||||
- Должны быть доступные участники (не победители)
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Изменения в базе данных
|
||||
|
||||
### Таблица `winners`
|
||||
|
||||
Добавлено новое поле:
|
||||
- `claimed_at` (TIMESTAMP) - время подтверждения выигрыша победителем
|
||||
|
||||
### Миграция
|
||||
|
||||
Файл: `migrations/versions/004_add_claimed_at.py`
|
||||
|
||||
Применить:
|
||||
```bash
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Технические детали
|
||||
|
||||
### Обработчик подтверждения
|
||||
|
||||
**Файл:** `main.py`
|
||||
|
||||
**Callback:** `confirm_win_{winner_id}`
|
||||
|
||||
**Функция:** `confirm_winner_response()`
|
||||
|
||||
**Логика:**
|
||||
1. Проверяет существование выигрыша
|
||||
2. Проверяет, что подтверждает владелец
|
||||
3. Устанавливает `is_claimed = True` и `claimed_at = now()`
|
||||
4. Обновляет сообщение победителя
|
||||
5. Уведомляет всех администраторов
|
||||
|
||||
### Система уведомлений
|
||||
|
||||
**Функция:** `notify_winners_async()`
|
||||
|
||||
**Изменения:**
|
||||
- Добавлена кнопка "✅ Подтвердить получение приза"
|
||||
- Добавлено предупреждение о 24-часовом лимите
|
||||
- Добавлена кнопка "📞 Связаться с администратором"
|
||||
|
||||
### Повторный розыгрыш
|
||||
|
||||
**Файл:** `src/handlers/redraw_handlers.py`
|
||||
|
||||
**Команды:**
|
||||
- `check_unclaimed_winners()` - проверка
|
||||
- `redraw_lottery()` - переигровка
|
||||
|
||||
**Алгоритм:**
|
||||
1. Получает всех победителей розыгрыша
|
||||
2. Фильтрует неподтвержденных (is_claimed=False, is_notified=True, >24ч)
|
||||
3. Получает пул участников (исключая победителей)
|
||||
4. Для каждого неподтвержденного:
|
||||
- Выбирает случайного участника
|
||||
- Удаляет старого победителя
|
||||
- Создает нового победителя
|
||||
- Отправляет уведомление
|
||||
|
||||
---
|
||||
|
||||
## 📊 Состояния выигрыша
|
||||
|
||||
### Таймлайн жизни выигрыша:
|
||||
|
||||
```
|
||||
1. Розыгрыш проведен
|
||||
├─ is_notified: False
|
||||
├─ is_claimed: False
|
||||
└─ claimed_at: NULL
|
||||
|
||||
2. Уведомление отправлено
|
||||
├─ is_notified: True
|
||||
├─ is_claimed: False
|
||||
└─ claimed_at: NULL
|
||||
|
||||
3А. Победитель подтвердил (успех)
|
||||
├─ is_notified: True
|
||||
├─ is_claimed: True
|
||||
└─ claimed_at: 2025-11-16 13:00:00
|
||||
|
||||
3Б. Прошло 24 часа (неудача)
|
||||
├─ is_notified: True
|
||||
├─ is_claimed: False
|
||||
├─ claimed_at: NULL
|
||||
└─ ⏰ time_passed > 24h → переигровка
|
||||
|
||||
4. После переигровки (новый победитель)
|
||||
├─ Старый победитель удален
|
||||
├─ Создан новый победитель
|
||||
├─ is_notified: True (после отправки)
|
||||
├─ is_claimed: False
|
||||
└─ claimed_at: NULL → снова 24 часа
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Важные моменты
|
||||
|
||||
### Безопасность
|
||||
|
||||
1. **Проверка владельца**: Только владелец счета может подтвердить выигрыш
|
||||
2. **Повторное подтверждение**: Если выигрыш уже подтвержден, показывается соответствующее сообщение
|
||||
3. **Права администратора**: Только админы могут запускать `/redraw`
|
||||
|
||||
### Ограничения
|
||||
|
||||
1. **24-часовой лимит**: Жестко закодирован, но легко изменить в коде
|
||||
2. **Пул участников**: Если все участники уже победители, переигровка невозможна
|
||||
3. **Уникальность**: Один счет не может выиграть дважды в одном розыгрыше
|
||||
|
||||
### Отказоустойчивость
|
||||
|
||||
1. **Уведомления**: Если не удается отправить - продолжает работу
|
||||
2. **Транзакции**: Все изменения в БД атомарны
|
||||
3. **Логирование**: Все действия записываются в лог
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Типичные сценарии
|
||||
|
||||
### Сценарий 1: Все подтвердили
|
||||
|
||||
```
|
||||
1. Розыгрыш → 3 победителя
|
||||
2. Все 3 нажали кнопку подтверждения
|
||||
3. Админ: /check_unclaimed 1
|
||||
→ "✅ Все победители подтвердили выигрыш"
|
||||
4. Приз передается всем победителям
|
||||
```
|
||||
|
||||
### Сценарий 2: Один не подтвердил
|
||||
|
||||
```
|
||||
1. Розыгрыш → 3 победителя
|
||||
2. 2 подтвердили, 1 игнорирует
|
||||
3. Через 25 часов админ: /check_unclaimed 1
|
||||
→ "⚠️ 1 неподтвержденный выигрыш"
|
||||
4. Админ: /redraw 1
|
||||
5. Система переигрывает 1 место
|
||||
6. Новый победитель получает уведомление
|
||||
7. У нового победителя снова 24 часа
|
||||
```
|
||||
|
||||
### Сценарий 3: Множественная переигровка
|
||||
|
||||
```
|
||||
1. Розыгрыш → 5 победителей
|
||||
2. 3 подтвердили, 2 игнорируют
|
||||
3. Через 25 часов: /redraw 1
|
||||
4. 2 новых победителя выбраны
|
||||
5. Один из новых тоже игнорирует
|
||||
6. Через 25 часов: /redraw 1 снова
|
||||
7. Выбран еще один новый победитель
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Статистика и мониторинг
|
||||
|
||||
### Проверка статуса
|
||||
|
||||
```
|
||||
/winner_status 1
|
||||
```
|
||||
|
||||
Покажет:
|
||||
- ✅ Подтвержденные выигрыши (с is_claimed=True)
|
||||
- ⏳ Ожидающие подтверждения (с is_claimed=False)
|
||||
- 📨 Статус уведомления (is_notified)
|
||||
|
||||
### SQL запросы для админа
|
||||
|
||||
**Найти все неподтвержденные старше 24 часов:**
|
||||
|
||||
```sql
|
||||
SELECT w.*, l.title
|
||||
FROM winners w
|
||||
JOIN lotteries l ON w.lottery_id = l.id
|
||||
WHERE w.is_notified = TRUE
|
||||
AND w.is_claimed = FALSE
|
||||
AND w.created_at < NOW() - INTERVAL '24 hours';
|
||||
```
|
||||
|
||||
**Статистика по подтверждениям:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
lottery_id,
|
||||
COUNT(*) as total_winners,
|
||||
SUM(CASE WHEN is_claimed THEN 1 ELSE 0 END) as confirmed,
|
||||
SUM(CASE WHEN NOT is_claimed THEN 1 ELSE 0 END) as unconfirmed
|
||||
FROM winners
|
||||
WHERE is_notified = TRUE
|
||||
GROUP BY lottery_id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Использование
|
||||
|
||||
### Для администратора
|
||||
|
||||
1. **После розыгрыша**: Ничего не делать - система отправит уведомления
|
||||
2. **Через 24-30 часов**: Проверить `/check_unclaimed <id>`
|
||||
3. **Если есть неподтвержденные**: Запустить `/redraw <id>`
|
||||
4. **Повторить** при необходимости
|
||||
|
||||
### Для победителя
|
||||
|
||||
1. **Получить уведомление** с кнопкой
|
||||
2. **Нажать "✅ Подтвердить"**
|
||||
3. **Дождаться связи с админом**
|
||||
4. **Получить приз**
|
||||
|
||||
---
|
||||
|
||||
## 💡 Рекомендации
|
||||
|
||||
### Оптимальные настройки
|
||||
|
||||
- **Лимит подтверждения**: 24 часа (можно увеличить до 48ч)
|
||||
- **Частота проверки**: 1-2 раза в день
|
||||
- **Уведомления**: Включить push-уведомления в боте
|
||||
|
||||
### Коммуникация с пользователями
|
||||
|
||||
После розыгрыша отправьте общее сообщение:
|
||||
|
||||
```
|
||||
🎉 Розыгрыш завершен!
|
||||
|
||||
Если вы выиграли, вам придет сообщение с кнопкой подтверждения.
|
||||
|
||||
⏰ У вас будет 24 часа чтобы подтвердить выигрыш!
|
||||
|
||||
Если не подтвердите - приз будет переигран.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔮 Возможные улучшения
|
||||
|
||||
1. **Напоминания**: Отправка напоминания за 2 часа до истечения срока
|
||||
2. **Гибкий лимит**: Разные лимиты для разных типов призов
|
||||
3. **История**: Логирование всех переигровок
|
||||
4. **Статистика**: Процент подтверждений, среднее время подтверждения
|
||||
5. **Автоматизация**: Cron-задача для автоматической переигровки
|
||||
|
||||
---
|
||||
|
||||
## ✅ Преимущества системы
|
||||
|
||||
- 🤖 **Полная автоматизация**: Минимум ручной работы для админа
|
||||
- ⏱️ **Справедливость**: Четкий дедлайн для всех
|
||||
- 🔄 **Эффективность**: Призы не "зависают" у неактивных победителей
|
||||
- 📊 **Прозрачность**: Полная история всех действий
|
||||
- 🛡️ **Безопасность**: Только владелец может подтвердить
|
||||
- 💬 **UX**: Простая кнопка вместо сложной верификации
|
||||
|
||||
---
|
||||
|
||||
## 📞 Поддержка
|
||||
|
||||
Если что-то пошло не так:
|
||||
|
||||
1. Проверьте логи бота
|
||||
2. Проверьте состояние БД (claimed_at, is_notified, is_claimed)
|
||||
3. Используйте `/winner_status <id>` для диагностики
|
||||
4. При критических ошибках - используйте `/verify_winner` для ручного подтверждения
|
||||
Reference in New Issue
Block a user