fix(subscription): show expiry clock time (MSK) when under a day
- subscription_time_left: replace floor-div '23 ч.'/'мин.' branches with the concrete expiry timestamp when less than a full day remains - add MSK_TIMEZONE (UTC+3) as display default; label time as '(МСК)' - add shared subscription_status_text helper, use it in status menu, post-payment reply and dev confirmation instead of floor-rounded days - tests: cover under-a-day clock format; fix stale to_thread mock
This commit is contained in:
1 parent
140f2f7263
commit
87f22fb249
6 files changed
+52
-17
No files matched your search
+27
-4
@@ -145,6 +145,8 @@ def init_db(db_path: str | None = None) -> None:
|
||||
TRIAL_DAYS = 3
|
||||
SUBSCRIPTION_MONTH_DAYS = 30 # Совместимость со старым dev-сценарием.
|
||||
SUBSCRIPTION_PRICE_STARS = 450
|
||||
# Время окончания подписки показываем по Москве (MSK = фиксированный UTC+3).
|
||||
MSK_TIMEZONE = datetime.timezone(datetime.timedelta(hours=3))
|
||||
SUBSCRIPTION_PLANS = {
|
||||
0: 1,
|
||||
1: 15,
|
||||
@@ -183,7 +185,11 @@ def _days_until(sub: sqlite3.Row, now: datetime.datetime | None = None) -> int:
|
||||
return delta.days if delta.total_seconds() > 0 else -1
|
||||
|
||||
|
||||
def subscription_time_left(sub: sqlite3.Row, now: datetime.datetime | None = None) -> tuple[bool, int, str]:
|
||||
def subscription_time_left(
|
||||
sub: sqlite3.Row,
|
||||
now: datetime.datetime | None = None,
|
||||
display_tz: datetime.timezone | None = None,
|
||||
) -> tuple[bool, int | str, str]:
|
||||
expires = _subscription_expires_at(sub)
|
||||
if expires is None:
|
||||
return False, 0, ""
|
||||
@@ -194,9 +200,26 @@ def subscription_time_left(sub: sqlite3.Row, now: datetime.datetime | None = Non
|
||||
return False, 0, ""
|
||||
if seconds >= 86400:
|
||||
return True, seconds // 86400, "дн."
|
||||
if seconds >= 3600:
|
||||
return True, seconds // 3600, "ч."
|
||||
return True, max(1, seconds // 60), "мин."
|
||||
# Меньше суток — показываем конкретное время окончания вместо "N ч.".
|
||||
display_tz = display_tz or MSK_TIMEZONE
|
||||
stamp = (expires + datetime.timedelta(microseconds=1)).replace(tzinfo=datetime.timezone.utc)
|
||||
return True, stamp.astimezone(display_tz).strftime("%d.%m.%Y %H:%M") + " (МСК)", ""
|
||||
|
||||
|
||||
def subscription_status_text(
|
||||
sub: sqlite3.Row | None,
|
||||
now: datetime.datetime | None = None,
|
||||
display_tz: datetime.timezone | None = None,
|
||||
) -> str:
|
||||
"""Единый текст статуса подписки: дни (>= суток) или конкретное время (< суток)."""
|
||||
if not sub:
|
||||
return "Подписка закончилась"
|
||||
active, value, unit = subscription_time_left(sub, now=now, display_tz=display_tz)
|
||||
if not active:
|
||||
return "Подписка закончилась"
|
||||
if unit == "":
|
||||
return f"Подписка активна\nЗакончится в {value}"
|
||||
return f"Подписка активна\nЗакончится через {value} {unit}"
|
||||
|
||||
def subscription_row(user_id: int, db_path: str | None = None) -> sqlite3.Row | None:
|
||||
with closing(connect(db_path)) as connection:
|
||||
|
||||
Reference in new issue
Block a user