diff --git a/app/billing/routes.py b/app/billing/routes.py index 3c8971d..75d10ec 100644 --- a/app/billing/routes.py +++ b/app/billing/routes.py @@ -56,9 +56,12 @@ def subscribe(): abort(400) from control.base import control_session - from control.models import Tenant as ControlTenant + from control.models import Tenant as ControlTenant, Plan from app.billing.stripe_client import create_stripe_customer, create_checkout_session + # Allow tenant to pick a plan via ?plan= when on Free. + requested_plan_code = request.args.get('plan') + with control_session() as s: t = s.get(ControlTenant, tenant.id) if t is None: @@ -66,13 +69,20 @@ def subscribe(): return redirect(url_for('tenant_settings.plan')) plan = t.plan + + # If a specific plan was requested (e.g. from the plan picker), use it. + if requested_plan_code: + chosen = s.query(Plan).filter_by(code=requested_plan_code).first() + if chosen and chosen.stripe_price_id: + plan = chosen + + # If still on Free (no price ID), show the plan picker instead. if plan is None or not plan.stripe_price_id: - flash( - 'Your current plan does not have a Stripe price configured. ' - 'Please contact support to set up billing.', - 'warning', - ) - return redirect(url_for('tenant_settings.plan')) + paid_plans = (s.query(Plan) + .filter(Plan.stripe_price_id.isnot(None)) + .order_by(Plan.price_cents) + .all()) + return render_template('billing/plan_picker.html', plans=paid_plans) # Get or create Stripe customer. Write back immediately within the # control_session so the customer_id is persisted before the redirect. diff --git a/app/templates/billing/plan_picker.html b/app/templates/billing/plan_picker.html new file mode 100644 index 0000000..2b014aa --- /dev/null +++ b/app/templates/billing/plan_picker.html @@ -0,0 +1,71 @@ +{% extends "base.html" %} +{% block title %}Choose a Plan — JQC{% endblock %} + +{% block content %} +
+
+

Choose a Plan

+

+ Select the plan that best fits your team. You can upgrade or downgrade at any time. +

+ +
+ {% for plan in plans %} +
+
+
+ {{ plan.name }} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Users{{ plan.max_users if plan.max_users else 'Unlimited' }}
Facilities{{ plan.max_facilities if plan.max_facilities else 'Unlimited' }}
Inspections / mo{{ plan.max_inspections_month if plan.max_inspections_month else 'Unlimited' }}
Mobile API (iPad){% if plan.allow_mobile_api %}{% else %}{% endif %}
Scheduled Reports{% if plan.allow_scheduled_reports %}{% else %}{% endif %}
Branding{% if plan.allow_branding %}{% else %}{% endif %}
Custom Domain{% if plan.allow_custom_domain %}{% else %}{% endif %}
+ +
+
+
+ {% endfor %} +
+ + +
+
+{% endblock %}