Fix account enrollment and operator callback flows with Redis scenarios
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2026-09-14 21:01:56 +09:00
parent f3f8d0f737
commit a9af9cb010
17 changed files with 678 additions and 167 deletions

View File

@@ -40,7 +40,9 @@
- Перед проведением проверьте «По розыгрышам» / «Отчёт»: состав, количество участников, отсутствие ошибочно добавленных счетов.
- Ошибочное участие удаляйте через «Удалить» либо соответствующую массовую операцию до проведения розыгрыша. Повторное добавление того же счёта в один розыгрыш не создаёт второй билет.
Бот поддерживает участие по пользователю и по счёту. Используйте способ, соответствующий опубликованным правилам. Счёт может участвовать без связанного профиля; в этом случае автоматическое личное уведомление владельцу невозможно до установления связи.
Для быстрого добавления отправьте в личный диалог `КАРТА СЧЁТ`, например `0007 11-22-33-44-55-66-77`, затем «Добавить в розыгрыш» и нужный розыгрыш. Если карта известна боту, новый счёт будет привязан к клиенту одновременно с добавлением участия. Ведущие нули карты сохраняются. Если счёт уже принадлежит другому клиенту или деактивирован, бот откажет в добавлении. Повторное добавление покажет пропуск без создания второго билета.
Бот поддерживает участие по пользователю и по счёту. Используйте способ, соответствующий опубликованным правилам. Счёт без указания карты может участвовать без связанного профиля; в этом случае автоматическое личное уведомление владельцу невозможно до установления связи.
## Проведение и выдача призов

View File

@@ -38,6 +38,8 @@
3. За один ввод допускается до 1000 распознанных счетов.
4. Проверьте количества «Добавлено», «Пропущено» и ошибки. Повтор того же счёта в том же розыгрыше не создаёт второго участия.
Чтобы сразу привязать новый счёт клиенту, отправьте строку `КАРТА СЧЁТ`, например `0007 11-22-33-44-55-66-77`. Карта должна быть известна боту. Создание счёта и добавление участия сохраняются вместе. Чужой или неактивный счёт нельзя перепривязать таким вводом; исправьте данные или обратитесь к администратору.
Если розыгрыш уже проведён или закрыт, бот отклонит добавление. Если активных розыгрышей нет, обратитесь к администратору. Кассир не может открыть или создать розыгрыш.
Счёт без привязки к клиенту тоже может быть добавлен. Чтобы клиент получил личное уведомление и мог подтвердить выигрыш по коду, сначала проверьте привязку счёта к его зарегистрированному профилю.

View File

@@ -0,0 +1,29 @@
# Проверка операций со счетами и сценариев бота — 14 сентября 2026
## Что подтвердилось на сервере
Проверен контейнер `lottery_bot`, исходная версия `f3f8d0f`, деплой №93. Контейнер работал, healthcheck проходил, автоматических перезапусков не было. При этом отдельные действия завершались исключениями: состояние контейнера само по себе не проверяет функциональность меню.
В логах за сутки найдены `DetachedInstanceError` при добавлении счетов и `ValueError` при выборе «Участники по розыгрышам». Проверка базы во время диагностики показала отсутствие записей счетов и участий с номерами счетов. Поэтому проверены обе причины пропуска: новый счёт с известной картой и повтор уже добавленного счёта. Точный исходный текст клиента в предоставленных логах отсутствует.
## Исправления
- При отклонённой операции `rollback()` инвалидировал загруженные ORM-объекты. Итоговый ответ обращался к `lottery.title` после закрытия сессии. Теперь необходимые значения сохраняются до операции; аналогичные обращения исправлены в одиночных и массовых операциях по пользователям.
- Быстрый ввод `КАРТА СЧЁТ` не создавал отсутствующий счёт, хотя предварительный экран находил владельца карты. Теперь известная карта позволяет создать счёт и участие одной транзакцией. Уникальность счёта защищает работу кассиров в разных розыгрышах; владелец существующего счёта не меняется.
- Широкие фильтры кнопок перехватывали отчёты, подтверждения переигровки и удаления, редактирование победителя. Фильтры теперь проверяют полный формат и допустимый числовой ID. Нераспознанная кнопка получает понятный ответ.
- Удалённые розыгрыши и истёкшие данные диалога обрабатываются без `NoneType` и `IndexError`.
- Добавление и удаление счёта из детального меню используют общие транзакционные проверки открытого розыгрыша и владельца.
- Экраны победителей поддерживают участие без Telegram-профиля. При ручном назначении по счёту сохраняется именно выбранный билет; один счёт нельзя назначить на разные призовые места.
- Имена, названия с символами HTML и длинные списки не ломают ответы в проверенных операциях со счетами. Длинные отчёты разделяются, кнопки остаются на последней странице. Завершённый диалог очищается до отправки итогового отчёта.
## Как воспроизводятся сценарии
`tests/test_operator_scenarios.py` отправляет сообщения и нажатия через настоящий `main.dp.feed_update`. Используются отдельная база и синтетические Telegram ID. Вместо сети транспорт сохраняет вызовы API и проверяет длину текста, структуру HTML и callback-data. Ошибки, перехваченные middleware, также приводят к падению теста.
Проверяются: быстрый ввод нового и повторного счёта, команда добавления, массовое добавление, касса, просмотр клиентом своих счетов, проведение розыгрыша и выдача приза, конкурирующие кассиры, создание одного счёта в разных розыгрышах, чужая карта, ручные победители, удалённые объекты, старые и некорректные кнопки, отчёты и длинные списки.
Полный набор дополнительно проверяет регистрацию, премиум-эмодзи, роли сотрудников, недоступных получателей, таймауты отправки, фоновые рассылки, повторную выдачу, миграции и ограничения базы.
В Drone тесты выполняются на SQLite и отдельно на PostgreSQL 16 с Redis 7. Для PostgreSQL-прогона `TEST_REDIS_URL` включает настоящий Redis FSM и блокировки диалогов. Тестовая очистка ограничена пространством синтетического бота `fsm:123456:*`.
Эмуляция не создаёт настоящих розыгрышей и не отправляет сообщения клиентам. Она не заменяет проверку интерфейса приложением Telegram. После CI требуется отдельно проверить установленную версию, healthcheck, heartbeat, Telegram API и новые ошибки контейнера.