mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-03-01 15:52:30 +00:00
@@ -290,26 +290,54 @@ async def confirm_change_devices(callback: types.CallbackQuery, db_user: User, d
|
||||
chargeable_devices = additional_devices
|
||||
|
||||
devices_price_per_month = chargeable_devices * price_per_device
|
||||
months_hint = get_remaining_months(subscription.end_date)
|
||||
period_hint_days = months_hint * 30 if months_hint > 0 else None
|
||||
devices_discount_percent = _get_addon_discount_percent_for_user(
|
||||
db_user,
|
||||
'devices',
|
||||
period_hint_days,
|
||||
)
|
||||
discounted_per_month, discount_per_month = apply_percentage_discount(
|
||||
devices_price_per_month,
|
||||
devices_discount_percent,
|
||||
)
|
||||
price, charged_months = calculate_prorated_price(
|
||||
discounted_per_month,
|
||||
subscription.end_date,
|
||||
)
|
||||
total_discount = discount_per_month * charged_months
|
||||
|
||||
# Проверяем является ли тариф суточным
|
||||
is_daily_tariff = tariff and getattr(tariff, 'is_daily', False)
|
||||
|
||||
if is_daily_tariff:
|
||||
# Для суточных тарифов считаем по дням (как в кабинете)
|
||||
now = datetime.utcnow()
|
||||
days_left = max(1, (subscription.end_date - now).days)
|
||||
period_hint_days = days_left
|
||||
|
||||
devices_discount_percent = _get_addon_discount_percent_for_user(
|
||||
db_user,
|
||||
'devices',
|
||||
period_hint_days,
|
||||
)
|
||||
discounted_per_month, discount_per_month = apply_percentage_discount(
|
||||
devices_price_per_month,
|
||||
devices_discount_percent,
|
||||
)
|
||||
# Цена = месячная_цена * days_left / 30
|
||||
price = int(discounted_per_month * days_left / 30)
|
||||
price = max(100, price) # Минимум 1 рубль
|
||||
total_discount = int(discount_per_month * days_left / 30)
|
||||
period_label = f'{days_left} дн.' if days_left > 1 else '1 день'
|
||||
else:
|
||||
# Для обычных тарифов - по месяцам
|
||||
months_hint = get_remaining_months(subscription.end_date)
|
||||
period_hint_days = months_hint * 30 if months_hint > 0 else None
|
||||
|
||||
devices_discount_percent = _get_addon_discount_percent_for_user(
|
||||
db_user,
|
||||
'devices',
|
||||
period_hint_days,
|
||||
)
|
||||
discounted_per_month, discount_per_month = apply_percentage_discount(
|
||||
devices_price_per_month,
|
||||
devices_discount_percent,
|
||||
)
|
||||
price, charged_months = calculate_prorated_price(
|
||||
discounted_per_month,
|
||||
subscription.end_date,
|
||||
)
|
||||
total_discount = discount_per_month * charged_months
|
||||
period_label = f'{charged_months} мес'
|
||||
|
||||
if price > 0 and db_user.balance_kopeks < price:
|
||||
missing_kopeks = price - db_user.balance_kopeks
|
||||
required_text = f'{texts.format_price(price)} (за {charged_months} мес)'
|
||||
required_text = f'{texts.format_price(price)} (за {period_label})'
|
||||
message_text = texts.t(
|
||||
'ADDON_INSUFFICIENT_FUNDS_MESSAGE',
|
||||
(
|
||||
@@ -343,10 +371,10 @@ async def confirm_change_devices(callback: types.CallbackQuery, db_user: User, d
|
||||
if price > 0:
|
||||
cost_text = texts.t(
|
||||
'DEVICE_CHANGE_EXTRA_COST',
|
||||
'Доплата: {amount} (за {months} мес)',
|
||||
'Доплата: {amount} (за {period})',
|
||||
).format(
|
||||
amount=texts.format_price(price),
|
||||
months=charged_months,
|
||||
period=period_label,
|
||||
)
|
||||
if total_discount > 0:
|
||||
cost_text += texts.t(
|
||||
@@ -949,35 +977,63 @@ async def confirm_add_devices(callback: types.CallbackQuery, db_user: User, db:
|
||||
return
|
||||
|
||||
devices_price_per_month = devices_count * price_per_device
|
||||
months_hint = get_remaining_months(subscription.end_date)
|
||||
period_hint_days = months_hint * 30 if months_hint > 0 else None
|
||||
devices_discount_percent = _get_addon_discount_percent_for_user(
|
||||
db_user,
|
||||
'devices',
|
||||
period_hint_days,
|
||||
)
|
||||
discounted_per_month, discount_per_month = apply_percentage_discount(
|
||||
devices_price_per_month,
|
||||
devices_discount_percent,
|
||||
)
|
||||
price, charged_months = calculate_prorated_price(
|
||||
discounted_per_month,
|
||||
subscription.end_date,
|
||||
)
|
||||
total_discount = discount_per_month * charged_months
|
||||
|
||||
# Проверяем является ли тариф суточным
|
||||
is_daily_tariff = tariff and getattr(tariff, 'is_daily', False)
|
||||
|
||||
if is_daily_tariff:
|
||||
# Для суточных тарифов считаем по дням (как в кабинете)
|
||||
now = datetime.utcnow()
|
||||
days_left = max(1, (subscription.end_date - now).days)
|
||||
period_hint_days = days_left
|
||||
|
||||
devices_discount_percent = _get_addon_discount_percent_for_user(
|
||||
db_user,
|
||||
'devices',
|
||||
period_hint_days,
|
||||
)
|
||||
discounted_per_month, discount_per_month = apply_percentage_discount(
|
||||
devices_price_per_month,
|
||||
devices_discount_percent,
|
||||
)
|
||||
# Цена = месячная_цена * days_left / 30
|
||||
price = int(discounted_per_month * days_left / 30)
|
||||
price = max(100, price) # Минимум 1 рубль
|
||||
total_discount = int(discount_per_month * days_left / 30)
|
||||
period_label = f'{days_left} дн.' if days_left > 1 else '1 день'
|
||||
else:
|
||||
# Для обычных тарифов - по месяцам
|
||||
months_hint = get_remaining_months(subscription.end_date)
|
||||
period_hint_days = months_hint * 30 if months_hint > 0 else None
|
||||
|
||||
devices_discount_percent = _get_addon_discount_percent_for_user(
|
||||
db_user,
|
||||
'devices',
|
||||
period_hint_days,
|
||||
)
|
||||
discounted_per_month, discount_per_month = apply_percentage_discount(
|
||||
devices_price_per_month,
|
||||
devices_discount_percent,
|
||||
)
|
||||
price, charged_months = calculate_prorated_price(
|
||||
discounted_per_month,
|
||||
subscription.end_date,
|
||||
)
|
||||
total_discount = discount_per_month * charged_months
|
||||
period_label = f'{charged_months} мес'
|
||||
|
||||
logger.info(
|
||||
'Добавление %s устройств: %.2f₽/мес × %s мес = %.2f₽ (скидка %.2f₽)',
|
||||
'Добавление %s устройств: %.2f₽/мес × %s = %.2f₽ (скидка %.2f₽)',
|
||||
devices_count,
|
||||
discounted_per_month / 100,
|
||||
charged_months,
|
||||
period_label,
|
||||
price / 100,
|
||||
total_discount / 100,
|
||||
)
|
||||
|
||||
if db_user.balance_kopeks < price:
|
||||
missing_kopeks = price - db_user.balance_kopeks
|
||||
required_text = f'{texts.format_price(price)} (за {charged_months} мес)'
|
||||
required_text = f'{texts.format_price(price)} (за {period_label})'
|
||||
message_text = texts.t(
|
||||
'ADDON_INSUFFICIENT_FUNDS_MESSAGE',
|
||||
(
|
||||
@@ -1007,7 +1063,7 @@ async def confirm_add_devices(callback: types.CallbackQuery, db_user: User, db:
|
||||
|
||||
try:
|
||||
success = await subtract_user_balance(
|
||||
db, db_user, price, f'Добавление {devices_count} устройств на {charged_months} мес'
|
||||
db, db_user, price, f'Добавление {devices_count} устройств на {period_label}'
|
||||
)
|
||||
|
||||
if not success:
|
||||
@@ -1024,7 +1080,7 @@ async def confirm_add_devices(callback: types.CallbackQuery, db_user: User, db:
|
||||
user_id=db_user.id,
|
||||
type=TransactionType.SUBSCRIPTION_PAYMENT,
|
||||
amount_kopeks=price,
|
||||
description=f'Добавление {devices_count} устройств на {charged_months} мес',
|
||||
description=f'Добавление {devices_count} устройств на {period_label}',
|
||||
)
|
||||
|
||||
await db.refresh(db_user)
|
||||
@@ -1035,7 +1091,7 @@ async def confirm_add_devices(callback: types.CallbackQuery, db_user: User, db:
|
||||
f'📱 Добавлено: {devices_count} устройств\n'
|
||||
f'Новый лимит: {subscription.device_limit} устройств\n'
|
||||
)
|
||||
success_text += f'💰 Списано: {texts.format_price(price)} (за {charged_months} мес)'
|
||||
success_text += f'💰 Списано: {texts.format_price(price)} (за {period_label})'
|
||||
if total_discount > 0:
|
||||
success_text += f' (скидка {devices_discount_percent}%: -{texts.format_price(total_discount)})'
|
||||
|
||||
|
||||
@@ -1924,12 +1924,28 @@ def get_change_devices_keyboard(
|
||||
|
||||
texts = get_texts(language)
|
||||
|
||||
months_multiplier = 1
|
||||
period_text = ''
|
||||
if subscription_end_date:
|
||||
months_multiplier = get_remaining_months(subscription_end_date)
|
||||
if months_multiplier > 1:
|
||||
period_text = f' (за {months_multiplier} мес)'
|
||||
# Проверяем является ли тариф суточным
|
||||
is_daily_tariff = tariff and getattr(tariff, 'is_daily', False)
|
||||
|
||||
# Для суточных тарифов считаем по дням, для обычных - по месяцам
|
||||
if is_daily_tariff and subscription_end_date:
|
||||
# Суточный тариф: цена за оставшиеся дни (обычно 1 день)
|
||||
from datetime import datetime
|
||||
|
||||
now = datetime.utcnow()
|
||||
days_left = max(1, (subscription_end_date - now).days)
|
||||
# Множитель = days_left / 30 (как в кабинете)
|
||||
price_multiplier = days_left / 30
|
||||
period_text = f' (за {days_left} дн.)' if days_left > 1 else ' (за 1 день)'
|
||||
else:
|
||||
# Обычный тариф: цена за оставшиеся месяцы
|
||||
months_multiplier = 1
|
||||
period_text = ''
|
||||
if subscription_end_date:
|
||||
months_multiplier = get_remaining_months(subscription_end_date)
|
||||
if months_multiplier > 1:
|
||||
period_text = f' (за {months_multiplier} мес)'
|
||||
price_multiplier = months_multiplier
|
||||
|
||||
# Используем цену из тарифа если есть, иначе глобальную настройку
|
||||
tariff_device_price = getattr(tariff, 'device_price_kopeks', None) if tariff else None
|
||||
@@ -1943,7 +1959,12 @@ def get_change_devices_keyboard(
|
||||
|
||||
buttons = []
|
||||
|
||||
max_devices = settings.MAX_DEVICES_LIMIT if settings.MAX_DEVICES_LIMIT > 0 else 20
|
||||
# Используем max_device_limit из тарифа если есть, иначе глобальную настройку
|
||||
tariff_max_devices = getattr(tariff, 'max_device_limit', None) if tariff else None
|
||||
if tariff_max_devices and tariff_max_devices > 0:
|
||||
max_devices = tariff_max_devices
|
||||
else:
|
||||
max_devices = settings.MAX_DEVICES_LIMIT if settings.MAX_DEVICES_LIMIT > 0 else 20
|
||||
|
||||
start_range = max(1, min(current_devices - 3, max_devices - 6))
|
||||
end_range = min(max_devices + 1, max(current_devices + 4, 7))
|
||||
@@ -1967,10 +1988,12 @@ def get_change_devices_keyboard(
|
||||
price_per_month,
|
||||
discount_percent,
|
||||
)
|
||||
total_price = discounted_per_month * months_multiplier
|
||||
total_price = int(discounted_per_month * price_multiplier)
|
||||
total_price = max(100, total_price) # Минимум 1 рубль
|
||||
price_text = f' (+{total_price // 100}₽{period_text})'
|
||||
if discount_percent > 0 and discount_per_month * months_multiplier > 0:
|
||||
price_text += f' (скидка {discount_percent}%: -{(discount_per_month * months_multiplier) // 100}₽)'
|
||||
total_discount = int(discount_per_month * price_multiplier)
|
||||
if discount_percent > 0 and total_discount > 0:
|
||||
price_text += f' (скидка {discount_percent}%: -{total_discount // 100}₽)'
|
||||
action_text = ''
|
||||
else:
|
||||
price_text = ' (бесплатно)'
|
||||
|
||||
Reference in New Issue
Block a user