From f59791caf10c7848879fdd528730f2cfca165f95 Mon Sep 17 00:00:00 2001 From: kolo Date: Tue, 17 Mar 2026 20:36:51 +0300 Subject: [PATCH] update --- src/dutylog/application/__main__.py | 1 - .../bot/creator_dialogs/__init__.py | 5 +- .../bot/creator_dialogs/admins_management.py | 15 ++++ .../creator_dialogs/creator_menu_dialog.py | 4 + .../creator_dialogs/transactions_history.py | 79 +++++++++++++++++++ .../application/bot/user_dialogs/states.py | 1 + .../database/dao/hours_transactions_dao.py | 4 +- .../database/dao/residents_dao.py | 2 +- src/dutylog/services/report_service.py | 1 - 9 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 src/dutylog/application/bot/creator_dialogs/transactions_history.py diff --git a/src/dutylog/application/__main__.py b/src/dutylog/application/__main__.py index a9524db..3d9256a 100644 --- a/src/dutylog/application/__main__.py +++ b/src/dutylog/application/__main__.py @@ -55,7 +55,6 @@ async def main(): setup_dialogs(dp) setup_dishka(container, dp, auto_inject=True) - # Устанавливаем команды бота await set_bot_commands(bot) await dp.start_polling(bot) diff --git a/src/dutylog/application/bot/creator_dialogs/__init__.py b/src/dutylog/application/bot/creator_dialogs/__init__.py index 4fa302d..fbdd606 100644 --- a/src/dutylog/application/bot/creator_dialogs/__init__.py +++ b/src/dutylog/application/bot/creator_dialogs/__init__.py @@ -1,5 +1,8 @@ from dutylog.application.bot.creator_dialogs.creator_menu_dialog import ( creator_menu_dialog, ) +from dutylog.application.bot.creator_dialogs.transactions_history import ( + transactions_history_window, +) -__all__ = ["creator_menu_dialog"] +__all__ = ["creator_menu_dialog", "transactions_history_window"] diff --git a/src/dutylog/application/bot/creator_dialogs/admins_management.py b/src/dutylog/application/bot/creator_dialogs/admins_management.py index 893a050..e71b576 100644 --- a/src/dutylog/application/bot/creator_dialogs/admins_management.py +++ b/src/dutylog/application/bot/creator_dialogs/admins_management.py @@ -289,6 +289,21 @@ admins_list_window = Window( id="add_admin_btn", on_click=on_add_admin_click, ), + Button( + Const("──────────"), + id="separator_btn", + on_click=lambda c, b, m: None, + ), + SwitchTo( + Const("👨‍💼 Админы"), + id="admins_btn", + state=CreatorMenuSG.admins_list, + ), + SwitchTo( + Const("📜 История"), + id="history_btn", + state=CreatorMenuSG.transactions_history, + ), Button( Const("◀️ Назад"), id="back_to_main_from_admins", diff --git a/src/dutylog/application/bot/creator_dialogs/creator_menu_dialog.py b/src/dutylog/application/bot/creator_dialogs/creator_menu_dialog.py index cedc4a1..b4b747c 100644 --- a/src/dutylog/application/bot/creator_dialogs/creator_menu_dialog.py +++ b/src/dutylog/application/bot/creator_dialogs/creator_menu_dialog.py @@ -7,6 +7,9 @@ from dutylog.application.bot.creator_dialogs.admins_management import ( add_admin_select_user_window, add_admin_confirm_window, ) +from dutylog.application.bot.creator_dialogs.transactions_history import ( + transactions_history_window, +) creator_menu_dialog = Dialog( @@ -15,4 +18,5 @@ creator_menu_dialog = Dialog( remove_admin_confirm_window, add_admin_select_user_window, add_admin_confirm_window, + transactions_history_window, ) diff --git a/src/dutylog/application/bot/creator_dialogs/transactions_history.py b/src/dutylog/application/bot/creator_dialogs/transactions_history.py new file mode 100644 index 0000000..355e3b7 --- /dev/null +++ b/src/dutylog/application/bot/creator_dialogs/transactions_history.py @@ -0,0 +1,79 @@ +from aiogram_dialog import Window +from aiogram_dialog.widgets.text import Format, Const +from aiogram_dialog.widgets.kbd import Back, NumberedPager, Group +from dishka import FromDishka +from dishka.integrations.aiogram_dialog import inject + +from dutylog.application.bot.user_dialogs.states import CreatorMenuSG +from dutylog.infrastructure.database.repositories.hours_transactions_repository import ( + HoursTransactionsRepository, +) +from dutylog.infrastructure.database.repositories.residents_repository import ( + ResidentsRepository, +) +from dutylog.infrastructure.database.repositories.rooms_repository import ( + RoomsRepository, +) +from dutylog.infrastructure.utils.datetime import msk_now + + +@inject +async def get_transactions_history_data( + transactions_repository: FromDishka[HoursTransactionsRepository], + residents_repository: FromDishka[ResidentsRepository], + rooms_repository: FromDishka[RoomsRepository], + dialog_manager, + **kwargs, +) -> dict: + all_transactions = await transactions_repository.get_all_transactions() + all_transactions.sort(key=lambda t: t.created_at, reverse=True) + + page = await dialog_manager.find("transactions_pager").get_page() + per_page = 7 + start_idx = page * per_page + end_idx = start_idx + per_page + + page_transactions = all_transactions[start_idx:end_idx] + + if not page_transactions: + content = "
📜 История всех транзакций
\n\nНет транзакций" + else: + content = "
📜 История всех транзакций
\n\n" + + for tx in page_transactions: + resident = await residents_repository.get_by_id(tx.resident_id) + if not resident: + continue + + room = await rooms_repository.get_by_id(resident.room) + room_number = room.number if room else "???" + + operation = "Начислено" if tx.transaction_type == "increase" else "Списано" + emoji = "+" if tx.transaction_type == "increase" else "−" + room_mark = " 🚪" if tx.per_room 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💬 {tx.remark}" if tx.remark else "" + + content += f"
{operation} {emoji}{tx.amount} ч{room_mark}\n👤 {resident.real_name or 'Без имени'} (к. {room_number})\n📅 {date_str}{remark_text}
\n" + + total_pages = (len(all_transactions) + per_page - 1) // per_page + + return { + "content": content, + "pages": total_pages, + } + + +transactions_history_window = Window( + Format("{content}"), + Group( + NumberedPager(scroll="transactions_pager", when="pages"), + width=8, + ), + Back(Const("◀️ Назад")), + state=CreatorMenuSG.transactions_history, + getter=get_transactions_history_data, +) diff --git a/src/dutylog/application/bot/user_dialogs/states.py b/src/dutylog/application/bot/user_dialogs/states.py index 464f3dc..f53c80e 100644 --- a/src/dutylog/application/bot/user_dialogs/states.py +++ b/src/dutylog/application/bot/user_dialogs/states.py @@ -67,6 +67,7 @@ class CreatorMenuSG(StatesGroup): remove_admin_confirm = State() add_admin_select_user = State() add_admin_confirm = State() + transactions_history = State() class RegistrationSG(StatesGroup): diff --git a/src/dutylog/infrastructure/database/dao/hours_transactions_dao.py b/src/dutylog/infrastructure/database/dao/hours_transactions_dao.py index e95fec1..d27bba4 100644 --- a/src/dutylog/infrastructure/database/dao/hours_transactions_dao.py +++ b/src/dutylog/infrastructure/database/dao/hours_transactions_dao.py @@ -1,3 +1,5 @@ +from datetime import datetime, time + from sqlalchemy import select, delete from sqlalchemy.ext.asyncio import AsyncSession @@ -41,8 +43,6 @@ class HoursTransactionsDAO: await self.session.commit() async def get_by_period(self, start_date, end_date) -> list[HoursTransaction]: - from datetime import datetime, time - start_datetime = datetime.combine(start_date, time.min) end_datetime = datetime.combine(end_date, time.max) diff --git a/src/dutylog/infrastructure/database/dao/residents_dao.py b/src/dutylog/infrastructure/database/dao/residents_dao.py index 3dce8d0..cefcd9d 100644 --- a/src/dutylog/infrastructure/database/dao/residents_dao.py +++ b/src/dutylog/infrastructure/database/dao/residents_dao.py @@ -2,6 +2,7 @@ from sqlalchemy import select, update, delete from sqlalchemy.ext.asyncio import AsyncSession from dutylog.infrastructure.database.models.resident import Resident +from dutylog.infrastructure.database.models.room import Room class ResidentsDAO: @@ -37,7 +38,6 @@ class ResidentsDAO: return list(result.scalars().all()) async def search_by_room_number(self, room_number: int) -> list[Resident]: - from dutylog.infrastructure.database.models.room import Room result = await self.session.execute( select(Resident) .join(Room, Resident.room == Room.id) diff --git a/src/dutylog/services/report_service.py b/src/dutylog/services/report_service.py index 14166a7..9ff2d22 100644 --- a/src/dutylog/services/report_service.py +++ b/src/dutylog/services/report_service.py @@ -43,7 +43,6 @@ class ReportService: start_date, end_date ) - # Разделяем транзакции на личные и комнатные resident_transactions = [t for t in all_transactions if not t.per_room] room_transactions = [t for t in all_transactions if t.per_room]