fix coupons/formatted day

This commit is contained in:
Capybara-z
2025-04-19 15:55:21 +03:00
parent 9ae5cf2660
commit 26411ef982
6 changed files with 61 additions and 69 deletions
+10 -2
View File
@@ -74,8 +74,9 @@ async def activate_coupon(message: Message, state: FSMContext, session: Any, cou
coupon_record = await get_coupon_by_code(coupon_code, session)
if not coupon_record:
await message.answer(COUPON_NOT_FOUND_MSG)
await state.clear()
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="exit_coupon_input"))
await message.answer(COUPON_NOT_FOUND_MSG, reply_markup=builder.as_markup())
return
if coupon_record["usage_count"] >= coupon_record["usage_limit"] or coupon_record["is_used"]:
@@ -220,3 +221,10 @@ async def cancel_coupon_activation(callback_query: CallbackQuery, state: FSMCont
await callback_query.message.edit_text("⚠️ Активация купона отменена.")
await process_callback_view_profile(callback_query.message, state, admin)
await state.clear()
@router.callback_query(F.data == "exit_coupon_input")
async def handle_exit_coupon_input(callback_query: CallbackQuery, state: FSMContext):
await state.clear()
is_admin = callback_query.from_user.id in ADMIN_ID
await process_callback_view_profile(callback_query.message, state, admin=is_admin)
+2 -2
View File
@@ -41,7 +41,7 @@ from handlers.texts import (
PLAN_SELECTION_MSG,
SUCCESS_RENEWAL_MSG,
)
from handlers.utils import edit_or_send_message
from handlers.utils import edit_or_send_message, format_months
from logger import logger
@@ -66,7 +66,7 @@ async def process_callback_renew_key(callback_query: CallbackQuery, session: Any
discount = DISCOUNTS.get(plan_id, 0) if isinstance(DISCOUNTS, dict) else 0
button_text = f"📅 {months} месяц{'а' if months > 1 else ''} ({price} руб.)"
button_text = f"📅 {format_months(months)} ({price} руб.)"
if discount > 0:
button_text += f" {discount}% скидка"
+3 -3
View File
@@ -48,7 +48,7 @@ from handlers.texts import (
NO_SUBSCRIPTIONS_MSG,
key_message,
)
from handlers.utils import edit_or_send_message, handle_error, is_full_remnawave_cluster
from handlers.utils import edit_or_send_message, handle_error, is_full_remnawave_cluster, format_days, format_hours, format_minutes
from logger import logger
@@ -215,13 +215,13 @@ async def process_callback_view_key(callback_query: CallbackQuery, session: Any)
time_left = expiry_date - datetime.utcnow()
if time_left.total_seconds() <= 0:
days_left_message = "<b>🕒 Статус подписки:</b>\n🔴 Истекла\nОсталось часов: 0\nОсталось минут: 0"
days_left_message = "<b>🕒 Статус подписки:</b>\n🔴 Истекла"
else:
total_seconds = int(time_left.total_seconds())
days = total_seconds // 86400
hours = (total_seconds % 86400) // 3600
minutes = (total_seconds % 3600) // 60
days_left_message = f"Осталось: <b>{days}</b> дней, <b>{hours}</b> часов, <b>{minutes}</b> минут"
days_left_message = f"Осталось: <b>{format_days(days)}</b>, <b>{format_hours(hours)}</b>, <b>{format_minutes(minutes)}</b>"
formatted_expiry_date = expiry_date.strftime("%d %B %Y года")
response_message = key_message(
+20 -13
View File
@@ -44,6 +44,7 @@ from handlers.texts import (
KEY_RENEWED,
KEY_RENEWED_TEMP_MSG,
)
from handlers.utils import format_hours, format_minutes
from logger import logger
from .notify_utils import send_notification
@@ -137,8 +138,8 @@ 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 +147,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 +193,8 @@ 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 +202,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 +309,21 @@ 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)
delay_message = KEY_EXPIRED_DELAY_HOURS_MINUTES_MSG.format(
email=email,
hours_formatted=format_hours(hours),
minutes_formatted=format_minutes(minutes)
)
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)
delay_message = KEY_EXPIRED_DELAY_HOURS_MSG.format(
email=email,
hours_formatted=format_hours(hours)
)
else:
delay_message = KEY_EXPIRED_DELAY_MINUTES_MSG.format(email=email, minutes=NOTIFY_DELETE_DELAY)
delay_message = KEY_EXPIRED_DELAY_MINUTES_MSG.format(
email=email,
minutes_formatted=format_minutes(minutes)
)
else:
delay_message = KEY_EXPIRED_NO_DELAY_MSG.format(email=email)
@@ -18,6 +18,7 @@ from database import (
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 handlers.utils import format_days
from logger import logger
@@ -80,12 +81,15 @@ async def notify_inactive_trial_users(bot: Bot, conn: asyncpg.Connection):
total_days = NOTIFY_EXTRA_DAYS + TRIAL_TIME
message = TRIAL_INACTIVE_BONUS_MSG.format(
display_name=display_name,
NOTIFY_EXTRA_DAYS=NOTIFY_EXTRA_DAYS,
total_days=total_days,
extra_days_formatted=format_days(NOTIFY_EXTRA_DAYS),
total_days_formatted=format_days(total_days),
)
await conn.execute("UPDATE users SET trial = -1 WHERE tg_id = $1", tg_id)
else:
message = TRIAL_INACTIVE_FIRST_MSG.format(display_name=display_name, TRIAL_TIME=TRIAL_TIME)
message = TRIAL_INACTIVE_FIRST_MSG.format(
display_name=display_name,
trial_time_formatted=format_days(TRIAL_TIME)
)
try:
await bot.send_message(tg_id, message, reply_markup=keyboard)
+19 -46
View File
@@ -115,64 +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,