feat: gel des votes au désabonnement/réabonnement #94
This commit is contained in:
@@ -73,12 +73,32 @@ def get_by_customer(customer_handle: str) -> sqlite3.Row | None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def freeze_votes_cursor(user_id: int) -> None:
|
||||||
|
"""Réactivation après une période sans abonnement : repart de maintenant.
|
||||||
|
|
||||||
|
Ne fait rien si le curseur est NULL (première activation jamais atteinte) :
|
||||||
|
les +2 initiaux restent gérés par credit_pending. Ne re-crédite jamais.
|
||||||
|
"""
|
||||||
|
row = get_by_user(user_id)
|
||||||
|
if row is None or row["votes_credited_until"] is None:
|
||||||
|
return
|
||||||
|
now = _now()
|
||||||
|
get_conn().execute(
|
||||||
|
"UPDATE subscriptions SET votes_credited_until = ?, updated_at = ? "
|
||||||
|
"WHERE user_id = ?",
|
||||||
|
(now, now, user_id),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def update_from_webhook(
|
def update_from_webhook(
|
||||||
customer_handle: str,
|
customer_handle: str,
|
||||||
subscription_handle: str | None,
|
subscription_handle: str | None,
|
||||||
status: str,
|
status: str,
|
||||||
current_period_end: str | None,
|
current_period_end: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
prev = get_by_customer(customer_handle)
|
||||||
|
if prev is not None and prev["status"] == "active" and status != "active":
|
||||||
|
credit_pending(prev["user_id"]) # banque les semaines acquises avant gel
|
||||||
trial_flag = 1 if status in _ACCESS_STATUSES else 0
|
trial_flag = 1 if status in _ACCESS_STATUSES else 0
|
||||||
get_conn().execute(
|
get_conn().execute(
|
||||||
"UPDATE subscriptions SET "
|
"UPDATE subscriptions SET "
|
||||||
@@ -95,9 +115,14 @@ def update_from_webhook(
|
|||||||
customer_handle,
|
customer_handle,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
if prev is not None and prev["status"] != "active" and status == "active":
|
||||||
|
freeze_votes_cursor(prev["user_id"])
|
||||||
|
|
||||||
|
|
||||||
def set_cancelled(user_id: int, current_period_end: str | None) -> None:
|
def set_cancelled(user_id: int, current_period_end: str | None) -> None:
|
||||||
|
credit_pending(
|
||||||
|
user_id
|
||||||
|
) # banque les semaines pleines acquises (statut encore actif)
|
||||||
get_conn().execute(
|
get_conn().execute(
|
||||||
"UPDATE subscriptions SET status = 'cancelled', current_period_end = ?, "
|
"UPDATE subscriptions SET status = 'cancelled', current_period_end = ?, "
|
||||||
"updated_at = ? WHERE user_id = ?",
|
"updated_at = ? WHERE user_id = ?",
|
||||||
|
|||||||
@@ -191,3 +191,35 @@ def test_spend_vote_refused_when_balance_zero(users_db_path):
|
|||||||
_activate(uid, cursor_iso=None)
|
_activate(uid, cursor_iso=None)
|
||||||
# solde reste 0 tant que credit_pending n'est pas appelé
|
# solde reste 0 tant que credit_pending n'est pas appelé
|
||||||
assert db.spend_vote(uid) is False
|
assert db.spend_vote(uid) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_reactivation_resets_cursor_without_regranting(users_db_path):
|
||||||
|
db.init_schema()
|
||||||
|
uid = _make_user()
|
||||||
|
db.create_pending(uid, "decpinfo-1", "simple")
|
||||||
|
_activate(uid, cursor_iso=None)
|
||||||
|
db.credit_pending(uid) # +2, curseur posé
|
||||||
|
# désabonnement
|
||||||
|
db.update_from_webhook("decpinfo-1", "sub_1", "cancelled", _future())
|
||||||
|
# période sans abonnement simulée : on recule artificiellement le curseur
|
||||||
|
old_cursor = (datetime.now(timezone.utc) - timedelta(days=30)).isoformat()
|
||||||
|
db.get_conn().execute(
|
||||||
|
"UPDATE subscriptions SET votes_credited_until = ? WHERE user_id = ?",
|
||||||
|
(old_cursor, uid),
|
||||||
|
)
|
||||||
|
# réabonnement
|
||||||
|
db.update_from_webhook("decpinfo-1", "sub_1", "active", _future())
|
||||||
|
row = db.get_by_user(uid)
|
||||||
|
assert row["votes_balance"] == 2 # pas de re-crédit des +2
|
||||||
|
# le curseur a été remis ~à maintenant → pas de crédit du gap de 30 jours
|
||||||
|
assert db.credit_pending(uid) == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_trial_to_active_does_not_reset_then_grants_two(users_db_path):
|
||||||
|
db.init_schema()
|
||||||
|
uid = _make_user()
|
||||||
|
db.create_pending(uid, "decpinfo-1", "simple")
|
||||||
|
db.update_from_webhook("decpinfo-1", "sub_1", "trial", _future())
|
||||||
|
db.update_from_webhook("decpinfo-1", "sub_1", "active", _future())
|
||||||
|
# fin d'essai : credit_pending accorde les +2 initiaux
|
||||||
|
assert db.credit_pending(uid) == 2
|
||||||
|
|||||||
Reference in New Issue
Block a user