From 0ffe64765759467f166c8f99c5b66c3f75fa1f9e Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Wed, 1 Jul 2026 14:37:25 +0200 Subject: [PATCH] =?UTF-8?q?feat(subscriptions):=20subscribe()=20g=C3=A9n?= =?UTF-8?q?=C3=A8re=20et=20transmet=20le=20handle,=20mark=5Ffailed=20en=20?= =?UTF-8?q?cas=20d'=C3=A9chec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/subscriptions/routes.py | 19 +++++++++------ tests/subscriptions/test_routes.py | 39 ++++++++++++++---------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/subscriptions/routes.py b/src/subscriptions/routes.py index 35bf1be..9fd2a0a 100644 --- a/src/subscriptions/routes.py +++ b/src/subscriptions/routes.py @@ -18,8 +18,8 @@ def _customer_handle(user_id: int) -> str: @login_required def subscribe(): plan_key = request.form.get("plan") or "" - handle = plans.resolve_handle(plan_key) - if handle is None: + plan_handle = plans.resolve_handle(plan_key) + if plan_handle is None: return "Plan inconnu", 400 base = os.getenv("APP_BASE_URL", "") @@ -27,11 +27,11 @@ def subscribe(): return redirect(f"{base}/compte/abonnement") cust = _customer_handle(current_user.id) + meta = plans.plan_meta(plan_key) + sub_handle, subscription_id = db.create_pending( + current_user.id, cust, plan_key, meta["prix_ht"] if meta else None + ) try: - meta = plans.plan_meta(plan_key) - db.create_pending( - current_user.id, cust, plan_key, meta["prix_ht"] if meta else None - ) no_trial = db.has_used_trial(current_user.id) siret = (request.form.get("siret") or "").strip() billing: dict = { @@ -61,7 +61,8 @@ def subscribe(): if customer_exists: url = client.create_subscription_session( - handle, + plan_handle, + sub_handle, f"{base}/compte/abonnement?paiement=succes", f"{base}/compte/abonnement?paiement=annule", customer_handle=cust, @@ -72,7 +73,8 @@ def subscribe(): if siret: create_customer["metadata"] = {"siret": siret} url = client.create_subscription_session( - handle, + plan_handle, + sub_handle, f"{base}/compte/abonnement?paiement=succes", f"{base}/compte/abonnement?paiement=annule", create_customer=create_customer, @@ -80,6 +82,7 @@ def subscribe(): ) except client.FrisbiiError: logger.exception("Échec de création de session d'abonnement Frisbii") + db.mark_failed(subscription_id) return redirect("/compte/abonnement?error=frisbii") return redirect(url, code=303) diff --git a/tests/subscriptions/test_routes.py b/tests/subscriptions/test_routes.py index 1a0287f..ec653aa 100644 --- a/tests/subscriptions/test_routes.py +++ b/tests/subscriptions/test_routes.py @@ -18,6 +18,7 @@ def test_subscribe_redirects_to_hosted_url(logged_in_client, monkeypatch): frisbii_client, "create_subscription_session", lambda plan, + handle, ok, ko, no_trial=False, @@ -27,25 +28,23 @@ def test_subscribe_redirects_to_hosted_url(logged_in_client, monkeypatch): resp = client.post("/subscriptions/subscribe", data={"plan": "simple"}) assert resp.status_code == 303 assert resp.headers["Location"] == "https://pay.test/cs_1" - assert db.get_by_user(uid)["status"] == "pending" + row = db.get_current(uid) + assert row["status"] == "pending" + assert row["frisbii_subscription_handle"] == f"abo-{uid}-1" def test_subscribe_disables_trial_after_first_use(logged_in_client, monkeypatch): client, uid = logged_in_client # L'utilisateur a déjà consommé un essai par le passé (abonnement maintenant expiré). - db.create_pending(uid, "colibre-%d" % uid, "simple") - db.update_from_webhook( - "colibre-%d" % uid, "sub_42", "trial", "2099-01-01T00:00:00+00:00" - ) + handle, _ = db.create_pending(uid, "colibre-%d" % uid, "simple") + db.update_from_webhook(handle, "trial", "2099-01-01T00:00:00+00:00") # L'essai est terminé : abonnement expiré, trial_used reste à 1. - db.update_from_webhook( - "colibre-%d" % uid, "sub_42", "expired", "2020-01-01T00:00:00+00:00" - ) + db.update_from_webhook(handle, "expired", "2020-01-01T00:00:00+00:00") captured = {} monkeypatch.setattr(frisbii_client, "update_customer", lambda h, d: {}) def fake_session( - plan, ok, ko, no_trial=False, customer_handle=None, create_customer=None + plan, handle, ok, ko, no_trial=False, customer_handle=None, create_customer=None ): captured["no_trial"] = no_trial return "https://pay.test/cs_9" @@ -62,8 +61,8 @@ def test_subscribe_unknown_plan(logged_in_client): assert resp.status_code == 400 -def test_subscribe_api_error_redirects_with_error(logged_in_client, monkeypatch): - client, _ = logged_in_client +def test_subscribe_api_error_marks_failed_and_redirects(logged_in_client, monkeypatch): + client, uid = logged_in_client def boom(h, d): raise frisbii_client.FrisbiiError(500, "boom") @@ -72,6 +71,8 @@ def test_subscribe_api_error_redirects_with_error(logged_in_client, monkeypatch) resp = client.post("/subscriptions/subscribe", data={"plan": "simple"}) assert resp.status_code == 302 assert "error=frisbii" in resp.headers["Location"] + row = db.get_current(uid) + assert row["status"] == "failed" def test_subscribe_requires_login(sub_app): @@ -136,10 +137,8 @@ def test_webhook_updates_subscription(sub_app, monkeypatch): def test_subscribe_skips_if_already_active(logged_in_client, monkeypatch): """Fix 1 : un abonné actif ne doit pas voir son statut remis à 'pending'.""" client, uid = logged_in_client - db.create_pending(uid, "colibre-%d" % uid, "simple") - db.update_from_webhook( - "colibre-%d" % uid, "sub_42", "active", "2099-01-01T00:00:00+00:00" - ) + handle, _ = db.create_pending(uid, "colibre-%d" % uid, "simple") + db.update_from_webhook(handle, "active", "2099-01-01T00:00:00+00:00") called = [] monkeypatch.setattr( frisbii_client, "update_customer", lambda h, d: called.append(h) @@ -150,17 +149,15 @@ def test_subscribe_skips_if_already_active(logged_in_client, monkeypatch): assert "compte/abonnement" in resp.headers["Location"] assert called == [], "Frisbii ne doit pas être appelé pour un abonné actif" # Le statut DB ne doit pas avoir été écrasé. - assert db.get_by_user(uid)["status"] == "active" + assert db.get_current(uid)["status"] == "active" def test_subscribe_skips_if_trial_active(logged_in_client, monkeypatch): """Fix 1 : un abonné en période d'essai est protégé de la même façon.""" client, uid = logged_in_client - db.create_pending(uid, "colibre-%d" % uid, "simple") - db.update_from_webhook( - "colibre-%d" % uid, "sub_42", "trial", "2099-01-01T00:00:00+00:00" - ) + handle, _ = db.create_pending(uid, "colibre-%d" % uid, "simple") + db.update_from_webhook(handle, "trial", "2099-01-01T00:00:00+00:00") resp = client.post("/subscriptions/subscribe", data={"plan": "simple"}) assert resp.status_code == 302 assert "compte/abonnement" in resp.headers["Location"] - assert db.get_by_user(uid)["status"] == "trial" + assert db.get_current(uid)["status"] == "trial"