feat(tradein): configurable estimate quota + new exhausted-quota copy (#658)

Make the monthly estimate quota limit configurable via
Settings.estimate_quota_limit (env ESTIMATE_QUOTA_LIMIT, default 15),
replacing the hardcoded 15 in account_quota.py. Change exhausted-quota
text (backend 429 detail + frontend banner) to
'За полной версией обращайтесь к Копылову'; banner uses dynamic limit.

Closes #658
This commit is contained in:
lekss361 2026-05-29 18:47:58 +03:00
parent 6508023c29
commit 8472d83ac3
4 changed files with 17 additions and 6 deletions

View file

@ -47,5 +47,9 @@ class Settings(BaseSettings):
dadata_api_token: str | None = None
dadata_api_secret: str | None = None
# Лимит успешных оценок trade-in за календарный месяц на аккаунт (#658).
# Конфигурируется через env ESTIMATE_QUOTA_LIMIT. Default 15.
estimate_quota_limit: int = 15
settings = Settings()

View file

@ -1,7 +1,8 @@
"""Сервис квоты оценок trade-in — 15 успешных оценок в месяц на аккаунт.
"""Сервис квоты оценок trade-in — N успешных оценок в месяц на аккаунт.
Правила:
- Лимит = 15 успешных оценок за календарный месяц (UTC, период 'YYYY-MM').
- Лимит = settings.estimate_quota_limit успешных оценок за календарный месяц
(UTC, период 'YYYY-MM'); конфигурируется через env ESTIMATE_QUOTA_LIMIT, default 15.
- Без лимита (unlimited): роль admin ИЛИ username == 'kopylov'.
- Учитываются ТОЛЬКО успешные оценки (инкремент ПОСЛЕ estimate_quality).
- Если заголовок X-Authenticated-User отсутствует (dev без Caddy) unlimited,
@ -19,12 +20,16 @@ from sqlalchemy import text
from sqlalchemy.orm import Session
from app.core.auth import get_role
from app.core.config import settings
logger = logging.getLogger(__name__)
MONTHLY_LIMIT = 15
# Лимит успешных оценок за календарный месяц — конфигурируется через
# env ESTIMATE_QUOTA_LIMIT (core.config.Settings), default 15 (#658).
MONTHLY_LIMIT = settings.estimate_quota_limit
LIMIT_EXHAUSTED_MESSAGE = (
"Лимит из 15 оценок в этом месяце исчерпан. Свяжитесь с Артёмом Копыловым."
f"Лимит из {MONTHLY_LIMIT} оценок в этом месяце исчерпан. "
"За полной версией обращайтесь к Копылову."
)

View file

@ -147,7 +147,8 @@ def test_check_and_raise_pilot_blocked_exact_detail() -> None:
with pytest.raises(HTTPException) as exc_info:
check_and_raise(db, "user3")
assert exc_info.value.detail == (
"Лимит из 15 оценок в этом месяце исчерпан. Свяжитесь с Артёмом Копыловым."
f"Лимит из {MONTHLY_LIMIT} оценок в этом месяце исчерпан. "
"За полной версией обращайтесь к Копылову."
)

View file

@ -429,7 +429,8 @@ export function EstimateForm({
marginBottom: 8,
}}
>
Лимит из 15 оценок в этом месяце исчерпан. Свяжитесь с Артёмом Копыловым.
Лимит из {limit ?? 15} оценок в этом месяце исчерпан. За полной версией
обращайтесь к Копылову.
</div>
) : (
<>