Fix redirection Frisbii après ajout de moyen de paiement au premier abonnement
accept_url/cancel_url n'existent pas dans le schéma de POST /v1/subscription (ils y sont silencieusement ignorés) : Frisbii attend ces paramètres en query string sur le lien hosted_page_links.payment_info retourné. Ajout d'un warning loggé sur signature de webhook invalide, jusque-là silencieuse. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@@ -61,6 +62,13 @@ def update_customer(handle: str, data: dict) -> dict:
|
|||||||
return _call("PUT", f"/v1/customer/{handle}", json=data)
|
return _call("PUT", f"/v1/customer/{handle}", json=data)
|
||||||
|
|
||||||
|
|
||||||
|
def _with_query(url: str, **params: str) -> str:
|
||||||
|
parts = urlsplit(url)
|
||||||
|
query = dict(parse_qsl(parts.query))
|
||||||
|
query.update(params)
|
||||||
|
return urlunsplit(parts._replace(query=urlencode(query)))
|
||||||
|
|
||||||
|
|
||||||
def create_subscription_session(
|
def create_subscription_session(
|
||||||
plan_handle: str,
|
plan_handle: str,
|
||||||
handle: str,
|
handle: str,
|
||||||
@@ -70,12 +78,13 @@ def create_subscription_session(
|
|||||||
customer_handle: str | None = None,
|
customer_handle: str | None = None,
|
||||||
create_customer: dict | None = None,
|
create_customer: dict | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
|
# CreateSubscription (POST /v1/subscription) n'a pas de champs accept_url/
|
||||||
|
# cancel_url : ils doivent être ajoutés en query string sur le lien
|
||||||
|
# hosted_page_links.payment_info renvoyé, pas dans le body (cf. doc Frisbii).
|
||||||
body: dict = {
|
body: dict = {
|
||||||
"plan": plan_handle,
|
"plan": plan_handle,
|
||||||
"signup_method": "link",
|
"signup_method": "link",
|
||||||
"handle": handle,
|
"handle": handle,
|
||||||
"accept_url": accept_url,
|
|
||||||
"cancel_url": cancel_url,
|
|
||||||
}
|
}
|
||||||
if customer_handle:
|
if customer_handle:
|
||||||
body["customer"] = customer_handle
|
body["customer"] = customer_handle
|
||||||
@@ -84,7 +93,8 @@ def create_subscription_session(
|
|||||||
if no_trial:
|
if no_trial:
|
||||||
body["no_trial"] = True
|
body["no_trial"] = True
|
||||||
data = _call("POST", "/v1/subscription", json=body)
|
data = _call("POST", "/v1/subscription", json=body)
|
||||||
return data["hosted_page_links"]["payment_info"]
|
payment_info = data["hosted_page_links"]["payment_info"]
|
||||||
|
return _with_query(payment_info, accept_url=accept_url, cancel_url=cancel_url)
|
||||||
|
|
||||||
|
|
||||||
def create_recurring_session(
|
def create_recurring_session(
|
||||||
|
|||||||
@@ -148,6 +148,9 @@ def cancel():
|
|||||||
def webhook():
|
def webhook():
|
||||||
payload = request.get_json(silent=True) or {}
|
payload = request.get_json(silent=True) or {}
|
||||||
if not webhooks.verify_signature(payload, os.getenv("FRISBII_WEBHOOK_SECRET", "")):
|
if not webhooks.verify_signature(payload, os.getenv("FRISBII_WEBHOOK_SECRET", "")):
|
||||||
|
logger.warning(
|
||||||
|
"Webhook Frisbii : signature invalide (event %s)", payload.get("id")
|
||||||
|
)
|
||||||
return "", 403
|
return "", 403
|
||||||
|
|
||||||
customer = payload.get("customer")
|
customer = payload.get("customer")
|
||||||
|
|||||||
@@ -43,7 +43,11 @@ def test_create_subscription_session_with_customer_handle(fake_httpx):
|
|||||||
"https://app/ko",
|
"https://app/ko",
|
||||||
customer_handle="colibre-1",
|
customer_handle="colibre-1",
|
||||||
)
|
)
|
||||||
assert url == "https://checkout.reepay.com/#/sub-1"
|
assert url == (
|
||||||
|
"https://checkout.reepay.com/"
|
||||||
|
"?accept_url=https%3A%2F%2Fapp%2Fok&cancel_url=https%3A%2F%2Fapp%2Fko"
|
||||||
|
"#/sub-1"
|
||||||
|
)
|
||||||
body = fake_httpx["calls"][0]["json"]
|
body = fake_httpx["calls"][0]["json"]
|
||||||
assert body["plan"] == "plan_simple"
|
assert body["plan"] == "plan_simple"
|
||||||
assert body["handle"] == "abo-1-1"
|
assert body["handle"] == "abo-1-1"
|
||||||
@@ -51,6 +55,10 @@ def test_create_subscription_session_with_customer_handle(fake_httpx):
|
|||||||
assert body["signup_method"] == "link"
|
assert body["signup_method"] == "link"
|
||||||
assert "generate_handle" not in body
|
assert "generate_handle" not in body
|
||||||
assert "prepare_subscription" not in body
|
assert "prepare_subscription" not in body
|
||||||
|
# accept_url/cancel_url ne sont pas des champs de CreateSubscription :
|
||||||
|
# Frisbii les ignore silencieusement s'ils sont dans le body.
|
||||||
|
assert "accept_url" not in body
|
||||||
|
assert "cancel_url" not in body
|
||||||
|
|
||||||
|
|
||||||
def test_create_subscription_session_no_trial(fake_httpx):
|
def test_create_subscription_session_no_trial(fake_httpx):
|
||||||
|
|||||||
Reference in New Issue
Block a user