fix: separate base and purchased traffic in renewal pricing
When a user has 25GB base + 100GB purchased = 125GB total, the renewal priced it at the 250GB tier (nearest tier >= 125GB) instead of pricing each component separately at its own tier: base 25GB + purchased 100GB. - Split traffic_limit_gb into base and purchased components - Price each component at its own tier via get_traffic_price() - Apply same discount percentage to purchased portion - Log warning when purchased >= total (data corruption) - Fix in both subscription_renewal_service and subscription CRUD
This commit is contained in:
@@ -1391,11 +1391,27 @@ async def get_subscription_renewal_cost(
|
||||
total_servers_discount = servers_discount_per_month * months_in_period
|
||||
|
||||
# В режиме fixed_with_topup при продлении используем фиксированный лимит
|
||||
purchased_traffic = subscription.purchased_traffic_gb or 0
|
||||
if settings.is_traffic_fixed():
|
||||
renewal_traffic_gb = settings.get_fixed_traffic_limit()
|
||||
traffic_price_per_month = settings.get_traffic_price(settings.get_fixed_traffic_limit())
|
||||
# Separate base traffic from purchased to avoid wrong tier lookup
|
||||
elif purchased_traffic > 0:
|
||||
base_traffic_gb = (subscription.traffic_limit_gb or 0) - purchased_traffic
|
||||
if base_traffic_gb <= 0:
|
||||
logger.warning(
|
||||
'Purchased traffic >= total limit, pricing purchased portion only',
|
||||
subscription_id=subscription.id,
|
||||
traffic_limit_gb=subscription.traffic_limit_gb,
|
||||
purchased_traffic_gb=purchased_traffic,
|
||||
)
|
||||
traffic_price_per_month = settings.get_traffic_price(purchased_traffic)
|
||||
else:
|
||||
traffic_price_per_month = (
|
||||
settings.get_traffic_price(base_traffic_gb)
|
||||
+ settings.get_traffic_price(purchased_traffic)
|
||||
)
|
||||
else:
|
||||
renewal_traffic_gb = subscription.traffic_limit_gb
|
||||
traffic_price_per_month = settings.get_traffic_price(renewal_traffic_gb)
|
||||
traffic_price_per_month = settings.get_traffic_price(subscription.traffic_limit_gb)
|
||||
traffic_discount_percent = _get_discount_percent(
|
||||
user,
|
||||
promo_group,
|
||||
|
||||
@@ -325,8 +325,22 @@ class SubscriptionRenewalService:
|
||||
await self._validate_servers_for_user_promo_group(db, user, connected_uuids)
|
||||
|
||||
# В режиме fixed_with_topup при продлении используем фиксированный лимит
|
||||
purchased_traffic = subscription.purchased_traffic_gb or 0
|
||||
if settings.is_traffic_fixed():
|
||||
traffic_limit = settings.get_fixed_traffic_limit()
|
||||
# Separate base traffic from purchased to avoid wrong tier lookup
|
||||
# e.g. 25GB base + 100GB purchased = 125GB total → would round up to 250GB tier
|
||||
elif purchased_traffic > 0:
|
||||
base_traffic = (subscription.traffic_limit_gb or 0) - purchased_traffic
|
||||
if base_traffic <= 0:
|
||||
logger.warning(
|
||||
'Purchased traffic >= total limit, pricing purchased portion only',
|
||||
subscription_id=subscription.id,
|
||||
traffic_limit_gb=subscription.traffic_limit_gb,
|
||||
purchased_traffic_gb=purchased_traffic,
|
||||
)
|
||||
base_traffic = settings.DEFAULT_TRAFFIC_LIMIT_GB or 0
|
||||
traffic_limit = base_traffic
|
||||
else:
|
||||
traffic_limit = subscription.traffic_limit_gb
|
||||
if traffic_limit is None:
|
||||
@@ -347,6 +361,20 @@ class SubscriptionRenewalService:
|
||||
|
||||
months = details.get('months_in_period') or calculate_months_from_days(period_days)
|
||||
|
||||
# Add purchased traffic cost separately (uses its own tier price, same discount %)
|
||||
if purchased_traffic > 0 and not settings.is_traffic_fixed():
|
||||
purchased_price_per_month = settings.get_traffic_price(purchased_traffic)
|
||||
traffic_discount_pct = details.get('traffic_discount_percent', 0)
|
||||
purchased_disc_per_month = purchased_price_per_month * traffic_discount_pct // 100
|
||||
discounted_purchased_per_month = purchased_price_per_month - purchased_disc_per_month
|
||||
purchased_total = discounted_purchased_per_month * months
|
||||
purchased_disc_total = purchased_disc_per_month * months
|
||||
|
||||
total_cost += purchased_total
|
||||
details['traffic_price_per_month'] = details.get('traffic_price_per_month', 0) + purchased_price_per_month
|
||||
details['total_traffic_price'] = details.get('total_traffic_price', 0) + purchased_total
|
||||
details['traffic_discount_total'] = details.get('traffic_discount_total', 0) + purchased_disc_total
|
||||
|
||||
base_original_total = (
|
||||
details.get('base_price_original', 0)
|
||||
+ details.get('traffic_price_per_month', 0) * months
|
||||
|
||||
Reference in New Issue
Block a user