Use PostgreSQL-compatible winner menu queries
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-09-14 21:09:36 +09:00
parent a9af9cb010
commit 9b19b82caf
3 changed files with 6 additions and 6 deletions

View File

@@ -11,6 +11,7 @@
- При отклонённой операции `rollback()` инвалидировал загруженные ORM-объекты. Итоговый ответ обращался к `lottery.title` после закрытия сессии. Теперь необходимые значения сохраняются до операции; аналогичные обращения исправлены в одиночных и массовых операциях по пользователям. - При отклонённой операции `rollback()` инвалидировал загруженные ORM-объекты. Итоговый ответ обращался к `lottery.title` после закрытия сессии. Теперь необходимые значения сохраняются до операции; аналогичные обращения исправлены в одиночных и массовых операциях по пользователям.
- Быстрый ввод `КАРТА СЧЁТ` не создавал отсутствующий счёт, хотя предварительный экран находил владельца карты. Теперь известная карта позволяет создать счёт и участие одной транзакцией. Уникальность счёта защищает работу кассиров в разных розыгрышах; владелец существующего счёта не меняется. - Быстрый ввод `КАРТА СЧЁТ` не создавал отсутствующий счёт, хотя предварительный экран находил владельца карты. Теперь известная карта позволяет создать счёт и участие одной транзакцией. Уникальность счёта защищает работу кассиров в разных розыгрышах; владелец существующего счёта не меняется.
- Широкие фильтры кнопок перехватывали отчёты, подтверждения переигровки и удаления, редактирование победителя. Фильтры теперь проверяют полный формат и допустимый числовой ID. Нераспознанная кнопка получает понятный ответ. - Широкие фильтры кнопок перехватывали отчёты, подтверждения переигровки и удаления, редактирование победителя. Фильтры теперь проверяют полный формат и допустимый числовой ID. Нераспознанная кнопка получает понятный ответ.
- PostgreSQL-прогон выявил несовместимость `SELECT DISTINCT` по розыгрышам с JSON-полями. Меню редактирования и удаления победителей используют `EXISTS`: розыгрыш выводится один раз без сравнения JSON.
- Удалённые розыгрыши и истёкшие данные диалога обрабатываются без `NoneType` и `IndexError`. - Удалённые розыгрыши и истёкшие данные диалога обрабатываются без `NoneType` и `IndexError`.
- Добавление и удаление счёта из детального меню используют общие транзакционные проверки открытого розыгрыша и владельца. - Добавление и удаление счёта из детального меню используют общие транзакционные проверки открытого розыгрыша и владельца.
- Экраны победителей поддерживают участие без Telegram-профиля. При ручном назначении по счёту сохраняется именно выбранный билет; один счёт нельзя назначить на разные призовые места. - Экраны победителей поддерживают участие без Telegram-профиля. При ручном назначении по счёту сохраняется именно выбранный билет; один счёт нельзя назначить на разные призовые места.

View File

@@ -3069,8 +3069,7 @@ async def edit_winner_start(callback: CallbackQuery):
from sqlalchemy import select from sqlalchemy import select
result = await session.execute( result = await session.execute(
select(Lottery) select(Lottery)
.join(Winner) .where(select(Winner.id).where(Winner.lottery_id == Lottery.id).exists())
.distinct()
.order_by(Lottery.created_at.desc()) .order_by(Lottery.created_at.desc())
.limit(20) .limit(20)
) )
@@ -3196,8 +3195,7 @@ async def remove_winner_start(callback: CallbackQuery):
from sqlalchemy import select from sqlalchemy import select
result = await session.execute( result = await session.execute(
select(Lottery) select(Lottery)
.join(Winner) .where(select(Winner.id).where(Winner.lottery_id == Lottery.id).exists())
.distinct()
.order_by(Lottery.created_at.desc()) .order_by(Lottery.created_at.desc())
.limit(20) .limit(20)
) )

View File

@@ -119,7 +119,7 @@ async def test_duplicate_account_reports_and_finishes_dialog(route, caplog):
@pytest.mark.parametrize("callback", [ @pytest.mark.parametrize("callback", [
"admin_participants_by_lottery", "admin_participants_report", "admin_edit_winner", "admin_participants_by_lottery", "admin_participants_report", "admin_edit_winner", "admin_remove_winner",
"admin_edit_winner_lottery_{id}", "admin_edit_lottery_select_{id}", "admin_edit_winner_lottery_{id}", "admin_edit_lottery_select_{id}",
"admin_lottery_detail_{id}", "admin_participants_{id}", "admin_stats", "admin_lottery_detail_{id}", "admin_participants_{id}", "admin_stats",
"admin_list_all_participants", "admin_users_list:1", "admin_winners", "admin_list_all_participants", "admin_users_list:1", "admin_winners",
@@ -244,7 +244,8 @@ async def test_anonymous_winner_admin_pages(caplog):
session.add(winner) session.add(winner)
await session.commit() await session.commit()
winner_id = winner.id winner_id = winner.id
for callback in (f"admin_edit_winner_lottery_{lottery_id}", f"admin_edit_winner_id_{winner_id}", for callback in ("admin_edit_winner", "admin_remove_winner",
f"admin_edit_winner_lottery_{lottery_id}", f"admin_edit_winner_id_{winner_id}",
f"admin_remove_winner_lottery_{lottery_id}", f"admin_confirm_remove_winner_{winner_id}", f"admin_remove_winner_lottery_{lottery_id}", f"admin_confirm_remove_winner_{winner_id}",
f"admin_do_remove_winner_{winner_id}"): f"admin_do_remove_winner_{winner_id}"):
await send(callback=callback) await send(callback=callback)