fix(subscription): extend by absolute expiry timestamp, not floored days
- activate_subscription_days now adds timedelta to the real expires_at (max(now, current_expires)) instead of _days_until() floor value; prevents losing fractional time on each renewal (10d + 1d -> was 10d) - return ceil day count for display consistency - keep _days_until only for is_subscribed gate and support stats
This commit is contained in:
1 parent
261b2b2d02
commit
6f52599342
2 files changed
+11
-9
No files matched your search
+10
-8
@@ -238,7 +238,11 @@ def ensure_subscription(user_id: int, db_path: str | None = None) -> None:
|
||||
|
||||
|
||||
def activate_subscription_days(user_id: int, days: int, db_path: str | None = None) -> int:
|
||||
"""Добавляет срок к текущей подписке и возвращает оставшиеся дни."""
|
||||
"""Добавляет срок к подписке и возвращает оставшиеся дни (ceil).
|
||||
|
||||
Сложение ведётся по абсолютному UTC-моменту истечения, без округления дней:
|
||||
это исключает потерю дроби при каждой продлировке (было 10д + 1д -> 10д).
|
||||
"""
|
||||
if days <= 0:
|
||||
raise ValueError("Subscription days must be positive")
|
||||
with closing(connect(db_path)) as connection, connection:
|
||||
@@ -246,12 +250,9 @@ def activate_subscription_days(user_id: int, days: int, db_path: str | None = No
|
||||
if not sub:
|
||||
raise RuntimeError("Subscription record not found")
|
||||
now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
||||
current_days = _days_until(sub, now)
|
||||
if current_days > 0:
|
||||
current_expires = now + datetime.timedelta(days=current_days, seconds=1)
|
||||
new_expires = current_expires + datetime.timedelta(days=days)
|
||||
else:
|
||||
new_expires = now + datetime.timedelta(days=days)
|
||||
current_expires = _subscription_expires_at(sub)
|
||||
base = max(now, current_expires) if current_expires is not None else now
|
||||
new_expires = base + datetime.timedelta(days=days)
|
||||
connection.execute(
|
||||
"""
|
||||
UPDATE subscriptions
|
||||
@@ -260,7 +261,8 @@ def activate_subscription_days(user_id: int, days: int, db_path: str | None = No
|
||||
""",
|
||||
(new_expires.isoformat(), days, user_id),
|
||||
)
|
||||
return max(0, (new_expires - now).days)
|
||||
remaining_seconds = int((new_expires - now).total_seconds())
|
||||
return -(-remaining_seconds // 86400) if remaining_seconds > 0 else 0
|
||||
|
||||
|
||||
def activate_subscription(user_id: int, months: int = 1, db_path: str | None = None) -> int:
|
||||
|
||||
Reference in new issue
Block a user