fix coupons/formatted day
This commit is contained in:
+10
-2
@@ -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)
|
||||
|
||||
@@ -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}% скидка"
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user