fix(tariff-worker): match premium bandwidth stats by username, not uuid
This commit is contained in:
@@ -78,6 +78,7 @@ class TariffTrafficWorker:
|
|||||||
panel_data = await self.panel_service.get_user_by_uuid(sub.panel_user_uuid, log_response=False) or {}
|
panel_data = await self.panel_service.get_user_by_uuid(sub.panel_user_uuid, log_response=False) or {}
|
||||||
used, limit, panel_strategy = self.subscription_service._extract_panel_traffic_details(panel_data)
|
used, limit, panel_strategy = self.subscription_service._extract_panel_traffic_details(panel_data)
|
||||||
panel_status = str(panel_data.get("status") or "").upper()
|
panel_status = str(panel_data.get("status") or "").upper()
|
||||||
|
panel_username = panel_data.get("username") if isinstance(panel_data, dict) else None
|
||||||
if used is not None and used != sub.traffic_used_bytes:
|
if used is not None and used != sub.traffic_used_bytes:
|
||||||
sub.traffic_used_bytes = used
|
sub.traffic_used_bytes = used
|
||||||
if limit is not None and limit != sub.traffic_limit_bytes:
|
if limit is not None and limit != sub.traffic_limit_bytes:
|
||||||
@@ -96,7 +97,7 @@ class TariffTrafficWorker:
|
|||||||
warning_period_start=warning_period_start if tariff.billing_model == "period" else None,
|
warning_period_start=warning_period_start if tariff.billing_model == "period" else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
await self._sync_premium_squad_limit(session, sub, tariff, now)
|
await self._sync_premium_squad_limit(session, sub, tariff, now, panel_username=panel_username)
|
||||||
|
|
||||||
async def _ensure_period_reset_strategy(
|
async def _ensure_period_reset_strategy(
|
||||||
self,
|
self,
|
||||||
@@ -190,6 +191,8 @@ class TariffTrafficWorker:
|
|||||||
sub: Subscription,
|
sub: Subscription,
|
||||||
tariff,
|
tariff,
|
||||||
now: datetime,
|
now: datetime,
|
||||||
|
*,
|
||||||
|
panel_username: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if not getattr(tariff, "premium_squad_uuids", None):
|
if not getattr(tariff, "premium_squad_uuids", None):
|
||||||
if any(
|
if any(
|
||||||
@@ -222,7 +225,13 @@ class TariffTrafficWorker:
|
|||||||
|
|
||||||
start_date = now.date().replace(day=1).isoformat()
|
start_date = now.date().replace(day=1).isoformat()
|
||||||
end_date = now.date().isoformat()
|
end_date = now.date().isoformat()
|
||||||
premium_used = await self._premium_usage_for_user(sub.panel_user_uuid, node_uuids, start_date, end_date)
|
premium_used = await self._premium_usage_for_user(
|
||||||
|
sub.panel_user_uuid,
|
||||||
|
node_uuids,
|
||||||
|
start_date,
|
||||||
|
end_date,
|
||||||
|
panel_username=panel_username,
|
||||||
|
)
|
||||||
if premium_used is None:
|
if premium_used is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -379,9 +388,12 @@ class TariffTrafficWorker:
|
|||||||
node_uuids: list[str],
|
node_uuids: list[str],
|
||||||
start_date: str,
|
start_date: str,
|
||||||
end_date: str,
|
end_date: str,
|
||||||
|
*,
|
||||||
|
panel_username: Optional[str] = None,
|
||||||
) -> Optional[int]:
|
) -> Optional[int]:
|
||||||
total = 0
|
total = 0
|
||||||
found = False
|
found = False
|
||||||
|
username = (panel_username or "").strip() or None
|
||||||
for node_uuid in node_uuids:
|
for node_uuid in node_uuids:
|
||||||
stats = await self.panel_service.get_node_users_bandwidth_stats(
|
stats = await self.panel_service.get_node_users_bandwidth_stats(
|
||||||
node_uuid,
|
node_uuid,
|
||||||
@@ -403,7 +415,21 @@ class TariffTrafficWorker:
|
|||||||
or entry.get("uuid")
|
or entry.get("uuid")
|
||||||
or entry.get("user_uuid")
|
or entry.get("user_uuid")
|
||||||
)
|
)
|
||||||
if entry_uuid != user_uuid:
|
entry_username = (
|
||||||
|
user_obj.get("username")
|
||||||
|
or entry.get("username")
|
||||||
|
or entry.get("userUsername")
|
||||||
|
)
|
||||||
|
# Remnawave's /bandwidth-stats/nodes/{uuid}/users response
|
||||||
|
# currently exposes only {color, username, total}; match by
|
||||||
|
# username first, fall back to UUID if a future version
|
||||||
|
# adds it back.
|
||||||
|
matched = False
|
||||||
|
if entry_uuid and entry_uuid == user_uuid:
|
||||||
|
matched = True
|
||||||
|
elif username and entry_username and entry_username == username:
|
||||||
|
matched = True
|
||||||
|
if not matched:
|
||||||
continue
|
continue
|
||||||
value = entry.get("total")
|
value = entry.get("total")
|
||||||
if value is None:
|
if value is None:
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ class TariffWorkerTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
return_value={
|
return_value={
|
||||||
"topUsers": [
|
"topUsers": [
|
||||||
{
|
{
|
||||||
"user": {"uuid": "panel-uuid"},
|
"username": "tg_123",
|
||||||
"total": 2 * (1024**3),
|
"total": 2 * (1024**3),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -176,7 +176,13 @@ class TariffWorkerTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
tariff = settings.tariffs_config.require("standard")
|
tariff = settings.tariffs_config.require("standard")
|
||||||
|
|
||||||
with patch("bot.services.tariff_worker.tariff_dal.get_warning", new=AsyncMock(return_value=True)):
|
with patch("bot.services.tariff_worker.tariff_dal.get_warning", new=AsyncMock(return_value=True)):
|
||||||
await worker._sync_premium_squad_limit(AsyncMock(), sub, tariff, datetime.now(timezone.utc))
|
await worker._sync_premium_squad_limit(
|
||||||
|
AsyncMock(),
|
||||||
|
sub,
|
||||||
|
tariff,
|
||||||
|
datetime.now(timezone.utc),
|
||||||
|
panel_username="tg_123",
|
||||||
|
)
|
||||||
|
|
||||||
self.assertTrue(sub.premium_is_limited)
|
self.assertTrue(sub.premium_is_limited)
|
||||||
panel_service.update_user_details_on_panel.assert_awaited_once()
|
panel_service.update_user_details_on_panel.assert_awaited_once()
|
||||||
@@ -205,7 +211,7 @@ class TariffWorkerTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
return_value={
|
return_value={
|
||||||
"topUsers": [
|
"topUsers": [
|
||||||
{
|
{
|
||||||
"user": {"uuid": "panel-uuid"},
|
"username": "tg_123",
|
||||||
"total": int(1.5 * (1024**3)),
|
"total": int(1.5 * (1024**3)),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -233,7 +239,9 @@ class TariffWorkerTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
)
|
)
|
||||||
tariff = settings.tariffs_config.require("standard")
|
tariff = settings.tariffs_config.require("standard")
|
||||||
|
|
||||||
await worker._sync_premium_squad_limit(AsyncMock(), sub, tariff, now)
|
await worker._sync_premium_squad_limit(
|
||||||
|
AsyncMock(), sub, tariff, now, panel_username="tg_123"
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(sub.premium_topup_balance_bytes, int(1.5 * (1024**3)))
|
self.assertEqual(sub.premium_topup_balance_bytes, int(1.5 * (1024**3)))
|
||||||
self.assertEqual(sub.premium_topup_used_bytes, int(0.5 * (1024**3)))
|
self.assertEqual(sub.premium_topup_used_bytes, int(0.5 * (1024**3)))
|
||||||
@@ -243,14 +251,16 @@ class TariffWorkerTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
return_value={
|
return_value={
|
||||||
"topUsers": [
|
"topUsers": [
|
||||||
{
|
{
|
||||||
"user": {"uuid": "panel-uuid"},
|
"username": "tg_123",
|
||||||
"total": int(0.1 * (1024**3)),
|
"total": int(0.1 * (1024**3)),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
next_month = datetime(2026, 6, 2, tzinfo=timezone.utc)
|
next_month = datetime(2026, 6, 2, tzinfo=timezone.utc)
|
||||||
await worker._sync_premium_squad_limit(AsyncMock(), sub, tariff, next_month)
|
await worker._sync_premium_squad_limit(
|
||||||
|
AsyncMock(), sub, tariff, next_month, panel_username="tg_123"
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(sub.premium_topup_balance_bytes, int(1.5 * (1024**3)))
|
self.assertEqual(sub.premium_topup_balance_bytes, int(1.5 * (1024**3)))
|
||||||
self.assertEqual(sub.premium_topup_used_bytes, 0)
|
self.assertEqual(sub.premium_topup_used_bytes, 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user