diff --git a/app/cabinet/routes/subscription_modules/devices.py b/app/cabinet/routes/subscription_modules/devices.py index 60728108..90a8ab60 100644 --- a/app/cabinet/routes/subscription_modules/devices.py +++ b/app/cabinet/routes/subscription_modules/devices.py @@ -13,6 +13,7 @@ POST /subscription/devices/save-cart from __future__ import annotations +import math from datetime import UTC, datetime from typing import Any @@ -380,7 +381,7 @@ async def purchase_devices( if end_date.tzinfo is None: end_date = end_date.replace(tzinfo=UTC) - days_left = max(1, (end_date - now).days) + days_left = max(1, math.ceil((end_date - now).total_seconds() / 86400)) total_days = 30 # Base period for device price calculation # Устройства в пределах тарифного лимита — бесплатные @@ -658,7 +659,7 @@ async def save_devices_cart( if end_date.tzinfo is None: end_date = end_date.replace(tzinfo=UTC) - days_left = max(1, (end_date - now).days) + days_left = max(1, math.ceil((end_date - now).total_seconds() / 86400)) total_days = 30 # Устройства в пределах тарифного лимита — бесплатные @@ -772,7 +773,7 @@ async def get_device_price( if end_date.tzinfo is None: end_date = end_date.replace(tzinfo=UTC) - days_left = max(1, (end_date - now).days) + days_left = max(1, math.ceil((end_date - now).total_seconds() / 86400)) total_days = 30 # Устройства в пределах тарифного лимита — бесплатные diff --git a/app/handlers/subscription/devices.py b/app/handlers/subscription/devices.py index 63087c89..082b5d1c 100644 --- a/app/handlers/subscription/devices.py +++ b/app/handlers/subscription/devices.py @@ -1,4 +1,5 @@ import html as html_mod +import math from datetime import UTC, datetime from aiogram import types @@ -343,7 +344,7 @@ async def confirm_change_devices( # Считаем стоимость по оставшимся дням подписки now = datetime.now(UTC) - days_left = max(1, (subscription.end_date - now).days) + days_left = max(1, math.ceil((subscription.end_date - now).total_seconds() / 86400)) period_hint_days = days_left devices_discount_percent = PricingEngine.get_addon_discount_percent( @@ -572,7 +573,7 @@ async def execute_change_devices( chargeable_devices = devices_difference devices_price_per_month = chargeable_devices * price_per_device - days_left = max(1, (subscription.end_date - datetime.now(UTC)).days) + days_left = max(1, math.ceil((subscription.end_date - datetime.now(UTC)).total_seconds() / 86400)) devices_discount_percent = PricingEngine.get_addon_discount_percent( db_user, 'devices', @@ -601,7 +602,7 @@ async def execute_change_devices( ) return - charged_days = max(1, (subscription.end_date - datetime.now(UTC)).days) + charged_days = max(1, math.ceil((subscription.end_date - datetime.now(UTC)).total_seconds() / 86400)) await create_transaction( db=db, user_id=db_user.id, @@ -1253,7 +1254,7 @@ async def confirm_add_devices(callback: types.CallbackQuery, db_user: User, db: if is_daily_tariff: # Для суточных тарифов считаем по дням (как в кабинете) now = datetime.now(UTC) - days_left = max(1, (subscription.end_date - now).days) + days_left = max(1, math.ceil((subscription.end_date - now).total_seconds() / 86400)) period_hint_days = days_left devices_discount_percent = PricingEngine.get_addon_discount_percent( @@ -1274,7 +1275,7 @@ async def confirm_add_devices(callback: types.CallbackQuery, db_user: User, db: else: # Для обычных тарифов - по дням (как в кабинете) now = datetime.now(UTC) - days_left = max(1, (subscription.end_date - now).days) + days_left = max(1, math.ceil((subscription.end_date - now).total_seconds() / 86400)) period_hint_days = days_left devices_discount_percent = PricingEngine.get_addon_discount_percent( diff --git a/app/keyboards/inline.py b/app/keyboards/inline.py index b7934210..5b6dc0d9 100644 --- a/app/keyboards/inline.py +++ b/app/keyboards/inline.py @@ -1,3 +1,4 @@ +import math from datetime import UTC, datetime import structlog @@ -2169,7 +2170,7 @@ def get_add_traffic_keyboard( # Считаем по дням (как в кабинете и подтверждении) if subscription_end_date: now = datetime.now(UTC) - days_left = max(1, (subscription_end_date - now).days) + days_left = max(1, math.ceil((subscription_end_date - now).total_seconds() / 86400)) price_multiplier = days_left / 30 period_text = f' (за {days_left} дн.)' if days_left > 1 else ' (за 1 день)' else: @@ -2311,7 +2312,7 @@ def get_change_devices_keyboard( # Считаем по дням (как в кабинете и подтверждении) if subscription_end_date: now = datetime.now(UTC) - days_left = max(1, (subscription_end_date - now).days) + days_left = max(1, math.ceil((subscription_end_date - now).total_seconds() / 86400)) price_multiplier = days_left / 30 period_text = f' (за {days_left} дн.)' if days_left > 1 else ' (за 1 день)' else: @@ -2473,7 +2474,7 @@ def get_manage_countries_keyboard( # Считаем по дням (как в кабинете и подтверждении) if subscription_end_date: now = datetime.now(UTC) - days_left = max(1, (subscription_end_date - now).days) + days_left = max(1, math.ceil((subscription_end_date - now).total_seconds() / 86400)) price_multiplier = days_left / 30 logger.info( '🔍 Расчет для управления странами: осталось дней до', diff --git a/app/utils/pricing_utils.py b/app/utils/pricing_utils.py index 9282e5da..5505d67b 100644 --- a/app/utils/pricing_utils.py +++ b/app/utils/pricing_utils.py @@ -1,3 +1,4 @@ +import math from collections.abc import Sequence from datetime import UTC, datetime from typing import TYPE_CHECKING, Any, Optional @@ -26,7 +27,7 @@ def calculate_prorated_price(monthly_price: int, end_date: datetime, min_charge_ tuple of (total_price_kopeks, days_charged) """ now = datetime.now(UTC) - days_remaining = max(1, (end_date - now).days) + days_remaining = max(1, math.ceil((end_date - now).total_seconds() / 86400)) days_to_charge = max(min_charge_days, days_remaining) total_price = monthly_price * days_to_charge // 30