From d19eee8897f722d2727c6072bec20e8bff468cf8 Mon Sep 17 00:00:00 2001 From: Capybara-z Date: Tue, 15 Apr 2025 01:24:36 +0300 Subject: [PATCH 1/3] Fix time declination MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Склонение времени --- .../notifications/general_notifications.py | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/handlers/notifications/general_notifications.py b/handlers/notifications/general_notifications.py index 6c4c075d..e5ea81c4 100644 --- a/handlers/notifications/general_notifications.py +++ b/handlers/notifications/general_notifications.py @@ -45,6 +45,7 @@ from handlers.texts import ( KEY_RENEWED_TEMP_MSG, ) from logger import logger +from handlers.utils import format_hours, format_months, format_minutes from .notify_utils import send_notification from .special_notifications import notify_inactive_trial_users, notify_users_no_traffic @@ -137,8 +138,10 @@ async def notify_24h_keys(bot: Bot, conn: asyncpg.Connection, current_time: int, continue hours_left = int((expiry_timestamp - current_time) / (1000 * 3600)) - days_left_message = ( - f"⏳ Осталось времени: {hours_left} часов" if hours_left > 0 else "⏳ Последний день подписки!" + hours_left_formatted = ( + f"⏳ Осталось времени: {format_hours(hours_left)}" + if hours_left > 0 + else "⏳ Последний день подписки!" ) expiry_datetime = datetime.fromtimestamp(expiry_timestamp / 1000, tz=moscow_tz) @@ -146,7 +149,7 @@ async def notify_24h_keys(bot: Bot, conn: asyncpg.Connection, current_time: int, notification_text = KEY_EXPIRY_24H.format( email=email, - days_left_message=days_left_message, + hours_left_formatted=hours_left_formatted, formatted_expiry_date=formatted_expiry_date, ) @@ -192,8 +195,10 @@ async def notify_10h_keys(bot: Bot, conn: asyncpg.Connection, current_time: int, continue hours_left = int((expiry_timestamp - current_time) / (1000 * 3600)) - hours_left_message = ( - f"⏳ Осталось времени: {hours_left} часов" if hours_left > 0 else "⏳ Последний день подписки!" + hours_left_formatted = ( + f"⏳ Осталось времени: {format_hours(hours_left)}" + if hours_left > 0 + else "⏳ Последний день подписки!" ) expiry_datetime = datetime.fromtimestamp(expiry_timestamp / 1000, tz=moscow_tz) @@ -201,7 +206,7 @@ async def notify_10h_keys(bot: Bot, conn: asyncpg.Connection, current_time: int, notification_text = KEY_EXPIRY_10H.format( email=email, - hours_left_message=hours_left_message, + hours_left_formatted=hours_left_formatted, formatted_expiry_date=formatted_expiry_date, ) @@ -308,15 +313,23 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time: if hours > 0: if minutes > 0: - hour_suffix = "час" if hours == 1 else "часа" if 2 <= hours <= 4 else "часов" - time_str = f"{hours} {hour_suffix} и {minutes} минут" - delay_message = KEY_EXPIRED_DELAY_HOURS_MINUTES_MSG.format(email=email, time_str=time_str) + time_left_formatted = f"{format_hours(hours)} и {format_minutes(minutes)}" + delay_message = KEY_EXPIRED_DELAY_HOURS_MINUTES_MSG.format( + email=email, + time_left_formatted=time_left_formatted + ) else: - hour_suffix = "час" if hours == 1 else "часа" if 2 <= hours <= 4 else "часов" - time_str = f"{hours} {hour_suffix}" - delay_message = KEY_EXPIRED_DELAY_HOURS_MSG.format(email=email, time_str=time_str) + time_left_formatted = format_hours(hours) + delay_message = KEY_EXPIRED_DELAY_HOURS_MSG.format( + email=email, + time_left_formatted=time_left_formatted + ) else: - delay_message = KEY_EXPIRED_DELAY_MINUTES_MSG.format(email=email, minutes=NOTIFY_DELETE_DELAY) + minutes_formatted = format_minutes(minutes) + delay_message = KEY_EXPIRED_DELAY_MINUTES_MSG.format( + email=email, + minutes_formatted=minutes_formatted + ) else: delay_message = KEY_EXPIRED_NO_DELAY_MSG.format(email=email) @@ -385,6 +398,7 @@ async def process_auto_renew_or_notify( new_expiry_time = current_expiry + renewal_period_months * 30 * 24 * 3600 * 1000 formatted_expiry_date = datetime.fromtimestamp(new_expiry_time / 1000, moscow_tz).strftime("%d %B %Y, %H:%M") + months_formatted = format_months(renewal_period_months) logger.info( f"[Автопродление] Продление подписки {email} на {renewal_period_months} мес. для пользователя {tg_id}. Баланс: {balance}, списываем: {renewal_cost}" @@ -403,7 +417,9 @@ async def process_auto_renew_or_notify( ) renewed_message = KEY_RENEWED.format( - email=email, months=renewal_period_months, expiry_date=formatted_expiry_date + email=email, + months_formatted=months_formatted, + expiry_date=formatted_expiry_date ) keyboard = build_notification_expired_kb() From e04be209cbb0a07f6fbe993389f07ddeeff6f21d Mon Sep 17 00:00:00 2001 From: Capybara-z Date: Tue, 15 Apr 2025 01:25:48 +0300 Subject: [PATCH 2/3] Fix time declination MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Склоение времени. --- handlers/notifications/special_notifications.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/handlers/notifications/special_notifications.py b/handlers/notifications/special_notifications.py index 23df7227..f927d9f3 100644 --- a/handlers/notifications/special_notifications.py +++ b/handlers/notifications/special_notifications.py @@ -19,6 +19,7 @@ from handlers.buttons import MAIN_MENU from handlers.keys.key_utils import get_user_traffic from handlers.texts import TRIAL_INACTIVE_BONUS_MSG, TRIAL_INACTIVE_FIRST_MSG, ZERO_TRAFFIC_MSG from logger import logger +from handlers.utils import format_days router = Router() @@ -84,12 +85,21 @@ async def notify_inactive_trial_users(bot: Bot, conn: asyncpg.Connection): if trial_extended: total_days = NOTIFY_EXTRA_DAYS + TRIAL_TIME + trial_time_formatted = format_days(TRIAL_TIME) + extra_days_formatted = format_days(NOTIFY_EXTRA_DAYS) + total_days_formatted = format_days(total_days) message = TRIAL_INACTIVE_BONUS_MSG.format( - display_name=display_name, NOTIFY_EXTRA_DAYS=NOTIFY_EXTRA_DAYS, total_days=total_days + display_name=display_name, + extra_days_formatted=extra_days_formatted, + total_days_formatted=total_days_formatted, ) await conn.execute("UPDATE connections SET trial = -1 WHERE tg_id = $1", tg_id) else: - message = TRIAL_INACTIVE_FIRST_MSG.format(display_name=display_name, TRIAL_TIME=TRIAL_TIME) + trial_time_formatted = format_days(TRIAL_TIME) + message = TRIAL_INACTIVE_FIRST_MSG.format( + display_name=display_name, + trial_time_formatted=trial_time_formatted, + ) try: await bot.send_message(tg_id, message, reply_markup=keyboard) From 0887e28b2bbe12c531f700cd3aab8ff188025631 Mon Sep 17 00:00:00 2001 From: Capybara-z Date: Tue, 15 Apr 2025 01:26:17 +0300 Subject: [PATCH 3/3] Adding time declination MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Добавил новые склонения --- handlers/utils.py | 66 ++++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/handlers/utils.py b/handlers/utils.py index 71a677d8..dc97d1c9 100644 --- a/handlers/utils.py +++ b/handlers/utils.py @@ -115,63 +115,37 @@ async def handle_error(tg_id: int, callback_query: object | None = None, message logger.error(f"Ошибка при обработке ошибки: {e}") -def format_time_until_deletion(seconds: int) -> str: - if seconds <= 0: - return "0 минут" - - days = seconds // (3600 * 24) - hours = (seconds % (3600 * 24)) // 3600 - minutes = (seconds % 3600 + 59) // 60 - - parts = [] - - if days > 0: - if days == 1: - parts.append(f"{days} день") - elif 2 <= days <= 4: - parts.append(f"{days} дня") - else: - parts.append(f"{days} дней") - - if hours > 0: - if hours == 1: - parts.append(f"{hours} час") - elif 2 <= hours <= 4: - parts.append(f"{hours} часа") - else: - parts.append(f"{hours} часов") - - if minutes > 0 and days == 0: - if minutes == 1: - parts.append("1 минута") - elif 2 <= minutes <= 4: - parts.append(f"{minutes} минуты") - else: - parts.append(f"{minutes} минут") - - return " и ".join(parts) if parts else "менее минуты" - - def get_plural_form(num: int, form1: str, form2: str, form3: str) -> str: + """Универсальная функция для получения правильной формы множественного числа""" n = abs(num) % 100 if 10 < n < 20: return form3 return {1: form1, 2: form2, 3: form2, 4: form2}.get(n % 10, form3) +def format_months(months: int) -> str: + """Форматирует количество месяцев с правильным склонением""" + if months <= 0: + return "0 месяцев" + return f"{months} {get_plural_form(months, 'месяц', 'месяца', 'месяцев')}" + def format_days(days: int) -> str: - """ - Форматирует количество дней с правильным склонением. - - Args: - days (int): Количество дней. - - Returns: - str: Строка с числом и склонённым словом "день/дня/дней". - """ + """Форматирует количество дней с правильным склонением""" if days <= 0: return "0 дней" return f"{days} {get_plural_form(days, 'день', 'дня', 'дней')}" +def format_hours(hours: int) -> str: + """Форматирует количество часов с правильным склонением""" + if hours <= 0: + return "0 часов" + return f"{hours} {get_plural_form(hours, 'час', 'часа', 'часов')}" + +def format_minutes(minutes: int) -> str: + """Форматирует количество минут с правильным склонением""" + if minutes <= 0: + return "0 минут" + return f"{minutes} {get_plural_form(minutes, 'минута', 'минуты', 'минут')}" + async def edit_or_send_message( target_message: Message,