Files
DutyLog/src/dutylog/application/bot/admin_dialogs/rooms_management.py
T

851 lines
29 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
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.
import json
from aiogram import Bot
from aiogram.enums import ContentType
from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError, TelegramRetryAfter
from aiogram.types import Message, CallbackQuery, InputMediaPhoto
from aiogram_dialog import Window, DialogManager
from aiogram_dialog.widgets.text import Format, Const
from aiogram_dialog.widgets.kbd import SwitchTo, Button, ScrollingGroup, Select, Row, Group
from aiogram_dialog.widgets.input import MessageInput
from aiogram_dialog.widgets.media import DynamicMedia
from aiogram_dialog.api.entities.media import MediaAttachment, MediaId
from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject
from dutylog.application.bot.user_dialogs.states import AdminMenuSG
from dutylog.infrastructure.database.repositories.rooms_repository import (
RoomsRepository,
)
from dutylog.infrastructure.database.repositories.floors_repository import (
FloorsRepository,
)
from dutylog.infrastructure.database.repositories.residents_repository import (
ResidentsRepository,
)
from dutylog.infrastructure.database.repositories.hours_transactions_repository import (
HoursTransactionsRepository,
)
from dutylog.infrastructure.database.repositories.users_repository import (
UsersRepository,
)
from dutylog.infrastructure.utils.datetime import msk_now
async def on_rooms_click(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
):
await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor)
@inject
async def get_rooms_floors_data(
floors_repository: FromDishka[FloorsRepository],
**kwargs,
):
all_floors = await floors_repository.get_all_floors()
all_floors.sort(key=lambda f: f.number)
floors_data = [(f"🏢 Этаж {f.number}", f.id) for f in all_floors]
content = "<blockquote>🚪 <b>Комнаты</b></blockquote>\n\nВыберите этаж для просмотра комнат:"
return {
"content": content,
"floors": floors_data,
}
async def on_rooms_floor_selected(
callback: CallbackQuery,
widget: Select,
dialog_manager: DialogManager,
item_id: str,
):
dialog_manager.dialog_data["selected_floor_id"] = int(item_id)
await dialog_manager.switch_to(AdminMenuSG.rooms_list)
@inject
async def get_rooms_list_data(
dialog_manager: DialogManager,
rooms_repository: FromDishka[RoomsRepository],
floors_repository: FromDishka[FloorsRepository],
**kwargs,
):
floor_id = dialog_manager.dialog_data.get("selected_floor_id")
if not floor_id:
return {
"content": "Ошибка: этаж не выбран",
"rooms": [],
"floor_number": "???",
}
floor = await floors_repository.get_floor_by_id(floor_id)
floor_number = floor.number if floor else "???"
rooms = await rooms_repository.get_rooms_by_floor(floor_id)
rooms.sort(key=lambda r: r.number)
rooms_data = [(f"🚪 Комната {r.number}", r.id) for r in rooms]
content = f"<blockquote>🚪 <b>Комнаты на этаже {floor_number}</b></blockquote>\n\n<b>Всего комнат:</b> <code>{len(rooms)}</code>\n\nВыберите комнату для просмотра:"
return {
"content": content,
"rooms": rooms_data,
"floor_number": floor_number,
}
async def on_room_selected(
callback: CallbackQuery,
widget: Select,
dialog_manager: DialogManager,
item_id: str,
):
dialog_manager.dialog_data["selected_room_id"] = int(item_id)
await dialog_manager.switch_to(AdminMenuSG.room_info)
async def on_add_room_click(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
):
await dialog_manager.switch_to(AdminMenuSG.create_room_select_floor)
@inject
async def get_create_room_floors_data(
floors_repository: FromDishka[FloorsRepository],
**kwargs,
):
all_floors = await floors_repository.get_all_floors()
all_floors.sort(key=lambda f: f.number)
floors_data = [(f"🏢 Этаж {f.number}", f.id) for f in all_floors]
content = "<blockquote> <b>Создание комнаты</b></blockquote>\n\nВыберите этаж для новой комнаты:"
return {
"content": content,
"floors": floors_data,
}
async def on_create_room_floor_selected(
callback: CallbackQuery,
widget: Select,
dialog_manager: DialogManager,
item_id: str,
):
dialog_manager.dialog_data["new_room_floor_id"] = int(item_id)
await dialog_manager.switch_to(AdminMenuSG.create_room_input)
async def on_room_number_input(
message: Message,
widget: MessageInput,
dialog_manager: DialogManager,
):
if not message.text:
await message.answer("⚠️ Пожалуйста, введите номер комнаты")
return
try:
room_number = int(message.text)
if room_number <= 0:
await message.answer("⚠️ Номер комнаты должен быть положительным числом")
return
dialog_manager.dialog_data["new_room_number"] = room_number
await dialog_manager.switch_to(AdminMenuSG.create_room_confirm)
except ValueError:
await message.answer("⚠️ Пожалуйста, введите корректное число")
async def get_create_room_confirm_data(
dialog_manager: DialogManager,
**kwargs,
):
room_number = dialog_manager.dialog_data.get("new_room_number", "???")
return {"room_number": room_number}
@inject
async def on_create_room_confirm(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
rooms_repository: FromDishka[RoomsRepository],
):
room_number = dialog_manager.dialog_data.get("new_room_number")
floor_id = dialog_manager.dialog_data.get("new_room_floor_id")
if room_number and floor_id:
existing_room = await rooms_repository.get_room_by_number(room_number)
if existing_room:
await callback.answer(
f"⚠️ Комната {room_number} уже существует!",
show_alert=True
)
await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor)
return
await rooms_repository.create_room(room_number, floor_id)
await callback.answer("✅ Комната создана!")
await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor)
async def on_create_room_cancel(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
):
await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor)
@inject
async def get_room_info_data(
dialog_manager: DialogManager,
rooms_repository: FromDishka[RoomsRepository],
floors_repository: FromDishka[FloorsRepository],
residents_repository: FromDishka[ResidentsRepository],
**kwargs,
):
room_id = dialog_manager.dialog_data.get("selected_room_id")
if not room_id:
return {"info_content": "Ошибка: комната не выбрана"}
room = await rooms_repository.get_room_by_id(room_id)
if not room:
return {"info_content": "Ошибка: комната не найдена"}
floor = await floors_repository.get_floor_by_id(room.on_floor)
floor_number = floor.number if floor else "???"
residents = await residents_repository.get_residents_by_room(room_id)
total_active_hours = sum(r.active_hours for r in residents)
total_inactive_hours = sum(r.inactive_hours for r in residents)
residents_info = ""
if residents:
residents_info = "\n<b>Проживающие:</b>\n"
for resident in residents:
status = "🟢" if resident.is_busy else "⚪️"
name = resident.real_name if resident.real_name else "Без имени"
residents_info += f"{status} {name} (<code>{resident.active_hours}</code> ч)\n"
else:
residents_info = "\n<i>Нет проживающих</i>\n"
info_content = f"<blockquote>🚪 <b>Информация о комнате</b></blockquote>\n\n<b>Номер:</b> <code>{room.number}</code>\n<b>Этаж:</b> <code>{floor_number}</code>\n{residents_info}\n🟢 <b>Отработанные часы (всего):</b> <code>{total_inactive_hours}</code> ч\n🔴 <b>Неотработанные часы (всего):</b> <code>{total_active_hours}</code> ч"
return {
"info_content": info_content,
"has_residents": len(residents) > 0,
}
async def on_room_add_hours_click(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
):
await dialog_manager.switch_to(AdminMenuSG.room_add_hours_select)
async def get_room_hours_select_data(**kwargs):
hours_options = [
(5, "5"), (10, "10"), (15, "15"), (20, "20"),
(25, "25"), (30, "30"), (35, "35"), (40, "40"),
(45, "45"), (50, "50"), (55, "55"), (60, "60"),
(65, "65"), (70, "70"), (75, "75"), (80, "80"),
]
return {"hours_options": hours_options}
async def on_room_hours_selected(
callback: CallbackQuery,
widget: Select,
dialog_manager: DialogManager,
item_id: str,
):
dialog_manager.dialog_data["selected_hours"] = int(item_id)
await dialog_manager.switch_to(AdminMenuSG.room_add_hours_remark)
async def on_room_custom_hours_click(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
):
await dialog_manager.switch_to(AdminMenuSG.room_add_hours_custom)
async def on_room_custom_hours_input(
message: Message,
widget: MessageInput,
dialog_manager: DialogManager,
):
if not message.text:
await message.answer("⚠️ Пожалуйста, введите число")
return
try:
hours = int(message.text)
if hours <= 0:
await message.answer("⚠️ Количество часов должно быть положительным числом")
return
dialog_manager.dialog_data["selected_hours"] = hours
await dialog_manager.switch_to(AdminMenuSG.room_add_hours_remark)
except ValueError:
await message.answer("⚠️ Пожалуйста, введите корректное число")
async def on_room_remark_input(
message: Message,
widget: MessageInput,
dialog_manager: DialogManager,
):
album = dialog_manager.middleware_data.get("album")
photo_file_ids = []
remark = None
if album:
for msg in album:
if msg.photo:
photo_file_ids.append(msg.photo[-1].file_id)
if msg.caption and msg.caption.strip():
remark = msg.caption.strip()
elif message.photo:
photo_file_ids = [message.photo[-1].file_id]
remark = message.caption.strip() if message.caption and message.caption.strip() else None
elif message.text and message.text.strip():
remark = message.text.strip()
dialog_manager.dialog_data["remark"] = remark
dialog_manager.dialog_data["photo_file_ids"] = photo_file_ids
await dialog_manager.switch_to(AdminMenuSG.room_add_hours_confirm)
async def on_room_skip_remark(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
):
dialog_manager.dialog_data["remark"] = None
dialog_manager.dialog_data["photo_file_ids"] = []
await dialog_manager.switch_to(AdminMenuSG.room_add_hours_confirm)
async def get_room_hours_confirm_data(
dialog_manager: DialogManager,
**kwargs,
):
hours = dialog_manager.dialog_data.get("selected_hours", 0)
remark = dialog_manager.dialog_data.get("remark", "")
remark_text = f"\n\n<b>Примечание:</b> {remark}" if remark else ""
photo_file_ids = dialog_manager.dialog_data.get("photo_file_ids", [])
has_photo = bool(photo_file_ids)
return {
"hours": hours,
"remark_text": remark_text,
"has_photo": f"✅ Да ({len(photo_file_ids)} шт.)" if has_photo else "❌ Нет",
}
@inject
async def on_room_add_hours_confirm(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
transactions_repository: FromDishka[HoursTransactionsRepository],
residents_repository: FromDishka[ResidentsRepository],
users_repository: FromDishka[UsersRepository],
**kwargs,
):
bot: Bot = dialog_manager.middleware_data.get("bot")
room_id = dialog_manager.dialog_data.get("selected_room_id")
hours = dialog_manager.dialog_data.get("selected_hours")
remark = dialog_manager.dialog_data.get("remark")
admin_id = callback.from_user.id
if room_id and hours:
photo_file_ids = dialog_manager.dialog_data.get("photo_file_ids", [])
photo_file_id = json.dumps(photo_file_ids) if photo_file_ids else None
results = await transactions_repository.add_hours_to_room(
room_id=room_id,
amount=hours,
admin_id=admin_id,
is_active=True,
remark=remark,
photo_file_id=photo_file_id,
)
for transaction, resident in results:
if resident and resident.user_entity:
user = await users_repository.get_user_by_id(resident.user_entity)
if user:
try:
remark_text = f"\n💬 <i>{remark}</i>" if remark else ""
notification_text = f"<blockquote> <b>Уведомление</b></blockquote>\n\nВашей комнате начислено <b>+{hours}</b> ч{remark_text}"
if photo_file_ids:
if len(photo_file_ids) == 1:
await bot.send_photo(user.id, photo_file_ids[0], caption=notification_text)
else:
media = [InputMediaPhoto(media=fid, caption=notification_text if i == 0 else None) for i, fid in enumerate(photo_file_ids)]
await bot.send_media_group(user.id, media=media)
else:
await bot.send_message(user.id, notification_text)
except (TelegramBadRequest, TelegramForbiddenError, TelegramRetryAfter):
pass
await dialog_manager.switch_to(AdminMenuSG.room_info)
async def on_room_hours_cancel(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
):
await dialog_manager.switch_to(AdminMenuSG.room_info)
@inject
async def get_room_delete_confirm_data(
dialog_manager: DialogManager,
rooms_repository: FromDishka[RoomsRepository],
**kwargs,
):
room_id = dialog_manager.dialog_data.get("selected_room_id")
if not room_id:
return {"room_number": "???"}
room = await rooms_repository.get_room_by_id(room_id)
room_number = room.number if room else "???"
return {"room_number": room_number}
@inject
async def on_delete_room_confirm(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
rooms_repository: FromDishka[RoomsRepository],
):
room_id = dialog_manager.dialog_data.get("selected_room_id")
if room_id:
await rooms_repository.delete_room(room_id)
await callback.answer("✅ Комната удалена!")
await dialog_manager.switch_to(AdminMenuSG.rooms_list)
async def on_delete_room_cancel(
callback: CallbackQuery,
button: Button,
dialog_manager: DialogManager,
):
await dialog_manager.switch_to(AdminMenuSG.room_info)
@inject
async def get_room_history_data(
dialog_manager: DialogManager,
rooms_repository: FromDishka[RoomsRepository],
transactions_repository: FromDishka[HoursTransactionsRepository],
**kwargs,
):
room_id = dialog_manager.dialog_data.get("selected_room_id")
if not room_id:
return {"history_content": "Ошибка: комната не выбрана", "transactions": [], "has_transactions": False}
room = await rooms_repository.get_room_by_id(room_id)
if not room:
return {"history_content": "Ошибка: комната не найдена", "transactions": [], "has_transactions": False}
transactions = await transactions_repository.get_room_transactions(room_id)
last_10 = transactions[:10]
if not last_10:
history_text = f"<blockquote>📜 <b>История операций</b></blockquote>\n\n<b>Комната:</b> {room.number}\n\n<i>История операций пуста</i>"
else:
history_text = f"<blockquote>📜 <b>История операций</b></blockquote>\n\n<b>Комната:</b> {room.number}\n\n"
tx_items = []
for tx in last_10:
emoji = "+" if tx.transaction_type == "increase" else ""
msk_time = tx.created_at.astimezone(msk_now().tzinfo).replace(tzinfo=None)
date_str = msk_time.strftime("%d.%m.%Y %H:%M")
photo_mark = " 📷" if tx.photo_file_id else ""
label = f"{emoji}{tx.amount} ч | {date_str}{photo_mark}"
tx_items.append((label, str(tx.id)))
return {
"history_content": history_text,
"transactions": tx_items,
"has_transactions": len(tx_items) > 0,
}
@inject
async def on_room_transaction_selected(
callback: CallbackQuery,
widget: Select,
dialog_manager: DialogManager,
item_id: str,
transactions_repository: FromDishka[HoursTransactionsRepository],
users_repository: FromDishka[UsersRepository],
):
dialog_manager.dialog_data["selected_transaction_id"] = int(item_id)
tx = await transactions_repository.get_transaction_by_id(int(item_id))
if tx:
photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx)
if len(photo_file_ids) > 1:
operation = "Начислено" if tx.transaction_type == "increase" else "Списано"
emoji = "+" if tx.transaction_type == "increase" else ""
msk_time = tx.created_at.astimezone(msk_now().tzinfo).replace(tzinfo=None)
date_str = msk_time.strftime("%d.%m.%Y %H:%M")
remark_text = f"\n💬 <i>{tx.remark}</i>" if tx.remark else ""
admin_info = ""
if tx.admin_id:
admin = await users_repository.get_user_by_id(tx.admin_id)
if admin:
admin_name = f"@{admin.username}" if admin.username else admin.first_name or f"ID: {admin.id}"
admin_info = f"\n👨‍💼 <b>Администратор:</b> {admin_name}"
caption = f"📋 <b>Детали транзакции</b>\n\n⚙️ <b>Операция:</b> {operation}\n🔢 <b>Количество:</b> {emoji}<code>{tx.amount}</code> ч\n📅 <b>Дата:</b> {date_str}{remark_text}{admin_info}"
bot: Bot = dialog_manager.middleware_data.get("bot")
try:
media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)]
await bot.send_media_group(callback.message.chat.id, media=media)
except Exception:
pass
await dialog_manager.switch_to(AdminMenuSG.room_history_detail)
@inject
async def get_room_transaction_detail_data(
dialog_manager: DialogManager,
transactions_repository: FromDishka[HoursTransactionsRepository],
users_repository: FromDishka[UsersRepository],
**kwargs,
):
tx_id = dialog_manager.dialog_data.get("selected_transaction_id")
if not tx_id:
return {"detail_content": "Ошибка: транзакция не выбрана", "photo_media": None, "has_multiple_photos": False}
tx = await transactions_repository.get_transaction_by_id(int(tx_id))
if not tx:
return {"detail_content": "Ошибка: транзакция не найдена", "photo_media": None, "has_multiple_photos": False}
operation = "Начислено" if tx.transaction_type == "increase" else "Списано"
emoji = "+" if tx.transaction_type == "increase" else ""
msk_time = tx.created_at.astimezone(msk_now().tzinfo).replace(tzinfo=None)
date_str = msk_time.strftime("%d.%m.%Y %H:%M")
remark_text = f"\n💬 <i>{tx.remark}</i>" if tx.remark else ""
admin_info = ""
if tx.admin_id:
admin = await users_repository.get_user_by_id(tx.admin_id)
if admin:
admin_name = f"@{admin.username}" if admin.username else admin.first_name or f"ID: {admin.id}"
admin_info = f"\n👨‍💼 <b>Администратор:</b> {admin_name}"
content = f"""
<blockquote>📋 <b>Детали транзакции</b></blockquote>
⚙️ <b>Операция:</b> {operation}
🔢 <b>Количество:</b> {emoji}<code>{tx.amount}</code> ч
📅 <b>Дата:</b> {date_str}{remark_text}{admin_info}
"""
photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx)
photo_media = None
has_multiple_photos = len(photo_file_ids) > 1
if photo_file_ids and not has_multiple_photos:
photo_media = MediaAttachment(
type=ContentType.PHOTO,
file_id=MediaId(file_id=photo_file_ids[0]),
)
if has_multiple_photos:
detail_content = ""
else:
detail_content = content
return {
"detail_content": detail_content,
"photo_media": photo_media,
"has_multiple_photos": has_multiple_photos,
}
rooms_select_floor_window = Window(
Format("{content}"),
Group(
Select(
Format("{item[0]}"),
id="rooms_floors_select",
item_id_getter=lambda x: x[1],
items="floors",
on_click=on_rooms_floor_selected,
),
width=2,
),
Button(
Const(" Добавить комнату"),
id="add_room_btn",
on_click=on_add_room_click,
),
SwitchTo(
Const("◀️ Назад"),
id="back_to_admin_menu_from_rooms",
state=AdminMenuSG.main,
),
state=AdminMenuSG.rooms_select_floor,
getter=get_rooms_floors_data,
)
rooms_list_window = Window(
Format("{content}"),
ScrollingGroup(
Select(
Format("{item[0]}"),
id="rooms_select",
item_id_getter=lambda x: x[1],
items="rooms",
on_click=on_room_selected,
),
id="rooms_scroll",
width=1,
height=7,
),
SwitchTo(
Const("◀️ Назад к этажам"),
id="back_to_rooms_floors",
state=AdminMenuSG.rooms_select_floor,
),
state=AdminMenuSG.rooms_list,
getter=get_rooms_list_data,
)
room_info_window = Window(
Format("{info_content}"),
Button(
Const("Добавить часы"),
id="room_add_hours_btn",
on_click=on_room_add_hours_click,
),
Button(
Const("📜 История"),
id="room_history_btn",
on_click=lambda c, b, m: m.switch_to(AdminMenuSG.room_history),
),
Button(
Const("🗑 Удалить комнату"),
id="delete_room_btn",
on_click=lambda c, b, m: m.switch_to(AdminMenuSG.room_delete_confirm),
),
SwitchTo(
Const("◀️ Назад к списку"),
id="back_to_rooms_list",
state=AdminMenuSG.rooms_list,
),
state=AdminMenuSG.room_info,
getter=get_room_info_data,
)
room_delete_confirm_window = Window(
Format("<blockquote>⚠️ <b>Подтверждение удаления</b></blockquote>\n\nВы точно хотите удалить комнату <code>{room_number}</code>?\nЭто действие необратимо и удалит всех резидентов в этой комнате!"),
Row(
Button(
Const("✅ Да, удалить"),
id="confirm_delete_room",
on_click=on_delete_room_confirm,
),
Button(
Const("❌ Отмена"),
id="cancel_delete_room",
on_click=on_delete_room_cancel,
),
),
state=AdminMenuSG.room_delete_confirm,
getter=get_room_delete_confirm_data,
)
room_add_hours_select_window = Window(
Const("<blockquote> <b>Добавить часы комнате</b></blockquote>\n\nВыберите количество часов:"),
Group(
Select(
Format("{item[1]} ч"),
id="room_hours_select_add",
item_id_getter=lambda x: x[0],
items="hours_options",
on_click=on_room_hours_selected,
),
width=4,
),
Button(
Const("✏️ Ввести свое количество"),
id="room_custom_hours_add_btn",
on_click=on_room_custom_hours_click,
),
SwitchTo(
Const("◀️ Отмена"),
id="cancel_room_add_hours",
state=AdminMenuSG.room_info,
),
state=AdminMenuSG.room_add_hours_select,
getter=get_room_hours_select_data,
)
room_add_hours_custom_window = Window(
Const("<blockquote>✏️ <b>Добавить часы</b></blockquote>\n\nВведите количество часов:"),
MessageInput(on_room_custom_hours_input),
SwitchTo(
Const("◀️ Отмена"),
id="cancel_room_custom_add",
state=AdminMenuSG.room_add_hours_select,
),
state=AdminMenuSG.room_add_hours_custom,
)
room_add_hours_remark_window = Window(
Const("<blockquote>💬 <b>Примечание</b></blockquote>\n\nВведите примечание к операции или отправьте фото/медиагруппу с подписью (или пропустите):"),
MessageInput(on_room_remark_input),
Button(
Const("⏭ Пропустить"),
id="skip_room_add_remark",
on_click=on_room_skip_remark,
),
SwitchTo(
Const("◀️ Отмена"),
id="cancel_room_add_remark",
state=AdminMenuSG.room_info,
),
state=AdminMenuSG.room_add_hours_remark,
)
room_add_hours_confirm_window = Window(
Format("<blockquote> <b>Подтверждение</b></blockquote>\n\nВы уверены, что хотите добавить <code>{hours}</code> часов?{remark_text}\n\n📷 <b>Фото:</b> {has_photo}"),
Row(
Button(
Const("✅ Да"),
id="confirm_room_add_hours",
on_click=on_room_add_hours_confirm,
),
Button(
Const("❌ Нет"),
id="cancel_room_add_hours_confirm",
on_click=on_room_hours_cancel,
),
),
state=AdminMenuSG.room_add_hours_confirm,
getter=get_room_hours_confirm_data,
)
create_room_select_floor_window = Window(
Format("{content}"),
Group(
Select(
Format("{item[0]}"),
id="create_room_floors_select",
item_id_getter=lambda x: x[1],
items="floors",
on_click=on_create_room_floor_selected,
),
width=2,
),
SwitchTo(
Const("◀️ Отмена"),
id="cancel_create_room_floor",
state=AdminMenuSG.rooms_select_floor,
),
state=AdminMenuSG.create_room_select_floor,
getter=get_create_room_floors_data,
)
create_room_input_window = Window(
Const("<blockquote> <b>Создание комнаты</b></blockquote>\n\nВведите номер комнаты:"),
MessageInput(on_room_number_input),
SwitchTo(
Const("◀️ Назад"),
id="back_to_create_room_floor",
state=AdminMenuSG.create_room_select_floor,
),
state=AdminMenuSG.create_room_input,
)
create_room_confirm_window = Window(
Format("<blockquote>✅ <b>Подтверждение</b></blockquote>\n\nСоздать комнату <code>{room_number}</code>?"),
Row(
Button(
Const("✅ Да"),
id="confirm_create_room",
on_click=on_create_room_confirm,
),
Button(
Const("❌ Нет"),
id="cancel_create_room",
on_click=on_create_room_cancel,
),
),
state=AdminMenuSG.create_room_confirm,
getter=get_create_room_confirm_data,
)
room_history_window = Window(
Format("{history_content}"),
ScrollingGroup(
Select(
Format("{item[0]}"),
id="room_transactions_select",
item_id_getter=lambda x: x[1],
items="transactions",
on_click=on_room_transaction_selected,
),
id="room_transactions_scroll",
width=1,
height=8,
when="has_transactions",
),
SwitchTo(
Const("◀️ Назад"),
id="back_to_room_info",
state=AdminMenuSG.room_info,
),
state=AdminMenuSG.room_history,
getter=get_room_history_data,
)
room_history_detail_window = Window(
DynamicMedia("photo_media"),
Format("{detail_content}"),
SwitchTo(
Const("◀️ К списку"),
id="back_to_room_history_from_detail",
state=AdminMenuSG.room_history,
),
state=AdminMenuSG.room_history_detail,
getter=get_room_transaction_detail_data,
)