feat(billing): A6 — planner/supplier routes use get_price_id() + _provider()

- planner/routes.py: import get_price_id instead of get_paddle_price,
  export_checkout uses _provider().build_checkout_payload()
- suppliers/routes.py: all get_paddle_price → get_price_id,
  signup_checkout uses _provider().build_multi_item_checkout_payload(),
  dashboard boosts use get_all_price_ids() bulk load

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-03-03 15:36:12 +01:00
parent 8f0a56079f
commit bf69270913
2 changed files with 30 additions and 35 deletions

View File

@@ -18,7 +18,7 @@ from ..core import (
feature_gate, feature_gate,
fetch_all, fetch_all,
fetch_one, fetch_one,
get_paddle_price, get_price_id,
utcnow_iso, utcnow_iso,
) )
from ..i18n import get_translations from ..i18n import get_translations
@@ -687,7 +687,9 @@ async def export_details():
@login_required @login_required
@csrf_protect @csrf_protect
async def export_checkout(): async def export_checkout():
"""Return JSON for Paddle.js overlay checkout for business plan PDF.""" """Return checkout JSON for business plan PDF (works with Paddle overlay or Stripe redirect)."""
from ..billing.routes import _provider
form = await request.form form = await request.form
scenario_id = form.get("scenario_id") scenario_id = form.get("scenario_id")
language = form.get("language", "en") language = form.get("language", "en")
@@ -703,23 +705,20 @@ async def export_checkout():
if not scenario: if not scenario:
return jsonify({"error": "Scenario not found."}), 404 return jsonify({"error": "Scenario not found."}), 404
price_id = await get_paddle_price("business_plan") price_id = await get_price_id("business_plan")
if not price_id: if not price_id:
return jsonify({"error": "Product not configured. Contact support."}), 500 return jsonify({"error": "Product not configured. Contact support."}), 500
return jsonify( payload = _provider().build_checkout_payload(
{ price_id=price_id,
"items": [{"priceId": price_id, "quantity": 1}], custom_data={
"customData": { "user_id": str(g.user["id"]),
"user_id": str(g.user["id"]), "scenario_id": str(scenario_id),
"scenario_id": str(scenario_id), "language": language,
"language": language, },
}, success_url=f"{config.BASE_URL}/planner/export/success",
"settings": {
"successUrl": f"{config.BASE_URL}/planner/export/success",
},
}
) )
return jsonify(payload)
@bp.route("/export/success") @bp.route("/export/success")

View File

@@ -17,7 +17,8 @@ from ..core import (
feature_gate, feature_gate,
fetch_all, fetch_all,
fetch_one, fetch_one,
get_paddle_price, get_all_price_ids,
get_price_id,
is_flag_enabled, is_flag_enabled,
) )
from ..i18n import get_translations from ..i18n import get_translations
@@ -383,7 +384,9 @@ def _compute_order(data: dict, included_boosts: list, t: dict) -> dict:
@bp.route("/signup/checkout", methods=["POST"]) @bp.route("/signup/checkout", methods=["POST"])
@csrf_protect @csrf_protect
async def signup_checkout(): async def signup_checkout():
"""Validate form, return JSON for Paddle.js overlay checkout.""" """Validate form, return checkout JSON (Paddle overlay or Stripe redirect)."""
from ..billing.routes import _provider
form = await request.form form = await request.form
accumulated = _parse_accumulated(form) accumulated = _parse_accumulated(form)
@@ -401,9 +404,9 @@ async def signup_checkout():
if period == "yearly" if period == "yearly"
else plan_info.get("paddle_key_monthly", plan) else plan_info.get("paddle_key_monthly", plan)
) )
plan_price_id = await get_paddle_price(price_key) plan_price_id = await get_price_id(price_key)
if not plan_price_id: if not plan_price_id:
return jsonify({"error": "Invalid plan selected. Run setup_paddle first."}), 400 return jsonify({"error": "Invalid plan selected. Run setup first."}), 400
# Build items list # Build items list
items = [{"priceId": plan_price_id, "quantity": 1}] items = [{"priceId": plan_price_id, "quantity": 1}]
@@ -416,14 +419,14 @@ async def signup_checkout():
for b in BOOST_OPTIONS: for b in BOOST_OPTIONS:
if b["type"] in selected_boosts and b["type"] not in included_boosts: if b["type"] in selected_boosts and b["type"] not in included_boosts:
price_id = await get_paddle_price(b["key"]) price_id = await get_price_id(b["key"])
if price_id: if price_id:
items.append({"priceId": price_id, "quantity": 1}) items.append({"priceId": price_id, "quantity": 1})
# Add credit pack (one-time) # Add credit pack (one-time)
credit_pack = accumulated.get("credit_pack", "") credit_pack = accumulated.get("credit_pack", "")
if credit_pack: if credit_pack:
price_id = await get_paddle_price(credit_pack) price_id = await get_price_id(credit_pack)
if price_id: if price_id:
items.append({"priceId": price_id, "quantity": 1}) items.append({"priceId": price_id, "quantity": 1})
@@ -477,15 +480,12 @@ async def signup_checkout():
"plan": plan, "plan": plan,
} }
return jsonify( payload = _provider().build_multi_item_checkout_payload(
{ items=items,
"items": items, custom_data=custom_data,
"customData": custom_data, success_url=f"{config.BASE_URL}/suppliers/signup/success",
"settings": {
"successUrl": f"{config.BASE_URL}/suppliers/signup/success",
},
}
) )
return jsonify(payload)
@bp.route("/claim/<slug>") @bp.route("/claim/<slug>")
@@ -1035,12 +1035,8 @@ async def dashboard_boosts():
(supplier["id"],), (supplier["id"],),
) )
# Resolve Paddle price IDs for buy buttons # Resolve price IDs for buy buttons (from active provider)
price_ids = {} price_ids = await get_all_price_ids()
for b in BOOST_OPTIONS:
price_ids[b["key"]] = await get_paddle_price(b["key"])
for cp in CREDIT_PACK_OPTIONS:
price_ids[cp["key"]] = await get_paddle_price(cp["key"])
return await render_template( return await render_template(
"suppliers/partials/dashboard_boosts.html", "suppliers/partials/dashboard_boosts.html",