Skip to content

Commit 4843c5d

Browse files
authored
Merge pull request #145 from ilyarolf/develop
Develop
2 parents d0b77fe + 51b9d22 commit 4843c5d

File tree

5 files changed

+45
-15
lines changed

5 files changed

+45
-15
lines changed

enums/statistics_timedelta.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import calendar
2-
from datetime import datetime, timedelta
2+
from datetime import datetime, timedelta, timezone
33
from enum import IntEnum
44

55

@@ -9,7 +9,7 @@ class StatisticsTimeDelta(IntEnum):
99
MONTH = 30
1010

1111
def get_time_range(self) -> tuple[datetime, datetime]:
12-
now = datetime.now()
12+
now = datetime.now(timezone.utc)
1313

1414
match self:
1515
case StatisticsTimeDelta.DAY:

handlers/admin/statistics.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ async def entity_statistics(**kwargs):
3737
callback_data: StatisticsCallback = kwargs.get("callback_data")
3838
session: AsyncSession = kwargs.get("session")
3939
language: Language = kwargs.get("language")
40-
media, kb_builder = await StatisticsService.get_statistics(callback_data, session, language)
40+
state: FSMContext = kwargs.get("state")
41+
media, kb_builder = await StatisticsService.get_statistics(callback_data, session, state, language)
4142
await callback.message.delete()
4243
await callback.message.answer_photo(photo=media.media, caption=media.caption, reply_markup=kb_builder.as_markup())
4344

repositories/buy.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ async def create(buy_dto: BuyDTO, session: Session | AsyncSession) -> BuyDTO:
5353
@staticmethod
5454
async def get_max_refund_page(filters: list[str], session: AsyncSession):
5555
conditions = [
56-
Buy.status == BuyStatus.REFUNDED
56+
Buy.status != BuyStatus.REFUNDED
5757
]
5858
if filters:
5959
filters = [username.replace("@", "") for username in filters]
@@ -78,7 +78,7 @@ async def get_refund_data(sort_pairs: dict[str, int],
7878
sort_column = sort_property.get_column(Buy)
7979
sort_method = (getattr(sort_column, sort_order.name.lower()))
8080
sort_methods.append(sort_method())
81-
conditions = [Buy.status == BuyStatus.REFUNDED]
81+
conditions = [Buy.status != BuyStatus.REFUNDED]
8282
if filters:
8383
filters = [username.replace("@", "") for username in filters]
8484
filter_conditions = [User.telegram_username.icontains(name) for name in filters]
@@ -119,7 +119,7 @@ async def get_refund_data_single(buy_id: int, session: Session | AsyncSession) -
119119
.join(User, User.id == Buy.buyer_id)
120120
.join(Item, Item.id.in_(BuyItem.item_ids))
121121
.join(Subcategory, Subcategory.id == Item.subcategory_id)
122-
.where(Buy.status == BuyStatus.REFUNDED, Buy.id == buy_id)
122+
.where(Buy.status != BuyStatus.REFUNDED, Buy.id == buy_id)
123123
.limit(1))
124124
refund_data = await session_execute(stmt, session)
125125
return RefundDTO.model_validate(refund_data.mappings().one(), from_attributes=True)
@@ -144,7 +144,7 @@ async def get_by_timedelta(timedelta: StatisticsTimeDelta, session: Session | As
144144
start, end = timedelta.get_time_range()
145145
stmt = select(Buy).where(Buy.buy_datetime >= start,
146146
Buy.buy_datetime <= end,
147-
Buy.status == BuyStatus.REFUNDED)
147+
Buy.status != BuyStatus.REFUNDED)
148148
buys = await session_execute(stmt, session)
149149
return [BuyDTO.model_validate(buy, from_attributes=True) for buy in buys.scalars().all()]
150150

@@ -162,14 +162,14 @@ async def get_max_page_purchase_history(buyer_id: int | None, session: AsyncSess
162162
async def get_qty_by_buyer_id(buyer_id: int, session: AsyncSession | Session) -> int:
163163
stmt = (select(func.count(Buy.id))
164164
.where(Buy.buyer_id == buyer_id,
165-
Buy.status == BuyStatus.REFUNDED))
165+
Buy.status != BuyStatus.REFUNDED))
166166
qty = await session_execute(stmt, session)
167167
return qty.scalar_one()
168168

169169
@staticmethod
170170
async def get_spent_amount(buyer_id: int, session: AsyncSession) -> float:
171171
stmt = func.coalesce((select(func.sum(Buy.total_price))
172172
.where(Buy.buyer_id == buyer_id,
173-
Buy.status == BuyStatus.REFUNDED)), 0)
173+
Buy.status != BuyStatus.REFUNDED)), 0)
174174
qty = await session_execute(stmt, session)
175175
return qty.scalar_one()

repositories/user.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,16 @@ async def get_user_entity(user_entity: int | str, session: Session | AsyncSessio
7474
return UserDTO.model_validate(user, from_attributes=True)
7575

7676
@staticmethod
77-
async def get_by_timedelta(timedelta: StatisticsTimeDelta,
77+
async def get_by_timedelta(timedelta: StatisticsTimeDelta, session: Session | AsyncSession) -> list[UserDTO]:
78+
start, end = timedelta.get_time_range()
79+
users_stmt = (select(User)
80+
.where(User.registered_at >= start,
81+
User.registered_at <= end))
82+
users = await session_execute(users_stmt, session)
83+
return [UserDTO.model_validate(user, from_attributes=True) for user in users.scalars().all()]
84+
85+
@staticmethod
86+
async def get_by_timedelta_paginated(timedelta: StatisticsTimeDelta,
7887
page: int, session: Session | AsyncSession) -> list[UserDTO]:
7988
start, end = timedelta.get_time_range()
8089
users_stmt = (select(User)
@@ -107,3 +116,12 @@ async def get_referrals_qty_by_referrer_id(referrer_id: int, session: AsyncSessi
107116
.where(User.referred_by_user_id == referrer_id))
108117
referrals_qty = await session_execute(stmt, session)
109118
return referrals_qty.scalar_one()
119+
120+
@staticmethod
121+
async def get_qty_by_timedelta(timedelta: StatisticsTimeDelta, session: AsyncSession) -> int:
122+
start, end = timedelta.get_time_range()
123+
users_stmt = (select(func.count(User.id))
124+
.where(User.registered_at >= start,
125+
User.registered_at <= end))
126+
users_qty = await session_execute(users_stmt, session)
127+
return users_qty.scalar_one()

services/statistics.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from collections import defaultdict
22
from datetime import datetime, timedelta
3+
from aiogram.fsm.context import FSMContext
34
from aiogram.types import InputMediaPhoto, BufferedInputFile
45
from aiogram.utils.keyboard import InlineKeyboardBuilder
56
from sqlalchemy.ext.asyncio import AsyncSession
@@ -134,17 +135,27 @@ def build_statistics_chart(objects: list[UserDTO | BuyDTO | DepositDTO],
134135
@staticmethod
135136
async def get_statistics(callback_data: StatisticsCallback,
136137
session: AsyncSession,
138+
state: FSMContext,
137139
language: Language) -> tuple[InputMediaPhoto, InlineKeyboardBuilder]:
138140
kb_builder = InlineKeyboardBuilder()
139141
timedelta_localized = get_text(language, BotEntity.ADMIN, f"{callback_data.timedelta}_day")
140142
match callback_data.statistics_entity:
141143
case StatisticsEntity.USERS:
142-
users = await UserRepository.get_by_timedelta(callback_data.timedelta, callback_data.page,
143-
session)
144+
users = await UserRepository.get_by_timedelta(callback_data.timedelta, session)
145+
users_paginated = await UserRepository.get_by_timedelta_paginated(callback_data.timedelta,
146+
callback_data.page,
147+
session)
148+
users_qty = await UserRepository.get_qty_by_timedelta(callback_data.timedelta, session)
144149
[kb_builder.button(text=user.telegram_username, url=f'tg://user?id={user.telegram_id}') for user in
145-
users
150+
users_paginated
146151
if user.telegram_username]
147-
chart = StatisticsService.build_statistics_chart(users, callback_data.timedelta, language)
152+
state_data = await state.get_data()
153+
chart = state_data.get(f"chart_{callback_data.timedelta.name.lower()}")
154+
if chart is None:
155+
chart = StatisticsService.build_statistics_chart(users, callback_data.timedelta, language)
156+
await state.update_data(chart=chart.hex())
157+
else:
158+
chart = bytes.fromhex(chart)
148159
kb_builder.adjust(1)
149160
kb_builder = await add_pagination_buttons(
150161
kb_builder,
@@ -154,7 +165,7 @@ async def get_statistics(callback_data: StatisticsCallback,
154165
language)
155166
kb_builder.row(AdminConstants.back_to_main_button(language), callback_data.get_back_button(language))
156167
caption = get_text(language, BotEntity.ADMIN, "new_users_msg").format(
157-
users_count=len(users),
168+
users_count=users_qty,
158169
timedelta=timedelta_localized
159170
)
160171
media = InputMediaPhoto(

0 commit comments

Comments
 (0)