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
440 lines
15 KiB
Markdown
440 lines
15 KiB
Markdown
# Система автоматического подтверждения и повторного розыгрыша
|
||
|
||
## 🎯 Обзор системы
|
||
|
||
Реализована полная система автоматического подтверждения выигрышей с возможностью повторного розыгрыша для неподтвержденных призов.
|
||
|
||
---
|
||
|
||
## 🔄 Как это работает
|
||
|
||
### 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` для ручного подтверждения
|