fix: delegate tariff resets to panel

This commit is contained in:
3252a8
2026-04-28 15:36:13 +03:00
parent 258b2f4dec
commit 4958e1fdfd
5 changed files with 119 additions and 171 deletions
+6 -10
View File
@@ -8,7 +8,7 @@ from bot.middlewares.i18n import JsonI18n
from db.dal import user_dal, subscription_dal, promo_code_dal, payment_dal, user_billing_dal, tariff_dal
from config.tariffs_config import Tariff
from bot.utils.date_utils import add_months, month_start
from bot.utils.date_utils import add_months
from bot.utils.config_link import prepare_config_links
from db.models import User, Subscription
@@ -825,7 +825,7 @@ class SubscriptionService:
if target.billing_model == "period":
update_data["tier_baseline_bytes"] = target.monthly_bytes
update_data["traffic_limit_bytes"] = target.monthly_bytes + int(sub.topup_balance_bytes or 0)
update_data["period_start_at"] = month_start()
update_data["period_start_at"] = None
update_data["effective_monthly_price_rub"] = target.period_price(1, "rub") or target.min_period_price_rub()
if mode == "recalc_days" and options.get("recalc_days") is not None:
update_data["end_date"] = now + timedelta(days=int(options["recalc_days"]))
@@ -858,7 +858,7 @@ class SubscriptionService:
expire_at=updated.end_date,
status="ACTIVE",
traffic_limit_bytes=updated.traffic_limit_bytes,
traffic_limit_strategy="NO_RESET" if target.billing_model == "traffic" else self.settings.USER_TRAFFIC_STRATEGY,
traffic_limit_strategy="NO_RESET" if target.billing_model == "traffic" else "MONTH",
)
panel_payload["activeInternalSquads"] = target.squad_uuids
panel_payload.update(self._panel_identity_payload_for_user(db_user))
@@ -1077,11 +1077,6 @@ class SubscriptionService:
topup_balance_bytes = int(getattr(current_active_sub, "topup_balance_bytes", 0) or 0)
tier_baseline_bytes = tariff.monthly_bytes if tariff else self.settings.user_traffic_limit_bytes
period_start_at = month_start() if tariff else (
datetime.now(timezone.utc)
if starts_after_lapse or not current_active_sub or not getattr(current_active_sub, "period_start_at", None)
else current_active_sub.period_start_at
)
effective_monthly_price = float(payment_amount) / max(1, months_int)
traffic_limit_bytes = self._traffic_limit_for_period_tariff(tariff, topup_balance_bytes)
sub_payload = {
@@ -1100,7 +1095,7 @@ class SubscriptionService:
"tariff_key": tariff.key if tariff else None,
"tier_baseline_bytes": tier_baseline_bytes,
"topup_balance_bytes": topup_balance_bytes,
"period_start_at": period_start_at,
"period_start_at": None,
"is_throttled": False,
"effective_monthly_price_rub": effective_monthly_price,
}
@@ -1120,6 +1115,7 @@ class SubscriptionService:
expire_at=final_end_date,
status="ACTIVE",
traffic_limit_bytes=traffic_limit_bytes,
traffic_limit_strategy="MONTH" if tariff else self.settings.USER_TRAFFIC_STRATEGY,
)
if tariff:
panel_update_payload["activeInternalSquads"] = tariff.squad_uuids
@@ -1381,7 +1377,7 @@ class SubscriptionService:
except Exception:
tariff = None
billing_model_display = tariff.billing_model if tariff else ("traffic" if getattr(self.settings, "traffic_sale_mode", False) else "period")
traffic_limit_strategy = "MONTH" if billing_model_display == "period" else panel_traffic_strategy
traffic_limit_strategy = panel_traffic_strategy
return {
"user_id": panel_user_data.get("uuid"),
+31 -47
View File
@@ -58,6 +58,7 @@ class TariffTrafficWorker:
async def traffic_period_tick(self, session: AsyncSession) -> None:
now = datetime.now(timezone.utc)
warning_period_start = month_start(now)
result = await session.execute(
select(Subscription).where(
Subscription.is_active == True,
@@ -71,61 +72,42 @@ class TariffTrafficWorker:
except Exception:
continue
panel_data = await self.panel_service.get_user_by_uuid(sub.panel_user_uuid, log_response=False) or {}
used, limit, _ = self.subscription_service._extract_panel_traffic_details(panel_data)
used, limit, panel_strategy = self.subscription_service._extract_panel_traffic_details(panel_data)
if used is not None and used != sub.traffic_used_bytes:
sub.traffic_used_bytes = used
if limit is not None and limit != sub.traffic_limit_bytes:
sub.traffic_limit_bytes = limit
if tariff.billing_model == "period":
reset_happened = await self._maybe_reset_period(session, sub, tariff, used)
if reset_happened:
used = 0
sub.traffic_used_bytes = 0
await self._maybe_warn_or_throttle(session, sub, tariff, used, limit)
async def _maybe_reset_period(self, session: AsyncSession, sub: Subscription, tariff, used: Optional[int]) -> bool:
now = datetime.now(timezone.utc)
current_month_start = month_start(now)
if not sub.period_start_at:
await subscription_dal.update_subscription(
await self._ensure_period_reset_strategy(sub, tariff, limit, panel_strategy)
await self._maybe_warn_or_throttle(
session,
sub.subscription_id,
{"period_start_at": current_month_start},
sub,
tariff,
used,
limit,
warning_period_start=warning_period_start if tariff.billing_model == "period" else None,
)
sub.period_start_at = current_month_start
return False
stored_month_start = month_start(sub.period_start_at)
if stored_month_start == current_month_start or sub.end_date <= now:
return False
await self.panel_service.reset_user_traffic(sub.panel_user_uuid)
restore_throttled = bool(sub.is_throttled)
restore_succeeded = True
if restore_throttled:
for squad_uuid in tariff.squad_uuids:
restore_succeeded = await self.panel_service.add_users_to_internal_squad(
squad_uuid,
[sub.panel_user_uuid],
) and restore_succeeded
should_clear_throttle = restore_throttled and restore_succeeded
await subscription_dal.update_subscription(
session,
sub.subscription_id,
{
"period_start_at": current_month_start,
"traffic_used_bytes": 0,
"is_throttled": False if should_clear_throttle else sub.is_throttled,
"status_from_panel": "ACTIVE" if should_clear_throttle else sub.status_from_panel,
},
async def _ensure_period_reset_strategy(
self,
sub: Subscription,
tariff,
limit: Optional[int],
panel_strategy: Optional[str],
) -> None:
if str(panel_strategy or "").upper() == "MONTH":
return
traffic_limit_bytes = int(limit or sub.traffic_limit_bytes or (tariff.monthly_bytes + int(sub.topup_balance_bytes or 0)))
payload = self.subscription_service._build_panel_update_payload(
panel_user_uuid=sub.panel_user_uuid,
expire_at=sub.end_date,
status="ACTIVE",
traffic_limit_bytes=traffic_limit_bytes,
traffic_limit_strategy="MONTH",
)
sub.period_start_at = current_month_start
sub.traffic_used_bytes = 0
if should_clear_throttle:
sub.is_throttled = False
sub.status_from_panel = "ACTIVE"
await tariff_dal.clear_period_warnings(session, sub.subscription_id)
return True
payload["activeInternalSquads"] = tariff.squad_uuids
await self.panel_service.update_user_details_on_panel(sub.panel_user_uuid, payload, log_response=False)
async def _maybe_warn_or_throttle(
self,
@@ -134,6 +116,8 @@ class TariffTrafficWorker:
tariff,
used: Optional[int],
limit: Optional[int],
*,
warning_period_start: Optional[datetime] = None,
) -> None:
used_val = int(used or sub.traffic_used_bytes or 0)
limit_val = int(limit or sub.traffic_limit_bytes or 0)
@@ -146,7 +130,7 @@ class TariffTrafficWorker:
warning = await tariff_dal.get_warning(
session,
subscription_id=sub.subscription_id,
period_start_at=sub.period_start_at if tariff.billing_model == "period" else None,
period_start_at=warning_period_start if tariff.billing_model == "period" else None,
level=level,
traffic_limit_bytes=limit_val if tariff.billing_model == "traffic" else None,
)
@@ -155,7 +139,7 @@ class TariffTrafficWorker:
await tariff_dal.create_warning(
session,
subscription_id=sub.subscription_id,
period_start_at=sub.period_start_at if tariff.billing_model == "period" else None,
period_start_at=warning_period_start if tariff.billing_model == "period" else None,
level=level,
traffic_limit_bytes=limit_val if tariff.billing_model == "traffic" else None,
)